文章目录
- EWMA、加权平均与一次低通滤波的对比与选型
-
- 三者解决的共同问题
- 用"权重形状"理解原理与异同点
-
- 加权平均
- [移动平均/加权移动平均(FIR 思路)](#移动平均/加权移动平均(FIR 思路))
-
- [FIR 的通用差分方程](#FIR 的通用差分方程)
- EWMA(指数加权移动平均)
- [一次低通滤波(First-order Low-pass)](#一次低通滤波(First-order Low-pass))
- 核心差异总结
- 优劣势与使用场景
-
- 加权平均
- 加权移动平均(FIR)
- EWMA
- [一次低通滤波(与 EWMA 等价)](#一次低通滤波(与 EWMA 等价))
- [示例 C 代码](#示例 C 代码)
-
- 1) 加权平均(一次性计算) 加权平均(一次性计算))
- 2) 加权移动平均(FIR,线性权重示例) 加权移动平均(FIR,线性权重示例))
- 3) EWMA(递推,固定 ( α ) (\alpha) (α)) EWMA(递推,固定 ( α ) (\alpha) (α)))
- 4) 一次低通(时间常数 ( τ ) (\tau) (τ) 版本,采样间隔可变) 一次低通(时间常数 ( τ ) (\tau) (τ) 版本,采样间隔可变))
- 选型速记

