1. 项目背景与核心需求
在嵌入式信号处理领域,工频干扰(50Hz/60Hz)一直是困扰工程师的典型问题。去年我在开发一款工业振动监测设备时,就遇到了传感器信号被50Hz工频严重污染的情况。这种干扰会导致有效信号被淹没,直接影响设备的状态判断精度。
传统解决方案往往采用简单的RC无源滤波或FIR滤波器,但前者存在衰减严重、相位失真问题,后者则需要较高的计算资源。而IIR(无限脉冲响应)滤波器凭借其"用较少阶数实现陡峭过渡带"的特性,特别适合STM32这类资源有限的MCU平台。
这次我们要实现的巴特沃斯型IIR带阻滤波器,核心目标就是精准滤除50Hz工频干扰(可根据需要调整中心频率),同时保持通带内信号幅度尽可能平坦。这种滤波器在ECG检测、工业传感器信号调理等场景中都有广泛应用。
2. 滤波器选型与技术路线
2.1 为什么选择直接II型结构
在IIR滤波器的多种实现结构中(直接I型、直接II型、级联型等),直接II型(又称规范型)具有明显的内存优势。其特点是将差分方程中的反馈和前馈部分共享相同的延迟单元,这意味着:
- 对于N阶滤波器,只需要N个存储单元(直接I型需要2N个)
- 在STM32这类内存有限的设备上,能减少约50%的RAM占用
- 计算量与传统结构相当,但存储效率显著提升
以一个4阶带阻滤波器为例:
- 直接I型需要8个状态变量
- 直接II型仅需4个状态变量
- 在STM32F103(20KB RAM)上处理多通道信号时,这种节省非常关键
2.2 巴特沃斯滤波器的特性优势
相比切比雪夫或椭圆滤波器,巴特沃斯滤波器虽然过渡带较缓,但其核心优势在于:
- 最大平坦通带:在通带内无纹波,保证有效信号不失真
- 相位特性相对较好:群延迟波动较小,适合对波形保持要求高的场景
- 计算稳定性:极点均匀分布在单位圆上,数值处理更稳定
特别针对工频干扰:
- 干扰频率固定(50Hz±2Hz)
- 需要阻带宽度约4-10Hz即可
- 有效信号通常分布在DC-40Hz和60Hz以上
这种频谱特性与巴特沃斯滤波器的平缓过渡带完美匹配。
3. 差分方程的理论推导
3.1 从传递函数到差分方程
设计一个中心频率50Hz、采样率1kHz的4阶巴特沃斯带阻滤波器:
-
先确定数字域截止频率:
- 低截止频率:f1 = 48Hz → ω1 = 2π*48/1000 = 0.3016 rad/sample
- 高截止频率:f2 = 52Hz → ω2 = 2π*52/1000 = 0.3267 rad/sample
-
通过双线性变换将模拟滤波器数字化:
matlab复制[b,a] = butter(2, [0.3016 0.3267], 'stop');得到传递函数系数:
code复制b = [0.9391 -3.4996 5.2235 -3.4996 0.9391] a = [1 -3.6386 4.9883 -3.0446 0.6949] -
转换为直接II型的差分方程:
code复制y[n] = 0.9391x[n] - 3.4996x[n-1] + 5.2235x[n-2] - 3.4996x[n-3] + 0.9391x[n-4] + 3.6386y[n-1] - 4.9883y[n-2] + 3.0446y[n-3] - 0.6949y[n-4]
3.2 直接II型的结构优化
将上述差分方程重组为直接II型结构:
- 中间变量w[n]的计算:
code复制w[n] = x[n] + 3.6386w[n-1] - 4.9883w[n-2] + 3.0446w[n-3] - 0.6949w[n-4] - 输出y[n]的计算:
code复制y[n] = 0.9391w[n] - 3.4996w[n-1] + 5.2235w[n-2] - 3.4996w[n-3] + 0.9391w[n-4]
这样只需维护4个状态变量(w[n-1]到w[n-4]),比直接I型少用一半内存。
4. STM32上的实现细节
4.1 定点数优化策略
STM32F4的FPU虽然支持浮点运算,但定点数方案仍具有优势:
- 避免浮点运算的精度损失
- 减少计算周期(尤其在M0/M3内核上)
- 方便DSP指令集优化
将系数转换为Q15格式(16位有符号定点数):
c复制#define COEFF_B0 30779 // 0.9391 * 32768
#define COEFF_B1 -114668 // -3.4996 * 32768
#define COEFF_B2 171143 // 5.2235 * 32768
// 其他系数类似...
4.2 状态变量管理
使用环形缓冲区管理状态变量:
c复制typedef struct {
int16_t w[4]; // 状态变量
int16_t idx; // 当前写入位置
} IIR_Filter;
int16_t IIR_Update(IIR_Filter* f, int16_t x) {
// 计算中间变量w[n]
int32_t wn = (int32_t)x;
wn += (f->w[(f->idx+3)%4] * COEFF_A1) >> 15;
wn += (f->w[(f->idx+2)%4] * COEFF_A2) >> 15;
// ...其他反馈项
// 计算输出y[n]
int32_t y = (wn * COEFF_B0) >> 15;
y += (f->w[(f->idx+3)%4] * COEFF_B1) >> 15;
// ...其他前馈项
// 更新状态变量
f->w[f->idx] = (int16_t)wn;
f->idx = (f->idx + 1) % 4;
return (int16_t)y;
}
4.3 性能优化技巧
-
使用ARM DSP库加速:
c复制
arm_biquad_cascade_df2T_instance_q15 filter; arm_biquad_cascade_df2T_init_q15(&filter, NUM_STAGES, pCoeffs, pState); arm_biquad_cascade_df2T_q15(&filter, pSrc, pDst, blockSize); -
DMA配合双缓冲:
- 配置ADC+DMA实现自动采样
- 使用双缓冲区交替处理:
c复制while(1) { if(adc_buf_ready) { process_buffer(adc_buf_active); swap_buffers(); } }
-
避免中间结果溢出:
- 对32位中间变量使用饱和运算
- 关键代码添加溢出检测:
c复制if(wn > 32767) wn = 32767; if(wn < -32768) wn = -32768;
5. 实际测试与问题排查
5.1 频响特性测试
使用信号发生器+ADC注入扫频信号,实测得到:
- 阻带中心:49.8Hz(与设计值50Hz偏差0.4%)
- -3dB截止频率:47.6Hz和52.3Hz
- 阻带衰减:-42dB(满足工业应用需求)
5.2 常见问题与解决
-
极限频率处增益异常:
- 现象:在0Hz和Nyquist频率处增益不为1
- 原因:双线性变换的频率畸变
- 解决:在设计中预畸变校正频率
-
阶跃响应过冲:
- 现象:输入突变时输出有振荡
- 原因:高阶IIR的相位非线性
- 解决:串联两个2阶滤波器替代4阶设计
-
定点运算累积误差:
- 现象:长时间运行后滤波特性漂移
- 原因:Q15格式的截断误差累积
- 解决:定期重置状态变量或改用Q31格式
关键提示:在最终产品中建议加入滤波器旁路功能,方便对比验证滤波效果。
6. 进阶优化方向
-
自适应陷波:
- 实时检测工频频率变化(如49.5Hz→50.2Hz)
- 动态调整滤波器系数
c复制void Update_Coefficients(float freq) { // 根据新频率重新计算系数 // 使用ARM的浮点运算库 } -
多级滤波架构:
- 第一级:IIR带阻滤除工频
- 第二级:FIR平滑处理相位失真
- 这种组合兼顾了性能和资源消耗
-
硬件加速方案:
- 在STM32H7系列中使用Chrom-ART加速器
- 利用M7内核的Cache优化数据访问
c复制
SCB_EnableDCache(); SCB_EnableICache();
经过实际验证,这个直接II型实现方案在STM32F407上仅消耗:
- 0.8%的CPU资源(运行在168MHz时)
- 2KB的RAM(处理4通道数据)
- 无需外置ADC芯片即可达到80dB的信噪比