☰
MATLAB振动信号处理全流程实操:采样滤波FFT与特征提取
2026/10/13 23:05:38 网站建设 项目流程

简介:MATLAB在振动信号处理中的应用是一套面向机械、航空航天、土木工程等专业学生与工程技术人员的程序代码集,围绕振动信号预处理、时域与频域分析、数字信号生成以及试验模态参数识别等核心环节展开,也适合作为设备故障诊断与状态监测的入门练习。压缩包共79个文件,以33个m源程序为主,配有25个mat数据文件用于结果验证,20个asv为编辑备份,1个txt为说明文档,整体仅490KB,轻量易用。代码按章节组织,从预处理方法到时域处理、频域处理,再到模态参数的频域/时域识别,目录层次清晰,读者可结合数据文件逐步复现傅里叶变换、滤波、相关分析、功率谱估计和小波变换等典型操作。目前已有1567人学习下载,对于希望将MATLAB应用到实际振动信号处理中的初学者和研究人员,是一份功能完整、便于对照实践的参考代码包。

1. 振动信号处理为什么绕不开 MATLAB:从原始数据到可用特征的一段路

振动信号处理在设备状态监测和故障诊断里几乎是日常标配。传感器采回来的是时间序列,但工程师真正关心的是转频、倍频、边带、共振带。MATLAB在振动信号处理中的应用之所以普及,是因为从采样设置、滤波去噪到FFT、包络、谱分析,再到批量导出特征,一条链路都能在一个环境里跑完。新手容易把精力耗在数据格式转换和画图上,而用MATLAB可以很快从原始数据走到可用特征,先看到结果再去深挖原理。这篇文章会沿着实际处理流程展开,把参数设置和踩坑记录写清楚,适合正在做故障诊断、结构监测或振动测试的工程师,尤其是被频谱、包络谱折磨过但还没形成系统排查方法的从业者。

2. 采样、去趋势与滤波:把原始振动数据变成能分析的干净信号

2.1 采样参数怎么定:避免混叠的第一步

振动信号处理的第一个坑往往是采样率。根据奈奎斯特定理,采样率至少要高于信号最高频率的两倍。但在工程里,我一般不会卡着这个下限,而是留足余量,常见做法是取关注最高频率的2.56倍或5倍。为什么是2.56?因为抗混叠滤波器不是理想砖墙,通常过渡带会占用一部分频带,2.56倍这个系数在很多数据采集器里是默认约定。如果只需要分析到1000 Hz,采样率取2560 Hz甚至5120 Hz都行,但不要取刚刚2000 Hz,否则衰减不干净,高频噪声会被折叠回通带。

另一个关键参数是采样时长。频率分辨率Δf = fs / N,N是采样点数。想要区分相邻两个频率,比如转频23.5 Hz和24 Hz,Δf至少要小于0.5 Hz,这意味着采样时长至少2秒。很多初学朋友只关心采样率,忽略了采样时长,结果频谱上两个峰糊在一起,这是典型的参数搭配失误。实际采集设备保存数据时常常只给采样率和波形,点数、时长、分辨率这三者的关系必须在拿到数据的瞬间就换算清楚。

下面给一个最小示例,生成一个模拟振动信号并做基础检查。这个示例会贯穿后面几章,你可以直接复制运行。

fs = 5120; % 采样率 5120 Hz T = 4; % 采样时长 4 秒 N = fs * T; % 总点数 t = (0:N-1)/fs; % 时间轴 % 构造两个频率分量:23.5 Hz 和 24 Hz,幅值分别为 1 和 0.8 f1 = 23.5; f2 = 24; x = 1.0*sin(2*pi*f1*t) + 0.8*sin(2*pi*f2*t) + 0.3*randn(1,N);

这段代码用4秒时长、5120 Hz采样。频率分辨率Δf = 5120/20480 = 0.25 Hz,足以区分23.5和24 Hz。如果采样时长缩短到0.5秒,Δf = 2 Hz,谱线上两个峰就会变成一个包络,此时无论采样率多高都救不回来。这个认知是后续所有频域分析的基础。站点上采集的信号通常不是仿真这么干净,但采样率和时长的关系是完全一样的。

