繁体   English   中英

带通的butterworth过滤器频率scipy

[英]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()

fs = 25,低= 0.5,高= 4fs = 25,低= 0.05,高= 0.4

更新:在Scipy 0.14上讨论并明显解决了这个问题。 然而,在Scipy更新后,情节看起来仍然很糟糕。 怎么了?

在Scipy 0.14之后,更糟糕

  1. 不要在高级滤波器中使用b, a = butter ,无论是在Matlab,SciPy还是Octave中。 传递函数格式具有数值稳定性问题 ,因为一些系数非常大而其他系数非常小。 这就是为什么我们改变了滤波器设计功能以在内部使用zpk格式 要想看到它的好处,你需要使用z, p, k = butter(output='zpk') ,然后使用极点和零而不是分子和分母。
  2. 不要在一个阶段中执行高阶数字滤波器。 无论您使用哪种软件或硬件,这都是一个坏主意。 通常,最好将它们分解为二阶部分 在Matlab中,您可以使用zp2sos自动生成这些内容。 这还没有在SciPy中实现 ,虽然我在这里有GPL代码: https ://gist.github.com/endolith/4525003(GPL许可证与scipy不兼容,因此需要从头开始重写。)

显然这个问题是一个已知的错误:

Github上

这是数字滤波器中的常见问题。 由于浮点数的精度有限,截止频率远低于奈奎斯特频率的高阶滤波器往往具有不稳定的系数。 最后我检查了(不可否认的是几年前)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)

其中kab是常数。 标准带通滤波器的分子是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM