99
1010from .. import references
1111from ..due import due
12- from .utils import hamming , physio_or_numpy
12+ from .utils import hamming
1313
1414
1515def envelopedetect (data , upperpass = 0.05 , order = 5 ):
1616 """
17-
17+ Detects the amplitude envelope of a pseudoperiodic waveform (respiration, cardiac, etc.)
1818 Parameters
1919 ----------
2020 data
@@ -55,30 +55,80 @@ def envelopedetect(data, upperpass=0.05, order=5):
5555 return einferior , esuperior
5656
5757
58+ def respiratorysqi (rawresp , debug = False ):
59+ """
60+ Calculate the breath by breath quality of the respiratory signal
61+ Parameters
62+ ----------
63+ rawresp: physio_like
64+ The raw respiratory signal
65+ debug: bool
66+ Print debug information and plot intermediate results
67+
68+ Returns
69+ -------
70+ breathlist: list
71+ List of "breathinfo" dictionaries for each detected breath. Each breathinfo dictionary contains:
72+ "startime", "centertime", and "endtime" of each detected breath in seconds from the start of the waveform,
73+ and "correlation" - the Pearson correlation of that breath waveform with the average waveform.
74+
75+ """
76+ targetfs = 25.0
77+ prefilterlimits = [0.01 , 2.0 ]
78+ seglength = 12.0
79+ segstep = 2.0
80+ envelopelpffreq = 0.05
81+ slidingfilterpctwidth = 10.0
82+
83+ return romanosqi (
84+ rawresp ,
85+ targetfs = targetfs ,
86+ prefilterlimits = prefilterlimits ,
87+ envelopelpffreq = envelopelpffreq ,
88+ slidingfilterpctwidth = slidingfilterpctwidth ,
89+ seglength = seglength ,
90+ segstep = segstep ,
91+ debug = debug ,
92+ )
93+
94+
5895@due .dcite (references .ROMANO_2023 )
59- def respiratorysqi (
60- rawresp , Fs , envelopelpffreq = 0.075 , slidingfilterpctwidth = 10.0 , debug = False
96+ def romanosqi (
97+ rawresp ,
98+ targetfs = 25.0 ,
99+ prefilterlimits = (0.01 , 2.0 ),
100+ envelopelpffreq = 0.05 ,
101+ slidingfilterpctwidth = 10.0 ,
102+ seglength = 12.0 ,
103+ segstep = 2.0 ,
104+ debug = False ,
61105):
62106 """
63107 Implementation of Romano's method from A Signal Quality Index for Improving the Estimation of
64108 Breath-by-Breath Respiratory Rate During Sport and Exercise,
65109 IEEE SENSORS JOURNAL, VOL. 23, NO. 24, 15 DECEMBER 2023
66110
67111 NB: In part A, Romano does not specify the upper pass frequency for the respiratory envelope filter.
68- 0.075Hz looks pretty good.
112+ 0.05Hz looks pretty good for respiration .
69113 In part B, the width of the sliding window bandpass filter is not specified. We use a range of +/- 5% of the
70114 center frequency.
71115
72116 Parameters
73117 ----------
74- rawresp: ndarray
118+ rawresp: physio_like
75119 The raw respiration signal
76- Fs: float
77- The sampling frequency of the respiration signal in Hz
120+ targetfs: float
121+ Sample rate for internal calculations
122+ prefilterlimits: tuple
123+ Lower and upper frequency limits for prefiltering the input signal
78124 envelopelpffreq: float
79125 Cutoff frequency of the RMS envelope filter in Hz
80126 slidingfilterpctwidth: float
81127 Width of the sliding window bandpass filter in percent of the center frequency
128+ seglength: float
129+ Length of the window for measuring the waveform center frequency in seconds
130+ segstep: float
131+ Step size of the window for measuring the waveform center frequency in seconds
82132 debug: bool
83133 Print debug information and plot intermediate results
84134
@@ -87,20 +137,17 @@ def respiratorysqi(
87137 breathlist: list
88138 List of "breathinfo" dictionaries for each detected breath. Each breathinfo dictionary contains:
89139 "startime", "centertime", and "endtime" of each detected breath in seconds from the start of the waveform,
90- and "correlation" - the Pierson correlation of that breath waveform with the average waveform.
140+ and "correlation" - the Pearson correlation of that breath waveform with the average waveform.
91141 """
92- # rawresp = physio_or_numpy(rawresp)
93142
94143 # get the sample frequency down to around 25 Hz for respiratory waveforms
95- targetfs = 25.0
96- rawresp = Physio (rawresp , fs = Fs )
97144 rawresp = operations .interpolate_physio (rawresp , target_fs = targetfs )
98145
99146 # A. Signal Preprocessing
100147 # Apply third order Butterworth bandpass, 0.01-2Hz
101148 prefiltered = operations .filter_physio (
102149 rawresp ,
103- [ 0.01 , 2.0 ] ,
150+ prefilterlimits ,
104151 "bandpass" ,
105152 order = 3 ,
106153 )
@@ -147,10 +194,8 @@ def respiratorysqi(
147194 )
148195 plt .show ()
149196
150- # B. Detection of breaths in sliding window
151- seglength = 12.0
197+ # B. Detection of peaks in sliding window
152198 segsamples = int (seglength * targetfs )
153- segstep = 2.0
154199 stepsamples = int (segstep * targetfs )
155200 totaltclength = len (rawresp )
156201 numsegs = int ((totaltclength - segsamples ) // stepsamples )
@@ -298,19 +343,17 @@ def plotbreathqualities(breathlist, totaltime=None):
298343 plt .show ()
299344
300345
301- def plotbreathwaveformwithquality (waveform , breathlist , Fs , plottype = "rectangle" ):
346+ def plotbreathwaveformwithquality (data , breathlist , plottype = "rectangle" ):
302347 """
303348 Make an informational plot of the respiratory waveform with the quantifiability of each detected breath as a
304349 color overlay.
305350
306351 Parameters
307352 ----------
308- waveform: ndarray
353+ data: physio_like
309354 The respiratory waveform
310355 breathlist: list
311356 A list of breathinfo dictionaries output from respiratorysqi
312- Fs: float
313- The sampling frequency of the respiratory waveform in Hz
314357 plottype: str
315358 The type of plot to make. If plottype is rectangle (default), overlay a colored rectangle to show the
316359 quantifiability of each detected breath. If anything else, use the waveform line color to indicate the
@@ -319,6 +362,9 @@ def plotbreathwaveformwithquality(waveform, breathlist, Fs, plottype="rectangle"
319362 -------
320363
321364 """
365+ waveform = data .data
366+ Fs = data .fs
367+
322368 # now plot the respiratory waveform, color coded for quality
323369
324370 # set up the color codes
0 commit comments