原理
所谓滤波是指再输入信号中提取期望有效的信号,消除不期望的出现的信号即噪声。经典的数字滤波器主要利用信号的频域特性处理噪声,即滤除指定频率分量的滤波器。而现代滤波器利用的是信号的统计特性,即根据某个信号出现的概率进行滤波。这里主要讨论如何设计经典滤波器。
经典滤波器按照结构可以分为IIR(无限冲激响应)和FIR(有限冲激响应)两大类,前者存在输出反馈回路,可以用较低的阶数获得较高的选择性,但是相位是非线性的,并且在设计上存在不稳定的可能,而后者则恰好相反,无输出反馈回路,在同样的选择性下FIR滤波器需要较IIR更高阶数,但其相位是严格线性的并且滤波器总是稳定的。例如在对于控制反馈量的滤波,宜采用FIR确保其输入波形不发生失真。
设计
数字滤波器可以借助Matlab实现,这里以2阶低通IIR为例。打开Matlab的Filter Designer,在对话框内选Lowpass,Butterworth,指定阶数,通带阻带大小,点下面的Design Filter即可
当然同样可以选择FIR滤波器,类型选用Window(窗函数设计法),Window选项选用合适的窗函数即可,参考下表
查看参数的作用也可以点工具栏上的Filter Specification
实现
直接计算
以二阶IIR实现为例,根据IIR的N阶差分方程
可以直接编程计算,但是Matlab生成的滤波器默认带多个Section,为了能直接计算,需要将参数转换为单个Section,在菜单栏中选Convert -> Convert to single section
在Filter Coefficient中可以看到参数分为Numerator(分子)和Denominator(分母),这是写成系统方程的表述,分母代表ai(a0总是为1),分子为bi。然后在点Generate C Header即可生成带参数的头文件fdacoef.h
实现代码
1 | /** |
FIR的实现类似,但是Convert Structure里面应选择Direct-Form FIR
ARM Math库实现
ARM官方提供了可在STM32上运行并且带优化的arm math库,其中就包含了各种滤波器函数的实现,根据精度不同可以使用多种定点和浮点计算,并且支持如下滤波器实现结构
IIR Biquad 串级
即Matlab IIR 设计里Direct-Form默认生成的带多个Section的滤波器,实质上是多个二阶IIR串联结构,其中针对单个IIR的结构支持Direct Form I(直接I型),Direct Form II Transposed(直接2型),在文档中提到的初始化直接型的参数说明
Coefficient and State Ordering
The coefficients are stored in the array
pCoeffs
in the following order:{b10, b11, b12, a11, a12, b20, b21, b22, a21, a22, ...}
即格型网络结构,对应Matlab结构Lattice Autoregressive Moving-average,文档说明的初始化参数为
pkCoeffs
points to array of reflection coefficients of sizenumStages
. Reflection Coefficients are stored in time-reversed order.
{kN, kN-1, ..., k1}
pvCoeffs
points to the array of ladder coefficients of size(numStages+1)
. Ladder coefficients are stored in time-reversed order.{vN, vN-1, ..., v0}
需要注意的是Lattice的初始化参数其顺序与Matlab生成的顺序完全相反,在转换为代码是需要调换
这个跟上面自己编程实现类似,但是与IIR Lattice的参数一样都是逆序的
pCoeffs
points to a coefficient array of sizenumTaps
. Coefficients are stored in time reversed order.{b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
参数类似IIR Lattice 但没有ladder coefficients,参数顺序也是逆序排列
以三阶IIR Biquad 串级(浮点)为例,由于Matlab中生成的参数不符合输入要求,因此我们只能手动完成变换。在转换为Direct Form II 后选File-> Export,选导出到工作区
导出后可以看到工作区多了两个变量SOS
和G
,在CMSIS ARM Math库中没有把增益作为输入参数,因此只能预先合并入SOS
中,编写Matlab即可获得C代码
1 | m_array = reshape(SOS.*G(1:end-1),numel(SOS),1); |
其初始化和调用应该是这样的
1 | //初始化 |
同理Lattice型只需要将输出数组顺序反转,用上述后半段程序转换为C数组即可