Пример #1
0
def gqrs_detect(sig: np.ndarray, fs: Real, **kwargs) -> np.ndarray:
    """
    default kwargs:
        d_sig=None, adc_gain=None, adc_zero=None,
        threshold=1.0, hr=75, RRdelta=0.2, RRmin=0.28, RRmax=2.4,
        QS=0.07, QT=0.35, RTmin=0.25, RTmax=0.33,
        QRSa=750, QRSamin=130
    """
    kw = dict(d_sig=None,
              adc_gain=None,
              adc_zero=None,
              threshold=1.0,
              hr=75,
              RRdelta=0.2,
              RRmin=0.28,
              RRmax=2.4,
              QS=0.07,
              QT=0.35,
              RTmin=0.25,
              RTmax=0.33,
              QRSa=750,
              QRSamin=130)
    kw = {k: kwargs.get(k, v) for k, v in kw.items()}
    rpeaks = _gqrs_detect(sig, fs, **kw)
    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
Пример #2
0
def ssf_detect(sig:np.ndarray, fs:Real, **kwargs) -> np.ndarray:
    """

    Slope Sum Function (SSF)

    might be too simple

    References:
    -----------
    [1] Zong, W., et al. "An open-source algorithm to detect onset of arterial blood pressure pulses." Computers in Cardiology, 2003. IEEE, 2003.
    """
    rpeaks, = BSE.ssf_segmenter(
        signal=sig, sampling_rate=fs,
        threshold=kwargs.get("threshold", 20),
        before=kwargs.get("before", 0.03),
        after=kwargs.get("after", 0.01),
    )
    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
Пример #3
0
def get_rpeaks(ecg):
    """ function: get_rpeaks

    returns an array of indices of the r peaks in a given ecg

    Args:
        ecg : np.ndarray
            an ecg
    Returns:
        rpeaks : np.ndarray
            an array of indices of the r peaks
    """
    try:
        ecg = ecg[:, 0]
    except:
        pass

    filtered, _, _ = biosppy_tools.filter_signal(signal=ecg,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=150,
                                                 frequency=[3, 45],
                                                 sampling_rate=500)
    rpeaks, = biosppy_ecg.hamilton_segmenter(signal=filtered,
                                             sampling_rate=500)
    # correct R-peak locations
    rpeaks, = biosppy_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=500,
                                         tol=0.05)

    return np.array(rpeaks)
Пример #4
0
def feature_extraction(recording, signal, labels):
    data = []
    for i in tqdm(range(len(labels)), desc=recording, file=sys.stdout):
        segment = signal[i * fs * 60:(i + 1) * fs * 60]
        segment, _, _ = st.filter_signal(segment,
                                         ftype='FIR',
                                         band='bandpass',
                                         order=int(0.3 * fs),
                                         frequency=[3, 45],
                                         sampling_rate=fs)
        # Finding R peaks
        rpeaks, = hamilton_segmenter(segment, sampling_rate=fs)
        rpeaks, = correct_rpeaks(segment, rpeaks, sampling_rate=fs, tol=0.1)
        # Extracting feature
        label = 0 if labels[i] == "N" else 1
        if 40 <= len(rpeaks) <= 200:  # Remove abnormal R peaks
            rri_tm, rri = rpeaks[1:] / float(fs), np.diff(rpeaks,
                                                          axis=-1) / float(fs)
            rri = medfilt(rri, kernel_size=3)
            edr_tm, edr = rpeaks / float(fs), segment[rpeaks]
            # Remove physiologically impossible HR signal
            if np.all(np.logical_and(60 / rri >= hr_min, 60 / rri <= hr_max)):
                rri_time_features, rri_frequency_features = time_domain(
                    rri * 1000), frequency_domain(rri, rri_tm)
                edr_frequency_features = frequency_domain(edr, edr_tm)
                # 6 + 6 + 6 + 1 = 19
                data.append([
                    rri_time_features["rmssd"], rri_time_features["sdnn"],
                    rri_time_features["nn50"], rri_time_features["pnn50"],
                    rri_time_features["mrri"], rri_time_features["mhr"],
                    rri_frequency_features["vlf"] /
                    rri_frequency_features["total_power"],
                    rri_frequency_features["lf"] /
                    rri_frequency_features["total_power"],
                    rri_frequency_features["hf"] /
                    rri_frequency_features["total_power"],
                    rri_frequency_features["lf_hf"],
                    rri_frequency_features["lfnu"],
                    rri_frequency_features["hfnu"],
                    edr_frequency_features["vlf"] /
                    edr_frequency_features["total_power"],
                    edr_frequency_features["lf"] /
                    edr_frequency_features["total_power"],
                    edr_frequency_features["hf"] /
                    edr_frequency_features["total_power"],
                    edr_frequency_features["lf_hf"],
                    edr_frequency_features["lfnu"],
                    edr_frequency_features["hfnu"], label
                ])
            else:
                data.append([np.nan] * 18 + [label])
        else:
            data.append([np.nan] * 18 + [label])
    data = np.array(data, dtype="float")
    return data
