Exemple #1
0
def test_ecg_delineate():

    sampling_rate = 1000

    # test with simulated signals
    ecg = nk.ecg_simulate(duration=20,
                          sampling_rate=sampling_rate,
                          random_state=42)
    _, rpeaks = nk.ecg_peaks(ecg, sampling_rate=sampling_rate)
    number_rpeaks = len(rpeaks['ECG_R_Peaks'])

    # Method 1: derivative
    _, waves_derivative = nk.ecg_delineate(ecg,
                                           rpeaks,
                                           sampling_rate=sampling_rate)
    assert len(waves_derivative['ECG_P_Peaks']) == number_rpeaks
    assert len(waves_derivative['ECG_Q_Peaks']) == number_rpeaks
    assert len(waves_derivative['ECG_S_Peaks']) == number_rpeaks
    assert len(waves_derivative['ECG_T_Peaks']) == number_rpeaks
    assert len(waves_derivative['ECG_P_Onsets']) == number_rpeaks
    assert len(waves_derivative['ECG_T_Offsets']) == number_rpeaks

    # Method 2: CWT
    _, waves_cwt = nk.ecg_delineate(ecg,
                                    rpeaks,
                                    sampling_rate=sampling_rate,
                                    method='cwt')
    assert np.allclose(len(waves_cwt['ECG_P_Peaks']), 22, atol=1)
    assert np.allclose(len(waves_cwt['ECG_T_Peaks']), 22, atol=1)
    assert np.allclose(len(waves_cwt['ECG_R_Onsets']), 23, atol=1)
    assert np.allclose(len(waves_cwt['ECG_R_Offsets']), 23, atol=1)
    assert np.allclose(len(waves_cwt['ECG_P_Onsets']), 22, atol=1)
    assert np.allclose(len(waves_cwt['ECG_P_Offsets']), 22, atol=1)
    assert np.allclose(len(waves_cwt['ECG_T_Onsets']), 22, atol=1)
    assert np.allclose(len(waves_cwt['ECG_T_Offsets']), 22, atol=1)
def get_HRVs_values(data, header_data):

    filter_lowcut = 0.001
    filter_highcut = 15.0
    filter_order = 1

    tmp_hea = header_data[0].split(' ')
    ptID = tmp_hea[0]
    num_leads = int(tmp_hea[1])
    sample_Fs = int(tmp_hea[2])
    gain_lead = np.zeros(num_leads)

    for ii in range(num_leads):
        tmp_hea = header_data[ii + 1].split(' ')
        gain_lead[ii] = int(tmp_hea[2].split('/')[0])

    # for testing, we included the mean age of 57 if the age is a NaN
    # This value will change as more data is being released
    for iline in header_data:
        if iline.startswith('#Age'):
            tmp_age = iline.split(': ')[1].strip()
            age = int(tmp_age if tmp_age != 'NaN' else 57)
        elif iline.startswith('#Sex'):
            tmp_sex = iline.split(': ')[1]
            if tmp_sex.strip() == 'Female':
                sex = 1
            else:
                sex = 0
        elif iline.startswith('#Dx'):
            label = iline.split(': ')[1].split(',')[0]

    signal = data[1]
    gain = gain_lead[1]

    ecg_signal = nk.ecg_clean(signal * gain,
                              sampling_rate=sample_Fs,
                              method="biosppy")
    _, rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=sample_Fs)
    hrv_time = nk.hrv_time(rpeaks, sampling_rate=sample_Fs)
    # hrv_non = nk.hrv_nonlinear(rpeaks, sampling_rate=sample_Fs)
    try:
        signal_peak, waves_peak = nk.ecg_delineate(ecg_signal,
                                                   rpeaks,
                                                   sampling_rate=sample_Fs)
        p_peaks = waves_peak['ECG_P_Peaks']
    except ValueError:
        print('Exception raised!')
        pass

    p_peaks = np.asarray(p_peaks, dtype=float)
    p_peaks = p_peaks[~np.isnan(p_peaks)]
    p_peaks = [int(a) for a in p_peaks]
    mean_P_Peaks = np.mean([signal[w] for w in p_peaks])

    hrv_time['mean_P_Peaks'] = mean_P_Peaks
    hrv_time['age'] = age
    hrv_time['label'] = label
    # df = pd.concat([hrv_time, hrv_non], axis=1)

    return hrv_time
Exemple #3
0
def nothing():
    # Quality check algorithms
    # qcqrs = run_qc(signal=data.filtered, epoch_len=15, fs=fs, algorithm="averageQRS", show_plot=False)

    # Removing invalid data based on QC thresholdling
    #t = threshold_averageqrs_data(signal=data.filtered, qc_signal=qc, epoch_len=10, fs=fs, pad_val=0,
    #                              thresh=.95, method='exclusive', plot_data=False)

    p, pc = find_peaks(signal=data.filtered,
                       fs=fs,
                       show_plot=True,
                       peak_method="pantompkins1985",
                       clean_method='neurokit')
    hrv = nk.hrv_time(peaks=pc, sampling_rate=data.sample_rate, show=False)

    freq = nk.hrv_frequency(peaks=pc,
                            sampling_rate=data.sample_rate,
                            show=True)

    # df_events, info = test_ecg_process_func(signal=data.filtered[15000:15000+1250], start=0, n_samples=int(10*125), fs=fs, plot_builtin=True, plot_events=False)

    # heartbeats = segment_ecg(signal=d, fs=fs)

    waves, sigs = nk.ecg_delineate(ecg_cleaned=data.filtered,
                                   rpeaks=pc,
                                   sampling_rate=data.sample_rate,
                                   method='dwt',
                                   show=False)

    intervals, ecg_rate, ecg_hrv = nk.ecg_intervalrelated()


# TODO
# Organizing
# Signal quality in organized section --> able to pick which algorithm
def run_test_func(test_data):
    _, waves = nk.ecg_delineate(test_data['ecg'],
                                test_data['rpeaks'],
                                test_data['sampling_rate'],
                                method='dwt')
    for key in waves:
        waves[key] = np.array(waves[key])
    return waves
Exemple #5
0
 def _other_peaks_detection(ecg_data, rpeaks, sampling_rate):
     _, waves_peak = nk.ecg_delineate(ecg_data[1],
                                      rpeaks,
                                      sampling_rate=sampling_rate)
     q_peaks = waves_peak['ECG_Q_Peaks']
     q_peaks = np.delete(q_peaks,
                         np.where(np.isnan(q_peaks))[0]).astype(
                             int)  # not use
     s_peaks = waves_peak['ECG_S_Peaks']
     s_peaks = np.delete(s_peaks,
                         np.where(np.isnan(s_peaks))[0]).astype(
                             int)  # not use
     return q_peaks, s_peaks
