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
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)
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
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