Пример #5
0
 def __init__(self, sig, fs=250.0):
     assert len(sig.shape) == 1, 'The signal must be 1-dimension.'
     assert sig.shape[0] >= fs * 6, 'The signal must >= 6 seconds.'
     self.sig = utils.WTfilt_1d(sig)
     self.fs = fs
     self.rpeaks, = ecg.hamilton_segmenter(signal=self.sig,
                                           sampling_rate=self.fs)
     self.rpeaks, = ecg.correct_rpeaks(signal=self.sig,
                                       rpeaks=self.rpeaks,
                                       sampling_rate=self.fs)
     self.RR_intervals = np.diff(self.rpeaks)
     self.dRR = np.diff(self.RR_intervals)
Пример #6
0
def christov_detect(sig:np.ndarray, fs:Real, **kwargs) -> np.ndarray:
    """

    References:
    -----------
    [1] Ivaylo I. Christov, "Real time electrocardiogram QRS detection using combined adaptive threshold", BioMedical Engineering OnLine 2004, vol. 3:28, 2004
    """
    rpeaks, = BSE.christov_segmenter(signal=sig, sampling_rate=fs)
    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
Пример #7
0
def pantompkins(sig:np.ndarray, fs:Real, **kwargs) -> np.ndarray:
    """ to keep in accordance of parameters with `xqrs` and `gqrs`
    
    References:
    -----------
    [1] Pan, Jiapu, and Willis J. Tompkins. "A real-time QRS detection algorithm." IEEE transactions on biomedical engineering 3 (1985): 230-236.
    """
    rpeaks = _pantompkins(sig, fs)
    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
Пример #8
0
def xqrs_detect(sig:np.ndarray, fs:Real, **kwargs) -> np.ndarray:
    """
    default kwargs:
        sampfrom=0, sampto='end', conf=None, learn=True, verbose=True
    """
    kw = dict(sampfrom=0, sampto='end', conf=None, learn=True, verbose=False)
    kw = {k: kwargs.get(k,v) for k,v in kw.items()}
    rpeaks = _xqrs_detect(sig, fs, **kw)
    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
Пример #9
0
def filter_signal(signal, sampling_rate):
    order = int(0.3 * sampling_rate)
    filtered, _, _, = ecg.st.filter_signal(signal=signal,
                                           ftype='FIR',
                                           band='bandpass',
                                           order=order,
                                           frequency=[3, 45],
                                           sampling_rate=sampling_rate)
    rpeaks, = ecg.hamilton_segmenter(signal=filtered,
                                     sampling_rate=sampling_rate)
    rpeaks_corrected, = ecg.correct_rpeaks(signal=filtered,
                                           rpeaks=rpeaks,
                                           sampling_rate=sampling_rate,
                                           tol=0.05)
    rpeaks = peaks_to_series(signal, rpeaks)
    rpeaks_corrected = peaks_to_series(signal, rpeaks_corrected)
    return filtered, rpeaks_corrected
