Exemplo n.º 1
0
    def smooth(self, data):
        sm_size = int(0.08 * self.sample_rate)

        smoothed_data, _ = st.smoother(signal=data,
                                           kernel='hamming',
                                           size=sm_size, mirror=True)

        return smoothed_data
Exemplo n.º 2
0
def diffSCR(data,fs,min_amplitude):
 	#onset at local minimum; peak at diff maximum
	df = np.diff(data)
	df = np.append(df,df[-1])
	size = int(1. * fs)
	df = tools.smoother(df,'bartlett',size)['signal']
	#plotsignal([data,df],False)
	onsets, pks, amps = find_zeropeak(df,min_amplitude,'diff')
	return onsets,pks,amps,df
Exemplo n.º 3
0
def compute_intervals(peaks, smooth=False, size=3):
    intervals = [0]
    for i in range(len(peaks)-1):
        intervals.append(peaks[i+1]-peaks[i])
    intervals = np.array(intervals)
    
    if smooth and (len(intervals) > 1):
        intervals, _ = smoother(signal=intervals, kernel='boxcar', size=size, mirror=True)

    return intervals
Exemplo n.º 4
0
def read_sample(path, name, sampling_rate, preprocess=True):
    dataset = pandas.read_csv(path + name + '.txt',
                              delimiter='\t',
                              skiprows=4,
                              skipfooter=1,
                              engine='python')
    x_signal = dataset.values[:total_length * sampling_rate, 0]
    y = dataset.values[:total_length * sampling_rate, 1]

    y_signal = normalize_data(pandas.DataFrame(y), max_range, min_range)

    if preprocess is True:
        smoothed_signal, params = smoother(y_signal[:, 0])
        y_signal = np.reshape(smoothed_signal, [smoothed_signal.shape[0], 1])

    if sampling_rate != rate:
        down_sample_factor = int(sampling_rate // rate)
        y_signal = decimate(y_signal, down_sample_factor)
        #x_signal = decimate(x_signal, down_sample_factor)
        y_signal = normalize_data(pandas.DataFrame(y), max_range, min_range)

    return x_signal, y_signal
Exemplo n.º 5
0
    def __call__(self, signal):
        import biodata
        from scipy.signal import find_peaks
        from biosppy.signals.tools import get_heart_rate, smoother

        list_smoothing_heart = [None, 10, 100]
        list_smoothing_rate = [None, 1000, 10000]
        list_smoothing_eda = [None, 10]
        list_features = []

        heart_raw = biodata.enveloppe_filter(signal[:, 1])
        heart_peaks, heart_properties = find_peaks(
            heart_raw,
            distance=self.distance_heart,
            width=self.width_heart,
            prominence=self.prominence_heart)
        for smoothing in list_smoothing_heart:
            if smoothing is None:
                size = 1
                smoothing = False
            else:
                size = smoothing
                smoothing = True

            bpm = get_heart_rate(heart_peaks,
                                 sampling_rate=self.sampling_rate,
                                 smooth=smoothing,
                                 size=size)
            amplitudes = heart_properties["prominences"]
            if smoothing:
                amplitudes, _ = smoother(signal=amplitudes,
                                         kernel='boxcar',
                                         size=size,
                                         mirror=True)

            bpm = biodata.interpolate(bpm[1], bpm[0], len(signal))
            amplitudes = biodata.interpolate(amplitudes, heart_peaks,
                                             len(signal))

            list_features += [bpm, amplitudes]

        eda_raw = biodata.enveloppe_filter(signal[:, 2])
        eda_peaks, eda_properties = find_peaks(eda_raw,
                                               distance=self.distance_eda,
                                               width=self.width_eda,
                                               prominence=self.prominence_eda)
        for smoothing in list_smoothing_eda:
            if smoothing is None:
                size = 1
                smoothing = False
            else:
                size = smoothing
                smoothing = True

            intervals = biodata.compute_intervals(eda_peaks,
                                                  smooth=smoothing,
                                                  size=size)
            amplitudes = eda_properties["prominences"]
            if smoothing:
                amplitudes, _ = smoother(signal=amplitudes,
                                         kernel='boxcar',
                                         size=size,
                                         mirror=True)
            intervals = biodata.interpolate(intervals, eda_peaks, len(signal))
            amplitudes = biodata.interpolate(amplitudes, eda_peaks,
                                             len(signal))

            list_features += [intervals, amplitudes]

        for smoothing in list_smoothing_rate:
            if smoothing is None:
                size = 1
                smoothing = False
            else:
                size = smoothing
                smoothing = True

            rate = biodata.rate_of_change(eda_raw, size=size)
            list_features.append(rate)

        features = np.array(list_features).transpose()
        if self.normalization is None:
            pass
        elif self.normalization == "standardized":
            features = (features - features.mean(0)) / features.std(0)
        elif self.normalization == "normalized":
            features = (features - features.min(0)) / (features.max(0) -
                                                       features.min(0))
        else:
            raise ValueError

        return torch.tensor(features).float()
Exemplo n.º 6
0
def resp(signal=None, sampling_rate=1000., show=True):
    """Process a raw Respiration signal and extract relevant signal features
    using default parameters.
    Parameters
    ----------
    signal : array
        Raw Respiration signal.
    sampling_rate : int, float, optional
        Sampling frequency (Hz).
    show : bool, optional
        If True, show a summary plot.
    Returns

    -------
    ts : array
        Signal time axis reference (seconds).
    filtered : array
        Filtered Respiration signal.
    zeros : array
        Indices of Respiration zero crossings.
    resp_rate_ts : array
        Inspiration rate time axis reference (seconds).
    resp_rate : array
        Instantaneous respiration rate (Hz).
    """

    # check inputs
    if signal is None:
        raise TypeError("Please specify an input signal.")

    # ensure numpy
    signal = np.array(signal)
    sampling_rate = float(sampling_rate)

    # filter signal
    # 0.1 ~~ 0.35 Hzのバンドパスフィルタ
    filtered, _, _ = st.filter_signal(signal=signal,
                                      ftype='butter',
                                      band='bandpass',
                                      order=2,
                                      frequency=[0.1, 0.35],
                                      sampling_rate=sampling_rate)

    # compute zero crossings
    filtered = filtered - np.mean(filtered)

    # zeros
    df = np.diff(np.sign(filtered))
    inspiration = np.nonzero(df > 0)[0]
    expiration = np.nonzero(df < 0)[0]

    if len(inspiration) < 2:
        rate_idx = []
        rate = []
    else:
        # compute resp peaks between inspiration and expiration
        peaks = []
        for i in range(len(inspiration) - 1):
            cycle = filtered[inspiration[i]:inspiration[i + 1]]
            peaks.append(np.argmax(cycle) + inspiration[i])
        # list to array
        peaks = np.array(peaks)

        # compute respiration rate
        rate_idx = inspiration[1:]
        rate = sampling_rate * (1. / np.diff(inspiration))

        # physiological limits
        # 0.35Hz以下のresp_rateは省かれる
        indx = np.nonzero(rate <= 0.35)
        rate_idx = rate_idx[indx]
        rate = rate[indx]

        # smooth with moving average
        size = 3
        rate, _ = st.smoother(signal=rate,
                              kernel='boxcar',
                              size=size,
                              mirror=True)

    # get time vectors
    length = len(signal)
    T = (length - 1) / sampling_rate
    ts = np.linspace(0, T, length, endpoint=True)
    ts_rate = ts[rate_idx]

    # plot
    if show:
        plotting.plot_resp(ts=ts,
                           raw=signal,
                           filtered=filtered,
                           zeros=zeros,
                           resp_rate_ts=ts_rate,
                           resp_rate=rate,
                           path=None,
                           show=True)
    # output
    args = (ts, filtered, ts_rate, rate, inspiration, expiration, peaks)
    names = ('ts', 'filtered', 'resp_rate_ts', 'resp_rate', 'inspiration',
             'expiration', 'peaks')
    return utils.ReturnTuple(args, names)
Exemplo n.º 7
0
def ecg(
    Kb=130,
    Ap=0.2,
    Kp=100,
    Kpq=40,
    Aq=0.1,
    Kq1=25,
    Kq2=5,
    Ar=0.7,
    Kr=40,
    As=0.2,
    Ks=30,
    Kcs=5,
    sm=96,
    Kst=100,
    At=0.15,
    Kt=220,
    si=2,
    Ki=200,
    var=0.01,
    sampling_rate=10000,
):  # normal values by default
    """Concatenates the segments and waves to make an ECG signal. The default values are physiological.

    Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03].

    If the parameters introduced aren't within physiological values (limits based on the website [ECGwaves]), a warning will raise.

    Parameters
    ----------
    Kb : int, optional
        B segment width (miliseconds).
    Ap : float, optional
        P wave amplitude (milivolts).
    Kp : int, optional
        P wave width (miliseconds).
    Kpq : int, optional
        PQ segment width (miliseconds).
    Aq : float, optional
        Q wave amplitude (milivolts).
    Kq1 : int, optional
        First 5/6 of the Q wave width (miliseconds).
    Kq2 : int, optional
        Last 1/6 of the Q wave width (miliseconds).
    Ar : float, optional
        R wave amplitude (milivolts).
    Kr : int, optional
        R wave width (miliseconds).
    As : float, optional
        S wave amplitude (milivolts).
    Ks : int, optional
        S wave width (miliseconds).
    Kcs : int, optional
        Parameter which allows slight adjustment of S wave shape by cutting away a portion at the end.
    sm : int, optional
        Slope parameter in the ST segment.
    Kst : int, optional
        ST segment width (miliseconds).
    At : float, optional
        1/2 of the T wave amplitude (milivolts).
    Kt : int, optional
        T wave width (miliseconds).
    si : int, optional
        Parameter for setting the transition slope between T wave and isoelectric line.
    Ki : int, optional
        I segment width (miliseconds).
    var : float, optional
        Value between 0.0 and 1.0 that adds variability to the obtained signal, by changing each parameter following a normal distribution with mean value `parameter_value` and std `var * parameter_value`.
    sampling_rate : int, optional
        Sampling frequency (Hz).

    Returns
    -------
    ecg : array
        Amplitude values of the ECG wave.
    t : array
        Time values accoring to the provided sampling rate.
    params : dict
        Input parameters of the function


    Example
    -------
    sampling_rate = 10000
    beats = 3
    noise_amplitude = 0.05

    ECGtotal = np.array([])
    for i in range(beats):
        ECGwave = ecg(sampling_rate=sampling_rate, var=0.1)
        ECGtotal = np.concatenate((ECGtotal, ECGwave))
    t = np.arange(0, len(ECGtotal)) / sampling_rate

    # add powerline noise (50 Hz)
    noise = noise_amplitude * np.sin(50 * (2 * pi) * t)
    ECGtotal += noise

    plt.plot(t, ECGtotal)
    plt.xlabel("Time (ms)")
    plt.ylabel("Amplitude (mV)")
    plt.grid()
    plt.title("ECG")

    plt.show()

    References
    ----------
    .. [Model03] Pavol DOLINSKÝ, Imrich ANDRÁŠ, Linus MICHAELI, Domenico GRIMALDI,
       "MODEL FOR GENERATING SIMPLE SYNTHETIC ECG SIGNALS",
       Acta Electrotechnica et Informatica, Vol. 18, No. 3, 2018, 3–8
    .. [ECGwaves] https://ecgwaves.com/
    """
    if Kp > 120 and Ap >= 0.25:
        warnings.warn("P wave isn't within physiological values.")

    if Kq1 + Kq2 > 30 or Aq > 0.25 * Ar:
        warnings.warn("Q wave isn't within physiological values.")

    if 120 > Kp + Kpq or Kp + Kpq > 220:
        warnings.warn("PR interval isn't within physiological limits.")

    if Kq1 + Kq2 + Kr + Ks - Kcs > 120:
        warnings.warn(
            "QRS complex duration isn't within physiological limits.")

    if Kq1 + Kq2 + Kr + Ks - Kcs + Kst + Kt > 450:
        warnings.warn(
            "QT segment duration isn't within physiological limits for men.")

    if Kq1 + Kq2 + Kr + Ks - Kcs + Kst + Kt > 470:
        warnings.warn(
            "QT segment duration isn't within physiological limits for women.")

    if var < 0 or var > 1:
        raise TypeError("Variability value should be between 0.0 and 1.0")

    if var > 0:
        # change the parameter according to the provided variability
        nd = lambda x: np.random.normal(x, x * var)
        Kb = round(np.clip(nd(Kb), 0, 130))
        Ap = np.clip(nd(Ap), -0.2, 0.5)
        Kp = np.clip(nd(Kp), 10, 100)
        Kpq = round(np.clip(nd(Kpq), 0, 60))
        Aq = np.clip(nd(Aq), 0, 0.5)
        Kq1 = round(np.clip(nd(Kq1), 0, 70))
        Kq2 = round(np.clip(nd(Kq2), 0, 50))
        Ar = np.clip(nd(Ar), 0.5, 2)
        Kr = round(np.clip(nd(Kr), 10, 150))
        As = np.clip(nd(As), 0, 1)
        Ks = round(np.clip(nd(Ks), 10, 200))
        Kcs = round(np.clip(nd(Kcs), -5, 150))
        sm = round(np.clip(nd(sm), 1, 150))
        Kst = round(np.clip(nd(Kst), 0, 110))
        At = np.clip(nd(At), -0.5, 1)
        Kt = round(np.clip(nd(Kt), 50, 300))
        si = round(np.clip(nd(si), 0, 50))

    # variable i is the time between samples (in miliseconds)
    i = 1000 / sampling_rate
    l = int(1 / i)

    B_to_S = (B(Kb, l) + P(Ap, Kp, i) + Pq(Kpq, l) + Q1(Aq, Kq1, i) +
              Q2(Aq, Kq2, i) + R(Ar, Kr, i) + S(As, Ks, Kcs, i))
    St_to_I = (St(As, Ks, Kcs, sm, Kst, i) +
               T(As, Ks, Kcs, sm, Kst, At, Kt, i) +
               I(As, Ks, Kcs, sm, Kst, At, Kt, si, Ki, i))

    # The signal is filtered in two different sizes
    ECG1_filtered, n1 = st.smoother(B_to_S, size=50)
    ECG2_filtered, n2 = st.smoother(St_to_I, size=500)

    # The signal is concatenated
    ECGwave = np.concatenate((ECG1_filtered, ECG2_filtered))

    # Time array
    t = np.arange(0, len(ECGwave)) / sampling_rate

    # output
    params = {
        "Kb": 130,
        "Ap": 0.2,
        "Kp": 100,
        "Kpq": 40,
        "Aq": 0.1,
        "Kq1": 25,
        "Kq2": 5,
        "Ar": 0.7,
        "Kr": 40,
        "As": 0.2,
        "Ks": 30,
        "Kcs": 5,
        "sm": 96,
        "Kst": 100,
        "At": 0.15,
        "Kt": 220,
        "si": 2,
        "Ki": 200,
        "var": 0.01,
        "sampling_rate": 10000,
    }

    args = (ECGwave, t, params)
    names = ("ecg", "t", "params")

    return utils.ReturnTuple(args, names)
Exemplo n.º 8
0
                                               band='bandpass',
                                               order=order,
                                               frequency=[2, 50],
                                               sampling_rate=sampling_rate)

    filtered_data_ch2, _, _ = st.filter_signal(signal=data_ch2_arr,
                                               ftype='FIR',
                                               band='bandpass',
                                               order=order,
                                               frequency=[2, 50],
                                               sampling_rate=sampling_rate)


    # Smooth
    filtered_data_ch1, _ = st.smoother(signal=filtered_data_ch1,
                                       kernel='hamming',
                                       size=sm_size, mirror=True)

    filtered_data_ch2, _ = st.smoother(signal=filtered_data_ch2,
                                       kernel='hamming',
                                       size=sm_size, mirror=True)

    # Peaks

    peaks_ch1 = find_peaks(filtered_data_ch1, sampling_rate)

    peaks_ch2 = find_peaks(filtered_data_ch2, sampling_rate)


    for i in range(0, len(peaks_ch1)):
        peak1 = -5
