def qrs_detector(ecg_clean, ecg_noisy, ecg_res): qrs_inds_clean = processing.xqrs_detect(sig=ecg_clean, fs=360) qrs_inds_noisy = processing.xqrs_detect(sig=ecg_noisy, fs=360) qrs_inds_res = processing.xqrs_detect(sig=ecg_res, fs=360) print(f'QRS Clean: {len(qrs_inds_clean)}') print(f'QRS Noisy: {len(qrs_inds_noisy)}') print(f'QRS Res: {len(qrs_inds_res)}') pass
def detect(self, records): return [ processing.xqrs_detect( sig = record.p_signal.T[0], fs = record.fs, verbose = False) for record in records]
def qrs_detect(signals, fields, max_num=48): """ qrs_indexes holds list of integer representing the location of QRS in the signals, the indices of the detected qrs complexes signals is ECG signal of recorded individuals """ fs = fields["fs"] qrs_indexes = [] all_signals = [] for signal in signals[:max_num]: print("Signals: matrix form", signal) # Converting into array arr_signal = np.array(signal).ravel() print("Signals: array form", arr_signal) qrs_index = processing.xqrs_detect(sig=signal[:, 0], fs=fs) # Plot the detected complex on graph # plt.plot(arr_signal) # plt.scatter([qrs_index], [arr_signal[qrs_index]], c="r") # plt.show() qrs_indexes.append(qrs_index) all_signals.append(arr_signal) # xqrs = processing.XQRS(sig=signal[:, 0], fs=fs) # xqrs.detect() # wfdb.plot_items( # signal=signal, ann_samp=[xqrs.qrs_inds], title="Using XQRS", figsize=(10, 4) # ) print(len(all_signals)) qrs_indexes = np.asarray(qrs_indexes) return qrs_indexes, all_signals
def compute_rr_interval(record, channels=0): qrs_inds = processing.xqrs_detect(sig=record.p_signal[:, channels], fs=record.fs) rr_intervals = processing.calc_rr(qrs_inds, fs=record.fs, rr_units='seconds') return rr_intervals
def detect_qrs_xqrs(ecg_data, fs): qrs_frames = [] try: qrs_frames = processing.xqrs_detect(sig=ecg_data, fs=fs, verbose=False) except Exception: print("Exception in detect_qrs_xqrs") # return qrs_frames.tolist() return qrs_frames
def xqrs_segment_beat(signal, fs, winL=180, winR=180, size_RR_max=5): r_poses = processing.xqrs_detect(sig=signal, fs=fs) beat = [] for pos in r_poses: if pos > size_RR_max and pos < (len(signal) - size_RR_max): beat_poses = segment(signal, pos, winL, winR, size_RR_max) if (pos > winL and pos < (len(signal) - winR)): beat.append(beat_poses) return beat
def get_qrs_inds(self, signals, fs): qrs_inds = processing.correct_peaks( signals[:, 0], processing.xqrs_detect(signals[:, 0], fs, conf=processing.XQRS.Conf(hr_min=20, hr_max=230, qrs_width=0.5)), fs * 60 // 230, fs // 2, 'compare') return qrs_inds
def __compute_R_points(self): if self.R_points is None: self.R_points = processing.xqrs_detect(self.signal[:,0],self.fs,verbose=False).tolist() self.indexes = [i for i in range(len(self.R_points))] if self.filteredSignal==None: self.filteredSignal = self.__butter_lowpass_filter(10) if self.derivativeSignal==None: self.__compute_signal_derivative() for i in range(len(self.R_points)): while abs(self.derivativeSignal[self.R_points[i]]<=eps): self.R_points[i]-=1
def signal_heart_rate(signal): lead_mean_rates = [] for sig in signal: r_locs = processing.xqrs_detect(sig=sig, fs=conf.sample_rate, verbose=False) lead_mean_rate = 60 / (np.nanmean(np.diff(r_locs)) / conf.sample_rate) lead_mean_rates.append(lead_mean_rate) lead_mean_rates = np.array([x for x in lead_mean_rates if str(x) != 'nan']) lead_mean_rates = reject_outliers(lead_mean_rates, m=2.) signal_mean_rate = np.mean(lead_mean_rates) return signal_mean_rate
def get_beat_bank(start_sec=275, stop_sec=300): """ Make a beat bank of ecgs by extracting all beats from the same time section of channels 0 and 1 of all true alarm training records """ fs = 250 beat_bank = dict([(sig_name, []) for c in ecg_channels]) # No cheating! We should only have access to training data records_train, records_test = train_test_split(record_names) for record_name in records_train: # Skip false alarm records if not alarm_data.loc['v131l', 'result']: continue # Read record signal, fields = wfdb.rdsamp(os.path.join(data_dir, record_name), sampfrom=start_sec * fs, sampto=stop_sec * fs, channels=[0, 1]) # Clean the signals, removing nans signal = get_clean_signal(sig=signal, nan_thresh=0.5) # Filter the signal signal = bandpass(signal, fs=fs, f_low=0.5, f_high=40, order=2) # Get beats from each channel for ch in range(2): sig_ch = signal[:, ch] sig_name = fields['sig_name'][ch] # Skip flatline signals if is_flatline(sig_ch): continue # Get beat locations qrs_inds = processing.xqrs_detect(sig_ch, fs=fs, verbose=False) # Skip if too few beats if len(qrs_inds) < 2: continue # Normalize the signal sig_ch = normalize(sig_ch) # Get the beats beats, _ = get_beats(sig_ch, qrs_inds) beat_bank[sig_name] = beat_bank[sig_name] + beats print('Finished obtaining beat bank') # Remove signals without beats from the dictionary for sig_name in beat_bank: if len(beat_bank[sig_name]) == 0: print('Obtained no beats for signal %s. Removing.' % sig_name) del (beat_bank[sig_name]) return beat_bank
def PreProcessing(signal, fs=360, datasetinds=None): filteredSig = butter_bandpass_filter(signal, 0.5, 40, 300, 2) filteredSig = normalized(filteredSig) if datasetinds == None: qrs_inds = processing.xqrs_detect(sig=filteredSig[:, 0], fs=fs) beats = DynamicSegmentation(qrs_inds, filteredSig) else: beats = DynamicSegmentation(datasetinds, filteredSig) beats = resampling(beats, 300) return beats
def get_avg_beat(seg, window=200, fs=300): out = [] left_offset = window//2 right_offset = window - left_offset len_seg = len(seg) qrs_inds = processing.xqrs_detect(sig=seg, fs=fs, verbose=False) if len(qrs_inds) == 0: return np.zeros(window) for ind in qrs_inds: if ind >= left_offset and ind <= (len_seg-right_offset): out.append(seg[(ind-left_offset):(ind+right_offset)]) out = np.array(out) if len(out.shape) == 1: avg_beat = out else: avg_beat = np.mean(out, axis=0) return avg_beat
def calc_ECG_annotation(annotation_GT, reconstructed, fs=360): qrs_inds = processing.xqrs_detect(sig=reconstructed, fs=fs, verbose=True) # Compare detected qrs complexes to reference annotation. # Note, first sample in 100.atr is not a qrs.ֶ comparitor = processing.compare_annotations(ref_sample=annotation_GT, test_sample=qrs_inds, window_width=int(0.1 * fs), signal=reconstructed) F_mesure = 2 * (comparitor.positive_predictivity * comparitor.sensitivity) / (comparitor.positive_predictivity + comparitor.sensitivity) return [ len(annotation_GT), comparitor.n_test, comparitor.tp, comparitor.fp, comparitor.fn, comparitor.positive_predictivity, comparitor.sensitivity, F_mesure ]
def xqrs_algorithm(filename, sampfrom=None, sampto=None, channel=0, r_peak_inds=None, fig=None, pic_index=1, pic_size=1, skip_flag=False): sig, fields = wfdb.rdsamp(filename, channels=[channel], sampfrom=sampfrom, sampto=sampto) qrs_inds = processing.xqrs_detect(sig=sig[:, 0], fs=fields['fs']) #numpy.array print(qrs_inds) #标记位置减去采样点开始位置得到相对位置 r_peak_inds -= sampfrom if len(qrs_inds) < 1: qrs_inds = np.array([-100]) if skip_flag: return draw_graph(r_peak_inds, sig, fields, 'XQRS', qrs_inds, fig=fig, pic_index=pic_index, pic_size=pic_size, skip_flag=skip_flag) summary, fig = draw_graph(r_peak_inds, sig, fields, 'XQRS', qrs_inds, fig=fig, pic_index=pic_index, pic_size=pic_size) return summary, fig
def detect_qrs(ecg_measurements, fs, win_len_min=10, win_overlap_min=1): win_len = int(fs * 60 * win_len_min) win_overlap = int(fs * 60 * win_overlap_min) indices = set() win_skip = win_len - win_overlap wins = int((len(ecg_measurements) - win_len) / win_skip) + 2 min_bpm = 20 max_bpm = 230 search_radius = int(fs * 60 / max_bpm) start_time_all = time.time() for i, w_start in enumerate([x * win_skip for x in range(wins)]): w_end = w_start + win_len start_time = time.time() calc_data = ecg_measurements[w_start:w_end] qrs_inds = processing.xqrs_detect(sig=calc_data, fs=fs, learn=True, verbose=False) corrected_peak_inds = processing.correct_peaks( calc_data, peak_inds=qrs_inds, search_radius=search_radius, smooth_window_size=150) start_upd_dict_time = time.time() corrected_peak_inds = corrected_peak_inds + w_start indices.update(corrected_peak_inds) end_time = time.time() print( "{:5} {:10} - {:10} czas wykonania: {:10.2} całkowity czas wykonania: {:10.2} liczba probek: {} liczba qrs: {} liczba probek w zbiorze {}" .format(i, w_start, w_end, end_time - start_time, end_time - start_time_all, len(calc_data), len(corrected_peak_inds), len(indices)), flush=True) result = np.array(list(indices)) np.ndarray.sort(result) return result
import wfdb from wfdb import processing DATA_PATH = "/data/" SAVE_PATH = "/pred/" with open(DATA_PATH + "RECORDS", 'r') as f: records = f.readlines() records = list(map(lambda r: r.strip("\n"), records)) for record in records: sig, fields = wfdb.rdsamp(DATA_PATH + record, channels=[0]) res = processing.xqrs_detect(sig[:, 0], fs=fields['fs']) if len(res) > 0: wfdb.wrann(record, 'atr', res, write_dir=SAVE_PATH, symbol=(['N'] * len(res)))
print(len(predict_beat_dict['Abnormal Beats'])) print(len(predict_beat_dict['Normal Beats'])) model = load_model('my_model.h5') columns = ['Distance to Previous Beat', 'Distance to Next Beat', 'Beat'] signal_df = pd.DataFrame(columns = columns) sample_rate = 360 record, fields = wfdb.rdsamp(record_name='uploads/101', sampfrom = 0, channels = [0]) #annotations = wfdb.rdann(record_name='Data/101', extension = 'atr', sampfrom = 0) #locate R peaks qrs_inds = xqrs_detect(record[:,0], fs=sample_rate) print(fields['fs']) print('-----------------------------') for i, peak in enumerate(qrs_inds): if i > 1 and i != len(qrs_inds)-1: beat_peak = qrs_inds[i] next_peak = qrs_inds[i+1] prev_peak = qrs_inds[i-1] beat_indices.append(beat_peak) low_diff = beat_peak - prev_peak high_diff = next_peak - beat_peak beat = record[int(beat_peak - 180) : int(beat_peak + 180)]
def run_algo(algorithm: str, sig: numpy.ndarray, freq_sampling: int) -> List[int]: """ run a qrs detector on a signal :param algorithm: name of the qrs detector to use :type algorithm: str :param sig: values of the sampled signal to study :type sig: ndarray :param freq_sampling: value of sampling frequency of the signal :type freq_sampling: int :return: localisations of qrs detections :rtype: list(int) """ detectors = Detectors(freq_sampling) if algorithm == 'Pan-Tompkins-ecg-detector': qrs_detections = detectors.pan_tompkins_detector(sig) elif algorithm == 'Hamilton-ecg-detector': qrs_detections = detectors.hamilton_detector(sig) elif algorithm == 'Christov-ecg-detector': qrs_detections = detectors.christov_detector(sig) elif algorithm == 'Engelse-Zeelenberg-ecg-detector': qrs_detections = detectors.engzee_detector(sig) elif algorithm == 'SWT-ecg-detector': qrs_detections = detectors.swt_detector(sig) elif algorithm == 'Matched-filter-ecg-detector' and freq_sampling == 360: qrs_detections = detectors.matched_filter_detector( sig, 'templates/template_360hz.csv') elif algorithm == 'Matched-filter-ecg-detector' and freq_sampling == 250: qrs_detections = detectors.matched_filter_detector( sig, 'templates/template_250hz.csv') elif algorithm == 'Two-average-ecg-detector': qrs_detections = detectors.two_average_detector(sig) elif algorithm == 'Hamilton-biosppy': qrs_detections = bsp_ecg.ecg(signal=sig, sampling_rate=freq_sampling, show=False)[2] elif algorithm == 'Christov-biosppy': order = int(0.3 * freq_sampling) filtered, _, _ = bsp_tools.filter_signal(signal=sig, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=freq_sampling) rpeaks, = bsp_ecg.christov_segmenter(signal=filtered, sampling_rate=freq_sampling) rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered, rpeaks=rpeaks, sampling_rate=freq_sampling, tol=0.05) _, qrs_detections = bsp_ecg.extract_heartbeats( signal=filtered, rpeaks=rpeaks, sampling_rate=freq_sampling, before=0.2, after=0.4) elif algorithm == 'Engelse-Zeelenberg-biosppy': order = int(0.3 * freq_sampling) filtered, _, _ = bsp_tools.filter_signal(signal=sig, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=freq_sampling) rpeaks, = bsp_ecg.engzee_segmenter(signal=filtered, sampling_rate=freq_sampling) rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered, rpeaks=rpeaks, sampling_rate=freq_sampling, tol=0.05) _, qrs_detections = bsp_ecg.extract_heartbeats( signal=filtered, rpeaks=rpeaks, sampling_rate=freq_sampling, before=0.2, after=0.4) elif algorithm == 'Gamboa-biosppy': order = int(0.3 * freq_sampling) filtered, _, _ = bsp_tools.filter_signal(signal=sig, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=freq_sampling) rpeaks, = bsp_ecg.gamboa_segmenter(signal=filtered, sampling_rate=freq_sampling) rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered, rpeaks=rpeaks, sampling_rate=freq_sampling, tol=0.05) _, qrs_detections = bsp_ecg.extract_heartbeats( signal=filtered, rpeaks=rpeaks, sampling_rate=freq_sampling, before=0.2, after=0.4) elif algorithm == 'mne-ecg': qrs_detections = mne_ecg.qrs_detector(freq_sampling, sig) elif algorithm == 'heartpy': rol_mean = rolling_mean(sig, windowsize=0.75, sample_rate=100.0) qrs_detections = hp_pkdetection.detect_peaks( sig, rol_mean, ma_perc=20, sample_rate=100.0)['peaklist'] elif algorithm == 'gqrs-wfdb': qrs_detections = processing.qrs.gqrs_detect(sig=sig, fs=freq_sampling) elif algorithm == 'xqrs-wfdb': qrs_detections = processing.xqrs_detect(sig=sig, fs=freq_sampling) else: raise ValueError( f'Sorry... unknown algorithm. Please check the list {algorithms_list}' ) cast_qrs_detections = [int(element) for element in qrs_detections] return cast_qrs_detections
def classify_beats(signal_file, model, sampling_rate): ''' method predicts the classes of all beats in an ECG signal -------------------- Input: signal --> the input data in the form of an ECG signal from physionet model --> the trained and saved neural network used for classification sampling rate --> the sampling frequency of the ECG signal ------------------- Output: predict_beat_dict --> a dictionary containing the locations of each beat classified as normal or abnormal ''' normal = [] abnormal = [] beat_indices = [] predict_beat_dict = {'Normal Beats': normal, 'Abnormal Beats': abnormal} columns = ['Distance to Previous Beat', 'Distance to Next Beat', 'Beat'] signal_df = pd.DataFrame(columns=columns) record, fields = wfdb.rdsamp(record_name=signal_file, sampfrom=0, channels=[0]) #locate R peaks qrs_inds = xqrs_detect(record[:, 0], fs=sampling_rate) for i, peak in enumerate(qrs_inds): if i > 1 and i != len(qrs_inds) - 1: beat_peak = qrs_inds[i] next_peak = qrs_inds[i + 1] prev_peak = qrs_inds[i - 1] beat_indices.append(beat_peak) low_diff = beat_peak - prev_peak high_diff = next_peak - beat_peak beat = record[int(beat_peak - (sampling_rate / 2)):int(beat_peak + (sampling_rate / 2))] denoised_beat = denoise_wave.denoise(beat) denoised_beat = denoised_beat.flatten() signal_df = signal_df.append( { 'Distance to Previous Beat': low_diff, 'Distance to Next Beat': high_diff, 'Beat': denoised_beat }, ignore_index=True) for i in range(len(signal_df['Beat'][0])): col_name = 'amp{}'.format(i) columns.append(col_name) signal_df[col_name] = np.nan row_count = 0 for beat in signal_df['Beat']: amp_count = 0 for amp in beat: col = 'amp{}'.format(amp_count) signal_df[col][row_count] = amp amp_count += 1 row_count += 1 signal_df = signal_df[signal_df.Beat != '[]'] signal_df["Distance to Previous Beat"] = pd.to_numeric( signal_df["Distance to Previous Beat"]) signal_df["Distance to Next Beat"] = pd.to_numeric( signal_df["Distance to Next Beat"]) signal_df = signal_df.drop('Beat', axis=1) signal_df = signal_df.dropna(axis=0) signal_array = signal_df.to_numpy() signal_array = np.expand_dims(signal_array, axis=2) pred_classes = model.predict_classes(signal_array, batch_size=24, verbose=0) count = 0 for pred in pred_classes: if pred == 0: normal.append(beat_indices[count]) count += 1 elif pred == 1: abnormal.append(beat_indices[count]) count += 1 else: print('unidentified class for Beat index {}'.format(i)) return predict_beat_dict
def trigger(self, record): return processing.xqrs_detect( sig = record.p_signal.T[0], fs = record.fs, verbose = False)
def xqrs_single(fields, record, save_path, sig, save=True): r_peaks = processing.xqrs_detect(sig[:, 0], fs=fields['fs'], verbose=False) if save: save_prediction(r_peaks, record, save_path) else: return r_peaks