做电机控制这行干久了,你对“滤波”的容忍度会越来越低。我说个真实场景:某次量产前的拷机,电流波形看着没事,一加载负载、电机嗡嗡声就来了。示波器怼上去一看,ADC 采回来的电流信号毛刺比主波还高,全是 PWM 开关噪声、死区谐波和电源纹波混出来的东西。这种信号直接丢给 FOC 里的 PI 调节器,电流环轻则啸叫、重则直接发散,严重的还会触发过流保护跳闸。IIR 数字滤波器就是干这个的,也是我在做 FOC 控制、无感算法和高频注入方案时最常用、也最容易被低估的一个模块。这篇文章从一个电机控制一线工程师的视角,把 IIR 滤波器从 Z 平面、低通/带通设计,到 FOC 电流环、高频注入场景里的具体用法一次讲透。刚接触电机控制的初学者可以拿来当入门地图,已经在调环路但被滤波整得头疼的同行,也能在里面找到几个能直接用上的排查思路。
1. 为什么电机控制离不开 IIR 滤波器
1.1 反馈信号里到底藏着哪些“脏东西”
电机控制系统的反馈链路,远没有教科书画得那么干净。以最常见的 PMSM 矢量控制为例,电流采样通常通过采样电阻或霍尔传感器完成,信号经过运放放大、ADC 量化,最终变成 DSP 或者 MCU 里的一串整数。整个过程每一级都会往里掺噪声。
第一类噪声是 PWM 开关噪声。逆变器以 8kHz 到 20kHz 的频率开通关断功率管,每次开关动作都会在采样电阻两端产生尖锐的电压跳变,尤其在上管刚导通的瞬间还有一段振铃。如果 ADC 采样时刻没躲开这个窗口,采回来的电流值根本不能反映真实电流。
第二类是死区引起的谐波。三相逆变器为了避免上下桥臂直通,必须插入死区时间。死区会让实际输出电压与指令电压产生偏差,而这个偏差对应的是 5、7、11 次等低次谐波。谐波叠加在基波电流上,会在电流环里形成周期性扰动。
第三类是电气噪声和量化噪声。电流传感器的带宽内噪声、PCB 布局串扰、电源地弹,以及 12 位 ADC 在低电流时不可忽略的量化步长,全都混在信号里。
这些噪声对 FOC 控制来说都是致命的。电流环带宽通常在几百赫兹到几 kHz,PI 调节器不会区分噪声和有效信号,它只知道“误差大了就加输出”。毛刺被放大后,驱动波形会跟着抖,电机转矩波动、噪音增大,严重时整条电流环都会震荡。所以,在信号进入控制算法之前,必须用一个可靠的数字滤波器把带外噪声清理掉。
1.2 为什么实时闭环里选 IIR 而不是 FIR
刚接触数字滤波器的同学经常会问:为什么不直接上 FIR 滤波器呢?FIR 线性相位、设计简单、永远稳定,看起来更香。但放到电机控制的实时闭环里,这个问题的答案就没那么天真了。
我用一个表格直接对比一下:
| 对比项 | IIR | FIR |
|---|---|---|
| 通带边缘陡峭程度 | 二阶就能做到比较陡的过渡带 | 同等陡峭度可能需要几十上百阶 |
| 单次采样计算量 | 固定几次乘加 | 随阶数线性增长 |
| 相位特性 | 非线性、有滞后,需要补偿 | 严格线性相位 |
| 稳定性 | 受极点位置影响,需设计保证 | 全零点结构,无条件稳定 |
| 群延迟 | 延迟较小,适合闭环 | 阶数越高,群延迟越大 |
| 典型场景 | 实时控制环路、观测器 | 离线分析、通讯信号处理 |
关键矛盾在“实时闭环”这四个字上。电流环每个 PWM 周期就要算一次,采样频率 10kHz 就意味着每 100 微秒必须完成 ADC 读取、滤波、坐标变换、PI 调节、PWM 更新这一整串工作。如果用一个 64 阶 FIR 做电流滤波,单单乘法次数就从几次飙到两百多次,在低成本 MCU 上这几乎是不可接受的资源占用。
而且 FIR 的群延迟是硬伤。阶数越高,信号经过滤波器后的时间延迟越大。在一个相位裕度本来就紧张的电流环里,多出几十微秒的延迟,可能直接把稳定余量吃光。
所以我个人的结论非常明确:电机控制的实时环路里,优先用 IIR。它用极少的计算量换来足够陡峭的滤波效果,唯一需要认真对待的就是相位滞后问题,这一点在后面会有专门的章节展开。
2. 从 Z 平面看透 IIR 滤波器的本质
2.1 零点和极点:滤波器的灵魂
IIR 滤波器本质上一个带反馈的差分方程。一个二阶 IIR 滤波器长这样:
y[n] = b0·x[n] + b1·x[n-1] + b2·x[n-2] - a1·y[n-1] - a2·y[n-2]
反馈项 a1、a2 的存在,让输出不仅依赖输入的历史值,还依赖输出自身的历史值。正是这种递归结构让 IIR 能用低阶实现陡峭滤波特性。
把它做 Z 变换后,就得到了传递函数:
H(z) = (b0 + b1·z^{-1} + b2·z^{-2}) / (1 + a1·z^{-1} + a2·z^{-2})
分母多项式的根就是极点,分子多项式的根就是零点。在 Z 平面上,极点的位置决定了滤波器的“性格”,零点则像一个个固定频率的陷阱,专门压制特定频段的信号。
判断 IIR 滤波器是否稳定有一套非常直接的规则:所有极点必须全部落在单位圆内。只要有一个极点在单位圆外,这个滤波器就是一个会自激的振荡器。即使极点勉强在单位圆内但非常靠近边缘,脉冲响应也会衰减得极慢,表现为滤波输出拖尾很长,甚至对微小扰动发出持续的“振荡余音”。
我习惯用一个生活化的类比去理解极点:极点就像音叉的固有频率。音叉被敲一下,会按它的固有频率嗡嗡响,衰减快慢取决于阻尼。极点离单位圆越近,等效阻尼越小,输出的“余音”越长,滤波器的带宽也越窄。反过来,极点离原点越近,阻尼越大,响应越快,但滤波能力也越弱。理解了这一层,后面调截止频率和 Q 值的时候,心里就有谱了。
2.2 双线性变换:模拟设计到数字实现的桥
实际设计 IIR 滤波器时,通常不是直接写差分方程,而是先有一个模拟滤波器原型,再通过双线性变换映射到数字域。最常见的模拟原型有一阶低通、二阶巴特沃斯、二阶带通等。
双线性变换的核心公式是:
s = (2/T) · (1 - z^{-1}) / (1 + z^{-1})
其中 T 是采样周期。这个变换的巧妙之处在于,它把模拟域的虚轴映射到数字域的单位圆,模拟稳定的滤波器数字实现后也稳定,不会出现频率混叠的问题。
代价是频率轴会发生非线性压缩,数字域的实际频率和模拟原型频率对不上。所以在做变换之前,必须先做一步“频率预畸变”:
Ωc = (2/T) · tan(ωd / 2)
这里 ωd 是期望的数字角频率,Ωc 是用于设计模拟原型的实际角频率。如果不做这一步,设计出来的滤波器截止频率会明显偏离目标值。
我举个例子:设计一个一阶低通,采样频率 fs=10kHz,希望截止频率 fc=500Hz。先计算数字角频率 ωd=2π·500/10000≈0.314rad/sample,再计算预畸变后的 Ωc≈3183rad/s。代入一阶模拟低通 H(s)=Ωc/(s+Ωc),整理后得到离散系数:b0=b1≈0.1368,a1≈0.7265。对应的差分方程极其简洁:
y[n] = 0.1368·(x[n] + x[n-1]) + 0.7265·y[n-1]
这个滤波器的含义很直观:它把上一拍的输出保留 72.65%,再把当前输入和上一拍输入各取 13.68% 叠加进去。截止频率越低,a1 越接近 1,也就是“记忆”越持久,滤波越平滑。
2.3 低通、带通的离散化设计步骤
工程上设计 IIR 滤波器,我不太建议每次都手推传递函数,正确姿势是先明确指标,再借助工具生成系数,最后放进代码验证。完整的流程我拆成五步:
- 明确采样频率和目标频率。比如电流环 PWM 频率 10kHz,要滤掉 5kHz 以上的开关噪声,可以选择截止频率 500Hz 到 1kHz。
- 根据需求选择滤波器类型。滤基波用低通,做高频注入信号提取用带通,剔除特定谐波用陷波。
- 用设计工具生成系数。Python 的 scipy.signal 是最常用的,Matlab 的 Filter Designer 也可以。
- 把生成的系数放到代码里前,先在软件里做一次零极点图检查,确保极点全部在单位圆内。
- 联调时用示波器或者 DA 输出观察滤波前后波形,验证截止频率和相位滞后是否满足预期。
分享一个我用 Python 生成带通系数的快捷做法:
from scipy import signal fs = 10000.0 # 采样频率 10kHz f0 = 1000.0 # 带通中心频率 1kHz bw = 200.0 # 带宽 200Hz b, a = signal.butter(2, [f0 - bw/2, f0 + bw/2], btype='bandpass', fs=fs) print("b =", b) # [b0, b1, b2] print("a =", a) # [a0, a1, a2],注意 a0=1拿到系数后,很多同学直接在单片机里套差分方程,结果发现波形不对。这里有个常见坑:带通滤波器在高 Q 值下对系数精度极敏感。浮点环境下没事,一旦转到定点平台做 Q15 量化,极点位置就可能漂到单位圆外,滤波器直接自激。所以每次定完系数,第一件事先看零极点分布,确认稳定性,再谈移植。
3. IIR 滤波器在 FOC 电流环里的实战位置
3.1 滤波器到底该放在哪个环节
FOC 的电流反馈链路一般是:三相电流采样 → ADC 转换 → 坐标变换(Clarke 和 Park)→ PI 调节器 → 空间矢量调制。IIR 低通滤波器可以放在多个位置,但位置不同,效果完全不一样。
我做过很多次对比实验,结论如下:如果主要目标是把 PWM 开关毛刺干干净,滤波器放在 ADC 采集之后、坐标变换之前最直接。这时候信号还是一相一相的原生电流,滤波不会影响坐标变换的相位一致性。
如果目标是让最终的 Id 和 Iq 反馈值更平滑,则滤波器放在 Park 变换之后更合适。因为 dq 坐标系下是直流量,低通滤波对直流成分几乎没有相位影响,对残余交流噪声的抑制能力很强。
但放在 dq 域有一个必须注意的铁律:d 轴和 q 轴的滤波器系数必须完全一致。两个通道的相位响应一旦有细微差异,高速运行时 dq 轴之间就会出现明显的耦合误差,电机表现为抖动和额外的转矩脉动。我调试时见过有人只给 q 轴加了滤波,d 轴漏了,结果转速一上去噪声反而更严重,查了整整一天才发现是通道不一致导致的。
3.2 低通滤波提取基波电流的实操
我手头一个典型项目是这个配置:PWM 开关频率 10kHz,电流环中断固定 10kHz,电机额定转速对应基波频率 100Hz 左右。为了滤掉开关噪声又不至于让电流环带宽损失太多,我选择一阶低通截止频率 1kHz,当时计算出的系数和前面 2.2 节类似。
实际操作的时候,我不会一开始就把固定系数烧进去。正确姿势是这样:先关掉滤波器,空载低速跑起来,用调试器观察原始电流波形,记一下毛刺的幅值和频率。然后逐步降低滤波截止频率,从 5kHz 降到 2kHz 再降到 1kHz,每次降低后都做一次电流环阶跃响应测试,感受系统是否稳定,听电机有没有高频啸叫。
最终定下的截止频率是一个工程折中:既要让毛刺衰减到可接受范围,又要保证电流环的动态响应不发软。如果发现截止频率压得太低导致电流环发软,优先考虑提高采样频率,而不是强行提高截止频率。比如把 PWM 频率从 10kHz 提高到 16kHz,同样滤波效果下,相位滞后几乎减半。
3.3 相位延迟问题与补偿技巧
IIR 低通滤波器带来的相位滞后,是 FOC 调环里最容易翻车的地方。一阶低通在截止频率处的相位滞后接近 45°,如果在 1kHz 截止、500Hz 工作频率下,滞后大概在 28° 左右。电流环本身的相位裕度通常只有 30° 到 50°,一个滤波器就可能把裕度吃干净。
我问过一个很典型的现象:加了电流滤波器之后,系统空载稳定,一加载就抖动。这是因为负载增大后电流指令变化剧烈,反馈通道的相位滞后让实际电流跟不住指令,误差信号过冲,PI 输出振荡。
我常用的补偿技巧有三个。第一,也是性价比最高的方案:把同样的滤波器加到电流指令参考值的通道上。反馈通道延迟,指令通道也延迟,两者相减之后误差信号重新同步了相位,这个我在多个项目里验证过非常有效。第二,尽量把滤波器的截止频率设得比电流环带宽高 5 到 10 倍,让相位滞后远离环路交越频率。第三,如果滤波器同时用于高速观测器,注意观测器增益和滤波延迟之间的平衡,必要时在观测器里做超前补偿。
说到底,滤波器不是灵丹妙药。它是一个会窃取相位裕度的环节,你要么接受它的滞后,要么想办法把滞后从系统的误差路径里“抵消”掉,没有第三条路可走。
4. 高频注入中的 IIR 带通滤波器
4.1 高频注入原理简述
无感 PMSM 控制有一个绕不开的难题:零速和低速时,反电动势几乎为零,靠反电动势估算转子位置是做不到的。这时候就要用高频注入法。
方法是在估计的 d 轴方向叠加一个高频正弦电压,频率通常取 500Hz 到 1kHz以上,幅值远小于基波电压。由于电机转子存在凸极效应,也就是直轴电感 Ld 和交轴电感 Lq 不相等,高频电流响应的幅值会随着转子角度变化。通过解调这个高频电流响应,就能间接算出转子位置角和转速。
这套方案里,滤波器的角色极其关键,因为采样得到的电流信号中,既有低频基波电流,又有注入的高频电流,还有一大堆噪声和逆变器非线性产生的杂波。必须用带通滤波器把注入频率附近的那段信号干净地提出来,才能做后续解调。
4.2 带通滤波器分离高频响应的设计要点
高频注入链路里的带通滤波器,中心频率要严格对齐注入信号频率。我常用注入频率 1kHz,采样频率也是 10kHz。带通带宽一般取几十到几百赫兹,具体取决于位置环需要的动态响应速度。
这里有一个物理矛盾:带宽越窄,抑制噪声能力越强,但是带通滤波器的群延迟越大,位置环带宽就会被限制。带宽越宽,动态响应快,但噪声残余多,解调出来的位置信号抖动大。工程折中一般取注入频率的 10%~20%,例如 1kHz 注入频率配 100Hz 到 200Hz 带宽。
带通滤波器处于高频信号的路径上,它对相位的要求比低通更苛刻。因为后续要对高频电流做乘法解调,带通引入的相位偏移会直接影响解调输出的幅值和符号。如果解调参考信号与带通输出之间存在明显相位差,位置误差信号的增益就会被压缩,严重时甚至出现符号反转。所以设计带通时,要把带通相位、解调参考相位、采样延迟三者一起核算。
我在实际项目里通常是先把带通滤波器建模,再用仿真器跑一遍完整的注入-解调链路,记录各个频率下的相位偏移,然后在校准表里把解调参考信号的相位补偿掉。这种做法比盲目调带宽要靠谱得多。
4.3 解调与最终低通
高频电流经过带通滤波器提取后,要和注入信号同频的参考信号做乘法解调。数学上,两个同频正弦相乘会产生一个直流分量和一个二倍频分量。直流分量正比于位置误差信号,二倍频分量是需要滤掉的杂散成分。
所以在乘法解调之后,还需要一个低通滤波器把二倍频分量和残余高频彻底清掉。这个低通一般选用第一性的简单一阶 IIR,截止频率取位置环带宽的 2 到 3 倍。如果位置环带宽是 50Hz,低通截止就取 100 到 150Hz。
整个高频注入信号链路的滤波链是:电流采样 → IIR 带通 → 乘法解调 → IIR 低通 → 位置调节器。每一级滤波器都会贡献延迟,设计时要算总账。带通延迟、低通延迟、乘法器的计算延迟、PWM 的更新延迟全部加起来,必须小于位置环能够容忍的极限延迟。我在调试时就遇到过带通带宽选太窄,整个链路延迟过大,位置环怎么调 PI 都振,最后把带宽从 80Hz 放宽到 150Hz,问题才消失。
5. 常见问题、避坑技巧与调试实录
5.1 滤波系数精度陷阱
IIR 滤波器在高 Q 值下对系数精度极其敏感,这个坑我踩过不止一次。有一个带通滤波器设计中心频率 1kHz、带宽 80Hz,Q 值到了 12 左右。浮点仿真时零极点稳稳落在单位圆内,移植到定点平台做 Q15 量化后,极点直接飘到了单位圆边界上,输出开始自激振荡。
教训是:定点平台上的 IIR 滤波器,系数精度评估不能只看量化误差的平均值,要看量化后的极点在最恶劣情况下的位置。Q15 只有 16 位精度,二阶带通高 Q 时分子分母系数动态范围又大,往往会出问题。我的建议是能用浮点就尽量用浮点,MCU 支持硬件浮点则直接写 float;如果必须定点,至少 Q31,并且对乘法结果做饱和处理,绝不能简单截断。
5.2 相位滞后引发的振荡
症状很典型:加了滤波器后,电流环空载正常,一带载就啸叫或抖动。排查思路按三步走。第一步,把滤波器临时旁路掉,确认振荡消失。第二步,对比反馈通道和指令通道的相位。如果指令通道没有加同样的滤波器,反馈通道的滞后就会在误差信号中形成虚假的高频分量。第三步,把同样滤波器加回指令通道,或者降低截止频率查看响应。大多数情况下,问题都能锁在相位滞后上。
5.3 启动瞬间滤波器输出跳变
滤波器历史状态如果从零开始,上电初期会有一段暂态过程。有些电机控制器的切入逻辑是“档位切换”,从开环切闭环的一瞬间,滤波器输出可能还在收敛过程中,这会让电流环看到一个假的冲击误差,导致启动失败或者过流。
解决方法是做一个“滤波器预热”逻辑:在切入闭环之前,让滤波器先正常运行几十毫秒,并把输出初始化为当前采样值,或者强制把历史状态置为最终稳态值。这个细节不处理好,滤波器系数设计得再完美,实际体验也会很糟糕。
5.4 C 语言实现与定点平台移植经验
以一个完整的二阶 IIR 为例,在 STM32、C2000 或者 C6000 系列 DSP 上实现非常固定。我用的是 Direct Form II Transposed 结构,代码简洁不容易出错,状态变量只需要维护两组历史值。
typedef struct { float b0, b1, b2; // 分子系数 float a1, a2; // 分母系数,a0 归一化为 1 float x1, x2; // 历史输入 float y1, y2; // 历史输出 } iir_biquad_t; void iir_biquad_init(iir_biquad_t *f) { f->x1 = f->x2 = f->y1 = f->y2 = 0.0f; } float iir_biquad_process(iir_biquad_t *f, float xn) { float yn = f->b0 * xn + f->b1 * f->x1 + f->b2 * f->x2 - f->a1 * f->y1 - f->a2 * f->y2; f->x2 = f->x1; f->x1 = xn; f->y2 = f->y1; f->y1 = yn; return yn; }这段代码核心只有五次乘法和四次加法,在绝大多数控制芯片上都能在一个 PWM 周期内轻松算完。如果你用的是定点 DSP,比如 C6000 平台写 Q15 格式,那么在乘法运算时要先把状态变量和系数转换为 Q15 后相乘,结果的中间量用 32 位保存,最后统一缩放到 Q15。特别注意乘法结果的符号位扩展,否则会出现严重的直流偏置。
5.5 常见问题速查表
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 滤波后电流波形仍有毛刺 | 截止频率过高,或采样时刻靠近 PWM 开关沿 | 降低截止频率,微调 ADC 采样时刻 |
| 加滤波器后环路啸叫 | 反馈相位滞后过大,或者系数不稳定 | 检查零极点,指令通道加同款滤波器 |
| 启动瞬间电流突跳 | 滤波器历史值未初始化 | 闭环前预热滤波器或预置稳态值 |
| 带通滤波器在定点平台自激 | Q 值过高,系数量化精度不足 | 改用浮点或 Q31,并做饱和保护 |
| 解调后位置信号抖动大 | 带通带宽过窄或低通截止过高 | 放宽带宽,压低一阶低通截止 |
| dq 轴滤波后电机抖动 | d 轴 q 轴滤波器参数不一致 | 强制使用相同滤波器系数 |
写在最后的一点工程师体会
做 FOC 和高速注入这些年,我越来越觉得滤波器调试是一门“算总账”的功夫。新手总想着把噪声滤得越干净越好,把截止频率一路往下压,结果系统响应越来越肉,震荡接二连三。老手会先算清楚整个环路每一级的延迟预算,再回头定滤波器的类型、阶数和截止频率。我自己现在写滤波系数之前,一定会先问自己三个数:采样率是多少?目标频率是多少?我能接受的相位滞后是多少?这三个数定不下来,后面步步都是坑。
如果你的项目正在被电流环啸叫、高频注入解调出来的位置抖动、或者定点移植后的滤波器自激折腾,不用怀疑,多半不是计算量不够,而是滤波器的相位和精度问题没想透。拿这篇文章里的排查逻辑,从 Z 平面的极点和系数精度开始查,许多问题都能迎刃而解。搞电机控制,滤波器不是一个被动的辅助工具,它就是你控制算法里一个真实的、有时会捣乱的环节。“先想清楚滤波器的代价,再享受它的好处”,这句话我每次写代码前都会默念一遍,也送给所有正在调滤波器的同行。