def generate_features(ecg, header):
    #input: 12-lead ecg and its header
    fs = 500
    features = {}

    lead_names = []
    for iline in header:
        if '.mat' in iline:
            name = iline.split(' 0 ')[2].strip()
            lead_names.append(name)

    for ecg_signal, lead in zip(ecg, lead_names):

        ecg_cleaned = nk.ecg_clean(ecg_signal, sampling_rate=fs)

        if np.all((ecg_cleaned == 0)):
            return None
        else:
            _, rpeaks = nk.ecg_peaks(ecg_cleaned, sampling_rate=fs)

            if rpeaks['ECG_R_Peaks'].size == 0:
                return None
            else:
                try:
                    signal_dwt, waves_dwt = nk.ecg_delineate(
                        ecg_cleaned,
                        rpeaks['ECG_R_Peaks'],
                        sampling_rate=fs,
                        method="dwt")
                    biphase, areas, t_till_peaks, ampls, dur, idxs, pq_intervals = p_peak_features(
                        ecg_cleaned, waves_dwt)
                    features_for_single_lead = {
                        'PQ_int': calculate_features(pq_intervals),
                        'P_dur': calculate_features(dur),
                        'Area/Dur_P': calculate_features(idxs),
                        'Area_under_P': calculate_features(areas),
                        'P_amp': calculate_features(ampls),
                        'Time_till_P': calculate_features(t_till_peaks),
                        'Biphase_P': calculate_features(biphase)
                    }
                except IndexError:
                    return None

        features[lead] = features_for_single_lead

    return features
Exemple #7
0
def compute_qrs_ratio(x, fs=460, length_of_beat=0.75):
    # Find Q and S peaks
    _, rpeaks = nk.ecg_peaks(x, sampling_rate=fs)
    _, waves_peak = nk.ecg_delineate(x,
                                     rpeaks,
                                     sampling_rate=fs,
                                     method="peak")

    # Compute diff across Q and S peaks
    Q_waves = waves_peak['ECG_Q_Peaks']
    S_waves = waves_peak['ECG_S_Peaks']
    diff = [s - q for s, q in zip(S_waves, Q_waves)]

    # Divide the diff by 0.75 seconds (length of 1 beat in samples)
    duration_samples = int(length_of_beat * fs)
    ratio = [i / duration_samples for i in diff if not np.isnan(i)]
    return sum(ratio) / len(ratio)
Exemple #8
0
def my_processing(ecg_signal):
    # Try processing
    ecg_cleaned = nk.ecg_clean(ecg_signal, sampling_rate=300, method="biosppy")
    instant_peaks, rpeaks = nk.ecg_peaks(ecg_cleaned,
                                         sampling_rate=300,
                                         method='hamilton2002')
    info = rpeaks
    try:
        # Additional info of the ecg signal
        delineate_signal, delineate_waves = nk.ecg_delineate(
            ecg_cleaned=ecg_cleaned,
            rpeaks=rpeaks,
            sampling_rate=300,
            method='cwt')
    except:
        delineate_signal = np.NaN
        delineate_waves = np.NaN
    return ecg_cleaned, delineate_signal, delineate_waves, info
Exemple #9
0
def extract_prt_features(row, signal, rpeaks):
    """
    Extract the PRT features - the segment lengths and intervals between them.

    :param row: a `BaseDataset` row to calculate the features from
    :param signal: the raw ECG signal
    :param rpeaks: the R peaks detected by `nk.ecg_peaks`
    :return: `row` with the added features
    """
    _, segments = nk.ecg_delineate(signal,
                                   rpeaks,
                                   sampling_rate=row.Fs,
                                   method="dwt")

    for key in segments:
        segments[key] = np.array(segments[key]) / row.Fs

    P_length = segments['ECG_P_Offsets'] - segments['ECG_P_Onsets']
    R_length = segments['ECG_R_Offsets'] - segments['ECG_R_Onsets']
    T_length = segments['ECG_T_Offsets'] - segments['ECG_T_Onsets']

    PR_interval = segments['ECG_R_Onsets'] - segments['ECG_P_Onsets']
    RT_interval = segments['ECG_T_Onsets'] - segments['ECG_R_Onsets']

    features = [
        (P_length, 'P_LENGTH'),
        (R_length, 'R_LENGTH'),
        (T_length, 'T_LENGTH'),
        (PR_interval, 'PR_INTERVAL'),
        (RT_interval, 'RT_INTERVAL'),
    ]

    for feature, name in features:
        row = row.append(get_statistics(feature, name, ignore_nan=True))

    return row
Exemple #10
0
 def _discrete_wavelet_trans(ecg_data, rpeaks, sample_freq):
     _, waves_dwt = nk.ecg_delineate(ecg_data[1],
                                     rpeaks,
                                     sampling_rate=sample_freq,
                                     method="dwt")
     p_offsets = waves_dwt['ECG_P_Offsets']
     p_offsets = np.delete(p_offsets,
                           np.where(np.isnan(p_offsets))[0]).astype(int)
     p_onsets = waves_dwt['ECG_P_Onsets']
     p_onsets = np.delete(p_onsets,
                          np.where(np.isnan(p_onsets))[0]).astype(int)
     p_peaks = waves_dwt['ECG_P_Peaks']
     p_peaks = np.delete(p_peaks,
                         np.where(np.isnan(p_peaks))[0]).astype(int)
     t_peaks = waves_dwt['ECG_T_Peaks']
     t_peaks = np.delete(t_peaks,
                         np.where(np.isnan(t_peaks))[0]).astype(int)
     t_offsets = waves_dwt['ECG_T_Offsets']
     t_offsets = np.delete(t_offsets,
                           np.where(np.isnan(t_offsets))[0]).astype(int)
     t_onsets = waves_dwt['ECG_T_Onsets']
     t_onsets = np.delete(t_onsets,
                          np.where(np.isnan(t_onsets))[0]).astype(int)
     return p_offsets, p_onsets, p_peaks, t_peaks, t_offsets, t_onsets
    def extract_features_tmaps(
        self,
        signal_tm: TensorMap,
        clean_method: str = "neurokit",
        r_method: str = "neurokit",
        wave_method: str = "dwt",
        min_peaks: int = 200,
    ):
        """
        Function to extract the ecg features using the neurokit2 package. That
        is the P, Q, R, S and T peaks and the P, QRS and T waves onsets and
        offsets. The result is saved internally.

        :param signal_tm: <TensorMap>
        :param clean_method: <str> The processing pipeline to apply. Can be one of
                             ‘neurokit’ (default), ‘biosppy’, ‘pantompkins1985’,
                             ‘hamilton2002’, ‘elgendi2010’, ‘engzeemod2012’.
        :param r_method: <str> The algorithm to be used for R-peak detection. Can be one
                         of ‘neurokit’ (default), ‘pantompkins1985’, ‘hamilton2002’,
                         ‘christov2004’, ‘gamboa2008’, ‘elgendi2010’, ‘engzeemod2012’
                         or ‘kalidas2017’.
        :param wave_method: <str> Can be one of ‘dwt’ (default) for discrete
                            wavelet transform or ‘cwt’ for continuous wavelet transform.
        :param min_peaks: <int> Minimum R peaks to be detected to proceed with
                          further calculations.
        """
        for i, _ in enumerate(self.sampling_rate):
            sampling_rate = self.sampling_rate[i][0]
            init = self.sampling_rate[i][1]
            if i == len(self.sampling_rate) - 1:
                end = -1
            else:
                end = self.sampling_rate[i + 1][1]
            ecg_signal = signal_tm.tensor_from_file(signal_tm,
                                                    self)[0][init:end]
            ecg_signal = nk.ecg_clean(ecg_signal, sampling_rate, clean_method)

            try:
                _, r_peaks = nk.ecg_peaks(ecg_signal, sampling_rate, r_method)
            except IndexError:
                continue
            if len(r_peaks["ECG_R_Peaks"]) < min_peaks:
                continue
            _, waves_peaks = nk.ecg_delineate(ecg_signal, r_peaks,
                                              sampling_rate)
            _, waves_peaks_2 = nk.ecg_delineate(
                ecg_signal,
                r_peaks,
                sampling_rate,
                wave_method,
            )
            waves_peaks.update(waves_peaks_2)
            for peak_type in r_peaks:
                if peak_type not in self.r_peaks:
                    self.r_peaks[peak_type] = r_peaks[peak_type]
                else:
                    self.r_peaks[peak_type] = np.append(
                        self.r_peaks[peak_type],
                        r_peaks[peak_type],
                    )
            for peak_type in waves_peaks:
                if peak_type not in self.waves_peaks:
                    self.waves_peaks[peak_type] = waves_peaks[peak_type]
                else:
                    self.waves_peaks[peak_type] = np.append(
                        self.waves_peaks[peak_type],
                        waves_peaks[peak_type],
                    )

        for peak_type in self.r_peaks:
            self.r_peaks[peak_type] = list(self.r_peaks[peak_type])
        for peak_type in self.waves_peaks:
            self.waves_peaks[peak_type] = list(self.waves_peaks[peak_type])
