Ejemplo n.º 1
0
def test_compute_qrs_frames_correlation(ecg_signal=ecg_signal,
                                        qrs_frames_none=qrs_frames_none,
                                        fs=fs):
    detectors = Detectors(fs)
    qrs_frames_swt = detectors.swt_detector(ecg_signal)
    qrs_frames_hamilton = bsp_ecg.hamilton_segmenter(
        signal=np.array(ecg_signal), sampling_rate=fs)[0]

    correlation_coefs = compute_qrs_frames_correlation(
        qrs_frames_1=qrs_frames_swt,
        qrs_frames_2=qrs_frames_hamilton,
        sampling_frequency=fs)

    assert isinstance(correlation_coefs, float)

    # test for qrs without length

    correlation_coefs_none_1 = compute_qrs_frames_correlation(
        qrs_frames_1=qrs_frames_none,
        qrs_frames_2=qrs_frames_hamilton,
        sampling_frequency=fs)

    assert correlation_coefs_none_1 == 0

    correlation_coefs_none_2 = compute_qrs_frames_correlation(
        qrs_frames_1=qrs_frames_swt,
        qrs_frames_2=qrs_frames_none,
        sampling_frequency=fs)

    assert correlation_coefs_none_2 == 0
Ejemplo n.º 2
0
def qsqi(ecg_signal: list, sampling_frequency: int) -> float:
    """Matching Degree of R Peak Detection

    Two R wave detection algorithms are compared with their respective number
    of R waves detected.

    * Hamilton
    * SWT (Stationary Wavelet Transform)

    Parameters
    ----------
    ecg_signal : list
        Input ECG signal
    sampling_frequency : list
        Input ecg sampling frequency

    Returns
    -------
    q_sqi_score : float

    """
    detectors = Detectors(sampling_frequency)
    qrs_frames_swt = detectors.swt_detector(ecg_signal)
    qrs_frames_hamilton = bsp_ecg.hamilton_segmenter(
        signal=np.array(ecg_signal), sampling_rate=sampling_frequency)[0]

    q_sqi_score = compute_qrs_frames_correlation(qrs_frames_hamilton,
                                                 qrs_frames_swt,
                                                 sampling_frequency)

    return q_sqi_score
Ejemplo n.º 3
0
def stationary_wavelet_transform_single(fields, record, save_path, sig, save=True):
    detectors = Detectors(fields['fs'])
    r_peaks = detectors.swt_detector(sig[:, 0])
    if save:
        save_prediction(r_peaks, record, save_path)
    else:
        return r_peaks
Ejemplo n.º 4
0
def heart_rate_variability(sample, lead, rpeak_method = 'string'):
    curdir = 'DATA\TrainData_FeatureExtraction'
    [all_data, header_data, BAD_LABELS] = data_read.data_files_load(curdir)

    data = all_data[sample][lead]

    """INITIALIZE DETECTOR CLASS WITH THE SAMPLING RATE:"""
    detectors = Detectors(500)

    """FIND RPEAK USING ONE OF THE METHODS BELOW--------------------"""

    if rpeak_method == 'hamilton' or rpeak_method == 'string':
        #Hamilton.
        r_peaks = detectors.hamilton_detector(data)

    elif rpeak_method == 'christov':
        #Christov
        r_peaks = detectors.christov_detector(data)

    elif rpeak_method == 'engelse':
        #Engelse and Zeelenberg
        r_peaks = detectors.engzee_detector(data)

    elif rpeak_method == 'pan':
        #Pan and Tompkins
        r_peaks = detectors.pan_tompkins_detector(data)

    elif rpeak_method == 'stationary_wavelet':
        #Stationary Wavelet Transform
        r_peaks = detectors.swt_detector(data)

    elif rpeak_method == 'two_moving_average':
        #Two Moving Average
        r_peaks = detectors.two_average_detector(data)

    #elif rpeak_method == 'matched_filter':
        #Matched Filter
        #go to pyhrv documentation to find the template file
        #r_peaks = detectors.matched_filter_detector(data,template_file)

    """COMPUTE NNI SERIES-------------------------------------------"""
    nn = nn_intervals(r_peaks) #nni seems to be off by a factor of 3
    print("\n\n", nn, "\n\n")

    """PLOT ECG/TACHOGRAM-------------------------------------------"""
    #plot_ecg(data, sampling_rate = 500)
    #tachogram(nn, sampling_rate = 500)

    """COMPUTE HRV--------------------------------------------------"""
    results = hrv(nn, None, None, 500)

    """COMPUTE HR PARAMETERS--(SOMETHING IS WRONG HERE BPM TOO HIGH)"""
    hr = heart_rate(nn)

    """COMPUTE FREQUENCY ANALYSIS-----------------------------------"""
    freq_results = results['fft_bands']

    return results, hr, freq_results
