核心内容摘要
遇见色彩,倾听心声:小蓝GTV,中国男Gay的闪耀舞台
作为嵌入式工程师你大概率遇到过这种棘手情况采集电机转速时串口打印的数值跳得厉害明明机械结构稳如泰山显示转速却像“过山车”用万用表测模拟信号还算平稳AD采样后的数据却杂乱无章直接导致PID调节频繁震荡电机运行噪音骤增。
这其实是典型的信号噪声干扰问题而一阶IIR低通滤波器凭借“占用资源少、计算简单、延迟低”的核心优势成为嵌入式场景下解决这类问题的“性价比之王”。
今天我们就从基础原理出发一步步拆解一阶IIR低通滤波器的设计与实现最终落地到电机转速平滑的实战场景帮你快速上手应用。
原理拆解从RC低通电路到数字滤波器在接触数字滤波器前不少工程师都用过RC低通电路做信号平滑——利用电阻和电容的充放电特性把高频噪声过滤掉。
而一阶IIR低通滤波器的核心思路就是把RC低通电路的物理特性用数字运算等效实现让单片机、MCU等数字设备也能完成信号平滑处理。
1 RC低通电路的核心特性RC低通电路的结构很简单输入信号Vi经电阻R后一端接电容C电容另一端接地输出信号Vo从电容两端取出。
其核心是基于电容充放电的微分方程这也是后续设计的基础Vo(t) RC·dVo(t)/dt Vi(t)其中RC是电路的时间常数τ。
τ越大电容充放电越慢滤波后的信号越平滑但对信号变化的响应也越慢反之τ越小响应速度越快但滤波效果会打折扣。
电路的截止频率fc高频信号开始明显衰减的频率与τ的关系为fc 1/(2πτ) 1/(2πRC)。
这两个公式是后续数字滤波器设计的核心依据务必牢记。
2 数字等效差分方程的推导数字设备处理信号的核心特点是“离散化”——只能每隔固定时间采样周期Ts采集一次输入信号没法处理连续的模拟信号。
所以我们需要把RC电路的微分方程转化为适合数字运算的差分方程离散域方程。
这里我们采用嵌入式场景中常用的“向后欧拉法”数值积分离散化方法稳定性强、适配性好对微分方程进行离散化。
对于电容电压的变化率dVo(t)/dt我们用相邻两个采样时刻的电压差值近似表示dVo(t)/dt ≈ [Vo(n) - Vo(n-
] / Ts其中Vo(n)是第n次采样的输出值Vo(n-
是第n-1次采样的输出值Ts是采样周期Ts 1/FsFs为采样频率。
把这个近似公式代入RC电路的微分方程整理后就能得到Vo(n) [Ts/(Ts RC)]·Vi(n) [RC/(Ts RC)]·Vo(n-
这就是一阶IIR低通滤波器的核心差分方程从公式能清晰看出当前时刻的滤波输出Vo(n)由两部分组成一是当前采样的输入信号Vi(n)二是上一时刻的滤波输出Vo(n-
。
这种“依赖历史输出值”的递归运算特性正是IIR无限脉冲响应滤波器的核心标志——理论上一个输入信号会通过递归运算持续影响后续无限多个输出信号。
为了方便后续工程实现我们通常把差分方程简化为更直观的形式Vo(n) α·Vi(n) (1-α)·Vo(n-
其中α是滤波系数取值范围0 α 1α Ts/(Ts RC)。
到这里我们就完成了从模拟RC电路到数字IIR滤波器的核心转化后续所有工程实现本质上都是围绕这个简化后的差分方程展开的。
工程化分析从参数计算到实战适配原理推导完成后最关键的是“落地实操”——怎么根据实际需求比如采样率、截止频率计算滤波系数α递归运算中如何保存历史状态避免数据丢失怎么适配嵌入式设备常用的定点数运算这些问题直接决定滤波器能不能用、好不好用。
1 滤波系数α的计算公式工具从α Ts/(Ts RC)和fc 1/(2πRC)这两个公式我们可以推导出α与采样频率Fs、截止频率fc的直接关系因为Ts 1/Fs这个推导后的公式是工程中计算α的核心α 1 / (1 1/(2πfcTs)) 1 / (1 Fs/(2πfc))这个公式特别实用只需知道两个关键参数就能计算一是采样频率Fs我们设计的AD采样频率二是截止频率fc需要保留的信号最高频率根据实际信号特性设定。
举个实际工程例子假设我们采集电机转速的AD采样频率Fs 100Hz每秒采样100次结合电机转速特性我们希望过滤掉10Hz以上的高频噪声因此设定截止频率fc 10Hz。
把参数代入公式计算α 1 / (1 100/(2×
14×
) ≈ 1 / (1
1.
≈
386这里给大家推荐两个实用工具避免手动计算出错一是在线IIR滤波器系数计算器比如Filter Design Toolbox输入Fs和fc就能直接出α值二是Excel提前把不同Fs、fc组合对应的α值计算好项目中直接调用效率更高。
2 状态变量的保存逻辑避免数据丢失从差分方程Vo(n) α·Vi(n) (1-α)·Vo(n-
能明显看出当前输出依赖上一时刻的输出Vo(n-
这个Vo(n-
就是我们必须妥善保存的“状态变量”。
如果状态变量保存不当滤波效果会直接失效——比如每次采样都重新初始化状态变量相当于每次都重新开始滤波根本达不到平滑效果。
工程中的保存逻辑很简单记住这3步就行初始化系统上电时把状态变量比如last_out初始化为第一个采样值Vi(
避免初始值为0导致输出突然跳变递归更新每次完成滤波计算后立刻把当前输出Vo(n)赋值给状态变量作为下一次计算的历史状态变量类型选择C语言实现时状态变量要定义为全局变量或静态局部变量确保函数调用后值不丢失如果定义为普通局部变量函数执行完值就释放了下次调用会重新初始化状态保存失效。
3 定点数适配Q格式转换与溢出防护很多嵌入式设备比如8位单片机、低成本MCU不支持浮点运算而滤波系数α是小数比如
386这就需要把浮点运算转化为定点运算。
最常用的方法是Q格式转换——用整数表示小数通过移位运算替代乘法运算既能保证精度又能提高运算效率。
2.
1 Q格式转换规则Q格式的核心逻辑是“把小数放大2Q倍后取整为整数”其中Q是小数位数比如Q15就表示把小数放大21532768倍。
举个例子α
386采用Q15格式转换α_q15 round(
386 ×
≈ round(
12658.
12658对应的(1-α)转换为Q15格式1-α
614(1-α)_q15 round(
614 ×
≈ 20120。
转换后差分方程也随之调整为定点版Vo(n)_q15 (α_q15 × Vi(n) (1-α)_q15 × Vo(n-
) 15其中“15”是右移15位相当于除以2^15目的是把放大后的整数结果还原到原来的数值范围。
2.
2 溢出防护技巧定点数运算很容易出现溢出问题——比如两个16位整数相乘结果很可能超过16位整数的取值范围。
这里分享两个工程中常用的解决方法提升临时变量位数用32位整数存储乘法运算结果再进行移位运算。
比如Vi(n)和α_q15都是16位整数两者相乘的结果用32位整数存储就能避免溢出输入信号归一化把输入信号的范围压缩到合适区间比如0~32767确保乘法运算后的结果不会超过32位整数的取值范围。
C语言实现浮点版定点版适配不同场景根据嵌入式设备的性能差异我们提供两种C语言实现方案大家按需选择浮点版实现简单适合支持浮点运算的MCU比如STM32定点版运算高效适合不支持浮点运算的低成本单片机比如51单片机。
1 浮点版实现简单易上手快速验证#includestdint.h// 滤波系数α根据Fs100Hz、fc10Hz计算#defineALPHA
386f// 状态变量保存上一次滤波输出全局变量避免函数调用时丢失staticfloatlast_out
0f;// 一阶IIR低通滤波函数浮点版// 输入当前采样值vi// 输出滤波后的值vofloatiir_lowpass_float(uint16_tvi){floatvo;// 核心差分方程voALPHA*vi(1-ALPHA)*last_out;// 更新状态变量last_outvo;returnvo;}// 初始化函数可选建议在采样开始前调用voidiir_lowpass_init(uint16_tfirst_vi){last_outfirst_vi;// 用第一个采样值初始化避免初始突变}
2 定点版实现Q15格式高效适配低成本MCU#includestdint.h// Q15格式定义2^1532768#defineQ15_SCALE32768// 滤波系数α的Q15格式α
386#defineALPHA_Q1512658// (1-α)的Q15格式1-α
614#defineBETA_Q15(Q15_SCALE-ALPHA_Q
// 32768 - 12658 20110// 状态变量保存上一次滤波输出静态局部变量仅在函数内部可见staticint16_tlast_out_q150;// 一阶IIR低通滤波函数定点版// 输入当前采样值vi16位整数// 输出滤波后的值vo16位整数int16_tiir_lowpass_q15(uint16_tvi){int32_ttemp;// 32位临时变量防止乘法溢出int16_tvo_q15;// 核心差分方程定点版vo (α*vi (1-α)*last_out) 15temp(int32_t)ALPHA_Q15*vi;// α*vi32位存储避免溢出temp(int32_t)BETA_Q15*last_out_q15;// 加上(1-α)*last_outvo_q15(int16_t)(temp
;// 右移15位还原// 更新状态变量last_out_q15vo_q15;returnvo_q15;}// 初始化函数voidiir_lowpass_q15_init(uint16_tfirst_vi){last_out_q15first_vi;}
实战验证电机转速信号平滑处理接下来我们把上面的实现方案用到电机转速采集场景中实际验证滤波效果。
本次实战的硬件平台STM32F103C8T6支持浮点运算转速采集方式霍尔传感器采集电机转数AD采样频率Fs100Hz设定截止频率fc10Hz针对性过滤高频噪声。
1 实战步骤硬件连接把霍尔传感器的输出信号接到STM32的AD采集引脚比如PA0电机带动霍尔传感器旋转每转一圈产生固定数量的脉冲信号采样与转速计算通过定时器配置AD采样频率为100Hz每次采样完成后根据霍尔脉冲数计算当前电机转速单位r/min滤波处理把计算得到的原始转速值传入浮点版滤波函数iir_lowpass_float()得到平滑后的转速值数据输出把原始转速值和滤波后的转速值通过串口打印到电脑直观对比两者的波动情况。
2 实战结果对比原始转速数据部分
152、
168、
145、
172、
150、
165、
170波动范围±20r/min完全没法直接用滤波后转速数据部分
152、
158.
5、
154.
3、
159.
8、
157.
2、
160.
1、
157.
5、
1
2波动范围缩小到±5r/min稳定性大幅提升。
从结果能明显看出滤波后的转速值波动大幅减小同时对转速变化的响应速度很快无明显延迟完全能满足电机PID调节对转速信号平滑性的要求。
这里给大家一个调试技巧如果觉得滤波效果不够可适当减小α值比如从
386调到
2但要注意响应速度会变慢如果觉得响应太慢可适当增大α值比如从
386调到
5但滤波效果会略有下降实际调试时找到两者的平衡点即可。
问题解决实战中
常见问题与解决方案实际项目中不少工程师会遇到滤波效果差、程序崩溃等问题这里
总结了3个最常见的问题及对应的解决方案帮你避坑
1 问题1滤波后信号波动依然很大原因要么是截止频率fc设置太高没把高频噪声有效过滤要么是α值太大对历史状态的权重不足当前噪声的影响被放大。
解决方案降低截止频率fc比如从10Hz调到5Hz重新计算α值或者直接减小α值比如从
386调到
2增加历史输出的权重强化平滑效果。
2 问题2程序运行中出现数据溢出原因定点版实现时没用到32位临时变量存储乘法结果导致16位整数相乘溢出或者输入信号范围太大超出了运算承载范围。
解决方案严格用32位临时变量存储乘法运算结果对输入信号做归一化处理比如把AD采样的04095范围压缩到032767。
3 问题3滤波后信号延迟严重原因α值太小对当前输入信号的权重不足过度依赖历史状态导致信号变化后滤波输出没法及时跟上。
解决方案增大α值比如从
2调到
5平衡平滑效果和响应速度或者适当提高截止频率fc让滤波器对信号变化更敏感。
总结本文从RC低通电路的数字等效入手完整推导了一阶IIR低通滤波器的差分方程重点拆解了滤波系数计算、状态变量保存、定点数适配等工程化
关键技术最后通过电机转速平滑的实战场景验证了方案的有效性。
一阶IIR低通滤波器虽然结构简单但在嵌入式场景中的性价比极高掌握它的设计与实现方法能解决大部分信号平滑的需求是嵌入式工程师必备的基础技能。
如果这篇文章帮你理清了一阶IIR低通滤波器的实现思路欢迎点赞、收藏并关注我后续我还会分享更多嵌入式信号处理、PID调节、硬件驱动开发的实战技巧。
如果在实际应用中遇到其他问题或者有更好的优化方案也欢迎在评论区留言交流