def Get_TPQS_Peaks(ecg_signal, rpeaks):
    # Delineate ECG signal to get TPQS peaks
    print(
        "=======   Using DWT to retrieve TPQS Peaks and On/Offsets   ========")
    dwt_sig, waves_dwt_peak = nk.ecg_delineate(ecg_signal,
                                               rpeaks,
                                               sampling_rate=3000,
                                               method="dwt",
                                               show=True,
                                               show_type="all")

    #Print to console
    for key in waves_dwt_peak:
        print(key, ' : ', waves_dwt_peak[key])

    def_sig, waves_peak = nk.ecg_delineate(ecg_signal,
                                           rpeaks,
                                           sampling_rate=3000,
                                           show_type="peaks")

    # Visualize the T-peaks, P-peaks, Q-peaks and S-peaks  **for JupyterNotebook
    plot_TPQS_Signal = nk.events_plot([
        waves_peak['ECG_T_Peaks'], waves_peak['ECG_P_Peaks'],
        waves_peak['ECG_Q_Peaks'], waves_peak['ECG_S_Peaks']
    ], ecg_signal)
    plot_TPQS_Signal.savefig("TPQS_signal", dpi=300)

    # Zooming into the first 3 R-peaks, with focus on
    # T_peaks, P-peaks, Q-peaks and S-peaks  **for JupyterNotebook
    plot_TPQS_Head = nk.events_plot([
        waves_peak['ECG_T_Peaks'][:3], waves_peak['ECG_P_Peaks'][:3],
        waves_peak['ECG_Q_Peaks'][:3], waves_peak['ECG_S_Peaks'][:3]
    ], ecg_signal[:12500])
    plot_TPQS_Head.savefig("TPQS_head", dpi=300)

    # Delineate the ECG signal and visualizing all peaks of ECG complexes
    _, waves_peak = nk.ecg_delineate(ecg_signal,
                                     rpeaks,
                                     sampling_rate=3000,
                                     show=True,
                                     show_type='peaks')

    # Delineate the ECG signal and visualizing all P-peaks boundaries
    signal_peak, waves_peak = nk.ecg_delineate(ecg_signal,
                                               rpeaks,
                                               sampling_rate=3000,
                                               show=True,
                                               show_type='bounds_P')

    # Delineate the ECG signal and visualizing all T-peaks boundaries
    signal_peaj, waves_peak = nk.ecg_delineate(ecg_signal,
                                               rpeaks,
                                               sampling_rate=3000,
                                               show=True,
                                               show_type='bounds_T')

    #Print to Console
    for key in waves_peak:
        if (key == 'ECG_Q_Peaks' or key == 'ECG_S_Peaks'):
            print(key, ' : ', waves_peak[key])
    print()

    return waves_dwt_peak, waves_peak
Exemple #13
0
    def analyzeECG(ecg, sampling_rate, method = "dwt"):
        #Funkcja zwraca parametry analizy, które mogą być wykorzystane do wyświetlania oraz do dalszej analizy.
        #Zwraca puls, średnią HRV, HRVSDNN, HRVRMSSD, informacje związane z załamkami (długość, czas, amplituda)
        a, peaks = nk.ecg_process(ecg[1], sampling_rate = sampling_rate)
        info = nk.ecg_analyze(a, sampling_rate = sampling_rate)
        ECG_Rate_Mean = info["ECG_Rate_Mean"][0]
        HRV_RMSSD = info["HRV_RMSSD"][0]
        HRV_MeanNN = info["HRV_MeanNN"][0]
        HRV_SDNN = info["HRV_SDNN"][0]

        _,rpeaksnk = nk.ecg_peaks(ecg[1], sampling_rate = sampling_rate)
        R_peaks = [[],[]]
        for i in rpeaksnk["ECG_R_Peaks"]:
            R_peaks[0].append(ecg[0][i])
            R_peaks[1].append(ecg[1][i])

        # Delineate the ECG signal
        _, waves_peak = nk.ecg_delineate(ecg[1], rpeaksnk, sampling_rate = sampling_rate, show = False,
                                         show_type = "peaks")
        if method == "cwt":
            _, waves_other = nk.ecg_delineate(ecg[1], rpeaksnk, sampling_rate = sampling_rate,
                                            method="cwt", show=False, show_type='all')
        if method == "dwt":
            _, waves_other = nk.ecg_delineate(ecg[1], rpeaksnk, sampling_rate = sampling_rate,
                                            method="dwt", show=False, show_type='all')

        #Wyznaczanie załamków P, Q, S, T
        P_peaks = [[],[]]
        Q_peaks = [[],[]]
        S_peaks = [[],[]]
        T_peaks = [[],[]]
        for name in waves_peak:
            for i in waves_peak[str(name)]:
                if math.isnan(i):
                    continue
                if str(name) == "ECG_P_Peaks":
                    P_peaks[0].append(ecg[0][i])
                    P_peaks[1].append(ecg[1][i])
                if str(name) == "ECG_Q_Peaks":
                    Q_peaks[0].append(ecg[0][i])
                    Q_peaks[1].append(ecg[1][i])
                if str(name) == "ECG_S_Peaks":
                    S_peaks[0].append(ecg[0][i])
                    S_peaks[1].append(ecg[1][i])
                if str(name) == "ECG_T_Peaks":
                    T_peaks[0].append(ecg[0][i])
                    T_peaks[1].append(ecg[1][i])

        #Wyznaczanie początków i końców załamków P, Q, S, T
        P_onsets = [[],[]]
        P_offsets = [[],[]]
        R_onsets = [[],[]]
        R_offsets = [[],[]]
        T_onsets = [[],[]]
        T_offsets = [[],[]]

        for name in waves_other:
            for i in waves_other[str(name)]:
                if math.isnan(i):
                    continue
                if str(name) == "ECG_P_Onsets":
                    P_onsets[0].append(ecg[0][i])
                    P_onsets[1].append(ecg[1][i])
                if str(name) == "ECG_P_Offsets":
                    P_offsets[0].append(ecg[0][i])
                    P_offsets[1].append(ecg[1][i])
                if str(name) == "ECG_R_Onsets":
                    R_onsets[0].append(ecg[0][i])
                    R_onsets[1].append(ecg[1][i])
                if str(name) == "ECG_R_Offsets":
                    R_offsets[0].append(ecg[0][i])
                    R_offsets[1].append(ecg[1][i])
                if str(name) == "ECG_T_Onsets":
                    T_onsets[0].append(ecg[0][i])
                    T_onsets[1].append(ecg[1][i])
                if str(name) == "ECG_T_Offsets":
                    T_offsets[0].append(ecg[0][i])
                    T_offsets[1].append(ecg[1][i])

        #Czasy załamków
        P_Time = calculateTime(P_offsets[0], P_onsets[0])
        QRS_Time = calculateTime(R_offsets[0], R_onsets[0])
        T_Time = calculateTime(T_offsets[0], T_onsets[0])

        #Amplitudy załamków
        P_Amplitude = np.mean(P_peaks[1])
        Q_Amplitude = np.mean(Q_peaks[1])
        R_Amplitude = np.mean(R_peaks[1])
        S_Amplitude = np.mean(S_peaks[1])
        T_Amplitude = np.mean(T_peaks[1])

        #Odstępy
        PQ_Space = calculateTime(R_onsets[0], P_onsets[0])
        QT_Space = calculateTime(T_offsets[0], R_onsets[0])

        #Odcinki
        PQ_Segment = calculateTime(R_onsets[0], P_offsets[0])
        ST_Segment = calculateTime(T_onsets[0], R_offsets[0])

        #Słowniki z pozyskanymi informacjami
        data = {}
        info = {}

        data["P_peaks"] = P_peaks
        data["Q_peaks"] = Q_peaks
        data["R_peaks"] = R_peaks
        data["S_peaks"] = S_peaks
        data["T_peaks"] = T_peaks
        data["P_onsets"] = P_onsets
        data["P_offsets"] = P_offsets
        data["R_onsets"] = R_onsets
        data["R_offsets"] = R_offsets
        data["T_onsets"] = T_onsets
        data["T_offsets"] = T_offsets

        info["ECG_Rate_Mean"] = round(ECG_Rate_Mean, 4)
        info["HRV_MeanNN"] = round(HRV_MeanNN, 4)
        info["HRV_RMSSD"] = round(HRV_RMSSD, 4)
        info["HRV_SDNN"] = round(HRV_SDNN, 4)
        info["P_Time"] = round(P_Time, 4)
        info["QRS_Time"] = round(QRS_Time, 4)
        info["T_Time"] = round(T_Time, 4)
        info["P_Amplitude"] = round(P_Amplitude, 4)
        info["Q_Amplitude"] = round(Q_Amplitude, 4)
        info["R_Amplitude"] = round(R_Amplitude, 4)
        info["S_Amplitude"] = round(S_Amplitude, 4)
        info["T_Amplitude"] = round(T_Amplitude, 4)
        info["PQ_Space"] = round(PQ_Space, 4)
        info["QT_Space"] = round(QT_Space, 4)
        info["PQ_Segment"] = round(PQ_Segment, 4)
        info["ST_Segment"] = round(ST_Segment, 4)

        return data, info
