指数移动平均(Exponential Moving Average, EMA)详解

指数移动平均是加权移动平均的一种特殊形式,它对历史数据的权重呈指数衰减:越新的数据权重越大,越老的数据权重越小。
这使得 EMA 对近期变化响应更快,同时计算量极低(只需一次乘法 + 一次加法),适合实时嵌入式系统、传感器去噪、姿态融合、金融K线等场景。

核心公式(KaTeX)

[
EMA_t = \alpha \cdot x_t + (1 - \alpha) \cdot EMA_{t-1}
]

其中:

  • ( x_t ):当前时刻原始采样值
  • ( \alpha ):平滑因子(0 < α ≤ 1),越大越重视新数据
  • ( EMA_{t-1} ):上一次 EMA 值(初始值通常取 ( x_0 ) 或简单平均)

α 的常见计算方式(按周期 N):
[
\alpha = \frac{2}{N + 1}
]

  • N=5 → α≈0.333(最近数据权重约33%)
  • N=10 → α≈0.182
  • N=20 → α≈0.095(更平滑)

等价递归形式(更常用):
[
EMA_t = EMA_{t-1} + \alpha \cdot (x_t - EMA_{t-1})
]

EMA vs 简单移动平均(SMA)的本质区别

项目 EMA SMA(简单移动平均)
权重 指数衰减(新数据权重最高) 均匀权重
对突变的响应 更快(滞后 ≈ 1/α) 滞后 ≈ (N-1)/2 个采样点
历史记忆 无限(但老数据权重趋近0) 严格只看最近 N 个点
计算量 O(1)(只需上次结果) O(N)(每次都要重新求和)
相位延迟 固定且较大
典型应用 姿态融合、电池SOC、实时趋势 温度/压力等极慢变信号

优点

  • 实时性极高(嵌入式单片机只需 2 行代码)
  • 对白噪声抑制好,同时保留趋势
  • 初始值收敛快(几周期后就稳定)

缺点

  • 对尖峰脉冲噪声(盐椒噪声)敏感(会把尖峰“拉”进趋势)
  • α 调不好会过冲或响应太慢

C# 极简实现(推荐直接复制):

public class EMAFilter
{
    private double ema;
    private readonly double alpha;

    public EMAFilter(double period = 10)
    {
        alpha = 2.0 / (period + 1);
        ema = 0; // 第一次用 rawValue 初始化
    }

    public double Update(double newValue)
    {
        if (Math.Abs(ema) < 1e-9) ema = newValue; // 首次初始化
        ema = alpha * newValue + (1 - alpha) * ema;
        return ema;
    }
}

中值滤波算法(Median Filter)详解

中值滤波是非线性滤波器,专门针对脉冲噪声(盐椒噪声、尖峰干扰)设计。它不做平均,而是把窗口内数据排序后取中间值,因此能完全剔除极端异常值,同时完美保留信号边沿(阶跃、方波)。

算法步骤

  1. 取当前时刻前后共 2k+1 个数据(奇数窗口长度,常见 3、5、7)
  2. 对这 2k+1 个数进行排序
  3. 输出排序后的中间值(第 k+1 个)

窗口长度为 5 的示例如下(假设原始序列含一个大尖峰):
原始窗口:[10, 12, 50, 11, 13]
排序后:[10, 11, 12, 13, 50]
→ 中值 = 12(完美剔除 50)

数学表达

[
y[n] = \text{median}{ x[n-k], \dots, x[n], \dots, x[n+k] }
]

C# 实现(窗口长度可配置):

public class MedianFilter
{
    private readonly double[] buffer;
    private readonly int windowSize; // 必须为奇数
    private int index = 0;

    public MedianFilter(int size = 5)
    {
        windowSize = size;
        buffer = new double[size];
    }

    public double Update(double newValue)
    {
        buffer[index] = newValue;
        index = (index + 1) % windowSize;

        // 复制 + 排序(小窗口效率极高)
        double[] sorted = (double[])buffer.Clone();
        Array.Sort(sorted);
        return sorted[windowSize / 2];
    }
}

中值滤波对比分析(2025–2026 工程视角)

以下表格把中值滤波与前面讲过的几种主流滤波器做全面对比(针对传感器数据:IMU、Vce、温度、压力等):

滤波器类型 噪声类型最擅长 边沿/阶跃保留能力 计算量(单次) 延迟 对白噪声抑制 对脉冲噪声抑制 典型应用场景 推荐场景优先级(传感器)
中值滤波 盐椒/脉冲/尖峰 ★★★★★(最佳) O(N log N) (N-1)/2 ★★ ★★★★★ 编码器、超声、激光、Vce异常剔除 ★★★★★(有尖峰时首选)
简单移动平均 白噪声/高斯噪声 ★★ O(N) (N-1)/2 ★★★★ ★★ 温度、液位、慢变信号 ★★★☆
指数移动平均 白噪声 + 趋势提取 ★★★ O(1) ≈1/α ★★★★ ★★ IMU 融合、SOC、实时趋势 ★★★★★(计算资源紧张)
Kalman/EKF 多传感器融合 + 动态模型 ★★★★ O(状态维度²) 极小 ★★★★★ ★★★★ 无人机、机器人、自动驾驶 ★★★★★(高精度需求)
Madgwick/Mahony IMU 噪声 + 漂移 ★★★★ O(1) 极小 ★★★★ ★★★ 9轴姿态融合 ★★★★★(姿态专用)

中值滤波独有优势

  • 完全免疫极端异常值(只要窗口内异常值不超过一半,就不会影响输出)—— 这是 EMA/SMA/Kalman 都做不到的
  • 边沿无模糊(阶跃信号几乎零延迟保留)—— 适合位置、距离、开关信号
  • 实现最简单(排序 + 取中位数)

中值滤波局限

  • 对白噪声(随机抖动)抑制较弱(输出仍会小幅抖)
  • 计算量比 EMA 大(但窗口 5~7 时单片机完全无压力)
  • 不适合需要“趋势预测”的场景(EMA/Kalman 更优)

组合使用推荐(工业最优实践)

  1. 先中值滤波(窗口 5)→ 剔除尖峰
  2. 再接 EMA(N=10)→ 平滑剩余白噪声
  3. 最后可选 Kalman 做多传感器融合

实际测试建议(针对你之前的 Vce 数据):

  • 中值滤波(窗口 5)对 0、-1、0.2、0.11 这类极端值一次性剔除,输出直接稳定在 0.45
  • EMA(α=0.2)也能稳定,但如果出现连续 3 个 0,会轻微拉低趋势
  • 结论:有明显脉冲噪声时优先中值;纯白噪声 + 需要极低计算量时选 EMA

你现在是想把这些滤波器应用到 VceSat / IMU / 温度哪个场景?
需要我给你中值 + EMA 级联 C# 代码窗口长度自动推荐公式,还是与你之前 FilterVceAndUpdate 的融合版?随时告诉我,我立刻给出完整可运行实现!

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