问题描述
我有几个关于在 python/scipy.signal 中制作低通滤波器的问题。希望得到任何答案。
- 我正在尝试了解 special format 的工作原理。它是否采用滤波器系数并将它们乘以数据值,以便对于
data[500]
,它会做
for b in range(0,len(coeff)):
filtered = filtered + data[500-b]*coeff[b]
做那个和它正在做的有什么区别?
- 我也不明白点击次数在开始过滤时有何影响。对于不同的点击次数,我看到它从数据的不同值开始。我认为它只有在它具有必要的系数后才会开始。在我的示例中,我有来自
scipy.signal.firwin
的 683 个系数,但过滤器从 300-400 开始,正如您在图像scipy.signal.lfilter
中看到的(过滤器为蓝色;正弦波为红色;x 从 0 开始-1000)
from scipy import signal
a = signal.firwin(683,cutoff = 1/30,window = "hamming")
t = signal.lfilter(a,1,sig)
-
如果 fs=1,cutoff = fs/30,我得到了一个带有 firwin 的低通滤波器,它被延迟了很多,如上图所示。我可以做些什么来改善延迟?
-
改变采样率会如何影响过滤器?
import math
(2/3) * math.log10(1/(10*ripple*attenuation)) * fs/transition_width
((-10*math.log10(ripple*attenuation) - 13)/(14.6)) * fs/transition_width
哪个是更好的近似值?
任何澄清将不胜感激。
解决方法
- 我正在尝试了解 scipy.signal.lfilter 的工作原理。
scipy.signal.lfilter(b,a,x)
实现了 "infinite impulse response" (IIR),aka "recursive",filtering,其中 b
和 a
代表 IIR 滤波器,x
是输入信号。
b
arg 是一个 M+1
分子(前馈)滤波器系数数组,而 a
是一个 N+1
分母(反馈)滤波器系数数组。按照惯例,a[0]
= 1(否则可以将过滤器归一化以使其如此),因此我假设 a[0]
= 1。第 n 个输出样本 y[n]
计算为
y[n] = b[0] * x[n] + b[1] * x[n-1] + ... + b[M] * x[n-M]
- a[1] * y[n-1] - ... - a[N] * y[n-N].
IIR 过滤的特殊之处在于 y[n]
的这个公式取决于之前的 N
输出值 y[n-1]
,...,y[n-N]
;该公式是递归的。因此,为了开始这个过程,通常通过假设 y[n]
和 x[n]
在 n scipy.signal.lfilter 在默认情况下所做的。>
您也可以使用 scipy.signal.lfilter
通过设置 a = [1]
来应用“有限脉冲响应”(FIR),正如您在问题 2 中所做的那样。然后过滤公式中没有递归反馈项,所以过滤就变成了 b
和 x
的简单卷积。
- 我也不明白点击次数在开始过滤时有何影响。对于不同的点击次数,我看到它从数据的不同值开始。我认为它只有在它具有必要的系数后才会开始。在我的示例中,我有 683 个来自 scipy.signal.firwin 的系数,但滤波器从 300-400 开始,正如您在图像中看到的 Firwin 低通滤波器(滤波器为蓝色;正弦波为红色;x 从 0-1000 )
scipy.signal.lfilter
立即开始过滤。正如我上面提到的,它这样做(默认情况下)假设 y[n]
和 x[n]
对于 n y[0] 计算为>
y[0] = b[0] * x[0].
但是,根据您的过滤器,b[0]
可能接近于零,这可以解释为什么一开始似乎什么也没有发生。
检查滤波器行为的一个好方法是计算其“脉冲响应”,即查看通过将单位脉冲 [1,...]
作为输入传递而产生的输出:
plot(scipy.signal.lfilter(b,[1] + [0] * 800))
这是b = firwin(683,cutoff = 1/30,window = "hamming")
、a = [1]
我得到的结果:
从该图中我们可以看到几件事:脉冲响应起初非常小,然后上升并振荡,在样本索引 341 处达到峰值,然后再次对称衰减为零。滤波器的延迟为 341 = 683 // 2,即您在设计滤波器时指定给 firwin
的抽头数的一半。
- 我可以做些什么来改善延迟?
尝试将抽头数量 683 减少到更小。或者,如果您不需要过滤为 causal,请尝试 scipy.ndimage.convolve1d,它会移动计算以便过滤器居中:
scipy.ndimage.convolve1d(sig,firwin_filter,mode='constant')
- 改变采样率会如何影响过滤器?
对于大多数滤波器设计,如果截止频率小于采样率的 1/4,那么精确的采样率几乎没有影响。或者换句话说,除非截止频率适度接近奈奎斯特频率,否则这通常不是问题。
- 我在网上找到了两种估算点击次数的方法。
我不熟悉这些公式。请注意,实现目标特性所需的抽头数量取决于特定的设计方法,因此请注意这些公式假设的上下文。
在 scipy.signal
内,我建议将 kaiserord
与 firwin
或 firwin2
一起用于目标波纹量和过渡宽度。 Here is their example,其中 65 是以 dB 为单位的阻带纹波,width
是以 Hz 为单位的过渡宽度:
使用 kaiserord
确定过滤器的长度和 Kaiser 窗口的参数。
>>> numtaps,beta = kaiserord(65,width/(0.5*fs))
>>> numtaps
167
>>> beta
6.20426
使用 firwin
创建 FIR 滤波器。
>>> taps = firwin(numtaps,cutoff,window=('kaiser',beta),scale=False,nyq=0.5*fs)
编辑:对于其他设计,kaiserord
可能会进入正确的范围,但不要依赖于实现波纹或过渡宽度的目标量。所以一个可能的通用策略可能是一个像这样的迭代过程:
- 使用
kaiserord
获得点按次数的初始估计值。 - 用那么多的水龙头设计过滤器。
- 使用 scipy.signal.freqz 获取滤波器的频率响应。
- 评估响应幅度与所需响应的接近程度。即,在通带上,从 1 计算最大绝对差,在阻带上,从 0 计算最大绝对差。
- 如果响应不够接近,请增加敲击次数并返回到第 2 步。否则,看看是否可以通过减少敲击次数来摆脱困境。