Пример #10
0
def hamilton_detect(sig: np.ndarray, fs: Real, **kwargs) -> np.ndarray:
    """

    References
    ----------
    [1] Hamilton, Pat. "Open source ECG analysis." Computers in cardiology. IEEE, 2002.
    """
    # segment
    rpeaks, = BSE.hamilton_segmenter(signal=sig, sampling_rate=fs)

    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
def worker(name, labels):
    print("processing %s!" % name)
    X = []
    y = []
    groups = []
    signals = wfdb.rdrecord(os.path.join(base_dir, name),
                            channels=[0]).p_signal[:, 0]  # Read recording
    for j in range(len(labels)):
        if j < before or \
                (j + 1 + after) > len(signals) / float(sample):
            continue
        signal = signals[int((j - before) * sample):int((j + 1 + after) *
                                                        sample)]
        signal, _, _ = st.filter_signal(
            signal,
            ftype='FIR',
            band='bandpass',
            order=int(0.3 * fs),
            frequency=[3, 45],
            sampling_rate=fs)  # Filtering the ecg signal to remove noise
        # Find R peaks
        rpeaks, = hamilton_segmenter(signal,
                                     sampling_rate=fs)  # Extract R-peaks
        rpeaks, = correct_rpeaks(signal,
                                 rpeaks=rpeaks,
                                 sampling_rate=fs,
                                 tol=0.1)
        if len(rpeaks) / (1 + after + before) < 40 or \
                len(rpeaks) / (1 + after + before) > 200:  # Remove abnormal R peaks signal
            continue
        # Extract RRI, Ampl signal
        rri_tm, rri_signal = rpeaks[1:] / float(fs), np.diff(rpeaks) / float(
            fs)
        rri_signal = medfilt(rri_signal, kernel_size=3)
        ampl_tm, ampl_siganl = rpeaks / float(fs), signal[rpeaks]
        hr = 60 / rri_signal
        # Remove physiologically impossible HR signal
        if np.all(np.logical_and(hr >= hr_min, hr <= hr_max)):
            # Save extracted signal
            X.append([(rri_tm, rri_signal), (ampl_tm, ampl_siganl)])
            y.append(0. if labels[j] == 'N' else 1.)
            groups.append(name)
    print("over %s!" % name)
    return X, y, groups
Пример #12
0
def gamboa_detect(sig:np.ndarray, fs:Real, **kwargs) -> np.ndarray:
    """

    References:
    -----------
    [1] Gamboa, Hugo. "Multi-modal behavioral biometrics based on HCI and electrophysiology." PhD ThesisUniversidade (2008).
    """
    rpeaks, = BSE.gamboa_segmenter(
        signal=sig, sampling_rate=fs,
        tol=kwargs.get("tol", 0.48),
    )
    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
Пример #13
0
def engzee_detect(sig:np.ndarray, fs:Real, **kwargs) -> np.ndarray:
    """

    References:
    -----------
    [1] W. Engelse and C. Zeelenberg, "A single scan algorithm for QRS detection and feature extraction", IEEE Comp. in Cardiology, vol. 6, pp. 37-42, 1979
    [2] A. Lourenco, H. Silva, P. Leite, R. Lourenco and A. Fred, "Real Time Electrocardiogram Segmentation for Finger Based ECG Biometrics", BIOSIGNALS 2012, pp. 49-54, 2012
    """
    rpeaks, = BSE.engzee_segmenter(
        signal=sig, sampling_rate=fs,
        threshold=kwargs.get("threshold", 0.48),
    )
    # correct R-peak locations
    rpeaks, = BSE.correct_rpeaks(
        signal=sig,
        rpeaks=rpeaks,
        sampling_rate=fs,
        tol=kwargs.get("correct_tol", 0.05),
    )
    return rpeaks
