如果可能,请设计您的过滤器,然后执行必须执行的操作(缓冲等)以正确实现该过滤器。在实现有限脉冲响应 (FIR) 滤波器时,例如:(伪代码:)
out[t] = 0.5*in[t] - 0.6*in[t-1] + 0.7*in[t-2] - 0.8*in[t-3]
其中t
是整数时间索引,您可以这样做,以便将一些过去的in
值存储在缓冲区中,如下所示,步进t
:
t buf[0] buf[1] buf[2]
----------------------
0 0 0 0
1 0 0 in[0]
2 0 in[0] in[1]
3 in[0] in[1] in[2]
4 in[1] in[2] in[3]
5 in[2] in[3] in[4]
...
这样你总是有in[t-1]
,in[t-2]
并且in[t-3]
可用于计算out[t]
。也许您担心在像这样的“滚动”缓冲区中移动数据的性能成本。但是可以通过使用循环缓冲区来避免额外的工作,其长度通常四舍五入到最接近的2^n
(integer n
),以便可以使用 binary 完成环绕and (2^n-1)
。下一个写入位置存储在一个额外的状态变量中i
:
t i buf[0] buf[1] buf[2] buf[3]
-------------------------------
0 0 0 0 0 0
1 1 in[0] 0 0 0
2 2 in[0] in[1] 0 0
3 3 in[0] in[1] in[2] 0
4 0 in[0] in[1] in[2] in[3]
5 1 in[4] in[1] in[2] in[3]
6 2 in[4] in[5] in[2] in[3]
7 3 in[4] in[5] in[6] in[3]
8 0 in[4] in[5] in[6] in[7]
...
如果您使用单指令多数据 (SIMD) 加速,in[t]
在计算out[t]
.
如果您有一个无限脉冲响应 (IIR) 滤波器(如 Butterworth),您可以使用另一个循环缓冲区来存储过去的out
值。这将给出一个称为直接形式 I 的 IIR 实现结构。还有其他结构可能具有更好的数值稳定性,也可能不具有更好的数值稳定性,请参见http://www.earlevel.com/main/2003/02/28/biquads/。
如果您不关心滤波器频率响应的相位,一个简单的二极点、二零陷波 IIR 滤波器将完成消除 50 Hz 的工作:(伪代码:)
params:
fs = sampling frequency
f = notch frequency
r = sharpness, 0..1 excluding 1
init:
z1x = cos(2*pi*f/fs)
a0a2 = (1.0 - r)*(1.0 - r)/(2.0*(fabs(z1x) + 1.0)) + r
a1 = -2.0*z1x*a0a2
b1 = 2.0*z1x*r
b2 = -r*r
loop:
out[t] = a0a2*(in[t] + in[t-2]) + a1*in[t-1]
+ b1*out[t-1] + b2*out[t-2]
对于这样一个简单的过滤器,您可能希望跳过实施复杂的索引缓冲方案。