NeuroKit icon indicating copy to clipboard operation
NeuroKit copied to clipboard

'No R-peak detected' is not handled in ecg_quality

Open CeliaBenquet opened this issue 2 years ago • 5 comments

Description of the bug

Using ecg.ecg_quality, the function ecg.ecg_findpeaks is used. It works well for all signals but for a really noisy signal (hand-crafted signal using ecg.ecg_simulate, with artificial powerline noise on top of it - see image and data provided), it turns out that no peaks are detected, which leads to an empty list that is not handled properly in the rest of the code leading to all sorts of errors (IndexError, ValueError, ZeroDivisionError, ... errors obtained while modifying the code to handling the error).

Error obtained on original code:

NeuroKit/neurokit2/ecg/ecg_findpeaks.py", line 260, in _ecg_findpeaks_neurokit
    end_qrs = end_qrs[end_qrs > beg_qrs[0]]
IndexError: index 0 is out of bounds for axis 0 with size 0

To Reproduce

  1. Get the provided data (data.csv) in Material section: clean data obtained using nk.ecg_simulate() with heart rate of 110Hz and PowerlineNoise added on top of it (sinusoid of amplitude 50Hz, energy ratio of 977% of the initial clean signal)
  2. Use nk.ecg_quality() with sampling_rate=256
  3. See error

Expected behaviour

At least: I would expect the empty list to be handled so that the reported heart rate is 0 and quality is set to bad. At best: However, seeing the shape of the signal, I would expect the function ecg_findpeaks to spot the peaks but the quality algorithm to still be able to determine that the signal is noisy, based on its other SQIs.

Screenshots and material on the signal used for the bug

Shape of the signal on which the bug occurs Screen Shot 2021-11-16 at 12 06 53

Data to us to reproduce the bug (data used for plot above) data.csv

System Specifications

  • OS: Darwin ( 64bit)

  • Python: 3.9.7

  • NeuroKit2: 0.1.4.1

  • NumPy: 1.21.2

  • Pandas: 1.3.1

  • SciPy: 1.6.2

  • sklearn: 1.0.1

  • matplotlib: 3.4.2

CeliaBenquet avatar Nov 16 '21 11:11 CeliaBenquet

Hi 👋 Thanks for reaching out and opening your first issue here! We'll try to come back to you as soon as possible. ❤️ kenobi

welcome[bot] avatar Nov 16 '21 11:11 welcome[bot]

Hi @CeliaBenquet

Is your data.csv file the simulated signal? What was the method that you used with ecg_quality? I might be missing something here but using your instructions, I managed to run the pipeline quite smoothly without errors

ecg = pd.read_csv('data.csv')['ecg']
cleaned = nk.ecg_clean(ecg, sampling_rate=256)
quality = nk.ecg_quality(cleaned, sampling_rate=256, method='averageQRS')
nk.signal_plot([ecg, cleaned, quality], labels=['Original', 'Cleaned', 'Quality'])

Figure_1

and for method='zhao2018', running nk.ecg_quality(cleaned, sampling_rate=256, method='zhao2018') returns 'Unacceptable'

zen-juen avatar Nov 23 '21 03:11 zen-juen

Hi @zen-juen,

I used method='zhao2018'. I didn't have this line: cleaned = nk.ecg_clean(ecg, sampling_rate=256). I would like to evaluate the quality of the original signal and not the corresponding cleaned signal. When I run your snippet of code using ecg rather than cleaned with ecg_quality(), I also get the error described above.

CeliaBenquet avatar Nov 26 '21 10:11 CeliaBenquet

I see, thanks for clarifying! You're right in that the error is due to ecg_findpeaks rather than ecg_quality which requires the former to work in order to compute quality indices that vary based on heart rate (See zhao et al.). For ecg_findpeaks, the default method is 'neurokit' which identifies peaks by QRS complexes, which doesn't work because of the noisy signal. You can specify another method such as 'pantompkins' and pass the resultant rpeaks into ecg_quality to circumvent this issue:

ecg = pd.read_csv('data.csv')['ecg']
rpeaks = nk.ecg_findpeaks(ecg, method='pantompkins')
quality = nk.ecg_quality(ecg, sampling_rate=256, rpeaks=rpeaks, method='zhao2018')
quality
'Barely acceptable'

Hope this helps!

zen-juen avatar Nov 28 '21 03:11 zen-juen

This issue has been automatically marked as inactive because it has not had recent activity. It will eventually be closed if no further activity occurs.

stale[bot] avatar May 30 '22 21:05 stale[bot]

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

stale[bot] avatar Sep 08 '22 17:09 stale[bot]