Пример #14
0
def feature_extraction(x):
    X = []

    [ts, filtered_sig, rpeaks, temp_ts, temp, hr_ts,
     heart_rate] = ecg.ecg(signal=x, sampling_rate=300, show=False)
    rpeaks = ecg.correct_rpeaks(signal=x,
                                rpeaks=rpeaks,
                                sampling_rate=300,
                                tol=0.1)

    peaks = x[rpeaks]
    if len(heart_rate) < 2:
        heart_rate = [0, 1]
    if len(hr_ts) < 2:
        hr_ts = [0, 1]

    X.append(np.median(peaks))
    X.append(np.min(peaks))
    X.append(np.max(peaks))
    X.append(np.median(np.diff(rpeaks)))
    X.append(np.min(np.diff(rpeaks)))
    X.append(np.max(np.diff(rpeaks)))
    X.append(np.std(np.diff(rpeaks)))
    X.append(np.median(heart_rate))
    X.append(np.min(heart_rate))
    X.append(np.max(heart_rate))
    X.append(np.median(np.diff(heart_rate)))
    X.append(np.min(np.diff(heart_rate)))
    X.append(np.max(np.diff(heart_rate)))
    X.append(np.std(np.diff(heart_rate)))
    X.append(np.min(np.diff(hr_ts)))
    X.append(np.max(np.diff(hr_ts)))
    X.append(np.std(np.diff(hr_ts)))

    #    X += list(np.median(temp, axis=0))
    #    X += list(np.min(temp, axis=0))
    #    X += list(np.max(temp, axis=0))

    return np.array(X)
Пример #15
0
def offline_rr_interval_orignal(signal, fs=200):  # 逐波心率(bmp),原始
    ecg_signal = np.array(signal)
    sampling_rate = fs
    sampling_rate = float(sampling_rate)

    # filter signal
    order = int(0.3 * sampling_rate)
    filtered, _, _ = st.filter_signal(signal=ecg_signal,
                                      ftype='FIR',
                                      band='bandpass',
                                      order=order,
                                      frequency=[5, 30],
                                      sampling_rate=sampling_rate)

    rpeaks, = eecg.hamilton_segmenter(signal=filtered, sampling_rate=sampling_rate)
    # correct R-peak locations
    rpeaks, = eecg.correct_rpeaks(signal=filtered,
                                  rpeaks=rpeaks,
                                  sampling_rate=sampling_rate,
                                  tol=0.05)
    rpeaks_orignal = np.unique(rpeaks)
    rr_interval_orignal = np.diff(rpeaks_orignal)
    rpeaks_whithoutfirst = rpeaks_orignal[1:]
    rpeaks_whithoutfirst = rpeaks_orignal

    outlier = []
    for jk in range(len(rr_interval_orignal)):
        if rr_interval_orignal[jk] >= sampling_rate * 2 or rr_interval_orignal[jk] <= sampling_rate * 0.4:
            if filtered[rr_interval_orignal[jk]] >= filtered[rr_interval_orignal[jk-1]]:
                outlier.append(jk-1)
            else:
                outlier.append(jk)

    outlier.reverse()
    rr_interval_outlier = np.asarray(rr_interval_orignal)
    for jk1 in outlier:
        rr_interval_outlier = np.delete(rr_interval_outlier, jk1)
        rpeaks_whithoutfirst = np.delete(rpeaks_whithoutfirst, jk1)
    return rpeaks_whithoutfirst.tolist(), filtered
Пример #16
0
from frecg.tools import *
from frecg.ecg import *
from biosppy.signals.ecg import hamilton_segmenter, correct_rpeaks
import os

for root, dirs, files in os.walk("data_pasien/splitted/"):
    for file in files:
        dataset = splitted_file_load("data_pasien/splitted/%s" % file)
        summary = []
        for ecg_raw in dataset:
            filtered = filter_ecg(signal=ecg_raw, sampling_rate=250)
            #            r_peaks = getr_peaks(filtered)    # segment
            rpeaks, = hamilton_segmenter(signal=filtered, sampling_rate=250)
            r_peaks, = correct_rpeaks(signal=filtered,
                                      rpeaks=rpeaks,
                                      sampling_rate=250,
                                      tol=0.05)
            if (len(r_peaks) > 5):
                feature, predicted_beats, rr, hr, start_stop = classify_peaks(
                    r_peaks)
                summary.append(create_summary_minute(predicted_beats, rr, hr))
            else:
                summary.append([0, 0, 0, 0, 0, 0, 0, 0])

        print(file, "done")
        save_summary_tocsv(summary, 'result/' + file)
