Python中的IIR响应
我有一个新问题与Python直接相关-内置在Python中我有一个具有给定特性的二阶IIR带通滤波器[以下代码是故意惯用的]:Python中的IIR响应,python,filter,response,Python,Filter,Response,我有一个新问题与Python直接相关-内置在Python中我有一个具有给定特性的二阶IIR带通滤波器[以下代码是故意惯用的]: fs = 40e6 # 40 MHz f sample frequency fc = 1e6/fs # 1 MHz center cutoff BW = 20e3/fs # 20 kHz bandwidth fl = (fc - BW/2)/fs # 0.99 MHz f lower cutoff fh = (fc +
fs = 40e6 # 40 MHz f sample frequency
fc = 1e6/fs # 1 MHz center cutoff
BW = 20e3/fs # 20 kHz bandwidth
fl = (fc - BW/2)/fs # 0.99 MHz f lower cutoff
fh = (fc + BW/2)/fs # 1.01 MHz f higher cutoff
其中给出了系数:
R = 1 - (3*BW)
K = (1 - 2*R*np.cos(2*np.pi*fc) + (R*R)) / (2 - 2*np.cos(2*np.pi*fc))
a0 = 1 - K # a0 = 0.00140
a1 = 2*(K-R)*np.cos(2*np.pi*fc) # a1 = 0.00018
a2 = (R*R) - K # a2 = -0.00158
b1 = 2*R*np.cos(2*np.pi*fc) # b1 = 1.97241
b2 = -(R*R) # b2 = -0.99700
正如我所建议的,我已经使用了scipy.signal.freqz,但遗憾的是没有得到我想要的响应——也就是说,我相信过滤器可以按预期工作(代码如下)。以下是freqz的结果:
我的问题是:如何生成更像预期响应的图形?
代码:
用线性x标度你看不到任何漂亮的东西。我不知道numpy,但我熟悉matlab,有一些函数可以在日志中进行绘图。尝试将x-log比例用于:
import matplotlib.pyplot as pyplot
fig = pyplot.figure()
ax = fig.add_subplot(2,1,1)
line, = ax.plot(w/np.max(w), h_dB, color='blue', lw=2)
ax.set_xscale('log')
show()
顺便说一句,我没有测试它,我没有安装python:(
编辑:
我尝试在matlab中为一个IIR滤波器阶数为4和一个IIR滤波器阶数为20的butterworth滤波器建模
%!/usr/local/bin/matlab
%% Inputs
fs = 40e6;
fc = 1e6;
BW = 20e3;
fl = (fc - BW/2);
fh = (fc + BW/2);
%% Build bandpass filter IIR Butterworth order 4
N = 4; % Filter Order
h = fdesign.bandpass('N,F3dB1,F3dB2', N, fl, fh, fs);
Hd1 = design(h, 'butter');
%% Build bandpass filter IIR Butterworth order 50
N = 20; % Filter Order
h = fdesign.bandpass('N,F3dB1,F3dB2', N, fl, fh, fs);
Hd2 = design(h, 'butter');
%% Compare
fvtool(Hd1,Hd2);
这里是第一个滤波器的系数A和B:
FilterStructure: 'Direct-Form II Transposed'
A: [2.46193004641106e-06 0 -4.92386009282212e-06 0 2.46193004641106e-06]
B: [1 -3.94637005453608 5.88902106889851 -3.93761314372475 0.995566972065978]
如果我有时间,我会尝试对numpy做同样的事情。问题是
signal.freqz
返回半圆上的点…所以你不能扩展到更大的x
,除非你通过signal.freqz
来实现。我试着戳了戳它,我发现你可以使用passwhole=True
到signal.freqz
,你会得到上面的结果,但是镜像到负数x
。所以不是这样。但是,还有一个关键字参数,允许你传递你想要的signal.freqz
点数组所以我试着使用np.arange(-5,5,0.1)
…它看起来一点也不像你期望的右边的曲线图——它看起来像是原始曲线图的一束反射。所以我想…也许右边的曲线图和左边的曲线图有不同的轴?具体来说,是一个角频率,而另一个只是普通的旧频率
进一步拨动后,signal.freqz
返回w,h
,其中w
是以弧度/采样为单位的标准化角频率。因此,您不需要通过np.max(w)进行标准化
在您的代码中进行绘图。但是,这仍然不能解决问题。右侧的绘图似乎以fc
为单位,并且fc
以MHz为单位(例如1/样本)
因此,要使左边的图与右边的图匹配,我想这意味着你需要“非标准化”你的x
轴,然后你需要转换成MHz的角频率单位
或者,更可能的情况是,使用不同于
信号的函数。freqz
我不认为问题在于您绘制响应的方式-这取决于您选择的过滤器。您正在尝试仅使用低阶IIR过滤器创建非常窄的过滤器响应。我认为您要么需要高阶过滤器,要么放松约束ts
例如,下面使用了一个实现为IIR的butterworth过滤器,它给出的响应形状与您正在寻找的形状更为相似。显然,要获得预期的过滤器特性,还需要做更多的工作
b, a = signal.butter(4, [1.0/4-1.0/2e2,1.0/4+1.0/2e2], 'bandpass', analog=False)
w, h = signal.freqs(b, a)
import matplotlib.pyplot as plt
fig = plt.figure()
plt.title('Digital filter frequency response')
ax1 = fig.add_subplot(111)
plt.semilogy(w, np.abs(h), 'b')
plt.ylabel('Amplitude (dB)', color='b')
plt.xlabel('Frequency (rad/sample)')
ax2 = ax1.twinx()
angles = np.unwrap(np.angle(h))
plt.plot(w, angles, 'g')
plt.ylabel('Angle (radians)', color='g')
plt.grid()
plt.axis('tight')
plt.show()
其中:
我想知道代码中的
Fc
和Ft
是什么?它们以前没有定义。我应该很清楚:Fc是由采样频率(fs)归一化的中心频率。Ft与Fc(打字错误)相同--根据您的评论,方程式取自我将Fc
改为Fc
和Ft
改为Fc
。感谢您澄清了这一点,Jan Philip并没有解决这个问题。更简单的方法是执行plt.semilogx()
(或者,对于其他人来说,plt.semilogy())
,plt.loglog
)。您可以在预先存在的绘图上执行它们,也可以将它们用作plt.plot
。Pro提示:在交互模式下,按L
或K
切换对数轴(仅当0不在绘图上时有效,但您可以移动它).不。这对您完全没有任何作用。将比例更改为对数比例无法显示更多的点。基本上,您得到的绘图与线性比例绘图相同。您需要在不同的范围内绘图。
b, a = signal.butter(4, [1.0/4-1.0/2e2,1.0/4+1.0/2e2], 'bandpass', analog=False)
w, h = signal.freqs(b, a)
import matplotlib.pyplot as plt
fig = plt.figure()
plt.title('Digital filter frequency response')
ax1 = fig.add_subplot(111)
plt.semilogy(w, np.abs(h), 'b')
plt.ylabel('Amplitude (dB)', color='b')
plt.xlabel('Frequency (rad/sample)')
ax2 = ax1.twinx()
angles = np.unwrap(np.angle(h))
plt.plot(w, angles, 'g')
plt.ylabel('Angle (radians)', color='g')
plt.grid()
plt.axis('tight')
plt.show()