[英]Bandpass butterworth filter frequencies in scipy
我正在按照食谱设计scipy中的带通滤波器。 但是,如果我过多地降低滤波频率,我会在高阶滤波器中使用垃圾。 我究竟做错了什么?
from scipy.signal import butter, lfilter
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = butter(order, [low, high], btype='band')
return b, a
if __name__ == "__main__":
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import freqz
# Sample rate and desired cutoff frequencies (in Hz).
fs = 25
# Plot the frequency response for a few different orders.
plt.figure(1)
plt.clf()
for order in [1, 3, 5, 6, 9]:
b, a = butter_bandpass(0.5, 4, fs, order=order)
w, h = freqz(b, a, worN=2000)#np.logspace(-4, 3, 2000))
plt.semilogx((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Gain')
plt.grid(True)
plt.legend(loc='best')
plt.figure(2)
plt.clf()
for order in [1, 3, 5, 6, 9]:
b, a = butter_bandpass(0.05, 0.4, fs, order=order)
w, h = freqz(b, a, worN=2000)#np.logspace(-4, 3, 2000))
plt.semilogx((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Gain')
plt.grid(True)
plt.legend(loc='best')
plt.show()
更新:在Scipy 0.14上讨论并明显解决了这个问题。 然而,在Scipy更新后,情节看起来仍然很糟糕。 怎么了?
b, a = butter
,无论是在Matlab,SciPy还是Octave中。 传递函数格式具有数值稳定性问题 ,因为一些系数非常大而其他系数非常小。 这就是为什么我们改变了滤波器设计功能以在内部使用zpk格式 。 要想看到它的好处,你需要使用z, p, k = butter(output='zpk')
,然后使用极点和零而不是分子和分母。 显然这个问题是一个已知的错误:
这是数字滤波器中的常见问题。 由于浮点数的精度有限,截止频率远低于奈奎斯特频率的高阶滤波器往往具有不稳定的系数。 最后我检查了(不可否认的是几年前)Matlab在保存精度方面做得比scipy好得多,尽管它仍然会给出足够极端的过滤器问题。
如果你不能使用matlab,有几个选项。 首先是将过滤器分解为级联的二阶段。 基本上,您计算所需的极点和零点,将它们分解为复共轭对,并计算每对的传递函数。
第二种选择是重新采样到更类似于滤波器频率的采样率。 例如,在您的第二个示例中,您的采样率为25,最高截止频率为.4。 您可以使用低通抗混叠滤波器,然后将系数抽取10倍,采样率为2.5。 采样率越低,带通滤波器系数对舍入误差的敏感度越低。 如果这样做,您必须确保抗锯齿滤波器没有相同的问题。
会发生的是, 脚本中创建的带通(BP)过滤器的顺序实际上是图中显示的顺序的两倍 。 回想一下,滤波器的阶数是传递函数分母中多项式的阶数。 Canonic 带通滤波器总是有序的 。
所示的数字是低通(LP)原型的阶数(通常标准化为1rad / s的截止频率),其用于应用LP-to-BP变换,其使滤波器的阶数加倍。 因此,例如,如果我们从订单1的LP开始,我们最终会得到二阶带通:
1 /(S + 1) => LP-2-BP transf。 => ks /(s ^ 2 + a.s + b)
其中k , a和b是常数。 标准带通滤波器的分子是ks ^(N / 2) ,因此滤波器的阶数N必须是偶数。
在SciPy 文档中未提及带通的订单问题(也适用于陷波或带阻滤波器)。 事实上,如果你在plt.show()
之前print(len(a))
分母a的长度(通过使用print(len(a))
plt.show()
,你会看到它有19个系数,对应于18阶多项式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.