Пример #17
0
 def rinfo_correct(self, rpeaks=None, tolerance=0.05):
     """Get corrected ECG R peaks.
     """
     return ecg.correct_rpeaks(self.__ecg, rpeaks, self.__signal_rate,
                               tolerance)
Пример #18
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
Пример #19
0
def seq_lab_net_detect(sig: np.ndarray,
                       fs: Real,
                       correction: bool = False,
                       **kwargs) -> np.ndarray:
    """ finished, checked,

    use model of entry 0416 of CPSC2019,
    to detect R peaks in single-lead ECGs of arbitrary length

    NOTE: `sig` should have units in mV, NOT in μV!

    Parameters:
    -----------
    sig: ndarray,
        the (raw) ECG signal of arbitrary length, with units in mV
    fs: real number,
        sampling frequency of `sig`
    correction: bool, default False,
        if True, correct rpeaks to local maximum in a small nbh
        of rpeaks detected by DL model using `BSE.correct_rpeaks`
    kwargs: dict,
        optional key word arguments, including
        - verbose, int, default 0,
            print verbosity
        - batch_size, int, default None,
            batch size for feeding into the model

    NOTE:
    -----
    `rpeaks` might not always be the local maxima, e.g. in aVR lead,
    hence after `correction` using `BSE.correct_rpeaks`,
    the "corrected" position might NOT be correct

    Returns:
    --------
    rpeaks: ndarray,
        indices of rpeaks in `sig`

    References:
    -----------
    [1] Cai, Wenjie, and Danqin Hu. "QRS complex detection using novel deep learning neural networks." IEEE Access (2020).
    """
    verbose = kwargs.get("verbose", 0)
    batch_size = kwargs.get("batch_size", None)

    model_fs = 500
    model_granularity = 8  # 1/8 times of model_fs

    # pre-process
    sig_rsmp = _seq_lab_net_pre_process(sig, verbose=verbose)

    if fs != model_fs:
        sig_rsmp = resample_poly(sig_rsmp, up=model_fs, down=int(fs))

    max_single_batch_half_len = 10 * 60 * model_fs
    if len(sig_rsmp) > 2 * max_single_batch_half_len:
        if batch_size is None:
            batch_size = 64
        if verbose >= 1:
            print(
                f"the signal is too long, hence split into segments for parallel computing of batch size {batch_size}"
            )
    if batch_size is not None:
        model_input_len = 5000
        half_overlap_len = 256  # approximately 0.5s, should be divisible by `model_granularity`
        half_overlap_len_prob = half_overlap_len // model_granularity
        overlap_len = 2 * half_overlap_len
        forward_len = model_input_len - overlap_len

        n_segs, residue = divmod(len(sig_rsmp) - overlap_len, forward_len)
        if residue != 0:
            sig_rsmp = np.append(sig_rsmp, np.zeros((forward_len - residue, )))
            n_segs += 1

        n_batches = math.ceil(n_segs / batch_size)
        if verbose >= 2:
            print(f"number of batches = {n_batches}")

        prob = []
        segs = list(range(n_segs))
        for b_idx in range(n_batches):
            # b_start = b_idx * batch_size * forward_len
            b_start = b_idx * batch_size
            b_segs = segs[b_start:b_start + batch_size]
            b_input = np.vstack([
                sig_rsmp[idx * forward_len:idx * forward_len + model_input_len]
                for idx in b_segs
            ]).reshape((-1, model_input_len, 1))
            prob_cnn = CNN_MODEL.predict(b_input)
            prob_crnn = CRNN_MODEL.predict(b_input)
            b_prob = (prob_cnn[..., 0] + prob_crnn[..., 0]) / 2
            b_prob = b_prob[..., half_overlap_len_prob:-half_overlap_len_prob]
            prob += b_prob.flatten().tolist()
            if b_idx == 0:
                head_prob = (b_prob[0, :half_overlap_len_prob]).tolist()
            if b_idx == n_batches - 1:
                tail_prob = (b_prob[-1, -half_overlap_len_prob:]).tolist()
            if verbose >= 1:
                print(f"{b_idx+1}/{n_batches} batches", end="\r")
        # prob, output from the for loop,
        # is the array of probabilities for sig_rsmp[half_overlap_len: -half_overlap_len]
        prob = list(repeat(0, half_overlap_len_prob)) + prob + list(
            repeat(0, half_overlap_len_prob))
        # prob = head_prob + prob + tail_prob  # NOTE: head and tail might not be trustable
        prob = np.array(prob)
    else:
        prob_cnn = CNN_MODEL.predict(sig_rsmp.reshape((1, len(sig_rsmp), 1)))
        prob_crnn = CRNN_MODEL.predict(sig_rsmp.reshape((1, len(sig_rsmp), 1)))
        prob = ((prob_cnn + prob_crnn) / 2).squeeze()

    # prob --> qrs mask --> qrs intervals --> rpeaks
    rpeaks = _seq_lab_net_post_process(prob, 0.5, verbose=verbose)

    # convert from resampled positions to original positions
    rpeaks = (np.round((fs / model_fs) * rpeaks)).astype(int)
    rpeaks = rpeaks[np.where(rpeaks < len(sig))[0]]

    # adjust to the "true" rpeaks,
    # i.e. the max in a small nbh of each element in `rpeaks`
    if correction:
        rpeaks, = BSE.correct_rpeaks(
            signal=sig,
            rpeaks=rpeaks,
            sampling_rate=fs,
            tol=0.05,
        )
    return rpeaks
