最近在折腾一个传感器信号处理的项目,发现原始数据里总有些低频干扰挥之不去。得嘞,撸起袖子给STM32整了个FIR高通滤波器。咱不整那些虚的,直接上干货
·
STM32开发 FIR高通滤波器 STM32实现FIR有限冲击响应高通滤波器,自编代码,汉明窗,送MATLAB程序,代码注释详细

先别急着写代码,咱们得先搞定滤波器系数。掏出MATLAB,20阶高通滤波器走起:
order = 20;
cutoff = 0.4; % 归一化截止频率
h = fir1(order, cutoff, 'high', hamming(order+1));
fprintf('{%.8ff, ', h(1:end-1));
fprintf('%.8ff}', h(end));
这段脚本直接生成汉明窗加权的滤波器系数,打印成C数组格式。注意这里截止频率别设太高,0.4对应实际采样频率的40%。比如采样率1kHz的话,截止就是200Hz。

接下来STM32这边,直接上硬核代码。先整个环形缓冲区管理输入数据:
#define FILTER_ORDER 20
float buffer[FILTER_ORDER+1];
uint8_t buf_index = 0;
void push_sample(float new_sample) {
buffer[buf_index] = new_sample;
buf_index = (buf_index + 1) % (FILTER_ORDER+1);
}
这个环形缓冲区的骚操作在于,每次新数据覆盖最老的数据,省去了数组整体移动的开销。注意FILTER_ORDER+1的缓冲区长度,刚好装下当前窗口的所有采样点。

STM32开发 FIR高通滤波器 STM32实现FIR有限冲击响应高通滤波器,自编代码,汉明窗,送MATLAB程序,代码注释详细

卷积运算才是重头戏,直接手撸:
float fir_filter(float *coeffs) {
float output = 0.0f;
uint8_t index = buf_index;
for(int i=0; i<=FILTER_ORDER; i++){
if(index == 0) index = FILTER_ORDER;
output += coeffs[i] * buffer[index];
index--;
}
return output;
}
这里倒着取缓冲区数据的操作是关键,因为新数据总在buf_index位置,老数据顺时针排列。用if判断代替取模运算,实测能省20%计算时间。
实际工程里记得把系数转成Q15格式,上ARM的DSP库加速:
#include "arm_math.h"
arm_fir_instance_f32 fir;
float fir_state[FILTER_ORDER + BLOCK_SIZE -1];
void filter_init() {
arm_fir_init_f32(&fir, FILTER_ORDER+1, hamming_coeffs, fir_state, BLOCK_SIZE);
}
void process_block(float *input, float *output) {
arm_fir_f32(&fir, input, output, BLOCK_SIZE);
}
用DSP库的批处理模式,一次处理一个数据块,比单点处理快3倍不止。注意state数组要足够大,别溢出。
调试时遇到过坑:直接浮点运算在F103上慢成狗,后来切到CMSIS-DSP的定点库,Q15格式配合armfirq15,速度直接起飞。不过要小心系数缩放,搞不好就溢出。建议先用MATLAB验证定点化的误差:
q15_coeffs = int16(h * 32767);
最后在main函数里这么用:
while(1) {
float raw = read_adc();
push_sample(raw);
float filtered = fir_filter(coeffs);
printf("%f\t%f\n", raw, filtered);
}
实测效果拔群,50Hz工频干扰被干得服服帖帖。完整工程丢在Github了,需要自取。记住滤波器阶数不是越高越好,够用就行,STM32F4跑100阶滤波器照样轻松。
更多推荐


所有评论(0)