Exemple #1
0
def predict_pac_pvc_bbbb(ecg, f=250):
    """
    Predict Apnea for all segments of ECG
    
    Parameters
    ----------
    ecg: array_like
        2D Array containing amplitude all segments of the ECG signal
        
    f: float, optional
        Number corresponding to the sampling frequency of the input signal,
        must be in Hertz
             
    Returns
    -------
    dict_all: Dictionary
        Dictionary of ECG beats and its corresponding PCA beats and predictions
        
    """

    window = int(f * 0.4)  #800ms beat
    ecg_new = baseline_correct(ecg, f)
    rpeaks = np.array(ecgsig.hamilton_segmenter(
        ecg_new, f)['rpeaks'])[2:-2]  #detect rpeaks from ecg
    beats = np.array([ecg_new[i - window:i + window] for i in rpeaks])
    pca = PCA(n_components=10)
    beats_new = pca.fit_transform(beats)
    beats_new = StandardScaler().fit_transform(beats_new)
    predictions = predict_pac_pvc_bbbb_per_beat(beats_new)
    dict_all = {}
    dict_all['beats'] = beats
    dict_all['PCA beats'] = beats_new
    dict_all['predictions'] = predictions
    return dict_all
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
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)
def csqi(ecg_signal: list, sampling_frequency: int) -> float:
    """Variability in the R-R Interval

    When an artifact is present, the QRS detector underperforms by either
    missing R-peaks or erroneously identifying noisy peaks as R- peaks. The
    above two problems will lead to a high degree of variability in the
    distribution of R-R intervals;

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

    Returns
    -------
    c_sqi_score : float

    """
    with np.errstate(invalid='raise'):

        try:

            rri_list = bsp_ecg.hamilton_segmenter(
                signal=np.array(ecg_signal),
                sampling_rate=sampling_frequency)[0]

            c_sqi_score = float(
                np.round(np.std(rri_list, ddof=1) / np.mean(rri_list), 3))

        except Exception:
            c_sqi_score = 0

        return c_sqi_score
def extract_r(ecg_detrend, fs=100):
    """ Extract R peaks from ECG data 
        ECG data should have the length around 1 minute to get a stable result

        Parameters
        ----------
        ecg_detrend: numpy array or list
            Detrended ECG data 
        fs: scalar
            Sampling frequency of ecg_detrend

        Returns
        -------
        r_idx: Index of R peaks for ecg_detrend
    """
    import biosppy.signals.ecg as ECG

    r_idx = list(ECG.christov_segmenter(ecg_detrend,
                                        fs))[0]  # Works fine in most cases
    # Assuming HR = 1 bps, check if half of the R peaks are detected
    if len(r_idx) < (len(ecg_detrend) / fs) / 2:
        r_idx_2 = list(ECG.hamilton_segmenter(
            ecg_detrend, fs))[0]  # Might return negative R peaks
        if len(r_idx_2) > len(r_idx):
            r_idx = r_idx_2
    return r_idx
Exemple #6
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
Exemple #7
0
def calculate_ratio(filepath):
  ecg_data = pd.read_csv(filepath, sep=',', error_bad_lines=False, lineterminator="\n")
  ecg_df = ecg_data['ekg'].apply(lambda line: (((int(line) / bitSize) - 0.5) * vccConst) / sensorGain) * 1000
  ecg_np_array = ecg_df.to_numpy()
  out = ecg.ecg(signal=ecg_np_array, sampling_rate=1000., show=False)
  ecg_r_peaks = ecg.hamilton_segmenter(signal=ecg_np_array)
  res = list(map(operator.sub, ecg_r_peaks[0][1:], ecg_r_peaks[0][:-1]))
  median = statistics.median(res)
  final_val = min(res)/median
  return final_val
Exemple #8
0
def detect_qrs_hamilton(ecg_data, fs):
    qrs_frames = []
    try:
        qrs_frames = bsp_ecg.hamilton_segmenter(signal=np.array(ecg_data),
                                                sampling_rate=fs)[0]

    except Exception:
        # raise ValueError("xqrs")
        print("Exception in detect_qrs_hamilton")
    return qrs_frames
