在SciPy中创build低通滤波器 – 理解方法和单位
我想用python过滤嘈杂的心率信号。 因为心率不应该是每分钟220次左右,所以我想过滤220bpm以上的所有噪音。 我把220 /分钟转换成3.66666666赫兹,然后把赫兹转换成rad / s,得到23.0383461 rad / sec。
取数据的芯片的采样频率是30Hz,所以我把它转换为rad / s得到188.495559rad / s。
在网上查了一些东西之后,我发现了一些带通滤波器,我想把它们变成低通滤波器。 这里是带通码的链接 ,所以我把它转换成这样:
from scipy.signal import butter, lfilter from scipy.signal import freqs def butter_lowpass(cutOff, fs, order=5): nyq = 0.5 * fs normalCutoff = cutOff / nyq b, a = butter(order, normalCutoff, btype='low', analog = True) return b, a def butter_lowpass_filter(data, cutOff, fs, order=4): b, a = butter_lowpass(cutOff, fs, order=order) y = lfilter(b, a, data) return y cutOff = 23.1 #cutoff frequency in rad/s fs = 188.495559 #sampling frequency in rad/s order = 20 #order of filter #print sticker_data.ps1_dxdt2 y = butter_lowpass_filter(data, cutOff, fs, order) plt.plot(y)
我很困惑,因为我很确定黄油function以rad / s截取和采样频率,但我似乎正在得到一个奇怪的输出。 它实际上是在赫兹?
其次是这两行的目的是什么:
nyq = 0.5 * fs normalCutoff = cutOff / nyq
我知道它正常化的一些东西,但我认为nyquist是抽样频率的2倍,而不是一半。 为什么你用nyquist作为标准化程序?
能解释一下如何用这些函数创buildfilter吗?
我绘制了使用filter
w, h = signal.freqs(b, a) plt.plot(w, 20 * np.log10(abs(h))) plt.xscale('log') plt.title('Butterworth filter frequency response') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(100, color='green') # cutoff frequency plt.show()
并得到这明显不能在23弧度/秒切断
几点意见:
- 奈奎斯特频率是采样率的一半。
- 您正在处理定期采样的数据,因此您需要数字滤波器,而不是模拟滤波器。 这意味着你不应该在调用
butter
使用analog=True
,而应该使用scipy.signal.freqz
(而不是freqs
)来产生频率响应。 - 这些短暂的实用function的目标之一就是允许您保留所有以Hz为单位的频率。 你不应该转换为弧度/秒。 只要你用一致的单位来expression你的频率,效用函数的缩放就会为你规范化。
这里是我的脚本的修改版本,后面是它生成的情节。
import numpy as np from scipy.signal import butter, lfilter, freqz import matplotlib.pyplot as plt def butter_lowpass(cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = butter(order, normal_cutoff, btype='low', analog=False) return b, a def butter_lowpass_filter(data, cutoff, fs, order=5): b, a = butter_lowpass(cutoff, fs, order=order) y = lfilter(b, a, data) return y # Filter requirements. order = 6 fs = 30.0 # sample rate, Hz cutoff = 3.667 # desired cutoff frequency of the filter, Hz # Get the filter coefficients so we can check its frequency response. b, a = butter_lowpass(cutoff, fs, order) # Plot the frequency response. w, h = freqz(b, a, worN=8000) plt.subplot(2, 1, 1) plt.plot(0.5*fs*w/np.pi, np.abs(h), 'b') plt.plot(cutoff, 0.5*np.sqrt(2), 'ko') plt.axvline(cutoff, color='k') plt.xlim(0, 0.5*fs) plt.title("Lowpass Filter Frequency Response") plt.xlabel('Frequency [Hz]') plt.grid() # Demonstrate the use of the filter. # First make some data to be filtered. T = 5.0 # seconds n = int(T * fs) # total number of samples t = np.linspace(0, T, n, endpoint=False) # "Noisy" data. We want to recover the 1.2 Hz signal from this. data = np.sin(1.2*2*np.pi*t) + 1.5*np.cos(9*2*np.pi*t) + 0.5*np.sin(12.0*2*np.pi*t) # Filter the data, and plot both the original and filtered signals. y = butter_lowpass_filter(data, cutoff, fs, order) plt.subplot(2, 1, 2) plt.plot(t, data, 'b-', label='data') plt.plot(t, y, 'g-', linewidth=2, label='filtered data') plt.xlabel('Time [sec]') plt.grid() plt.legend() plt.subplots_adjust(hspace=0.35) plt.show()