예제 #1
0
def get_all_features_hrva(data_sample, sample_rate=100, rpeak_method=0):
    """
    :param data_sample:
    :param sample_rate:
    :param rpeak_method:
    :return:
    """

    if rpeak_method in [1, 2, 3, 4]:
        detector = PeakDetector()
        peak_list = detector.ppg_detector(data_sample, rpeak_method)[0]
    else:
        rol_mean = rolling_mean(data_sample,
                                windowsize=0.75,
                                sample_rate=100.0)
        peaks_wd = detect_peaks(data_sample,
                                rol_mean,
                                ma_perc=20,
                                sample_rate=100.0)
        peak_list = peaks_wd["peaklist"]

    rr_list = np.diff(peak_list) * (1000 / sample_rate)  #1000 milisecond

    nn_list = get_nn_intervals(rr_list)
    nn_list_non_na = np.copy(nn_list)
    nn_list_non_na[np.where(np.isnan(nn_list_non_na))[0]] = -1

    time_domain_features = get_time_domain_features(rr_list)
    frequency_domain_features = get_frequency_domain_features(rr_list)
    geometrical_features = get_geometrical_features(rr_list)
    csi_cvi_features = get_csi_cvi_features(rr_list)

    return time_domain_features,frequency_domain_features,\
           geometrical_features,csi_cvi_features
예제 #2
0
def split_segment(s, split_type=0, duration=30.0,
                      overlaping=1,sampling_rate=100,
                   peak_detector=7, wave_type='ppg'):
    """
    Save segment waveform and plot (optional) to csv and image file.
    Input is a segment with timestamps.

    Parameters
    ----------
    s :
        array-like represent the signal.
    split_type :
        0: split by time
        1: split by beat
    duration :
        the duration of each segment if split by time in seconds, default = 30 (second)
        the number of complex/beat in each segement if split by beat, default = 30(beat/segment)

    sampling_rate :
        device sampling rate

    peak_detector :
        The type of peak detection if split the segment by beat.

    wave_type:
        Type of signal. Either 'ppg' or 'ecg'

    Returns
    -------
    >>>from vital_sqi.common.utils import generate_timestamp
    >>>s = np.arange(100000)
    >>>timestamps = generate_timestamp(None,100,len(s))
    >>>df = pd.DataFrame(np.hstack((np.array(timestamps).reshape(-1,1),
                                 np.array(s).reshape(-1,1))))
    >>>split_segment(df,overlaping=3)
    """
    assert check_signal_format(s) is True
    if split_type is 0:
        chunk_size = int(duration * sampling_rate)
        chunk_step = int(overlaping * sampling_rate)
        chunk_indices = [
                [int(i), int(i + chunk_size)] for i in
                range(0, len(s), chunk_size - chunk_step)
            ]
    else:
        if wave_type == 'ppg':
            detector = PeakDetector(wave_type='ppg')
            peak_list, trough_list = detector.ppg_detector(s,detector_type=peak_detector)
        else:
            detector = PeakDetector(wave_type='ecg')
            peak_list, trough_list = detector.ecg_detector(s, detector_type=peak_detector)
        chunk_indices = [
                [peak_list[i], peak_list[i+duration]] for i in range(0,
                                                                     len(peak_list),int(duration-overlaping))
        ]
        chunk_indices[0] = 0
    milestones = pd.DataFrame(chunk_indices)
    segments = cut_segment(s, milestones)
    return segments, milestones
예제 #3
0
def msq_sqi(s, peak_detector_1=7, peak_detector_2=6, wave_type='ppg'):
    """
    MSQ SQI as defined in Elgendi et al
    "Optimal Signal Quality Index for Photoplethysmogram Signals"
    with modification of the second algorithm used.
    Instead of Bing's, a SciPy built-in implementation is used.
    The SQI tracks the agreement between two peak detectors
    to evaluate quality of the signal.

    Parameters
    ----------
    s : sequence
        A signal with peaks.

    peak_detector_1 : array of int
        Type of the primary peak detection algorithm, default = Billauer

    peak_detect2 : int
        Type of the second peak detection algorithm, default = Scipy

    Returns
    -------
    msq_sqi : number
        MSQ SQI value for the given signal

    """
    if wave_type == 'ppg':
        detector = PeakDetector(wave_type='ppg')
        peaks_1, trough_list = detector.ppg_detector(
            s, detector_type=peak_detector_1)
        peaks_2 = detector.ppg_detector(s,
                                        detector_type=peak_detector_2,
                                        preprocess=False)
    else:
        detector = PeakDetector(wave_type='ecg')
        peaks_1, trough_list = detector.ecg_detector(
            s, detector_type=peak_detector_1)
        peaks_2 = detector.ecg_detector(s,
                                        detector_type=peak_detector_2,
                                        preprocess=False)
    if len(peaks_1) == 0 or len(peaks_2) == 0:
        return 0.0
    peak1_dom = len(np.intersect1d(peaks_1, peaks_2)) / len(peaks_1)
    peak2_dom = len(np.intersect1d(peaks_2, peaks_1)) / len(peaks_2)
    return min(peak1_dom, peak2_dom)