Ejemplo n.º 5
0
def detect_qrs_swt(ecg_data, fs):
    qrs_frames = []
    try:
        detectors = Detectors(fs)  # Explain why
        qrs_frames = detectors.swt_detector(ecg_data)
    except Exception:
        # raise ValueError("swt")
        print("Exception in detect_qrs_swt")
    return qrs_frames
        hrv_class = HRV(sitting_class.fs)

        if "e" in sys.argv[1]:
            ecg_channel_sitting = sitting_class.einthoven_II
            ecg_channel_maths = maths_class.einthoven_II
        elif "v" in sys.argv[1]:
            ecg_channel_sitting = sitting_class.cs_V2_V1
            ecg_channel_maths = maths_class.cs_V2_V1
        else:
            print(
                "Bad argument. Specify 'e' for Einthoven or 'v' for the Chest strap."
            )
            exit(1)

        r_peaks = detectors.swt_detector(ecg_channel_sitting)
        sitting_rr_sd.append(hrv_class.RMSSD(r_peaks, True))
        r_peaks = detectors.swt_detector(ecg_channel_maths)
        maths_rr_sd.append(hrv_class.RMSSD(r_peaks, True))

        sitting_error_rr = detectors.pan_tompkins_detector(ecg_channel_sitting)
        sitting_error_rr_sd.append(hrv_class.RMSSD(sitting_error_rr, True))

        maths_error_rr = detectors.pan_tompkins_detector(ecg_channel_maths)
        maths_error_rr_sd.append(hrv_class.RMSSD(maths_error_rr, True))

        maths_true_rr = maths_class.anno_cs
        maths_true_sd.append(hrv_class.RMSSD(maths_true_rr, True))

        sitting_true_rr = sitting_class.anno_cs
        sitting_true_sd.append(hrv_class.RMSSD(sitting_true_rr, True))
