Skip to content

Commit 02e9592

Browse files
committed
Added legends to plots, tweaked envelope filtering
1 parent bd39278 commit 02e9592

File tree

1 file changed

+32
-11
lines changed

1 file changed

+32
-11
lines changed

physioqc/metrics/chest_belt.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,25 @@ def respirationprefilter(
2323
# return operations.filter_physio(rawresp, cutoffs=[lowerpass, upperpass], method='bandpass')
2424

2525

26-
def respenvelopefilter(squarevals, Fs, upperpass=0.1, order=8, debug=False):
26+
def respenvelopefilter(squarevals, Fs, upperpass=0.05, order=8, debug=False):
2727
if debug:
2828
print(f"respenvelopefilter: Fs={Fs} order={order}, upperpass={upperpass}")
2929
return butterlpfiltfilt(Fs, upperpass, squarevals, order, debug=debug)
3030

3131

3232
@due.dcite(references.ROMANO_2023)
33-
def respiratorysqi(rawresp, Fs, debug=False):
33+
def respiratorysqi(
34+
rawresp, Fs, envelopelpffreq=0.05, slidingfilterpctwidth=10.0, debug=False
35+
):
3436
"""Implementation of Romano's method from A Signal Quality Index for Improving the Estimation of
3537
Breath-by-Breath Respiratory Rate During Sport and Exercise,
36-
IEEE SENSORS JOURNAL, VOL. 23, NO. 24, 15 DECEMBER 2023"""
38+
IEEE SENSORS JOURNAL, VOL. 23, NO. 24, 15 DECEMBER 2023
39+
40+
NB: In part A, Romano does not specify the upper pass frequency for the respiratory envelope filter.
41+
0.05Hz looks pretty good.
42+
In part B, the width of the sliding window bandpass filter is not specified. We use a range of +/- 5% of the
43+
center frequency.
44+
"""
3745

3846
# rawresp = physio_or_numpy(rawresp)
3947

@@ -51,6 +59,8 @@ def respiratorysqi(rawresp, Fs, debug=False):
5159
if debug:
5260
plt.plot(rawresp)
5361
plt.plot(prefiltered)
62+
plt.title("Raw and prefiltered respiratory signal")
63+
plt.legend(["Raw", "Prefiltered"])
5464
plt.show()
5565
if debug:
5666
print("prefiltered: ", prefiltered)
@@ -67,25 +77,35 @@ def respiratorysqi(rawresp, Fs, debug=False):
6777
normderiv = 2.0 * (derivative - derivmin) / derivrange - 1.0
6878
if debug:
6979
plt.plot(normderiv)
80+
plt.title("Normalized derivative of respiratory signal")
81+
plt.legend(["Normalized derivative"])
7082
plt.show()
7183

7284
# amplitude correct by flattening the envelope function
7385
esuperior = 2.0 * respenvelopefilter(
74-
np.square(np.where(normderiv > 0.0, normderiv, 0.0)), Fs
86+
np.square(np.where(normderiv > 0.0, normderiv, 0.0)),
87+
Fs,
88+
upperpass=envelopelpffreq,
7589
)
7690
esuperior = np.sqrt(np.where(esuperior > 0.0, esuperior, 0.0))
7791
einferior = 2.0 * respenvelopefilter(
78-
np.square(np.where(normderiv < 0.0, normderiv, 0.0)), Fs
92+
np.square(np.where(normderiv < 0.0, normderiv, 0.0)),
93+
Fs,
94+
upperpass=envelopelpffreq,
7995
)
80-
einferior = np.sqrt(np.where(einferior > 0.0, einferior, 0.0))
96+
einferior = -np.sqrt(np.where(einferior > 0.0, einferior, 0.0))
8197
if debug:
8298
plt.plot(normderiv)
8399
plt.plot(esuperior)
84-
plt.plot(-einferior)
100+
plt.plot(einferior)
101+
plt.legend(["Normalized derivative", "esuperior", "einferior"])
85102
plt.show()
86-
rmsnormderiv = normderiv / (esuperior + einferior)
103+
rmsnormderiv = (normderiv - einferior) / (esuperior - einferior)
87104
if debug:
88105
plt.plot(rmsnormderiv)
106+
plt.title(
107+
"Normalized derivative of respiratory signal after envelope correction"
108+
)
89109
plt.show()
90110

91111
# B. Detection of breaths in sliding window
@@ -112,10 +132,9 @@ def respiratorysqi(rawresp, Fs, debug=False):
112132
segment -= np.mean(segment)
113133
thex, they = welch(segment, Fs, nfft=4096)
114134
peakfreqs[i] = thex[np.argmax(they)]
115-
respfilterpctwidth = 10.0
116135
respfilterorder = 1
117-
lowerfac = 1.0 - respfilterpctwidth / 200.0
118-
upperfac = 1.0 + respfilterpctwidth / 200.0
136+
lowerfac = 1.0 - slidingfilterpctwidth / 200.0
137+
upperfac = 1.0 + slidingfilterpctwidth / 200.0
119138
lowerpass = peakfreqs[i] * lowerfac
120139
upperpass = peakfreqs[i] * upperfac
121140
if debug:
@@ -138,6 +157,8 @@ def respiratorysqi(rawresp, Fs, debug=False):
138157
print(peakfreqs)
139158
plt.plot(rmsnormderiv)
140159
plt.plot(respfilteredderivs)
160+
plt.title("Normalized derivative before and after targeted bandpass filtering")
161+
plt.legend(["Normalized derivative", "Filtered normalized derivative"])
141162
plt.show()
142163

143164
# C. Breaths segmentation

0 commit comments

Comments
 (0)