简体   繁体   English

带通的butterworth过滤器频率scipy

[英]Bandpass butterworth filter frequencies in scipy

I'm designing a bandpass filter in scipy following the cookbook . 我正在按照食谱设计scipy中的带通滤波器。 However, if I decrecrease the filtering frequencies too much I end up with garbage at high order filters. 但是,如果我过多地降低滤波频率,我会在高阶滤波器中使用垃圾。 What am I doing wrong? 我究竟做错了什么?

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

Update: the issue was discussed and apparently solved on Scipy 0.14. 更新:在Scipy 0.14上讨论并明显解决了这个问题。 However, the plot still looks really bad after Scipy update. 然而,在Scipy更新后,情节看起来仍然很糟糕。 What's wrong? 怎么了?

在Scipy 0.14之后,更糟糕

  1. Don't use b, a = butter for high-order filters, whether in Matlab or SciPy or Octave. 不要在高级滤波器中使用b, a = butter ,无论是在Matlab,SciPy还是Octave中。 Transfer function format has numerical stability problems , because some of the coefficients are very large while others are very small. 传递函数格式具有数值稳定性问题 ,因为一些系数非常大而其他系数非常小。 This is why we changed the filter design functions to use zpk format internally . 这就是为什么我们改变了滤波器设计功能以在内部使用zpk格式 To see the benefits of this, you need to use z, p, k = butter(output='zpk') and then work with poles and zeros instead of numerator and denominator. 要想看到它的好处,你需要使用z, p, k = butter(output='zpk') ,然后使用极点和零而不是分子和分母。
  2. Don't do high-order digital filters in a single stage. 不要在一个阶段中执行高阶数字滤波器。 This is a bad idea no matter what software or hardware you're implementing them on. 无论您使用哪种软件或硬件,这都是一个坏主意。 Typically it's best to break them up into second-order sections . 通常,最好将它们分解为二阶部分 In Matlab, you can use zp2sos to generate these automatically. 在Matlab中,您可以使用zp2sos自动生成这些内容。 This has not been implemented in SciPy yet , though I have GPL code to do it here: https://gist.github.com/endolith/4525003 (GPL license is incompatible with scipy, so it needs to be rewritten from scratch.) 这还没有在SciPy中实现 ,虽然我在这里有GPL代码: https ://gist.github.com/endolith/4525003(GPL许可证与scipy不兼容,因此需要从头开始重写。)

Apparently the issue is a known bug: 显然这个问题是一个已知的错误:

Github Github上

This is a common problem in digital filters. 这是数字滤波器中的常见问题。 High order filters with cutoff frequencies far below the nyquist frequency tend to have unstable coefficients due to the limited precision of floating point numbers. 由于浮点数的精度有限,截止频率远低于奈奎斯特频率的高阶滤波器往往具有不稳定的系数。 Last I checked (admittedly a couple of years ago) Matlab did a much better job of conserving precision than scipy, although it will still give problems with sufficiently extreme filters. 最后我检查了(不可否认的是几年前)Matlab在保存精度方面做得比scipy好得多,尽管它仍然会给出足够极端的过滤器问题。

There are a couple of options if you can't use matlab. 如果你不能使用matlab,有几个选项。 The first is to break your filter up into cascaded second order sections. 首先是将过滤器分解为级联的二阶段。 Basically you compute your desired poles and zeros, break them up into complex conjugate pairs, and compute the transfer function for each pair. 基本上,您计算所需的极点和零点,将它们分解为复共轭对,并计算每对的传递函数。

The second option is to resample to a sample rate more similar to the filter frequency. 第二种选择是重新采样到更类似于滤波器频率的采样率。 For instance, in your second example your sample rate is 25 and your highest cutoff frequency is .4. 例如,在您的第二个示例中,您的采样率为25,最高截止频率为.4。 You can use a low-pass anti-aliasing filter and then decimate by a factor of 10 to a sample rate of 2.5. 您可以使用低通抗混叠滤波器,然后将系数抽取10倍,采样率为2.5。 With the lower sampling rate, your bandpass filter coefficients will be less sensitive to rounding errors. 采样率越低,带通滤波器系数对舍入误差的敏感度越低。 If you do this, you have to make sure the anti-aliasing filter doesn't have the same problem. 如果这样做,您必须确保抗锯齿滤波器没有相同的问题。

What happens is that the orders of the bandpass (BP) filters created in the script are in fact the double of those shown in the plot . 会发生的是, 脚本中创建的带通(BP)过滤器的顺序实际上是图中显示的顺序的两倍 Recall that the order of the filter is the order of the polynomial in the denominator of the transfer function. 回想一下,滤波器的阶数是传递函数分母中多项式的阶数。 Canonic bandpass filters are always of even order . Canonic 带通滤波器总是有序的

Those numbers shown are the orders of the low-pass (LP) prototype (usually normalized to a cutoff frequency of 1 rad/s) which is used to apply the LP-to-BP transformation which doubles the order of the filter. 所示的数字是低通(LP)原型的阶数(通常标准化为1rad / s的截止频率),其用于应用LP-to-BP变换,其使滤波器的阶数加倍。 So, for instance, if we start with an LP of order 1, we end up with a second order bandpass: 因此,例如,如果我们从订单1的LP开始,我们最终会得到二阶带通:

1/(S+1) => LP-2-BP transf. 1 /(S + 1) => LP-2-BP transf。 => ks/(s^2+a.s+b) => ks /(s ^ 2 + a.s + b)

Where k , a and b are constants. 其中kab是常数。 The numerator of a standard bandpass filter is ks^ (N/2) and so the order N of the filter has to be even. 标准带通滤波器的分子是ks ^(N / 2) ,因此滤波器的阶数N必须是偶数。

This order issue for bandpass (which also happens to notches or band-reject filters) is not mentioned in SciPy documentation . 在SciPy 文档中未提及带通的订单问题(也适用于陷波或带阻滤波器)。 In fact, if you print the length of denominator a (by using print(len(a)) ) before plt.show() , you will see it has 19 coefficients, what corresponds to a polynomial of 18th order. 事实上,如果你在plt.show()之前print(len(a))分母a的长度(通过使用print(len(a)) plt.show() ,你会看到它有19个系数,对应于18阶多项式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Scipy的巴特沃斯滤波器 - Butterworth Filter Using Scipy 使用 scipy.signal.lfilter 时,实现巴特沃斯带通滤波器遇到:“ValueError: object of too small depth for desired array”错误 - Implementing Butterworth bandpass filter running into: "ValueError: object of too small depth for desired array" error when using scipy.signal.lfilter 低频带通滤波 - Bandpass filtering at low frequencies 在 python 中应用巴特沃斯带通滤波器后,如何消除信号开头的大尖峰? - how do I remove large spike at the beginning of signal after applying Butterworth Bandpass filter in python? 使用BeagleBone Black上的numpy(不是scipy!)编程一个butterworth过滤器 - Program a butterworth filter using numpy (not scipy!) on a BeagleBone Black signal.butter 带通误差:数字滤波器临界频率必须为 0 &lt; Wn &lt; 1 - signal.butter bandpass error: Digital filter critical frequencies must be 0 < Wn < 1 如何从python中的带通滤波器频率扫描数据中找到中断频率/3dB点? - How can I find the break frequencies/3dB points from a bandpass filter frequency sweep data in python? 如何使用Scipy.signal.butter实现带通Butterworth滤波器 - How to implement band-pass Butterworth filter with Scipy.signal.butter 巴特沃思滤波器-输出x(-1)? - butterworth filter - output x (-1)? 设置巴特沃斯滤波器的参数 - Setting Parameters for a Butterworth Filter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM