def predict_pac_pvc_bbbb(ecg, f=250): """ Predict Apnea for all segments of ECG Parameters ---------- ecg: array_like 2D Array containing amplitude all segments of the ECG signal f: float, optional Number corresponding to the sampling frequency of the input signal, must be in Hertz Returns ------- dict_all: Dictionary Dictionary of ECG beats and its corresponding PCA beats and predictions """ window = int(f * 0.4) #800ms beat ecg_new = baseline_correct(ecg, f) rpeaks = np.array(ecgsig.hamilton_segmenter( ecg_new, f)['rpeaks'])[2:-2] #detect rpeaks from ecg beats = np.array([ecg_new[i - window:i + window] for i in rpeaks]) pca = PCA(n_components=10) beats_new = pca.fit_transform(beats) beats_new = StandardScaler().fit_transform(beats_new) predictions = predict_pac_pvc_bbbb_per_beat(beats_new) dict_all = {} dict_all['beats'] = beats dict_all['PCA beats'] = beats_new dict_all['predictions'] = predictions return dict_all
def qsqi(ecg_signal: list, sampling_frequency: int) -> float: """Matching Degree of R Peak Detection Two R wave detection algorithms are compared with their respective number of R waves detected. * Hamilton * SWT (Stationary Wavelet Transform) Parameters ---------- ecg_signal : list Input ECG signal sampling_frequency : list Input ecg sampling frequency Returns ------- q_sqi_score : float """ detectors = Detectors(sampling_frequency) qrs_frames_swt = detectors.swt_detector(ecg_signal) qrs_frames_hamilton = bsp_ecg.hamilton_segmenter( signal=np.array(ecg_signal), sampling_rate=sampling_frequency)[0] q_sqi_score = compute_qrs_frames_correlation(qrs_frames_hamilton, qrs_frames_swt, sampling_frequency) return q_sqi_score
def get_rpeaks(ecg): """ function: get_rpeaks returns an array of indices of the r peaks in a given ecg Args: ecg : np.ndarray an ecg Returns: rpeaks : np.ndarray an array of indices of the r peaks """ try: ecg = ecg[:, 0] except: pass filtered, _, _ = biosppy_tools.filter_signal(signal=ecg, ftype='FIR', band='bandpass', order=150, frequency=[3, 45], sampling_rate=500) rpeaks, = biosppy_ecg.hamilton_segmenter(signal=filtered, sampling_rate=500) # correct R-peak locations rpeaks, = biosppy_ecg.correct_rpeaks(signal=filtered, rpeaks=rpeaks, sampling_rate=500, tol=0.05) return np.array(rpeaks)
def csqi(ecg_signal: list, sampling_frequency: int) -> float: """Variability in the R-R Interval When an artifact is present, the QRS detector underperforms by either missing R-peaks or erroneously identifying noisy peaks as R- peaks. The above two problems will lead to a high degree of variability in the distribution of R-R intervals; Parameters ---------- ecg_signal : list Input ECG signal sampling_frequency : list Input ecg sampling frequency Returns ------- c_sqi_score : float """ with np.errstate(invalid='raise'): try: rri_list = bsp_ecg.hamilton_segmenter( signal=np.array(ecg_signal), sampling_rate=sampling_frequency)[0] c_sqi_score = float( np.round(np.std(rri_list, ddof=1) / np.mean(rri_list), 3)) except Exception: c_sqi_score = 0 return c_sqi_score
def extract_r(ecg_detrend, fs=100): """ Extract R peaks from ECG data ECG data should have the length around 1 minute to get a stable result Parameters ---------- ecg_detrend: numpy array or list Detrended ECG data fs: scalar Sampling frequency of ecg_detrend Returns ------- r_idx: Index of R peaks for ecg_detrend """ import biosppy.signals.ecg as ECG r_idx = list(ECG.christov_segmenter(ecg_detrend, fs))[0] # Works fine in most cases # Assuming HR = 1 bps, check if half of the R peaks are detected if len(r_idx) < (len(ecg_detrend) / fs) / 2: r_idx_2 = list(ECG.hamilton_segmenter( ecg_detrend, fs))[0] # Might return negative R peaks if len(r_idx_2) > len(r_idx): r_idx = r_idx_2 return r_idx
def test_compute_qrs_frames_correlation(ecg_signal=ecg_signal, qrs_frames_none=qrs_frames_none, fs=fs): detectors = Detectors(fs) qrs_frames_swt = detectors.swt_detector(ecg_signal) qrs_frames_hamilton = bsp_ecg.hamilton_segmenter( signal=np.array(ecg_signal), sampling_rate=fs)[0] correlation_coefs = compute_qrs_frames_correlation( qrs_frames_1=qrs_frames_swt, qrs_frames_2=qrs_frames_hamilton, sampling_frequency=fs) assert isinstance(correlation_coefs, float) # test for qrs without length correlation_coefs_none_1 = compute_qrs_frames_correlation( qrs_frames_1=qrs_frames_none, qrs_frames_2=qrs_frames_hamilton, sampling_frequency=fs) assert correlation_coefs_none_1 == 0 correlation_coefs_none_2 = compute_qrs_frames_correlation( qrs_frames_1=qrs_frames_swt, qrs_frames_2=qrs_frames_none, sampling_frequency=fs) assert correlation_coefs_none_2 == 0
def calculate_ratio(filepath): ecg_data = pd.read_csv(filepath, sep=',', error_bad_lines=False, lineterminator="\n") ecg_df = ecg_data['ekg'].apply(lambda line: (((int(line) / bitSize) - 0.5) * vccConst) / sensorGain) * 1000 ecg_np_array = ecg_df.to_numpy() out = ecg.ecg(signal=ecg_np_array, sampling_rate=1000., show=False) ecg_r_peaks = ecg.hamilton_segmenter(signal=ecg_np_array) res = list(map(operator.sub, ecg_r_peaks[0][1:], ecg_r_peaks[0][:-1])) median = statistics.median(res) final_val = min(res)/median return final_val
def detect_qrs_hamilton(ecg_data, fs): qrs_frames = [] try: qrs_frames = bsp_ecg.hamilton_segmenter(signal=np.array(ecg_data), sampling_rate=fs)[0] except Exception: # raise ValueError("xqrs") print("Exception in detect_qrs_hamilton") return qrs_frames
def feature_extraction(recording, signal, labels): data = [] for i in tqdm(range(len(labels)), desc=recording, file=sys.stdout): segment = signal[i * fs * 60:(i + 1) * fs * 60] segment, _, _ = st.filter_signal(segment, ftype='FIR', band='bandpass', order=int(0.3 * fs), frequency=[3, 45], sampling_rate=fs) # Finding R peaks rpeaks, = hamilton_segmenter(segment, sampling_rate=fs) rpeaks, = correct_rpeaks(segment, rpeaks, sampling_rate=fs, tol=0.1) # Extracting feature label = 0 if labels[i] == "N" else 1 if 40 <= len(rpeaks) <= 200: # Remove abnormal R peaks rri_tm, rri = rpeaks[1:] / float(fs), np.diff(rpeaks, axis=-1) / float(fs) rri = medfilt(rri, kernel_size=3) edr_tm, edr = rpeaks / float(fs), segment[rpeaks] # Remove physiologically impossible HR signal if np.all(np.logical_and(60 / rri >= hr_min, 60 / rri <= hr_max)): rri_time_features, rri_frequency_features = time_domain( rri * 1000), frequency_domain(rri, rri_tm) edr_frequency_features = frequency_domain(edr, edr_tm) # 6 + 6 + 6 + 1 = 19 data.append([ rri_time_features["rmssd"], rri_time_features["sdnn"], rri_time_features["nn50"], rri_time_features["pnn50"], rri_time_features["mrri"], rri_time_features["mhr"], rri_frequency_features["vlf"] / rri_frequency_features["total_power"], rri_frequency_features["lf"] / rri_frequency_features["total_power"], rri_frequency_features["hf"] / rri_frequency_features["total_power"], rri_frequency_features["lf_hf"], rri_frequency_features["lfnu"], rri_frequency_features["hfnu"], edr_frequency_features["vlf"] / edr_frequency_features["total_power"], edr_frequency_features["lf"] / edr_frequency_features["total_power"], edr_frequency_features["hf"] / edr_frequency_features["total_power"], edr_frequency_features["lf_hf"], edr_frequency_features["lfnu"], edr_frequency_features["hfnu"], label ]) else: data.append([np.nan] * 18 + [label]) else: data.append([np.nan] * 18 + [label]) data = np.array(data, dtype="float") return data
def ex1_2_1_biosppy(): filtered_ecg_signal = ecg_processing.ecg(ecg_signal, ecg_sf, show=False)['filtered'] ecg_peak_indices = ecg_processing.hamilton_segmenter(ecg_signal, ecg_sf)['rpeaks'] ecg_peak_times = ecg_peak_indices / ecg_sf plot_peaks(filtered_ecg_signal, ecg_times, ecg_peak_times, ecg_peak_indices, ecg_envelopes, ecg_label, 'hamilton', 'results_hamilton', (-150, 250)) plot_peak_intervals(ecg_peak_times, ecg_label, 'hamilton', 'RRI', 'results_hamilton') """
def extract_beats(data_path): data = loadmat("./ECGTestData/ECGTestData/" + data_path)['data'].T # II导 data = data[1:, :] # 去除第一行index beats_matrix = [] logging.info("--------------------------------------------------") logging.info("载入信号-%s, 长度 = %d " % (data_path, len(data[0]))) min_beats = math.inf for i in DAOLIAN: signal = data[i] fs = 500 # 信号采样率 500 Hz # logging.info("调用 hamilton_segmenter 进行R波检测 ...") # tic = time.time() rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs) # toc = time.time() # logging.info("完成. 用时: %f 秒. " % (toc - tic)) rpeaks = rpeaks[0] # heart_rate = 60 / (np.mean(np.diff(rpeaks)) / fs) # np.diff 计算相邻R峰之间的距离分别有多少个采样点,np.mean求平均后,除以采样率, # 将单位转化为秒,然后计算60秒内可以有多少个RR间期作为心率 # logging.info("平均心率: %.3f / 分钟." % (heart_rate)) win_before = 0.2 win_after = 0.4 # logging.info("根据R波位置截取心拍, 心拍前窗口:%.3f 秒 ~ 心拍后窗口:%.3f 秒 ..." % (win_before, win_after)) # rpeak全部落在100处 # tic = time.time() beats, rpeaks_beats = ecg.extract_heartbeats(signal, rpeaks, fs, win_before, win_after) # toc = time.time() # logging.info("完成. 用时: %f 秒." % (toc - tic)) # logging.info("共截取到 %d 个心拍, 每个心拍长度为 %d 个采样点" % (beats.shape[0], beats.shape[1])) # plt.figure() # plt.grid(True) # for i in range(beats.shape[0]): # plt.plot(beats[i]) # plt.title(data_path) # plt.show() beats_matrix.append(beats) if len(beats) < min_beats: min_beats = len(beats) test_data = [] for i in range(min_beats): tdata = [] for j in range(len(DAOLIAN)): rbeats = denoise(beats_matrix[j][i]) tdata.append(rbeats) test_data.append(tdata) test_data = np.array(test_data).flatten().reshape(-1, 300 * len(DAOLIAN), 1) return test_data
def __init__(self, sig, fs=250.0): assert len(sig.shape) == 1, 'The signal must be 1-dimension.' assert sig.shape[0] >= fs * 6, 'The signal must >= 6 seconds.' self.sig = utils.WTfilt_1d(sig) self.fs = fs self.rpeaks, = ecg.hamilton_segmenter(signal=self.sig, sampling_rate=self.fs) self.rpeaks, = ecg.correct_rpeaks(signal=self.sig, rpeaks=self.rpeaks, sampling_rate=self.fs) self.RR_intervals = np.diff(self.rpeaks) self.dRR = np.diff(self.RR_intervals)
def r_peak_detection(data, type='hamilton'): if type == 'hamilton': r_peaks_tuple = hamilton_segmenter(signal=data, sampling_rate=277) r_peaks_ind = r_peaks_tuple['rpeaks'] r_peak_neighbourhood = 7 # expected range of R peak (in samples) for i in xrange(len(r_peaks_ind)): start = np.maximum(r_peaks_ind[i] - r_peak_neighbourhood, 1) stop = np.minimum(r_peaks_ind[i] + r_peak_neighbourhood, len(data)) ind = np.argmax(data[start:stop]) r_peaks_ind[i] = start + ind r_peaks_val = data[r_peaks_ind] elif type == 'threshold': # R-peak detection r_threshold = 0.4 temp_data = data * 1.0 # temporary data copy temp_data[temp_data < r_threshold] = 0 # setting samples below threshold to zero r_segm_start = np.array([]) r_segm_stop = np.array([]) for i in xrange(len(temp_data) - 1): if temp_data[i] == 0 and temp_data[i + 1] != 0: r_segm_start = np.append( r_segm_start, i) # start index for each segment above threshold if temp_data[i] != 0 and temp_data[i + 1] == 0: r_segm_stop = np.append( r_segm_stop, i) # end index for each segment above threshold nPeaks = len(r_segm_start) nSamples = len(data) r_peaks_val = np.zeros(nPeaks) r_peaks_ind = np.zeros(nPeaks) # local maximums search for i in xrange(nPeaks): ind_start = int(r_segm_start[i]) ind_stop = int(r_segm_stop[i]) segm_mask = np.zeros(nSamples) segm_mask[ind_start:ind_stop] = 1 temp_data = data * segm_mask val = temp_data.max() ind = int(temp_data.argmax()) r_peaks_val[i] = val # r-peak value r_peaks_ind[i] = int(ind) # r-peak index return r_peaks_val, r_peaks_ind
def QRS_detection(signal, fs): # R Peaks : P.S. Hamilton, "Open Source ECG Analysis Software Documentation", E.P.Limited, 2002 rpeaks, = ecg.hamilton_segmenter(signal=signal, sampling_rate=fs) array = [] for x in rpeaks: array.append(x) #plt.figure() #plt.plot(signal[1:1000]) #for xc in array: # if xc < 1000: # plt.axvline(x=xc, color='red') #plt.show() return array
def process_slice(record, subslice, threshold=15): time = (1 / record.fs) * np.arange(subslice.start, subslice.stop) for i in range(record.n_sig): signal = record.p_signal[subslice, i] rpeaks, = hamilton_segmenter(signal, record.fs) # out = ecg.ecg(signal=signal, sampling_rate=record.fs, show=False) try: rr_int = np.vstack( (rr_int, np.array(time[rpeaks[1:]] - time[rpeaks[:-1]]))) except Exception: rr_int = np.array(time[rpeaks[1:]] - time[rpeaks[:-1]]) rr_int = np.mean(rr_int, axis=0) hrv_perc = np.abs(np.round(100 * (rr_int / np.min(rr_int) - 1), 2)) arrythmia = np.any(hrv_perc > threshold) return record.record_name, subslice.start, subslice.stop, arrythmia, rr_int.max( ), rr_int.min(), hrv_perc.max(), hrv_perc.min(), hrv_perc, rr_int
def predict_apnea(ecg, f=100, segment_size=60): """ Predict Apnea for all segments of ECG Parameters ---------- ecg: array_like 2D Array containing amplitude all segments of the ECG signal f: float, optional Number corresponding to the sampling frequency of the input signal, must be in Hertz segment_size: int, optional Specifies segment length (15-sec, 30-sec, or 60-sec) Returns ------- dict_all: Dictionary Dictionary of ECG segments and its corresponding predictions """ window = int(f * segment_size) #800ms beat ecg_wind = segment_ecg(ecg, segment_size=segment_size, f=f) rpeaks = np.array([ ecgsig.hamilton_segmenter(i, f)['rpeaks'] for i in ecg_wind ]) #detect rpeaks from ecg RR_int = np.array([np.diff(i) for i in rpeaks]) peak_count = np.array([len(i) for i in rpeaks]) #remove segments without detectable rpeaks n_peaks = segment_size / 2 ecg_wind = ecg_wind[np.where(peak_count > n_peaks)] RR_int = RR_int[np.where(peak_count > n_peaks)] rpeaks = rpeaks[np.where(peak_count > n_peaks)] peak_count_new = peak_count[np.where(peak_count > n_peaks)] #features X = calculate_features(ecg_wind, rpeaks, peak_count_new, RR_int, f=f) X_c = StandardScaler().fit_transform(X) predictions = predict_apnea_per_segment(X_c) dict_all = {} dict_all['ecg'] = ecg_wind dict_all['predictions'] = predictions return dict_all
def filter_signal(signal, sampling_rate): order = int(0.3 * sampling_rate) filtered, _, _, = ecg.st.filter_signal(signal=signal, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=sampling_rate) rpeaks, = ecg.hamilton_segmenter(signal=filtered, sampling_rate=sampling_rate) rpeaks_corrected, = ecg.correct_rpeaks(signal=filtered, rpeaks=rpeaks, sampling_rate=sampling_rate, tol=0.05) rpeaks = peaks_to_series(signal, rpeaks) rpeaks_corrected = peaks_to_series(signal, rpeaks_corrected) return filtered, rpeaks_corrected
def hamilton_detect(sig: np.ndarray, fs: Real, **kwargs) -> np.ndarray: """ References ---------- [1] Hamilton, Pat. "Open source ECG analysis." Computers in cardiology. IEEE, 2002. """ # segment rpeaks, = BSE.hamilton_segmenter(signal=sig, sampling_rate=fs) # correct R-peak locations rpeaks, = BSE.correct_rpeaks( signal=sig, rpeaks=rpeaks, sampling_rate=fs, tol=kwargs.get("correct_tol", 0.05), ) return rpeaks
def worker(name, labels): print("processing %s!" % name) X = [] y = [] groups = [] signals = wfdb.rdrecord(os.path.join(base_dir, name), channels=[0]).p_signal[:, 0] # Read recording for j in range(len(labels)): if j < before or \ (j + 1 + after) > len(signals) / float(sample): continue signal = signals[int((j - before) * sample):int((j + 1 + after) * sample)] signal, _, _ = st.filter_signal( signal, ftype='FIR', band='bandpass', order=int(0.3 * fs), frequency=[3, 45], sampling_rate=fs) # Filtering the ecg signal to remove noise # Find R peaks rpeaks, = hamilton_segmenter(signal, sampling_rate=fs) # Extract R-peaks rpeaks, = correct_rpeaks(signal, rpeaks=rpeaks, sampling_rate=fs, tol=0.1) if len(rpeaks) / (1 + after + before) < 40 or \ len(rpeaks) / (1 + after + before) > 200: # Remove abnormal R peaks signal continue # Extract RRI, Ampl signal rri_tm, rri_signal = rpeaks[1:] / float(fs), np.diff(rpeaks) / float( fs) rri_signal = medfilt(rri_signal, kernel_size=3) ampl_tm, ampl_siganl = rpeaks / float(fs), signal[rpeaks] hr = 60 / rri_signal # Remove physiologically impossible HR signal if np.all(np.logical_and(hr >= hr_min, hr <= hr_max)): # Save extracted signal X.append([(rri_tm, rri_signal), (ampl_tm, ampl_siganl)]) y.append(0. if labels[j] == 'N' else 1.) groups.append(name) print("over %s!" % name) return X, y, groups
def segmentation(data, label=None): inputs, labels = [], [] for sap_id in range(len(data)): data_ref = denoise(copy.copy(data[sap_id][:, 9])) r_peaks = ecg.hamilton_segmenter(data_ref, 500).as_dict()['rpeaks'] beats = np.hstack([ ecg.extract_heartbeats(signal=denoise( copy.copy(data[sap_id][:, dao_id])), rpeaks=r_peaks, sampling_rate=500, before=0.2, after=0.4)["templates"] for dao_id in [1, 3, 6, 9] ]) inputs.append(beats) if label: labels.append(np.full(beats.shape[0], label[sap_id])) # if label: labels.append(label[sap_id]) if not label: return np.array(inputs, dtype=object) else: return np.vstack(inputs), np.hstack(labels)
def r_peak_loc(x, fs): """ Gives location of R peaks Parameters ---------- x : array_like Array containing magnitudes of ECG signal fs: float Number corresponding to the sampling frequency of the input signal, must be in Hertz Returns ------- rloc: array Array containing the R-peak locations in the array """ rloc = ecgsig.hamilton_segmenter(x, fs)['rpeaks'] return rloc
def calculate_features(signal): sampling_rate = 400 ts, signal, rpeaks, templates_ts, templates, heart_rate_ts, heart_rates = ecg.ecg(signal=signal, sampling_rate=sampling_rate, show=False) rpeaks = ecg.hamilton_segmenter(signal=signal, sampling_rate=sampling_rate)[0] heartbeat_templates, heartbeat_rpeaks = ecg.extract_heartbeats(signal=signal, rpeaks=rpeaks, sampling_rate=sampling_rate) rpeaks_diff = np.diff(rpeaks) rpeaks_diff_diff = np.diff(rpeaks_diff) heartbeat_rpeaks_diff = np.diff(heartbeat_rpeaks) feature = "" mean_amplitude = np.mean(signal) std_amplitude = np.std(signal) max_amplitude = np.amax(signal) min_amplitude = np.amin(signal) median_amplitude = np.median(signal) feature = feature + str(mean_amplitude) + "," + str(std_amplitude) + "," + str(max_amplitude) + "," + str(min_amplitude) + "," + str(median_amplitude) mean_rpeaks_diff = np.mean(rpeaks_diff) std_rpeaks_diff = np.std(rpeaks_diff) median_rpeaks_diff = np.median(rpeaks_diff) feature = feature + "," + str(mean_rpeaks_diff) + "," + str(std_rpeaks_diff) + "," + str(median_rpeaks_diff) mean_rpeaks_diff_diff = np.mean(rpeaks_diff_diff) std_rpeaks_diff_diff = np.std(rpeaks_diff_diff) median_rpeaks_diff_diff = np.median(rpeaks_diff_diff) feature = feature + "," + str(mean_rpeaks_diff_diff) + "," + str(std_rpeaks_diff_diff) + "," + str(median_rpeaks_diff_diff) heartbeat_length = len(heartbeat_templates) mean_heart_rate = np.mean(heart_rates) if len(heart_rates) > 0 else 0.0 std_heart_rate = np.std(heart_rates) if len(heart_rates) > 0 else 0.0 median_heart_rate = np.median(heart_rates) if len(heart_rates) > 0 else 0.0 feature = feature + "," + str(heartbeat_length) + "," + str(mean_heart_rate) + "," + str(std_heart_rate) + "," + str(median_heart_rate) mean_heartbeat_rpeaks_diff = np.mean(heartbeat_rpeaks_diff) std_heartbeat_rpeaks_diff = np.std(heartbeat_rpeaks_diff) median_heartbeat_rpeaks_diff = np.median(heartbeat_rpeaks_diff) feature = feature + "," + str(mean_heartbeat_rpeaks_diff) + "," + str(std_heartbeat_rpeaks_diff) + "," + str(median_heartbeat_rpeaks_diff) return feature
def offline_rr_interval_orignal(signal, fs=200): # 逐波心率(bmp),原始 ecg_signal = np.array(signal) sampling_rate = fs sampling_rate = float(sampling_rate) # filter signal order = int(0.3 * sampling_rate) filtered, _, _ = st.filter_signal(signal=ecg_signal, ftype='FIR', band='bandpass', order=order, frequency=[5, 30], sampling_rate=sampling_rate) rpeaks, = eecg.hamilton_segmenter(signal=filtered, sampling_rate=sampling_rate) # correct R-peak locations rpeaks, = eecg.correct_rpeaks(signal=filtered, rpeaks=rpeaks, sampling_rate=sampling_rate, tol=0.05) rpeaks_orignal = np.unique(rpeaks) rr_interval_orignal = np.diff(rpeaks_orignal) rpeaks_whithoutfirst = rpeaks_orignal[1:] rpeaks_whithoutfirst = rpeaks_orignal outlier = [] for jk in range(len(rr_interval_orignal)): if rr_interval_orignal[jk] >= sampling_rate * 2 or rr_interval_orignal[jk] <= sampling_rate * 0.4: if filtered[rr_interval_orignal[jk]] >= filtered[rr_interval_orignal[jk-1]]: outlier.append(jk-1) else: outlier.append(jk) outlier.reverse() rr_interval_outlier = np.asarray(rr_interval_orignal) for jk1 in outlier: rr_interval_outlier = np.delete(rr_interval_outlier, jk1) rpeaks_whithoutfirst = np.delete(rpeaks_whithoutfirst, jk1) return rpeaks_whithoutfirst.tolist(), filtered
def test_extract_beats(data_path): signal, mdata = load_txt(data_path) logging.info("--------------------------------------------------") logging.info("载入信号-%s, 长度 = %d " % (data_path, len(signal))) fs = 360 # 信号采样率 360 Hz logging.info("调用 hamilton_segmenter 进行R波检测 ...") tic = time.time() rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs) toc = time.time() logging.info("完成. 用时: %f 秒. " % (toc - tic)) rpeaks = rpeaks[0] heart_rate = 60 / (np.mean(np.diff(rpeaks)) / fs) # np.diff 计算相邻R峰之间的距离分别有多少个采样点,np.mean求平均后,除以采样率, # 将单位转化为秒,然后计算60秒内可以有多少个RR间期作为心率 logging.info("平均心率: %.3f / 分钟." % (heart_rate)) win_before = 0.2 win_after = 0.4 logging.info("根据R波位置截取心拍, 心拍前窗口:%.3f 秒 ~ 心拍后窗口:%.3f 秒 ..." \ % (win_before, win_after)) tic = time.time() beats, rpeaks_beats = ecg.extract_heartbeats(signal, rpeaks, fs, win_before, win_after) toc = time.time() logging.info("完成. 用时: %f 秒." % (toc - tic)) logging.info("共截取到 %d 个心拍, 每个心拍长度为 %d 个采样点" % \ (beats.shape[0], beats.shape[1])) plt.figure() plt.grid(True) for i in range(beats.shape[0]): plt.plot(beats[i]) plt.title(data_path) plt.show() return
def test_rpeaks_simple(data_path): signal, mdata = load_txt(data_path) logging.info("--------------------------------------------------") logging.info("载入信号-%s, 长度 = %d " % (data_path, len(signal))) fs = 360 # 信号采样率 360 Hz logging.info("调用 christov_segmenter 进行R波检测 ...") tic = time.time() rpeaks = ecg.christov_segmenter(signal, sampling_rate=fs) toc = time.time() logging.info("完成. 用时: %f 秒. " % (toc - tic)) # 以上这种方式返回的rpeaks类型为biosppy.utils.ReturnTuple, biosppy的内置类 logging.info("直接调用 christov_segmenter 返回类型为 " + str(type(rpeaks))) # 得到R波位置序列的方法: # 1) 取返回值的第1项: logging.info("使用第1种方式取R波位置序列 ... ") rpeaks_indices_1 = rpeaks[0] logging.info("完成. 结果类型为 " + str(type(rpeaks_indices_1))) # 2) 调用ReturnTuple的as_dict()方法,得到Python有序字典(OrderedDict)类型 logging.info("使用第2种方式取R波位置序列 ... ") rpeaks_indices_2 = rpeaks.as_dict() # 然后使用说明文档中的参数名(这里是rpeaks)作为key取值。 rpeaks_indices_2 = rpeaks_indices_2["rpeaks"] logging.info("完成. 结果类型为 " + str(type(rpeaks_indices_2))) # 检验两种方法得到的结果是否相同: check_sum = np.sum(rpeaks_indices_1 == rpeaks_indices_2) if check_sum == len(rpeaks_indices_1): logging.info("两种取值方式结果相同 ... ") else: logging.info("两种取值方式结果不同,退出 ...") sys.exit(1) # 与 christov_segmenter 接口一致的还有 hamilton_segmenter logging.info("调用接口一致的 hamilton_segmenter 进行R波检测") tic = time.time() rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs) toc = time.time() logging.info("完成. 用时: %f 秒. " % (toc - tic)) rpeaks_indices_3 = rpeaks.as_dict()["rpeaks"] # 绘波形图和R波位置 num_plot_samples = 3600 logging.info("绘制波形图和检测的R波位置 ...") sig_plot = signal[:num_plot_samples] rpeaks_plot_1 = rpeaks_indices_1[rpeaks_indices_1 <= num_plot_samples] plt.figure() plt.plot(sig_plot, "g", label="ECG") plt.grid(True) plt.plot(rpeaks_plot_1, sig_plot[rpeaks_plot_1], "ro", label="christov_segmenter") rpeaks_plot_3 = rpeaks_indices_3[rpeaks_indices_3 <= num_plot_samples] plt.plot(rpeaks_plot_3, sig_plot[rpeaks_plot_3], "b^", label="hamilton_segmenter") plt.legend() plt.title(data_path) plt.show() logging.info("完成.") return
def get_rpeaks(signal, sampling_rate=360): signal = np.array(signal) filtered = filter_signal(signal) rpeaks, = hamilton_segmenter(signal=filtered, sampling_rate=sampling_rate) return rpeaks#[1:]
import numpy as np import matplotlib as plt import biosppy.signals.ecg as bio samplrate = 3428 / 10 data = np.loadtxt('FilteredData/filtereddata3.txt') rpeaks1 = bio.christov_segmenter(data, 342) bio.ecg(data, 342, True) rpeaks2 = bio.engzee_segmenter(data, 342) rpeaks3 = bio.gamboa_segmenter(data, 342) rpeaks4 = bio.hamilton_segmenter(data, 342) rpeaks5 = bio.ssf_segmenter(data, 342) np.savetxt('FilteredData/peaksdata13.txt', rpeaks1, header=str(len(rpeaks1))) np.savetxt('FilteredData/peaksdata23.txt', rpeaks2, header=str(len(rpeaks2))) np.savetxt('FilteredData/peaksdata33.txt', rpeaks3, header=str(len(rpeaks3))) np.savetxt('FilteredData/peaksdata43.txt', rpeaks4, header=str(len(rpeaks4))) np.savetxt('FilteredData/peaksdata53.txt', rpeaks5, header=str(len(rpeaks5))) #np.savetxt('FilteredData/roundeddata3.txt', introunddata)
def extract_features(ts): """Extract features from individual patient Arguments --------- ts: time series of interest Returns ------- """ """ 1. R-R interval: -what is the average interval between peaks? -how much variation is there in this measure? -max/min value """ # Peak detection: perhaps take it from .ecg function? rpeak0=ecg.hamilton_segmenter(signal=ts,\ sampling_rate=300)[0] # Interval lengths l_RRint = [] for a in range(len(rpeak0)): if (a > 0): l_RRint.append(rpeak0[a] - rpeak0[a - 1]) # Some "robust" extreme values statistics (no max or min) RRint_10, RRint_90 = np.percentile(l_RRint, q=[0.1, 0.9]) RRint_mean = np.mean(l_RRint) RRint_sd = np.std(l_RRint) """ 2. R amplitude (difference between value at peak minus baseline -not "valley"-): -what is the average R amplitude? -how much variation is there in this measure? -max/min value NOTE: YOU CANNOT USE THE INDEXING OF THE R-PEAKS TO FIND THE VALUE OF THE Y! First impression: use ecg.ecg and work with the filtered series (here indeces seem to match) Idea: work with index of filtered series. For baseline take an average of the first and last 20 values of the series """ filtered_ts = ecg.ecg(ts, sampling_rate=300, show=False) hb, hb_peaks= ecg.extract_heartbeats(signal=filtered_ts["filtered"], \ rpeaks= rpeak0, sampling_rate=300.0) # if all(hb[1]==rpeak0): # hb=hb[0] #else: # print "Error" # Finding value at R-peak R_max_value = filtered_ts["filtered"][hb_peaks] # Computing baseline ts_baselines = [] for a_hb in hb: ts_baselines.append((sum(a_hb[0:20])+ \ sum(a_hb[(len(a_hb)-20):(len(a_hb)-1)]))/40.) # R_max -baseline R_amplitude = [] for hb_nr in range(len(hb)): R_amplitude.append(R_max_value[hb_nr] - ts_baselines[hb_nr]) Rampl_10, Rampl_90 = np.percentile(R_amplitude, q=[0.1, 0.9]) Rampl_mean = np.mean(R_amplitude) Rampl_sd = np.std(R_amplitude) """ 3. Q and S (latter optional) amplitude (difference between value at min before R minus baseline): Idea: Examinate the HB. Find out: what is a reasonal nr of steps to look before the R peak to find Q? Baseline (see above) - 25 time steps before R-peak to find Q value (the same for S) --> Note, since the R-peak is sometimes identified at the very beginning of the series, we need the window to be relative to where this index is choice: look at indeces int(2./3*R_index):R_index """ Q_vals = [] Q_amplitude = [] S_vals = [] S_amplitude = [] for hb_nr in range(len(hb)): # Q stats R_index = np.where(hb[hb_nr] == R_max_value[hb_nr])[0][0] Q_min = min(hb[hb_nr][int(2. / 3 * R_index):R_index]) Q_vals.append(Q_min) Q_amplitude.append(ts_baselines[hb_nr] - Q_min) # S stats S_min = min(hb[hb_nr][R_index:(R_index + 25)]) S_vals.append(S_min) S_amplitude.append(ts_baselines[hb_nr] - S_min) # Remark: some values are completely off due to clear errors in the # peak detction algorithm (e.g. heartbeat 34 in 19th individual) Qampl_10, Qampl_90 = np.percentile(Q_amplitude, q=[0.1, 0.9]) Qampl_mean = np.mean(Q_amplitude) Qampl_sd = np.std(Q_amplitude) Sampl_10, Sampl_90 = np.percentile(S_amplitude, q=[0.1, 0.9]) Sampl_mean = np.mean(S_amplitude) Sampl_sd = np.std(S_amplitude) """ 4. QRS duration: Idea: we have the index of Q_min and that of S_min. Difference between the two APPROXIMATES this feature (the way I understand it, I should measure how long it takes, once we have left the "baseline" to fall into the Q-in, to come back to the baseline after the S min) """ QRS_time = [] for hb_nr in range(len(hb)): Q_index = np.where(hb[hb_nr] == Q_vals[hb_nr])[0][0] S_index = np.where(hb[hb_nr] == S_vals[hb_nr])[0][0] QRS_time.append(S_index - Q_index) QRSts_10, QRSts_90 = np.percentile(QRS_time, q=[0.1, 0.9]) QRSts_mean = np.mean(QRS_time) QRSts_sd = np.std(QRS_time) """ 5. Hearth rate variability Idea: extract from the .ecg function """ hr_ts = filtered_ts[ "heart_rate"] # For subjet 2719 no heart rate is computed! Weird... if len(hr_ts) == 0: HR_10, HR_90, HR_mean, HR_sd = [None] * 4 else: HR_10, HR_90 = np.percentile(hr_ts, q=[0.1, 0.9]) HR_mean = np.mean(hr_ts) HR_sd = np.std(hr_ts) """ 5. Wavelet energy Idea: don't understand what this is or how to obtain it """ return RRint_mean, RRint_sd, RRint_10, RRint_90, \ Rampl_mean, Rampl_sd, Rampl_10, Rampl_90, \ Qampl_mean, Qampl_sd, Qampl_10, Qampl_90, \ Sampl_mean, Sampl_sd, Sampl_10, Sampl_90, \ QRSts_mean, QRSts_sd, QRSts_10, QRSts_90, \ HR_mean, HR_sd, HR_10, HR_90
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) signal_path = "./data/ecg_records_117.txt" ann_path = "./data/ecg_ann_117.txt" logging.info("--------------------------------------------------") signal, _ = load_txt(signal_path) logging.info("载入信号-%s, 长度 = %d. " % (signal_path, len(signal))) ann, _ = load_txt(ann_path) logging.info("载入R峰位置人工标记, 共 %d 个R峰." % (len(ann))) fs = 360 # 信号采样率 360 Hz logging.info("调用 hamilton_segmenter 进行R波检测 ...") tic = time.time() rpeaks = ecg.hamilton_segmenter(signal, sampling_rate=fs) toc = time.time() logging.info("完成. 用时: %f 秒. " % (toc - tic)) rpeaks = rpeaks[0] logging.info("使用compare_segmentation对比算法结果与人工标记 ...") tic = time.time() eval_results = ecg.compare_segmentation(ann, rpeaks, fs, tol=0.02) toc = time.time() logging.info("完成. 用时: %f 秒. 返回结果类型为 %s ." % (toc - tic, str(type(eval_results)))) dict_results = eval_results.as_dict() logging.info("********** 结果报告 *************") logging.info("* 准确率(acc): %.3f *" % dict_results["acc"]) logging.info("* 总体表现(performance): %.3f *" % dict_results["performance"]) logging.info("*********************************")
def main(): #signal time_before_seizure = 30 time_after_seizure = 10 # path_to_load = '~/Desktop/phisionet_seizures.h5' sampling_rate = 1000 path_to_load = '~/Desktop/seizure_datasets.h5' name_list = [ str(time_before_seizure * 60) + '_' + str(time_after_seizure * 60) ] group_list_raw = ['raw'] group_list_baseline_removal = ['medianFIR'] group_list_noise_removal = ['FIR_lowpass_40hz'] group_list_esksmooth = ['esksmooth'] # Raw signal signal_structure_raw = load_signal(path_to_load, zip(group_list_raw, name_list)) # one_signal_structure_raw = get_one_signal_structure(signal_structure, zip(group_list, name_list)[0]) # records_raw = get_multiple_records(one_signal_structure_raw) # stop # ======================================================== # Baseline removal records_baseline_removal, mdata_baseline_removal = load_baseline_removal( path_to_load, group_list_raw, name_list, sampling_rate, compute_flag=False) # stop # ========================================================= # Noise removal records_noise_removal, mdata_noise_removal = load_noise_removal( path_to_load, group_list_baseline_removal, name_list, sampling_rate, compute_flag=False) # Noise removal kalman records_kalman, mdata_kalman = load_kalman(path_to_load, group_list_baseline_removal, name_list, sampling_rate, compute_flag=False) # stop # ========================================================= # Rpeak detection # rpeaks_noise_removal = load_rpeaks(path_to_load, group_list_noise_removal, name_list, sampling_rate, compute_flag = False) # stop # ========================================================= # Allocate time array Fs = 250 N = len(records_kalman[0, :]) T = (N - 1) / Fs t = np.linspace(0, T, N, endpoint=False) factor = 2 # Visual inspection of rpeak detection start = 280 end = 300 seizure_nr = 1 if seizure_nr < 3: Fs = 1000 N = len(records_baseline_removal[0, :]) T = (N - 1) / Fs t_new = np.linspace(0, T, N, endpoint=False) signal_inter = records_baseline_removal[seizure_nr] rpeaks_RAM = ecg.hamilton_segmenter( signal=signal_inter, sampling_rate=sampling_rate)['rpeaks'] else: signal = records_kalman[seizure_nr] signal_inter, t_new = interpolate(t, signal, 1000) rpeaks_RAM = ecg.hamilton_segmenter( signal=signal_inter, sampling_rate=sampling_rate)['rpeaks'] # stop y = np.diff(rpeaks_RAM) # visual_inspection(signal_inter, rpeaks_RAM, y, t, time_before_seizure, # start, end, sampling_rate) t_rpeaks = t_new[rpeaks_RAM[1:]] y_new, t_n = interpolate(t_rpeaks, y, 2) print(len(t) - 1) / 250 print(len(t_n) - 1) / 2 time_before_seizure = time_before_seizure * 60 print time_before_seizure #rpeaks # rpeaks = rpeaks_noise_removal[seizure_nr] # rpeaks_resample = resample_rpeaks(np.diff(rpeaks), rpeaks, t) # rpeaks = find_rpeaks(rpeaks, start * sampling_rate, # end * sampling_rate) #signal # signal_baseline_removal = records_baseline_removal[seizure_nr,:] # signal_noise_removal = records_noise_removal[seizure_nr,:] #plot plt.subplot(2, 1, 1) plt.plot(t_new, signal_inter) plt.plot(t_new[rpeaks_RAM], signal_inter[rpeaks_RAM], 'o') # plt.axvline(x=time_before_seizure*60, color = 'g') plt.subplot(2, 1, 2) plt.plot(t_n, y_new) plt.axvline(x=time_before_seizure, color='g') plt.plot() # plt.xlim([start, end]) # plt.subplot(2,1,2) # plt.plot(t, signal_baseline_removal) # plt.xlim([start, end]) plt.show() # # stop beats = compute_fixed_beats(signal_inter, rpeaks_RAM) print np.shape(beats[0:5]) pca = compute_PC(beats[0:5]) pca = np.dot(pca, beats[0:5]) print np.shape(pca) evol = trace_evol_PC(beats) print np.shape(evol) evol = evol.T t_evol = t_new[rpeaks_RAM[6:-1]] print len(t_evol) ev = [interpolate(t_evol, eigen, 2) for eigen in evol] plt.subplot(6, 1, 1) plt.plot(ev[4][1], 1 * 1000 * 60 / y_new[1:len(ev[4][1]) + 1]) plt.axvline(x=time_before_seizure, color='g') plt.legend(['HRV', 'Seizure onset']) plt.ylabel('bpm') plt.subplot(6, 1, 2) plt.plot(ev[4][1], ev[4][0]) plt.axvline(x=time_before_seizure, color='g') plt.legend(['Eigen-Value 1', 'Seizure onset']) plt.subplot(6, 1, 3) plt.plot(ev[3][1], ev[3][0]) plt.axvline(x=time_before_seizure, color='g') plt.legend(['Eigen-Value 2', 'Seizure onset']) plt.subplot(6, 1, 4) plt.plot(ev[2][1], ev[2][0]) plt.axvline(x=time_before_seizure, color='g') plt.legend(['Eigen-Value 3', 'Seizure onset']) plt.subplot(6, 1, 5) plt.plot(ev[1][1], ev[1][0]) plt.axvline(x=time_before_seizure, color='g') plt.legend(['Eigen-Value 4', 'Seizure onset']) plt.subplot(6, 1, 6) plt.plot(ev[0][1], ev[0][0]) plt.axvline(x=time_before_seizure, color='g') plt.legend(['Eigen-Value 5', 'Seizure onset']) plt.xlabel('t (s)') plt.subplots_adjust(0.09, 0.1, 0.94, 0.94, 0.26, 0.46) plt.show()
def feature_extraction(sample, sampling_rate=300): # Normalize raw signal signal = ecg.st.normalize(sample)['signal'] # ensure numpy signal = np.array(signal) sampling_rate = float(sampling_rate) # filter signal order = int(0.3 * sampling_rate) filtered, _, _ = ecg.st.filter_signal(signal=signal, ftype='FIR', band='bandpass', order=order, frequency=[5, 15], sampling_rate=sampling_rate) # segment rpeaks, = ecg.hamilton_segmenter(signal=filtered, sampling_rate=sampling_rate) # correct R-peak locations rpeaks, = ecg.correct_rpeaks(signal=filtered, rpeaks=rpeaks, sampling_rate=sampling_rate, tol=0.05) templates, rpeaks = ecg.extract_heartbeats(signal=filtered, rpeaks=rpeaks, sampling_rate=sampling_rate, before=0.2, after=0.4) # get time vectors length = len(signal) T = (length - 1) / sampling_rate ts = np.linspace(0, T, length, endpoint=False) # Extract time domain measures rpeaks_time = ts[rpeaks] rr_intervals = extract_rr_intervals(rpeaks_time) rr_diffs = extract_rr_diffs(rr_intervals) bpm = get_bpm(rr_intervals) ibi = np.mean(rr_intervals) sdnn = np.std(rr_intervals) sdsd = np.std(rr_diffs) rmssd = np.sqrt(np.mean(rr_diffs**2)) nn20 = np.sum([rr_diffs > 0.02]) / len(rr_diffs) nn50 = np.sum([rr_diffs > 0.05]) / len(rr_diffs) # QRS qpeaks = find_q_point(filtered, rpeaks) speaks = find_s_point(filtered, rpeaks) # Extract wavelet power power_spectrum = ecg.st.power_spectrum(filtered, 300) frequency = [power_spectrum['freqs'][0], power_spectrum['freqs'][-1]] wavelet_energie = ecg.st.band_power(power_spectrum['freqs'], power_spectrum['power'], frequency)['avg_power'] # Amplitudes qamplitudes = filtered[qpeaks] ramplitudes = filtered[rpeaks] samplitudes = filtered[speaks] # QRS duration qrs_duration = ts[speaks] - ts[qpeaks] qrs_duration_diffs = extract_rr_diffs(qrs_duration) iqrs = np.mean(qrs_duration) sdqrs = np.std(qrs_duration) sdqrsdiffs = np.std(qrs_duration_diffs) rmssqrsdiffs = np.sqrt(np.mean(qrs_duration_diffs**2)) extracted_features = [ bpm, ibi, sdnn, sdsd, rmssd, nn20, nn50, wavelet_energie, iqrs, sdqrs, sdqrsdiffs, rmssqrsdiffs, np.median(qamplitudes), np.min(qamplitudes), np.max(qamplitudes), np.median(ramplitudes), np.min(ramplitudes), np.max(ramplitudes), np.median(samplitudes), np.min(samplitudes), np.max(samplitudes) ] return extracted_features