def _filtering(signal,fs,pass_frequency,n): if n == 1: order = int(0.3 * fs) filtered, _, _ = filter_signal(signal=signal,ftype='FIR',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs) elif n == 2: order = 5 filtered, _, _ = filter_signal(signal=signal,ftype='butter',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs) elif n == 3: order = 5 filtered, _, _ = filter_signal(signal=signal,ftype='bessel',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs) elif n == 4: order = 5 filtered, _, _ = filter_signal(signal=signal,ftype='ellip',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs,rp=5,rs=40) return(filtered)
def biosppy_bandpass(self, data_time_pair): ret_list = [] data = [] # Give enough data points to filter properly if len(data_time_pair) > 300: # Extract vals for point in data_time_pair: data.append(point[1]) # Calculate order of filter order = int(0.3 * self.sample_rate) # Apply filters filtered_data, _, _ = st.filter_signal( signal=data, ftype='FIR', band='bandpass', order=order, frequency=[1, 58], sampling_rate=self.sample_rate) # MIGHT NEED TO CONVERT filtered_data INTO A LIST!!! # Recompile data with times for i in range(0, len(data_time_pair)): ret_list.append([data_time_pair[i][0], filtered_data[i]]) else: ret_list = data_time_pair return ret_list
def find_peaks(self, X, channel=0): X_processed = X[:, channel].copy() X_processed = filter_signal(signal=X_processed, ftype='FIR', band='bandpass', order=150, frequency=[3, 45], sampling_rate=400)[0] # check original polarity ecg_object = ecg.ecg(signal=X_processed, sampling_rate=400, show=False) peaks_plus = ecg_object['rpeaks'] # rpeak indices # check reversed polarity ecg_object = ecg.ecg(signal=-1 * X_processed, sampling_rate=400, show=False) peaks_minus = ecg_object['rpeaks'] # # select polarity if np.abs(np.median(X_processed[peaks_minus])) > np.abs( np.median(X_processed[peaks_plus])): peaks = peaks_minus.copy() else: peaks = peaks_plus.copy() return peaks
def bandpass(self, data): ret_list = [] data = [] # Give enough data points to filter properly if len(data) > 300: # Calculate order of filter order = int(0.3 * self.sample_rate) # Apply filters filtered_data, _, _ = st.filter_signal( signal=data, ftype='FIR', band='bandpass', order=order, frequency=[2, 50], sampling_rate=self.sample_rate) ret_list = filtered_data else: ret_list = data return ret_list
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 biosppy_bandpass(self, data_time_pair): ret_list = [] data = [] # Give enough data points to filter properly if len(data_time_pair) > 300: # Extract vals for point in data_time_pair: data.append(point[1]) # Calculate order of filter order = int(0.3 * self.sample_rate) # Apply filters filtered_data, _, _ = st.filter_signal(signal=data, ftype='FIR', band='bandpass', order=order, frequency=[1, 58], sampling_rate=self.sample_rate) # MIGHT NEED TO CONVERT filtered_data INTO A LIST!!! # Recompile data with times for i in range(0, len(data_time_pair)): ret_list.append([data_time_pair[i][0], filtered_data[i]]) else: ret_list = data_time_pair return ret_list
def test_imports(): """ Test to check import of libraries. """ #checking scipy, keras, numpy, biosppy dummy = sp.__version__ dummy3 = k.__version__ dummy4 = np.__version__ dummy5 = bsp.__version__ sine = fn.sinewave() emg = em.emgsig() #checking matplotlib.pyplot if plt.plot(sine): pass #checking tensorflow help(tf.keras.Sequential) #checking scipy.signal if signal.correlate(emg, sine) is not None: pass #checking biosppy.signals.tools if tools.filter_signal(emg, ftype='butter', band='lowpass', order=2, frequency=50, sampling_rate=1000) is not None: pass
def passfilter(signal, fs, freq1, freq2): """Filter raw ECG waveform with bandpass finite-impulse-response filter.""" # Calculate filter order order = int(0.3 * fs) # Filter waveform signal.val, _, _ = tools.filter_signal(signal=signal.val, ftype='FIR', band='bandpass', order=order, frequency=(freq1, freq2), sampling_rate=fs) return signal
def _apply_filter(self, signal_raw, filter_bandwidth): """Apply FIR bandpass filter to waveform.""" signal_filtered, _, _ = filter_signal(signal=signal_raw, ftype='FIR', band='bandpass', order=int(0.3 * self.fs), frequency=filter_bandwidth, sampling_rate=self.fs) return signal_filtered
def filter(signal): signal = np.array(signal, dtype=np.float) filtered, _, _ = filter_signal(signal=signal, ftype='FIR', band='bandpass', order=150, frequency=(2, 200), sampling_rate=500) return filtered
def filter_ecg(signal=None, sampling_rate=1000.): order = int(0.3 * sampling_rate) filtered, _, _ = st.filter_signal(signal=signal, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=sampling_rate) return filtered
def filter_signal(signal, sampling_rate=360): signal = np.array(signal) order = int(0.3 * sampling_rate) filtered, _, _ = st.filter_signal(signal=signal, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=sampling_rate) return filtered
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 _filter_waveform(self): """Filter raw ECG waveform with bandpass finite-impulse-response filter.""" # Calculate filter order order = int(0.3 * self.fs) # Filter waveform filtered = np.zeros(self.waveform.shape) for lead in range(self.waveform.shape[1]): filtered[:, lead], _, _ = filter_signal(signal=self.waveform[:, lead], ftype='FIR', band='bandpass', order=order, frequency=self.filter_bands, sampling_rate=self.fs) return filtered
def _apply_filter(self, signal, filter_bandwidth): # Calculate filter order order = int(0.3 * self.fs) # Filter signal signal, _, _ = filter_signal(signal=signal, ftype='FIR', band='bandpass', order=order, frequency=filter_bandwidth, sampling_rate=self.fs) return signal
def _filter_waveform(self): # Calculate filter order order = int(0.3 * self.fs) # Filter waveform filtered, _, _ = filter_signal(signal=self.waveform, ftype='FIR', band='bandpass', order=order, frequency=self.filter_bands, sampling_rate=self.fs) return filtered
def _filter_waveform(self): """Filter raw ECG waveform with bandpass finite-impulse-response filter.""" # Calculate filter order order = int(0.3 * self.fs) # Filter waveform filtered, _, _ = filter_signal(signal=self.waveform, ftype='FIR', band='bandpass', order=order, frequency=self.filter_bands, sampling_rate=self.fs) return filtered
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 low_pass_filter(self, signal, cutoff_frequency, framerate): """ :param data: imported data -> self.podatki :return: filtered .wav data as np array """ if cutoff_frequency == "" or cutoff_frequency == "0": cutoff_frequency = 1000 cutoff_frequency = int(cutoff_frequency) filtered, _, _ = st.filter_signal(signal=signal, ftype='FIR', band='lowpass', frequency=cutoff_frequency, order=int(0.3 * 4000), sampling_rate=framerate) return np.array(filtered)
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
sampling_rate = 960.0 # sampling rate Ts = 1.0 / sampling_rate # sampling interval sm_size = int(0.08 * sampling_rate) # t = [] eye_left = [] for i in range(0, len(data_ch1)): t.append(i*Ts) order = int(0.3 * sampling_rate) # Filter Data filtered_data_ch1, _, _ = st.filter_signal(signal=data_ch1_arr, ftype='FIR', band='bandpass', order=order, frequency=[2, 50], sampling_rate=sampling_rate) filtered_data_ch2, _, _ = st.filter_signal(signal=data_ch2_arr, ftype='FIR', band='bandpass', order=order, frequency=[2, 50], sampling_rate=sampling_rate) # Smooth filtered_data_ch1, _ = st.smoother(signal=filtered_data_ch1, kernel='hamming', size=sm_size, mirror=True)
def preprocess_signal(raw_sig: np.ndarray, fs: Real, config: Optional[ED] = None) -> Dict[str, np.ndarray]: """ finished, checked, Parameters ---------- raw_sig: ndarray, the raw ecg signal fs: real number, sampling frequency of `raw_sig` config: dict, optional, extra process configuration, `PreprocCfg` will be updated by this `config` Returns ------- retval: dict, with items - 'filtered_ecg': the array of the processed ecg signal - 'rpeaks': the array of indices of rpeaks; empty if 'rpeaks' in `config` is not set NOTE ---- output (`retval`) are resampled to have sampling frequency equal to `config.fs` (if `config` has item `fs`) or `PreprocCfg.fs` """ filtered_ecg = raw_sig.copy() cfg = deepcopy(PreprocCfg) cfg.update(deepcopy(config) or {}) if fs != cfg.fs: filtered_ecg = resample(filtered_ecg, int(round(len(filtered_ecg) * cfg.fs / fs))) # remove baseline if 'baseline' in cfg.preproc: window1 = 2 * (cfg.baseline_window1 // 2) + 1 # window size must be odd window2 = 2 * (cfg.baseline_window2 // 2) + 1 baseline = median_filter(filtered_ecg, size=window1, mode='nearest') baseline = median_filter(baseline, size=window2, mode='nearest') filtered_ecg = filtered_ecg - baseline # filter signal if 'bandpass' in cfg.preproc: filtered_ecg = filter_signal( signal=filtered_ecg, ftype='FIR', band='bandpass', order=int(0.3 * fs), sampling_rate=fs, frequency=cfg.filter_band, )['signal'] if cfg.rpeaks and cfg.rpeaks.lower() not in DL_QRS_DETECTORS: # dl detectors not for parallel computing using `mp` detector = QRS_DETECTORS[cfg.rpeaks.lower()] rpeaks = detector(sig=filtered_ecg, fs=fs).astype(int) else: rpeaks = np.array([], dtype=int) retval = ED({ "filtered_ecg": filtered_ecg, "rpeaks": rpeaks, }) return retval
diff = time.time() - start # datafile.close() # Numpy Array Creation # data = np.loadtxt(filepath) samplrate = (data.size) / 10.0 samplrate = float(samplrate) # Powerline Interference Frequency Filter lowfiltered = butter_lowpass_filter(data, lowcut, samplingf, 5) # Filter Signal For Smoothing order = int(0.3 * samplrate) filtered, _, _ = st.filter_signal(signal=lowfiltered, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=samplrate) # Normalization filtered -= basedrift filtered *= scalefactor # Save to TXT file np.savetxt(filepath, filtered) counter = counter + 1 # Low pass filter functions def butter_lowpass(cutoff, samplef, order=5): nyq = 0.5 * samplef # Nyquist frequency normal_cutoff = cutoff / nyq
def call_filter( self, filter_type, filter_band, first_cutoff, second_cutoff, order, max_ripple, min_attenuation): """ Call specified filter function on all audio clips :param filter_type: type of filter :param filter_band: band of filter :param first_cutoff: first cutoff frequency :param second_cutoff: second cutoff frequency :param order: filter order :param max_ripple: the maximum ripple :param min_attenuation: the minimum attenuatio :return: Void """ if self.data is None: return filterBand = (''.join(c for c in filter_band if c not in "-")).lower() filterType = self.convertTypeToStr(filter_type) error = None self.X = [] self.metas = [] try: for i in range(len(self.data.metas)): if self.data.X != []: input_data = self.data.X[i] else: input_data = read(self.data.metas[i][1])[1] if len(input_data.shape) > 1: input_data = input_data[:, 0] if filterType == "FIR" or filterType == "butter" or filterType == "bessel": if filterBand == "lowpass" or filterBand == "highpass": filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=first_cutoff, sampling_rate=self.data.metas[i][-1]) else: filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=[first_cutoff, second_cutoff], sampling_rate=self.data.metas[i][-1]) elif filterType == "cheby1": if filterBand == "lowpass" or filterBand == "highpass": filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=first_cutoff, sampling_rate=self.data.metas[i][-1], rp=max_ripple) else: filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=[first_cutoff, second_cutoff], sampling_rate=self.data.metas[i][-1], rp=max_ripple) elif filterType == "cheby2": if filterBand == "lowpass" or filterBand == "highpass": filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=first_cutoff, sampling_rate=self.data.metas[i][-1], rs=min_attenuation) else: filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=[first_cutoff, second_cutoff], sampling_rate=self.data.metas[i][-1], rs=min_attenuation) else: if filterBand == "lowpass" or filterBand == "highpass": filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=first_cutoff, sampling_rate=self.data.metas[i][-1], rp=max_ripple, rs=min_attenuation) else: filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order, frequency=[first_cutoff, second_cutoff], sampling_rate=self.data.metas[i][-1], rp=max_ripple, rs=min_attenuation) self.new_tmp_dir = os.path.dirname( self.data.metas[i][1]) + os.sep + "filtered-" + self.tmp_dir_id + os.sep if not os.path.exists(self.new_tmp_dir): os.makedirs(self.new_tmp_dir) self.new_tmp_dirs.append(self.new_tmp_dir) filename = self.new_tmp_dir + self.data.metas[i][0] + ".wav" self.metas.append([self.data.metas[i][0], filename, self.data.metas[i][2], self.data.metas[i][3], self.data.metas[i][4]]) data = filtered["signal"] data = data / data.max() data = data * (2 ** 15 - 1) data = data.astype(numpy.int16) write(filename, self.data.metas[i][-1], data) except Exception as ex: error = ex if not error: self.info.setStyleSheet(success_green) self.info.setText( filter_type + " " + filter_band + " " + "filter successful!") orange_table = Orange.data.Table.from_numpy( self.data.domain, numpy.empty((len(self.data.Y), 0), dtype=float), self.data.Y, self.metas ) self.send("Filtered data", orange_table) if error: self.info.setStyleSheet(error_red) self.info.setText("An error occurred:\n{}".format(error)) return
def preprocess_single_lead_signal(raw_sig: np.ndarray, fs: Real, bl_win: Optional[List[Real]] = None, band_fs: Optional[List[Real]] = None, rpeak_fn: Optional[str] = None, verbose: int = 0) -> Dict[str, np.ndarray]: """ finished, checked, perform preprocessing for single lead ecg signal (with units in mV), preprocessing may include median filter, bandpass filter, and rpeaks detection, etc. Parameters: ----------- raw_sig: ndarray, the raw ecg signal, with units in mV fs: real number, sampling frequency of `raw_sig` bl_win: list (of 2 real numbers), optional, window (units in second) of baseline removal using `median_filter`, the first is the shorter one, the second the longer one, a typical pair is [0.2, 0.6], if is None or empty, baseline removal will not be performed band_fs: list (of 2 real numbers), optional, frequency band of the bandpass filter, a typical pair is [0.5, 45], be careful when detecting paced rhythm, if is None or empty, bandpass filtering will not be performed rpeak_fn: str, optional, name of the function detecting rpeaks, can be one of keys of `QRS_DETECTORS`, case insensitive verbose: int, default 0, print verbosity Returns: -------- retval: dict, with items - 'filtered_ecg': the array of the processed ecg signal - 'rpeaks': the array of indices of rpeaks; empty if `rpeak_fn` is not given """ filtered_ecg = raw_sig.copy() # remove baseline if bl_win: window1 = 2 * (int(bl_win[0] * fs) // 2) + 1 # window size must be odd window2 = 2 * (int(bl_win[1] * fs) // 2) + 1 baseline = median_filter(filtered_ecg, size=window1, mode='nearest') baseline = median_filter(baseline, size=window2, mode='nearest') filtered_ecg = filtered_ecg - baseline # filter signal if band_fs: filtered_ecg = filter_signal( signal=filtered_ecg, ftype='FIR', # ftype='butter', band='bandpass', order=int(0.3 * fs), sampling_rate=fs, frequency=band_fs, )['signal'] if rpeak_fn: rpeaks = QRS_DETECTORS[rpeak_fn.lower()](filtered_ecg, fs).astype(int) else: rpeaks = np.array([], dtype=int) retval = ED({ "filtered_ecg": filtered_ecg, "rpeaks": rpeaks, }) if verbose >= 3: from utils.misc import plot_single_lead from cfg import PlotCfg t = np.arange(len(filtered_ecg)) / fs waves = { "qrs": get_mask( shape=len(filtered_ecg), critical_points=rpeaks, left_bias=ms2samples(PlotCfg.qrs_radius, fs), right_bias=ms2samples(PlotCfg.qrs_radius, fs), return_fmt="intervals", ) } plot_single_lead(t=t, sig=filtered_ecg, ticks_granularity=2, waves=waves) return retval
def reshape_resting_ecg_to_tidy( sample_id: Union[int, str], folder: Optional[str] = None, tmap: TensorMap = DEFAULT_RESTING_ECG_SIGNAL_TMAP, ) -> pd.DataFrame: """Wrangle resting ECG data to tidy. Args: sample_id: The id of the ECG sample to retrieve. folder: The local or Cloud Storage folder under which the files reside. tmap: The TensorMap to use for ECG input. Returns: A pandas dataframe in tidy format or print a notebook-friendly error and return an empty dataframe. """ if folder is None: folder = get_resting_ecg_hd5_folder(sample_id) data: Dict[str, Any] = {'lead': [], 'raw': [], 'ts_reference': [], 'filtered': [], 'filtered_1': [], 'filtered_2': []} with tempfile.TemporaryDirectory() as tmpdirname: sample_hd5 = str(sample_id) + '.hd5' local_path = os.path.join(tmpdirname, sample_hd5) try: tf.io.gfile.copy(src=os.path.join(folder, sample_hd5), dst=local_path) except (tf.errors.NotFoundError, tf.errors.PermissionDeniedError) as e: print(f'''Warning: Resting ECG not available for sample {sample_id} in folder {folder}. Use the folder parameter to read HD5s from a different directory or bucket.\n\n{e.message}''') return pd.DataFrame(data) with h5py.File(local_path, mode='r') as hd5: try: signals = tmap.tensor_from_file(tmap, hd5) except (KeyError, ValueError) as e: print(f'''Warning: Resting ECG TMAP {tmap.name} not available for sample {sample_id}. Use the tmap parameter to choose a different TMAP.\n\n{e}''') _examine_available_keys(hd5) return pd.DataFrame(data) for (lead, channel) in ECG_REST_LEADS.items(): signal = signals[:, channel] signal_length = len(signal) data['raw'].extend(signal) data['lead'].extend([lead] * signal_length) data['ts_reference'].extend(np.array([i*1./(SAMPLING_RATE+1.) for i in range(0, signal_length)])) filtered, _, _ = filter_signal( signal=signal, ftype='FIR', band='bandpass', order=int(0.3 * SAMPLING_RATE), frequency=[.9, 50], sampling_rate=SAMPLING_RATE, ) data['filtered'].extend(filtered) filtered_1, _, _ = filter_signal( signal=signal, ftype='FIR', band='bandpass', order=int(0.3 * SAMPLING_RATE), frequency=[.9, 20], sampling_rate=SAMPLING_RATE, ) data['filtered_1'].extend(filtered_1) filtered_2, _, _ = filter_signal( signal=signal, ftype='FIR', band='bandpass', order=int(0.3 * SAMPLING_RATE), frequency=[.9, 30], sampling_rate=SAMPLING_RATE, ) data['filtered_2'].extend(filtered_2) signal_df = pd.DataFrame(data) # Convert the raw signal to mV. signal_df['raw_mV'] = signal_df['raw'] * RAW_SCALE signal_df['filtered_mV'] = signal_df['filtered'] * RAW_SCALE signal_df['filtered_1_mV'] = signal_df['filtered_1'] * RAW_SCALE signal_df['filtered_2_mV'] = signal_df['filtered_2'] * RAW_SCALE # Reshape to tidy (long format). tidy_signal_df = signal_df.melt( id_vars=['lead', 'ts_reference'], value_vars=['raw_mV', 'filtered_mV', 'filtered_1_mV', 'filtered_2_mV'], var_name='filtering', value_name='signal_mV', ) # The leads have a meaningful order, apply the order to this column. lead_factor_type = pd.api.types.CategoricalDtype( categories=[ 'strip_I', 'strip_aVR', 'strip_V1', 'strip_V4', 'strip_II', 'strip_aVL', 'strip_V2', 'strip_V5', 'strip_III', 'strip_aVF', 'strip_V3', 'strip_V6', ], ordered=True, ) tidy_signal_df['lead'] = tidy_signal_df.lead.astype(lead_factor_type) return tidy_signal_df
data.append(float(str(row[1]))) counter+= 1 data_arr = np.array(data) sampling_rate = 256.0 # sampling rate Ts = 1.0 / sampling_rate # sampling interval t = [] for i in range(0, len(data)): t.append(i*Ts) order = int(0.3 * sampling_rate) # filtered_data = ecg.ecg(data_arr, 256, False)['filtered'] filtered_data, _, _ = st.filter_signal(signal=data_arr, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=sampling_rate) print(filtered_data) plt.plot(t, filtered_data, 'r') #plt.plot(t, data, 'b') plt.xlabel("Time") plt.ylabel("Amplitude (V)") plt.show()
def fir(signal, order=2, cutoff=[50, 450], ftype='bandpass', fs=1000.0, plot='yes', **kwargs): """ Apply a FIR filter to the input signal. Input parameters ---------------- signal: ndarray the input signal to be filter order: int, optional the order of the filter; default set to 2 cutoff: scalar (int or float) or 2 length sequence (for band-pass and band-stop filter) the critical frequency; default set to [50,500] ftype: str, optional type of filter to be used; default set to 'bandpass' types: 'lowpass','highpass', 'bandpass', 'bandstop' fs: int or float, optional sampling rate plot: str - yes/Y or no/N (non-case sensitive), optional plot the filtered signal or not; default set to yes **kwargs: dict, optional Additional keyword arguments are passed to the underlying scipy.signal function Output ------ Output will be in the format --> filtersig filtersig: ndarray the filtered signal """ #cutoff error try: cutoff = float(cutoff) except TypeError: cutoff = np.array(cutoff) except ValueError: raise ValueError("Cutoff can only be an int, float or numpy array.") if isinstance(cutoff, np.ndarray): if cutoff.size == 2: if isinstance(cutoff[0], complex): raise TypeError("Cutoff frequency cannot be complex.") if isinstance(cutoff[-1], complex): raise TypeError("Cutoff frequency cannot be complex.") else: raise ValueError( "Cutoff must be a scalar (int or float) or 2 length sequence (list or numpy array)." ) #sampling frequency error try: fs = float(fs) except TypeError: raise TypeError("Sampling frequency (fs) must be int or float.") except ValueError: raise ValueError("Sampling frequency (fs) must be int or float.") #signal error if isinstance(signal, (list, np.ndarray)): signal = np.array(signal) elif isinstance(signal, (int, float)): raise ValueError("Signal should be a list or numpy array.") else: raise TypeError("Signal should be a list or numpy array.") for i in signal: if isinstance(i, complex): raise ValueError("Signal cannot contain complex elements.") #order error try: order = int(order) except TypeError: raise TypeError("Order must be an int.") except ValueError: raise ValueError("Order must be an int.") #filter type error if ftype in ['lowpass', 'highpass', 'bandpass', 'bandstop']: pass elif isinstance(ftype, str): raise ValueError( "Filter type must be 'lowpass', 'highpass', 'bandpass', 'bandstop'." ) else: raise TypeError("Filter type must be a string.") #plot error if plot in ['Yes', 'yes', 'No', 'no', 'Y', 'y', 'N', 'n', 'YES', 'NO']: pass elif isinstance(plot, str): raise ValueError("Plot can be Yes/Y or No/N (non-case sensitive).") else: raise TypeError( "Plot must be a string - Yes/Y or No/N (non-case sensitive).") #filtering filtersig = tools.filter_signal(signal, ftype='FIR', band=ftype, order=order, frequency=cutoff, sampling_rate=fs, **kwargs) filtersig = filtersig['signal'] #plotting if plot in ['yes', 'Yes', 'Y', 'y', 'YES']: time = np.arange(0, len(signal) / fs, 1 / fs) plt.figure(figsize=(12, 6)) plt.subplot(211) plt.plot(time, signal, label="Raw signal") plt.suptitle("Raw & Filtered signal") plt.ylabel("Amplitude") plt.legend() plt.subplot(212) plt.plot(time, filtersig, c='#ff7f0e', label="Filtered signal") plt.xlabel("Time") plt.ylabel("Amplitude") plt.legend() plt.tight_layout() plt.show() return filtersig
data.append(float(str(row[1]))) counter += 1 data_arr = np.array(data) sampling_rate = 256.0 # sampling rate Ts = 1.0 / sampling_rate # sampling interval t = [] for i in range(0, len(data)): t.append(i * Ts) order = int(0.3 * sampling_rate) # filtered_data = ecg.ecg(data_arr, 256, False)['filtered'] filtered_data, _, _ = st.filter_signal(signal=data_arr, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=sampling_rate) print(filtered_data) plt.plot(t, filtered_data, 'r') #plt.plot(t, data, 'b') plt.xlabel("Time") plt.ylabel("Amplitude (V)") plt.show()
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 resp(signal=None, sampling_rate=1000., show=True): """Process a raw Respiration signal and extract relevant signal features using default parameters. Parameters ---------- signal : array Raw Respiration signal. sampling_rate : int, float, optional Sampling frequency (Hz). show : bool, optional If True, show a summary plot. Returns ------- ts : array Signal time axis reference (seconds). filtered : array Filtered Respiration signal. zeros : array Indices of Respiration zero crossings. resp_rate_ts : array Inspiration rate time axis reference (seconds). resp_rate : array Instantaneous respiration rate (Hz). """ # check inputs if signal is None: raise TypeError("Please specify an input signal.") # ensure numpy signal = np.array(signal) sampling_rate = float(sampling_rate) # filter signal # 0.1 ~~ 0.35 Hzのバンドパスフィルタ filtered, _, _ = st.filter_signal(signal=signal, ftype='butter', band='bandpass', order=2, frequency=[0.1, 0.35], sampling_rate=sampling_rate) # compute zero crossings filtered = filtered - np.mean(filtered) # zeros df = np.diff(np.sign(filtered)) inspiration = np.nonzero(df > 0)[0] expiration = np.nonzero(df < 0)[0] if len(inspiration) < 2: rate_idx = [] rate = [] else: # compute resp peaks between inspiration and expiration peaks = [] for i in range(len(inspiration) - 1): cycle = filtered[inspiration[i]:inspiration[i + 1]] peaks.append(np.argmax(cycle) + inspiration[i]) # list to array peaks = np.array(peaks) # compute respiration rate rate_idx = inspiration[1:] rate = sampling_rate * (1. / np.diff(inspiration)) # physiological limits # 0.35Hz以下のresp_rateは省かれる indx = np.nonzero(rate <= 0.35) rate_idx = rate_idx[indx] rate = rate[indx] # smooth with moving average size = 3 rate, _ = st.smoother(signal=rate, kernel='boxcar', size=size, mirror=True) # get time vectors length = len(signal) T = (length - 1) / sampling_rate ts = np.linspace(0, T, length, endpoint=True) ts_rate = ts[rate_idx] # plot if show: plotting.plot_resp(ts=ts, raw=signal, filtered=filtered, zeros=zeros, resp_rate_ts=ts_rate, resp_rate=rate, path=None, show=True) # output args = (ts, filtered, ts_rate, rate, inspiration, expiration, peaks) names = ('ts', 'filtered', 'resp_rate_ts', 'resp_rate', 'inspiration', 'expiration', 'peaks') return utils.ReturnTuple(args, names)
def scale_maxabs(arr, maxabs, thres): arr = (arr / maxabs) * thres return arr def apply_threshold(arr, thres): arr[arr > thres] = thres arr[arr < -thres] = thres return arr order = int(0.3 * 100) filtered_train_x, _, _ = st.filter_signal(signal=X_train, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=100) filtered_test_x, _, _ = st.filter_signal(signal=X_test, ftype='FIR', band='bandpass', order=order, frequency=[3, 45], sampling_rate=100) X_threshold = apply_threshold(filtered_train_x, 1000) test_x_thres = apply_threshold(filtered_test_x, 1000) current_x = scale_maxabs(X_threshold, np.max(np.abs(X_threshold)), 30) current_test_x = scale_maxabs(test_x_thres, np.max(np.abs(test_x_thres)), 30) import os data_dir = '../../subsampled_data'
def plot_class_activation_map_template(model, index, time_series, labels, fs): """ Plots one univariate time series Parameters ---------- model : object Active model with live session index : int time series id time_series : np.array([m, length]) image array labels : np.array([m,]) a 1D array of length m training examples containing class labels fs : int sample frequency """ # Label lookup label_lookup = [ 'Normal Sinus Rhythm', 'Atrial Fibrillation', 'Other Rhythm' ] # Get logits logits = model.sess.run(fetches=[model.graph.logits], feed_dict={ model.graph.x: time_series[[index]], model.graph.y: labels[[index]], model.graph.is_training: False, }) # Get output conv conv = model.sess.run(fetches=[model.graph.net], feed_dict={ model.graph.x: time_series[[index]], model.graph.y: labels[[index]], model.graph.is_training: False, }) # Get class activation map cam = model.sess.run(get_class_map(conv[0], np.squeeze(np.argmax(logits)))) cam = ((cam - cam.min()) / (cam.max() - cam.min())) cam = cam[0, :, 0] cam_time = np.arange(conv[0].shape[1]) / (conv[0].shape[1] / 60) # Get non-zero-pad indices non_zero_index = np.where(time_series[index, :, 0] != 0)[0] # Get non-zero-pad waveform time_series_filt = time_series[index, non_zero_index, 0] time_series_filt_ts = np.arange(time_series_filt.shape[0]) * 1 / fs # Linear interpolation cam_time_intrp = np.arange(time_series[index].shape[0]) * 1 / fs cam_intrp = np.interp(cam_time_intrp, cam_time, cam) # Get non-zero-pad cam cam_filt = cam_intrp[non_zero_index] # Setup figure fig = plt.figure(figsize=(15, 15)) fig.subplots_adjust(wspace=0, hspace=0) ax1 = plt.subplot2grid((3, 5), (0, 0), colspan=5) ax2 = plt.subplot2grid((3, 5), (1, 0), colspan=5) ax3 = plt.subplot2grid((3, 5), (2, 1), colspan=3) prob = model.sess.run(tf.nn.softmax(logits[0])) # Set plot title ax1.set_title('True Label: ' + label_lookup[np.squeeze(np.argmax(labels[index]))] + '\n' + 'Predicted Label: ' + label_lookup[np.squeeze(np.argmax(logits))] + '\n' + 'Normal Sinus Rhythm: ' + str(np.round(prob[0][0], 2)) + ' Atrial Fibrillation: ' + str(np.round(prob[0][1], 2)) + ' Other Rhythm: ' + str(np.round(prob[0][2], 2)), fontsize=20, y=1.03) # Plot image ax1.plot(time_series_filt_ts, time_series_filt, '-k', lw=1.5) # Axes labels ax1.set_ylabel('Normalized Amplitude', fontsize=22) ax1.set_xlim([0, time_series_filt_ts.max()]) ax1.tick_params(labelbottom='off') ax1.yaxis.set_tick_params(labelsize=16) # Plot CAM ax2.plot(time_series_filt_ts, cam_filt, '-k', lw=1.5) # Axes labels ax2.set_xlabel('Time, seconds', fontsize=22) ax2.set_ylabel('Class Activation Map', fontsize=22) ax2.set_xlim([0, time_series_filt_ts.max()]) ax2.set_ylim([cam_filt.min() - 0.05, cam_filt.max() + 0.05]) ax2.xaxis.set_tick_params(labelsize=16) ax2.yaxis.set_tick_params(labelsize=16) # Get ECG object ecg_object = ecg.ecg(time_series_filt, sampling_rate=fs, show=False) # Get waveform templates templates, _ = _get_templates(time_series_filt, ecg_object['rpeaks'], 0.4, 0.6, fs) cam_filt, _, _ = filter_signal(signal=cam_filt, ftype='FIR', band='bandpass', order=int(0.3 * fs), frequency=[3, 100], sampling_rate=fs) # Get cam templates cam_templates, _ = _get_templates(cam_filt, ecg_object['rpeaks'], 0.4, 0.6, fs) templates_ts = np.linspace(-250, 400, templates.shape[0], endpoint=False) ax3.plot(templates_ts, templates, '-', color=[0.7, 0.7, 0.7]) ax3.plot(templates_ts, np.median(templates, axis=1), '-k') ax3.set_ylim([-0.75, 1.5]) ax4 = ax3.twinx() ax3.set_xlim([-250, 400]) ax4.set_xlim([-250, 400]) ax4.plot(templates_ts, cam_templates, '-r', lw=0.25, alpha=0.5) ax4.plot(templates_ts, np.mean(cam_templates, axis=1), '-r') ax4.set_ylim([ np.median(cam_templates, axis=1).min() - 0.02, np.median(cam_templates, axis=1).max() + 0.02 ]) plt.savefig( r'C:\Users\sgoodfellow\Documents\Sebastian\Sick Kids\Publications\Conference\mlforhc\2018\Draft\template.eps' ) plt.show()