Exemple #9
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
Exemple #10
0
def ex1_2_1_biosppy():
    filtered_ecg_signal = ecg_processing.ecg(ecg_signal, ecg_sf, show=False)['filtered']

    ecg_peak_indices = ecg_processing.hamilton_segmenter(ecg_signal, ecg_sf)['rpeaks']
    ecg_peak_times = ecg_peak_indices / ecg_sf

    plot_peaks(filtered_ecg_signal, ecg_times, ecg_peak_times, ecg_peak_indices, ecg_envelopes, ecg_label, 'hamilton', 'results_hamilton',
               (-150, 250))
    plot_peak_intervals(ecg_peak_times, ecg_label, 'hamilton', 'RRI', 'results_hamilton')

    """
Exemple #11
0
def extract_beats(data_path):
    data = loadmat("./ECGTestData/ECGTestData/" + data_path)['data'].T  # II导
    data = data[1:, :]  # 去除第一行index
    beats_matrix = []
    logging.info("--------------------------------------------------")
    logging.info("载入信号-%s, 长度 = %d " % (data_path, len(data[0])))
    min_beats = math.inf
    for i in DAOLIAN:
        signal = data[i]
        fs = 500  # 信号采样率 500 Hz
        # logging.info("调用 hamilton_segmenter 进行R波检测 ...")
        # tic = time.time()
        rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs)
        # toc = time.time()
        # logging.info("完成. 用时: %f 秒. " % (toc - tic))
        rpeaks = rpeaks[0]

        # heart_rate = 60 / (np.mean(np.diff(rpeaks)) / fs)
        # np.diff 计算相邻R峰之间的距离分别有多少个采样点,np.mean求平均后,除以采样率,
        # 将单位转化为秒,然后计算60秒内可以有多少个RR间期作为心率
        # logging.info("平均心率: %.3f / 分钟." % (heart_rate))

        win_before = 0.2
        win_after = 0.4
        # logging.info("根据R波位置截取心拍, 心拍前窗口:%.3f 秒 ~ 心拍后窗口:%.3f 秒 ..." % (win_before, win_after)) # rpeak全部落在100处
        # tic = time.time()
        beats, rpeaks_beats = ecg.extract_heartbeats(signal, rpeaks, fs,
                                                     win_before, win_after)
        # toc = time.time()
        # logging.info("完成. 用时: %f 秒." % (toc - tic))
        # logging.info("共截取到 %d 个心拍, 每个心拍长度为 %d 个采样点" % (beats.shape[0], beats.shape[1]))

        # plt.figure()
        # plt.grid(True)
        # for i in range(beats.shape[0]):
        #     plt.plot(beats[i])
        # plt.title(data_path)
        # plt.show()

        beats_matrix.append(beats)
        if len(beats) < min_beats:
            min_beats = len(beats)

    test_data = []
    for i in range(min_beats):
        tdata = []
        for j in range(len(DAOLIAN)):
            rbeats = denoise(beats_matrix[j][i])
            tdata.append(rbeats)
        test_data.append(tdata)

    test_data = np.array(test_data).flatten().reshape(-1, 300 * len(DAOLIAN),
                                                      1)
    return test_data
Exemple #12
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)
Exemple #13
0
def r_peak_detection(data, type='hamilton'):
    if type == 'hamilton':
        r_peaks_tuple = hamilton_segmenter(signal=data, sampling_rate=277)
        r_peaks_ind = r_peaks_tuple['rpeaks']
        r_peak_neighbourhood = 7
        # expected range of R peak (in samples)
        for i in xrange(len(r_peaks_ind)):
            start = np.maximum(r_peaks_ind[i] - r_peak_neighbourhood, 1)
            stop = np.minimum(r_peaks_ind[i] + r_peak_neighbourhood, len(data))
            ind = np.argmax(data[start:stop])
            r_peaks_ind[i] = start + ind
        r_peaks_val = data[r_peaks_ind]
    elif type == 'threshold':
        # R-peak detection
        r_threshold = 0.4
        temp_data = data * 1.0  # temporary data copy
        temp_data[temp_data <
                  r_threshold] = 0  # setting samples below threshold to zero

        r_segm_start = np.array([])
        r_segm_stop = np.array([])
        for i in xrange(len(temp_data) - 1):
            if temp_data[i] == 0 and temp_data[i + 1] != 0:
                r_segm_start = np.append(
                    r_segm_start,
                    i)  # start index for each segment above threshold
            if temp_data[i] != 0 and temp_data[i + 1] == 0:
                r_segm_stop = np.append(
                    r_segm_stop,
                    i)  # end index for each segment above threshold

        nPeaks = len(r_segm_start)
        nSamples = len(data)

        r_peaks_val = np.zeros(nPeaks)
        r_peaks_ind = np.zeros(nPeaks)

        # local maximums search
        for i in xrange(nPeaks):
            ind_start = int(r_segm_start[i])
            ind_stop = int(r_segm_stop[i])
            segm_mask = np.zeros(nSamples)
            segm_mask[ind_start:ind_stop] = 1
            temp_data = data * segm_mask
            val = temp_data.max()
            ind = int(temp_data.argmax())
            r_peaks_val[i] = val  # r-peak value
            r_peaks_ind[i] = int(ind)  # r-peak index

    return r_peaks_val, r_peaks_ind
Exemple #14
0
def QRS_detection(signal, fs):
    # R Peaks : P.S. Hamilton, "Open Source ECG Analysis Software Documentation", E.P.Limited, 2002
    rpeaks, = ecg.hamilton_segmenter(signal=signal, sampling_rate=fs)
    array = []
    for x in rpeaks:
        array.append(x)
    #plt.figure()
    #plt.plot(signal[1:1000])
    #for xc in array:
    #    if xc < 1000:
    #        plt.axvline(x=xc, color='red')
    #plt.show()

    return array
Exemple #15
0
def process_slice(record, subslice, threshold=15):
    time = (1 / record.fs) * np.arange(subslice.start, subslice.stop)

    for i in range(record.n_sig):
        signal = record.p_signal[subslice, i]
        rpeaks, = hamilton_segmenter(signal, record.fs)
        # out = ecg.ecg(signal=signal, sampling_rate=record.fs, show=False)
        try:
            rr_int = np.vstack(
                (rr_int, np.array(time[rpeaks[1:]] - time[rpeaks[:-1]])))
        except Exception:
            rr_int = np.array(time[rpeaks[1:]] - time[rpeaks[:-1]])
    rr_int = np.mean(rr_int, axis=0)
    hrv_perc = np.abs(np.round(100 * (rr_int / np.min(rr_int) - 1), 2))
    arrythmia = np.any(hrv_perc > threshold)
    return record.record_name, subslice.start, subslice.stop, arrythmia, rr_int.max(
    ), rr_int.min(), hrv_perc.max(), hrv_perc.min(), hrv_perc, rr_int
Exemple #16
0
def predict_apnea(ecg, f=100, segment_size=60):
    """
    Predict Apnea for all segments of ECG
    
    Parameters
    ----------
    ecg: array_like
        2D Array containing amplitude all segments of the ECG signal
        
    f: float, optional
        Number corresponding to the sampling frequency of the input signal,
        must be in Hertz
        
    segment_size: int, optional 
        Specifies segment length (15-sec, 30-sec, or 60-sec)
        
       
    Returns
    -------
    dict_all: Dictionary
        Dictionary of ECG segments and its corresponding predictions
        
    """

    window = int(f * segment_size)  #800ms beat
    ecg_wind = segment_ecg(ecg, segment_size=segment_size, f=f)
    rpeaks = np.array([
        ecgsig.hamilton_segmenter(i, f)['rpeaks'] for i in ecg_wind
    ])  #detect rpeaks from ecg
    RR_int = np.array([np.diff(i) for i in rpeaks])
    peak_count = np.array([len(i) for i in rpeaks])

    #remove segments without detectable rpeaks
    n_peaks = segment_size / 2
    ecg_wind = ecg_wind[np.where(peak_count > n_peaks)]
    RR_int = RR_int[np.where(peak_count > n_peaks)]
    rpeaks = rpeaks[np.where(peak_count > n_peaks)]
    peak_count_new = peak_count[np.where(peak_count > n_peaks)]
    #features
    X = calculate_features(ecg_wind, rpeaks, peak_count_new, RR_int, f=f)
    X_c = StandardScaler().fit_transform(X)
    predictions = predict_apnea_per_segment(X_c)
    dict_all = {}
    dict_all['ecg'] = ecg_wind
    dict_all['predictions'] = predictions
    return dict_all
Exemple #17
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
Exemple #18
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
def segmentation(data, label=None):
    inputs, labels = [], []
    for sap_id in range(len(data)):
        data_ref = denoise(copy.copy(data[sap_id][:, 9]))
        r_peaks = ecg.hamilton_segmenter(data_ref, 500).as_dict()['rpeaks']
        beats = np.hstack([
            ecg.extract_heartbeats(signal=denoise(
                copy.copy(data[sap_id][:, dao_id])),
                                   rpeaks=r_peaks,
                                   sampling_rate=500,
                                   before=0.2,
                                   after=0.4)["templates"]
            for dao_id in [1, 3, 6, 9]
        ])
        inputs.append(beats)
        if label: labels.append(np.full(beats.shape[0], label[sap_id]))
        # if label: labels.append(label[sap_id])
    if not label:
        return np.array(inputs, dtype=object)
    else:
        return np.vstack(inputs), np.hstack(labels)
Exemple #21
0
def r_peak_loc(x, fs):
    """
    Gives location of R peaks
    
    Parameters
    ----------
    x : array_like
        Array containing magnitudes of ECG signal

    fs: float
        Number corresponding to the sampling frequency of the input signal,
        must be in Hertz
    
    Returns
    -------
    rloc: array
        Array containing the R-peak locations in the array
        
    """
    rloc = ecgsig.hamilton_segmenter(x, fs)['rpeaks']
    return rloc
def calculate_features(signal):
  sampling_rate = 400
  ts, signal, rpeaks, templates_ts, templates, heart_rate_ts, heart_rates = ecg.ecg(signal=signal, sampling_rate=sampling_rate, show=False)
  rpeaks = ecg.hamilton_segmenter(signal=signal, sampling_rate=sampling_rate)[0]
  heartbeat_templates, heartbeat_rpeaks = ecg.extract_heartbeats(signal=signal, rpeaks=rpeaks, sampling_rate=sampling_rate)

  rpeaks_diff = np.diff(rpeaks)
  rpeaks_diff_diff = np.diff(rpeaks_diff)
  heartbeat_rpeaks_diff = np.diff(heartbeat_rpeaks)
  feature = ""

  mean_amplitude = np.mean(signal)
  std_amplitude = np.std(signal)
  max_amplitude = np.amax(signal)
  min_amplitude = np.amin(signal)
  median_amplitude = np.median(signal)
  feature = feature + str(mean_amplitude) + "," + str(std_amplitude) + "," + str(max_amplitude) + "," + str(min_amplitude) + "," + str(median_amplitude)

  mean_rpeaks_diff = np.mean(rpeaks_diff)
  std_rpeaks_diff = np.std(rpeaks_diff)
  median_rpeaks_diff = np.median(rpeaks_diff)
  feature = feature + "," + str(mean_rpeaks_diff) + "," + str(std_rpeaks_diff) + "," + str(median_rpeaks_diff)

  mean_rpeaks_diff_diff = np.mean(rpeaks_diff_diff)
  std_rpeaks_diff_diff = np.std(rpeaks_diff_diff)
  median_rpeaks_diff_diff = np.median(rpeaks_diff_diff)
  feature = feature + "," + str(mean_rpeaks_diff_diff) + "," + str(std_rpeaks_diff_diff) + "," + str(median_rpeaks_diff_diff)

  heartbeat_length = len(heartbeat_templates)
  mean_heart_rate = np.mean(heart_rates) if len(heart_rates) > 0 else 0.0
  std_heart_rate = np.std(heart_rates) if len(heart_rates) > 0 else 0.0
  median_heart_rate = np.median(heart_rates) if len(heart_rates) > 0 else 0.0
  feature = feature + "," + str(heartbeat_length) + "," + str(mean_heart_rate) + "," + str(std_heart_rate) + "," + str(median_heart_rate)

  mean_heartbeat_rpeaks_diff = np.mean(heartbeat_rpeaks_diff)
  std_heartbeat_rpeaks_diff = np.std(heartbeat_rpeaks_diff)
  median_heartbeat_rpeaks_diff = np.median(heartbeat_rpeaks_diff)
  feature = feature + "," + str(mean_heartbeat_rpeaks_diff) + "," + str(std_heartbeat_rpeaks_diff) + "," + str(median_heartbeat_rpeaks_diff)
  return feature
Exemple #23
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
Exemple #24
0
def test_extract_beats(data_path):
    signal, mdata = load_txt(data_path)
    logging.info("--------------------------------------------------")
    logging.info("载入信号-%s, 长度 = %d " % (data_path, len(signal)))
    fs = 360  # 信号采样率 360 Hz
    logging.info("调用 hamilton_segmenter 进行R波检测 ...")
    tic = time.time()
    rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs)
    toc = time.time()
    logging.info("完成. 用时: %f 秒. " % (toc - tic))
    rpeaks = rpeaks[0]

    heart_rate = 60 / (np.mean(np.diff(rpeaks)) / fs)
    # np.diff 计算相邻R峰之间的距离分别有多少个采样点,np.mean求平均后,除以采样率,
    # 将单位转化为秒,然后计算60秒内可以有多少个RR间期作为心率
    logging.info("平均心率: %.3f / 分钟." % (heart_rate))

    win_before = 0.2
    win_after = 0.4
    logging.info("根据R波位置截取心拍, 心拍前窗口:%.3f 秒 ~ 心拍后窗口:%.3f 秒 ..." \
                 % (win_before, win_after))
    tic = time.time()
    beats, rpeaks_beats = ecg.extract_heartbeats(signal, rpeaks, fs,
                                                 win_before, win_after)
    toc = time.time()
    logging.info("完成. 用时: %f 秒." % (toc - tic))
    logging.info("共截取到 %d 个心拍, 每个心拍长度为 %d 个采样点" % \
                 (beats.shape[0], beats.shape[1]))

    plt.figure()
    plt.grid(True)
    for i in range(beats.shape[0]):
        plt.plot(beats[i])
    plt.title(data_path)
    plt.show()
    return
Exemple #25
0
def test_rpeaks_simple(data_path):
    signal, mdata = load_txt(data_path)
    logging.info("--------------------------------------------------")
    logging.info("载入信号-%s, 长度 = %d " % (data_path, len(signal)))
    fs = 360  # 信号采样率 360 Hz
    logging.info("调用 christov_segmenter 进行R波检测 ...")
    tic = time.time()
    rpeaks = ecg.christov_segmenter(signal, sampling_rate=fs)
    toc = time.time()
    logging.info("完成. 用时: %f 秒. " % (toc - tic))
    # 以上这种方式返回的rpeaks类型为biosppy.utils.ReturnTuple, biosppy的内置类
    logging.info("直接调用 christov_segmenter 返回类型为 " + str(type(rpeaks)))

    # 得到R波位置序列的方法:
    # 1) 取返回值的第1项:
    logging.info("使用第1种方式取R波位置序列 ... ")
    rpeaks_indices_1 = rpeaks[0]
    logging.info("完成. 结果类型为 " + str(type(rpeaks_indices_1)))
    # 2) 调用ReturnTuple的as_dict()方法,得到Python有序字典(OrderedDict)类型
    logging.info("使用第2种方式取R波位置序列 ... ")
    rpeaks_indices_2 = rpeaks.as_dict()
    #    然后使用说明文档中的参数名(这里是rpeaks)作为key取值。
    rpeaks_indices_2 = rpeaks_indices_2["rpeaks"]
    logging.info("完成. 结果类型为 " + str(type(rpeaks_indices_2)))

    # 检验两种方法得到的结果是否相同:
    check_sum = np.sum(rpeaks_indices_1 == rpeaks_indices_2)
    if check_sum == len(rpeaks_indices_1):
        logging.info("两种取值方式结果相同 ... ")
    else:
        logging.info("两种取值方式结果不同,退出 ...")
        sys.exit(1)

    # 与 christov_segmenter 接口一致的还有 hamilton_segmenter
    logging.info("调用接口一致的 hamilton_segmenter 进行R波检测")
    tic = time.time()
    rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs)
    toc = time.time()
    logging.info("完成. 用时: %f 秒. " % (toc - tic))
    rpeaks_indices_3 = rpeaks.as_dict()["rpeaks"]
    # 绘波形图和R波位置
    num_plot_samples = 3600
    logging.info("绘制波形图和检测的R波位置 ...")
    sig_plot = signal[:num_plot_samples]
    rpeaks_plot_1 = rpeaks_indices_1[rpeaks_indices_1 <= num_plot_samples]
    plt.figure()
    plt.plot(sig_plot, "g", label="ECG")
    plt.grid(True)
    plt.plot(rpeaks_plot_1,
             sig_plot[rpeaks_plot_1],
             "ro",
             label="christov_segmenter")
    rpeaks_plot_3 = rpeaks_indices_3[rpeaks_indices_3 <= num_plot_samples]
    plt.plot(rpeaks_plot_3,
             sig_plot[rpeaks_plot_3],
             "b^",
             label="hamilton_segmenter")
    plt.legend()
    plt.title(data_path)
    plt.show()
    logging.info("完成.")
    return
Exemple #26
0
def get_rpeaks(signal, sampling_rate=360):
    signal = np.array(signal)
    filtered = filter_signal(signal)
    rpeaks, = hamilton_segmenter(signal=filtered, sampling_rate=sampling_rate)
    return rpeaks#[1:]
import numpy as np
import matplotlib as plt
import biosppy.signals.ecg as bio

samplrate = 3428 / 10
data = np.loadtxt('FilteredData/filtereddata3.txt')

rpeaks1 = bio.christov_segmenter(data, 342)
bio.ecg(data, 342, True)
rpeaks2 = bio.engzee_segmenter(data, 342)
rpeaks3 = bio.gamboa_segmenter(data, 342)
rpeaks4 = bio.hamilton_segmenter(data, 342)
rpeaks5 = bio.ssf_segmenter(data, 342)

np.savetxt('FilteredData/peaksdata13.txt', rpeaks1, header=str(len(rpeaks1)))
np.savetxt('FilteredData/peaksdata23.txt', rpeaks2, header=str(len(rpeaks2)))
np.savetxt('FilteredData/peaksdata33.txt', rpeaks3, header=str(len(rpeaks3)))
np.savetxt('FilteredData/peaksdata43.txt', rpeaks4, header=str(len(rpeaks4)))
np.savetxt('FilteredData/peaksdata53.txt', rpeaks5, header=str(len(rpeaks5)))
#np.savetxt('FilteredData/roundeddata3.txt', introunddata)
Exemple #28
0
def extract_features(ts):
    """Extract features from individual patient

    Arguments
    ---------
    ts: time series of interest

    Returns
    -------
    
    """
    """
    1. R-R interval:
    -what is the average interval between peaks?
    -how much variation is there in this measure?
    -max/min value
    """
    # Peak detection: perhaps take it from .ecg function?
    rpeak0=ecg.hamilton_segmenter(signal=ts,\
                              sampling_rate=300)[0]
    # Interval lengths
    l_RRint = []
    for a in range(len(rpeak0)):
        if (a > 0):
            l_RRint.append(rpeak0[a] - rpeak0[a - 1])
    # Some "robust" extreme values statistics (no max or min)
    RRint_10, RRint_90 = np.percentile(l_RRint, q=[0.1, 0.9])
    RRint_mean = np.mean(l_RRint)
    RRint_sd = np.std(l_RRint)
    """
    2. R amplitude (difference between value at peak
                    minus baseline -not "valley"-):
        -what is the average R amplitude?
        -how much variation is there in this measure?
        -max/min value
    NOTE: YOU CANNOT USE THE INDEXING OF THE R-PEAKS TO FIND THE
    VALUE OF THE Y! First impression: use ecg.ecg and work with
    the filtered series (here indeces seem to match)
    
    Idea: work with index of filtered series. For baseline
    take an average of the first and last 20 values of the series
    """
    filtered_ts = ecg.ecg(ts, sampling_rate=300, show=False)

    hb, hb_peaks= ecg.extract_heartbeats(signal=filtered_ts["filtered"], \
                    rpeaks= rpeak0, sampling_rate=300.0)
    # if all(hb[1]==rpeak0):
    #    hb=hb[0]
    #else:
    #    print "Error"
    # Finding value at R-peak
    R_max_value = filtered_ts["filtered"][hb_peaks]
    # Computing baseline
    ts_baselines = []
    for a_hb in hb:
        ts_baselines.append((sum(a_hb[0:20])+ \
                            sum(a_hb[(len(a_hb)-20):(len(a_hb)-1)]))/40.)
    # R_max -baseline
    R_amplitude = []
    for hb_nr in range(len(hb)):
        R_amplitude.append(R_max_value[hb_nr] - ts_baselines[hb_nr])
    Rampl_10, Rampl_90 = np.percentile(R_amplitude, q=[0.1, 0.9])
    Rampl_mean = np.mean(R_amplitude)
    Rampl_sd = np.std(R_amplitude)
    """
    3. Q and S (latter optional) amplitude 
               (difference between value at min before R
                    minus baseline):
    
    Idea: Examinate the HB. Find out: what is a reasonal nr of
     steps to look before the R peak to find Q? Baseline (see above)
     - 25 time steps before R-peak to find Q value (the same for S)
     --> Note, since the R-peak is sometimes identified at the very
     beginning of the series, we need the window to be relative
     to where this index is choice: look at indeces
     int(2./3*R_index):R_index
    """
    Q_vals = []
    Q_amplitude = []
    S_vals = []
    S_amplitude = []
    for hb_nr in range(len(hb)):
        # Q stats
        R_index = np.where(hb[hb_nr] == R_max_value[hb_nr])[0][0]
        Q_min = min(hb[hb_nr][int(2. / 3 * R_index):R_index])
        Q_vals.append(Q_min)
        Q_amplitude.append(ts_baselines[hb_nr] - Q_min)
        # S stats
        S_min = min(hb[hb_nr][R_index:(R_index + 25)])
        S_vals.append(S_min)
        S_amplitude.append(ts_baselines[hb_nr] - S_min)
    # Remark: some values are completely off due to clear errors in the
    # peak detction algorithm (e.g. heartbeat 34 in 19th individual)
    Qampl_10, Qampl_90 = np.percentile(Q_amplitude, q=[0.1, 0.9])
    Qampl_mean = np.mean(Q_amplitude)
    Qampl_sd = np.std(Q_amplitude)
    Sampl_10, Sampl_90 = np.percentile(S_amplitude, q=[0.1, 0.9])
    Sampl_mean = np.mean(S_amplitude)
    Sampl_sd = np.std(S_amplitude)
    """
    4. QRS duration:
    
    Idea: we have the index of Q_min and that of S_min. Difference between the two
    APPROXIMATES this feature (the way I understand it, I should measure how
    long it takes, once we have left the "baseline" to fall into the Q-in, to
    come back to the baseline after the S min)
    """
    QRS_time = []
    for hb_nr in range(len(hb)):
        Q_index = np.where(hb[hb_nr] == Q_vals[hb_nr])[0][0]
        S_index = np.where(hb[hb_nr] == S_vals[hb_nr])[0][0]
        QRS_time.append(S_index - Q_index)
    QRSts_10, QRSts_90 = np.percentile(QRS_time, q=[0.1, 0.9])
    QRSts_mean = np.mean(QRS_time)
    QRSts_sd = np.std(QRS_time)
    """
    5. Hearth rate variability
    
    Idea: extract from the .ecg function
    """
    hr_ts = filtered_ts[
        "heart_rate"]  # For subjet 2719 no heart rate is computed! Weird...
    if len(hr_ts) == 0:
        HR_10, HR_90, HR_mean, HR_sd = [None] * 4
    else:
        HR_10, HR_90 = np.percentile(hr_ts, q=[0.1, 0.9])
        HR_mean = np.mean(hr_ts)
        HR_sd = np.std(hr_ts)
    """
    5. Wavelet energy
    
    Idea: don't understand what this is or how to obtain it
    """

    return RRint_mean, RRint_sd, RRint_10, RRint_90, \
           Rampl_mean, Rampl_sd, Rampl_10, Rampl_90, \
           Qampl_mean, Qampl_sd, Qampl_10, Qampl_90, \
           Sampl_mean, Sampl_sd, Sampl_10, Sampl_90, \
           QRSts_mean, QRSts_sd, QRSts_10, QRSts_90, \
           HR_mean, HR_sd, HR_10, HR_90
Exemple #29
0
                    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

signal_path = "./data/ecg_records_117.txt"
ann_path = "./data/ecg_ann_117.txt"

logging.info("--------------------------------------------------")
signal, _ = load_txt(signal_path)
logging.info("载入信号-%s, 长度 = %d. " % (signal_path, len(signal)))
ann, _ = load_txt(ann_path)
logging.info("载入R峰位置人工标记, 共 %d 个R峰." % (len(ann)))

fs = 360  # 信号采样率 360 Hz
logging.info("调用 hamilton_segmenter 进行R波检测 ...")
tic = time.time()
rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs)
toc = time.time()
logging.info("完成. 用时: %f 秒. " % (toc - tic))
rpeaks = rpeaks[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("*********************************")
def main():

    #signal
    time_before_seizure = 30
    time_after_seizure = 10
    # path_to_load = '~/Desktop/phisionet_seizures.h5'
    sampling_rate = 1000
    path_to_load = '~/Desktop/seizure_datasets.h5'
    name_list = [
        str(time_before_seizure * 60) + '_' + str(time_after_seizure * 60)
    ]
    group_list_raw = ['raw']
    group_list_baseline_removal = ['medianFIR']
    group_list_noise_removal = ['FIR_lowpass_40hz']
    group_list_esksmooth = ['esksmooth']

    # Raw signal
    signal_structure_raw = load_signal(path_to_load,
                                       zip(group_list_raw, name_list))
    # one_signal_structure_raw = get_one_signal_structure(signal_structure, zip(group_list, name_list)[0])
    # records_raw = get_multiple_records(one_signal_structure_raw)

    # stop # ========================================================

    # Baseline removal
    records_baseline_removal, mdata_baseline_removal = load_baseline_removal(
        path_to_load,
        group_list_raw,
        name_list,
        sampling_rate,
        compute_flag=False)

    # stop # =========================================================

    # Noise removal
    records_noise_removal, mdata_noise_removal = load_noise_removal(
        path_to_load,
        group_list_baseline_removal,
        name_list,
        sampling_rate,
        compute_flag=False)

    # Noise removal kalman

    records_kalman, mdata_kalman = load_kalman(path_to_load,
                                               group_list_baseline_removal,
                                               name_list,
                                               sampling_rate,
                                               compute_flag=False)

    # stop # =========================================================

    # Rpeak detection
    # rpeaks_noise_removal = load_rpeaks(path_to_load, group_list_noise_removal, name_list, sampling_rate, compute_flag = False)

    # stop # =========================================================
    # Allocate time array
    Fs = 250
    N = len(records_kalman[0, :])
    T = (N - 1) / Fs
    t = np.linspace(0, T, N, endpoint=False)
    factor = 2

    # Visual inspection of rpeak detection
    start = 280
    end = 300
    seizure_nr = 1

    if seizure_nr < 3:
        Fs = 1000
        N = len(records_baseline_removal[0, :])
        T = (N - 1) / Fs
        t_new = np.linspace(0, T, N, endpoint=False)
        signal_inter = records_baseline_removal[seizure_nr]
        rpeaks_RAM = ecg.hamilton_segmenter(
            signal=signal_inter, sampling_rate=sampling_rate)['rpeaks']
    else:
        signal = records_kalman[seizure_nr]
        signal_inter, t_new = interpolate(t, signal, 1000)
        rpeaks_RAM = ecg.hamilton_segmenter(
            signal=signal_inter, sampling_rate=sampling_rate)['rpeaks']

    # stop
    y = np.diff(rpeaks_RAM)

    # visual_inspection(signal_inter, rpeaks_RAM, y, t, time_before_seizure,
    #             start, end, sampling_rate)

    t_rpeaks = t_new[rpeaks_RAM[1:]]
    y_new, t_n = interpolate(t_rpeaks, y, 2)
    print(len(t) - 1) / 250
    print(len(t_n) - 1) / 2
    time_before_seizure = time_before_seizure * 60
    print time_before_seizure
    #rpeaks
    # rpeaks = rpeaks_noise_removal[seizure_nr]
    # rpeaks_resample = resample_rpeaks(np.diff(rpeaks), rpeaks, t)
    # rpeaks = find_rpeaks(rpeaks, start * sampling_rate,
    #     end * sampling_rate)

    #signal
    # signal_baseline_removal = records_baseline_removal[seizure_nr,:]
    # signal_noise_removal = records_noise_removal[seizure_nr,:]

    #plot
    plt.subplot(2, 1, 1)
    plt.plot(t_new, signal_inter)
    plt.plot(t_new[rpeaks_RAM], signal_inter[rpeaks_RAM], 'o')
    # plt.axvline(x=time_before_seizure*60, color = 'g')
    plt.subplot(2, 1, 2)
    plt.plot(t_n, y_new)
    plt.axvline(x=time_before_seizure, color='g')
    plt.plot()
    # plt.xlim([start, end])
    # plt.subplot(2,1,2)
    # plt.plot(t, signal_baseline_removal)
    # plt.xlim([start, end])
    plt.show()
    # # stop

    beats = compute_fixed_beats(signal_inter, rpeaks_RAM)
    print np.shape(beats[0:5])
    pca = compute_PC(beats[0:5])

    pca = np.dot(pca, beats[0:5])
    print np.shape(pca)

    evol = trace_evol_PC(beats)
    print np.shape(evol)
    evol = evol.T

    t_evol = t_new[rpeaks_RAM[6:-1]]
    print len(t_evol)

    ev = [interpolate(t_evol, eigen, 2) for eigen in evol]

    plt.subplot(6, 1, 1)
    plt.plot(ev[4][1], 1 * 1000 * 60 / y_new[1:len(ev[4][1]) + 1])
    plt.axvline(x=time_before_seizure, color='g')
    plt.legend(['HRV', 'Seizure onset'])
    plt.ylabel('bpm')
    plt.subplot(6, 1, 2)
    plt.plot(ev[4][1], ev[4][0])
    plt.axvline(x=time_before_seizure, color='g')
    plt.legend(['Eigen-Value 1', 'Seizure onset'])
    plt.subplot(6, 1, 3)
    plt.plot(ev[3][1], ev[3][0])
    plt.axvline(x=time_before_seizure, color='g')
    plt.legend(['Eigen-Value 2', 'Seizure onset'])
    plt.subplot(6, 1, 4)
    plt.plot(ev[2][1], ev[2][0])
    plt.axvline(x=time_before_seizure, color='g')
    plt.legend(['Eigen-Value 3', 'Seizure onset'])
    plt.subplot(6, 1, 5)
    plt.plot(ev[1][1], ev[1][0])
    plt.axvline(x=time_before_seizure, color='g')
    plt.legend(['Eigen-Value 4', 'Seizure onset'])
    plt.subplot(6, 1, 6)
    plt.plot(ev[0][1], ev[0][0])
    plt.axvline(x=time_before_seizure, color='g')
    plt.legend(['Eigen-Value 5', 'Seizure onset'])
    plt.xlabel('t (s)')
    plt.subplots_adjust(0.09, 0.1, 0.94, 0.94, 0.26, 0.46)

    plt.show()
Exemple #31
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