MATLAB 和 SciPy 对 'buttord' 函数给出了不同的结果

标签 matlab scipy signal-processing

我正在尝试使用 buttord 函数设计一个模拟巴特沃斯滤波器(实际上,我正在移植一个从 MATLAB 调用此函数的程序到 Python)。

我的参数是:

通带频率 (Fp) = 10 Hz,给出 Wp = 2*pi*10 Hz

阻带频率 (Fs) = 100 Hz,给出 Ws = 2*pi*100 Hz

通带和阻带损耗/衰减(Rp、Rs)分别为 3 和 80 dB。

在 MATLAB 中我使用这段代码:

Wp = 2 * pi * 10
Ws = 2 * pi * 100
Rp = 3
Rs = 80
[N, Wn] = buttord(Wp, Ws, Rp, Rs, 's')

这给了我 N = 5Wn = 99.581776302

在 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 的来源和问题,我发现了 this pull request这可能解释了一些事情:原来 MATLAB 和 SciPy 有不同的设计目标(MATLAB 试图优化匹配阻带频率,而 SciPy 试图优化匹配通带频率)。

如果重要的话,我正在使用 MATLAB R2013a、Python 3.4.2 和 SciPy 0.15.0。

最佳答案

(我还在 scipy 邮件列表上发布了以下内容。)

当您使用 buttord 设计巴特沃斯滤波器时,没有足够的 完全满足所有设计约束的自由度。所以那里 是选择过渡区域的哪一端达到约束 哪一端是“过度设计”的。 scipy 0.14.0 中所做的更改将该选择从阻带边缘切换到通带边缘。

一张图就清楚了。下面的脚本生成以下图。 (我将 Rp 从 3 更改为 1.5。-3 dB 与 Wn 处的增益一致,这就是您的 Wn 与 Wp 相同的原因。)使用旧约定或新约定生成的滤波器都满足设计约束。使用新约定,响应只会在通带末端碰到约束。

frequency response

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()

关于MATLAB 和 SciPy 对 'buttord' 函数给出了不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28056404/

相关文章:

matlab - 在Matlab中绘制星星形状

python - 如何用scipy优化n个点的位置?

python - 稳态概率(马尔可夫链)Python 实现

python - NumPy/SciPy : Move mask over Image and check for equality

linux - 从任意音频文件中提取语音部分的好方法是什么?

c - 时域重叠相加如何实现时间拉伸(stretch)?

matlab - 使用 matlab 求解 ode 系统

swift - Swift 中的 DFT 结果与 MATLAB 中的不同

matlab - svmtrain 和 fitcsvm 的区别

wifi - 如何从无线路由器捕获原始信号?