2.2 去趋势项与异常值剔除:收拾原始数据的第一步

传感器输出常带有偏置或缓变趋势。比如压电式加速度计若无内置去耦,可能叠加一个缓慢变化的直流分量;或者被测结构本身存在温度漂移,导致信号基线随时间缓慢上移。如果直接做FFT,零频附近会出现很大的能量,甚至让低频段被掩盖。MATLAB 里去趋势项最直接的是 detrend 函数。

detrend 可以去除线性趋势,默认是把数据拟合成一条直线并减去。对于振动信号,我建议先看整体波形,再决定用 'linear' 还是 'constant'。如果趋势明显非线性,分段去趋势更稳妥,但要注意分段会引入拼接瞬态。另一个常见操作是剔除异常峰值,比如电缆松动造成的瞬间毛刺,用 filloutliers 按中位数填充比直接删除更好,因为删除会让时间轴错位,后续时频分析会出问题。代码示例:

% 模拟带趋势的振动信号 trend_signal = 0.5 * exp(t./4) + 1.5; % 指数趋势 x_raw = x + trend_signal; % 叠加趋势 % 去线性趋势 x_detrend = detrend(x_raw, 'linear'); % 剔除并填充异常值 x_clean = filloutliers(x_detrend, 'linear', 'movmedian', 101, 'ThresholdFactor', 3);

filloutliers 的关键参数是 'movmedian' 窗口大小101和 'ThresholdFactor' 3。窗口根据采样率调整,如果采样率是5120 Hz,101点覆盖约20毫秒,能捕捉到脉冲型毛刺。阈值3表示偏离局部中位数3倍标准差的点被标记。这里用 'linear' 方法填充,即以邻近正常点线性插值。参数改动的原则是:窗口越宽识别越平缓,阈值越小越敏感,需要结合实测波形反复试。如果发现去趋势后信号均值依然不为零,可以用x_clean = x_clean - mean(x_clean)强制归零。但要注意,如果是做包络分析,去均值是必须的,否则包络谱直流分量会很大。

2.3 滤波器选型与实作:低通、带通、陷波怎么选

振动分析中滤波不是拍脑袋选的。首先要明确目标频率区间。如果是分析齿轮箱啮合频率附近的高频故障特征,可以用带通滤波器;如果只是去除电源工频干扰,用陷波器;如果担心高频噪声影响包络分析,可以先用低通把无关频带压掉。但是滤波会带来相位延迟,尤其IIR滤波器存在非线性相位,为此我一般用 filtfilt 做零相位滤波。

设计滤波器我推荐 designfilt 而不是老式的 butter、cheby1 写在纸面上。designfilt 的语法更接近需求描述,且能自动检查是否满足约束。比如要做一个带通,通带是 800~1600 Hz,采样率5120 Hz的话,通带不能太接近奈奎斯特频率(上限是2560 Hz),所以完全可行。代码:

% 设计带通滤波器:通带 800~1600 Hz,过渡带各 200 Hz bpFilt = designfilt('bandpassfir', ... 'StopbandFrequency1', 600, 'PassbandFrequency1', 800, ... 'PassbandFrequency2',1600,'StopbandFrequency2',1800, ... 'StopbandAttenuation1', 60, 'PassbandRipple', 1, ... 'StopbandAttenuation2', 60, 'SampleRate', fs); % 零相位滤波 x_filt = filtfilt(bpFilt, x_clean);

这里 FIR 滤波器阶数由 designfilt 根据指标自动确定。如果发现滤波后信号变慢,可能是过渡带设得太窄,导致阶数很高,计算量上升。最直接的排查方式是freqz(bpFilt)看幅频响应是否在通带内平坦。另外注意,filtfilt 对信号边界的处理会延拓两端,如果信号本身只有几百个点,滤波结果两端会出现失真,此时要舍去两端各一段数据。设计滤波器时永远要先算清楚通带和过渡带占奈奎斯特频率的比例,比如采样率1000 Hz,最高有效频率500 Hz,通带上限设在400 Hz已经是极限,再高就没有过渡带空间了。

