Note
Go to the end to download the full example code
Respiration tutorial¶
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
from pprint import pprint
import physio
Respiration cycle detection: the quick way ——————————————
The fastest way is to use compute_respiration() using a predefined parameter preset. Here is a simple example.
# read data
raw_resp = np.load('resp1.npy')
srate = 1000.
times = np.arange(raw_resp.size) / srate
# the easiest way is to use predefined parameters
resp, resp_cycles = physio.compute_respiration(raw_resp, srate, parameter_preset='human_airflow')
# resp_cycles is a dataframe containing all cycles and related fetaures (duration, amplitude, volume, timing)
print(resp_cycles)
inspi_index = resp_cycles['inspi_index'].values
expi_index = resp_cycles['expi_index'].values
fig, ax = plt.subplots()
ax.plot(times, raw_resp)
ax.plot(times, resp)
ax.scatter(times[inspi_index], resp[inspi_index], marker='o', color='green')
ax.scatter(times[expi_index], resp[expi_index], marker='o', color='red')
ax.set_ylabel('resp')
ax.set_xlim(110, 170)
inspi_index expi_index ... expi_amplitude total_volume
0 963 3849 ... 102.789023 290.900295
1 8755 12470 ... 92.424274 248.221182
2 16629 20085 ... 114.051992 224.880845
3 25589 28826 ... 79.971850 179.640929
4 35467 39250 ... 80.847071 218.096948
5 45631 48992 ... 88.355380 184.421903
6 55914 59772 ... 80.166094 221.551973
7 67325 70801 ... 78.223802 172.416317
8 78023 81420 ... 121.968793 240.612522
9 86030 89213 ... 109.013617 161.906780
10 94623 97972 ... 176.532582 1083.501652
11 104423 108683 ... 112.247642 236.964441
12 114252 117877 ... 134.114274 215.359089
13 124700 127879 ... 121.508199 226.502400
14 134461 138178 ... 73.704242 196.257905
15 145780 149124 ... 77.729124 143.132747
16 156359 159809 ... 64.689117 172.424788
17 165930 169247 ... 68.542888 179.678477
18 175415 178225 ... 65.214481 129.565439
19 184867 188712 ... 90.656664 172.640214
20 195179 199483 ... 56.376923 186.983757
21 205152 209074 ... 63.106055 218.620572
22 214162 217778 ... 76.314458 206.421199
23 223497 227737 ... 66.216154 222.527032
24 233353 237747 ... 95.536105 254.269911
25 242949 247667 ... 92.769307 318.495735
26 253240 257182 ... 76.873371 258.033292
27 263116 266749 ... 81.421824 204.482721
28 273102 277759 ... 77.226645 243.681649
29 284946 288731 ... 76.494002 189.285082
[30 rows x 17 columns]
(110.0, 170.0)
Cycle detection: Default parameters ———————————–
- Here are the default parametersthose aiming to process a human airflow signal.
It is possible to get default parameters dictionnary by calling it with the
get_respiration_parameters()
function.
# this is a nested dict of parameters of every processing step
parameters = physio.get_respiration_parameters('human_airflow')
pprint(parameters)
{'baseline': {'baseline_mode': 'median'},
'cycle_clean': {'low_limit_log_ratio': 4.0},
'cycle_detection': {'inspiration_adjust_on_derivative': False,
'method': 'crossing_baseline'},
'features': {'compute_amplitude': True, 'compute_volume': True},
'preprocess': {'band': 7.0,
'btype': 'lowpass',
'ftype': 'bessel',
'normalize': False,
'order': 5},
'smooth': {'sigma_ms': 60.0, 'win_shape': 'gaussian'}}
Cycle detection: Parameters tuning ———————————–
If necessary, it is possible to change the predefined parameters. For example, we change here the length of the smoothing parameter.
# let's change on parameter in the structure ...
parameters['smooth']['sigma_ms'] = 100.
pprint(parameters)
# ... and use them by providing it to "parameters"
resp, resp_cycles = physio.compute_respiration(raw_resp, srate, parameters=parameters)
{'baseline': {'baseline_mode': 'median'},
'cycle_clean': {'low_limit_log_ratio': 4.0},
'cycle_detection': {'inspiration_adjust_on_derivative': False,
'method': 'crossing_baseline'},
'features': {'compute_amplitude': True, 'compute_volume': True},
'preprocess': {'band': 7.0,
'btype': 'lowpass',
'ftype': 'bessel',
'normalize': False,
'order': 5},
'smooth': {'sigma_ms': 100.0, 'win_shape': 'gaussian'}}
Respiration : step by step ————————–
Here are details of all low-level functions used internally in the compute_respiration()
resp = physio.preprocess(resp, srate, band=25., btype='lowpass', ftype='bessel', order=5, normalize=False)
resp = physio.smooth_signal(resp, srate, win_shape='gaussian', sigma_ms=90.0)
baseline = physio.get_respiration_baseline(resp, srate, baseline_mode='median')
print('baseline', baseline)
# this will give a numpy.array with shape (num_cycle, 3)
cycles = physio.detect_respiration_cycles(resp, srate, baseline_mode='manual', baseline=baseline)
print(cycles[:10])
# this will return a dataframe with all cycles and fetaure before cleaning
resp_cycles = physio.compute_respiration_cycle_features(resp, srate, cycles, baseline=baseline)
# this will remove outliers cycles based on log ratio distribution
resp_cycles = physio.clean_respiration_cycles(resp, srate, resp_cycles, baseline, low_limit_log_ratio=3)
print(resp_cycles.head(10))
inspi_index = resp_cycles['inspi_index'].values
expi_index = resp_cycles['expi_index'].values
fig, ax = plt.subplots()
ax.plot(times, resp)
ax.scatter(times[inspi_index], resp[inspi_index], marker='o', color='green')
ax.scatter(times[expi_index], resp[expi_index], marker='o', color='red')
ax.set_ylabel('resp')
ax.axhline(baseline, color='Coral')
ax.set_xlim(110, 170)
plt.show()
baseline -1635.6362015145448
[[ 921 3899 8696]
[ 8696 12407 16564]
[16564 20049 25536]
[25536 28891 35436]
[35436 39351 45588]
[45588 49038 55848]
[55848 59841 67282]
[67282 70835 77973]
[77973 81641 85983]
[85983 89221 94557]]
inspi_index expi_index ... expi_amplitude total_volume
0 921 3899 ... 100.699565 290.636011
1 8696 12407 ... 90.468119 248.115513
2 16564 20049 ... 109.301593 224.811918
3 25536 28891 ... 77.782396 179.517104
4 35436 39351 ... 79.514765 217.967633
5 45588 49038 ... 87.158593 184.333682
6 55848 59841 ... 77.257209 221.402827
7 67282 70835 ... 77.327921 172.267005
8 77973 81641 ... 117.712828 240.550042
9 85983 89221 ... 104.090516 161.702428
[10 rows x 17 columns]
Total running time of the script: (0 minutes 0.516 seconds)