MATLAB和SciPy在'buttord'函数上给出不同的结果

4
我正在尝试使用buttord函数设计模拟Butterworth滤波器(实际上,我正在将一个调用此函数的MATLAB程序移植到Python)。
我的参数是:
通带频率(Fp)= 10 Hz,因此Wp = 2*pi*10 Hz
阻带频率(Fs)= 100 Hz,因此Ws = 2*pi*100 Hz
通带和阻带损失/衰减(Rp,Rs)分别为3 dB和80 dB。
在MATLAB中,我使用以下代码:
Wp = 2 * pi * 10
Ws = 2 * pi * 100
Rp = 3
Rs = 80
[N, Wn] = buttord(Wp, Ws, Rp, Rs, 's')

这段文字给出了 N = 5, Wn = 99.581776302 相关的IT技术内容。

在SciPy中,我尝试做同样的事情:

from numpy import pi
from scipy import signal
Wp = 2 * pi * 10
Ws = 2 * pi * 100
Rp = 3
Rs = 80
(N, Wn) = signal.buttord(Wp, Ws, Rp, Rs, analog=True)

我得到了 N = 5Wn = 62.861698649592753。Wn与MATLAB给出的值不同,且奇怪地接近于Wp。这里有什么问题?

深入研究SciPy的源代码和问题,我发现这个拉取请求可能可以解释事情:原来MATLAB和SciPy有不同的设计目标(MATLAB试图优化匹配阻带频率,而SciPy试图优化匹配通带频率)。

如果有影响,我正在使用MATLAB R2013a、Python 3.4.2和SciPy 0.15.0。


Matlab信号处理工具通常要求频率相关参数以Nyquist为参考进行归一化。也就是说,Wp = Fp / Fn和Ws = Fs / Fn,其中Fn是您的Nyquist频率。 - Juderb
@Juderb 我正在处理模拟滤波器,其中奈奎斯特频率并不重要。根据SciPy的文档,对于模拟滤波器,wp和ws是角频率(例如rad/s). - Renan
1个回答

5
当使用buttord设计Butterworth滤波器时,自由度不足以完全满足所有设计约束条件。因此需要选择哪一端的过渡区域满足约束条件,哪一端是“过度设计”。在scipy 0.14.0中进行的更改将该选择从阻带边缘转换为通带边缘。
下面的脚本生成以下图表。(我将Rp从3改为1.5。-3dB与Wn处的增益重合,这就是为什么你的Wn与Wp相同)使用旧约定和新约定均可满足设计约束条件。使用新约定,响应只是在通带末端碰到约束条件。
import numpy as np
from scipy.signal import buttord, butter, freqs
import matplotlib.pyplot as plt


# Design results for:
Wp = 2*np.pi*10
Ws = 2*np.pi*100
Rp = 1.5      # instead of 3
Rs = 80

n_old = 5
wn_old = 99.581776302787929

n_new, wn_new = buttord(Wp, Ws, Rp, Rs, analog=True)

b_old, a_old = butter(n_old, wn_old, analog=True)
w_old, h_old = freqs(b_old, a_old)

b_new, a_new = butter(n_new, wn_new, analog=True)
w_new, h_new = freqs(b_new, a_new)


db_old = 20*np.log10(np.abs(h_old))
db_new = 20*np.log10(np.abs(h_new))

plt.semilogx(w_old, db_old, 'b--', label='old')
plt.axvline(wn_old, color='b', alpha=0.25)
plt.semilogx(w_new, db_new, 'g', label='new')
plt.axvline(wn_new, color='g', alpha=0.25)

plt.axhline(-3, color='k', ls=':', alpha=0.5, label='-3 dB')

plt.xlim(40, 1000)
plt.ylim(-100, 5)

xbounds = plt.xlim()
ybounds = plt.ylim()
rect = plt.Rectangle((Wp, ybounds[0]), Ws - Wp, ybounds[1] - ybounds[0],
                     facecolor="#000000", edgecolor='none', alpha=0.1, hatch='//')
plt.gca().add_patch(rect)
rect = plt.Rectangle((xbounds[0], -Rp), Wp - xbounds[0], 2*Rp,
                     facecolor="#FF0000", edgecolor='none', alpha=0.25)
plt.gca().add_patch(rect)
rect = plt.Rectangle((Ws, ybounds[0]), xbounds[1] - Ws, -Rs - ybounds[0],
                     facecolor="#FF0000", edgecolor='none', alpha=0.25)
plt.gca().add_patch(rect)

plt.annotate("Pass", (0.5*(xbounds[0] + Wp), Rp+0.5), ha='center')
plt.annotate("Stop", (0.5*(Ws + xbounds[1]), -Rs+0.5), ha='center')
plt.annotate("Don't Care", (0.1*(8*Wp + 2*Ws), -Rs+10), ha='center')

plt.legend(loc='best')
plt.xlabel('Frequency [rad/s]')
plt.ylabel('Gain [dB]')
plt.show()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接