savgol_filter最稳妥用于局部多项式平滑:window_length须为奇数且小于数据长度,polyorder通常取2或3;边界失真时优先用mode='nearest',实时流数据应改用ewma或convolve。

用 scipy.signal.savgol_filter 做局部多项式平滑最稳妥
短期随机波动通常不具备周期性,也不适合用傅里叶滤波,savgol_filter 是首选:它在滑动窗口内拟合多项式,保留趋势和拐点,比简单移动平均更抗异常值干扰。
关键参数要对齐数据特性:
-
window_length必须是奇数,且不能超过数据长度;太小(如 3)几乎不平滑,太大(如 >101)会抹平真实峰谷 -
polyorder一般取 2 或 3;设为 0 就退化成均值滤波,设为 1 相当于线性局部拟合 - 若数据采样不等距,必须先插值或改用
scipy.interpolate.UnivariateSpline
示例:
from scipy.signal import savgol_filter<br>y_smooth = savgol_filter(y, window_length=21, polyorder=3)
遇到边界失真时优先用 mode='nearest' 而不是默认 'interp'
savgol_filter 默认在边界做插值外推,容易产生虚假震荡,尤其在趋势陡变处。比如传感器启动阶段的阶跃上升,尾部常冒出一个反向尖峰。
改用 mode='nearest' 让边界用最近邻值延拓,更符合物理实际:
y_smooth = savgol_filter(y, window_length=31, polyorder=2, mode='nearest')
其他可选模式:'constant'(填 0)、'wrap'(首尾循环),但多数实测中 'nearest' 失真最小。
实时流式数据别用 savgol_filter,改用 numpy.convolve 手写滑动加权平均
savgol_filter 是离线全量处理,无法增量更新。如果接 MQTT 或串口持续进数据,每来一个新点就重算全部,延迟会随数据增长而上升。
此时更适合用固定权重卷积,例如指数加权(EWMA)或自定义窗:
- EWMA 只需上一时刻输出:
y_smooth[i] = alpha * y[i] + (1 - alpha) * y_smooth[i-1] - 若需对称窗,可用
numpy.convolve(y[-window:], weights, 'valid'),只卷最后window个点 - 注意
convolve默认补零,实时场景建议手动截断或用mode='same'后取末位
平滑后仍残留周期性毛刺?先检查是否欠采样导致混叠
如果原始信号本身含高频成分(如电机开关噪声、电源工频干扰),但采样率不足奈奎斯特频率,平滑滤波反而会让混叠伪影更明显——看起来像“抹不掉的规律性抖动”。
这时不能只调平滑参数,得回溯采集环节:
- 用
numpy.fft.rfft看频谱,确认毛刺是否集中在某倍频(如 50Hz、100Hz) - 若存在,优先在硬件端加 RC 低通,或软件端先用
scipy.signal.butter设计 20–30Hz 巴特沃斯低通预滤波 - 直接对混叠数据用
savgol_filter,窗口再大也消不掉结构化假频
平滑不是万能胶,它不修复信息丢失,只整理已有数据。真正难的是判断波动到底算“噪声”还是“未建模的动态”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











