### 1 One-way filtering

For given filter transfer function $H(\omega)$, the filtered data $X_1(\omega)$ is $$\begin{cases} X_1(\omega) &= H(\omega) \cdot X(\omega)\\ x_1(t) &= \mathscr{R} \{ \mathscr{F}^{-1}[X_1(\omega)] \} \end{cases} \tag{1}.$$ Eq. $(1)$ is called $one-way$ filtering, and it ensure that the onsets of original and filtered signals are at the same moment.

### 2 Two-way filtering

However, if we want to ensure that the peaks of original and filtered signals are at the same moment, we need to filter again, which is named $two-way$ filtering. $$\begin{cases} X_2(\omega) &= \mathscr{F} \{ Reverse [x_1(n)] \} \cdot H(\omega)\\ x_2(t) &= Reverse \{ \mathscr{R} \{ \mathscr{F}^{-1}[X_2(\omega)] \} \} \end{cases} \tag{2}.$$

Here, we give an example to show these two types of filters.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58  import numpy as np import matplotlib.pyplot as plt from scipy.signal import iirfilter, zpk2sos, sosfilt from scipy import fft def lowpass(d, fs, fc, orders=4, zerophase=False, taper=0.01): n = len(d) fd = fft.fft(d) f = np.arange(n) * fs / n w = 2 * np.pi * f / fs wc = 2 * np.pi * fc / fs k = np.arange(2*orders) if orders % 2 == 0: q = np.tan(wc/2) * np.exp(1j*(k+0.5)/orders*np.pi) else: q = np.tan(wc/2) * np.exp(1j*k/orders*np.pi) p = (1 + q) / (1 - q) z = np.exp(1j*w) h = np.ones_like(w, dtype=complex) for pp in p[abs(p)<1]: h *= ((1-pp) / (1-pp/z)) h *= ( (1+1/z) ** orders / 2**orders ) dd = fft.ifft(fd * h).real if zerophase: dd = fft.ifft(fft.fft(dd[::-1])*h)[::-1].real ni = int(n*taper) k1 = np.arange(ni) k2 = (-k1)[::-1] ta1 = np.cos(np.pi*k1/ni/2) ** N ta2 = np.cos(np.pi*k2/ni/2) ** N dd[:ni] *= ta2 dd[-ni:] *= ta1 return f, h, dd n = 500 dt = 0.05 t = np.arange(n) * dt fs = 1 / dt fc = 1 N = 4 d1 = np.zeros(n) d1[n//2-10: n//2+1] = 1/10*np.arange(n//2-10, n//2+1) + (20-n)/20 d1[n//2: n//2+11] = -1/10*np.arange(n//2, n//2+11) + (20+n)/20 f, h, d3 = lowpass(d1, fs, fc, orders=N, zerophase=True, taper=0.01) _, _, d2 = lowpass(d1, fs, fc, orders=N, zerophase=False, taper=0.01) z, p, k = iirfilter(N, 2*fc/fs, btype='lowpass', ftype='butter', output='zpk') sos = zpk2sos(z, p, k) d4 = sosfilt(sos, d1) d5 = sosfilt(sos, d4[::-1])[::-1] plt.figure(figsize=(10, 5)) plt.plot(t, d1, 'gray', lw=2, label='origin') plt.plot(t, d2, 'g', lw=3, label='this: one-way', alpha=0.5) plt.plot(t, d3, 'r', lw=3, label='this: two-way', alpha=0.5) plt.plot(t, d4, 'k', lw=1.5, label='scipy: one-way') plt.plot(t, d5, 'b', lw=1.5, label='scipy: two-way') plt.legend(fontsize=15) plt.show()