【问题标题】:Why do I get an error using butterworth filter for low frequency filtering?为什么使用巴特沃斯滤波器进行低频滤波会出错?
【发布时间】:2019-09-18 08:12:51
【问题描述】:

我正在尝试分析每个 1/3 倍频程频带频率的幅度,因此我使用了许多带通巴特沃斯滤波器。但是,当它是 3 阶时,它们仅适用于 50 Hz。我想使用 6 阶,但由于某种原因,我在 1 kHz 以下没有得到任何结果。

[fs, x_raw] = wavfile.read('ruido_rosa.wav')
x_max=np.amax(np.abs(x_raw))
x=x_raw/x_max
L=len(x)

# Creates the vector with all frequencies

f_center=np.array([50.12, 63.10, 79.43, 100, 125.89, 158.49, 199.53, 251.19, 316.23, 398.11, 501.19, 630.96, 794.33, 1000, 1258.9, 1584.9, 1995.3, 2511.9, 3162.3, 3981.1, 5011.9, 6309.6, 7943.3, 10000, 12589.3, 15848.9])
f_low=np.array([44.7, 56.2, 70.8, 89.1, 112, 141, 178, 224, 282, 355, 447, 562, 708, 891, 1120, 1410, 1780, 2240, 2820, 3550, 4470, 5620, 7080, 8910, 11200, 14100])
f_high=np.array([56.2, 70.8, 89.1, 112, 141, 178, 224, 282, 355, 447, 562, 708, 891, 1120, 1410, 1780, 2240, 2820, 3550, 4470, 5620, 7080, 8910, 11200, 14100, 17800])

L2=len(f_center)

x_filtered=np.zeros((L,L2))
for n in range (L2):    
    order=6
    nyq = 0.5*fs
    low = f_low[n]/nyq
    high = f_high[n]/nyq
    b,a = butter(order,[low,high],btype='band')
    x_filtered[:,n] = lfilter(b,a,x)

x_filtered_squared=np.power(x_filtered,2)

x_filtered_sum=np.sqrt(np.sum(x_filtered_squared,axis=0)/L)

pyplot.figure(2)
pyplot.semilogx(f_center,20*np.log10(np.abs(x_filtered_sum)))
pyplot.xlim((50,16000))
pyplot.xlabel('Frequência (Hz)')
pyplot.ylabel('Amplitude (dB)') 

如何使用 6 阶巴特沃斯滤波器正确过滤 50 Hz 带通?

【问题讨论】:

    标签: python filter signal-processing butterworth


    【解决方案1】:

    IIR 滤波器的多项式“ba”表示很容易受到滤波器系数量化误差的影响,这些误差可以将极点移出单位圆并相应地导致滤波器不稳定。这对于带宽较窄的滤波器尤其成问题。

    为了更好地理解发生了什么,我们可以将使用scipy.butter(..., output='zpk') 获得的预期极点位置与通过计算反馈多项式的根(a 系数)获得的有效极点位置进行比较。这可以通过以下代码完成:

    fs = 44100
    order = 6
    bands = np.array([np.array([2240, 2820]), 
                      np.array([1650,1.2589*1650]), 
                      np.array([1300,1.2589*1300]), 
                      np.array([1120,1410])])
    plt.figure()
    index = 1
    for band in bands:
      low = band[0]/(fs/2)
      high = band[1]/(fs/2)
      b,a=butter(order,[low,high],btype='band',output='ba')
      z,p,k=butter(order,[low,high],btype='band',output='zpk')
      r = np.roots(a)
    
      t = np.linspace(-np.pi,np.pi,200)
      plt.subplot(2,2,index)
      index += 1
      plt.title("low={:.0f}, high={:.0f} (BW={:.0f}Hz)".format(band[0], band[1], band[1]-band[0]))
      plt.plot(np.cos(t),np.sin(t),'k:')
      plt.plot(np.real(p),np.imag(p),'bx',label='poles')
      plt.plot(np.real(r),np.imag(r),'rs',fillstyle='none',label='roots')
    
      # Focus on the poles/roots at positive frequencies
      x0 = np.cos(0.5*np.pi*(low+high))
      y0 = np.sin(0.5*np.pi*(low+high))
      delta = 0.05
      plt.ylim(y0-delta,y0+delta)
      plt.xlim(x0-delta,x0+delta)
      plt.grid(True)
      plt.legend()
    

    这表明这两个集合被配置为具有较大带宽的滤波器,但是随着带宽的减小,位置开始不同,直到误差大到足以将根推到单位圆之外:

    为了避免这个问题,可以使用级联的二阶部分过滤器实现:

    sos = butter(order,[low,high],btype='band',output='sos')
    x_filtered[:,n] = sosfilt(sos,x)
    

    这应该将输出扩展到较低的频率,如下图所示:

    【讨论】:

      猜你喜欢
      • 2019-10-09
      • 1970-01-01
      • 2012-05-03
      • 2020-08-24
      • 1970-01-01
      • 2017-04-26
      • 2016-02-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多