Пример #20
0
    def inference(
            self,
            input: Union[np.ndarray, Tensor],
            bin_pred_thr: float = 0.5,
            duration_thr: int = 4 * 16,
            dist_thr: Union[int, Sequence[int]] = 200,
            correction: bool = False) -> Tuple[np.ndarray, List[np.ndarray]]:
        """ finished, NOT checked,

        auxiliary function to `forward`, for CPSC2019,

        NOTE: each segment of input be better filtered using `_remove_spikes_naive`,
        and normalized to a suitable mean and std

        Parameters
        ----------
        input: ndarray or Tensor,
            input tensor, of shape (batch_size, channels, seq_len)
        bin_pred_thr: float, default 0.5,
            the threshold for making binary predictions from scalar predictions
        duration_thr: int, default 4*16,
            minimum duration for a "true" qrs complex, units in ms
        dist_thr: int or sequence of int, default 200,
            if is sequence of int,
            (0-th element). minimum distance for two consecutive qrs complexes, units in ms;
            (1st element).(optional) maximum distance for checking missing qrs complexes, units in ms,
            e.g. [200, 1200]
            if is int, then is the case of (0-th element).
        correction: bool, default False,
            if True, correct rpeaks to local maximum in a small nbh
            of rpeaks detected by DL model using `BSE.correct_rpeaks`

        Returns
        -------
        pred: ndarray,
            the array of scalar predictions
        rpeaks: list of ndarray,
            list of rpeak indices for each batch element
        """
        if torch.cuda.is_available():
            device = torch.device("cuda")
        else:
            device = torch.device("cpu")
        self.to(device)
        batch_size, channels, seq_len = input.shape
        if isinstance(input, np.ndarray):
            _input = torch.from_numpy(input).to(device)
        else:
            _input = input.to(device)
        pred = self.forward(_input)
        pred = self.sigmoid(pred)
        pred = pred.cpu().detach().numpy().squeeze(-1)

        # prob --> qrs mask --> qrs intervals --> rpeaks
        rpeaks = self._inference_post_process(pred=pred,
                                              bin_pred_thr=bin_pred_thr,
                                              duration_thr=duration_thr,
                                              dist_thr=dist_thr)

        if correction:
            rpeaks = [
                BSE.correct_rpeaks(
                    signal=b_input,
                    rpeaks=b_rpeaks,
                    sampling_rate=self.config.fs,
                    tol=0.05,
                )[0] for b_input, b_rpeaks in zip(
                    _input.detach().numpy().squeeze(1), rpeaks)
            ]

        return pred, rpeaks
Пример #21
0
    # low pass filter
    filtered = butter_lowpass_filter(signal, cutoff, sampling_rate, order)

    # detrend with a low-pass
    order = 20
    filtered -= filtfilt(
        [1] * order, [order],
        filtered)  # this is a very simple moving average filter

    # Rpeaks
    Rpeaks = engzee_segmenter(signal=filtered,
                              sampling_rate=sampling_rate,
                              threshold=0)['rpeaks']
    Rpeaks = correct_rpeaks(signal=filtered,
                            rpeaks=Rpeaks,
                            sampling_rate=sampling_rate,
                            tol=rpeak_tol)['rpeaks']

    # peak to peak intervals
    IBI = []
    for i in range(1, len(Rpeaks)):
        IBI.append(Rpeaks[i] - Rpeaks[i - 1])
    IBI = np.array(IBI) / sampling_rate
    IBI = correct(IBI, 3)

    # feautres for IBI
    target.append(RMS(IBI))
    target.append(IBI.mean())
    target.append(IBI.std())
    target.append(skew(IBI))
    target.append(kurtosis(IBI))
Пример #22
0
def feature_extraction(sample, sampling_rate=300):
    # Normalize raw signal
    signal = ecg.st.normalize(sample)['signal']

    # ensure numpy
    signal = np.array(signal)

    sampling_rate = float(sampling_rate)

    # filter signal
    order = int(0.3 * sampling_rate)
    filtered, _, _ = ecg.st.filter_signal(signal=signal,
                                          ftype='FIR',
                                          band='bandpass',
                                          order=order,
                                          frequency=[5, 15],
                                          sampling_rate=sampling_rate)

    # segment
    rpeaks, = ecg.hamilton_segmenter(signal=filtered,
                                     sampling_rate=sampling_rate)

    # correct R-peak locations
    rpeaks, = ecg.correct_rpeaks(signal=filtered,
                                 rpeaks=rpeaks,
                                 sampling_rate=sampling_rate,
                                 tol=0.05)

    templates, rpeaks = ecg.extract_heartbeats(signal=filtered,
                                               rpeaks=rpeaks,
                                               sampling_rate=sampling_rate,
                                               before=0.2,
                                               after=0.4)

    # get time vectors
    length = len(signal)
    T = (length - 1) / sampling_rate
    ts = np.linspace(0, T, length, endpoint=False)

    # Extract time domain measures
    rpeaks_time = ts[rpeaks]

    rr_intervals = extract_rr_intervals(rpeaks_time)
    rr_diffs = extract_rr_diffs(rr_intervals)
    bpm = get_bpm(rr_intervals)
    ibi = np.mean(rr_intervals)
    sdnn = np.std(rr_intervals)
    sdsd = np.std(rr_diffs)
    rmssd = np.sqrt(np.mean(rr_diffs**2))
    nn20 = np.sum([rr_diffs > 0.02]) / len(rr_diffs)
    nn50 = np.sum([rr_diffs > 0.05]) / len(rr_diffs)

    # QRS
    qpeaks = find_q_point(filtered, rpeaks)
    speaks = find_s_point(filtered, rpeaks)

    # Extract wavelet power
    power_spectrum = ecg.st.power_spectrum(filtered, 300)
    frequency = [power_spectrum['freqs'][0], power_spectrum['freqs'][-1]]
    wavelet_energie = ecg.st.band_power(power_spectrum['freqs'],
                                        power_spectrum['power'],
                                        frequency)['avg_power']

    # Amplitudes
    qamplitudes = filtered[qpeaks]
    ramplitudes = filtered[rpeaks]
    samplitudes = filtered[speaks]

    # QRS duration
    qrs_duration = ts[speaks] - ts[qpeaks]
    qrs_duration_diffs = extract_rr_diffs(qrs_duration)
    iqrs = np.mean(qrs_duration)
    sdqrs = np.std(qrs_duration)
    sdqrsdiffs = np.std(qrs_duration_diffs)
    rmssqrsdiffs = np.sqrt(np.mean(qrs_duration_diffs**2))

    extracted_features = [
        bpm, ibi, sdnn, sdsd, rmssd, nn20, nn50, wavelet_energie, iqrs, sdqrs,
        sdqrsdiffs, rmssqrsdiffs,
        np.median(qamplitudes),
        np.min(qamplitudes),
        np.max(qamplitudes),
        np.median(ramplitudes),
        np.min(ramplitudes),
        np.max(ramplitudes),
        np.median(samplitudes),
        np.min(samplitudes),
        np.max(samplitudes)
    ]
    return extracted_features