Ejemplo n.º 7
0
    def prep_data(self):
        """Function that:
        -Initializes ecgdetector class instance
        -Runs stationary wavelet transform peak detection
            -Implements 0.1-10Hz bandpass filter
            -DB3 wavelet transformation
            -Pan-Tompkins peak detection thresholding
        -Calculates RR intervals
        -Removes first peak if it is within median RR interval / 2 from start of window
        -Calculates average HR in the window
        -Determines if there are enough beats in the window to indicate a possible valid period
        """

        # Initializes Detectors class instance with sample rate
        detectors = Detectors(self.fs)

        # Runs peak detection on raw data ----------------------------------------------------------------------------
        # Uses ecgdetectors package -> stationary wavelet transformation + Pan-Tompkins peak detection algorithm
        self.r_peaks = list(detectors.swt_detector(unfiltered_ecg=self.filt_data))

        # List of peak indexes relative to start of data file (i = 0)
        self.output_r_peaks = [i + self.start_index for i in self.r_peaks]

        # Checks to see if there are enough potential peaks to correspond to correct HR range ------------------------
        # Requires number of beats in window that corresponds to ~40 bpm to continue
        # Prevents the math in the self.hr calculation from returning "valid" numbers with too few beats
        # i.e. 3 beats in 3 seconds (HR = 60bpm) but nothing detected for rest of epoch
        if len(self.r_peaks) >= np.floor(40/60*self.epoch_len):
            self.enough_beats = True

            n_beats = len(self.r_peaks)  # number of beats in window
            delta_t = (self.r_peaks[-1] - self.r_peaks[0]) / self.fs  # time between first and last beat, seconds
            self.hr = 60 * (n_beats-1) / delta_t  # average HR, bpm

        # Stops function if not enough peaks found to be a potential valid period
        # Threshold corresponds to number of beats in the window for a HR of 40 bpm
        if len(self.r_peaks) < np.floor(40/60*self.epoch_len):
            self.enough_beats = False
            self.valid_period = False
            return

        # Calculates RR intervals in seconds -------------------------------------------------------------------------
        for peak1, peak2 in zip(self.r_peaks[:], self.r_peaks[1:]):
            rr_interval = (peak2 - peak1) / self.fs
            self.delta_rr.append(rr_interval)

        # Approach 1: median RR characteristics ----------------------------------------------------------------------
        # Calculates median RR-interval in seconds
        median_rr = np.median(self.delta_rr)

        # Converts median_rr to samples
        self.median_rr = int(median_rr * self.fs)

        # Removes any peak too close to start/end of data section: affects windowing later on ------------------------
        # Peak removed if within median_rr/2 samples of start of window
        # Peak removed if within median_rr/2 samples of end of window
        for i, peak in enumerate(self.r_peaks):
            if peak < (self.median_rr/2 + 1) or (self.epoch_len*self.fs - peak) < (self.median_rr/2 + 1):
                self.removed_peak.append(self.r_peaks.pop(i))
                self.removal_indexes.append(i)

        # Removes RR intervals corresponding to
        if len(self.removal_indexes) != 0:
            self.delta_rr = [self.delta_rr[i] for i in range(len(self.r_peaks)) if i not in self.removal_indexes]

        # Calculates range of ECG voltage ----------------------------------------------------------------------------
        self.volt_range = max(self.raw_data) - min(self.raw_data)
Ejemplo n.º 8
0
import numpy as np
import matplotlib.pyplot as plt
import pathlib
from ecgdetectors import Detectors

current_dir = pathlib.Path(__file__).resolve()

example_dir = current_dir.parent / 'example_data' / 'ECG.tsv'
unfiltered_ecg_dat = np.loadtxt(example_dir)
unfiltered_ecg = unfiltered_ecg_dat[:, 0]
fs = 250

detectors = Detectors(fs)

#r_peaks = detectors.two_average_detector(unfiltered_ecg)
#r_peaks = detectors.matched_filter_detector(unfiltered_ecg)
r_peaks = detectors.swt_detector(unfiltered_ecg)
#r_peaks = detectors.engzee_detector(unfiltered_ecg)
#r_peaks = detectors.christov_detector(unfiltered_ecg)
#r_peaks = detectors.hamilton_detector(unfiltered_ecg)
#r_peaks = detectors.pan_tompkins_detector(unfiltered_ecg)

plt.figure()
plt.plot(unfiltered_ecg)
plt.plot(r_peaks, unfiltered_ecg[r_peaks], 'ro')
plt.title('Detected R-peaks')

