4、信号预处理技术:去噪方法、归一化处理、趋势项去除
各位同行,咱们做三轴联动的,最头疼的是什么?
不是算法不够高级,而是采集回来的信号——脏、乱、差。
传感器一抖,电机一响,线缆一绕,信号里全是乱七八糟的噪声。你想想看,拿这种信号去做故障诊断,那不是缘木求鱼吗?
所以,信号预处理是咱们诊断流程里的第一道关。这道关过不去,后面再牛的算法也是白搭。今天我就把压箱底的预处理三板斧拿出来,跟大伙儿好好聊聊。
核心观点:预处理不是“锦上添花”,而是“雪中送炭”。没有干净的信号,就没有准确的诊断。
4.1 去噪方法:把信号里的“沙子”筛掉
信号里的噪声,说白了就是干扰。电机换向、变频器开关、机械振动,都会往信号里掺沙子。我见过最夸张的一次,现场传感器线缆跟动力电缆走同一个线槽,采集回来的信号简直没法看。
4.1.1 均值滤波
均值滤波的原理很简单——取一个窗口,算平均值。比如窗口大小是5,就把当前点前后各2个点加起来除以5。
优点是快,计算量小。缺点也明显:它会模糊信号的边缘。你想想看,如果信号里有个尖锐的冲击(比如轴承故障的脉冲),均值滤波一过,脉冲就变平了。
我的经验:均值滤波适合处理平稳噪声,比如热噪声。但不适合处理脉冲噪声。我在做丝杠预紧力监测时,就吃过这个亏——把故障特征给滤没了。
# Python 实现均值滤波
import numpy as np
def moving_average(signal, window_size=5):
"""均值滤波"""
kernel = np.ones(window_size) / window_size
return np.convolve(signal, kernel, mode='same')
# 示例:对振动信号做均值滤波
raw_signal = np.random.randn(1000) # 模拟原始信号
filtered_signal = moving_average(raw_signal, window_size=7)
4.1.2 中值滤波
中值滤波就聪明多了。它不取平均,而是取窗口内所有值的中位数。这样做的好处是——对脉冲噪声有奇效。
举个例子,信号里突然蹦出一个尖峰(比如传感器受到瞬间撞击),均值滤波会被这个尖峰拉偏,但中值滤波直接把它当成异常值忽略掉。
注意:中值滤波的窗口大小很关键。窗口太小,去噪效果差;窗口太大,会丢失细节。我一般从3开始试,不行就5、7,直到效果满意为止。
# Python 实现中值滤波
from scipy.signal import medfilt
def median_filter(signal, kernel_size=3):
"""中值滤波"""
return medfilt(signal, kernel_size=kernel_size)
# 示例:对电流信号做中值滤波
current_signal = np.random.randn(1000)
clean_signal = median_filter(current_signal, kernel_size=5)
4.1.3 小波去噪
小波去噪是这三兄弟里最厉害的。它能把信号分解成不同频率的成分,然后只保留有用的部分,把噪声扔掉。
我个人的习惯是:对于非平稳信号(比如启停机过程、变转速工况),小波去噪是首选。因为它能同时保留时域和频域的信息。
实战要点:小波去噪有三个关键参数:小波基(常用db4、db8、sym8)、分解层数(一般3-5层)、阈值选择(软阈值还是硬阈值)。
# Python 实现小波去噪
import pywt
def wavelet_denoise(signal, wavelet='db4', level=4):
"""小波去噪"""
# 小波分解
coeffs = pywt.wavedec(signal, wavelet, level=level)
# 计算阈值(通用阈值法)
sigma = np.median(np.abs(coeffs[-1])) / 0.6745
threshold = sigma * np.sqrt(2 * np.log(len(signal)))
# 软阈值处理
coeffs_thresh = [pywt.threshold(c, threshold, mode='soft') for c in coeffs]
# 重构信号
return pywt.waverec(coeffs_thresh, wavelet)
# 示例:对加速度信号做小波去噪
accel_signal = np.random.randn(1000)
denoised_signal = wavelet_denoise(accel_signal, wavelet='db8', level=3)
4.2 归一化处理:让不同量纲的信号“说同一种语言”
做三轴联动诊断时,我们经常要同时看X、Y、Z三个轴的信号。问题来了——三个轴的传感器量程可能不一样,信号幅值也差很多。
比如X轴振动是±10g,Y轴是±5g,Z轴是±2g。如果不做归一化,算法会天然地“偏爱”幅值大的那个轴。这显然不合理。
4.2.1 Min-Max 归一化
把信号线性映射到[0,1]区间。公式很简单:x' = (x - min) / (max - min)。
优点是简单直观。缺点是如果信号里有异常值,会把正常数据压缩得很厉害。
避坑指南:我曾经在分析一个温度信号时,传感器偶尔会跳出一个离谱的值。用Min-Max归一化后,整个信号都被压扁了,根本看不出趋势。后来我改用Z-score,问题就解决了。
4.2.2 Z-score 标准化
把信号转换成均值为0、标准差为1的分布。公式:x' = (x - μ) / σ。
这个方法的鲁棒性更好,不容易被异常值带偏。我个人更推荐用Z-score,尤其是在做故障诊断时。
# Python 实现归一化
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Z-score 标准化
scaler_z = StandardScaler()
signal_z = scaler_z.fit_transform(signal.reshape(-1, 1))
# Min-Max 归一化
scaler_mm = MinMaxScaler()
signal_mm = scaler_mm.fit_transform(signal.reshape(-1, 1))
4.3 趋势项去除:把信号里的“斜坡”拉平
趋势项是什么?就是信号里那个缓慢变化的“底漂”。比如温度漂移、传感器零漂、机械结构的热变形,都会让信号整体往上或往下飘。
你想想看,如果信号本身就在缓慢上升,你去做频谱分析,低频部分会被这个趋势项污染,根本分不清是故障特征还是漂移。
4.3.1 多项式拟合去除
用多项式拟合出趋势项,然后从原始信号里减掉。最常用的是线性拟合(一次多项式),有时候也用二次或三次。
# Python 实现趋势项去除
import numpy as np
def remove_trend(signal, order=1):
"""多项式拟合去除趋势项"""
t = np.arange(len(signal))
coeffs = np.polyfit(t, signal, order)
trend = np.polyval(coeffs, t)
return signal - trend
# 示例:去除线性趋势
clean_signal = remove_trend(raw_signal, order=1)
4.3.2 高通滤波去除
趋势项通常是低频成分(接近0Hz)。用高通滤波器,把低频部分滤掉,剩下的就是高频的故障特征。
这个方法的好处是不需要假设趋势项的形状(线性还是非线性),但需要合理选择截止频率。
注意:高通滤波的截止频率不能设得太高,否则会把有用的低频故障特征也滤掉。比如轴承的通过频率可能只有几赫兹,你设个10Hz的高通,那就什么都看不到了。
# Python 实现高通滤波去除趋势项
from scipy.signal import butter, filtfilt
def highpass_filter(signal, cutoff=0.5, fs=1000, order=4):
"""高通滤波去除趋势项"""
nyquist = 0.5 * fs
normal_cutoff = cutoff / nyquist
b, a = butter(order, normal_cutoff, btype='high', analog=False)
return filtfilt(b, a, signal)
# 示例:0.5Hz高通滤波
detrended_signal = highpass_filter(raw_signal, cutoff=0.5, fs=1000)
4.4 预处理流程总结
在实际项目中,我一般按这个顺序走:
- 先去除趋势项——把信号拉平,消除漂移
- 再去做去噪——根据噪声类型选方法(脉冲噪声用中值,平稳噪声用均值,非平稳用小波)
- 最后归一化——让不同通道的信号在同一个量级上
记住:预处理不是一次性的。做完一步,看一眼效果,不满意就调整参数。我经常要来回调好几轮,才能找到最合适的参数组合。这很正常,别嫌麻烦。
好了,信号预处理这块就聊到这儿。下一节咱们要进入真正的诊断环节了——时域分析。到时候我会教大家怎么看时域波形里的“门道”。