Пример #23
0
import biosppy.signals.ecg as bse
import numpy as np

#%% Train


data_train = pd.read_csv('Dropbox/MK/ETH MSc Statistics/Machine Learning/Advanced Machine Learning/exercises/project/task3/X_train.csv')
del data_train['id']

rpeaks_init = []
for i in range(0,data_train.shape[0]):
    rpeaks_init.append(bse.engzee_segmenter(signal=data_train.iloc[i,:].values, sampling_rate=300))
    
rpeaks_corrected = []
for i in range(0,data_train.shape[0]):
    rpeaks_corrected.append(bse.correct_rpeaks(signal=data_train.iloc[i,:].values, rpeaks=rpeaks_init[i][0], sampling_rate=300, tol=0.05))

heartbeats = []
for i in range(0,data_train.shape[0]):
    heartbeats.append(bse.extract_heartbeats(signal=data_train.iloc[i,:].values, rpeaks=rpeaks_corrected[i][0], sampling_rate=300, before=0.2, after=0.4)
)
    
R_peaks = []
for i in range(0,data_train.shape[0]):
    R = []
    for j in range(0,len(heartbeats[i][1])):
        R.append(heartbeats[i][1][j]) 
    R_peaks.append(np.array(R))
    
df = pd.DataFrame(R_peaks)
df.to_csv('R_train.csv', index=True, header=False)
Пример #24
0
logging.info("使用compare_segmentation对比算法结果与人工标记 ...")
tic = time.time()
eval_results = ecg.compare_segmentation(ann, rpeaks, fs, tol=0.02)
toc = time.time()
logging.info("完成. 用时: %f 秒. 返回结果类型为 %s ." % (toc - tic, str(type(eval_results))))

dict_results = eval_results.as_dict()
logging.info("********** 结果报告 *************")
logging.info("* 准确率(acc): %.3f *" % dict_results["acc"])
logging.info("* 总体表现(performance): %.3f *" % dict_results["performance"])
logging.info("*********************************")

correct_tol = 0.05
logging.info("使用correct_rpeaks校正R波位置, 最大校正范围 %.3f 秒 ..." % correct_tol)
tic = time.time()
rpeaks_correct = ecg.correct_rpeaks(signal, rpeaks, fs, tol=correct_tol)
toc = time.time()
logging.info("完成. 用时: %f 秒. 返回结果类型为 %s ." % (toc - tic,
                                             str(type(rpeaks_correct))))
rpeaks_correct = rpeaks_correct.as_dict()["rpeaks"]

logging.info("绘制部分R峰校正前后的位置 ...")
num_plot_samples = 3600
sig_plot = signal[:num_plot_samples]
rpeaks_plot = rpeaks[rpeaks <= num_plot_samples]
rpeaks_correct_plot = rpeaks_correct[rpeaks_correct <= num_plot_samples]
plt.figure()
plt.grid(True)
plt.plot(sig_plot, label="ECG")
plt.plot(rpeaks_plot, sig_plot[rpeaks_plot], "ro", label="rpeaks")
plt.plot(rpeaks_correct_plot, sig_plot[rpeaks_correct_plot], "b*", label="corrected rpeaks")