예제 #4
0
def msq(x):
    """Mean signal quality"""
    # Library
    from vital_sqi.common.rpeak_detection import PeakDetector
    # Detection of peaks
    detector = PeakDetector()
    peak_list, trough_list = detector.ppg_detector(x, 7)
    # Return
    return sq.standard_sqi.msq_sqi(x, peaks_1=peak_list, peak_detect2=6)
예제 #5
0
def get_peak_error_features(data_sample,
                            sample_rate=100,
                            rpeak_detector=0,
                            low_rri=300,
                            high_rri=2000):
    rules = ["malik", "karlsson", "kamath", "acar"]
    try:
        wd, m = hp.process(data_sample, sample_rate, calc_freq=True)
    except:
        try:
            wd, m = hp.process(data_sample, sample_rate)
        except:
            error_dict = {rule + "_error": np.nan for rule in rules}
            error_dict["outlier_error"] = np.nan
            return error_dict

    if rpeak_detector in [1, 2, 3, 4]:
        detector = PeakDetector(wave_type='ecg')
        peak_list = detector.ppg_detector(data_sample,
                                          rpeak_detector,
                                          preprocess=False)[0]
        wd["peaklist"] = peak_list
        wd = calc_rr(peak_list, sample_rate, working_data=wd)
        wd = check_peaks(wd['RR_list'],
                         wd['peaklist'],
                         wd['ybeat'],
                         reject_segmentwise=False,
                         working_data=wd)
        wd = clean_rr_intervals(working_data=wd)

    rr_intervals = wd["RR_list"]

    rr_intervals_cleaned = remove_outliers(rr_intervals,
                                           low_rri=low_rri,
                                           high_rri=high_rri)
    number_outliers = len(np.where(np.isnan(rr_intervals_cleaned))[0])
    outlier_ratio = number_outliers / (len(rr_intervals_cleaned) -
                                       number_outliers)

    error_sqi = {}
    error_sqi['outlier_error'] = outlier_ratio

    interpolated_rr_intervals = interpolate_nan_values(rr_intervals_cleaned)

    for rule in rules:
        nn_intervals = remove_ectopic_beats(interpolated_rr_intervals,
                                            method=rule)
        number_ectopics = len(np.where(np.isnan(nn_intervals))[0])
        ectopic_ratio = number_ectopics / (len(nn_intervals) - number_ectopics)
        error_sqi[rule + "_error"] = ectopic_ratio

    return error_sqi
예제 #6
0
def get_all_features_hrva(s, sample_rate=100, rpeak_method=0,wave_type='ecg'):
    """

    Parameters
    ----------
    data_sample :
        Raw signal
    rpeak_method :
        return: (Default value = 0)
    sample_rate :
        (Default value = 100)

    Returns
    -------


    """

    # if rpeak_method in [1, 2, 3, 4]:
    #     detector = PeakDetector()
    #     peak_list = detector.ppg_detector(data_sample, rpeak_method)[0]
    # else:
    #     rol_mean = rolling_mean(data_sample, windowsize=0.75, sample_rate=100.0)
    #     peaks_wd = detect_peaks(data_sample, rol_mean, ma_perc=20,
    #                             sample_rate=100.0)
    #     peak_list = peaks_wd["peaklist"]
    if wave_type=='ppg':
        detector = PeakDetector(wave_type='ppg')
        peak_list, trough_list = detector.ppg_detector(s, detector_type=rpeak_method)
    else:
        detector = PeakDetector(wave_type='ecg')
        peak_list, trough_list = detector.ecg_detector(s, detector_type=rpeak_method)

    rr_list = np.diff(peak_list) * (1000 / sample_rate)  # 1000 milisecond

    nn_list = get_nn_intervals(rr_list)
    nn_list_non_na = np.copy(nn_list)
    nn_list_non_na[np.where(np.isnan(nn_list_non_na))[0]] = -1

    time_domain_features = get_time_domain_features(rr_list)
    frequency_domain_features = get_frequency_domain_features(rr_list)
    geometrical_features = get_geometrical_features(rr_list)
    csi_cvi_features = get_csi_cvi_features(rr_list)

    return time_domain_features, frequency_domain_features, geometrical_features, csi_cvi_features