plt.show()
Ejemplo n.º 9
0
def ecg_peaks(x, sfreq=1000, new_sfreq=1000, method='pan-tompkins',
              find_local=True, win_size=100):
    """A simple wrapper for many popular R peaks detectors algorithms.

    This function calls methods from the py-ecg-detectors [#]_ module.

    Parameters
    ----------
    x : list or 1d array-like
        The oxi signal.
    sfreq : int
        The sampling frequency. Default is set to 75 Hz.
    method : str
        The method used. Can be one of the following: 'hamilton', 'christov',
        'engelse-zeelenberg', 'pan-tompkins', 'wavelet-transform',
        'moving-average'.
    find_local : bool
        If *True*, will use peaks indexs to search for local peaks given the
        window size (win_size).
    win_size : int
        Size of the time window used by :py:func:`systole.utils.to_neighbour()`

    Returns
    -------
    peaks : 1d array-like
        Numpy array containing peaks index.
    resampled_signal : 1d array-like
        Signal resampled to the `new_sfreq` frequency.

    Notes
    -----
    This function will call the py-ecg-detectors package to perform R wave
    detection.

    .. warning :: This function will resample the signal to 1000 Hz.

    Examples
    --------
    >>> from systole import import_dataset
    >>> from systole.detection import ecg_peaks
    >>> signal_df = import_dataset()[:20*2000]
    >>> signal, peaks = ecg_peaks(signal_df.ecg.to_numpy(), method='hamilton',
    >>>                           sfreq=2000, find_local=True)
    >>> print(f'{sum(peaks)} peaks detected.')
    24 peaks detected.

    References
    ----------
    .. [#] Howell, L., Porr, B. Popular ECG R peak detectors written in
    python. DOI: 10.5281/zenodo.3353396
    """

    if isinstance(x, list):
        x = np.asarray(x)

    # Interpolate
    f = interp1d(np.arange(0, len(x)/sfreq, 1/sfreq),
                 x,
                 fill_value="extrapolate")
    time = np.arange(0, len(x)/sfreq, 1/new_sfreq)
    x = f(time)

    # Copy resampled signal for output
    resampled_signal = np.copy(x)

    detectors = Detectors(new_sfreq)

    if method == 'hamilton':
        peaks_idx = detectors.hamilton_detector(resampled_signal)
    elif method == 'christov':
        peaks_idx = detectors.christov_detector(resampled_signal)
    elif method == 'engelse-zeelenberg':
        peaks_idx = detectors.engzee_detector(resampled_signal)
    elif method == 'pan-tompkins':
        peaks_idx = detectors.pan_tompkins_detector(resampled_signal)
    elif method == 'wavelet-transform':
        peaks_idx = detectors.swt_detector(resampled_signal)
    elif method == 'moving-average':
        peaks_idx = detectors.two_average_detector(resampled_signal)
    else:
        raise ValueError(
            'Invalid method provided, should be: hamilton,',
            'christov, engelse-zeelenberg, pan-tompkins, wavelet-transform,',
            'moving-average')
    peaks = np.zeros(len(resampled_signal), dtype=bool)
    peaks[peaks_idx] = True

    if find_local is True:
        peaks = to_neighbour(resampled_signal, peaks, size=win_size)

    return resampled_signal, peaks
    if sitting_class.anno_cs_exists and maths_class.anno_cs_exists:
        subject.append(i)

        hrv_class = HRV(sitting_class.fs)

        if "e" in sys.argv[1]:
            ecg_channel = sitting_class.einthoven_II
        elif "v" in sys.argv[1]:
            ecg_channel = sitting_class.cs_V2_V1
        else:
            print(
                "Bad argument. Specify 'e' for Einthoven or 'v' for the Chest strap."
            )
            exit(1)

        r_peaks = detectors.swt_detector(ecg_channel)
        sitting_rr_sd.append(hrv_class.RMSSD(r_peaks, True))
        r_peaks = detectors.swt_detector(maths_class.cs_V2_V1)
        maths_rr_sd.append(hrv_class.RMSSD(r_peaks, True))

        sitting_error_rr = detectors.two_average_detector(ecg_channel)
        sitting_error_rr_sd.append(hrv_class.RMSSD(sitting_error_rr, True))

        maths_error_rr = detectors.two_average_detector(maths_class.cs_V2_V1)
        maths_error_rr_sd.append(hrv_class.RMSSD(maths_error_rr, True))

        maths_true_rr = maths_class.anno_cs
        maths_true_sd.append(hrv_class.RMSSD(maths_true_rr, True))

        sitting_true_rr = sitting_class.anno_cs
        sitting_true_sd.append(hrv_class.RMSSD(sitting_true_rr, True))