def run_test_func(test_data):
    _, waves = nk.ecg_delineate(test_data["ecg"], test_data["rpeaks"], test_data["sampling_rate"], method="dwt")
    for key in waves:
        waves[key] = np.array(waves[key])
    return waves
Exemple #15
0
def get_HRVs_values(data, header_data):

    filter_lowcut = 0.001
    filter_highcut = 15.0
    filter_order = 1

    tmp_hea = header_data[0].split(' ')
    ptID = tmp_hea[0]
    num_leads = int(tmp_hea[1])
    sample_Fs= int(tmp_hea[2])
    gain_lead = np.zeros(num_leads)
    
    for ii in range(num_leads):
        tmp_hea = header_data[ii+1].split(' ')
        gain_lead[ii] = int(tmp_hea[2].split('/')[0])

    # for testing, we included the mean age of 57 if the age is a NaN
    # This value will change as more data is being released
    for iline in header_data:
        if iline.startswith('#Age'):
            tmp_age = iline.split(': ')[1].strip()
            age = int(tmp_age if tmp_age != 'NaN' else 57)
            # age = int(tmp_age)
        elif iline.startswith('#Sex'):
            tmp_sex = iline.split(': ')[1]
            if tmp_sex.strip()=='Female':
                sex =1
            else:
                sex=0
        elif iline.startswith('#Dx'):
            label = iline.split(': ')[1].split(',')[0]

    signal = data[1]
    gain = gain_lead[1]

    ecg_signal = nk.ecg_clean(signal*gain, sampling_rate=sample_Fs, method="biosppy")
    _ , rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=sample_Fs)
    hrv_time = nk.hrv_time(rpeaks, sampling_rate=sample_Fs)
    
    peaks, idx = detect_peaks(signal, sample_Fs, gain)
    # print(len(signal), len(idx))
    rr_intervals = idx / (sample_Fs * 1000)
    rr_intervals = pd.Series(rr_intervals)
    rr_ma = rr_intervals.rolling(3)

    try:
        signal_peak, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=sample_Fs)
        p_peaks = waves_peak['ECG_P_Peaks']
    except ValueError:
        print('Exception raised!')
        pass
    p_peaks = np.asarray(p_peaks, dtype=float)
    p_peaks = p_peaks[~np.isnan(p_peaks)]
    p_peaks = [int(a) for a in p_peaks]
    p_time = [x/sample_Fs for x in p_peaks]
    p_diff = np.diff(p_time)
    # mean_P_Peaks = np.mean([signal[w] for w in p_peaks])
    hrv_time['var_P_time'] = stats.tvar(p_diff)
    hrv_time['var_P_peaks'] = stats.tvar(signal[np.array(p_peaks)])
    
    hrv_time['age'] = age
    hrv_time['label'] = label
    
    return hrv_time