예제 #7
0
def get_split_rr_index(segment_seconds,sequence):
    """
    handy
    Return the index of the splitting points
    :param segment_seconds: the length of each cut split (in seconds)
    :param sequence:
    :return:
    """
    detector = PeakDetector()
    indices = [0]
    for i in range(0, int(np.ceil(len(sequence) / segment_seconds))):
        chunk = sequence[int(segment_seconds * i):
                         int(segment_seconds * (i + 1) + 60)]
        peak_list, trough_list = detector.ppg_detector(chunk)
        if len(trough_list)>0:
            indices.append(int(trough_list[-1]+segment_seconds * i))
        else:
            indices.append(int(segment_seconds * (i+1)))
    return indices
예제 #8
0
def get_all_features_heartpy(data_sample, sample_rate=100, rpeak_detector=0):
    """

    Parameters
    ----------
    data_sample :
        Raw signal

    sample_rate :
        (Default value = 100)
    rpeak_detector :
        (Default value = 0)

    Returns
    -------


    """
    # time domain features
    td_features = [
        "bpm", "ibi", "sdnn", "sdsd", "rmssd", "pnn20", "pnn50", "hr_mad",
        "sd1", "sd2", "s", "sd1/sd2", "breathingrate"
    ]
    # frequency domain features
    fd_features = ["lf", "hf", "lf/hf"]
    try:
        wd, m = hp.process(data_sample, sample_rate, calc_freq=True)
    except Exception as e:
        try:
            wd, m = hp.process(data_sample, sample_rate)
        except:
            time_domain_features = {k: np.nan for k in td_features}
            frequency_domain_features = {k: np.nan for k in fd_features}
            return time_domain_features, frequency_domain_features
    if rpeak_detector in [1, 2, 3, 4]:
        detector = PeakDetector(wave_type='ecg')
        peak_list = \
        detector.ppg_detector(data_sample, rpeak_detector, preprocess=False)[0]
        wd["peaklist"] = peak_list
        wd = calc_rr(peak_list, sample_rate, working_data=wd)
        wd = check_peaks(wd['RR_list'],
                         wd['peaklist'],
                         wd['ybeat'],
                         reject_segmentwise=False,
                         working_data=wd)
        wd = clean_rr_intervals(working_data=wd)
        rr_diff = wd['RR_list']
        rr_sqdiff = np.power(rr_diff, 2)
        wd, m = calc_ts_measures(wd['RR_list'],
                                 rr_diff,
                                 rr_sqdiff,
                                 working_data=wd)
        m = calc_poincare(wd['RR_list'],
                          wd['RR_masklist'],
                          measures=m,
                          working_data=wd)
        try:
            measures, working_data = calc_breathing(wd['RR_list_cor'],
                                                    data_sample,
                                                    sample_rate,
                                                    measures=m,
                                                    working_data=wd)
        except:
            measures['breathingrate'] = np.nan

        wd, m = calc_fd_measures(measures=measures, working_data=working_data)

    time_domain_features = {k: m[k] for k in td_features}

    frequency_domain_features = {}
    for k in fd_features:
        if k in m.keys():
            frequency_domain_features[k] = m[k]
        else:
            frequency_domain_features[k] = np.nan
    # frequency_domain_features = {k:m[k] for k in fd_features if k in m.keys}
    # frequency_domain_features = {k:np.na for k in fd_features if k not in m.keys}

    return time_domain_features, frequency_domain_features
