2. 时域滤波入门:移动平均滤波原理、参数窗口长度对平滑效果的影响

各位同学,欢迎来到时域滤波的第一站。

说实话,很多做信号处理的朋友一上来就怼着FFT、小波变换猛学,结果连最简单的移动平均滤波都没吃透。我个人觉得,这其实是个误区。移动平均滤波虽然简单,但它背后藏着时域滤波最核心的思维——用相邻点的信息来修正当前点。这个思路,贯穿了整个滤波体系。

2.1 移动平均滤波的原理

移动平均滤波,说白了就是“取邻居的平均值”。

假设你有一个信号序列 x[n],经过移动平均滤波后,输出 y[n] 的计算公式是:

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

这里的 N 就是窗口长度。每次取当前点及其前面 N-1 个点,算个算术平均,作为当前点的输出。

我刚开始做音频降噪时,觉得这玩意儿太简单了,不就是个低通滤波嘛。后来在项目中踩过坑才明白——简单的东西,往往最难用好。

核心要点:移动平均滤波的本质是一个 FIR 低通滤波器,其频率响应是一个 sinc 函数形状。窗口越长,截止频率越低,平滑效果越强。

2.2 窗口长度 N 的影响

窗口长度 N 是移动平均滤波唯一可调的参数。它的影响非常直观,但细节里藏着魔鬼。

窗口长度 N 平滑效果 频率响应 典型应用场景
N=2~3 轻微平滑,保留细节 截止频率较高 去除高频毛刺、传感器瞬态噪声
N=5~10 中等平滑,去除明显抖动 截止频率适中 语音信号包络提取、ECG基线漂移去除
N=20~50 强平滑,信号轮廓保留 截止频率较低 趋势分析、低频振动信号处理
N>100 极度平滑,细节几乎消失 截止频率极低 直流分量提取、超低频趋势分析

你想想看,窗口越长,参与平均的点越多,随机噪声被抵消得越干净。但代价是什么?信号的突变也会被抹平。

我记得有一次做语音端点检测,用了 N=15 的移动平均滤波来平滑能量曲线。结果发现语音的起始点被拖后了将近 100 毫秒。嗯,这就是窗口长度带来的群延迟问题。

避坑指南:移动平均滤波会引入 (N-1)/2 个采样点的群延迟。如果你做的是实时系统,这个延迟必须考虑进去。我曾经在一个对讲机项目里忽略了这一点,结果说话的回声感特别明显,被测试同事吐槽了好久。

2.3 频率响应的直观理解

移动平均滤波的频率响应可以用下面这个公式表示:

H(f) = sin(π f N) / (N * sin(π f))

这个公式看起来有点吓人,但它的形状其实很规律。第一个零点出现在 f = 1/N 的位置。也就是说,窗口长度 N 决定了你能滤掉的最低频率。

举个例子:

  • N=10 时,第一个零点在 f=0.1(归一化频率),意味着周期为 10 个采样点的波动会被完全消除。
  • N=50 时,第一个零点在 f=0.02,周期为 50 个采样点的波动被消除。

我个人习惯用这个规律来快速估算:想要滤掉周期为 T 的噪声,窗口长度至少取 T 的 1.5~2 倍。这样能保证噪声被有效衰减,同时信号的主要成分损失不大。

2.4 代码实现与效果对比

下面是一个简单的 Python 实现,你可以直接跑跑看:

import numpy as np
import matplotlib.pyplot as plt

def moving_average(x, N):
    """移动平均滤波"""
    y = np.zeros_like(x)
    for n in range(len(x)):
        if n < N - 1:
            y[n] = np.mean(x[:n+1])  # 起始段处理
        else:
            y[n] = np.mean(x[n-N+1:n+1])
    return y

# 生成测试信号:正弦波 + 高斯噪声
fs = 1000  # 采样率 1kHz
t = np.arange(0, 1, 1/fs)
x = np.sin(2 * np.pi * 5 * t) + 0.5 * np.random.randn(len(t))

# 不同窗口长度滤波
y3 = moving_average(x, 3)
y10 = moving_average(x, 10)
y30 = moving_average(x, 30)

# 这里省略绘图代码,建议你实际运行观察效果

运行这段代码你会发现:

  • N=3 时,噪声还有不少残留,但信号波形基本没变。
  • N=10 时,噪声明显减少,但正弦波的峰值略微降低。
  • N=30 时,噪声几乎看不见了,但正弦波的幅度被削掉了一大截,波形也变得圆润。

这就是平滑效果与信号保真度之间的权衡。没有完美的参数,只有适合你应用场景的参数。

实用技巧:如果你不确定选多大的窗口,可以从 N=5 开始试,然后逐步增大,观察信号的关键特征(如峰值、过零点、上升沿)是否还能保持。我一般会画一张不同 N 值的对比图,一眼就能看出哪个最合适。

2.5 移动平均滤波的变体

标准的移动平均滤波有个问题——它对所有历史数据一视同仁。但在很多场景下,我们希望离当前点越近的数据权重越大。这就引出了加权移动平均滤波。

加权移动平均滤波的公式:

y[n] = (w0*x[n] + w1*x[n-1] + ... + w_{N-1}*x[n-N+1]) / sum(w)

其中 w 是权重系数,通常越靠近当前点的权重越大。常见的权重分配方式有线性递减、指数递减等。

我个人在音频处理中更常用指数加权移动平均(EWMA),因为它计算简单,而且只需要记住上一个输出值:

y[n] = α * x[n] + (1-α) * y[n-1]

这里的 α 相当于平滑系数,取值范围 0~1。α 越大,跟踪越快,平滑越弱;α 越小,平滑越强,但响应越慢。

EWMA 的好处是没有固定的窗口长度,历史数据的影响呈指数衰减,理论上所有历史数据都有贡献,但越早的数据贡献越小。这在实时系统中特别实用,因为你不需要维护一个缓冲区。

2.6 本章知识体系

下面这张图总结了移动平均滤波的核心知识点,帮你理清思路:

移动平均滤波知识体系 移动平均滤波知识体系 核心原理 窗口长度 N 的影响 频率响应特性 加权变体 平滑程度 群延迟 sinc 形状 零点位置 指数加权移动平均 (EWMA) 核心权衡:平滑效果 vs 信号保真度 窗口越长,噪声抑制越强,但信号细节损失越大

2.7 实际应用中的注意事项

最后,分享几个我在项目中积累的经验:

  1. 边界处理要小心:信号起始段,窗口内数据不足 N 个。常见的处理方式有补零、镜像延拓、或者只取有效数据平均。我个人推荐镜像延拓,效果最自然。
  2. 不要盲目增大窗口:窗口太大不仅会抹掉有用信号,还会引入明显的相位失真。在音频处理中,超过 50ms 的窗口就会产生可感知的“拖尾”效应。
  3. 考虑计算效率:标准移动平均滤波可以用递推公式优化——每次只需要加一个新数据,减一个旧数据,计算量跟窗口长度无关。这在嵌入式系统上特别重要。

曾经踩过的坑:我在一个振动监测项目中,用移动平均滤波处理加速度信号。窗口长度设了 N=100,结果把一次真实的冲击事件给平滑掉了,导致报警系统没触发。后来我改用加权移动平均,才在平滑和灵敏度之间找到了平衡。所以,永远不要相信默认参数,一定要根据你的信号特征来调。

移动平均滤波虽然简单,但它是理解更复杂滤波器的基石。把它的原理、参数影响和局限性吃透了,后面学 IIR、FIR 滤波器会轻松很多。