Ejemplo n.º 11
0
# all_methods = [res1, res2]
# for peaks in all_methods:
#     peaks = peaks[np.argmax(peaks>plot_begin):np.argmax(peaks>plot_end)]
#     x = peaks*fs-plot_begin*fs
#     y = ecg[(peaks*fs).astype(int)]
#     plt.scatter(x, y)
# plt.legend(['ECG', 'Kubios','XQRS'])
stop
#%%
for p in tqdm(ss):
    fs = p.ecg.sampleRate
    sig = p.ecg.get_data('ecg').squeeze()
    r_true = p.get_RR(offset=False)[0]

    detectors = Detectors(fs)
    r_pred = np.array(detectors.swt_detector(sig))/fs
    dist, idxs = compare(r_true, r_pred)

    x, c = np.unique(np.round(dist, 3), return_counts=True)
    most_freq = x[np.argmax(c)]

    print(f'swt : {int(most_freq*1000)}ms')
    plt.figure()
    plt.hist(dist, 100)
    plt.title('swt')
    plt.xlim(0,0.4)
    plt.xlabel('diff in sec')
    plt.ylabel('count')

Ejemplo n.º 12
0
def run_algo(algorithm: str, sig: numpy.ndarray,
             freq_sampling: int) -> List[int]:
    """
    run a qrs detector on a signal

    :param algorithm: name of the qrs detector to use
    :type algorithm: str
    :param sig: values of the sampled signal to study
    :type sig: ndarray
    :param freq_sampling: value of sampling frequency of the signal
    :type freq_sampling: int
    :return: localisations of qrs detections
    :rtype: list(int)
    """
    detectors = Detectors(freq_sampling)
    if algorithm == 'Pan-Tompkins-ecg-detector':
        qrs_detections = detectors.pan_tompkins_detector(sig)
    elif algorithm == 'Hamilton-ecg-detector':
        qrs_detections = detectors.hamilton_detector(sig)
    elif algorithm == 'Christov-ecg-detector':
        qrs_detections = detectors.christov_detector(sig)
    elif algorithm == 'Engelse-Zeelenberg-ecg-detector':
        qrs_detections = detectors.engzee_detector(sig)
    elif algorithm == 'SWT-ecg-detector':
        qrs_detections = detectors.swt_detector(sig)
    elif algorithm == 'Matched-filter-ecg-detector' and freq_sampling == 360:
        qrs_detections = detectors.matched_filter_detector(
            sig, 'templates/template_360hz.csv')
    elif algorithm == 'Matched-filter-ecg-detector' and freq_sampling == 250:
        qrs_detections = detectors.matched_filter_detector(
            sig, 'templates/template_250hz.csv')
    elif algorithm == 'Two-average-ecg-detector':
        qrs_detections = detectors.two_average_detector(sig)
    elif algorithm == 'Hamilton-biosppy':
        qrs_detections = bsp_ecg.ecg(signal=sig,
                                     sampling_rate=freq_sampling,
                                     show=False)[2]
    elif algorithm == 'Christov-biosppy':
        order = int(0.3 * freq_sampling)
        filtered, _, _ = bsp_tools.filter_signal(signal=sig,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=order,
                                                 frequency=[3, 45],
                                                 sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.christov_segmenter(signal=filtered,
                                             sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=freq_sampling,
                                         tol=0.05)
        _, qrs_detections = bsp_ecg.extract_heartbeats(
            signal=filtered,
            rpeaks=rpeaks,
            sampling_rate=freq_sampling,
            before=0.2,
            after=0.4)
    elif algorithm == 'Engelse-Zeelenberg-biosppy':
        order = int(0.3 * freq_sampling)
        filtered, _, _ = bsp_tools.filter_signal(signal=sig,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=order,
                                                 frequency=[3, 45],
                                                 sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.engzee_segmenter(signal=filtered,
                                           sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=freq_sampling,
                                         tol=0.05)
        _, qrs_detections = bsp_ecg.extract_heartbeats(
            signal=filtered,
            rpeaks=rpeaks,
            sampling_rate=freq_sampling,
            before=0.2,
            after=0.4)
    elif algorithm == 'Gamboa-biosppy':
        order = int(0.3 * freq_sampling)
        filtered, _, _ = bsp_tools.filter_signal(signal=sig,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=order,
                                                 frequency=[3, 45],
                                                 sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.gamboa_segmenter(signal=filtered,
                                           sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=freq_sampling,
                                         tol=0.05)
        _, qrs_detections = bsp_ecg.extract_heartbeats(
            signal=filtered,
            rpeaks=rpeaks,
            sampling_rate=freq_sampling,
            before=0.2,
            after=0.4)
    elif algorithm == 'mne-ecg':
        qrs_detections = mne_ecg.qrs_detector(freq_sampling, sig)
    elif algorithm == 'heartpy':
        rol_mean = rolling_mean(sig, windowsize=0.75, sample_rate=100.0)
        qrs_detections = hp_pkdetection.detect_peaks(
            sig, rol_mean, ma_perc=20, sample_rate=100.0)['peaklist']
    elif algorithm == 'gqrs-wfdb':
        qrs_detections = processing.qrs.gqrs_detect(sig=sig, fs=freq_sampling)
    elif algorithm == 'xqrs-wfdb':
        qrs_detections = processing.xqrs_detect(sig=sig, fs=freq_sampling)
    else:
        raise ValueError(
            f'Sorry... unknown algorithm. Please check the list {algorithms_list}'
        )
    cast_qrs_detections = [int(element) for element in qrs_detections]
    return cast_qrs_detections
Ejemplo n.º 13
0
    def ecg_detector(self, s, detector_type="pan_tompkins"):
        """
        Expose

        ECG peak detector from the github
        https://github.com/berndporr/py-ecg-detectors

        Parameters
        ----------
        s :
            Input signal

        fs:
            The signal frequency. Default is '256 Hz'

        detector_type:
            'hamilton': Open Source ECG Analysis Software Documentation,
            E.P.Limited, 2002.

            'christov':Real time electrocardiogram QRS detection using combined
            adaptive threshold

            'engzee': A single scan algorithm for QRS detection and
            feature extraction

            'swt': Real-time QRS detector using Stationary Wavelet Transform
            for Automated ECG Analysis.
            Uses the Pan and Tompkins thresolding.

            'mva': Frequency Bands Effects on QRS Detection.

            'mtemp':

            'pan_tompkins': A Real-Time QRS Detection Algorithm

            Default = 'pan_tompkins'


        Returns
        -------
        type
            an array of 1-D numpy array represent the peak list

        """
        if self.wave_type == 'ppg':
            warnings.warn("A ECG detectors is using on PPG waveform. "
                          "Output may produce incorrect result")
        detector = Detectors(self.fs)
        if detector_type == 'hamilton':
            res = detector.hamilton_detector(s)
        elif detector_type == 'christov':
            res = detector.christov_detector(s)
        elif detector_type == 'engzee':
            res = detector.engzee_detector(s)
        elif detector_type == 'swt':
            res = detector.swt_detector(s)
        elif detector_type == 'mva':
            res = detector.two_average_detector(s)
        elif detector_type == 'mtemp':
            res = self.matched_filter_detector(s)
        else:
            res = detector.pan_tompkins_detector(s)
        return np.array(res)