4. 故障特征提取:时域、频域与统计特征
各位同学,咱们接着往下聊。上一节我们把传感器数据采集上来了,但原始数据就像一堆没加工的矿石——你得提炼出金子才行。这节我就讲讲怎么从这些波形里「挖」出能代表故障的特征。
说白了,特征提取就是给数据做「体检报告」。你想想看,一个电机正常运行时和轴承卡死时,振动波形肯定不一样。但不一样在哪里?是幅度变了?还是频率变了?或者波形形状变得不对称了?这些就是我们要找的特征。
核心思路:把高维的原始信号,压缩成几个有物理意义的数值。这样故障诊断就从「看波形」变成了「看数字」。
4.1 时域特征:最直观的「第一印象」
时域特征,说白了就是直接在时间轴上算统计量。我刚开始做售货机故障诊断时,第一个看的指标就是时域特征——因为它计算快,实时性好。
4.1.1 均值(Mean)
均值反映信号的直流分量或趋势项。对于振动信号,均值通常接近0。如果均值明显偏移,说明传感器可能零漂了,或者机械结构有静态变形。
// 均值计算(C语言示例)
float calculate_mean(float *data, int len) {
float sum = 0.0;
for (int i = 0; i < len; i++) {
sum += data[i];
}
return sum / len;
}
我的经验:在售货机出货口振动监测中,如果均值从0.02V漂到0.15V,大概率是传感器安装座松动了。我曾经遇到过一台机器,换了三次传感器都没解决,最后发现是安装螺丝滑丝了。
4.1.2 方差(Variance)与标准差
方差描述信号偏离均值的程度。说白了就是「抖得厉不厉害」。电机正常运行时方差较小,一旦轴承磨损,方差会明显增大。
// 方差计算
float calculate_variance(float *data, int len, float mean) {
float var = 0.0;
for (int i = 0; i < len; i++) {
float diff = data[i] - mean;
var += diff * diff;
}
return var / len;
}
标准差就是方差的平方根,单位跟原始信号一致,更直观。我一般用标准差做阈值判断——超过正常值的3倍,基本可以判定异常。
4.1.3 峰值(Peak Value)
峰值就是信号的最大绝对值。这个指标对冲击性故障特别敏感。比如售货机取货口被卡住时,电机堵转瞬间会产生很大的冲击峰值。
// 峰值计算
float calculate_peak(float *data, int len) {
float peak = 0.0;
for (int i = 0; i < len; i++) {
float abs_val = fabs(data[i]);
if (abs_val > peak) peak = abs_val;
}
return peak;
}
注意:峰值容易受噪声干扰。我建议先做一次低通滤波再算峰值,否则一个毛刺就能让阈值误触发。我曾经因为这个原因,让售货机在半夜频繁误报警,运维人员差点崩溃。
4.2 频域特征:看「节奏」而不是看「幅度」
时域特征只能告诉你「抖得厉害不厉害」,但频域特征能告诉你「怎么个抖法」。比如电机正常运行时,振动频率主要是基频和倍频。如果出现了非整数倍频的峰值,那基本就是故障信号。
4.2.1 FFT频谱分析
FFT(快速傅里叶变换)是把时域信号转换到频域的利器。我习惯用1024点FFT,采样率设为1000Hz,这样频率分辨率刚好1Hz左右,够用。
// FFT频谱分析(简化版,使用CMSIS-DSP库)
#include "arm_math.h"
float32_t input[1024]; // 时域数据
float32_t output[1024]; // FFT输出(复数)
arm_rfft_fast_instance_f32 fft_instance;
// 初始化FFT
arm_rfft_fast_init_f32(&fft_instance, 1024);
// 执行FFT
arm_rfft_fast_f32(&fft_instance, input, output, 0);
// 计算幅值谱
float32_t magnitude[512];
arm_cmplx_mag_f32(output, magnitude, 512);
得到频谱后,我一般关注三个频段:
- 低频段(0-50Hz):反映机械结构松动、不平衡
- 中频段(50-200Hz):反映轴承、齿轮故障
- 高频段(200Hz以上):反映摩擦、气蚀等
避坑指南:我曾经在分析一台售货机压缩机振动时,发现频谱里有个明显的100Hz峰值。一开始以为是轴承故障,后来才发现是电源工频干扰。所以做FFT前,一定要先做去直流和去工频处理。
4.2.2 频谱特征提取
从频谱里提取特征,我常用的有:
| 特征名称 | 计算公式 | 物理意义 |
|---|---|---|
| 频谱重心 | Σ(f·A(f)) / ΣA(f) | 能量集中的频率位置 |
| 频谱均方根 | √(ΣA(f)² / N) | 频域能量大小 |
| 峰值频率 | max(A(f))对应的f | 主要振动频率 |
4.3 统计特征:看「形状」而不是看「大小」
时域和频域特征看完了,有时候还不够。比如两个信号的均值和方差都一样,但一个波形对称,一个不对称——这时候就需要统计特征出马了。
4.3.1 偏度(Skewness)
偏度描述信号分布的不对称程度。正常振动信号接近正态分布,偏度接近0。如果偏度为正,说明信号有向上的尖峰;为负则有向下的尖峰。
// 偏度计算
float calculate_skewness(float *data, int len, float mean, float std) {
float skew = 0.0;
for (int i = 0; i < len; i++) {
float diff = (data[i] - mean) / std;
skew += diff * diff * diff;
}
return skew / len;
}
我记得有一次,售货机出货电机的声音听起来「不对劲」,但时域和频域特征都在正常范围内。最后算偏度发现从0.1变成了0.8——原来是电机转子有轻微扫膛,产生了不对称的冲击。
4.3.2 峭度(Kurtosis)
峭度描述信号分布的「尖锐程度」。正态分布的峭度是3。如果峭度大于3,说明信号有更多的极端值——说白了就是有冲击。
// 峭度计算
float calculate_kurtosis(float *data, int len, float mean, float std) {
float kurt = 0.0;
for (int i = 0; i < len; i++) {
float diff = (data[i] - mean) / std;
kurt += diff * diff * diff * diff;
}
return kurt / len;
}
实用技巧:峭度对早期故障特别敏感。轴承刚开始出现点蚀时,峭度会先于均方根值发生变化。我一般用峭度做「预警指标」,均方根做「报警指标」。
4.4 特征融合:把鸡蛋放在一个篮子里
单个特征往往不够可靠。我习惯把时域、频域、统计特征组合成一个特征向量,然后送入分类器。比如对于售货机出货口故障,我常用的特征向量是:
// 特征向量结构体
typedef struct {
float mean; // 时域均值
float variance; // 时域方差
float peak; // 时域峰值
float skewness; // 偏度
float kurtosis; // 峭度
float freq_peak; // 频谱峰值频率
float freq_energy; // 频谱能量
} FaultFeatureVector;
嗯,这里要注意一点:不同特征的量纲不一样。均值可能是0.01,峭度可能是5.0。直接放一起,峭度会主导结果。所以一定要做归一化处理。
我的习惯:用Z-score归一化,让每个特征的均值为0,标准差为1。这样所有特征都在同一个量级上,分类器才能正常工作。
好了,这一节的内容就到这里。特征提取是故障诊断的「眼睛」——你提取的特征好不好,直接决定了后续诊断的准确性。下一节我们聊聊怎么用这些特征做故障分类,到时候会用到一些机器学习的方法。
公众号:蓝海资料掘金营,微信deep3321