def test_scipy_resample(): """ Tests scipy signal's resample function """ # create a freq list with max freq < 16 Hz freq_list = np.random.randint(0, high=15, size=5) # make a test signal with sampling freq = 64 Hz a = [ np.sin(2 * np.pi * f * np.linspace(0, 1, 64, endpoint=False)) for f in freq_list ] tst = np.array(a).sum(axis=0) # interpolate to 128 Hz sampling t_up = signaltools.resample(tst, 128) np.testing.assert_array_almost_equal(t_up[::2], tst) # downsample to 32 Hz t_dn = signaltools.resample(tst, 32) np.testing.assert_array_almost_equal(t_dn, tst[::2]) # downsample to 48 Hz, and compute the sampling analytically for comparison dn_samp_ana = np.array([ np.sin(2 * np.pi * f * np.linspace(0, 1, 48, endpoint=False)) for f in freq_list ]).sum(axis=0) t_dn2 = signaltools.resample(tst, 48) npt.assert_array_almost_equal(t_dn2, dn_samp_ana)
def test_coherence_linear_dependence(): """ Tests that the coherence between two linearly dependent time-series behaves as expected. From William Wei's book, according to eq. 14.5.34, if two time-series are linearly related through: y(t) = alpha*x(t+time_shift) then the coherence between them should be equal to: .. :math: C(\nu) = \frac{1}{1+\frac{fft_{noise}(\nu)}{fft_{x}(\nu) \cdot \alpha^2}} """ t = np.linspace(0,16*np.pi,2**14) x = np.sin(t) + np.sin(2*t) + np.sin(3*t) + 0.1 *np.random.rand(t.shape[-1]) N = x.shape[-1] alpha = 10 m = 3 noise = 0.1 * np.random.randn(t.shape[-1]) y = alpha*(np.roll(x,m)) + noise f_noise = np.fft.fft(noise)[0:N/2] f_x = np.fft.fft(x)[0:N/2] c_t = ( 1/( 1 + ( f_noise/( f_x*(alpha**2)) ) ) ) f,c = tsa.coherence(np.vstack([x,y])) c_t = np.abs(signaltools.resample(c_t,c.shape[-1])) np.testing.assert_array_almost_equal(c[0,1],c_t,2)
def test_scipy_resample(): """ Tests scipy signal's resample function """ # create a freq list with max freq < 16 Hz freq_list = np.random.randint(0,high=15,size=5) # make a test signal with sampling freq = 64 Hz a = [np.sin(2*np.pi*f*np.linspace(0,1,64,endpoint=False)) for f in freq_list] tst = np.array(a).sum(axis=0) # interpolate to 128 Hz sampling t_up = signaltools.resample(tst, 128) np.testing.assert_array_almost_equal(t_up[::2], tst) # downsample to 32 Hz t_dn = signaltools.resample(tst, 32) np.testing.assert_array_almost_equal(t_dn, tst[::2]) # downsample to 48 Hz, and compute the sampling analytically for comparison dn_samp_ana = np.array([np.sin(2*np.pi*f*np.linspace(0,1,48,endpoint=False)) for f in freq_list]).sum(axis=0) t_dn2 = signaltools.resample(tst, 48) npt.assert_array_almost_equal(t_dn2, dn_samp_ana)
def _is_VF(signal): """ This function checks if a signal array meets the criteria to be considered a Ventricular Fibrillation following the method explained in: 'Amann: Detecting Ventricular Fibrillation by Time-Delay Methods. 2007'. In our case, the measured variable is the Pearson's goodness of fit statistic instead of the recurrence rate of the original paper. """ dfreq = 50 window = 8*dfreq #The threshold is the 0.99 quantile of the chi square distribution. thr = 6.64 tau = int(0.5*dfreq) #The signal is filtered and resampled to 50 Hz signal = fft_filt(signal, (0.5, 25), SAMPLING_FREQ) signal = resample(signal, int(len(signal) * dfreq / SAMPLING_FREQ)) n = int(math.ceil(len(signal)/float(window))) isvf = True #The conditions are validated in fragments of *window* size for i in range(n): if i == n-1 and n > 1: frag = signal[-window-tau:-tau] dfrag = signal[-min(len(frag), window):] else: frag = signal[i*window:(i+1)*window] dfrag = signal[i*window+tau:(i+1)*window+tau] frag = frag[:len(dfrag)] if len(frag) > len(dfrag) else frag #Constant arrays cannot be flutters. if len(frag) > 1 and not np.allclose(frag, frag[0]): #The size of the histogram scales with the size of the signal. nbins = int(math.ceil(math.sqrt(len(frag)*40.0**2/window))) H, _, _ = np.histogram2d(frag, dfrag, nbins) H /= len(frag) Ei = 1.0/(nbins*nbins) #The measured variable for the dispersion is the statistic of the #Pearson's goodnes of fit test (agains the uniform distribution). det = np.sum((H-Ei)**2/Ei) isvf = isvf and det < thr else: isvf = False if not isvf: break return isvf
def test_coherence_linear_dependence(): """ Tests that the coherence between two linearly dependent time-series behaves as expected. From William Wei's book, according to eq. 14.5.34, if two time-series are linearly related through: y(t) = alpha*x(t+time_shift) then the coherence between them should be equal to: .. :math: C(\nu) = \frac{1}{1+\frac{fft_{noise}(\nu)}{fft_{x}(\nu) \cdot \alpha^2}} """ t = np.linspace(0, 16 * np.pi, 2**14) x = (np.sin(t) + np.sin(2 * t) + np.sin(3 * t) + 0.1 * np.random.rand(t.shape[-1])) N = x.shape[-1] alpha = 10 m = 3 noise = 0.1 * np.random.randn(t.shape[-1]) y = alpha * np.roll(x, m) + noise f_noise = fftpack.fft(noise)[0:N // 2] f_x = fftpack.fft(x)[0:N // 2] c_t = (1 / (1 + (f_noise / (f_x * (alpha**2))))) method = {"this_method": 'welch', "NFFT": 2048, "Fs": 2 * np.pi} f, c = tsa.coherence(np.vstack([x, y]), csd_method=method) c_t = np.abs(signaltools.resample(c_t, c.shape[-1])) npt.assert_array_almost_equal(c[0, 1], c_t, 2)
# define the sfa node sfaNode = mdp.nodes.SFANode(output_dim=sfaNum) # define the ica node icaNode = mdp.nodes.FastICANode() icaNode.set_output_dim(icaNum) #define the flow flow = mdp.Flow(resNode + sfaNode + icaNode) #train the flow flow.train(sensorData.T) # icaOutput = flow.execute(sensorData.T) #resample the ica layer output back to 50 times the length icaOutputLong = resample(icaOutput, location.shape[0]) # number of components to plot plotsNum = 20 plt.subplot(plotsNum + 1, 1, 1) # first subplot of the numbered location of the robot plt.plot(location) # plot the independent components for i in range(plotsNum): plt.subplot(plotsNum + 1, 1, i + 2) plt.plot(icaOutputLong[:, i]) plt.show()
resNode.initialize() # define the sfa node sfaNode = mdp.nodes.SFANode(output_dim=sfaNum) # define the ica node icaNode = mdp.nodes.FastICANode() icaNode.set_output_dim(icaNum) #define the flow flow = mdp.Flow(resNode + sfaNode + icaNode) #train the flow flow.train(sensorData.T) # icaOutput = flow.execute(sensorData.T) #resample the ica layer output back to 50 times the length icaOutputLong = resample(icaOutput, location.shape[0]) # number of components to plot plotsNum = 20 plt.subplot(plotsNum + 1, 1, 1) # first subplot of the numbered location of the robot plt.plot(location) # plot the independent components for i in range(plotsNum): plt.subplot(plotsNum + 1, 1, i + 2) plt.plot(icaOutputLong[:, i]) plt.show()
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