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;
}

运行与验证

  1. 编译:将上述三个文件置于同一目录,执行 gcc -o angle_filter main.c angle_filter.c。
  2. 运行:./angle_filter,观察输出中raw与filtered的波动幅度。
  3. 通过条件:当输入噪声为±2 LSB时,滤波后输出波动应明显小于原始波动(通常降至±1 LSB以内)。窗口越大平滑效果越强,但响应延迟增加。

关键说明

  • 窗口长度设为8(2的幂),使index回绕可用位运算实现,避免取模开销。
  • 滤波器输出为窗口内整数均值,采用四舍五入避免截断偏差。
  • AS5048原始角度为14位(0~16383),滤波后仍保持该范围,可直接用于后续FOC电角度计算。
  • 若需处理角度跨越0°/360°边界(如从359°变到1°),需在滤波前对原始值做角度展开处理,本案例聚焦静态噪声抑制,不涉及该场景。