滤波设计完成以后,建议把原始信号和滤波后的信号画在同一张图上对比,使用 subplot 和 plot 快速确认波形形态是否合理。同时,把滤波前后的频谱叠加在 log 坐标下观察,看通带外是否衰减到位。这一步只需要三行代码,却能在几分钟内暴露滤波器设计错误,比盯着参数面板猜要高效得多。实际处理中,我见过有人在采样率只有1000 Hz时设计通带上限600 Hz的带通滤波器,结果过渡带没有余量,designfilt 直接报错,这就是没有先做频率规划。滤波不是越强越好,每多一级滤波就多引入一级相位变化和边界效应,能用带通解决就不要用低通加高通串联。

3. 时域特征与包络分析:从波形波动中提炼故障线索

3.1 时域统计特征:均值、峰值、峭度、裕度因子

时域特征计算成本低,适合做连续监测时的第一道筛子。振动信号的均值通常接近零,否则说明有直流分量;峰值容易受单次冲击影响,不能单独使用。真正有区分度的是峭度和裕度因子。峭度对脉冲型故障非常敏感,正常轴承振动接近高斯分布,峭度约为3,早期剥落会产生稀疏大脉冲,峭度迅速上升。裕度因子是峰值除以方均根,它对冲击也敏感,而且抗干扰能力强于单独峰值。

这些指标在MATLAB里可以直接用函数,但不建议一行行手工累加,因为数据量一大容易出错。用一个函数封起来:

function [features] = timeDomainFeatures(x, fs) N = length(x); mu = mean(x); sd = std(x); rms_val = sqrt(mean(x.^2)); peak_val = max(abs(x)); kurtosis_val = mean((x - mu).^4) / sd^4; crest_val = peak_val / rms_val; shape_val = rms_val / mean(abs(x)); % 波形指标 features = table(mu, sd, rms_val, peak_val, kurtosis_val, crest_val, shape_val); end

峭度分母用标准差四次方,如果标准差为零会得到NaN,实际振动信号很少出现。波形因子在随机噪声下接近1.25,在正弦信号下接近1.11,如果偏离太多要考虑是否有其他周期成分。这些特征应该按固定窗口长度计算,比如每1秒一个窗口,重叠50%,得到随时间变化的趋势。窗口太短,特征抖动大;窗口太长,早期故障的瞬态变化被平均掉,我一般取至少包含20个旋转周期的时长。对旋转机械,旋转周期是1/转频。假如转频是25 Hz,周期0.04秒,20个周期就是0.8秒,那么窗口长度取1秒比较合适。如果设备转速变化,窗口长度就要随转频自适应,否则峭度这种高阶特征会不稳定,所以现场处理时我会先算出转速曲线再决定窗口。

3.2 包络分析:从 Hilbert 变换找调制边带

包络分析是滚动轴承和齿轮故障诊断的经典方法。轴承局部缺陷会产生周期脉冲,激起高频共振,信号表现为高频载波被低频脉冲调制。直接看频谱看不到调制频率,必须先把包络解调出来,再做FFT,从而得到故障特征频率。MATLAB 的实现路径是先带通滤波,选取共振频带,然后做 Hilbert 变换得到解析信号,再取模得到包络。

代码很简洁,但参数选择有讲究:

% 已经得到带通滤波后的 x_filt h = hilbert(x_filt); env = abs(h); % 对包络做 FFT,观察调制频率 N_env = length(env); f_env = (0:N_env-1)/N_env * fs; spec_env = abs(fft(env - mean(env))) * 2 / N_env;

注意在做包络谱前要减去均值,否则直流分量会占据谱图第一根谱线。Hilbert变换对端部不连续很敏感,所以通常只取中间大部分做分析,比如舍弃前5%后5%。带通滤波的中心频率选择决定了包络效果,如果共振频带选偏了,包络谱可能淹没在噪声里。我会先用pspectrum看原始信号的三维谱图,找出共振峰集中的频带,再用 2.3 节的方法设计窄带带通滤波器。这个环节被很多人当成玄学,其实本质就是找到信噪比最高的频段。

举一个实际经验:某次在模拟项目X中,轴承外圈故障特征频率理论计算约为 103.6 Hz,但包络谱上只在 104 Hz 附近看到一个小峰,幅值并不突出。后来把带通滤波从 2000~3000 Hz 调到 5000~8000 Hz,峰幅值立刻上升了一个数量级。这是因为故障激起的共振频带在更高位置,而低频频带里主要是转频和噪声。所以求包络前一定要认真做共振频带搜索,不要用某个固定频带跑所有数据。

