对随时间变化的数据做 "平滑处理": EWMA

16 阅读2分钟

image.png

这个算法是指数加权移动平均(EWMA, Exponentially Weighted Moving Average),常用于对随时间变化的数据做“平滑处理”(给近期数据更高权重,远期数据更低权重)。

核心要素说明

  1. 参数 a

    • 取值范围是 0 ≤ a ≤ 1,它是“折扣系数”(也叫平滑系数)。
    • a 越接近 1:旧数据的权重越高,新数据的影响越小,结果越平滑;
    • a 越接近 0:新数据的权重越高,结果更“紧跟”最新数据。
  2. 函数逻辑 estimate_rate_pps(instant_rate, old_rate): 这个函数的作用是结合“当前瞬时速率(instant_rate)”和“历史旧速率(old_rate)”,计算新的平滑后速率。 公式为: 新速率=(1a)×instant_rate+a×old_rate\text{新速率} = (1-a) \times \text{instant\_rate} + a \times \text{old\_rate}

    • (1-a) 是“当前瞬时速率”的权重;
    • a 是“历史旧速率”的权重;
    • 本质是加权平均:用固定的系数 a 对新、旧数据做“折扣式”融合。

举个例子

比如 a=0.8,当前瞬时速率是 10,旧速率是 5新速率=(10.8)×10+0.8×5=0.2×10+0.8×5=2+4=6\text{新速率} = (1-0.8) \times 10 + 0.8 \times 5 = 0.2 \times 10 + 0.8 \times 5 = 2 + 4 = 6 能看到:旧数据(5)的权重更高,新速率更贴近旧值。

image.png

这是EWMA算法的具体代码实现,核心是把“折扣系数a”和“平滑逻辑”落地成代码,同时用“定点数(fixed point)”处理数值(避免浮点精度问题)。

逐行拆解逻辑

  1. 计算折扣系数a

    fpoint a = to_fixed_point(dur) / WINDOW;
    
    • dur:通常是“时间间隔”(比如两次数据更新的时间差);
    • to_fixed_point(dur):把dur转成定点数格式(用整数模拟小数,避免浮点误差);
    • WINDOW:是一个“时间窗口常数”(比如希望让数据在多长时间内完成平滑);
    • 所以a的本质是:a = 时间间隔 / 时间窗口,保证0 ≤ a ≤ 1(符合EWMA的参数要求)。
  2. 初始化新速率

    fpoint new_rate = old_rate;
    

    先把“新速率”初始化为“旧速率”,后续再根据当前值调整。

  3. 根据当前值调整新速率 核心是让新速率向“当前瞬时速率(rate_current)”靠近,靠近的幅度由a控制

    if (old_rate > to_fixed_point(rate_current)) {
        // 旧速率 > 当前速率 → 新速率 = 旧速率 - a*(旧速率-当前速率)
        new_rate -= a * to_int(old_rate - to_fixed_point(rate_current));
    } else {
        // 旧速率 ≤ 当前速率 → 新速率 = 旧速率 + a*(当前速率-旧速率)
        new_rate += a * to_int(to_fixed_point(rate_current) - old_rate);
    }
    
    • to_fixed_point(rate_current):把“当前瞬时速率”转成定点数;
    • to_int(...):把定点数的差值转成整数(配合定点数运算规则);
    • 本质等价于之前的EWMA公式:new_rate = (1-a)*rate_current + a*old_rate(只是拆成“加减”形式实现)。
  4. 返回新速率

    return new_rate;
    

总结

这段代码是**“定点数版的EWMA实现”**:用a = 时间间隔/时间窗口控制平滑幅度,通过“旧速率向当前速率逐步靠近”的逻辑,实现数据的指数加权平滑,同时用定点数避免浮点运算的精度问题。