4、软件滤波:滑动平均滤波、中值滤波、卡尔曼滤波在母线电压采样中的应用

母线电压采样,说白了就是FOC控制系统的「眼睛」。

眼睛要是花了,电机肯定跑不稳。我见过太多工程师,算法调得天花乱坠,结果一上电,母线电压跳得像心电图,最后全白费。

今天咱们就聊聊,怎么用软件把这双「眼睛」擦亮。

4.1 为什么需要软件滤波?

硬件上我们通常会加RC低通滤波,但有个问题——RC滤波会带来相位延迟。你想想看,母线电压采样要是滞后了,电流环的响应速度立马打折。

我个人的习惯是:硬件做粗滤,软件做精滤。硬件把高频毛刺干掉,软件负责处理那些低频的、周期性的波动。

核心观点:软件滤波不是万能的,但它能解决硬件解决不了的问题。比如电机突然加载导致的电压跌落,硬件RC根本来不及反应,但软件滤波可以做到「预测性补偿」。

4.2 滑动平均滤波

这是最基础、也最常用的方法。说白了就是取最近N次采样值的平均值。

数学表达式:

y[n] = (x[n] + x[n-1] + ... + x[n-N+1]) / N

代码实现(C语言):

#define WINDOW_SIZE 16

static uint16_t buffer[WINDOW_SIZE];
static uint8_t index = 0;
static uint32_t sum = 0;

uint16_t moving_average(uint16_t new_sample) {
    sum -= buffer[index];
    buffer[index] = new_sample;
    sum += new_sample;
    index = (index + 1) % WINDOW_SIZE;
    return sum / WINDOW_SIZE;
}

我踩过的坑:

我曾经在一个项目中,把窗口大小设成了64。结果电机启动时,母线电压明明已经掉到24V了,滤波输出还显示26V。为什么?窗口太大,响应太慢!

经验值:对于1kHz的采样率,窗口大小建议在8~16之间。既能滤掉开关噪声,又不至于让响应滞后超过10ms。

4.3 中值滤波

滑动平均最怕什么?怕「野值」。比如ADC偶尔采到一个异常值,滑动平均会被拉偏。中值滤波就是专门对付这种「毛刺」的。

原理:取N个采样值,排序后取中间那个。

uint16_t median_filter(uint16_t *data, uint8_t len) {
    uint16_t temp[len];
    for(uint8_t i = 0; i < len; i++) temp[i] = data[i];
    
    // 冒泡排序,只排一半就够了
    for(uint8_t i = 0; i < len/2 + 1; i++) {
        for(uint8_t j = 0; j < len - i - 1; j++) {
            if(temp[j] > temp[j+1]) {
                uint16_t t = temp[j];
                temp[j] = temp[j+1];
                temp[j+1] = t;
            }
        }
    }
    return temp[len/2];
}

注意:中值滤波的窗口大小必须是奇数。3、5、7都行。我建议用5,排序计算量不大,效果也够用。

什么时候用中值滤波?

  • 采样信号偶尔出现尖峰脉冲(比如IGBT开关瞬间的耦合噪声)
  • ADC参考电压不稳定导致的偶发跳变
  • 通信干扰导致的异常数据

4.4 卡尔曼滤波

嗯,说到卡尔曼滤波,很多朋友会觉得「高大上」、「难懂」。其实没那么玄乎。

卡尔曼滤波的核心思想就一句话:用模型预测 + 用测量修正

对于母线电压来说,我们可以建立一个简单的模型:

  • 状态量:母线电压 Vbus
  • 过程噪声:负载变化引起的电压波动
  • 测量噪声:ADC采样噪声

简化的一维卡尔曼滤波:

typedef struct {
    float x;      // 估计值
    float p;      // 估计误差协方差
    float q;      // 过程噪声协方差
    float r;      // 测量噪声协方差
    float k;      // 卡尔曼增益
} Kalman_1D;

void kalman_init(Kalman_1D *kf, float init_val) {
    kf->x = init_val;
    kf->p = 1.0f;
    kf->q = 0.01f;   // 根据实际调整
    kf->r = 0.1f;    // 根据ADC噪声调整
}

float kalman_update(Kalman_1D *kf, float measurement) {
    // 预测
    kf->p = kf->p + kf->q;
    
    // 更新
    kf->k = kf->p / (kf->p + kf->r);
    kf->x = kf->x + kf->k * (measurement - kf->x);
    kf->p = (1.0f - kf->k) * kf->p;
    
    return kf->x;
}

关键参数调优:

参数 含义 调大 调小
Q 过程噪声 响应更快,但波动大 响应慢,更平滑
R 测量噪声 更信任模型预测 更信任实际测量

我个人的经验:

卡尔曼滤波在母线电压采样中,最大的优势是无相位延迟。滑动平均和中值滤波都会引入延迟,但卡尔曼滤波能做到「实时跟踪」。我在做伺服驱动器时,用卡尔曼滤波替代了滑动平均,电流环带宽直接提升了15%。

4.5 三种滤波方法的对比

方法 延迟 计算量 抗野值 适用场景
滑动平均 噪声平稳的场合
中值滤波 偶发尖峰噪声
卡尔曼滤波 中高 需要实时跟踪的场合

4.6 实战建议:组合使用

说实话,我很少只用一种滤波方法。实际项目中,我通常这样搭配:

  1. 第一级:中值滤波(窗口=5)—— 干掉ADC的偶发毛刺
  2. 第二级:卡尔曼滤波 —— 平滑处理,同时保持低延迟

为什么这么搭?中值滤波负责「剔除坏数据」,卡尔曼滤波负责「平滑好数据」。各司其职,效果最好。

避坑指南:我曾经在一个项目中,只用了滑动平均,结果电机低速运行时,母线电压采样值一直有周期性波动。后来发现是PWM开关频率和采样频率产生了差拍。换成卡尔曼滤波后,问题立刻解决。

4.7 知识体系总览

下面这张图,帮你理清三种滤波方法在母线电压采样中的定位:

母线电压软件滤波方案 ADC原始采样值 滑动平均滤波 窗口大小8~16 中值滤波 窗口大小5(奇数) 卡尔曼滤波 一维模型,无延迟 滤波后的母线电压值 → 送入FOC电流环/速度环 实际项目中建议:中值滤波(去毛刺)+ 卡尔曼滤波(平滑跟踪)组合使用

嗯,三种方法各有千秋。滑动平均最简单,中值滤波最抗噪,卡尔曼滤波最智能。选哪个,取决于你的项目对延迟和计算资源的容忍度。

我个人建议:先从中值滤波+卡尔曼滤波的组合开始试。如果MCU算力紧张,再退回到滑动平均。别一上来就追求「高大上」,稳定可靠才是第一位的。


公众号:蓝海资料掘金营,微信deep3321