简介:MATLAB在振动信号处理中的应用是一份面向机械、航空航天及土木工程领域学习者的代码资源,由王济和胡晓编写,系统覆盖振动信号从预处理到故障诊断的完整流程。资源共79个文件,以.m程序源码、.mat实验数据文件和.asv自动存档文件为主,另有说明txt,压缩包仅490KB,便于下载与按章节检索。已有1567人浏览学习。代码按章节组织,包括振动信号时域处理方法、频域处理方法、数字信号生成,以及试验模态参数的频域/时域识别方法等模块,对应集成fft、filter、xcorr、pwelch等函数应用,并配有可供直接运行的示例程序和结果数据。学习者既能对照理论认识傅里叶变换、滤波、功率谱估计、小波分析等知识点,也能借助示例程序快速上手实际振动分析,适合正在学习信号处理课程或开展设备状态监测研究的初、中级读者。
1. 振动信号处理:MATLAB 在实测数据里的正确打开方式
不少刚接触设备状态监测的工程师,拿到传感器采回来的一批振动数据后,习惯先套一两个现成函数跑个频谱,看到峰值就急着下结论。我拆过不少这类需求,最后发现大多数结论都站不住:要么被趋势项带偏,要么被噪声干扰,要么因为窗函数选错导致特征频率对不上。这套关于“MATLAB 在振动信号处理中的应用”的资源,核心思路是先对原始信号做预处理,再按不同故障类型选择时域、频域或包络谱特征,最后用统一脚本批量输出结果,适合正在做设备振动监测、故障诊断或者课程设计的从业者。资源里给出的方法和代码,不是教科书里那种只讲理论的结构,而是能直接套到现场采集数据、能出图能导出结果的实现路径。
2. 把原始振动信号洗干净:趋势项消除与带通滤波的落地写法
2.1 为什么先处理趋势项,又怎么处理
实测振动信号里,最常见的“隐形杀手”不是随机噪声,而是趋势项。比如传感器本身的零漂、前置放大器温漂、以及采样过程中被测对象整体缓慢摆动,这些低频分量会叠加在真实振动信号上,直接导致频谱图里 0 Hz 附近出现一条异常高谱线,把 0.5 Hz 以下本来有用的低频成分全部压扁。很多初学者一看到频谱里低频段功率很大,就以为设备出现了严重的低频振动,实际上只是信号里掺杂了直流和缓慢变化的趋势成分。
处理趋势项的主流做法是最小二乘拟合法,对采样点做多项式拟合并从原信号中减去。一阶多项式就是线性趋势,二阶以上可以处理缓慢变化的曲线趋势。对绝大多数旋转机械振动信号来说,一阶或二阶趋势项消除已经足够。
% 读入原始振动加速度信号,单位 m/s^2 data = load('vibration_raw.mat'); x = data.acc; fs = 10240; % 采样率 10240 Hz,旋转机械通用配置 n = length(x); t = (0:n-1)/fs; % 时间轴 % 一阶趋势项消除(线性拟合) p = polyfit(t, x, 1); x_detrend = x - polyval(p, t)'; % 画图对比原始信号和去趋势后的信号 figure; subplot(2,1,1); plot(t, x); title('原始信号'); subplot(2,1,2); plot(t, x_detrend); title('去线性趋势后');这段代码里,polyfit用一次多项式拟合信号中的线性漂移,polyval还原拟合值,原信号减去拟合值后得到干净的振动成分。对于大多数加速度传感器信号,线性拟合足够;如果在长时间连续监测场景下发现信号整体呈弧形偏移,可以把阶数提高到 2,把polyfit(t, x, 1)改成polyfit(t, x, 2)。要注意t和x必须都是列向量,否则矩阵维度对不上,我习惯在数据读入后统一用x = x(:)转成列向量,避免低级维度错误。
2.2 带通滤波器的参数怎么定
消除趋势项之后,下一步是滤掉高频噪声和低频干扰。这一步不能随手选一个 1 kHz 到 5 kHz 的带通就完事,参数要根据设备的转频和关注频带来定。以常见的电机-齿轮箱系统为例,电机转频约 30 Hz,齿轮啮合频率可能在几百 Hz 到 2 kHz 之间,轴承早期故障特征频率往往落在 1 kHz 到 4 kHz 之间。此时带通范围设置在 500 Hz 到 4000 Hz 比较合理,既能盖住齿轮啮合频率及其谐波,又能尽量保留轴承故障的冲击成分。
MATLAB 里推荐用filtfilt配合butter做零相位滤波,普通filter会有相位偏移,对振动信号这种需要精确保留时间关系的场景不适用。
% 巴特沃斯 4 阶带通滤波,通带 500 Hz ~ 4000 Hz [fb, fa] = butter(4, [500 4000]/(fs/2), 'bandpass'); x_filtered = filtfilt(fb, fa, x_detrend); % 对比滤波前后频谱 [X_raw, f_raw] = pwelch(x_detrend, hann(1024), 512, 2048, fs); [X_filt, f_filt] = pwelch(x_filtered, hann(1024), 512, 2048, fs); figure; subplot(2,1,1); plot(f_raw, 20*log10(X_raw)); title('滤波前频谱'); xlabel('频率/Hz'); ylabel('功率谱/dB'); subplot(2,1,2); plot(f_filt, 20*log10(X_filt)); title('滤波后频谱'); xlabel('频率/Hz'); ylabel('功率谱/dB');butter里的阶数选 4 是兼顾了过渡带陡峭程度和数值稳定性。阶数太高会导致滤波器在高采样率下出现数值不稳定;太低则滤波不充分。filtfilt是零相位滤波,它把序列正反各滤一次,正好抵消相位偏移,代价是计算时间翻倍。常见的一个小坑是:如果信号很短(比如不到 0.1 秒),filtfilt会在端点处产生明显的边界效应,此时可以把信号前后各延拓一小段,滤完再截掉。
功率谱估计用的pwelch是 Welch 法,hann(1024)确定窗长,512是重叠长度,2048是 FFT 点数,fs是采样率。这套参数组合能保证频率分辨率在fs / 2048 = 5 Hz,足以区分 30 Hz 转频和 50 Hz 电网干扰。如果希望频率分辨率更细,可以把 FFT 点数提高到 4096,代价是单次计算量增加,对 10 kHz 采样率下的几十秒数据来说完全可以接受。
3. 时域与频域特征提取:从波形里读出设备状态
3.1 时域统计指标的组合判断逻辑
预处理完成后,先看整体振动水平。时域特征里最常用的是峰值、峰峰值、均方根值和峰值因子,四个指标配合使用可以快速区分“正常磨损”“轻微不平衡”“早期冲击类故障”。
均方根值对应振动能量的总体水平,峰值因子(峰值除以均方根)是最实用的指标之一。正常设备峰值因子通常在 3 到 5 之间;滚动轴承出现早期点蚀时,信号中叠加了周期性冲击成分,峰值因子会显著升高到 8 以上;但当故障持续发展、冲击能量增大到一定程度后,均方根值会快速上升,峰值因子反而会回落,这就是为什么单看峰值因子不够,必须配合均方根值一起判断。
% 计算时域统计特征 x = x_filtered(:); peak_val = max(abs(x)); % 峰值 peak_peak = max(x) - min(x); % 峰峰值 rms_val = sqrt(mean(x.^2)); % 均方根值 crest_factor = peak_val / rms_val; % 峰值因子 kurtosis_val = mean((x - mean(x)).^4) / (mean((x - mean(x)).^2)^2); % 峭度,正态分布信号峭度约等于 3 fprintf('峰值: %.3f m/s^2\n', peak_val); fprintf('峰峰值: %.3f m/s^2\n', peak_peak); fprintf('均方根: %.3f m/s^2\n', rms_val); fprintf('峰值因子: %.3f\n', crest_factor); fprintf('峭度: %.3f\n', kurtosis_val);这几个指标代码量不大,但在实际项目里我一般都建议直接封装成函数,输入一段信号输出一个结构体,方便批量处理多组数据。峭度的意义在于:滚动轴承早期故障信号中冲击成分稀少而尖锐,信号分布相对于正态分布会出现明显的“重尾”,峭度值会明显大于 3。如果某个测点的峭度超过 6,那基本可以断定存在局部冲击类故障,值得继续做包络分析定位故障频率。
3.2 频谱分析里必须明确的两组参数
频域分析最常用的是pwelch功率谱和直接 FFT 幅度谱。两者区别在于:功率谱对信号做平均处理,抑制随机噪声能力更强,适合观察稳定存在的频率成分;幅度谱分辨率更高,适合查看单次采样的细节。实际工程中我一般先看功率谱,一旦发现可疑频率,再回到原始信号做短时傅里叶变换确认特征频率是否随时间变化。
一个需要注意的操作细节是窗函数的选择。矩形窗的频率分辨率最高,但频谱泄漏严重;汉宁窗(hann)主瓣更宽、旁瓣衰减快,适合大多数连续振动信号;如果有两个频率非常接近的成分需要区分,选矩形窗,但同时要接受旁瓣干扰。
% 功率谱分析 window = hann(2048); % 汉宁窗,2048 点 noverlap = 1024; % 50% 重叠 nfft = 4096; % FFT 点数 [X, f] = pwelch(x_filtered, window, noverlap, nfft, fs); % 找前 10 个峰值,输出对应频率和幅值 [~, locs] = findpeaks(X, 'MinPeakHeight', max(X)/10, 'SortStr', 'descend'); for i = 1:min(10, length(locs)) fprintf('峰值 %d: 频率 %.2f Hz, 幅值 %.4f\n', i, f(locs(i)), X(locs(i))); endfindpeaks里的'MinPeakHeight'设置成max(X)/10可以滤掉大量噪声小峰,'SortStr', 'descend'让结果按幅值从大到小排列。这套逻辑能把频谱里最突出的 10 个频率成分自动列出来,比人眼在频谱图上找峰值靠谱得多。实际应用中,我会顺手把结果保存成 CSV 文件,再跟历史数据对比,看哪些频率成分幅值在持续增长——这才是故障预警的正确姿势。
3.3 批量处理多测点数据的脚本结构
现场采样往往不止一个测点,一套设备可能同时布置 6 到 8 个加速度传感器。一个可复用的批处理脚本能省去大量重复操作,结构大体如下:
% 批量处理所有测点的振动数据,输出特征表 files = dir('data/*.mat'); results = []; for i = 1:length(files) d = load(fullfile(files(i).folder, files(i).name)); x = d.acc(:); fs = d.fs; % 去趋势 t = (0:length(x)-1)/fs; p = polyfit(t, x, 1); x = x - polyval(p, t)'; % 带通滤波 [b, a] = butter(4, [500 4000]/(fs/2), 'bandpass'); x = filtfilt(b, a, x); % 时域特征 peak_val = max(abs(x)); rms_val = sqrt(mean(x.^2)); crest_val = peak_val / rms_val; kurt_val = mean((x-mean(x)).^4) / (mean((x-mean(x)).^2)^2); % 频域特征:取 0.5 kHz ~ 4 kHz 频段内最大谱峰频率 [X, f] = pwelch(x, hann(2048), 1024, 4096, fs); idx = f >= 500 & f <= 4000; [~, max_idx] = max(X(idx)); dominant_freq = f(idx); dominant_freq = dominant_freq(max_idx); results = [results; peak_val, rms_val, crest_val, kurt_val, dominant_freq]; end % 结果写入 CSV csvwrite('feature_results.csv', results);这套脚本的核心价值在于规范化流程:每个文件的数据都经过同一套去趋势、滤波、特征提取管线,最终得到的是一个五行左右的表格,每一行对应一个测点。某一天现场工程师发现第二测点的峭度从 3 跳到 9,第三测点的优势频率从 300 Hz 漂移到 350 Hz,就值得重点关注。
4. 振动信号处理常见问题排查:六个高频踩坑点
4.1 频谱里出现栅栏状异常谱线
现象:对滤波后的信号做 FFT,发现频谱里出现一排等间距的小峰,间距恰好等于转频和电源频率的差。
原因:数据采集时传感器或者采集卡受到了 50 Hz 工频干扰,且干扰信号与振动信号混叠后形成调制边带。这类谱线通常不是真实故障特征,直接下结论说“电机存在故障”是典型的误判。
解决:在滤波器的带通范围里加一个陷波滤波器,把 48 Hz 到 52 Hz 这段直接挖掉;或者检查现场布线,确认传感器线缆是否与动力电缆平行敷设。工程上我会先做后者,因为布线问题不解决,后续数据处理永远要跟着弥补。
4.2filtfilt边界效应导致端点振荡
现象:滤波后的信号在开头和结尾各出现一段明显的衰减振荡,持续约 0.1 秒,这个时间段内的特征完全不准确。
原因:filtfilt对信号的边界假设是信号在两端平滑延续,但实际采样的信号往往是突然截断的,边界处的高频冲击成分被滤波器放大,形成振铃现象。
解决:滤波前先把信号前后各延伸一段,延伸长度取滤波器阶数的 3 到 5 倍即可,滤波完成后把延伸段裁掉。更省事的做法是直接在采集端多采 2 秒数据,处理时只取中间稳定段。
4.3 峰值频率与实际特征频率对不上,整体偏小
现象:已知齿轮箱输入轴转频 30 Hz,齿数 32,啮合频率应该是 960 Hz。但频谱图里主峰在 955 Hz 左右,每次测量都差几个 Hz。
原因:转频不是绝对稳定的,电机在带负载时转速会有小幅波动,实测转频可能已经变为 29.8 Hz 左右,乘以 32 得到 953.6 Hz,与理论值出现偏差。另一个可能原因是采样率标称值是 10240 Hz,但实际采集卡晶体振荡器存在微小偏差。
解决:不要把理论特征频率当成唯一依据。正确做法是在频谱里找到啮合频率附近的实际峰值,用f / 32反算实际转频,再基于实际转频推算其他特征频率。
4.4 功率谱峰值被淹没在底噪里
现象:频谱图中想观察的微弱峰被周围底噪包住,无法分辨是真实信号还是随机噪声。
原因:单次pwelch平均次数不够,或者窗函数类型不适合信号特征。低频段底噪通常随着频率升高而降低,如果关注的频率成分恰好在低频段,很容易被起伏的底噪掩盖。
解决:把 FFT 点数加大、重叠率提高,增加分段平均次数;或者改用pmtm方法,多窗谱估计在抑制方差方面比 Welch 法更有效。工程上我通常会同时试 Welch 和pmtm,观察同一个频率在两个算法下是否都能稳定出现峰值,如果只有一种算法能看见,判定为可疑信号,需要进一步确认。
4.5 峭度值异常高,但时域波形看不出冲击
现象:峭度值高达 30,但波形图上肉眼看不出明显的周期性冲击,一切似乎正常。
原因:信号里可能混入了间歇性电脉冲或数据丢点,单点异常尖峰对峭度的贡献极大。真实机械冲击是周期性的,波形上应该能看到重复的瞬态衰减过程。
解决:遇到极高峭度时,先做一次中值滤波或者阈值限幅,把超出 5 倍标准差的数据点替换为相邻点均值,再重新计算峭度。如果去除尖峰后峭度仍然远大于 5,再判定为疑似冲击类故障。这条经验帮我挡住过不少误报警。
4.6 批处理脚本运行到一半崩溃
现象:循环处理第 17 个文件时提示变量类型不匹配,或者csvwrite报错,但前 16 个文件都正常。
原因:这批数据是不同时间采集的,部分文件采样率不同,甚至某些文件里缺失时间轴字段。批处理脚本没有对每份数据做完整性校验。
解决:在循环开头统一校验字段是否存在、采样率是否合法、信号长度是否超过滤波器的瞬态段长度,不满足条件的文件直接跳过并记录到日志。这样脚本能一次跑完,不会因为个别坏数据全盘卡死。
5. 包络解调与故障特征频率识别:一个完整的小例程
滚动轴承故障诊断是包络解调最典型的应用场景。轴承外圈、内圈、滚动体故障会产生不同频率的周期性冲击,但这些冲击在原始信号里往往被更强的齿轮啮合信号掩盖,直接看功率谱找不到故障特征。正确做法是先做带通滤波,再对滤波后的信号做希尔伯特变换得到包络信号,最后对包络信号做频谱分析,故障特征频率就会在包络谱里浮现。
% 包络解调完整例程,适用于滚动轴承故障诊断 x = x_filtered; % 已经经过带通滤波的振动信号 % 希尔伯特变换求包络 analytic_signal = hilbert(x); envelope = abs(analytic_signal); % 去除包络信号中的直流分量 env_detrend = envelope - mean(envelope); % 对包络做频谱分析 window = hann(2048); noverlap = 1024; nfft = 4096; [env_spectrum, f_env] = pwelch(env_detrend, window, noverlap, nfft, fs); % 输出 0 ~ 500 Hz 频段内的峰值频率 idx = f_env >= 0 & f_env <= 500; [~, locs] = findpeaks(env_spectrum(idx), 'MinPeakHeight', max(env_spectrum(idx))/5, 'SortStr', 'descend'); peak_freqs = f_env(idx); peak_freqs = peak_freqs(locs); disp('包络谱显著峰值频率:'); disp(peak_freqs);这段代码的适用范围是转频高于 10 Hz、故障特征频率低于 500 Hz 的滚动轴承系统。hilbert的结果是一个复信号,实部是原信号,虚部是原信号的 90 度相移,包络就是复信号的幅值。滤波器的通带选在 500 到 4000 Hz 的区间,目的是先剔除低频齿轮啮合信号和高频随机噪声,让轴承冲击成分相对突出,再进入包络解调。
参数选择上,窗长 2048 对应约 0.2 秒的段长度,对 30 Hz 转频的轴承系统来说足够覆盖两到三个冲击周期;FFT 点数 4096 的频率分辨率是 2.5 Hz,可以清楚分辨相差 5 Hz 以上的特征频率。如果轴承故障特征频率与外圈通过频率非常接近,比如相差不足 2 Hz,就需要把 FFT 点数提高到 8192 甚至 16384 才能分开,代价是计算量倍增。
有一次我帮某现场处理一批齿轮箱数据,功率谱里完全找不到任何异常峰值,但包络谱里出现了一个 100 Hz 左右的峰,对照轴承型号参数一算,恰好是滚动体故障特征频率,最终检修确认轴承滚动体表面已经有轻微点蚀。从那以后我每次做包络谱都会强制走一遍三个步骤:先确认滤波通带覆盖了轴承共振频带,再检查包络信号里是否残留明显周期成分,最后确认频谱峰值与理论特征频率的偏差在 3% 以内才下结论。这三个动作看起来简单,却帮我避免了至少三次把边带误判成故障的尴尬,希望帮到你。
本文还有配套的精品资源,点击获取