예제 #9
0
def ectopic_sqi(
    data_sample,
    rule_index=0,
    sample_rate=100,
    rpeak_detector=0,
    wave_type='ppg',
    low_rri=300,
    high_rri=2000,
):
    """
    Evaluate the invalid peaks (which exceeds normal range)
    base on HRV rules: Malik, Karlsson, Kamath, Acar
    Output the ratio of invalid
    Parameters
    ----------
    data_sample :

    rule_index:
        0: Default Outlier Peak
        1: Malik
        2: Karlsson
        3: Kamath
        4: Acar
        (Default rule is Malik)

    sample_rate :
        (Default value = 100)
    rpeak_detector :
        (Default value = 0)
        To explain other detector options
    low_rri :
        (Default value = 300)
    high_rri :
        (Default value = 2000)

    Returns
    -------

    
    """
    rules = ["malik", "karlsson", "kamath", "acar"]
    try:
        wd, m = hp.process(data_sample, sample_rate, calc_freq=True)
    except:
        try:
            wd, m = hp.process(data_sample, sample_rate)
        except:
            error_dict = {rule + "_error": np.nan for rule in rules}
            error_dict["outlier_error"] = np.nan
            return error_dict

    # if rpeak_detector in [1, 2, 3, 4]:
    if wave_type == 'ecg':
        detector = PeakDetector(wave_type='ecg')
        peak_list = detector.ecg_detector(data_sample, rpeak_detector)[0]
    else:
        detector = PeakDetector(wave_type='ppg')
        peak_list = detector.ppg_detector(data_sample,
                                          rpeak_detector,
                                          preprocess=False)[0]
    wd["peaklist"] = peak_list
    wd = calc_rr(peak_list, sample_rate, working_data=wd)
    wd = check_peaks(wd['RR_list'],
                     wd['peaklist'],
                     wd['ybeat'],
                     reject_segmentwise=False,
                     working_data=wd)
    wd = clean_rr_intervals(working_data=wd)

    rr_intervals = wd["RR_list"]

    rr_intervals_cleaned = remove_outliers(rr_intervals,
                                           low_rri=low_rri,
                                           high_rri=high_rri)
    number_outliers = len(np.where(np.isnan(rr_intervals_cleaned))[0])
    outlier_ratio = number_outliers / (len(rr_intervals_cleaned) -
                                       number_outliers)
    if rule_index == 0:
        return outlier_ratio

    # error_sqi = {}
    # error_sqi['outlier_error'] = outlier_ratio

    interpolated_rr_intervals = interpolate_nan_values(rr_intervals_cleaned)

    rule = rules[rule_index]
    nn_intervals = remove_ectopic_beats(interpolated_rr_intervals, method=rule)
    number_ectopics = len(np.where(np.isnan(nn_intervals))[0])
    ectopic_ratio = number_ectopics / (len(nn_intervals) - number_ectopics)

    return ectopic_ratio
