From 4015a14b31908330d956b5f56b7ccb25e50db0e1 Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Tue, 8 Dec 2020 10:29:07 -0500 Subject: [PATCH 01/13] made base rvt code --- .gitignore | 2 ++ phys2denoise/metrics/rvt.py | 13 +++++++++++++ phys2denoise/tests/test_rvt.py | 26 ++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 phys2denoise/metrics/rvt.py create mode 100644 phys2denoise/tests/test_rvt.py diff --git a/.gitignore b/.gitignore index 7c01937..f7285ed 100644 --- a/.gitignore +++ b/.gitignore @@ -125,3 +125,5 @@ dmypy.json .pyre/ .vscode/ +.idea/ +data/ diff --git a/phys2denoise/metrics/rvt.py b/phys2denoise/metrics/rvt.py new file mode 100644 index 0000000..5a1f7d0 --- /dev/null +++ b/phys2denoise/metrics/rvt.py @@ -0,0 +1,13 @@ +import numpy as np +from scipy.interpolate import interp1d + + +def rvt(belt_ts, peaks, troughs, samplerate, window=10, lags=(0,)): + timestep = 1/samplerate + time = np.array([i*timestep for i in range(len(belt_ts))]) + peak_time = time[peaks] + trough_time = time[troughs] + peak_interp = interp1d(peak_time, belt_ts[peaks], bounds_error=False, fill_value="extrapolate")(time) + trough_interp = interp1d(trough_time, belt_ts[troughs], bounds_error=False, fill_value="extrapolate")(time) + rvt = peak_interp - trough_interp + return rvt \ No newline at end of file diff --git a/phys2denoise/tests/test_rvt.py b/phys2denoise/tests/test_rvt.py new file mode 100644 index 0000000..0377d69 --- /dev/null +++ b/phys2denoise/tests/test_rvt.py @@ -0,0 +1,26 @@ +import peakdet +import numpy as np +import matplotlib.pyplot as plt +from phys2denoise.metrics.rvt import rvt + + +def read_real_phys(): + real_physio = np.genfromtxt("../../data/sub-A00077637_ses-BAS1_task-rest_acq-1400_physio.tsv.gz") + phys = peakdet.Physio(real_physio[:, 2]-real_physio[:, 2].mean(), fs=62.5) + phys = peakdet.operations.filter_physio(phys, cutoffs=3, method="lowpass") + return phys + +def test_peakdet(): + phys = read_real_phys() + phys = peakdet.operations.peakfind_physio(phys) + assert phys.troughs is not None + assert phys.peaks is not None + +def test_rvt(): + phys = read_real_phys() + phys = peakdet.operations.peakfind_physio(phys) + r = rvt(phys.data, phys.peaks, phys.troughs, samplerate=phys.fs) + plt.plot(r) + plt.show() + + From dc04b0edaa4572f8d9692eda2d9be5c9c100e79e Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Tue, 15 Dec 2020 23:35:12 -0500 Subject: [PATCH 02/13] add lags to rvt --- phys2denoise/metrics/rvt.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/phys2denoise/metrics/rvt.py b/phys2denoise/metrics/rvt.py index 5a1f7d0..c5b748c 100644 --- a/phys2denoise/metrics/rvt.py +++ b/phys2denoise/metrics/rvt.py @@ -2,12 +2,23 @@ from scipy.interpolate import interp1d -def rvt(belt_ts, peaks, troughs, samplerate, window=10, lags=(0,)): +def rvt(belt_ts, peaks, troughs, samplerate, lags=(0,4,8,12)): timestep = 1/samplerate time = np.array([i*timestep for i in range(len(belt_ts))]) + peak_vals = belt_ts[peaks] + trough_vals = belt_ts[troughs] peak_time = time[peaks] + mid_peak_time = (peak_time[:-1] + peak_time[1:])/2 + period = (peak_time[1:] - peak_time[:-1]) trough_time = time[troughs] - peak_interp = interp1d(peak_time, belt_ts[peaks], bounds_error=False, fill_value="extrapolate")(time) - trough_interp = interp1d(trough_time, belt_ts[troughs], bounds_error=False, fill_value="extrapolate")(time) - rvt = peak_interp - trough_interp - return rvt \ No newline at end of file + peak_interp = interp1d(peak_time, peak_vals, bounds_error=False, fill_value="extrapolate")(time) + trough_interp = interp1d(trough_time, trough_vals, bounds_error=False, fill_value="extrapolate")(time) + period_interp = interp1d(mid_peak_time, period, bounds_error=False, fill_value="extrapolate")(time) + rvt = (peak_interp - trough_interp)/period_interp + rvt_lags = np.zeros((len(rvt), len(lags))) + for ind, lag in enumerate(lags): + start_index = np.argmin(np.abs(time-lag)) + temp_rvt = np.concatenate((np.full((start_index), rvt[0]), rvt[:len(rvt)-start_index])) + rvt_lags[:, ind] = temp_rvt + + return rvt_lags \ No newline at end of file From 5973bfa5e3649fd665cde96ccf1258d21016aa25 Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Tue, 22 Dec 2020 09:26:44 -0500 Subject: [PATCH 03/13] added comments --- phys2denoise/metrics/rvt.py | 67 ++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/phys2denoise/metrics/rvt.py b/phys2denoise/metrics/rvt.py index c5b748c..3f485ee 100644 --- a/phys2denoise/metrics/rvt.py +++ b/phys2denoise/metrics/rvt.py @@ -2,23 +2,64 @@ from scipy.interpolate import interp1d -def rvt(belt_ts, peaks, troughs, samplerate, lags=(0,4,8,12)): - timestep = 1/samplerate - time = np.array([i*timestep for i in range(len(belt_ts))]) +def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): + """ " + Implements the Respiratory Variance over Time as described in Birn et al. (2006). + Procedural choices influenced by RetroTS + + Parameters + ---------- + belt_ts: array_like + respiratory belt data - samples x 1 + peaks: array_like + peaks found by peakdet algorithm + troughs: array_like + troughs found by peakdet algorithm + samplerate: float + sample rate in hz of respiratory belt + lags: tuple + lags in seconds of the RVT output. Default is 0, 4, 8, 12. + + Outputs + ------- + rvt: array_like + calculated RVT and associated lags. + + """ + + timestep = 1 / samplerate + # respiration belt timing + time = np.array([i * timestep for i in range(len(belt_ts))]) peak_vals = belt_ts[peaks] trough_vals = belt_ts[troughs] peak_time = time[peaks] - mid_peak_time = (peak_time[:-1] + peak_time[1:])/2 - period = (peak_time[1:] - peak_time[:-1]) trough_time = time[troughs] - peak_interp = interp1d(peak_time, peak_vals, bounds_error=False, fill_value="extrapolate")(time) - trough_interp = interp1d(trough_time, trough_vals, bounds_error=False, fill_value="extrapolate")(time) - period_interp = interp1d(mid_peak_time, period, bounds_error=False, fill_value="extrapolate")(time) - rvt = (peak_interp - trough_interp)/period_interp - rvt_lags = np.zeros((len(rvt), len(lags))) + mid_peak_time = (peak_time[:-1] + peak_time[1:]) / 2 + period = peak_time[1:] - peak_time[:-1] + # interpolate peak values over all timepoints + peak_interp = interp1d( + peak_time, peak_vals, bounds_error=False, fill_value="extrapolate" + )(time) + # interpolate trough values over all timepoints + trough_interp = interp1d( + trough_time, trough_vals, bounds_error=False, fill_value="extrapolate" + )(time) + # interpolate period over all timepoints + period_interp = interp1d( + mid_peak_time, period, bounds_error=False, fill_value="extrapolate" + )(time) + # full_rvt is (peak-trough)/period + full_rvt = (peak_interp - trough_interp) / period_interp + # calculate lags for RVT + rvt_lags = np.zeros((len(full_rvt), len(lags))) for ind, lag in enumerate(lags): - start_index = np.argmin(np.abs(time-lag)) - temp_rvt = np.concatenate((np.full((start_index), rvt[0]), rvt[:len(rvt)-start_index])) + start_index = np.argmin(np.abs(time - lag)) + temp_rvt = np.concatenate( + ( + np.full((start_index), full_rvt[0]), + full_rvt[: len(full_rvt) - start_index], + ) + ) rvt_lags[:, ind] = temp_rvt - return rvt_lags \ No newline at end of file + return rvt_lags From a1fa4077a2d34a1fd40fd16ad621ccc21c7312a8 Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Sat, 26 Dec 2020 18:36:59 -0500 Subject: [PATCH 04/13] switched to fake data --- phys2denoise/tests/test_rvt.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/phys2denoise/tests/test_rvt.py b/phys2denoise/tests/test_rvt.py index 0377d69..d8b233f 100644 --- a/phys2denoise/tests/test_rvt.py +++ b/phys2denoise/tests/test_rvt.py @@ -1,26 +1,30 @@ import peakdet import numpy as np -import matplotlib.pyplot as plt from phys2denoise.metrics.rvt import rvt -def read_real_phys(): - real_physio = np.genfromtxt("../../data/sub-A00077637_ses-BAS1_task-rest_acq-1400_physio.tsv.gz") - phys = peakdet.Physio(real_physio[:, 2]-real_physio[:, 2].mean(), fs=62.5) +def read_fake_phys(): + f = 0.3 + fs = 62.5 # sampling rate + t = 300 + samples = np.arange(t * fs) / fs + noise = np.random.normal(0, 0.5, len(samples)) + fake_phys = 10 * np.sin(2 * np.pi * f * samples) + noise + phys = peakdet.Physio(fake_phys, fs=62.5) phys = peakdet.operations.filter_physio(phys, cutoffs=3, method="lowpass") return phys + def test_peakdet(): - phys = read_real_phys() + phys = read_fake_phys() phys = peakdet.operations.peakfind_physio(phys) assert phys.troughs is not None assert phys.peaks is not None + def test_rvt(): - phys = read_real_phys() + phys = read_fake_phys() phys = peakdet.operations.peakfind_physio(phys) r = rvt(phys.data, phys.peaks, phys.troughs, samplerate=phys.fs) - plt.plot(r) - plt.show() - - + assert r is not None + assert len(r) == 18750 From e8ea08bacbf5647777cb9bedb7805a8988db276f Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Tue, 29 Dec 2020 17:42:58 -0500 Subject: [PATCH 05/13] changed name of RVT function --- phys2denoise/metrics/{rvt.py => chest_belt.py} | 0 phys2denoise/tests/test_rvt.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename phys2denoise/metrics/{rvt.py => chest_belt.py} (100%) diff --git a/phys2denoise/metrics/rvt.py b/phys2denoise/metrics/chest_belt.py similarity index 100% rename from phys2denoise/metrics/rvt.py rename to phys2denoise/metrics/chest_belt.py diff --git a/phys2denoise/tests/test_rvt.py b/phys2denoise/tests/test_rvt.py index d8b233f..f5c66d4 100644 --- a/phys2denoise/tests/test_rvt.py +++ b/phys2denoise/tests/test_rvt.py @@ -1,6 +1,6 @@ import peakdet import numpy as np -from phys2denoise.metrics.rvt import rvt +from phys2denoise.metrics.chest_belt import rvt def read_fake_phys(): From 35f6e56b8b874095826f82d3f1ed396abbd55a94 Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Wed, 6 Jan 2021 22:39:54 -0500 Subject: [PATCH 06/13] fix docstring linting issues --- .gitignore | 2 -- phys2denoise/metrics/chest_belt.py | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index f7285ed..7c01937 100644 --- a/.gitignore +++ b/.gitignore @@ -125,5 +125,3 @@ dmypy.json .pyre/ .vscode/ -.idea/ -data/ diff --git a/phys2denoise/metrics/chest_belt.py b/phys2denoise/metrics/chest_belt.py index 3f485ee..04d463c 100644 --- a/phys2denoise/metrics/chest_belt.py +++ b/phys2denoise/metrics/chest_belt.py @@ -1,10 +1,12 @@ +"""Denoising metrics for chest belt recordings.""" import numpy as np from scipy.interpolate import interp1d def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): - """ " + """ Implements the Respiratory Variance over Time as described in Birn et al. (2006). + Procedural choices influenced by RetroTS Parameters @@ -24,9 +26,7 @@ def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): ------- rvt: array_like calculated RVT and associated lags. - """ - timestep = 1 / samplerate # respiration belt timing time = np.array([i * timestep for i in range(len(belt_ts))]) From 2c109c32d1b72720f4b4852af8eb929f19812f65 Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Wed, 6 Jan 2021 22:48:42 -0500 Subject: [PATCH 07/13] change docstring to 'imperative style' as linter was complaining --- phys2denoise/metrics/chest_belt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phys2denoise/metrics/chest_belt.py b/phys2denoise/metrics/chest_belt.py index 04d463c..972992e 100644 --- a/phys2denoise/metrics/chest_belt.py +++ b/phys2denoise/metrics/chest_belt.py @@ -5,7 +5,7 @@ def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): """ - Implements the Respiratory Variance over Time as described in Birn et al. (2006). + Implements the Respiratory Variance over Time (Birn et al. (2006)). Procedural choices influenced by RetroTS From 46a496497ba6a981e7604e0061a9d5a3620b271a Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Wed, 6 Jan 2021 22:58:24 -0500 Subject: [PATCH 08/13] try imperative style again --- phys2denoise/metrics/chest_belt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phys2denoise/metrics/chest_belt.py b/phys2denoise/metrics/chest_belt.py index 972992e..a7005fc 100644 --- a/phys2denoise/metrics/chest_belt.py +++ b/phys2denoise/metrics/chest_belt.py @@ -5,7 +5,7 @@ def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): """ - Implements the Respiratory Variance over Time (Birn et al. (2006)). + Implement the Respiratory Variance over Time (Birn et al. (2006)). Procedural choices influenced by RetroTS From e1c667b992bb33e531a0b0cdc55590e371fc7d59 Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Mon, 18 Jan 2021 23:40:58 -0500 Subject: [PATCH 09/13] addressed comments --- phys2denoise/metrics/chest_belt.py | 4 ++-- phys2denoise/tests/test_rvt.py | 14 +++++++------- setup.cfg | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/phys2denoise/metrics/chest_belt.py b/phys2denoise/metrics/chest_belt.py index a7005fc..2b51504 100644 --- a/phys2denoise/metrics/chest_belt.py +++ b/phys2denoise/metrics/chest_belt.py @@ -5,7 +5,7 @@ def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): """ - Implement the Respiratory Variance over Time (Birn et al. (2006)). + Implement the Respiratory Variance over Time (Birn et al. 2006). Procedural choices influenced by RetroTS @@ -29,7 +29,7 @@ def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): """ timestep = 1 / samplerate # respiration belt timing - time = np.array([i * timestep for i in range(len(belt_ts))]) + time = np.arange(0, len(belt_ts)*timestep, timestep) peak_vals = belt_ts[peaks] trough_vals = belt_ts[troughs] peak_time = time[peaks] diff --git a/phys2denoise/tests/test_rvt.py b/phys2denoise/tests/test_rvt.py index f5c66d4..95b7c9b 100644 --- a/phys2denoise/tests/test_rvt.py +++ b/phys2denoise/tests/test_rvt.py @@ -1,9 +1,11 @@ import peakdet import numpy as np +import pytest from phys2denoise.metrics.chest_belt import rvt -def read_fake_phys(): +@pytest.fixture +def fake_phys(): f = 0.3 fs = 62.5 # sampling rate t = 300 @@ -15,16 +17,14 @@ def read_fake_phys(): return phys -def test_peakdet(): - phys = read_fake_phys() - phys = peakdet.operations.peakfind_physio(phys) +def test_peakdet(fake_phys): + phys = peakdet.operations.peakfind_physio(fake_phys) assert phys.troughs is not None assert phys.peaks is not None -def test_rvt(): - phys = read_fake_phys() - phys = peakdet.operations.peakfind_physio(phys) +def test_rvt(fake_phys): + phys = peakdet.operations.peakfind_physio(fake_phys) r = rvt(phys.data, phys.peaks, phys.troughs, samplerate=phys.fs) assert r is not None assert len(r) == 18750 diff --git a/setup.cfg b/setup.cfg index 0822bdb..7b64563 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,6 +44,7 @@ style = test = pytest >=5.3 pytest-cov + peakdet %(style)s all = %(duecredit)s From 7a7bc2fbcaca4700a5d04171a5a0975faa08440d Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Mon, 18 Jan 2021 23:48:32 -0500 Subject: [PATCH 10/13] added whitespace --- phys2denoise/metrics/chest_belt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phys2denoise/metrics/chest_belt.py b/phys2denoise/metrics/chest_belt.py index 2b51504..1098bed 100644 --- a/phys2denoise/metrics/chest_belt.py +++ b/phys2denoise/metrics/chest_belt.py @@ -29,7 +29,7 @@ def rvt(belt_ts, peaks, troughs, samplerate, lags=(0, 4, 8, 12)): """ timestep = 1 / samplerate # respiration belt timing - time = np.arange(0, len(belt_ts)*timestep, timestep) + time = np.arange(0, len(belt_ts) * timestep, timestep) peak_vals = belt_ts[peaks] trough_vals = belt_ts[troughs] peak_time = time[peaks] From d4fd563586d76207f4c21d8ff33986d0b1a8efd3 Mon Sep 17 00:00:00 2001 From: Ryan Lim Date: Thu, 25 Feb 2021 11:11:28 -0500 Subject: [PATCH 11/13] extracted fake phys --- phys2denoise/tests/conftest.py | 14 ++++++++++++++ phys2denoise/tests/test_rvt.py | 21 +++++---------------- 2 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 phys2denoise/tests/conftest.py diff --git a/phys2denoise/tests/conftest.py b/phys2denoise/tests/conftest.py new file mode 100644 index 0000000..1022b3e --- /dev/null +++ b/phys2denoise/tests/conftest.py @@ -0,0 +1,14 @@ +import numpy as np +import pytest + + +@pytest.fixture(scope="module") +def fake_phys(): + f = 0.3 + fs = 62.5 # sampling rate + t = 300 + samples = np.arange(t * fs) / fs + noise = np.random.normal(0, 0.5, len(samples)) + fake_phys = 10 * np.sin(2 * np.pi * f * samples) + noise + return fake_phys + diff --git a/phys2denoise/tests/test_rvt.py b/phys2denoise/tests/test_rvt.py index 95b7c9b..7923ac6 100644 --- a/phys2denoise/tests/test_rvt.py +++ b/phys2denoise/tests/test_rvt.py @@ -1,30 +1,19 @@ import peakdet -import numpy as np -import pytest from phys2denoise.metrics.chest_belt import rvt -@pytest.fixture -def fake_phys(): - f = 0.3 - fs = 62.5 # sampling rate - t = 300 - samples = np.arange(t * fs) / fs - noise = np.random.normal(0, 0.5, len(samples)) - fake_phys = 10 * np.sin(2 * np.pi * f * samples) + noise +def test_peakdet(fake_phys): phys = peakdet.Physio(fake_phys, fs=62.5) phys = peakdet.operations.filter_physio(phys, cutoffs=3, method="lowpass") - return phys - - -def test_peakdet(fake_phys): - phys = peakdet.operations.peakfind_physio(fake_phys) + phys = peakdet.operations.peakfind_physio(phys) assert phys.troughs is not None assert phys.peaks is not None def test_rvt(fake_phys): - phys = peakdet.operations.peakfind_physio(fake_phys) + phys = peakdet.Physio(fake_phys, fs=62.5) + phys = peakdet.operations.filter_physio(phys, cutoffs=3, method="lowpass") + phys = peakdet.operations.peakfind_physio(phys) r = rvt(phys.data, phys.peaks, phys.troughs, samplerate=phys.fs) assert r is not None assert len(r) == 18750 From b50277075af0953a97af1660e45e6fc4db364709 Mon Sep 17 00:00:00 2001 From: Kristina Zvolanek <54590158+kristinazvolanek@users.noreply.github.com> Date: Wed, 30 Nov 2022 09:39:28 -0600 Subject: [PATCH 12/13] Update chest_belt.py --- phys2denoise/metrics/chest_belt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phys2denoise/metrics/chest_belt.py b/phys2denoise/metrics/chest_belt.py index e6bb51e..85be77c 100644 --- a/phys2denoise/metrics/chest_belt.py +++ b/phys2denoise/metrics/chest_belt.py @@ -317,4 +317,4 @@ def respiratory_phase(resp, sample_rate, n_scans, slice_timings, t_r): phase_resp[:, i_slice] = phase_resp_crSlice - return phase_resp \ No newline at end of file + return phase_resp From 24515ca8f95486b072f5002577a156ba836d24cd Mon Sep 17 00:00:00 2001 From: smoia Date: Thu, 1 Dec 2022 18:22:07 +0100 Subject: [PATCH 13/13] Add back peakdet --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 031f8eb..a2f20fe 100644 --- a/setup.cfg +++ b/setup.cfg @@ -49,6 +49,7 @@ test = %(style)s pytest >=5.3 pytest-cov + peakdet coverage devtools = pre-commit