Beispiel #1
0
def test_hrv_frequency():
    # Test frequency domain
    ecg1 = nk.ecg_simulate(duration=60,
                           sampling_rate=2000,
                           heart_rate=70,
                           random_state=42)
    _, peaks1 = nk.ecg_process(ecg1, sampling_rate=2000)
    hrv1 = nk.hrv_frequency(peaks1, sampling_rate=2000)

    ecg2 = nk.signal_resample(ecg1,
                              sampling_rate=2000,
                              desired_sampling_rate=500)
    _, peaks2 = nk.ecg_process(ecg2, sampling_rate=500)
    hrv2 = nk.hrv_frequency(peaks2, sampling_rate=500)

    assert np.allclose(hrv1["HRV_HF"] - hrv2["HRV_HF"], 0, atol=1.5)
    assert np.isnan(hrv1["HRV_LF"][0])
    assert np.isnan(hrv2["HRV_LF"][0])
    assert np.isnan(hrv1["HRV_VLF"][0])
    assert np.isnan(hrv2["HRV_LF"][0])

    # Test warning on too short duration
    with pytest.warns(nk.misc.NeuroKitWarning,
                      match=r"The duration of recording is too short.*"):
        ecg3 = nk.ecg_simulate(duration=10,
                               sampling_rate=2000,
                               heart_rate=70,
                               random_state=42)
        _, peaks3 = nk.ecg_process(ecg3, sampling_rate=2000)
        nk.hrv_frequency(peaks3, sampling_rate=2000, silent=False)
Beispiel #2
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
Beispiel #3
0
def test_hrv_frequency():
    # Test frequency domain
    ecg1 = nk.ecg_simulate(duration=60,
                           sampling_rate=2000,
                           heart_rate=70,
                           random_state=42)
    _, peaks1 = nk.ecg_process(ecg1, sampling_rate=2000)
    hrv1 = nk.hrv_frequency(peaks1, sampling_rate=2000)

    ecg2 = nk.signal_resample(ecg1,
                              sampling_rate=2000,
                              desired_sampling_rate=500)
    _, peaks2 = nk.ecg_process(ecg2, sampling_rate=500)
    hrv2 = nk.hrv_frequency(peaks2, sampling_rate=500)

    assert np.allclose(hrv1["HRV_HF"] - hrv2["HRV_HF"], 0, atol=1.5)
    assert np.isnan(hrv1["HRV_LF"][0])
    assert np.isnan(hrv2["HRV_LF"][0])
    assert np.isnan(hrv1["HRV_VLF"][0])
    assert np.isnan(hrv2["HRV_LF"][0])
def my_hrv(peaks, sampling_rate):
    result = []
    result.append(nk.hrv_time(peaks, sampling_rate=sampling_rate))
    result.append(
        nk.hrv_frequency(peaks,
                         sampling_rate=sampling_rate,
                         vlf=(0.01, 0.04),
                         lf=(0.04, 0.15),
                         hf=(0.15, 0.4),
                         vhf=(0.4, 1)))
    return pd.concat(result, axis=1)
Beispiel #5
0
def process_bvp(bvp, show_fig=False):
    """
        Compute BVP signal features (more info: https://neurokit2.readthedocs.io/en/latest/functions.html#module-neurokit2.ppg).
        Compute HRV indices (more info: https://neurokit2.readthedocs.io/en/latest/functions.html#module-neurokit2.hrv)
        Parameters
        ----------
        bvp : dict [timestamp : value]
            EDA signal.

        Returns
        -------
        bvp_signals : DataFrame
        bvp_info : dict
    """

    bvp_signals, bvp_info = nk.ppg_process(bvp['value'], sampling_rate=64)

    # First 5 seconds of the signal.
    # Find peaks
    peaks = bvp_signals['PPG_Peaks'][:320]

    # Compute HRV indices
    time_hrv = nk.hrv_time(peaks, sampling_rate=64, show=show_fig)

    hrv_base = time_hrv
    hrv_base['type'] = 'base'

    # The rest part of the signal.
    # Find peaks
    peaks = bvp_signals['PPG_Peaks'][320:]

    # Compute HRV indices
    phase_hrv = nk.hrv_frequency(peaks, sampling_rate=64, show=show_fig)
    time_hrv = nk.hrv_time(peaks, sampling_rate=64, show=show_fig)
    nonlinear_hrv = nk.hrv_nonlinear(peaks, sampling_rate=64, show=show_fig)

    hrv_indices = pd.concat([phase_hrv, time_hrv, nonlinear_hrv], axis=1)
    hrv_indices['type'] = 'stimul'

    hrv_indices = pd.concat([hrv_indices, hrv_base])

    return bvp_signals, bvp_info, hrv_indices