3.3 特征矩阵构建:为后续诊断和机器学习打底

当有多个测点或者连续采集多个窗口时,需要把特征整合成矩阵,一行代表一个样本,一列代表一个特征。后续无论是做阈值报警、聚类还是神经网络输入,都需要这种结构化数据。我常用 table 存储,因为列名不会丢,后续可以直接读列名做特征选择。

function featMat = buildFeatureMatrix(x_all, fs, winLen, overlap) % x_all: 通道数×总点数 或 单通道长向量 % winLen: 窗口秒数 % overlap: 0~1 重叠比例 n = size(x_all, 1); winLenPts = round(winLen * fs); step = round(winLenPts * (1 - overlap)); starts = 1:step:(size(x_all,2)-winLenPts+1); featMat = table(); for k = 1:n row = []; for idx = starts seg = x_all(k, idx:idx+winLenPts-1); f = timeDomainFeatures(seg, fs); f = removevars(f, 'mu'); % 去除均值防止重复 row = [row; table2array(f)]; end featMat = [featMat; array2table(row)]; end end

注意不同通道的采样率必须一致,窗口对齐。数据量大时不要用循环拼接 table,会越跑越慢,建议预先用 zeros 分配数值矩阵,最后转成 table。这个脚本框架也是后面做批处理的基础。特征并不是越多越好,通常先保留峭度、峰值因子、包络谱特征频率处的幅值等对故障敏感的十几个特征,再用 PCA 或互信息筛掉冗余列,避免把噪声也喂给分类器。

另外,在构建特征矩阵时,一定要把工况参数也列进来,比如转速、负载、温度。原因很简单,故障特征会随转速变化,如果没有这些列,后续做分类时会出现同一故障在不同转速下被识别成不同类别。把工况参数跟统计特征合并到同一张表里,至少可以先简单做个归一化,再看特征与标签的关系。实际做故障诊断时,我比较喜欢用箱线图观察每个特征在不同类别下的分布。如果某个特征的箱子重叠严重,就删掉它;如果两个特征高度相关,留一个即可。这种手工筛选虽然朴素,但比盲目堆特征更可靠。等筛选完,再做标准化和降维,最终得到的数据才能进入训练流程。

4. 频域分析与阶次分析:FFT 参数陷阱与功率谱密度实用要点

4.1 FFT 的频率分辨率和泄漏问题:加窗与补零

FFT 是频域分析的基石,但很多翻车现场都发生在边界的处理上。频率分辨率 Δf = fs / N,这个数值决定了两个频率能分开多远。如果信号不是整周期截断,频谱会发生泄漏,本来集中的一根谱线扩散到相邻多根。补零不能提高频率分辨率,它只让谱线变密,很多人以为补零能“看出”更多细节,其实原始分辨率的极限没有变化。比如采样率1024,采样1秒,N=1024,Δf=1 Hz,补零到4096点后,视觉上谱线变细,但频峰宽度依然是1 Hz量级,真正的做法是延长采样时间。

在做 FFT 前一定要先考虑是否需要加窗。Hanning 窗适合随机信号,Kaiser 窗旁瓣可调,矩形窗只适合整周期信号。瞬态冲击信号加 Hanning 会削峰,我会选择矩形窗或者专门分析冲击的瞬态窗。下面这段代码展示了加窗和幅值恢复:

win = hanning(N, 'periodic')'; xw = x_clean .* win; % 幅值修正:加窗后幅值会降低,需要按窗能量恢复 U = sum(win.^2); % 能量修正系数 spec = abs(fft(xw)) * 2 / N; % 单边谱幅值 spec = spec * sqrt(N/U); % 幅值恢复 f = (0:floor(N/2)-1) * fs / N;