예제 #10
0
def segment_PPG_SQI_extraction(signal_segment,
                               sampling_rate=100,
                               primary_peakdet=7,
                               secondary_peakdet=6,
                               hp_cutoff_order=(1, 1),
                               lp_cutoff_order=(20, 4),
                               template_type=1):
    """
	Extract all package available SQIs from a single segment of PPG waveform.
	Return a dataframe with all SQIs and cut points for each segment.

	Parameters
	----------
	signal_segment : array-like
	A segment of raw signal. The length is user defined in compute_SQI()
	function.

	sampling_rate : int
	Sampling rate of the signal

	primary_peakdet : int
	Selects one of the peakdetectors from the PeakDetector class. The primary
	one is used to segment the waveform.

	secondary_peakdet : int
	Selects one of the peakdetectors from the PeakDetector class. The
	secondary peakdetector is used to compute MSQ SQI.

	hp_cutoff_order : touple (int, int)
	A high pass filter parameters, cutoff frequency and order

	Lp_cutoff_order : touple (int, int)
	A low pass filter parameters, cutoff frequency and order

	template_type : int
	Selects which template from the dtw SQI should be used

	Returns
	-------
	Pandas series object with all SQIs for the given segment

	"""

    raw_segment = signal_segment[signal_segment.columns[1]].to_numpy()
    # Prepare final dictonary that will be converted to dataFrame at the end
    SQI_dict = {
        'first': signal_segment['idx'][0],
        'last': signal_segment['idx'][-1]
    }
    # Prepare filter and filter signal
    filt = BandpassFilter(band_type='butter', fs=sampling_rate)
    filtered_segment = filt.signal_highpass_filter(raw_segment,
                                                   cutoff=hp_cutoff_order[0],
                                                   order=hp_cutoff_order[1])
    filtered_segment = filt.signal_lowpass_filter(filtered_segment,
                                                  cutoff=lp_cutoff_order[0],
                                                  order=lp_cutoff_order[1])
    # Prepare primary peak detector and perform peak detection
    detector = PeakDetector()
    peak_list, trough_list = detector.ppg_detector(filtered_segment,
                                                   primary_peakdet)
    # Helpful lists for iteration
    variations_stats = ['', '_mean', '_median', '_std']
    variations_acf = [
        '_peak1', '_peak2', '_peak3', '_value1', '_value2', '_value3'
    ]
    stats_functions = [('skewness', sq.standard_sqi.skewness_sqi),
                       ('kurtosis', sq.standard_sqi.kurtosis_sqi),
                       ('entropy', sq.standard_sqi.entropy_sqi)]
    # Raw signal SQI computation
    SQI_dict['snr'] = np.mean(sq.standard_sqi.signal_to_noise_sqi(raw_segment))
    SQI_dict['perfusion'] = sq.standard_sqi.perfusion_sqi(y=filtered_segment,
                                                          x=raw_segment)
    SQI_dict['mean_cross'] = sq.standard_sqi.mean_crossing_rate_sqi(
        raw_segment)
    # Filtered signal SQI computation
    SQI_dict['zero_cross'] = sq.standard_sqi.zero_crossings_rate_sqi(
        filtered_segment)
    SQI_dict['msq'] = sq.standard_sqi.msq_sqi(y=filtered_segment,
                                              peaks_1=peak_list,
                                              peak_detect2=secondary_peakdet)
    correlogram_list = sq.rpeaks_sqi.correlogram_sqi(filtered_segment)
    for idx, variations in enumerate(variations_acf):
        SQI_dict['correlogram' + variations] = correlogram_list[idx]
    # Per beat SQI calculation
    dtw_list = sq.standard_sqi.per_beat_sqi(sqi_func=sq.dtw_sqi,
                                            troughs=trough_list,
                                            signal=filtered_segment,
                                            taper=True,
                                            template_type=template_type)
    SQI_dict['dtw_mean'] = np.mean(dtw_list)
    SQI_dict['dtw_std'] = np.std(dtw_list)
    for funcion in stats_functions:
        SQI_dict[funcion[0] +
                 variations_stats[0]] = funcion[1](filtered_segment)
        statSQI_list = sq.standard_sqi.per_beat_sqi(sqi_func=funcion[1],
                                                    troughs=trough_list,
                                                    signal=filtered_segment,
                                                    taper=True)
        SQI_dict[funcion[0] + variations_stats[1]] = np.mean(statSQI_list)
        SQI_dict[funcion[0] + variations_stats[2]] = np.median(statSQI_list)
        SQI_dict[funcion[0] + variations_stats[3]] = np.std(statSQI_list)
    #
    return pd.Series(SQI_dict)
예제 #11
0
                                                filter_type=filter_type, sampling_rate=sampling_rate))

print(ppg_data.signals.shape)

s = np.arange(0, 1000, 1)
fig, ax = plt.subplots()
ax.plot(s, ppg_data.signals[0][8000:9000])
plt.show()

ppg_data.update_segment_indices(sqi_sg.generate_segment_idx(segment_length=segment_length, sampling_rate=sampling_rate,
                                                            signal_array=ppg_data.signals))
print(ppg_data.segments.shape)
print(ppg_data.segments)

detector = PeakDetector()
peak_list, trough_list = detector.ppg_detector(ppg_data.signals[0][ppg_data.segments[0][0]:ppg_data.segments[0][1]], 7)

# Plot results of peak detection
s = np.arange(0, 3000, 1)
fig, ax = plt.subplots()
ax.plot(s, ppg_data.signals[0][ppg_data.segments[0][0]:ppg_data.segments[0][1]])
if len(peak_list) != 0:
    ax.scatter(peak_list, ppg_data.signals[0][peak_list], color="r", marker="v")
if len(trough_list) != 0:
    ax.scatter(trough_list, ppg_data.signals[0][trough_list], color="b", marker="v")
plt.show()

# Plot a single period
fig, ax = plt.subplots()
ax.plot(ppg_data.signals[0][trough_list[0]:trough_list[1]])
plt.show()