本节摘要:去噪前先给噪声画像——加性白噪声占绝大多数场景,靠平均压、靠平滑滤。Savitzky-Golay 用窗口内多项式拟合替代简单平均,在压噪与保峰之间取得最好的折中;窗口与阶数是仅有的两个旋钮,本节用可复算数据展示拧过头会发生什么。
整备车间的第一道工序。第 1 章入库质检给了你信噪比估值,如果没达标,就轮到本节出手。它承接第 1 章的"加性噪声"诊断,通往第 2 章后面所有工序——因为基线校正和求导都会放大噪声,先把毛刺压到合理水平,后面的工序才站得住。
光谱里的噪声按来源分三类。散粒噪声:光子到达检测器本身是随机的,计数越大相对起伏越小,服从根号 N 规律;读出噪声:电子学线路的热噪声,与信号大小无关,是加性的;闪烁噪声:光源强度低频起伏,表现为慢变漂移,它其实算"基线问题",留给 2.3、2.4 节。本节对付的是前两类——统计上表现为每个数据点独立的随机偏差,数学名字叫白噪声。
白噪声有个要害:平均会消它,信号却平均不掉。这就是一切平滑方法的理论依据——滑动窗口取平均,噪声方差降为原来的 N 分之一(N 为窗口点数),而缓慢变化的信号几乎不动。但"几乎"里藏着陷阱:谱峰是快速变化的信号,平均会把峰顶削平。
移动平均对所有窗口内数据一视同仁,峰顶自然被拉低。Savitzky-Golay(下文简称 SG)的改进只有一步:在滑动窗口内做低阶多项式最小二乘拟合,用拟合值(而不是均值)作为输出。多项式能"跟"上峰形,于是峰高保得住。它与移动平均的对比如下,数据是两个叠加高斯峰加 0.03 的白噪声:
# SG 平滑与移动平均的对照实验 import numpy as np from scipy.signal import savgol_filter np.random.seed(42) rng = np.random.default_rng(7) x = np.linspace(0, 10, 400) clean = 0.8*np.exp(-0.5*((x-5.2)/0.22)**2) + 0.25*np.exp(-0.5*((x-6.6)/0.4)**2) y = clean + rng.normal(0, 0.03, x.size) # 加噪档案 ma = np.convolve(y, np.ones(9)/9, mode='same') # 9 点移动平均 sg = savgol_filter(y, 11, 3) # SG:窗口 11,三阶 def rmse(a, b): return float(np.sqrt(np.mean((a-b)**2))) print(f"raw RMSE={rmse(y, clean):.4f}") print(f"moving-average(9) RMSE={rmse(ma, clean):.4f} peak retained={ma.max()/clean.max()*100:.1f}%") print(f"SG(11,3) RMSE={rmse(sg, clean):.4f} peak retained={sg.max()/clean.max()*100:.1f}%")
输出:
raw RMSE=0.0316 moving-average(9) RMSE=0.0133 peak retained=95.9% SG(11,3) RMSE=0.0157 peak retained=100.8%
细看这组数字,结论比"谁更好"更有意思:移动平均的 RMSE 反而更低(0.0133 对 0.0157),但主峰高度被削掉了 4.1%;SG 的 RMSE 略高,峰高却完整保留。对定量任务来说,4% 的峰高损失是系统误差,直接进结果;而 RMSE 那点劣势只是随机误差,多平均几次就能摊薄。评估平滑方法必须用"峰高保留率"这类针对特征的指标,RMSE 单打独斗会误导选型——这是本节最重要的判断训练。
SG 只有两个旋钮:窗口点数(奇数)与多项式阶数。窗口越大越平滑、峰形失真越多;阶数越高越贴数据、去噪越弱。固定三阶,把窗口从小到大扫一遍:
# 窗口扫描:RMSE 与峰高的双重观察 for w in [5, 11, 21, 31]: f = savgol_filter(y, w, 3) print(f"window={w:2d} RMSE={rmse(f, clean):.4f} peak={f.max():.3f}")
输出:
window= 5 RMSE=0.0227 peak=0.823 window=11 RMSE=0.0157 peak=0.806 window=21 RMSE=0.0119 peak=0.789 window=31 RMSE=0.0137 peak=0.745
注意两个现象。其一,峰高随窗口单调下降:0.823 → 0.806 → 0.789 → 0.745,窗口 31 时已经丢了 7%;其二,RMSE 不是单调的——窗口 21 时最低(0.0119),到 31 反而回升(0.0137),因为宽窗口开始"追不上"峰形,把失真本身也算进了误差。经验起点:窗口宽度约为最窄目标峰半峰宽对应的点数,再上下各试两档。阶数通常取 2 或 3;除非峰形非常尖锐,别超过 5——高阶多项式会开始"拟合噪声"。
💡 关键直觉:平滑的本质是"用带宽换信噪比"。最窄峰的宽度是你不能让出的底线,底线之上的带宽才可以拿去换安静。
平滑解决"毛刺",下一站处理"结构化噪声":把谱图搬进频率域,看看噪声和信号在户口本上是怎么分居的,小波又如何给滤波装上局部开关。