这里 sqrt(N/U) 是常见的幅值恢复因子,不同窗系数不同,但原理都是一样的。实际工程里我更倾向用 pwelch 直接估计功率谱密度,因为它的平均和加窗处理都封装好了,不容易犯幅值换算错误。但要注意 pwelch 输出的是功率谱密度,单位不是幅值,不能直接拿峰值和 FFT 谱线比。加窗还有一个容易被忽略的点:窗函数会影响峰值频率附近的旁瓣水平。对于强干扰,需要选择旁瓣衰减大的窗,比如 Kaiser 窗的 beta 可以调。如果只分析正弦叠加,Hanning 就已经够用;一旦发现频率相近的强峰弱峰,就改用 Flattop 窗来获得更准确的幅值,但 Flattop 窗的主瓣很宽,频率分辨率会下降。这些窗的选择本质上是在谱分辨率和幅值精度之间做权衡。

4.2 功率谱密度估计:pwelch 的参数设置

pwelch 采用 Welch 平均法,把信号分段、加窗、做 FFT 再平均,方差小,谱线平滑。关键参数是段长、重叠率和窗函数。段长决定频率分辨率,重叠率决定平均次数,两者是权衡。比如段长设为 Nseg=2048,频率分辨率 Δf = fs / Nseg,如果 fs=5120,Δf=2.5 Hz。若想分辨率更高,就要增大段长或降低采样率,但段长越大,平均次数越少,谱的方差越大。我的经验是重叠取50%,窗用 hann,段长取 2 的整数次幂便于 FFT。

还有一个容易忽略的输入形式:pwelch(x, win, noverlap, nfft, fs)。如果把 nfft 设得比实际段长更大,相当于补零,谱线变密但不会真正提高分辨率,所以不必盲目设大。代码示例:

[pxx, f] = pwelch(x_clean, hann(2048), 1024, 2048, fs); % 提取 2~1000 Hz 频段的总功率 idx = f >= 2 & f <= 1000; bandPower = trapz(f(idx), pxx(idx));

bandPower 是频带内的总功率,单位 g^2 或 m/s^2 的平方,可以用于监测频带能量变化。在故障诊断里,高频带能量上升往往对应冲击性故障,所以这条指标值得存档。注意 pwelch 默认返回单边 PSD,幅值已经包含了单边修正,不需要自己再乘以2。还有一点,pwelch 的输入信号如果是多维数组,它会沿每一列分别计算,所以如果有多个通道,把数据排成矩阵即可一次算出所有通道的 PSD,但要注意返回的 pxx 维度。通常我会对每个通道单独调用,让代码更明确。

注意:pwelch 返回的是功率谱密度,不是幅值谱。如果你要对比某根谱线的幅值,应该用 FFT 加上窗修正;如果要看频带能量趋势,PSD 更合适,两者不要混用。

下面给一个实用的参数选择表格,供直接对照:

应用场景段长(点)重叠率窗函数频率分辨率
稳态工况,频率分辨率优先819250%hanningfs/8192
非稳态工况,趋势变化快102475%hanningfs/1024
幅值精度优先409650%flattopwinfs/4096
巡检数据,快速浏览5120%hanningfs/512

这个表格可以直接保存为笔记。实际使用时,如果信号长度不够一个段长,pwelch 会自动补零并警告,所以最好保证数据长度至少为段长的两倍。

4.3 阶次分析:变转速工况下的重采样思路

旋转机械转速波动时,FFT 上的谱峰会模糊,因为转频本身在变。阶次分析的核心是把等时间采样转化为等角度采样,即将信号按转轴转角重采样,得到转频倍数的阶次谱。MATLAB 中没有内置专门的一键函数,但可结合转速脉冲序列手工实现。常见做法是用转速计每转产生一个脉冲,拟合瞬时转速,再通过 cumtrapz 计算转角,最后用 interp1 把信号插值到等角度轴上。

% 已知脉冲时刻 tp(秒)和每转脉冲数 ppg % 先求瞬时转速 Npulse = length(tp); phase_unwrapped = (0:Npulse-1) * (2*pi/ppg); % 转角 theta = interp1(tp, phase_unwrapped, t, 'linear', 'extrap'); % 设定每圈采样点数 osr,构造等角度轴 theta_target = theta(1): (2*pi/osr) : theta(end); x_angle = interp1(theta, x_clean, theta_target, 'pchip');

