def test_ecg_delineate(): sampling_rate = 1000 # test with simulated signals ecg = nk.ecg_simulate(duration=20, sampling_rate=sampling_rate, random_state=42) _, rpeaks = nk.ecg_peaks(ecg, sampling_rate=sampling_rate) number_rpeaks = len(rpeaks['ECG_R_Peaks']) # Method 1: derivative _, waves_derivative = nk.ecg_delineate(ecg, rpeaks, sampling_rate=sampling_rate) assert len(waves_derivative['ECG_P_Peaks']) == number_rpeaks assert len(waves_derivative['ECG_Q_Peaks']) == number_rpeaks assert len(waves_derivative['ECG_S_Peaks']) == number_rpeaks assert len(waves_derivative['ECG_T_Peaks']) == number_rpeaks assert len(waves_derivative['ECG_P_Onsets']) == number_rpeaks assert len(waves_derivative['ECG_T_Offsets']) == number_rpeaks # Method 2: CWT _, waves_cwt = nk.ecg_delineate(ecg, rpeaks, sampling_rate=sampling_rate, method='cwt') assert np.allclose(len(waves_cwt['ECG_P_Peaks']), 22, atol=1) assert np.allclose(len(waves_cwt['ECG_T_Peaks']), 22, atol=1) assert np.allclose(len(waves_cwt['ECG_R_Onsets']), 23, atol=1) assert np.allclose(len(waves_cwt['ECG_R_Offsets']), 23, atol=1) assert np.allclose(len(waves_cwt['ECG_P_Onsets']), 22, atol=1) assert np.allclose(len(waves_cwt['ECG_P_Offsets']), 22, atol=1) assert np.allclose(len(waves_cwt['ECG_T_Onsets']), 22, atol=1) assert np.allclose(len(waves_cwt['ECG_T_Offsets']), 22, atol=1)
def get_HRVs_values(data, header_data): filter_lowcut = 0.001 filter_highcut = 15.0 filter_order = 1 tmp_hea = header_data[0].split(' ') ptID = tmp_hea[0] num_leads = int(tmp_hea[1]) sample_Fs = int(tmp_hea[2]) gain_lead = np.zeros(num_leads) for ii in range(num_leads): tmp_hea = header_data[ii + 1].split(' ') gain_lead[ii] = int(tmp_hea[2].split('/')[0]) # for testing, we included the mean age of 57 if the age is a NaN # This value will change as more data is being released for iline in header_data: if iline.startswith('#Age'): tmp_age = iline.split(': ')[1].strip() age = int(tmp_age if tmp_age != 'NaN' else 57) elif iline.startswith('#Sex'): tmp_sex = iline.split(': ')[1] if tmp_sex.strip() == 'Female': sex = 1 else: sex = 0 elif iline.startswith('#Dx'): label = iline.split(': ')[1].split(',')[0] signal = data[1] gain = gain_lead[1] ecg_signal = nk.ecg_clean(signal * gain, sampling_rate=sample_Fs, method="biosppy") _, rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=sample_Fs) hrv_time = nk.hrv_time(rpeaks, sampling_rate=sample_Fs) # hrv_non = nk.hrv_nonlinear(rpeaks, sampling_rate=sample_Fs) try: signal_peak, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=sample_Fs) p_peaks = waves_peak['ECG_P_Peaks'] except ValueError: print('Exception raised!') pass p_peaks = np.asarray(p_peaks, dtype=float) p_peaks = p_peaks[~np.isnan(p_peaks)] p_peaks = [int(a) for a in p_peaks] mean_P_Peaks = np.mean([signal[w] for w in p_peaks]) hrv_time['mean_P_Peaks'] = mean_P_Peaks hrv_time['age'] = age hrv_time['label'] = label # df = pd.concat([hrv_time, hrv_non], axis=1) return hrv_time
def nothing(): # Quality check algorithms # qcqrs = run_qc(signal=data.filtered, epoch_len=15, fs=fs, algorithm="averageQRS", show_plot=False) # Removing invalid data based on QC thresholdling #t = threshold_averageqrs_data(signal=data.filtered, qc_signal=qc, epoch_len=10, fs=fs, pad_val=0, # thresh=.95, method='exclusive', plot_data=False) p, pc = find_peaks(signal=data.filtered, fs=fs, show_plot=True, peak_method="pantompkins1985", clean_method='neurokit') hrv = nk.hrv_time(peaks=pc, sampling_rate=data.sample_rate, show=False) freq = nk.hrv_frequency(peaks=pc, sampling_rate=data.sample_rate, show=True) # df_events, info = test_ecg_process_func(signal=data.filtered[15000:15000+1250], start=0, n_samples=int(10*125), fs=fs, plot_builtin=True, plot_events=False) # heartbeats = segment_ecg(signal=d, fs=fs) waves, sigs = nk.ecg_delineate(ecg_cleaned=data.filtered, rpeaks=pc, sampling_rate=data.sample_rate, method='dwt', show=False) intervals, ecg_rate, ecg_hrv = nk.ecg_intervalrelated() # TODO # Organizing # Signal quality in organized section --> able to pick which algorithm
def run_test_func(test_data): _, waves = nk.ecg_delineate(test_data['ecg'], test_data['rpeaks'], test_data['sampling_rate'], method='dwt') for key in waves: waves[key] = np.array(waves[key]) return waves
def _other_peaks_detection(ecg_data, rpeaks, sampling_rate): _, waves_peak = nk.ecg_delineate(ecg_data[1], rpeaks, sampling_rate=sampling_rate) q_peaks = waves_peak['ECG_Q_Peaks'] q_peaks = np.delete(q_peaks, np.where(np.isnan(q_peaks))[0]).astype( int) # not use s_peaks = waves_peak['ECG_S_Peaks'] s_peaks = np.delete(s_peaks, np.where(np.isnan(s_peaks))[0]).astype( int) # not use return q_peaks, s_peaks
def generate_features(ecg, header): #input: 12-lead ecg and its header fs = 500 features = {} lead_names = [] for iline in header: if '.mat' in iline: name = iline.split(' 0 ')[2].strip() lead_names.append(name) for ecg_signal, lead in zip(ecg, lead_names): ecg_cleaned = nk.ecg_clean(ecg_signal, sampling_rate=fs) if np.all((ecg_cleaned == 0)): return None else: _, rpeaks = nk.ecg_peaks(ecg_cleaned, sampling_rate=fs) if rpeaks['ECG_R_Peaks'].size == 0: return None else: try: signal_dwt, waves_dwt = nk.ecg_delineate( ecg_cleaned, rpeaks['ECG_R_Peaks'], sampling_rate=fs, method="dwt") biphase, areas, t_till_peaks, ampls, dur, idxs, pq_intervals = p_peak_features( ecg_cleaned, waves_dwt) features_for_single_lead = { 'PQ_int': calculate_features(pq_intervals), 'P_dur': calculate_features(dur), 'Area/Dur_P': calculate_features(idxs), 'Area_under_P': calculate_features(areas), 'P_amp': calculate_features(ampls), 'Time_till_P': calculate_features(t_till_peaks), 'Biphase_P': calculate_features(biphase) } except IndexError: return None features[lead] = features_for_single_lead return features
def compute_qrs_ratio(x, fs=460, length_of_beat=0.75): # Find Q and S peaks _, rpeaks = nk.ecg_peaks(x, sampling_rate=fs) _, waves_peak = nk.ecg_delineate(x, rpeaks, sampling_rate=fs, method="peak") # Compute diff across Q and S peaks Q_waves = waves_peak['ECG_Q_Peaks'] S_waves = waves_peak['ECG_S_Peaks'] diff = [s - q for s, q in zip(S_waves, Q_waves)] # Divide the diff by 0.75 seconds (length of 1 beat in samples) duration_samples = int(length_of_beat * fs) ratio = [i / duration_samples for i in diff if not np.isnan(i)] return sum(ratio) / len(ratio)
def my_processing(ecg_signal): # Try processing ecg_cleaned = nk.ecg_clean(ecg_signal, sampling_rate=300, method="biosppy") instant_peaks, rpeaks = nk.ecg_peaks(ecg_cleaned, sampling_rate=300, method='hamilton2002') info = rpeaks try: # Additional info of the ecg signal delineate_signal, delineate_waves = nk.ecg_delineate( ecg_cleaned=ecg_cleaned, rpeaks=rpeaks, sampling_rate=300, method='cwt') except: delineate_signal = np.NaN delineate_waves = np.NaN return ecg_cleaned, delineate_signal, delineate_waves, info
def extract_prt_features(row, signal, rpeaks): """ Extract the PRT features - the segment lengths and intervals between them. :param row: a `BaseDataset` row to calculate the features from :param signal: the raw ECG signal :param rpeaks: the R peaks detected by `nk.ecg_peaks` :return: `row` with the added features """ _, segments = nk.ecg_delineate(signal, rpeaks, sampling_rate=row.Fs, method="dwt") for key in segments: segments[key] = np.array(segments[key]) / row.Fs P_length = segments['ECG_P_Offsets'] - segments['ECG_P_Onsets'] R_length = segments['ECG_R_Offsets'] - segments['ECG_R_Onsets'] T_length = segments['ECG_T_Offsets'] - segments['ECG_T_Onsets'] PR_interval = segments['ECG_R_Onsets'] - segments['ECG_P_Onsets'] RT_interval = segments['ECG_T_Onsets'] - segments['ECG_R_Onsets'] features = [ (P_length, 'P_LENGTH'), (R_length, 'R_LENGTH'), (T_length, 'T_LENGTH'), (PR_interval, 'PR_INTERVAL'), (RT_interval, 'RT_INTERVAL'), ] for feature, name in features: row = row.append(get_statistics(feature, name, ignore_nan=True)) return row
def _discrete_wavelet_trans(ecg_data, rpeaks, sample_freq): _, waves_dwt = nk.ecg_delineate(ecg_data[1], rpeaks, sampling_rate=sample_freq, method="dwt") p_offsets = waves_dwt['ECG_P_Offsets'] p_offsets = np.delete(p_offsets, np.where(np.isnan(p_offsets))[0]).astype(int) p_onsets = waves_dwt['ECG_P_Onsets'] p_onsets = np.delete(p_onsets, np.where(np.isnan(p_onsets))[0]).astype(int) p_peaks = waves_dwt['ECG_P_Peaks'] p_peaks = np.delete(p_peaks, np.where(np.isnan(p_peaks))[0]).astype(int) t_peaks = waves_dwt['ECG_T_Peaks'] t_peaks = np.delete(t_peaks, np.where(np.isnan(t_peaks))[0]).astype(int) t_offsets = waves_dwt['ECG_T_Offsets'] t_offsets = np.delete(t_offsets, np.where(np.isnan(t_offsets))[0]).astype(int) t_onsets = waves_dwt['ECG_T_Onsets'] t_onsets = np.delete(t_onsets, np.where(np.isnan(t_onsets))[0]).astype(int) return p_offsets, p_onsets, p_peaks, t_peaks, t_offsets, t_onsets
def extract_features_tmaps( self, signal_tm: TensorMap, clean_method: str = "neurokit", r_method: str = "neurokit", wave_method: str = "dwt", min_peaks: int = 200, ): """ Function to extract the ecg features using the neurokit2 package. That is the P, Q, R, S and T peaks and the P, QRS and T waves onsets and offsets. The result is saved internally. :param signal_tm: <TensorMap> :param clean_method: <str> The processing pipeline to apply. Can be one of ‘neurokit’ (default), ‘biosppy’, ‘pantompkins1985’, ‘hamilton2002’, ‘elgendi2010’, ‘engzeemod2012’. :param r_method: <str> The algorithm to be used for R-peak detection. Can be one of ‘neurokit’ (default), ‘pantompkins1985’, ‘hamilton2002’, ‘christov2004’, ‘gamboa2008’, ‘elgendi2010’, ‘engzeemod2012’ or ‘kalidas2017’. :param wave_method: <str> Can be one of ‘dwt’ (default) for discrete wavelet transform or ‘cwt’ for continuous wavelet transform. :param min_peaks: <int> Minimum R peaks to be detected to proceed with further calculations. """ for i, _ in enumerate(self.sampling_rate): sampling_rate = self.sampling_rate[i][0] init = self.sampling_rate[i][1] if i == len(self.sampling_rate) - 1: end = -1 else: end = self.sampling_rate[i + 1][1] ecg_signal = signal_tm.tensor_from_file(signal_tm, self)[0][init:end] ecg_signal = nk.ecg_clean(ecg_signal, sampling_rate, clean_method) try: _, r_peaks = nk.ecg_peaks(ecg_signal, sampling_rate, r_method) except IndexError: continue if len(r_peaks["ECG_R_Peaks"]) < min_peaks: continue _, waves_peaks = nk.ecg_delineate(ecg_signal, r_peaks, sampling_rate) _, waves_peaks_2 = nk.ecg_delineate( ecg_signal, r_peaks, sampling_rate, wave_method, ) waves_peaks.update(waves_peaks_2) for peak_type in r_peaks: if peak_type not in self.r_peaks: self.r_peaks[peak_type] = r_peaks[peak_type] else: self.r_peaks[peak_type] = np.append( self.r_peaks[peak_type], r_peaks[peak_type], ) for peak_type in waves_peaks: if peak_type not in self.waves_peaks: self.waves_peaks[peak_type] = waves_peaks[peak_type] else: self.waves_peaks[peak_type] = np.append( self.waves_peaks[peak_type], waves_peaks[peak_type], ) for peak_type in self.r_peaks: self.r_peaks[peak_type] = list(self.r_peaks[peak_type]) for peak_type in self.waves_peaks: self.waves_peaks[peak_type] = list(self.waves_peaks[peak_type])
def Get_TPQS_Peaks(ecg_signal, rpeaks): # Delineate ECG signal to get TPQS peaks print( "======= Using DWT to retrieve TPQS Peaks and On/Offsets ========") dwt_sig, waves_dwt_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=3000, method="dwt", show=True, show_type="all") #Print to console for key in waves_dwt_peak: print(key, ' : ', waves_dwt_peak[key]) def_sig, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=3000, show_type="peaks") # Visualize the T-peaks, P-peaks, Q-peaks and S-peaks **for JupyterNotebook plot_TPQS_Signal = nk.events_plot([ waves_peak['ECG_T_Peaks'], waves_peak['ECG_P_Peaks'], waves_peak['ECG_Q_Peaks'], waves_peak['ECG_S_Peaks'] ], ecg_signal) plot_TPQS_Signal.savefig("TPQS_signal", dpi=300) # Zooming into the first 3 R-peaks, with focus on # T_peaks, P-peaks, Q-peaks and S-peaks **for JupyterNotebook plot_TPQS_Head = nk.events_plot([ waves_peak['ECG_T_Peaks'][:3], waves_peak['ECG_P_Peaks'][:3], waves_peak['ECG_Q_Peaks'][:3], waves_peak['ECG_S_Peaks'][:3] ], ecg_signal[:12500]) plot_TPQS_Head.savefig("TPQS_head", dpi=300) # Delineate the ECG signal and visualizing all peaks of ECG complexes _, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=3000, show=True, show_type='peaks') # Delineate the ECG signal and visualizing all P-peaks boundaries signal_peak, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=3000, show=True, show_type='bounds_P') # Delineate the ECG signal and visualizing all T-peaks boundaries signal_peaj, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=3000, show=True, show_type='bounds_T') #Print to Console for key in waves_peak: if (key == 'ECG_Q_Peaks' or key == 'ECG_S_Peaks'): print(key, ' : ', waves_peak[key]) print() return waves_dwt_peak, waves_peak
def analyzeECG(ecg, sampling_rate, method = "dwt"): #Funkcja zwraca parametry analizy, które mogą być wykorzystane do wyświetlania oraz do dalszej analizy. #Zwraca puls, średnią HRV, HRVSDNN, HRVRMSSD, informacje związane z załamkami (długość, czas, amplituda) a, peaks = nk.ecg_process(ecg[1], sampling_rate = sampling_rate) info = nk.ecg_analyze(a, sampling_rate = sampling_rate) ECG_Rate_Mean = info["ECG_Rate_Mean"][0] HRV_RMSSD = info["HRV_RMSSD"][0] HRV_MeanNN = info["HRV_MeanNN"][0] HRV_SDNN = info["HRV_SDNN"][0] _,rpeaksnk = nk.ecg_peaks(ecg[1], sampling_rate = sampling_rate) R_peaks = [[],[]] for i in rpeaksnk["ECG_R_Peaks"]: R_peaks[0].append(ecg[0][i]) R_peaks[1].append(ecg[1][i]) # Delineate the ECG signal _, waves_peak = nk.ecg_delineate(ecg[1], rpeaksnk, sampling_rate = sampling_rate, show = False, show_type = "peaks") if method == "cwt": _, waves_other = nk.ecg_delineate(ecg[1], rpeaksnk, sampling_rate = sampling_rate, method="cwt", show=False, show_type='all') if method == "dwt": _, waves_other = nk.ecg_delineate(ecg[1], rpeaksnk, sampling_rate = sampling_rate, method="dwt", show=False, show_type='all') #Wyznaczanie załamków P, Q, S, T P_peaks = [[],[]] Q_peaks = [[],[]] S_peaks = [[],[]] T_peaks = [[],[]] for name in waves_peak: for i in waves_peak[str(name)]: if math.isnan(i): continue if str(name) == "ECG_P_Peaks": P_peaks[0].append(ecg[0][i]) P_peaks[1].append(ecg[1][i]) if str(name) == "ECG_Q_Peaks": Q_peaks[0].append(ecg[0][i]) Q_peaks[1].append(ecg[1][i]) if str(name) == "ECG_S_Peaks": S_peaks[0].append(ecg[0][i]) S_peaks[1].append(ecg[1][i]) if str(name) == "ECG_T_Peaks": T_peaks[0].append(ecg[0][i]) T_peaks[1].append(ecg[1][i]) #Wyznaczanie początków i końców załamków P, Q, S, T P_onsets = [[],[]] P_offsets = [[],[]] R_onsets = [[],[]] R_offsets = [[],[]] T_onsets = [[],[]] T_offsets = [[],[]] for name in waves_other: for i in waves_other[str(name)]: if math.isnan(i): continue if str(name) == "ECG_P_Onsets": P_onsets[0].append(ecg[0][i]) P_onsets[1].append(ecg[1][i]) if str(name) == "ECG_P_Offsets": P_offsets[0].append(ecg[0][i]) P_offsets[1].append(ecg[1][i]) if str(name) == "ECG_R_Onsets": R_onsets[0].append(ecg[0][i]) R_onsets[1].append(ecg[1][i]) if str(name) == "ECG_R_Offsets": R_offsets[0].append(ecg[0][i]) R_offsets[1].append(ecg[1][i]) if str(name) == "ECG_T_Onsets": T_onsets[0].append(ecg[0][i]) T_onsets[1].append(ecg[1][i]) if str(name) == "ECG_T_Offsets": T_offsets[0].append(ecg[0][i]) T_offsets[1].append(ecg[1][i]) #Czasy załamków P_Time = calculateTime(P_offsets[0], P_onsets[0]) QRS_Time = calculateTime(R_offsets[0], R_onsets[0]) T_Time = calculateTime(T_offsets[0], T_onsets[0]) #Amplitudy załamków P_Amplitude = np.mean(P_peaks[1]) Q_Amplitude = np.mean(Q_peaks[1]) R_Amplitude = np.mean(R_peaks[1]) S_Amplitude = np.mean(S_peaks[1]) T_Amplitude = np.mean(T_peaks[1]) #Odstępy PQ_Space = calculateTime(R_onsets[0], P_onsets[0]) QT_Space = calculateTime(T_offsets[0], R_onsets[0]) #Odcinki PQ_Segment = calculateTime(R_onsets[0], P_offsets[0]) ST_Segment = calculateTime(T_onsets[0], R_offsets[0]) #Słowniki z pozyskanymi informacjami data = {} info = {} data["P_peaks"] = P_peaks data["Q_peaks"] = Q_peaks data["R_peaks"] = R_peaks data["S_peaks"] = S_peaks data["T_peaks"] = T_peaks data["P_onsets"] = P_onsets data["P_offsets"] = P_offsets data["R_onsets"] = R_onsets data["R_offsets"] = R_offsets data["T_onsets"] = T_onsets data["T_offsets"] = T_offsets info["ECG_Rate_Mean"] = round(ECG_Rate_Mean, 4) info["HRV_MeanNN"] = round(HRV_MeanNN, 4) info["HRV_RMSSD"] = round(HRV_RMSSD, 4) info["HRV_SDNN"] = round(HRV_SDNN, 4) info["P_Time"] = round(P_Time, 4) info["QRS_Time"] = round(QRS_Time, 4) info["T_Time"] = round(T_Time, 4) info["P_Amplitude"] = round(P_Amplitude, 4) info["Q_Amplitude"] = round(Q_Amplitude, 4) info["R_Amplitude"] = round(R_Amplitude, 4) info["S_Amplitude"] = round(S_Amplitude, 4) info["T_Amplitude"] = round(T_Amplitude, 4) info["PQ_Space"] = round(PQ_Space, 4) info["QT_Space"] = round(QT_Space, 4) info["PQ_Segment"] = round(PQ_Segment, 4) info["ST_Segment"] = round(ST_Segment, 4) return data, info
def run_test_func(test_data): _, waves = nk.ecg_delineate(test_data["ecg"], test_data["rpeaks"], test_data["sampling_rate"], method="dwt") for key in waves: waves[key] = np.array(waves[key]) return waves
def get_HRVs_values(data, header_data): filter_lowcut = 0.001 filter_highcut = 15.0 filter_order = 1 tmp_hea = header_data[0].split(' ') ptID = tmp_hea[0] num_leads = int(tmp_hea[1]) sample_Fs= int(tmp_hea[2]) gain_lead = np.zeros(num_leads) for ii in range(num_leads): tmp_hea = header_data[ii+1].split(' ') gain_lead[ii] = int(tmp_hea[2].split('/')[0]) # for testing, we included the mean age of 57 if the age is a NaN # This value will change as more data is being released for iline in header_data: if iline.startswith('#Age'): tmp_age = iline.split(': ')[1].strip() age = int(tmp_age if tmp_age != 'NaN' else 57) # age = int(tmp_age) elif iline.startswith('#Sex'): tmp_sex = iline.split(': ')[1] if tmp_sex.strip()=='Female': sex =1 else: sex=0 elif iline.startswith('#Dx'): label = iline.split(': ')[1].split(',')[0] signal = data[1] gain = gain_lead[1] ecg_signal = nk.ecg_clean(signal*gain, sampling_rate=sample_Fs, method="biosppy") _ , rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=sample_Fs) hrv_time = nk.hrv_time(rpeaks, sampling_rate=sample_Fs) peaks, idx = detect_peaks(signal, sample_Fs, gain) # print(len(signal), len(idx)) rr_intervals = idx / (sample_Fs * 1000) rr_intervals = pd.Series(rr_intervals) rr_ma = rr_intervals.rolling(3) try: signal_peak, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=sample_Fs) p_peaks = waves_peak['ECG_P_Peaks'] except ValueError: print('Exception raised!') pass p_peaks = np.asarray(p_peaks, dtype=float) p_peaks = p_peaks[~np.isnan(p_peaks)] p_peaks = [int(a) for a in p_peaks] p_time = [x/sample_Fs for x in p_peaks] p_diff = np.diff(p_time) # mean_P_Peaks = np.mean([signal[w] for w in p_peaks]) hrv_time['var_P_time'] = stats.tvar(p_diff) hrv_time['var_P_peaks'] = stats.tvar(signal[np.array(p_peaks)]) hrv_time['age'] = age hrv_time['label'] = label return hrv_time
def get_12ECG_features_labels(data, header_data): tmp_hea = header_data[0].split(' ') ptID = tmp_hea[0] num_leads = int(tmp_hea[1]) sample_Fs= int(tmp_hea[2]) gain_lead = np.zeros(num_leads) for ii in range(num_leads): tmp_hea = header_data[ii+1].split(' ') gain_lead[ii] = int(tmp_hea[2].split('/')[0]) # for testing, we included the mean age of 57 if the age is a NaN # This value will change as more data is being released for iline in header_data: if iline.startswith('#Age'): tmp_age = iline.split(': ')[1].strip() age = int(tmp_age if tmp_age != 'NaN' else 57) elif iline.startswith('#Sex'): tmp_sex = iline.split(': ')[1] if tmp_sex.strip()=='Female': sex =1 else: sex=0 elif iline.startswith('#Dx'): label = iline.split(': ')[1].split(',')[0] signal = data[1] gain = gain_lead[1] N = len(signal) sp= sample_Fs/N # resolución espectral Y = np.fft.fft(signal*gain) ff = np.linspace(0, (N/2)*sp, N/2).flatten() fmax = float(ff[np.where(np.abs(Y[0:N//2]) == max(np.abs(Y[0:N//2])))]) # We are only using data from lead1 peaks,idx = detect_peaks(signal,sample_Fs,gain) # mean mean_RR = np.mean(idx/sample_Fs*1000) mean_R_Peaks = np.mean(peaks*gain) # median median_RR = np.median(idx/sample_Fs*1000) median_R_Peaks = np.median(peaks*gain) # standard deviation std_RR = np.std(idx/sample_Fs*1000) std_R_Peaks = np.std(peaks*gain) # variance var_RR = stats.tvar(idx/sample_Fs*1000) var_R_Peaks = stats.tvar(peaks*gain) # Skewness skew_RR = stats.skew(idx/sample_Fs*1000) skew_R_Peaks = stats.skew(peaks*gain) # Kurtosis kurt_RR = stats.kurtosis(idx/sample_Fs*1000) kurt_R_Peaks = stats.kurtosis(peaks*gain) # RMSSD (HRV) rmssd = np.sqrt(np.mean(np.square(np.diff(idx)))) # All Peaks ecg_signal = nk.ecg_clean(signal*gain, sampling_rate=sample_Fs, method="biosppy") _ , rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=sample_Fs) try: signal_peak, waves_peak = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=sample_Fs) t_peaks = waves_peak['ECG_T_Peaks'] p_peaks = waves_peak['ECG_P_Peaks'] q_peaks = waves_peak['ECG_Q_Peaks'] s_peaks = waves_peak['ECG_S_Peaks'] p_onsets = waves_peak['ECG_P_Onsets'] t_offsets = waves_peak['ECG_T_Offsets'] except ValueError: print('Exception raised!') pass # T Peaks t_peaks = np.asarray(t_peaks, dtype=float) t_peaks = t_peaks[~np.isnan(t_peaks)] t_peaks = [int(a) for a in t_peaks] mean_T_Peaks = np.mean([signal[w] for w in t_peaks]) # P peaks p_peaks = np.asarray(p_peaks, dtype=float) p_peaks = p_peaks[~np.isnan(p_peaks)] p_peaks = [int(a) for a in p_peaks] mean_P_Peaks = np.mean([signal[w] for w in p_peaks]) # Q peaks q_peaks = np.asarray(q_peaks, dtype=float) q_peaks = q_peaks[~np.isnan(q_peaks)] q_peaks = [int(a) for a in q_peaks] mean_Q_Peaks = np.mean([signal[w] for w in q_peaks]) # S peaks s_peaks = np.asarray(s_peaks, dtype=float) s_peaks = s_peaks[~np.isnan(s_peaks)] s_peaks = [int(a) for a in s_peaks] mean_S_Peaks = np.mean([signal[w] for w in s_peaks]) # P Onsets p_onsets = np.asarray(p_onsets, dtype=float) # p_onsets = p_onsets[~np.isnan(p_onsets)] mean_P_Onsets = np.mean(p_onsets/sample_Fs*1000) # T Onsets t_offsets = np.asarray(t_offsets, dtype=float) # t_offsets = t_offsets[~np.isnan(t_offsets)] mean_T_offsets = np.mean(t_offsets/sample_Fs*1000) features = [age,sex,fmax,mean_RR,mean_R_Peaks,mean_T_Peaks,mean_P_Peaks,mean_Q_Peaks,mean_S_Peaks,median_RR,median_R_Peaks,std_RR,std_R_Peaks,var_RR,var_R_Peaks,skew_RR,skew_R_Peaks,kurt_RR,kurt_R_Peaks,mean_P_Onsets,mean_T_offsets,rmssd,label] return features
def bandpass(lowcut, highcut, order=5): nyq = 0.5 * 500 low = lowcut / nyq high = highcut / nyq b, a = butter(order, [low, high], btype='band') return b, a b, a = bandpass(0.5, 45) filtered_ecg = signal.filtfilt(b, a, ecg_wave[250:4750]) _, rpeaks = nk.ecg_peaks(filtered_ecg, sampling_rate=500) _, waves_cwt = nk.ecg_delineate(filtered_ecg, rpeaks, sampling_rate=500, method="dwt", show=False, show_type='peaks') # 관심 ECG 설정 interest_ecg = filtered_ecg[rpeaks['ECG_R_Peaks'][0]:rpeaks['ECG_R_Peaks'][1]] # template ECG 설정 template_ecg = [] for i in range(len(rpeaks['ECG_R_Peaks'])): try: template_ecg.append( filtered_ecg[rpeaks['ECG_R_Peaks'][i + 1]:rpeaks['ECG_R_Peaks'][i +
fig.savefig("README_hrv.png", dpi=300, h_pad=3) # ============================================================================= # ECG Delineation # ============================================================================= # Download data ecg_signal = nk.data(dataset="ecg_3000hz")['ECG'] # Extract R-peaks locations _, rpeaks = nk.ecg_peaks(ecg_signal, sampling_rate=3000) # Delineate signal, waves = nk.ecg_delineate(ecg_signal, rpeaks, sampling_rate=3000, method="dwt", show=True, show_type='all') # Save plot fig = plt.gcf() fig.set_size_inches(10 * 1.5, 6 * 1.5, forward=True) fig.savefig("README_delineate.png", dpi=300, h_pad=3) # ============================================================================= # Complexity # ============================================================================= # Generate signal signal = nk.signal_simulate(frequency=[1, 3], noise=0.01, sampling_rate=100)
def create_df(dataframe: pd.DataFrame) -> pd.DataFrame: # get lengths of signals for each sample lengths = [] width = dataframe.shape[1] for row in dataframe.index.tolist(): temp_width = width for item in dataframe.loc[row][::-1]: if not pd.isna(item) and isinstance(item, float): temp_width -= 1 break temp_width -= 1 lengths.append(temp_width) """ README For the following features we measured: [mean, median, 5 % percentile, 95 % percentile, standard deviation] R-peak location were retrieved by nk.ecg_peaks Q-peak and S-location were retrieved by nk.ecg_delineate ?_ampl_* ?-Peak amplitude ?_nr_peaks number of ?-Peaks ?_diff_* Interval between ?-Peaks QRS_diff_* QRS duration len_* length of signal Qual_* quality of signal measured with nk.ecg_quality sign_* signal Also the output from nk.hrv_time which contains different measurements for the heart rate variation (HRV*) was added Additionally one 'typical' heartbeat was greated (all length 180): MN_* mean signal MD_* median signal P5_* 5 % percentile signal P95_* 95 % percentile signal SD_* standard deviation of signal """ names = ['R_ampl_mean', 'R_ampl_median', 'R_ampl_perc5', 'R_ampl_perc95', 'R_ampl_sd', 'R_nr_peaks', 'len_mean', 'len_median', 'len_perc5', 'len_perc95', 'len_sd', 'sign_mean', 'sign_median', 'sign_perc5', 'sign_perc95', 'sign_sd', 'Qual_mean', 'Qual_median', 'Qual_perc5', 'Qual_perc95', 'Qual_sd', 'Q_ampl_mean', 'Q_ampl_median', 'Q_ampl_perc5', 'Q_ampl_perc95', 'Q_ampl_sd', 'Q_nr_peaks', 'Q_diff_mean', 'Q_diff_median', 'Q_diff_perc5', 'Q_diff_perc95', 'Q_diff_sd', 'S_ampl_mean', 'S_ampl_median', 'S_ampl_perc5', 'S_ampl_perc95', 'S_ampl_sd', 'S_nr_peaks', 'S_diff_mean', 'S_diff_median', 'S_diff_perc5', 'S_diff_perc95', 'S_diff_sd', 'P_ampl_mean', 'P_ampl_median', 'P_ampl_perc5', 'P_ampl_perc95', 'P_ampl_sd', 'P_nr_peaks', 'T_ampl_mean', 'T_ampl_median', 'T_ampl_perc5', 'T_ampl_perc95', 'T_ampl_sd', 'T_nr_peaks', 'QRS_diff_mean', 'QRS_diff_median', 'QRS_diff_perc5', 'QRS_diff_perc95', 'QRS_diff_sd', 'PR_diff_mean', 'PR_diff_median', 'PR_diff_perc5', 'PR_diff_perc95', 'PR_diff_sd', 'RT_diff_mean', 'RT_diff_median', 'RT_diff_perc5', 'RT_diff_perc95', 'RT_diff_sd', 'HRV_RMSSD', 'HRV_MeanNN', 'HRV_SDNN', 'HRV_SDSD', 'HRV_CVNN', 'HRV_CVSD', 'HRV_MedianNN', 'HRV_MadNN', 'HRV_MCVNN', 'HRV_IQRNN', 'HRV_pNN50', 'HRV_pNN20', 'HRV_TINN', 'HRV_HTI', 'HRV_ULF','HRV_VLF','HRV_LF','HRV_HF','HRV_VHF','HRV_LFHF','HRV_LFn','HRV_HFn', 'HRV_LnHF', 'HRV_SD1','HRV_SD2', 'HRV_SD1SD2','HRV_S','HRV_CSI','HRV_CVI','HRV_CSI_Modified', 'HRV_PIP', 'HRV_IALS','HRV_PSS','HRV_PAS','HRV_GI','HRV_SI','HRV_AI','HRV_PI','HRV_C1d','HRV_C1a','HRV_SD1d', 'HRV_SD1a','HRV_C2d','HRV_C2a','HRV_SD2d','HRV_SD2a','HRV_Cd','HRV_Ca','HRV_SDNNd','HRV_SDNNa','HRV_ApEn', 'HRV_SampEn','J_LF','J_HF','J_L/H'] template_len = 180 mean_names = ['MN_' + str(index) for index in range(template_len)] median_names = ['MD_' + str(index) for index in range(template_len)] perc5_names = ['P5_' + str(index) for index in range(template_len)] perc95_names = ['P95_' + str(index) for index in range(template_len)] sd_names = ['SD_' + str(index) for index in range(template_len)] wavelet = 'db3' wl_len = int(np.floor((template_len + pywt.Wavelet(wavelet).dec_len - 1) / 2)) wl_mean_names = ['WLMN_' + str(index) for index in range(2*wl_len)] wl_median_names = ['WLMD_' + str(index) for index in range(2*wl_len)] wl_perc5_names = ['WLP5_' + str(index) for index in range(2*wl_len)] wl_perc95_names = ['WLP95_' + str(index) for index in range(2*wl_len)] wl_sd_names = ['WLSD_' + str(index) for index in range(2*wl_len)] typical_signal_names = mean_names + median_names + perc5_names + perc95_names + sd_names + wl_mean_names + \ wl_median_names + wl_perc5_names + wl_perc95_names + wl_sd_names names += typical_signal_names data = np.empty([dataframe.shape[0], len(names)]) iteration = 0 for row_index, row in dataframe.iterrows(): print(row_index) # Retrieve ECG data ecg_signal = row[:lengths[iteration] + 1] ecg_signal = nk.ecg_clean(ecg_signal, sampling_rate=SAMPLING_RATE) # Find R-peaks peaks, info = nk.ecg_peaks(ecg_signal, sampling_rate=SAMPLING_RATE) # R amplitude R_amplitudes = ecg_signal[info['ECG_R_Peaks']] # Check if the signal is flipped # Check if we have enough peaks to retrieve more information if len(R_amplitudes) > 4: _, waves_peak = nk.ecg_delineate(ecg_signal, info, sampling_rate=300, show=False) # Q amplitude # remove nan values Q_amplitudes = [ecg_signal[peak_index] if str(peak_index) != 'nan' else - np.infty for peak_index in waves_peak['ECG_Q_Peaks']] if np.sum([1 if np.abs(rpeak) > np.abs(Q_amplitudes[index]) else -1 for index, rpeak in enumerate(R_amplitudes)]) < 0: print("flip", row_index) ecg_signal = -ecg_signal peaks, info = nk.ecg_peaks(ecg_signal, sampling_rate=300) # R amplitude R_amplitudes = ecg_signal[info['ECG_R_Peaks']] if len(R_amplitudes) > 4: _, waves_peak = nk.ecg_delineate(ecg_signal, info, sampling_rate=300, show=False) data_temp = [] if len(R_amplitudes) > 0: data_temp = [np.mean(R_amplitudes), np.median(R_amplitudes), np.percentile(R_amplitudes, q=5), np.percentile(R_amplitudes, q=95), np.std(R_amplitudes), len(R_amplitudes)] else: empty = np.empty([6]) empty[:] = np.NaN data_temp += empty.tolist() # length of signal data_new = [np.mean(lengths[iteration] / SAMPLING_RATE), np.median(lengths[iteration] / SAMPLING_RATE), np.percentile(lengths[iteration] / SAMPLING_RATE, q=5), np.percentile(lengths[iteration] / SAMPLING_RATE, q=95), np.std(lengths[iteration] / SAMPLING_RATE)] data_temp += data_new # signal data_new = [np.mean(ecg_signal), np.median(ecg_signal), np.percentile(ecg_signal, q=5), np.percentile(ecg_signal, q=95), np.std(ecg_signal)] data_temp += data_new # Check if we have enough peaks to retrieve more information if len(R_amplitudes) > 4: quality = nk.ecg_quality(ecg_signal, sampling_rate=SAMPLING_RATE) data_new = [np.mean(quality), np.median(quality), np.percentile(quality, q=5), np.percentile(quality, q=95), np.std(quality)] data_temp += data_new # Delineate the ECG signal # “ECG_P_Peaks”, “ECG_Q_Peaks”, “ECG_S_Peaks”, “ECG_T_Peaks”, “ECG_P_Onsets”, “ECG_T_Offsets” # _, waves_peak = nk.ecg_delineate(ecg_signal, info, sampling_rate=SAMPLING_RATE, show=False) # Q amplitude # remove nan values Q_peaks = [peak for peak in waves_peak['ECG_Q_Peaks'] if str(peak) != 'nan'] if len(Q_peaks) > 0: Q_amplitudes = ecg_signal[Q_peaks] data_new = [np.mean(Q_amplitudes), np.median(Q_amplitudes), np.percentile(Q_amplitudes, q=5), np.percentile(Q_amplitudes, q=95), np.std(Q_amplitudes), len(Q_amplitudes)] data_temp += data_new else: empty = np.empty([6]) empty[:] = np.NaN empty[5] = 0 data_temp += empty.tolist() # more than 1 Q-Peak => can build interval[s] if len(Q_peaks) > 1: Q_peaks_diff = [(Q_peaks[index + 1] - Q_peaks[index]) / SAMPLING_RATE for index, item in enumerate(Q_peaks[:len(Q_peaks) - 1])] # QQ interval data_new = [np.mean(Q_peaks_diff), np.median(Q_peaks_diff), np.percentile(Q_peaks_diff, q=5), np.percentile(Q_peaks_diff, q=95), np.std(Q_peaks_diff)] data_temp += data_new # 0 or 1 Q-peak = no interval => return nan else: empty = np.empty([5]) empty[:] = np.NaN data_temp += empty.tolist() # S amplitude # remove nan values S_peaks = [peak for peak in waves_peak['ECG_S_Peaks'] if str(peak) != 'nan'] if len(S_peaks) > 0: S_amplitudes = ecg_signal[S_peaks] data_new = [np.mean(S_amplitudes), np.median(S_amplitudes), np.percentile(S_amplitudes, q=5), np.percentile(S_amplitudes, q=95), np.std(S_amplitudes), len(S_amplitudes)] data_temp += data_new else: empty = np.empty([6]) empty[:] = np.NaN empty[5] = 0 data_temp += empty.tolist() # more than one S-peak if len(S_peaks) > 1: S_peaks_diff = [(S_peaks[index + 1] - S_peaks[index]) / SAMPLING_RATE for index, item in enumerate(S_peaks[:len(S_peaks) - 1])] # SS interval data_new = [np.mean(S_peaks_diff), np.median(S_peaks_diff), np.percentile(S_peaks_diff, q=5), np.percentile(S_peaks_diff, q=95), np.std(S_peaks_diff)] data_temp += data_new # 0 or 1 S-peak = no interval => return nan else: empty = np.empty([5]) empty[:] = np.NaN data_temp += empty.tolist() P_peaks = [peak for peak in waves_peak['ECG_P_Peaks'] if str(peak) != 'nan'] if len(P_peaks) > 0: P_amplitudes = ecg_signal[P_peaks] data_new = [np.mean(P_amplitudes), np.median(P_amplitudes), np.percentile(P_amplitudes, q=5), np.percentile(P_amplitudes, q=95), np.std(P_amplitudes), len(P_amplitudes)] data_temp += data_new else: empty = np.empty([6]) empty[:] = np.NaN empty[5] = 0 data_temp += empty.tolist() T_peaks = [peak for peak in waves_peak['ECG_T_Peaks'] if str(peak) != 'nan'] if len(T_peaks) > 0: T_peaks = ecg_signal[T_peaks] data_new = [np.mean(T_peaks), np.median(T_peaks), np.percentile(T_peaks, q=5), np.percentile(T_peaks, q=95), np.std(T_peaks), len(T_peaks)] data_temp += data_new else: empty = np.empty([6]) empty[:] = np.NaN empty[5] = 0 data_temp += empty.tolist() # QRS interval QRS_peaks_diff = [] # compute difference between Q and S peak for index in range(len(waves_peak['ECG_Q_Peaks'])): if not (np.isnan(waves_peak['ECG_Q_Peaks'][index]) or np.isnan(waves_peak['ECG_S_Peaks'][index])): QRS_peaks_diff.append( (waves_peak['ECG_S_Peaks'][index] - waves_peak['ECG_Q_Peaks'][index]) / SAMPLING_RATE) if len(QRS_peaks_diff) > 0: data_new = [np.mean(QRS_peaks_diff), np.median(QRS_peaks_diff), np.percentile(QRS_peaks_diff, q=5), np.percentile(QRS_peaks_diff, q=95), np.std(QRS_peaks_diff)] data_temp += data_new else: empty = np.empty([5]) empty[:] = np.NaN data_temp += empty.tolist() # PR interval PR_peaks_diff = [] # compute difference between P and R peak for index in range(len(waves_peak['ECG_P_Peaks'])): if not np.isnan(waves_peak['ECG_P_Peaks'][index]): PR_peaks_diff.append( (info['ECG_R_Peaks'][index] - waves_peak['ECG_P_Peaks'][index]) / SAMPLING_RATE) if len(PR_peaks_diff) > 0: data_new = [np.mean(PR_peaks_diff), np.median(PR_peaks_diff), np.percentile(PR_peaks_diff, q=5), np.percentile(PR_peaks_diff, q=95), np.std(PR_peaks_diff)] data_temp += data_new else: empty = np.empty([5]) empty[:] = np.NaN data_temp += empty.tolist() # RT interval RT_peaks_diff = [] # compute difference between P and R peak for index in range(len(waves_peak['ECG_T_Peaks'])): if not np.isnan(waves_peak['ECG_T_Peaks'][index]): RT_peaks_diff.append( (waves_peak['ECG_T_Peaks'][index] - info['ECG_R_Peaks'][index]) / SAMPLING_RATE) if len(RT_peaks_diff) > 0: data_new = [np.mean(RT_peaks_diff), np.median(PR_peaks_diff), np.percentile(RT_peaks_diff, q=5), np.percentile(RT_peaks_diff, q=95), np.std(RT_peaks_diff)] data_temp += data_new else: empty = np.empty([5]) empty[:] = np.NaN data_temp += empty.tolist() # Extract clean EDA and SCR features # explanation of features: # https://neurokit2.readthedocs.io/en/latest/functions.html?highlight=hrv%20time#neurokit2.hrv.hrv_time hrv_time = nk.hrv(peaks, sampling_rate=SAMPLING_RATE, show=False) data_new = hrv_time.values.tolist()[0] data_temp += data_new # Jannik # http://www.paulvangent.com/2016/03/21/analyzing-a-discrete-heart-rate-signal-using-python-part-2/ rpeaks = info['ECG_R_Peaks'] r_interval = [rpeaks[index+1]-rpeaks[index] for index in range(len(rpeaks)-1)] RR_x_new = np.linspace(rpeaks[0],rpeaks[-2],rpeaks[-2]) f = interp1d(rpeaks[:-1], r_interval, kind='cubic') n = lengths[iteration] + 1 # Length of the signal frq = np.fft.fftfreq(n, d=(1 / SAMPLING_RATE)) # divide the bins into frequency categories frq = frq[range(int(n/2))] # Get single side of the frequency range Y = np.fft.fft(f(RR_x_new))/n # Calculate FFT try: Y = Y[range(int(n / 2))] lf = np.trapz(abs(Y[(frq >= 0.04) & (frq <= 0.15)])) hf = np.trapz(abs(Y[(frq >= 0.16) & (frq <= 0.5)])) # Do the same for 0.16-0.5Hz (HF) data_new = [lf, hf, lf / hf] data_temp += data_new except IndexError as err: print(err) data_temp += [None, None, None] # if we don't have enough R peaks return vector of nan's else: empty = np.empty([len(names) - 16 - len(typical_signal_names)]) empty[:] = np.NaN data_temp += empty.tolist() # Create a 'typical' heartbeat # Scaler = StandardScaler() # ecg_signal = Scaler.fit_transform(X=ecg_signal.reshape(-1, 1)).reshape(1, -1)[0].tolist() out = ecg.ecg(signal=ecg_signal, sampling_rate=SAMPLING_RATE, show=False) mean = np.mean(out['templates'], axis=0) median = np.median(out['templates'], axis=0) perc5 = np.percentile(out['templates'].astype(np.float64), axis=0, q=5) perc95 = np.percentile(out['templates'].astype(np.float64), axis=0, q=95) std = np.std(out['templates'].astype(np.float64), axis=0) data_new = np.concatenate((mean, median, perc5, perc95, std)).tolist() data_temp += data_new (wl_mean_cA, wl_mean_cD) = pywt.dwt(np.mean(out['templates'], axis=0), 'db3', 'periodic') (wl_median_cA, wl_median_cD) = pywt.dwt(np.median(out['templates'], axis=0), 'db3', 'periodic') (wl_perc5_cA, wl_perc5_cD) = pywt.dwt(np.percentile(out['templates'].astype(np.float64), axis=0, q=5), 'db3', 'periodic') (wl_perc95_cA, wl_perc95_cD) = pywt.dwt(np.percentile(out['templates'].astype(np.float64), axis=0, q=95), 'db3', 'periodic') (wl_sd_cA, wl_sd_cD) = pywt.dwt(np.std(out['templates'].astype(np.float64), axis=0), 'db3', 'periodic') data_new = np.concatenate((wl_mean_cA, wl_mean_cD, wl_median_cA, wl_median_cD, wl_perc5_cA, wl_perc5_cD, wl_perc95_cA, wl_perc95_cD, wl_sd_cA, wl_sd_cD)).tolist() data_temp += data_new data[iteration] = data_temp iteration += 1 features = pd.DataFrame(data, columns=names) return features
def extract_features( self, clean_method: str = "neurokit", r_method: str = "neurokit", wave_method: str = "dwt", min_peaks: int = 200, size: int = 200000, ): """ Function to extract the ecg features using the neurokit2 package. That is the P, Q, R, S and T peaks and the P, QRS and T waves onsets and offsets. The result is saved internally. :param clean_method: <str> The processing pipeline to apply. Can be one of ‘neurokit’ (default), ‘biosppy’, ‘pantompkins1985’, ‘hamilton2002’, ‘elgendi2010’, ‘engzeemod2012’. :param r_method: <str> The algorithm to be used for R-peak detection. Can be one of ‘neurokit’ (default), ‘pantompkins1985’, ‘hamilton2002’, ‘christov2004’, ‘gamboa2008’, ‘elgendi2010’, ‘engzeemod2012’ or ‘kalidas2017’. :param wave_method: <str> Can be one of ‘dwt’ (default) for discrete wavelet transform or ‘cwt’ for continuous wavelet transform. :param min_peaks: <int> Minimum R peaks to be detected to proceed with further calculations. :param size: <int> ECG sample size to analyze per loop. """ if not self.lead: return for i, _ in enumerate(self.sampling_rate): sampling_rate = self.sampling_rate[i][0] init = self.sampling_rate[i][1] if i == len(self.sampling_rate) - 1: ecg_signal_size = ( ECG_TMAPS[f"{self.lead}_value"].tensor_from_file( ECG_TMAPS[f"{self.lead}_value"], self, visit=self.visit, )[0][init:].shape[0]) else: ecg_signal_size = self.sampling_rate[i + 1][1] - init if size < ecg_signal_size: end = init + size else: end = init + ecg_signal_size while init < ecg_signal_size + self.sampling_rate[i][1]: ecg_signal = ECG_TMAPS[f"{self.lead}_value"].tensor_from_file( ECG_TMAPS[f"{self.lead}_value"], self, visit=self.visit, )[0][init:end] ecg_signal = nk.ecg_clean(ecg_signal, sampling_rate, clean_method) try: _, r_peaks = nk.ecg_peaks(ecg_signal, sampling_rate, r_method) except IndexError: init = end end = init + size if end > ecg_signal_size + self.sampling_rate[i][1]: end = ecg_signal_size + self.sampling_rate[i][1] continue if len(r_peaks["ECG_R_Peaks"]) < min_peaks: init = end end = init + size if end > ecg_signal_size + self.sampling_rate[i][1]: end = ecg_signal_size + self.sampling_rate[i][1] continue _, waves_peaks = nk.ecg_delineate(ecg_signal, r_peaks, sampling_rate) _, waves_peaks_2 = nk.ecg_delineate( ecg_signal, r_peaks, sampling_rate, wave_method, ) waves_peaks.update(waves_peaks_2) for peak_type in r_peaks: if peak_type not in self.r_peaks: self.r_peaks[peak_type] = r_peaks[peak_type] else: self.r_peaks[peak_type] = np.append( self.r_peaks[peak_type], r_peaks[peak_type], ) for peak_type in waves_peaks: if peak_type not in self.waves_peaks: self.waves_peaks[peak_type] = waves_peaks[peak_type] else: self.waves_peaks[peak_type] = np.append( self.waves_peaks[peak_type], waves_peaks[peak_type], ) init = end end = init + size if end > ecg_signal_size + self.sampling_rate[i][1]: end = ecg_signal_size + self.sampling_rate[i][1] for peak_type in self.r_peaks: self.r_peaks[peak_type] = list(self.r_peaks[peak_type]) for peak_type in self.waves_peaks: self.waves_peaks[peak_type] = list(self.waves_peaks[peak_type])