Beispiel #6
0
def signals_analysis(signals, is_out=False, is_show=False, out_path="figs"):
    """
    数据的分析 主要是特征参数的获取
    :param signals:     初步处理过的数据
    :param is_out:
    :param is_show:
    :param out_path:
    :return:
    """
    sampling_rate = signals["Sampling Rate"]
    feature_points = signals["Feature Points"]
    cleaned_pulses = feature_points["Cleaned Pulses"]
    peaks = feature_points["Peaks"]

    title = "Time Analysis"
    hrv_time = nk.hrv_time(peaks, sampling_rate, show=is_show)
    if is_out:
        no = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        out_name = os.path.join("outputs",
                                str(out_path) + "___" + no + title + ".png")
        plt.savefig(out_name, dpi=300)
    if is_show:
        plt.show()

    title = "Frequency Analysis"
    hrv_freq = nk.hrv_frequency(peaks, sampling_rate, show=is_show)
    if is_out:
        no = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        out_name = os.path.join("outputs",
                                str(out_path) + "___" + no + title + ".png")
        plt.savefig(out_name, dpi=300)
    if is_show:
        plt.show()

    title = "Nonlinear Analysis"
    hrv_nonlinear = nk.hrv_nonlinear(peaks, sampling_rate, show=is_show)
    if is_out:
        no = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        out_name = os.path.join("outputs",
                                str(out_path) + "___" + no + title + ".png")
        plt.savefig(out_name, dpi=300)
    if is_show:
        plt.show()

    # 傅里叶分析  对应给的文章
    xFFT = np.abs(np.fft.rfft(cleaned_pulses) / len(cleaned_pulses))
    xFFT = xFFT[:600]
    xFreqs = np.linspace(0, sampling_rate // 2, len(cleaned_pulses) // 2 + 1)
    xFreqs = xFreqs[:600]
    # 滤波处理 平滑去噪 只处理前200个信号即可
    # TODO 去噪方法可以调节
    cleaned_xFFT = nk.signal_smooth(xFFT, method="loess")
    # 计算特征值
    # F1值
    cleaned_FFT = cleaned_xFFT.copy()
    locmax, props = spsg.find_peaks(cleaned_xFFT)
    hr_hz_index = np.argmax(cleaned_xFFT)
    f1 = np.argmax(xFFT)
    fmax = np.argmax(cleaned_xFFT[locmax])
    cleaned_xFFT[locmax[fmax]] = np.min(cleaned_xFFT)
    f2s = np.argmax(cleaned_xFFT[locmax])
    if f2s - fmax != 1:
        hr_hz_index = locmax[0] + int(np.sqrt(locmax[1] - locmax[0]))
    # F2值
    f2 = locmax[np.argmax(cleaned_xFFT[locmax])]
    F1 = np.round(xFreqs[f1], 2)
    F2 = np.round(xFreqs[f2], 2)
    # 相位差
    F2_F1 = F2 - F1
    # 心率
    HR_FFT = xFreqs[hr_hz_index] * 60
    print(HR_FFT)

    if is_show:
        plt.plot(xFreqs, cleaned_FFT)
        plt.scatter(xFreqs[f1],
                    cleaned_FFT[f1],
                    color="red",
                    label="F1 = " + str(F1) + "HZ")
        plt.scatter(xFreqs[f2],
                    cleaned_FFT[f2],
                    color="orange",
                    label="F2 = " + str(F2) + "HZ")
        plt.legend(loc="upper right")
        plt.ylabel("Power")
        plt.xlabel("Freq(Hz)")
        title = "FFT analysis"
        plt.title(title)
        if is_out:
            no = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
            out_name = os.path.join(
                "outputs",
                str(out_path) + "___" + no + title + ".png")
            plt.savefig(out_name, dpi=300)
        plt.show()
    hrv_new = {
        "Power": xFFT,
        "Freq": cleaned_FFT,
        "X": xFreqs,
        "F1": F1,
        "F2": F2,
        "F2_F1": F2_F1,
        "HR_FFT": HR_FFT
    }
    return {
        "HRV New": hrv_new,
        "HRV Time": hrv_time,
        "HRV Frequency": hrv_freq,
        "HRV Nonlinear": hrv_nonlinear
    }
def process_epochs_neurokit(signal, window_len=300, jump_len=300):

    t = datetime.now()

    indexes = np.arange(0, len(signal), int(jump_len * data.sample_rate))
    print(
        f"\nRunning NeuroKit analysis in {window_len}-second windows with jump interval of {jump_len} seconds"
        f"({len(indexes)} iterations)...")

    # Within-epoch processing using NeuroKit to match Cardioscope output
    df_nk = pd.DataFrame([[], [], [], [], [], [], [], [], [], [], [], [], [],
                          [], [], []]).transpose()
    df_nk.columns = [
        "Timestamp", "Index", "Quality", "HR", "meanRR", "sdRR", "meanNN",
        "SDNN", "pNN20", 'pNN50', "VLF", "LF", "HF", "LF/HF", "LFn", "HFn"
    ]

    print("\nProcessing data in epochs with NeuroKit2...")

    for start in indexes:

        print(f"{round(100*start/len(signal), 1)}%")

        try:
            s, i = nk.ecg_process(signal[start:start +
                                         int(data.sample_rate * window_len)],
                                  sampling_rate=data.sample_rate)
            s = s.loc[s["ECG_R_Peaks"] == 1]
            inds = [i for i in s.index]

            hrv = nk.hrv_time(peaks=inds,
                              sampling_rate=data.sample_rate,
                              show=False)
            freq = nk.hrv_frequency(peaks=inds,
                                    sampling_rate=data.sample_rate,
                                    show=False)

            rr_ints = [(d2 - d1) / data.sample_rate
                       for d1, d2 in zip(inds[:], inds[1:])]
            mean_rr = 1000 * np.mean(rr_ints)
            sd_rr = 1000 * np.std(rr_ints)

            out = [
                data.timestamps[start], start, 100 * s["ECG_Quality"].mean(),
                s["ECG_Rate"].mean().__round__(3), mean_rr, sd_rr,
                hrv["HRV_MeanNN"].iloc[0], hrv["HRV_SDNN"].iloc[0],
                hrv["HRV_pNN20"].iloc[0], hrv["HRV_pNN50"].iloc[0],
                freq["HRV_VLF"].iloc[0], freq["HRV_LF"].iloc[0],
                freq["HRV_HF"].iloc[0], freq["HRV_LFHF"].iloc[0],
                freq["HRV_LFn"].iloc[0], freq["HRV_HFn"].iloc[0]
            ]

            df_out = pd.DataFrame(out).transpose()
            df_out.columns = df_nk.columns
            df_nk = df_nk.append(df_out, ignore_index=True)

        except (ValueError, IndexError):
            out = [
                data.timestamps[start], start, None, None, None, None, None,
                None, None, None, None, None, None, None, None
            ]

            df_out = pd.DataFrame(out).transpose()
            df_out.columns = df_nk.columns
            df_nk = df_nk.append(df_out, ignore_index=True)

    t1 = datetime.now()
    td = (t1 - t).total_seconds()
    print(f"100% ({round(td, 1)} seconds)")

    df_nk["Timestamp"] = pd.date_range(start=bf["Timestamp"].iloc[0],
                                       freq=f"{jump_len}S",
                                       periods=df_nk.shape[0])

    return df_nk
Beispiel #8
0
def extract_bvp_features(bvp_data, sampling_rate):
    # Extract Heart Rate, RR Interval, and Heart Rate Variability features from PPG signals
    # bvp_data = MinMaxScaler().fit_transform(np.array(bvp_data).reshape(-1, 1)).ravel()
    ppg_signals, info = nk.ppg_process(bvp_data, sampling_rate=sampling_rate)
    hr = ppg_signals['PPG_Rate']
    # hr = MinMaxScaler().fit_transform(np.array(hr).reshape(-1, 1)).ravel()
    peaks = info['PPG_Peaks']

    # Sanitize input
    peaks = _hrv_sanitize_input(peaks)
    if isinstance(peaks, tuple):  # Detect actual sampling rate
        peaks, sampling_rate = peaks[0], peaks[1]
    rri = _hrv_get_rri(peaks, sampling_rate=sampling_rate, interpolate=False)
    diff_rri = np.diff(rri)
    hrv_features = nk.hrv(
        peaks, sampling_rate=sampling_rate
    )  # Ignore NeuroKitWarning: The duration of recording is too short to support a sufficiently long window for high frequency resolution as we used another frequency for hrv_frequency
    hrv_frequency = nk.hrv_frequency(
        peaks,
        sampling_rate=sampling_rate,
        ulf=(0.01, 0.04),
        lf=(0.04, 0.15),
        hf=(0.15, 0.4)
    )  # the parameters of ULF, LF, HF follows the original paper of WESAD dataset

    # Philip Schmidt, Attila Reiss, Robert Duerichen, Claus Marberger, and Kristof Van Laerhoven. 2018. Introducing WESAD, a Multimodal Dataset for Wearable Stress and Affect Detection.
    # In Proceedings of the 20th ACM International Conference on Multimodal Interaction (ICMI '18). Association for Computing Machinery, New York, NY, USA, 400–408. DOI:https://doi.org/10.1145/3242969.3242985
    # Not including: f_x_HRV of ULF and HLF, rel_f_x, sum f_x_HRV
    mean_HR, std_HR = np.mean(hr), np.std(hr)
    mean_HRV, std_HRV = hrv_features['HRV_MeanNN'], hrv_features['HRV_SDNN']
    HRV_ULF, HRV_LF, HRV_HF, HRV_LFHF, HRV_LFnorm, HRV_HFnorm = hrv_frequency[
        'HRV_ULF'], hrv_frequency['HRV_LF'], hrv_frequency[
            'HRV_HF'], hrv_frequency['HRV_LFHF'], hrv_frequency[
                'HRV_LFn'], hrv_frequency['HRV_HFn']
    rms = np.sqrt(np.nanmean(rri**2))
    nn50 = np.sum(np.abs(diff_rri) > 50)
    HRV_TINN, HRV_pNN50, HRV_RMSSD = hrv_features['HRV_TINN'], hrv_features[
        'HRV_pNN50'], hrv_features['HRV_RMSSD']

    # Nkurikiyeyezu, K., Yokokubo, A., & Lopez, G. (2019). The Influence of Person-Specific Biometrics in Improving Generic Stress Predictive Models.
    # ArXiv, abs/1910.01770.
    kurtosis_HRV, skewness_HRV = kurtosis(rri), skew(rri)
    HRV_VLF = hrv_frequency['HRV_VLF']
    HRV_SD1, HRV_SD2 = hrv_features['HRV_SD1'], hrv_features['HRV_SD2']
    HRV_SDSD = hrv_features['HRV_SDSD']
    HRV_SDSD_RMSSD = HRV_SDSD / HRV_RMSSD
    adj_sum_rri = diff_rri + 2 * rri[:-1]
    HRV_pNN25 = np.sum(np.abs(diff_rri) > 25) / len(rri) * 100
    relative_RRI = 2 * diff_rri / adj_sum_rri
    mean_relativeRRI, median_relativeRRI, std_relativeRRI, RMSSD_relativeRRI, kurtosis_relativeRRI, skew_relativeRRI = np.mean(
        relative_RRI), np.median(relative_RRI), np.std(relative_RRI), np.sqrt(
            np.mean(np.diff(relative_RRI)**2)), kurtosis(relative_RRI), skew(
                relative_RRI)

    # Combining the extracted features
    features = [
        mean_HR, std_HR, mean_HRV, std_HRV, kurtosis_HRV, skewness_HRV, rms,
        nn50, HRV_pNN50, HRV_pNN25, HRV_TINN, HRV_RMSSD, HRV_LF, HRV_HF,
        HRV_LFHF, HRV_LFnorm, HRV_HFnorm, HRV_SD1, HRV_SD2, HRV_SDSD,
        HRV_SDSD_RMSSD, mean_relativeRRI, median_relativeRRI, std_relativeRRI,
        RMSSD_relativeRRI, kurtosis_relativeRRI, skew_relativeRRI
    ]
    features = np.array(list(map(float, features)))
    return features