这里的 osr 就是每转采样点数,决定角域频率分辨率。做 FFT 时,横轴不再是 Hz,而是阶次,1 阶等于每转一次。阶次谱上的尖峰对应与转速同步的振动特征。这个领域坑很多,比如脉冲误触发导致相位曲线跳变,重采样后信号长度会变得不规则,需要配合转速曲线校验。如果转速变化超过20%,建议先用低通滤波器去除高频噪声再重采样,否则混叠会更明显。

阶次谱的横轴分辨率怎么定?阶次分辨率是 1 /(总转数),也就是说,采样时间内转越多圈,阶次分辨率越高。假设采样4秒、平均转速1500 rpm(25转/秒),总转数100,阶次分辨率为0.01阶,足以分辨0.5阶的边带。如果转速很低,比如300 rpm只有5转/秒,4秒总转数20,阶次分辨率0.05阶,边带可能分辨不出来。这种时候只能延长采样时间,没有其他窍门。阶次分析还有一个常见误区,就是直接用时间域的自相关或 FFT 近似,那只能处理恒定转速。如果转速波动,时间域的特征频率会随转速漂移,必须依赖角度域。现在的商业软件里都有现成模块,MATLAB 没有一键,但手工重采样也就二十行代码,关键是理解脉冲计数的可靠性。

5. MATLAB 振动信号处理的 5 个避坑与排查记录

这一章里的每个问题我都至少遇到过两次,有些是在现场调试时花了半天才定位的。如果你照着前面的流程做,大概率会在某个环节撞上其中一两条。我把排查思路写成“现象→原因→解决”的格式,方便你直接对照,也省得再走一遍我当年的弯路。

5.1 FFT 峰值幅值对不上理论值:先检查窗修正和整周期

现象:用幅值为1的正弦信号做 FFT,峰值却只显示0.6或者1.7,幅度漂移很大。原因往往有两个:一是信号没有整周期截断,能量泄漏到旁瓣,主瓣幅值被摊薄;二是加了窗但没有做幅值修正,Hanning窗会使信号均方根变化,不修正幅值必然偏低。解决方法是先判断分析对象。如果只是想看频率位置,幅值偏差可以容忍;如果要测幅值,必须保证信号长度是目标频率周期的整数倍,或者使用幅值修正公式。我在脚本里固定一个 amplitudeCorrection 函数,每次 FFT 都调用,避免重复踩坑。这个函数核心就是计算窗能量系数,把峰值恢复到真实幅值附近。判断泄漏也很简单:看峰旁边是否出现很多小旁瓣,如果旁瓣高到接近主瓣,基本就是截断问题,先延长采样再谈加窗。

5.2 filtfilt 滤波后信号头尾振荡:边界效应处理

现象:filtfilt 似乎能消除相位偏移,但滤波后的信号在开头和结尾出现幅度很大的振荡,甚至盖过真实波形。原因:filtfilt 为了做零相位,会先正向滤波再反向滤波,边界延拓不够平滑会导致瞬态被放大。解决:滤波前先对信号做镜像延拓,或者滤波后直接舍去两端各约滤波器阶数一半的点数。如果分析窗口本身很长,舍去几百个点影响不大。千万不要因为边界振荡就把整个滤波结果扔掉,只需要截取中间稳定区域。我一般先看 filtfilt 后的信号前后各200点是否收敛,再决定截断范围。如果你的数据本身很短,比如只有1000点,那就要考虑改用一维中值滤波或者放弃零相位滤波,因为边界损失占比太高。

5.3 包络谱找不到故障特征频率:共振频带选择问题

现象:按理论计算出的轴承故障特征频率,包络谱上能看到一个峰,但幅值很小,或者完全被其他频率淹没。原因:带通滤波器的中心频率没有选在共振频带上。故障冲击激起的振动会经过结构传递,共振频带可能落在几千赫兹甚至更高,如果只按经验选一个低频带,包络信号的调制深度很低。解决:先对原始信号做谱图和功率谱密度分析,找到随时间持续存在的能量带,再设计窄带带通。另一个简单办法是直接用envspectrum(如果版本支持)自动搜索共振频带,但它的输出仍需人工确认。我的习惯是至少测试三个候选频带,对比包络谱特征峰幅值,选定最高者。不要嫌麻烦,这一步比后面所有算法都重要。