def calculateECGFeatures(dataFrame, smooth=True, normalize=True):
    '''
Inputs:     dataFrame   pandas.dataFrame containing clip of raw ECG data, should have two columns of
                        Timestamps (ms) and Sample (V)
                        
            smooth      optional Boolean, default value is True, flag for whether to smooth input raw
                        ECG data or not
            
            normalize   option Boolean, default value is True, flag for whether to normalize input raw
                        ECG data or not

Outputs:    features    pandas.dataFrame for input clip of data, each column corresponds to a different
                        feature, included features are as follows:
                        - mean                      - ultra low frequency power
                        - median                    - very low frequency power
                        - max                       - low frequency power
                        - variance                  - high frequency power
                        - standard deviation        - LF/HF ratio
                        - absolute deviation        - total power
                        - kurtois                   - R-R interval
                        - skew
'''

    # ----------------------------------------------------------------------------------------------------
    # Data Preprocessing ---------------------------------------------------------------------------------
    # ----------------------------------------------------------------------------------------------------

    time = dataFrame['Timestamp (ms)'].values
    data = dataFrame['Sample (V)'].values

    ## Smooth raw ECG data
    if smooth:
        smooth_signal = tools.smoother(
            data, kernel='median', size=5)  # Convolutional 5x5 kernel window
        data = smooth_signal['signal']

    ## Normalize raw ECG data
    if normalize:
        norm_signal = tools.normalize(data)
        data = norm_signal['signal']

    # ----------------------------------------------------------------------------------------------------
    # Begin Features Extraction Code ---------------------------------------------------------------------
    # ----------------------------------------------------------------------------------------------------
    ## Calculate basic statistic features
    s_mean, s_med, s_max, s_var, s_std_dev, s_abs_dev, s_kurtois, s_skew = tools.signal_stats(
        data)

    ## Obtain Power Spectra
    power_freqs, power_spectrum = tools.power_spectrum(data,
                                                       sampling_rate=2.0,
                                                       decibel=False)

    ## Calculate Ultra Low-Frequency Power (ULF Band: <= 0.003 Hz)
    #    power_ulf = tools.band_power(freqs=power_freqs, power=power_spectrum, frequency=[0, 0.003])
    #    power_ulf = np.absolute(power_ulf['avg_power'])

    # Calculate Very Low-Frequency Power (VLF Band: 0.0033 - 0.04 Hz)
    power_vlf = tools.band_power(freqs=power_freqs,
                                 power=power_spectrum,
                                 frequency=[0.0033, 0.04])
    power_vlf = np.absolute(power_vlf['avg_power'])

    # Calculate Low-Frequency Power (LF Band: 0.04 - 0.15 Hz Hz)
    power_lf = tools.band_power(freqs=power_freqs,
                                power=power_spectrum,
                                frequency=[0.04, 0.15])
    power_lf = np.absolute(power_lf['avg_power'])

    ## Calculate High-Frequency Power (HF Band: 0.15 - 0.40 Hz)
    power_hf = tools.band_power(freqs=power_freqs,
                                power=power_spectrum,
                                frequency=[0.15, 0.40])
    power_hf = np.absolute(power_hf['avg_power'])

    ## Calculate LF/HF Ratio
    lf_hf_ratio = power_lf / power_hf

    ## Calculate Total Power (VLF + LF + HF power)
    power_total = power_vlf + power_lf + power_hf

    # Calculate R peak indices
    r_peaks = ecg.engzee_segmenter(data, sampling_rate=500.0)
    if np.size(r_peaks) != 1:
        rr_indices = time[r_peaks]
        rr_intervals = np.mean(np.diff(rr_indices))
    else:
        rr_intervals = np.nan  # NaN indicates not enough R peaks within window to calculate R-R interval

    # ----------------------------------------------------------------------------------------------------
    # Collect Features and convert into dataFrame --------------------------------------------------------
    # ----------------------------------------------------------------------------------------------------

    signal_features = {
        'mean': s_mean,
        'median': s_med,
        'max': s_max,
        'variance': s_var,
        'std_dev': s_std_dev,
        'abs_dev': s_abs_dev,
        'kurtois': s_kurtois,
        'skew': s_skew,
        #                       'ulf_power': power_ulf,
        'vlf_power': power_vlf,
        'lf_power': power_lf,
        'hf_power': power_hf,
        'lf_hf_ratio': lf_hf_ratio,
        'rr_interval': rr_intervals,
    }

    features = pd.Series(signal_features)

    a = [
        s_mean,
        s_med,
        s_max,
        s_var,
        s_std_dev,
        s_abs_dev,
        s_kurtois,
        s_skew,
        #         power_ulf,
        power_vlf,
        power_lf,
        power_hf,
        lf_hf_ratio,
        rr_intervals
        #      rr_indices
    ]
    return a