neuropsychology / NeuroKit

NeuroKit2: The Python Toolbox for Neurophysiological Signal Processing
https://neuropsychology.github.io/NeuroKit
MIT License
1.53k stars 410 forks source link

Extract respiratory rate (BPM) from ECG signal #902

Closed NikolaosSintoris closed 1 year ago

NikolaosSintoris commented 1 year ago

I am trying to extract repsiratory rate (RR) in Breaths Per Minute (BPM), from an ECG signal using neurokit2 library.

I can not find online, a code that someone actualy does this.

Can someone help me?

So far, I have coded the below, but I am not sure if this is correct:

# Get data

ecg = nk.data('ecg_1000hz.csv')

sampling_rate = 1000

# Visualize signal

nk.signal_plot(ecg)

method_name_lst = ["vangent2019", "sarkar2015", "charlton2016", "soni2019"]

# Clean an ECG signal to remove noise and improve peak-detection accuracy.

# Different cleaning method are implemented.

# Return: Vector containing the cleaned ECG signal.

cleaned_ecg = nk.ecg_clean(ecg_signal = ecg, sampling_rate = sampling_rate, method = "neurokit")

# Find R-peaks in an ECG signal using the specified method.

# The method accepts unfiltered ECG signals as input,

# although it is expected that a filtered (cleaned) ECG will result in better results

rpeaks, info = nk.ecg_peaks(cleaned_ecg, sampling_rate = sampling_rate)

# Calculate signal rate (per minute) from a series of peaks. It is a general function that works

# for any series of peaks (i.e., not specific to a particular type of signal). It is computed as

# ``60 / period``, where the period is the time between the peaks (see func:`.signal_period`).

# Return: A vector containing the rate (peaks per minute).

ecg_rate = nk.signal_rate(rpeaks, sampling_rate = sampling_rate, desired_length = len(rpeaks))

for method_name in method_name_lst:

    print("Method: {}\n".format(method_name))

    # Extract ECG-Derived Respiration (EDR), a proxy of a respiratory signal based on heart rate.

    # Return: A Numpy array containing the derived respiratory rate.

    # ????? Is this actually the respiratory signal ????

    resp_signal = nk.ecg_rsp(ecg_rate, sampling_rate = sampling_rate, method = method_name)

    #nk.signal_plot(resp_signal)

    # Clean a respiration signal

    # Return: Vector containing the cleaned respiratory signal.

    rsp_cleaned = nk.rsp_clean(resp_signal, sampling_rate = sampling_rate)

    # Find respiration rate

    # Return: Instantenous respiration rate.

    rsp_rate_onsets = nk.rsp_rate(rsp_cleaned, sampling_rate = sampling_rate, method = "trough")

    rsp_rate_xcorr = nk.rsp_rate(rsp_cleaned, sampling_rate = sampling_rate, method = "xcorr")

    # ??? Is this correct ????

    print("\tMean RR (Trough): {}\n".format(np.mean(rsp_rate_onsets)))

    print("\tMean RR (Xcorr): {}\n".format(np.mean(rsp_rate_xcorr)))
welcome[bot] commented 1 year ago

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

DominiqueMakowski commented 1 year ago

????? Is this actually the respiratory signal ????

"Yes", or a proxy of it derived from the existing modulation of heart rate by respiration. However, take that with a grain of salt as it is often quite different (especially the shape / amplitude) from the real RSP