5.4 采样率够但高频段出现毛刺:抗混叠和降采样顺序

现象:采样率设为2000 Hz,按理说1000 Hz以下都是有效频段,但频谱在接近1000 Hz处出现未知毛刺。原因:可能是采集卡抗混叠滤波器未启用,也可能是你在处理流程里用了resample或decimate但忘了先低通。如果信号本身含有超过奈奎斯特频率的成分,它们会被混叠回可见频段。解决:如果是数据采集阶段,确认硬件上启用了内抗混叠滤波;如果是软件降采样,先用低通滤波器截止到目标奈奎斯特频率以下,再抽取。MATLAB 的resample默认会自动设计抗混叠滤波器,但downsample不会,所以不要混用。最好用resample,并把新的采样率设为原始采样率的整数分之一。毛刺出现的位置通常是以奈奎斯特频率为镜像对称的,比如原始信号里有2200 Hz,采样率4000 Hz时会被折叠到1800 Hz,根据这一点可以反向推断混叠来源。

5.5 小波重构后信号长度不匹配:边界延拓与频带划分

现象:用wavedec分解信号后,用waverec重构,却得到比原始信号更长或更短的长度。原因:小波变换在边界处需要延拓,默认模式可能改变长度;也可能是你用了wrcoef提取某层细节系数,然后直接相加,不同层系数长度不同。解决:在调用wavedec时显式指定'sym'或'per'延拓模式,并检查输入信号长度是否为2的整数次幂(如果不是,先补零或截断)。重构长度不对时,通常是因为每层细节系数的长度与下一层不一致,直接相加会报错。实际故障诊断中,我更推荐只保存各层细节系数的能量和包络谱,不必强制重构完整波形,因为层数选择不当重构也会失真。如果确实需要重构,就逐层用wrcoef返回与原始信号长度相同的系数,再叠加,不要直接操作appcoef返回的降采样数组。

6. 把处理流程固化成一个可复用的脚本框架:从单次分析到批处理

比起每次打开一个新数据文件重复写滤波和 FFT,我更建议把整个流程封装成一个函数,输入.mat文件路径,输出特征列表,然后所有新数据都走同一条路。这样既能保证参数一致,又能在改参数时只改一处,不用翻遍脚本。

function analyzeVibrationFile(matPath, resultDir, fs) data = load(matPath); x = data.vibration; if isempty(fs) || fs <= 0 fs = 5120; end x = detrend(x, 'linear'); x = filloutliers(x, 'linear', 'movmedian', 101, 'ThresholdFactor', 3); feat = timeDomainFeatures(x, fs); [pxx, f] = pwelch(x, hann(2048), 1024, 2048, fs); fband = f >= 500 & f <= 2000; feat.bandPower = trapz(f(fband), pxx(fband)); [~, name] = fileparts(matPath); resultFile = fullfile(resultDir, [name '_feat.mat']); save(resultFile, 'feat', 'fs'); end

这个函数的核心是固定流程,把去趋势、剔除异常值、时域特征、频带功率都放进一个入口。批处理时可以用parfor加速,但要注意parfor需要所有写入结果分布在独立变量上,一般用files索引保存即可,避免竞争写入。

写完之后,一定要做一次 smoke test。我的习惯是构造一段已知的正弦信号,例如幅值1、频率100 Hz,然后调用这个函数,检查输出的 rms 值是否逼近 0.7071,频带功率是否落在理论范围内。下面是最小的验证代码:

fs = 5120; t = 0:1/fs:2; x = sin(2*pi*100*t); feat = timeDomainFeatures(x, fs); assert(abs(feat.rms_val - 0.7071) < 0.01);

我现在的习惯是每个新数据集先跑一遍 smoke test,确认滤波和 FFT 的结果在容差内,再处理真实数据。这样做至少筛掉了我以前一半的“玄学”问题。以前我懒得做这一步,结果在某个测试台数据上浪费了一整天去查一个根本不是问题的“异常峰值”。希望这个流程能帮你少走这些弯路,也让你手里的振动数据真正变成可判断设备状态的特征,而不是一堆画不干净的曲线。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询