Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] Return an empty array rather than throwing an exception if no QRS dat… #1007

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion neurokit2/ecg/ecg_findpeaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ def _ecg_findpeaks_neurokit(
qrs = smoothgrad > gradthreshold
beg_qrs = np.where(np.logical_and(np.logical_not(qrs[0:-1]), qrs[1:]))[0]
end_qrs = np.where(np.logical_and(qrs[0:-1], np.logical_not(qrs[1:])))[0]

if len(beg_qrs) == 0:
return np.array([])

# Throw out QRS-ends that precede first QRS-start.
end_qrs = end_qrs[end_qrs > beg_qrs[0]]

Expand Down Expand Up @@ -500,6 +504,14 @@ def _ecg_findpeaks_zong(signal, sampling_rate=1000, cutoff=16, window=0.13, **kw
ret = np.pad(clt, (window_size - 1, 0), "constant", constant_values=(0, 0))
ret = np.convolve(ret, np.ones(window_size), "valid")

# Check that ret is at least as large as the window
if len(ret) < window_size:
warn(
f"The signal must be at least {window_size} samples long for peak detection with the Zong method. ",
category=NeuroKitWarning,
)
return np.array([])

for i in range(1, window_size):
ret[i - 1] = ret[i - 1] / i
ret[window_size - 1 :] = ret[window_size - 1 :] / window_size
Expand Down Expand Up @@ -635,7 +647,8 @@ def _ecg_findpeaks_christov(signal, sampling_rate=1000, **kwargs):
if len(RR) > 5:
RR.pop(0)
Rm = int(np.mean(RR))

if len(QRS) == 0:
return np.array([])
QRS.pop(0)
QRS = np.array(QRS, dtype="int")
return QRS
Expand Down Expand Up @@ -916,6 +929,9 @@ def _ecg_findpeaks_engzee(signal, sampling_rate=1000, **kwargs):
thi = False
thf = False

if len(r_peaks) == 0:
return np.array([])

r_peaks.pop(
0
) # removing the 1st detection as it 1st needs the QRS complex amplitude for the threshold
Expand Down Expand Up @@ -956,6 +972,12 @@ def running_mean(x, N):

# Eq. 1: First-order differencing difference
dn = np.append(filtered[1:], 0) - filtered

# If the signal is flat then return an empty array rather than error out
# with a divide by zero error.
if np.max(abs(dn)) == 0:
return np.array([])

# Eq. 2
dtn = dn / (np.max(abs(dn)))

Expand Down
13 changes: 13 additions & 0 deletions tests/tests_ecg_findpeaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import numpy as np
import pandas as pd
import pytest

# Trick to directly access internal functions for unit testing.
#
Expand All @@ -13,6 +14,7 @@
_ecg_findpeaks_MWA,
_ecg_findpeaks_peakdetect,
_ecg_findpeaks_hamilton,
_ecg_findpeaks_findmethod,
)


Expand All @@ -23,6 +25,17 @@ def _read_csv_column(csv_name, column):
csv_data = pd.read_csv(csv_path, header=None)
return csv_data[column].to_numpy()

#vgraph is not included because it currently causes CI to fail (issue 1007)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#vgraph is not included because it currently causes CI to fail (issue 1007)
#vgraph is not included because it currently causes CI to fail (issue #1009)

@pytest.mark.parametrize("method",["neurokit", "pantompkins", "nabian", "gamboa",
"slopesumfunction", "wqrs", "hamilton", "christov",
"engzee", "manikandan", "elgendi", "kalidas",
"martinez", "rodrigues",])
def test_ecg_findpeaks_all_methods_handle_empty_input(method):
method_func = _ecg_findpeaks_findmethod(method)
# The test here is implicit: no exceptions means that it passed,
# even if the output is nonsense.
_ = method_func(np.zeros(12*240), sampling_rate=240)


def test_ecg_findpeaks_MWA():
np.testing.assert_array_equal(
Expand Down
Loading