2. 角度数据滤波处理
任务目标
AS5048磁编码器在静止或低速场景下,原始角度数据通常包含±0.2°左右的随机噪声。本案例实现一个环形缓冲区滑动平均滤波器,对连续N次采样取均值,以降低噪声、提高角度读数稳定性。滤波后角度仍保持原始分辨率(0.0219°/LSB),不引入额外延迟补偿。
核心实现
// angle_filter.h
#ifndef ANGLE_FILTER_H
#define ANGLE_FILTER_H
#include <stdint.h>
#define FILTER_WINDOW_SIZE 8 // 滑动窗口长度(2的幂,便于取模)
typedef struct {
uint16_t buffer[FILTER_WINDOW_SIZE];
uint8_t index; // 当前写入位置
uint32_t sum; // 窗口内数据和
uint8_t count; // 已填充样本数
} AngleFilter;
void filter_init(AngleFilter *f);
uint16_t filter_add(AngleFilter *f, uint16_t raw_angle);
#endif // ANGLE_FILTER_H
// angle_filter.c
#include "angle_filter.h"
void filter_init(AngleFilter *f) {
f->index = 0;
f->sum = 0;
f->count = 0;
for (int i = 0; i < FILTER_WINDOW_SIZE; i++) {
f->buffer[i] = 0;
}
}
uint16_t filter_add(AngleFilter *f, uint16_t raw_angle) {
// 若窗口已满,先减去最旧样本
if (f->count == FILTER_WINDOW_SIZE) {
f->sum -= f->buffer[f->index];
} else {
f->count++;
}
// 写入新样本并更新和
f->buffer[f->index] = raw_angle;
f->sum += raw_angle;
// 环形索引前进
f->index = (f->index + 1) & (FILTER_WINDOW_SIZE - 1);
// 返回窗口均值(四舍五入)
return (uint16_t)((f->sum + (f->count >> 1)) / f->count);
}
// main.c 示例调用(假设AS5048通过SPI读取)
#include <stdio.h>
#include "angle_filter.h"
// 模拟AS5048 SPI读取函数(实际项目中替换为硬件驱动)
uint16_t as5048_read_raw(void) {
// 此处返回14位角度值(0~16383)
// 实际使用时替换为SPI读取命令:0xFFFF & (spi_transfer(0xFE) << 8 | spi_transfer(0x00))
static uint16_t sim = 8192;
sim = sim + (rand() % 5) - 2; // 模拟±2 LSB噪声
return sim & 0x3FFF;
}
int main(void) {
AngleFilter filter;
filter_init(&filter);
for (int i = 0; i < 20; i++) {
uint16_t raw = as5048_read_raw();
uint16_t filtered = filter_add(&filter, raw);
printf("raw=%5u filtered=%5u\n", raw, filtered);
}
return 0;
}
运行与验证
- 编译:将上述三个文件置于同一目录,执行
gcc -o angle_filter main.c angle_filter.c。 - 运行:
./angle_filter,观察输出中raw与filtered的波动幅度。 - 通过条件:当输入噪声为±2 LSB时,滤波后输出波动应明显小于原始波动(通常降至±1 LSB以内)。窗口越大平滑效果越强,但响应延迟增加。
关键说明
- 窗口长度设为8(2的幂),使
index回绕可用位运算实现,避免取模开销。 - 滤波器输出为窗口内整数均值,采用四舍五入避免截断偏差。
- AS5048原始角度为14位(0~16383),滤波后仍保持该范围,可直接用于后续FOC电角度计算。
- 若需处理角度跨越0°/360°边界(如从359°变到1°),需在滤波前对原始值做角度展开处理,本案例聚焦静态噪声抑制,不涉及该场景。