数字滤波器设计基础:FIR与IIR滤波器的区别、特性与设计方法
数字滤波器,说白了就是一段数学运算代码。它把输入的采样点序列,按照你想要的频率特性进行加工。我在刚入行那会儿,总觉得滤波器设计是理论家的活儿,直到第一次在定点DSP上跑IIR滤波器跑出了自激振荡……嗯,从那以后我才真正把这两类滤波器的脾气摸清楚。
今天咱们就聊聊FIR和IIR这对冤家。它们各有各的绝活,也各有各的坑。
从名字看本质:有限 vs 无限
先看名字:FIR(Finite Impulse Response)——有限冲激响应。IIR(Infinite Impulse Response)——无限冲激响应。
什么意思?你给滤波器输入一个单位冲激(就一个1,后面全是0),看它的输出:
- FIR:输出在有限个采样点后归零。因为它的结构里没有反馈,只有前馈。
- IIR:输出理论上会一直振荡下去,永不归零。因为它有反馈,输出会绕回来影响自己。
你想想看,一个没有反馈,一个有反馈。这个差异决定了它们几乎所有的特性。
核心差异一句话:FIR是“非递归”结构,IIR是“递归”结构。递归意味着极点,极点意味着可能不稳定。
FIR滤波器:稳,但慢
FIR的差分方程长这样:
y[n] = b0·x[n] + b1·x[n-1] + b2·x[n-2] + ... + bN·x[n-N]
没有y[n-1]、y[n-2]这些项。输出只取决于当前和过去的输入。
FIR的优点
- 绝对稳定:所有极点都在原点,不存在稳定性问题。你随便给系数,它都不会炸。
- 线性相位:这是FIR最大的王牌。所有频率分量的延迟时间相同,波形形状不变。通信系统中的匹配滤波器、均衡器,非FIR不可。
- 实现简单:就是乘累加,没有反馈环路,定点实现时不用担心溢出振荡。
FIR的缺点
- 阶数高:要获得陡峭的过渡带,你需要很高的阶数。比如一个-60dB阻带衰减、过渡带只有0.1π的FIR,阶数可能轻松上百。
- 延迟大:阶数越高,群延迟越大。实时性要求高的场景,这是个硬伤。
- 计算量大:每个输出点要做N+1次乘法和N次加法。N=100时,每秒48k采样率,那就是480万次乘累加。
我的经验:在音频均衡器里,我一般只用FIR做线性相位滤波。但如果你需要低延迟的实时效果器,比如吉他失真前的带通,我会毫不犹豫选IIR。
IIR滤波器:快,但娇气
IIR的差分方程带反馈项:
y[n] = b0·x[n] + b1·x[n-1] + ... + bM·x[n-M] - a1·y[n-1] - a2·y[n-2] - ... - aN·y[n-N]
注意那个负号。反馈系数a决定了滤波器的极点位置。
IIR的优点
- 阶数低:同样的过渡带和阻带衰减,IIR的阶数可能只有FIR的十分之一。一个4阶的切比雪夫IIR,效果可能顶得上一个40阶的FIR。
- 延迟小:阶数低,群延迟就小。适合实时控制、生物医学信号处理。
- 计算量小:每个输出点只需要几次乘累加。在低端MCU上也能跑。
IIR的缺点
- 可能不稳定:极点一旦落在单位圆外,滤波器就炸了。定点实现时,系数量化可能把极点推出圆外。
- 非线性相位:不同频率的延迟不一样,波形会失真。音频处理中,IIR的相位失真人耳能听出来。
- 定点实现麻烦:反馈环路容易产生极限环振荡。我曾经在一个16位定点DSP上实现IIR陷波器,结果输入为零时输出还在小幅度振荡……排查了两天才发现是系数舍入导致的。
避坑指南:我曾经在一个产品里用IIR做50Hz工频陷波。仿真时好好的,一上硬件就自激。后来发现是ADC的直流偏置让滤波器状态变量饱和了。解决办法:先做高通滤除直流,再用双精度累加器。
FIR vs IIR:一张表说清楚
| 对比项 | FIR | IIR |
|---|---|---|
| 结构 | 非递归(无反馈) | 递归(有反馈) |
| 稳定性 | 绝对稳定 | 可能不稳定 |
| 相位特性 | 可做到严格线性相位 | 非线性相位 |
| 阶数需求 | 高(通常50~200阶) | 低(通常2~10阶) |
| 计算量 | 大 | 小 |
| 延迟 | 大(等于阶数/2个采样周期) | 小 |
| 设计方法 | 窗函数法、频率采样法、Parks-McClellan | 巴特沃斯、切比雪夫、椭圆、贝塞尔 |
| 典型应用 | 通信、音频、图像处理 | 实时控制、生物医学、语音 |
设计方法:怎么把指标变成系数?
FIR设计——窗函数法
这是最直观的方法。步骤很简单:
- 先确定理想滤波器的频率响应,做逆傅里叶变换得到无限长的冲激响应。
- 用窗函数(汉明窗、布莱克曼窗、凯泽窗)截断到有限长度。
- 截断后的序列就是FIR系数。
窗函数的选择决定了过渡带宽度和阻带衰减。我个人习惯用凯泽窗,因为它有一个可调的β参数,可以在过渡带和衰减之间做权衡。
// 用凯泽窗设计低通FIR滤波器
// 采样率 48kHz,截止频率 10kHz,阶数 64
// β = 5.0 对应约 -50dB 阻带衰减
float beta = 5.0f;
float fc = 10000.0f / 48000.0f; // 归一化截止频率
int N = 64;
float h[N+1];
for (int n = 0; n <= N; n++) {
// 理想低通冲激响应
if (n == N/2)
h[n] = 2 * fc;
else
h[n] = sin(2 * M_PI * fc * (n - N/2)) / (M_PI * (n - N/2));
// 乘以凯泽窗
h[n] *= kaiser(n, N, beta);
}
IIR设计——从模拟到数字
IIR设计通常走这条路:先设计模拟滤波器(巴特沃斯、切比雪夫),再用双线性变换法映射到数字域。
为什么用双线性变换?因为它能保证映射后稳定——s平面的左半平面映射到z平面的单位圆内。但代价是频率会扭曲,需要做预畸变校正。
// 双线性变换的核心步骤
// 模拟截止频率 Ωc -> 数字截止频率 ωc
// 预畸变:Ωc = (2/T) * tan(ωc/2)
float fs = 48000.0f;
float fc = 1000.0f; // 数字截止频率
float omega_c = 2 * M_PI * fc / fs;
float Omega_c = (2.0f / (1.0f/fs)) * tan(omega_c / 2.0f);
// 然后用Omega_c设计模拟巴特沃斯滤波器
// 再通过双线性变换得到数字系数
我的建议:初学者先用MATLAB的fdatool或Python的scipy.signal。把系数算出来,再移植到C代码里。手算IIR系数太容易出错了,我吃过这个亏。
怎么选?三个问题帮你决策
你在项目里到底用FIR还是IIR?问自己三个问题:
- 相位重要吗?——如果信号波形必须保持(比如QRS波检测、通信解调),选FIR。
- 延迟敏感吗?——如果延迟超过1ms就不能接受(比如助听器、实时控制),选IIR。
- 计算资源够吗?——如果MCU只有几十MHz主频、几KB RAM,选IIR。如果用的是FPGA或高性能DSP,FIR随便上。
其实很多时候,你会两者混用。比如前端用IIR做粗略的带通,后端用FIR做精细的整形。我在一个心电监护仪项目里就是这么干的——IIR滤掉工频和基线漂移,FIR做QRS波匹配滤波。
知识体系总览
下面这张图把FIR和IIR的对比、设计流程、选型逻辑串在了一起。你可以把它当作本章的思维导图:
这张图把FIR和IIR从特性、优缺点、设计方法到选型逻辑串在了一起。你写代码前,先对着这张图想清楚:你的项目到底需要什么?