EWMA、加权平均与一次低通滤波的对比与选型
三者解决的共同问题
三者都用于把"抖动/噪声较大"的观测序列变成更稳定的信号,从而更适合做展示、阈值判断、控制调节等。其共同代价是:越平滑,越容易产生滞后(变化被延迟反映)。(维基百科)
用"权重形状"理解原理与异同点
加权平均
对一组样本按权重求和(一次性计算),不要求时间连续,也不内置"上一时刻状态"的概念:
y = ∑ i = 0 N − 1 w i x i ∑ i = 0 N − 1 w i \] \[ y=\\frac{\\sum_{i=0}\^{N-1} w_i x_i}{\\sum_{i=0}\^{N-1} w_i} \] \[y=∑i=0N−1wi∑i=0N−1wixi
- 权重 (w_i) 可任意设计(线性、分段、业务权重等)
- 需要拿到整组样本(或至少拿到一个窗口内的样本)
移动平均/加权移动平均(FIR 思路)
在固定窗口内做平均或加权平均,窗口之外权重为 0,因此是典型 FIR(有限冲激响应) :冲激响应在有限长度后严格为 0。(维基百科)
"移动平均滤波"是最典型的 FIR 例子之一,用于降低随机噪声。(analog.com)
FIR 的通用差分方程
长度为 (M) 的因果 FIR 滤波器可用"有限卷积"表示:
y \[ n \] = ∑ k = 0 M − 1 b k , x \[ n − k \] \] \[ y\[n\]=\\sum_{k=0}\^{M-1} b_k,x\[n-k\] \] \[y\[n\]=k=0∑M−1bk,x\[n−k\]
其中 ( b 0 , ... , b M − 1 ) ({b_0,\dots,b_{M-1}}) (b0,...,bM−1) 就是 FIR 系数(也等同于有限冲激响应 ( h [ k ] ) (h[k]) (h[k]))。
EWMA(指数加权移动平均)
EWMA 采用递推更新,只保留一个状态值,用指数衰减方式"记住历史":
S t = α x t + ( 1 − α ) S t − 1 \] \[ S_t=\\alpha x_t+(1-\\alpha)S_{t-1} \] \[St=αxt+(1−α)St−1
NIST 的"简单指数平滑(Single Exponential Smoothing)"给出了同类递推形式,并直接把平滑序列称为 EWMA。(NIST)
一次低通滤波(First-order Low-pass)
在离散实现中,一次低通常写为:
y t = y t − 1 + α ( x t − y t − 1 ) ⇒ y t = α x t + ( 1 − α ) y t − 1 \] \[ y_t=y_{t-1}+\\alpha(x_t-y_{t-1}) \\Rightarrow y_t=\\alpha x_t+(1-\\alpha)y_{t-1} \] \[yt=yt−1+α(xt−yt−1)⇒yt=αxt+(1−α)yt−1
该差分形式与 EWMA 在数学上等价,只是命名与参数语义更偏"滤波/控制"。一些工程资料也直接将该类指数滤波称为 EWMA/指数平滑,并指出其是"一阶滞后/一阶惯性"的离散等价。(gregstanleyandassociates.com)
核心差异总结
| 维度 | 加权平均 | (加权)移动平均 FIR | EWMA | 一次低通 |
|---|---|---|---|---|
| 结构 | 一次性求和 | 有限窗口卷积 | 递推 + 反馈 | 递推 + 反馈 |
| 记忆 | 仅样本集合 | 严格只看最近 N 个 | 指数衰减,无"硬截断" | 与 EWMA 等价 |
| 存储 | 需要样本集合 | 需保存 N 个样本 | 仅 1 个状态 | 仅 1 个状态 |
| 更新开销 | O(N) | 通常 O(N) | O(1) | O(1) |
| 响应/滞后 | 取决于权重 | 窗口越大越滞后 | (\alpha) 越小越滞后 | (\alpha)/(\tau) 越大越滞后 |
| 稳定性 | 非滤波器概念 | FIR 天然稳定 | IIR 取决于系数 | IIR 取决于系数 |
- FIR 的"有限冲激响应/有限记忆"特征:窗口外影响严格为 0。(维基百科)
- IIR 的"无限冲激响应"来自对历史输出的依赖(反馈),冲激响应理论上不会在有限时间完全变为 0。(维基百科)
- FIR 通常具有更直观的稳定性特征(讲义中给出 FIR 稳定性结论)。(ETH Zürich)
优劣势与使用场景
加权平均
优势
- 权重可完全按业务语义设计(例如对不同来源、不同质量样本赋权)
- 输出解释直观:就是"按权重的平均"
劣势
- 流式场景需要缓存样本或维护窗口,无法天然 O(1) 在线更新
- 需要明确"平均对象是什么"(一批样本、一个窗口、一个周期)
适用场景
- 分数融合、指标合成、一次性评估(离线/批处理)
- 明确知道要综合的样本集合(例如一次请求内多个子结果合并)
加权移动平均(FIR)
优势
- "只看最近 N 个"的语义清晰,窗口之外完全遗忘
- 对某些 FIR 结构可获得线性相位等性质(在信号处理里常见)
劣势
- 需要保存 N 个样本;N 大时内存与计算成本明显
- 对突变同样会滞后,且窗口越大滞后越明显
适用场景
- 需要严格窗口定义(最近 60 秒、最近 100 次)
- 对滤波器性质(如线性相位)有明确要求的 DSP 场景
- 更新频率较低或窗口较小的在线平滑
EWMA
优势
- 只维护一个状态,单次更新 O(1),非常适合热路径/实时路径
- 对噪声抑制强,且"近期样本权重更大"符合很多趋势判断需求(指数衰减)
劣势
- 没有"硬窗口边界",旧数据影响只会渐近变小而非突然归零
- 平滑引入滞后;(\alpha) 选得过小会导致对变化过迟钝
适用场景
- 压力/拥塞/忙碌度趋势(队列长度、重试率、丢包率、负载)
- 动态控制:用平滑后的信号调节并发度、批量大小、速率
- 指标展示:吞吐、延迟、利用率等需要更稳定的曲线(指数平滑常被视为低通去高频噪声)。(维基百科)
一次低通滤波(与 EWMA 等价)
优势
- 与 EWMA 同样是 O(1) 状态、O(1) 更新
- 参数可以用"时间常数 (\tau)"表达,便于在采样间隔变化时保持语义一致(按真实时间衰减)
劣势
- 与 EWMA 相同:必然滞后
- 若采样间隔变化但仍固定 ( α ) (\alpha) (α),滤波语义会漂移(需要时间归一化)
适用场景
- 传感器信号、控制量平滑(工程上常以"一阶惯性/一阶低通"描述)
- 采样周期不恒定的事件驱动更新(用 ( τ ) + ( Δ t ) (\tau) + (\Delta t) (τ)+(Δt) 动态算系数)
示例 C 代码
1) 加权平均(一次性计算)
c
#include <stddef.h>
double weighted_average(const double *x, const double *w, size_t n) {
double num = 0.0;
double den = 0.0;
for (size_t i = 0; i < n; i++) {
num += w[i] * x[i];
den += w[i];
}
return (den == 0.0) ? 0.0 : (num / den);
}
2) 加权移动平均(FIR,线性权重示例)
- 最新样本权重最大,越旧权重越小
- 需要环形缓冲区保存窗口内样本
c
#include <stddef.h>
typedef struct {
double *buf;
size_t cap; // window size
size_t idx; // next write position
size_t len; // current filled length
} wma_t;
void wma_push(wma_t *w, double x) {
w->buf[w->idx] = x;
w->idx = (w->idx + 1) % w->cap;
if (w->len < w->cap) w->len++;
}
double wma_eval_linear(const wma_t *w) {
if (w->len == 0) return 0.0;
double num = 0.0, den = 0.0;
// newest -> oldest
for (size_t k = 0; k < w->len; k++) {
size_t pos = (w->idx + w->cap - 1 - k) % w->cap;
double weight = (double)(w->len - k); // len, len-1, ..., 1
num += weight * w->buf[pos];
den += weight;
}
return num / den;
}
3) EWMA(递推,固定 ( α ) (\alpha) (α))
NIST 的简单指数平滑属于同类递推结构。(NIST)
c
typedef struct {
double s;
int initialized;
} ewma_t;
double ewma_update(ewma_t *e, double x, double alpha) {
// alpha in (0, 1]
if (!e->initialized) {
e->s = x;
e->initialized = 1;
return e->s;
}
e->s = alpha * x + (1.0 - alpha) * e->s;
return e->s;
}
4) 一次低通(时间常数 ( τ ) (\tau) (τ) 版本,采样间隔可变)
该写法常用于把"滤波强度"用时间常数表达,并按 ( Δ t ) (\Delta t) (Δt) 做指数衰减;工程资料也将其视为离散的一阶滞后/指数滤波。(gregstanleyandassociates.com)
c
#include <math.h>
#include <stdint.h>
typedef struct {
double y;
uint64_t last_ts; // timestamp, same unit as tau
int initialized;
} lp1_t;
// now_ts 与 tau 使用同一时间单位(例如都用 ns 或都用 ms)
// 编译时若使用 GCC/Clang,可能需要链接 -lm
double lowpass1_update(lp1_t *f, double x, uint64_t now_ts, double tau) {
if (!f->initialized) {
f->y = x;
f->last_ts = now_ts;
f->initialized = 1;
return f->y;
}
uint64_t dt_u = now_ts - f->last_ts;
double dt = (double)dt_u;
// alpha = 1 - exp(-dt/tau)
double alpha = 1.0 - exp(-dt / tau);
f->y = alpha * x + (1.0 - alpha) * f->y;
f->last_ts = now_ts;
return f->y;
}
选型速记
- 必须严格只看最近 N 个样本 :选(加权)移动平均(FIR),窗口语义明确。(维基百科)
- 必须 O(1) 在线更新,且只需要趋势 :选 EWMA / 一次低通(本质等价)。(NIST)
- 采样间隔不稳定但仍想保持"按时间"衰减语义 :选"一次低通的 (\tau)+(\Delta t)"动态系数版本。(gregstanleyandassociates.com)