Exemple #16
0
def get_12ECG_features_labels(data, header_data):

    tmp_hea = header_data[0].split(' ')
    ptID = tmp_hea[0]
    num_leads = int(tmp_hea[1])
    sample_Fs= int(tmp_hea[2])
    gain_lead = np.zeros(num_leads)
    
    for ii in range(num_leads):
        tmp_hea = header_data[ii+1].split(' ')
        gain_lead[ii] = int(tmp_hea[2].split('/')[0])

    # for testing, we included the mean age of 57 if the age is a NaN
    # This value will change as more data is being released
    for iline in header_data:
        if iline.startswith('#Age'):
            tmp_age = iline.split(': ')[1].strip()
            age = int(tmp_age if tmp_age != 'NaN' else 57)
        elif iline.startswith('#Sex'):
            tmp_sex = iline.split(': ')[1]
            if tmp_sex.strip()=='Female':
                sex =1
            else:
                sex=0
        elif iline.startswith('#Dx'):
            label = iline.split(': ')[1].split(',')[0]

    signal = data[1]
    gain = gain_lead[1]

    N = len(signal)
    sp= sample_Fs/N    # resolución espectral

    Y = np.fft.fft(signal*gain)
    ff = np.linspace(0, (N/2)*sp, N/2).flatten()
    fmax = float(ff[np.where(np.abs(Y[0:N//2]) == max(np.abs(Y[0:N//2])))])


#   We are only using data from lead1
    peaks,idx = detect_peaks(signal,sample_Fs,gain)
       
#   mean
    mean_RR = np.mean(idx/sample_Fs*1000)
    mean_R_Peaks = np.mean(peaks*gain)

#   median
    median_RR = np.median(idx/sample_Fs*1000)
    median_R_Peaks = np.median(peaks*gain)

#   standard deviation
    std_RR = np.std(idx/sample_Fs*1000)
    std_R_Peaks = np.std(peaks*gain)

#   variance
    var_RR = stats.tvar(idx/sample_Fs*1000)
    var_R_Peaks = stats.tvar(peaks*gain)

#   Skewness
    skew_RR = stats.skew(idx/sample_Fs*1000)
    skew_R_Peaks = stats.skew(peaks*gain)

#   Kurtosis
    kurt_RR = stats.kurtosis(idx/sample_Fs*1000)
    kurt_R_Peaks = stats.kurtosis(peaks*gain)

#   RMSSD (HRV)
    rmssd = np.sqrt(np.mean(np.square(np.diff(idx))))

#   All Peaks
    ecg_signal = nk.ecg_clean(signal*gain, sampling_rate=sample_Fs, method="biosppy")
    _ , rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=sample_Fs)
    try:
        signal_peak, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=sample_Fs)
        t_peaks = waves_peak['ECG_T_Peaks']
        p_peaks = waves_peak['ECG_P_Peaks']
        q_peaks = waves_peak['ECG_Q_Peaks']
        s_peaks = waves_peak['ECG_S_Peaks']
        p_onsets = waves_peak['ECG_P_Onsets']
        t_offsets = waves_peak['ECG_T_Offsets']
    except ValueError:
        print('Exception raised!')
        pass

#   T Peaks
    t_peaks = np.asarray(t_peaks, dtype=float)
    t_peaks = t_peaks[~np.isnan(t_peaks)]
    t_peaks = [int(a) for a in t_peaks]
    mean_T_Peaks = np.mean([signal[w] for w in t_peaks])

#   P peaks
    p_peaks = np.asarray(p_peaks, dtype=float)
    p_peaks = p_peaks[~np.isnan(p_peaks)]
    p_peaks = [int(a) for a in p_peaks]
    mean_P_Peaks = np.mean([signal[w] for w in p_peaks])    

#   Q peaks
    q_peaks = np.asarray(q_peaks, dtype=float)
    q_peaks = q_peaks[~np.isnan(q_peaks)]
    q_peaks = [int(a) for a in q_peaks]
    mean_Q_Peaks = np.mean([signal[w] for w in q_peaks])

#   S peaks
    s_peaks = np.asarray(s_peaks, dtype=float)
    s_peaks = s_peaks[~np.isnan(s_peaks)]
    s_peaks = [int(a) for a in s_peaks]
    mean_S_Peaks = np.mean([signal[w] for w in s_peaks])

#   P Onsets
    p_onsets = np.asarray(p_onsets, dtype=float)
    # p_onsets = p_onsets[~np.isnan(p_onsets)]
    mean_P_Onsets = np.mean(p_onsets/sample_Fs*1000)

#   T Onsets
    t_offsets = np.asarray(t_offsets, dtype=float)
    # t_offsets = t_offsets[~np.isnan(t_offsets)]
    mean_T_offsets = np.mean(t_offsets/sample_Fs*1000)

    features = [age,sex,fmax,mean_RR,mean_R_Peaks,mean_T_Peaks,mean_P_Peaks,mean_Q_Peaks,mean_S_Peaks,median_RR,median_R_Peaks,std_RR,std_R_Peaks,var_RR,var_R_Peaks,skew_RR,skew_R_Peaks,kurt_RR,kurt_R_Peaks,mean_P_Onsets,mean_T_offsets,rmssd,label]
  
    return features
Exemple #17
0
def bandpass(lowcut, highcut, order=5):
    nyq = 0.5 * 500
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='band')
    return b, a


b, a = bandpass(0.5, 45)
filtered_ecg = signal.filtfilt(b, a, ecg_wave[250:4750])

_, rpeaks = nk.ecg_peaks(filtered_ecg, sampling_rate=500)

_, waves_cwt = nk.ecg_delineate(filtered_ecg,
                                rpeaks,
                                sampling_rate=500,
                                method="dwt",
                                show=False,
                                show_type='peaks')

# 관심 ECG 설정

interest_ecg = filtered_ecg[rpeaks['ECG_R_Peaks'][0]:rpeaks['ECG_R_Peaks'][1]]

# template ECG 설정

template_ecg = []
for i in range(len(rpeaks['ECG_R_Peaks'])):
    try:
        template_ecg.append(
            filtered_ecg[rpeaks['ECG_R_Peaks'][i +
                                               1]:rpeaks['ECG_R_Peaks'][i +
Exemple #18
0
fig.savefig("README_hrv.png", dpi=300, h_pad=3)

# =============================================================================
# ECG Delineation
# =============================================================================

# Download data
ecg_signal = nk.data(dataset="ecg_3000hz")['ECG']

# Extract R-peaks locations
_, rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=3000)

# Delineate
signal, waves = nk.ecg_delineate(ecg_signal,
                                 rpeaks,
                                 sampling_rate=3000,
                                 method="dwt",
                                 show=True,
                                 show_type='all')

# Save plot
fig = plt.gcf()
fig.set_size_inches(10 * 1.5, 6 * 1.5, forward=True)
fig.savefig("README_delineate.png", dpi=300, h_pad=3)

# =============================================================================
# Complexity
# =============================================================================

# Generate signal
signal = nk.signal_simulate(frequency=[1, 3], noise=0.01, sampling_rate=100)
Exemple #19
0
def create_df(dataframe: pd.DataFrame) -> pd.DataFrame:
    # get lengths of signals for each sample
    lengths = []
    width = dataframe.shape[1]

    for row in dataframe.index.tolist():
        temp_width = width
        for item in dataframe.loc[row][::-1]:
            if not pd.isna(item) and isinstance(item, float):
                temp_width -= 1
                break

            temp_width -= 1

        lengths.append(temp_width)

    """
    README
    
    For the following features we measured: [mean, median, 5 % percentile, 95 % percentile, standard deviation]
    R-peak location were retrieved by nk.ecg_peaks
    Q-peak and S-location were retrieved by nk.ecg_delineate
    
    ?_ampl_*        ?-Peak amplitude
    ?_nr_peaks      number of ?-Peaks
    ?_diff_*        Interval between ?-Peaks
    QRS_diff_*      QRS duration
    len_*           length of signal
    Qual_*          quality of signal measured with nk.ecg_quality
    sign_*          signal
    
    Also the output from nk.hrv_time which contains different measurements for the heart rate variation (HRV*) was added
    
    Additionally one 'typical' heartbeat was greated (all length 180):
    
    MN_*            mean signal
    MD_*            median signal
    P5_*            5 % percentile signal
    P95_*           95 % percentile signal
    SD_*            standard deviation of signal
    """

    names = ['R_ampl_mean', 'R_ampl_median', 'R_ampl_perc5', 'R_ampl_perc95', 'R_ampl_sd', 'R_nr_peaks',
             'len_mean', 'len_median', 'len_perc5', 'len_perc95', 'len_sd',
             'sign_mean', 'sign_median', 'sign_perc5', 'sign_perc95', 'sign_sd',
             'Qual_mean', 'Qual_median', 'Qual_perc5', 'Qual_perc95', 'Qual_sd',
             'Q_ampl_mean', 'Q_ampl_median', 'Q_ampl_perc5', 'Q_ampl_perc95', 'Q_ampl_sd', 'Q_nr_peaks',
             'Q_diff_mean', 'Q_diff_median', 'Q_diff_perc5', 'Q_diff_perc95', 'Q_diff_sd',
             'S_ampl_mean', 'S_ampl_median', 'S_ampl_perc5', 'S_ampl_perc95', 'S_ampl_sd', 'S_nr_peaks',
             'S_diff_mean', 'S_diff_median', 'S_diff_perc5', 'S_diff_perc95', 'S_diff_sd',
             'P_ampl_mean', 'P_ampl_median', 'P_ampl_perc5', 'P_ampl_perc95', 'P_ampl_sd', 'P_nr_peaks',
             'T_ampl_mean', 'T_ampl_median', 'T_ampl_perc5', 'T_ampl_perc95', 'T_ampl_sd', 'T_nr_peaks',
             'QRS_diff_mean', 'QRS_diff_median', 'QRS_diff_perc5', 'QRS_diff_perc95', 'QRS_diff_sd',
             'PR_diff_mean', 'PR_diff_median', 'PR_diff_perc5', 'PR_diff_perc95', 'PR_diff_sd',
             'RT_diff_mean', 'RT_diff_median', 'RT_diff_perc5', 'RT_diff_perc95', 'RT_diff_sd',
             'HRV_RMSSD', 'HRV_MeanNN', 'HRV_SDNN', 'HRV_SDSD', 'HRV_CVNN', 'HRV_CVSD', 'HRV_MedianNN',
             'HRV_MadNN', 'HRV_MCVNN', 'HRV_IQRNN', 'HRV_pNN50', 'HRV_pNN20', 'HRV_TINN', 'HRV_HTI',
             'HRV_ULF','HRV_VLF','HRV_LF','HRV_HF','HRV_VHF','HRV_LFHF','HRV_LFn','HRV_HFn', 	'HRV_LnHF',
             'HRV_SD1','HRV_SD2', 'HRV_SD1SD2','HRV_S','HRV_CSI','HRV_CVI','HRV_CSI_Modified', 'HRV_PIP',
             'HRV_IALS','HRV_PSS','HRV_PAS','HRV_GI','HRV_SI','HRV_AI','HRV_PI','HRV_C1d','HRV_C1a','HRV_SD1d',
             'HRV_SD1a','HRV_C2d','HRV_C2a','HRV_SD2d','HRV_SD2a','HRV_Cd','HRV_Ca','HRV_SDNNd','HRV_SDNNa','HRV_ApEn',
             'HRV_SampEn','J_LF','J_HF','J_L/H']


    template_len = 180

    mean_names = ['MN_' + str(index) for index in range(template_len)]
    median_names = ['MD_' + str(index) for index in range(template_len)]
    perc5_names = ['P5_' + str(index) for index in range(template_len)]
    perc95_names = ['P95_' + str(index) for index in range(template_len)]
    sd_names = ['SD_' + str(index) for index in range(template_len)]

    wavelet = 'db3'

    wl_len = int(np.floor((template_len + pywt.Wavelet(wavelet).dec_len - 1) / 2))

    wl_mean_names = ['WLMN_' + str(index) for index in range(2*wl_len)]
    wl_median_names = ['WLMD_' + str(index) for index in range(2*wl_len)]
    wl_perc5_names = ['WLP5_' + str(index) for index in range(2*wl_len)]
    wl_perc95_names = ['WLP95_' + str(index) for index in range(2*wl_len)]
    wl_sd_names = ['WLSD_' + str(index) for index in range(2*wl_len)]

    typical_signal_names = mean_names + median_names + perc5_names + perc95_names + sd_names + wl_mean_names + \
                           wl_median_names + wl_perc5_names + wl_perc95_names + wl_sd_names

    names += typical_signal_names

    data = np.empty([dataframe.shape[0], len(names)])

    iteration = 0
    for row_index, row in dataframe.iterrows():
        print(row_index)

        # Retrieve ECG data
        ecg_signal = row[:lengths[iteration] + 1]
        ecg_signal = nk.ecg_clean(ecg_signal, sampling_rate=SAMPLING_RATE)

        # Find R-peaks
        peaks, info = nk.ecg_peaks(ecg_signal, sampling_rate=SAMPLING_RATE)

        # R amplitude
        R_amplitudes = ecg_signal[info['ECG_R_Peaks']]

        # Check if the signal is flipped
        # Check if we have enough peaks to retrieve more information
        if len(R_amplitudes) > 4:

            _, waves_peak = nk.ecg_delineate(ecg_signal, info, sampling_rate=300, show=False)

            # Q amplitude

            # remove nan values
            Q_amplitudes = [ecg_signal[peak_index] if str(peak_index) != 'nan' else - np.infty for peak_index in
                            waves_peak['ECG_Q_Peaks']]

            if np.sum([1 if np.abs(rpeak) > np.abs(Q_amplitudes[index]) else -1 for index, rpeak in
                       enumerate(R_amplitudes)]) < 0:
                print("flip", row_index)

                ecg_signal = -ecg_signal

                peaks, info = nk.ecg_peaks(ecg_signal, sampling_rate=300)

                # R amplitude
                R_amplitudes = ecg_signal[info['ECG_R_Peaks']]

                if len(R_amplitudes) > 4:
                    _, waves_peak = nk.ecg_delineate(ecg_signal, info, sampling_rate=300, show=False)

        data_temp = []
        if len(R_amplitudes) > 0:
            data_temp = [np.mean(R_amplitudes),
                         np.median(R_amplitudes),
                         np.percentile(R_amplitudes, q=5),
                         np.percentile(R_amplitudes, q=95),
                         np.std(R_amplitudes),
                         len(R_amplitudes)]
        else:
            empty = np.empty([6])
            empty[:] = np.NaN
            data_temp += empty.tolist()

        # length of signal
        data_new = [np.mean(lengths[iteration] / SAMPLING_RATE),
                    np.median(lengths[iteration] / SAMPLING_RATE),
                    np.percentile(lengths[iteration] / SAMPLING_RATE, q=5),
                    np.percentile(lengths[iteration] / SAMPLING_RATE, q=95),
                    np.std(lengths[iteration] / SAMPLING_RATE)]

        data_temp += data_new

        # signal
        data_new = [np.mean(ecg_signal),
                    np.median(ecg_signal),
                    np.percentile(ecg_signal, q=5),
                    np.percentile(ecg_signal, q=95),
                    np.std(ecg_signal)]

        data_temp += data_new

        # Check if we have enough peaks to retrieve more information
        if len(R_amplitudes) > 4:

            quality = nk.ecg_quality(ecg_signal, sampling_rate=SAMPLING_RATE)
            data_new = [np.mean(quality),
                        np.median(quality),
                        np.percentile(quality, q=5),
                        np.percentile(quality, q=95),
                        np.std(quality)]

            data_temp += data_new

            # Delineate the ECG signal
            # “ECG_P_Peaks”, “ECG_Q_Peaks”, “ECG_S_Peaks”, “ECG_T_Peaks”, “ECG_P_Onsets”, “ECG_T_Offsets”

            # _, waves_peak = nk.ecg_delineate(ecg_signal, info, sampling_rate=SAMPLING_RATE, show=False)

            # Q amplitude

            # remove nan values
            Q_peaks = [peak for peak in waves_peak['ECG_Q_Peaks'] if str(peak) != 'nan']

            if len(Q_peaks) > 0:
                Q_amplitudes = ecg_signal[Q_peaks]

                data_new = [np.mean(Q_amplitudes),
                            np.median(Q_amplitudes),
                            np.percentile(Q_amplitudes, q=5),
                            np.percentile(Q_amplitudes, q=95),
                            np.std(Q_amplitudes),
                            len(Q_amplitudes)]

                data_temp += data_new
            else:
                empty = np.empty([6])
                empty[:] = np.NaN
                empty[5] = 0
                data_temp += empty.tolist()

            # more than 1 Q-Peak => can build interval[s]
            if len(Q_peaks) > 1:
                Q_peaks_diff = [(Q_peaks[index + 1] - Q_peaks[index]) / SAMPLING_RATE
                                for index, item in enumerate(Q_peaks[:len(Q_peaks) - 1])]

                # QQ interval

                data_new = [np.mean(Q_peaks_diff),
                            np.median(Q_peaks_diff),
                            np.percentile(Q_peaks_diff, q=5),
                            np.percentile(Q_peaks_diff, q=95),
                            np.std(Q_peaks_diff)]

                data_temp += data_new

            # 0 or 1 Q-peak = no interval => return nan
            else:
                empty = np.empty([5])
                empty[:] = np.NaN
                data_temp += empty.tolist()

            # S amplitude

            # remove nan values
            S_peaks = [peak for peak in waves_peak['ECG_S_Peaks'] if str(peak) != 'nan']

            if len(S_peaks) > 0:
                S_amplitudes = ecg_signal[S_peaks]

                data_new = [np.mean(S_amplitudes),
                            np.median(S_amplitudes),
                            np.percentile(S_amplitudes, q=5),
                            np.percentile(S_amplitudes, q=95),
                            np.std(S_amplitudes),
                            len(S_amplitudes)]

                data_temp += data_new

            else:
                empty = np.empty([6])
                empty[:] = np.NaN
                empty[5] = 0
                data_temp += empty.tolist()

            # more than one S-peak
            if len(S_peaks) > 1:
                S_peaks_diff = [(S_peaks[index + 1] - S_peaks[index]) / SAMPLING_RATE
                                for index, item in enumerate(S_peaks[:len(S_peaks) - 1])]

                # SS interval

                data_new = [np.mean(S_peaks_diff),
                            np.median(S_peaks_diff),
                            np.percentile(S_peaks_diff, q=5),
                            np.percentile(S_peaks_diff, q=95),
                            np.std(S_peaks_diff)]

                data_temp += data_new

            # 0 or 1 S-peak = no interval => return nan
            else:
                empty = np.empty([5])
                empty[:] = np.NaN
                data_temp += empty.tolist()

            P_peaks = [peak for peak in waves_peak['ECG_P_Peaks'] if str(peak) != 'nan']

            if len(P_peaks) > 0:
                P_amplitudes = ecg_signal[P_peaks]

                data_new = [np.mean(P_amplitudes),
                            np.median(P_amplitudes),
                            np.percentile(P_amplitudes, q=5),
                            np.percentile(P_amplitudes, q=95),
                            np.std(P_amplitudes),
                            len(P_amplitudes)]

                data_temp += data_new

            else:
                empty = np.empty([6])
                empty[:] = np.NaN
                empty[5] = 0
                data_temp += empty.tolist()

            T_peaks = [peak for peak in waves_peak['ECG_T_Peaks'] if str(peak) != 'nan']

            if len(T_peaks) > 0:
                T_peaks = ecg_signal[T_peaks]

                data_new = [np.mean(T_peaks),
                            np.median(T_peaks),
                            np.percentile(T_peaks, q=5),
                            np.percentile(T_peaks, q=95),
                            np.std(T_peaks),
                            len(T_peaks)]

                data_temp += data_new

            else:
                empty = np.empty([6])
                empty[:] = np.NaN
                empty[5] = 0
                data_temp += empty.tolist()


            # QRS interval

            QRS_peaks_diff = []

            # compute difference between Q and S peak
            for index in range(len(waves_peak['ECG_Q_Peaks'])):
                if not (np.isnan(waves_peak['ECG_Q_Peaks'][index]) or np.isnan(waves_peak['ECG_S_Peaks'][index])):
                    QRS_peaks_diff.append(
                        (waves_peak['ECG_S_Peaks'][index] - waves_peak['ECG_Q_Peaks'][index]) / SAMPLING_RATE)

            if len(QRS_peaks_diff) > 0:
                data_new = [np.mean(QRS_peaks_diff),
                            np.median(QRS_peaks_diff),
                            np.percentile(QRS_peaks_diff, q=5),
                            np.percentile(QRS_peaks_diff, q=95),
                            np.std(QRS_peaks_diff)]

                data_temp += data_new

            else:
                empty = np.empty([5])
                empty[:] = np.NaN
                data_temp += empty.tolist()

            # PR interval

            PR_peaks_diff = []

            # compute difference between P and R peak
            for index in range(len(waves_peak['ECG_P_Peaks'])):
                if not np.isnan(waves_peak['ECG_P_Peaks'][index]):
                    PR_peaks_diff.append(
                        (info['ECG_R_Peaks'][index] - waves_peak['ECG_P_Peaks'][index]) / SAMPLING_RATE)

            if len(PR_peaks_diff) > 0:
                data_new = [np.mean(PR_peaks_diff),
                            np.median(PR_peaks_diff),
                            np.percentile(PR_peaks_diff, q=5),
                            np.percentile(PR_peaks_diff, q=95),
                            np.std(PR_peaks_diff)]

                data_temp += data_new
            else:
                empty = np.empty([5])
                empty[:] = np.NaN
                data_temp += empty.tolist()

            # RT interval

            RT_peaks_diff = []

            # compute difference between P and R peak
            for index in range(len(waves_peak['ECG_T_Peaks'])):
                if not np.isnan(waves_peak['ECG_T_Peaks'][index]):
                    RT_peaks_diff.append(
                        (waves_peak['ECG_T_Peaks'][index] - info['ECG_R_Peaks'][index]) / SAMPLING_RATE)

            if len(RT_peaks_diff) > 0:
                data_new = [np.mean(RT_peaks_diff),
                            np.median(PR_peaks_diff),
                            np.percentile(RT_peaks_diff, q=5),
                            np.percentile(RT_peaks_diff, q=95),
                            np.std(RT_peaks_diff)]

                data_temp += data_new

            else:
                empty = np.empty([5])
                empty[:] = np.NaN
                data_temp += empty.tolist()

            # Extract clean EDA and SCR features
            # explanation of features:
            # https://neurokit2.readthedocs.io/en/latest/functions.html?highlight=hrv%20time#neurokit2.hrv.hrv_time

            hrv_time = nk.hrv(peaks, sampling_rate=SAMPLING_RATE, show=False)

            data_new = hrv_time.values.tolist()[0]

            data_temp += data_new

            # Jannik
            # http://www.paulvangent.com/2016/03/21/analyzing-a-discrete-heart-rate-signal-using-python-part-2/
            rpeaks = info['ECG_R_Peaks']
            r_interval = [rpeaks[index+1]-rpeaks[index] for index in range(len(rpeaks)-1)]
            RR_x_new = np.linspace(rpeaks[0],rpeaks[-2],rpeaks[-2])
            f = interp1d(rpeaks[:-1], r_interval, kind='cubic')

            n = lengths[iteration] + 1 # Length of the signal
            frq = np.fft.fftfreq(n, d=(1 / SAMPLING_RATE)) # divide the bins into frequency categories
            frq = frq[range(int(n/2))] # Get single side of the frequency range

            Y = np.fft.fft(f(RR_x_new))/n # Calculate FFT

            try:
                Y = Y[range(int(n / 2))]
                lf = np.trapz(abs(Y[(frq >= 0.04) & (frq <= 0.15)]))

                hf = np.trapz(abs(Y[(frq >= 0.16) & (frq <= 0.5)]))  # Do the same for 0.16-0.5Hz (HF)

                data_new = [lf, hf, lf / hf]

                data_temp += data_new
            except IndexError as err:
                print(err)
                data_temp += [None, None, None]

        # if we don't have enough R peaks return vector of nan's
        else:
            empty = np.empty([len(names) - 16 - len(typical_signal_names)])
            empty[:] = np.NaN
            data_temp += empty.tolist()

        # Create a 'typical' heartbeat

        # Scaler = StandardScaler()
        # ecg_signal = Scaler.fit_transform(X=ecg_signal.reshape(-1, 1)).reshape(1, -1)[0].tolist()

        out = ecg.ecg(signal=ecg_signal, sampling_rate=SAMPLING_RATE, show=False)

        mean = np.mean(out['templates'], axis=0)
        median = np.median(out['templates'], axis=0)
        perc5 = np.percentile(out['templates'].astype(np.float64), axis=0, q=5)
        perc95 = np.percentile(out['templates'].astype(np.float64), axis=0, q=95)
        std = np.std(out['templates'].astype(np.float64), axis=0)

        data_new = np.concatenate((mean, median, perc5, perc95, std)).tolist()

        data_temp += data_new

        (wl_mean_cA, wl_mean_cD) = pywt.dwt(np.mean(out['templates'], axis=0),
                                            'db3', 'periodic')
        (wl_median_cA, wl_median_cD) = pywt.dwt(np.median(out['templates'], axis=0),
                                                'db3', 'periodic')
        (wl_perc5_cA, wl_perc5_cD) = pywt.dwt(np.percentile(out['templates'].astype(np.float64), axis=0, q=5),
                                              'db3', 'periodic')
        (wl_perc95_cA, wl_perc95_cD) = pywt.dwt(np.percentile(out['templates'].astype(np.float64), axis=0, q=95),
                                                'db3', 'periodic')
        (wl_sd_cA, wl_sd_cD) = pywt.dwt(np.std(out['templates'].astype(np.float64), axis=0),
                                        'db3', 'periodic')

        data_new = np.concatenate((wl_mean_cA, wl_mean_cD,
                                   wl_median_cA, wl_median_cD,
                                   wl_perc5_cA, wl_perc5_cD,
                                   wl_perc95_cA, wl_perc95_cD,
                                   wl_sd_cA, wl_sd_cD)).tolist()

        data_temp += data_new

        data[iteration] = data_temp

        iteration += 1

    features = pd.DataFrame(data, columns=names)

    return features
    def extract_features(
        self,
        clean_method: str = "neurokit",
        r_method: str = "neurokit",
        wave_method: str = "dwt",
        min_peaks: int = 200,
        size: int = 200000,
    ):
        """
        Function to extract the ecg features using the neurokit2 package. That
        is the P, Q, R, S and T peaks and the P, QRS and T waves onsets and
        offsets. The result is saved internally.

        :param clean_method: <str> The processing pipeline to apply. Can be one of
                             ‘neurokit’ (default), ‘biosppy’, ‘pantompkins1985’,
                             ‘hamilton2002’, ‘elgendi2010’, ‘engzeemod2012’.
        :param r_method: <str> The algorithm to be used for R-peak detection. Can be one
                         of ‘neurokit’ (default), ‘pantompkins1985’, ‘hamilton2002’,
                         ‘christov2004’, ‘gamboa2008’, ‘elgendi2010’, ‘engzeemod2012’
                         or ‘kalidas2017’.
        :param wave_method: <str> Can be one of ‘dwt’ (default) for discrete
                            wavelet transform or ‘cwt’ for continuous wavelet transform.
        :param min_peaks: <int> Minimum R peaks to be detected to proceed with
                          further calculations.
        :param size: <int> ECG sample size to analyze per loop.
        """
        if not self.lead:
            return

        for i, _ in enumerate(self.sampling_rate):
            sampling_rate = self.sampling_rate[i][0]
            init = self.sampling_rate[i][1]
            if i == len(self.sampling_rate) - 1:
                ecg_signal_size = (
                    ECG_TMAPS[f"{self.lead}_value"].tensor_from_file(
                        ECG_TMAPS[f"{self.lead}_value"],
                        self,
                        visit=self.visit,
                    )[0][init:].shape[0])
            else:
                ecg_signal_size = self.sampling_rate[i + 1][1] - init
            if size < ecg_signal_size:
                end = init + size
            else:
                end = init + ecg_signal_size
            while init < ecg_signal_size + self.sampling_rate[i][1]:
                ecg_signal = ECG_TMAPS[f"{self.lead}_value"].tensor_from_file(
                    ECG_TMAPS[f"{self.lead}_value"],
                    self,
                    visit=self.visit,
                )[0][init:end]
                ecg_signal = nk.ecg_clean(ecg_signal, sampling_rate,
                                          clean_method)
                try:
                    _, r_peaks = nk.ecg_peaks(ecg_signal, sampling_rate,
                                              r_method)
                except IndexError:
                    init = end
                    end = init + size
                    if end > ecg_signal_size + self.sampling_rate[i][1]:
                        end = ecg_signal_size + self.sampling_rate[i][1]
                    continue

                if len(r_peaks["ECG_R_Peaks"]) < min_peaks:
                    init = end
                    end = init + size
                    if end > ecg_signal_size + self.sampling_rate[i][1]:
                        end = ecg_signal_size + self.sampling_rate[i][1]
                    continue
                _, waves_peaks = nk.ecg_delineate(ecg_signal, r_peaks,
                                                  sampling_rate)
                _, waves_peaks_2 = nk.ecg_delineate(
                    ecg_signal,
                    r_peaks,
                    sampling_rate,
                    wave_method,
                )
                waves_peaks.update(waves_peaks_2)
                for peak_type in r_peaks:
                    if peak_type not in self.r_peaks:
                        self.r_peaks[peak_type] = r_peaks[peak_type]
                    else:
                        self.r_peaks[peak_type] = np.append(
                            self.r_peaks[peak_type],
                            r_peaks[peak_type],
                        )
                for peak_type in waves_peaks:
                    if peak_type not in self.waves_peaks:
                        self.waves_peaks[peak_type] = waves_peaks[peak_type]
                    else:
                        self.waves_peaks[peak_type] = np.append(
                            self.waves_peaks[peak_type],
                            waves_peaks[peak_type],
                        )
                init = end
                end = init + size
                if end > ecg_signal_size + self.sampling_rate[i][1]:
                    end = ecg_signal_size + self.sampling_rate[i][1]

        for peak_type in self.r_peaks:
            self.r_peaks[peak_type] = list(self.r_peaks[peak_type])
        for peak_type in self.waves_peaks:
            self.waves_peaks[peak_type] = list(self.waves_peaks[peak_type])