简介:本资源是一套面向机械故障诊断工程师、信号处理研究者及高校相关专业师生的MATLAB实践源码,聚焦滚珠轴承早期故障识别这一工业关键问题,解决旋转机械状态监测中非平稳振动信号特征提取难、故障定位精度低等实际痛点。压缩包共6个文件,含4个故障数据集ZIP(涵盖内圈、外圈故障实测信号)与2个核心MATLAB脚本(balls.m与Balls2.m),分别实现FFT频谱分析与双层小波分解(近似+细节分量),便于对比时频特性并提取微弱冲击特征;整体包体45.19MB,结构简洁,开箱即用。已有45人学习下载,提供从原始振动数据加载、去噪预处理、多尺度小波系数计算到故障特征可视化的一站式代码实现,附带Sample Outputs.zip供结果比对,显著降低算法复现门槛,助力快速掌握基于小波的轴承故障诊断工程落地方法。
1. 从“听声辨位”到“数据说话”:工业轴承故障诊断的演进
在工厂车间里,经验丰富的老师傅把耳朵贴在设备外壳上,通过轴承运转时发出的“咔哒”声或沉闷的摩擦声,就能大致判断出内部滚珠或滚道是否出现了损伤。这种“听声辨位”的技艺,是早期故障诊断的智慧结晶,但它高度依赖个人经验,难以量化,更无法实现大规模、自动化的设备健康管理。随着工业4.0和预测性维护概念的普及,我们迫切需要将这种“经验”转化为“数据”,将“耳听”升级为“算法分析”。而MATLAB,作为工程计算和数据分析领域的瑞士军刀,自然成为了实现这一转变的利器。今天,我们就来深入聊聊,如何利用MATLAB,从零开始构建一套滚珠轴承的故障诊断系统源码。这不仅仅是写几行代码,更是理解从信号采集、特征提取到智能识别的完整技术链条。
滚珠轴承作为旋转机械的核心部件,其健康状态直接关系到整台设备的运行安全与效率。典型的故障模式包括内圈故障、外圈故障、滚动体故障和保持架故障。每种故障都会在轴承运转时,激发特定的振动信号。我们的核心任务,就是充当设备的“内科医生”,通过“听诊器”(振动传感器)采集“心跳”(振动信号),然后利用“化验分析”(信号处理与特征提取)和“专家会诊”(机器学习算法)来确诊“病情”(故障类型与严重程度)。本文将围绕这一主线,拆解每一个技术环节,并提供可直接复现的MATLAB代码框架与实操心得。
2. 诊断基石:振动信号的数据获取与仿真生成
在实际工业场景中,我们需要通过加速度传感器采集轴承的振动信号。但对于学习和算法开发而言,获取大量、多样且标签清晰的真实故障数据成本高昂。因此,我们常常从仿真或公开数据集入手。最著名且被广泛使用的莫过于美国凯斯西储大学(CWRU)的轴承数据中心公开数据。我们的源码将以此数据为基础进行演示。
2.1 数据准备与理解:CWRU数据集解读
CWRU数据是在一个实验台架上采集的,驱动端轴承为SKF 6205-2RS深沟球轴承。数据包含了正常状态、内圈故障、外圈故障(分别在3点、6点、12点钟方向)和滚动体故障,每种故障又有不同尺寸(如0.007英寸,0.014英寸,0.021英寸)的损伤。采样频率通常为12 kHz或48 kHz。
在MATLAB中处理这些数据的第一步是读取和观察。数据通常以.mat文件或文本文件形式提供。我们需要明确几个关键参数:采样频率Fs、数据长度N、对应的转速(RPM)以及故障类型标签。
% 示例:加载并可视化一段振动信号 load('97.mat'); % 假设加载了CWRU的某个数据文件,变量名为‘bearing’或‘vibration’ data = bearing.vibration; % 具体变量名需根据实际文件调整 Fs = 12000; % 采样频率,单位Hz N = length(data); t = (0:N-1)/Fs; % 时间轴 figure; subplot(2,1,1); plot(t, data); xlabel('时间 (s)'); ylabel('振幅'); title('原始振动信号时域波形'); grid on; % 计算并绘制频谱 Y = fft(data); P2 = abs(Y/N); P1 = P2(1:floor(N/2)+1); P1(2:end-1) = 2*P1(2:end-1); f = Fs*(0:(N/2))/N; subplot(2,1,2); plot(f, P1); xlabel('频率 (Hz)'); ylabel('幅值'); title('单边振幅谱'); xlim([0, 1000]); % 重点关注低频段,故障特征频率通常在此范围内 grid on;这段代码完成了最基础的时域和频域观察。但原始信号往往包含大量噪声和无关的工频干扰,直接观察频谱可能一无所获。故障特征频率(如轴承的通过频率)能量很小,容易被淹没。这就是为什么我们需要更精细的信号处理技术。
注意:公开数据集的文件命名和内部变量结构可能不统一。务必仔细阅读数据集的说明文档。一个良好的习惯是,在脚本开头用注释明确记录数据来源、采样参数和故障标签的映射关系,避免后续混淆。
2.2 核心预处理:滤波与重采样
振动信号中的高频噪声和低频趋势项会干扰特征提取。常用的预处理包括去趋势和带通滤波。去趋势是为了消除信号中缓慢变化的基线漂移。带通滤波则根据轴承故障特征频率的范围(通常为几十Hz到几千Hz)来保留有效频段,滤除高频噪声和极低频的干扰。
% 1. 去趋势 data_detrend = detrend(data); % 2. 设计一个带通滤波器,例如通带为50Hz - 2000Hz Fpass1 = 50; % 通带下限频率 Fpass2 = 2000; % 通带上限频率 Fstop1 = Fpass1 - 20; % 阻带下限频率 Fstop2 = Fpass2 + 500; % 阻带上限频率 Apass = 1; % 通带衰减,dB Astop = 60; % 阻带衰减,dB % 使用fdesign设计滤波器 d = fdesign.bandpass('Fst1,Fp1,Fp2,Fst2,Ast1,Ap,Ast2', ... Fstop1, Fpass1, Fpass2, Fstop2, Astop, Apass, Astop, Fs); Hd = design(d, 'equiripple'); % 应用滤波器 data_filtered = filter(Hd, data_detrend); % 可视化滤波效果 figure; plot(t, data, 'b', 'LineWidth', 0.5); hold on; plot(t, data_filtered, 'r', 'LineWidth', 1.5); xlabel('时间 (s)'); ylabel('振幅'); legend('原始信号', '滤波后信号'); title('信号滤波前后对比'); grid on;滤波器的设计是一门艺术。选择“equiripple”(等波纹)设计是因为它在通带和阻带都能提供精确的控制。阻带衰减Astop设为60dB意味着能将阻带频率成分衰减到原信号的千分之一,这对于抑制强工频干扰(50Hz/60Hz)及其谐波非常有效。通带范围需要根据轴承的几何参数和转速计算出的故障特征频率来设定,确保覆盖所有可能的故障频率及其边带。
3. 特征工程的灵魂:从波形中提炼“诊断指纹”
原始信号数据量巨大且信息冗余,直接扔给机器学习模型效果差且效率低。特征工程的目的,就是从一维振动信号中提取出能够高度表征其健康状态的、低维度的统计量或指标。这些特征构成了模型的“输入特征向量”。
3.1 时域特征:信号的“体格检查”
时域特征直接从信号的振幅随时间变化的波形中计算,反映信号的总体能量、波动性和分布特性。它们是计算最快、最直观的特征。
function features_time = extractTimeDomainFeatures(signal) % 提取常用时域特征 features_time = zeros(1, 11); % 预分配空间 % 1. 基本统计量 features_time(1) = mean(signal); % 均值 features_time(2) = std(signal); % 标准差 features_time(3) = rms(signal); % 均方根值 - 总体能量 features_time(4) = peak2peak(signal); % 峰峰值 features_time(5) = skewness(signal); % 偏度 - 分布不对称性 features_time(6) = kurtosis(signal); % 峭度 - 冲击敏感性(对故障非常敏感!) % 2. 无量纲指标(对负载和转速变化相对不敏感) features_time(7) = features_time(4) / features_time(3); % 峰值因子 features_time(8) = features_time(4) / features_time(2); % 脉冲因子 features_time(9) = features_time(3) / mean(abs(signal)); % 波形因子 features_time(10) = (mean(sqrt(abs(signal))))^2 / features_time(3); % 裕度因子 features_time(11) = features_time(6) / (features_time(2)^4); % 峭度指标(标准化) end在这些特征中,峭度(Kurtosis)需要特别关注。正态分布的峭度为3。当轴承出现局部损伤(如点蚀、剥落)时,会产生瞬态冲击,使信号分布出现“重尾”,峭度值会显著大于3。因此,峭度是早期故障非常有效的指示器。但它的缺点是对背景噪声也敏感,在故障严重时可能反而下降。
3.2 频域特征:信号的“频谱分析报告”
故障会引发特定频率成分的能量变化。频域特征揭示了信号的频率结构。
function features_freq = extractFrequencyDomainFeatures(signal, Fs) % 提取频域特征 N = length(signal); Y = fft(signal); P2 = abs(Y/N); P1 = P2(1:floor(N/2)+1); P1(2:end-1) = 2*P1(2:end-1); f = Fs*(0:(N/2))/N; % 计算功率谱密度 (PSD) [psd, freq] = pwelch(signal, hanning(N/8), [], [], Fs); features_freq = zeros(1, 7); % 1. 重心频率 (FC) - 频谱能量分布的中心 features_freq(1) = sum(f .* P1) / sum(P1); % 2. 均方频率 (MSF) - 频谱的分散程度 features_freq(2) = sum((f.^2) .* P1) / sum(P1); % 3. 频率方差 (VF) - 频谱的波动 features_freq(3) = sum(((f - features_freq(1)).^2) .* P1) / sum(P1); % 4. 频谱峭度 (Spectral Kurtosis) - 特定频带的冲击性(需使用专用函数,此处简化) % 可以使用MATLAB的 `kurtogram` 函数进行更精确的计算,这里用频域幅值的峭度近似 features_freq(4) = kurtosis(P1); % 5-7. 特定频带能量比 (例如,划分低频、中频、高频段) freq_bands = [0, 100; 100, 1000; 1000, Fs/2]; % 划分三个频带 total_energy = sum(psd); for i = 1:size(freq_bands, 1) band_idx = freq >= freq_bands(i,1) & freq < freq_bands(i,2); band_energy = sum(psd(band_idx)); features_freq(4+i) = band_energy / total_energy; % 特征(5),(6),(7) end end频域特征能有效区分不同故障类型。例如,内圈故障频率(BPFI)及其谐波通常伴随着转频的边带;而外圈故障频率(BPFO)的谐波则更为清晰。通过计算各频带的能量比,可以捕捉到能量从基频向高频转移的趋势,这是故障发展的一个标志。
3.3 时频域特征:信号的“动态心电图”
轴承故障冲击是非平稳信号,其频率成分可能随时间变化。短时傅里叶变换(STFT)或小波变换(WT)等时频分析工具,可以同时观察信号在时间和频率上的演变。
% 使用连续小波变换 (CWT) 提取时频图并计算特征 function features_timefreq = extractTimeFreqFeatures(signal, Fs) % 执行连续小波变换 [cfs, frq] = cwt(signal, Fs); % 计算小波系数矩阵的统计量作为特征 % 1. 小波能量熵 - 反映时频能量分布的混乱程度 E = sum(abs(cfs).^2, 2); % 每个尺度(频率)上的能量 P = E / sum(E); % 能量概率分布 features_timefreq(1) = -sum(P .* log2(P + eps)); % 熵值 % 2. 小波系数矩阵的均值、标准差、峭度(按行或列计算后聚合) features_timefreq(2) = mean(abs(cfs(:))); features_timefreq(3) = std(abs(cfs(:))); features_timefreq(4) = kurtosis(abs(cfs(:))); % 3. 特定尺度(对应特定故障频率带)的能量集中度 % 假设我们关注与BPFO(外圈故障频率)相关的尺度范围 target_freq_range = [BPFO*0.8, BPFO*1.2]; % BPFO需提前计算 scale_idx = frq >= target_freq_range(1) & frq <= target_freq_range(2); if any(scale_idx) target_energy = sum(sum(abs(cfs(scale_idx, :)).^2)); total_energy = sum(sum(abs(cfs).^2)); features_timefreq(5) = target_energy / total_energy; else features_timefreq(5) = 0; end end时频特征信息量最丰富,但计算量也最大,且特征维数高。在实际应用中,需要权衡计算成本和诊断精度。对于在线监测系统,可能优先选择时域和频域特征;对于离线深度分析,时频特征则能提供更可靠的依据。
实操心得:特征工程不是越多越好。高维特征会引发“维度灾难”,增加模型过拟合风险,且很多特征间存在强相关性(共线性)。务必在提取后,进行特征筛选(如基于方差、相关性、递归特征消除RFE)或降维(如主成分分析PCA)。我通常的做法是,先提取一个包含时域、频域、时频域的大特征池(比如50-100个特征),然后用PCA降到10-20维,再送入分类器,效果和效率往往能取得很好的平衡。
4. 故障特征频率的计算:诊断的“理论地图”
在分析频谱时,我们需要知道在哪里寻找故障的“蛛丝马迹”。这就需要计算轴承的故障特征频率(Defect Frequency)。这些频率是理论值,由轴承几何参数和转速决定。
function [BPFI, BPFO, BSF, FTF] = calculateBearingFreq(d, D, n, alpha, rpm) % 计算轴承故障特征频率 (单位: Hz) % 输入: % d: 滚动体直径 (mm) % D: 节圆直径 (mm) - 滚动体中心所在圆的直径 % n: 滚动体数量 % alpha: 接触角 (度),对于深沟球轴承通常为0 % rpm: 轴转速 (转/分钟) % % 输出: % BPFI: 内圈故障频率 (Ball Pass Frequency Inner race) % BPFO: 外圈故障频率 (Ball Pass Frequency Outer race) % BSF: 滚动体故障频率 (Ball Spin Frequency) % FTF: 保持架故障频率 (Fundamental Train Frequency) fr = rpm / 60; % 转频 (Hz) alpha_rad = deg2rad(alpha); % 计算公式 BPFI = n/2 * fr * (1 + (d/D)*cos(alpha_rad)); BPFO = n/2 * fr * (1 - (d/D)*cos(alpha_rad)); BSF = D/(2*d) * fr * (1 - (d/D)^2 * (cos(alpha_rad))^2); FTF = fr/2 * (1 - (d/D)*cos(alpha_rad)); end % 示例:计算SKF 6205轴承在1797 RPM下的故障频率 d = 7.94; % mm D = 39.04; % mm n = 9; alpha = 0; rpm = 1797; [BPFI, BPFO, BSF, FTF] = calculateBearingFreq(d, D, n, alpha, rpm); fprintf('BPFI: %.2f Hz\n', BPFI); fprintf('BPFO: %.2f Hz\n', BPFO); fprintf('BSF: %.2f Hz\n', BSF); fprintf('FTF: %.2f Hz\n', FTF);得到这些频率后,我们在观察信号的频谱或包络谱时,就可以重点查看在这些频率点及其谐波(2x, 3x...)处是否有明显的谱峰。例如,一个清晰的外圈故障,通常在频谱上会在BPFO的整数倍频率处出现明显的峰值。
5. 包络分析:从“毛刺”中提取“冲击脉搏”
当早期故障产生微弱的周期性冲击时,这些冲击会调制在高频的共振频率上。直接观察低频段频谱可能看不到BPFO/BPFI。包络分析(Envelope Analysis)是解决这个问题的经典方法。它的核心思想是“解调”——先通过带通滤波器捕捉由冲击激发的高频共振(即轴承或结构的固有频率),然后对这个高频信号进行包络检波(取绝对值或希尔伯特变换),最后对包络信号做频谱分析。这样得到的“包络谱”,其谱线就对应着故障冲击的重复频率(即BPFI/BPFO等),变得非常清晰。
function envelopeSpectrum = performEnvelopeAnalysis(signal, Fs, bandpassRange) % 执行包络分析 % bandpassRange: [lowFreq, highFreq],共振频带范围 % 1. 带通滤波,提取共振频带信号 bpFilt = designfilt('bandpassiir', 'FilterOrder', 4, ... 'HalfPowerFrequency1', bandpassRange(1), ... 'HalfPowerFrequency2', bandpassRange(2), ... 'SampleRate', Fs); signal_bp = filtfilt(bpFilt, signal); % 使用零相位滤波filtfilt % 2. 希尔伯特变换求解析信号,并取模得到包络 analyticSignal = hilbert(signal_bp); envelope = abs(analyticSignal); % 3. 对包络信号进行频谱分析(通常只需看低频部分,如0-500Hz) N_env = length(envelope); Y_env = fft(envelope); P2_env = abs(Y_env/N_env); P1_env = P2_env(1:floor(N_env/2)+1); P1_env(2:end-1) = 2*P1_env(2:end-1); f_env = Fs*(0:(N_env/2))/N_env; % 只返回低频部分 freqLimit = 500; % Hz idx = f_env <= freqLimit; envelopeSpectrum.freq = f_env(idx); envelopeSpectrum.amp = P1_env(idx); % 可视化 figure; plot(envelopeSpectrum.freq, envelopeSpectrum.amp); xlabel('频率 (Hz)'); ylabel('幅值'); title('包络谱'); grid on; hold on; % 可以在图上标注计算出的故障特征频率线 plot([BPFO, BPFO], [0, max(envelopeSpectrum.amp)*0.8], 'r--', 'LineWidth', 1.5); text(BPFO, max(envelopeSpectrum.amp)*0.85, 'BPFO', 'Color', 'r'); % ... 标注其他频率线 end % 使用示例:假设共振频带在2000-4000Hz bandpassRange = [2000, 4000]; envSpec = performEnvelopeAnalysis(data_filtered, Fs, bandpassRange);关键点在于共振频带的选择。如果选择的频带不包含被故障冲击激发的主要共振,包络分析就会失败。有几种方法确定共振频带:1)观察原始信号频谱,找到能量较高的频带;2)使用快速峭度图(Fast Kurtogram)自动寻找冲击成分最丰富的频带。MATLAB的Signal Processing Toolbox中提供了pkurtosis函数来辅助计算峭度图。
% 使用快速峭度图寻找最佳滤波频带 [~, ~, ~, fc, bw, ~] = kurtogram(data_filtered, Fs); % fc为中心频率,bw为带宽 optimalBand = [fc - bw/2, fc + bw/2];6. 构建诊断模型:从特征到决策
提取了高质量的特征后,我们就进入了机器学习建模阶段。这是一个典型的模式分类问题:输入是特征向量,输出是故障类别(如:正常、内圈故障、外圈故障、滚动体故障)。
6.1 数据准备与划分
首先,我们需要为所有样本(不同状态、不同严重程度的数据段)提取特征,并打上标签,构建特征矩阵X和标签向量Y。
% 假设有一个cell数组allSignals存储所有样本信号,allLabels存储对应标签 numSamples = length(allSignals); allFeatures = []; % 用于存储所有特征 allLabels = []; % 用于存储所有标签 for i = 1:numSamples signal = allSignals{i}; label = allLabels(i); % 提取多种特征并拼接 feat_time = extractTimeDomainFeatures(signal); feat_freq = extractFrequencyDomainFeatures(signal, Fs); % feat_timefreq = extractTimeFreqFeatures(signal, Fs); % 可选,计算量大 featureVector = [feat_time, feat_freq]; % 拼接特征 allFeatures = [allFeatures; featureVector]; allLabels = [allLabels; label]; end % 划分训练集和测试集 (70%训练,30%测试) cv = cvpartition(allLabels, 'HoldOut', 0.3); idxTrain = training(cv); idxTest = test(cv); X_train = allFeatures(idxTrain, :); Y_train = allLabels(idxTrain); X_test = allFeatures(idxTest, :); Y_test = allLabels(idxTest); % 特征标准化 (非常重要!) [Z_train, mu, sigma] = zscore(X_train); % 计算训练集的均值和标准差 Z_test = (X_test - mu) ./ sigma; % 用训练集的参数标准化测试集注意:必须使用训练集的统计量(均值和标准差)来标准化测试集,这是机器学习中的基本准则,用于模拟模型遇到全新数据时的场景。如果混在一起标准化,会引入数据泄露,严重高估模型性能。
6.2 模型选择与训练:支持向量机(SVM)实战
对于小样本、高维度的分类问题,支持向量机(SVM)通常表现稳健。MATLAB的Statistics and Machine Learning Toolbox提供了完整的SVM实现。
% 训练一个多类SVM分类器(使用一对一策略) template = templateSVM('KernelFunction', 'gaussian', ... % 高斯核(RBF) 'Standardize', false, ... % 我们已经手动标准化了 'KernelScale', 'auto'); % 自动选择核尺度 SVMModel = fitcecoc(Z_train, Y_train, 'Learners', template, ... 'Coding', 'onevsone', 'Verbose', 0); % 在训练集上预测,评估基础性能 Y_train_pred = predict(SVMModel, Z_train); trainAccuracy = sum(Y_train_pred == Y_train) / numel(Y_train); fprintf('训练集准确率: %.2f%%\n', trainAccuracy*100); % 在测试集上预测,评估泛化能力 Y_test_pred = predict(SVMModel, Z_test); testAccuracy = sum(Y_test_pred == Y_test) / numel(Y_test); fprintf('测试集准确率: %.2f%%\n', testAccuracy*100); % 生成混淆矩阵,查看详细分类情况 figure; cm = confusionchart(Y_test, Y_test_pred); cm.Title = '测试集混淆矩阵'; cm.RowSummary = 'row-normalized'; % 显示行归一化的百分比 cm.ColumnSummary = 'column-normalized';为什么选择高斯核SVM?轴承故障特征与类别之间的关系通常是非线性的。线性分类器(如线性核SVM)可能无法很好地区分。高斯核(RBF核)通过将数据映射到高维空间,能够处理非常复杂的非线性边界。KernelScale参数(即核函数的σ)控制着模型的复杂度,‘auto’选项是一个不错的起点,它会根据数据特征间的距离启发式地设置一个值。
6.3 模型优化:超参数调优
默认参数不一定最优。我们可以使用交叉验证网格搜索来寻找最优的BoxConstraint(惩罚参数C,控制分类错误与间隔的权衡)和KernelScale。
% 定义超参数搜索网格 boxConstraints = logspace(-3, 3, 7); % [0.001, 0.01, 0.1, 1, 10, 100, 1000] kernelScales = logspace(-3, 3, 7); % 核尺度 % 使用5折交叉验证进行网格搜索 cv = cvpartition(Y_train, 'KFold', 5); bestAccuracy = 0; bestParams = struct('BoxConstraint', 1, 'KernelScale', 1); for bc = boxConstraints for ks = kernelScales template = templateSVM('KernelFunction', 'gaussian', ... 'BoxConstraint', bc, ... 'KernelScale', ks, ... 'Standardize', false); SVMModel_cv = fitcecoc(Z_train, Y_train, 'Learners', template, ... 'Coding', 'onevsone', 'CVPartition', cv, ... 'Verbose', 0); currAccuracy = 1 - kfoldLoss(SVMModel_cv, 'LossFun', 'classiferror'); if currAccuracy > bestAccuracy bestAccuracy = currAccuracy; bestParams.BoxConstraint = bc; bestParams.KernelScale = ks; end end end fprintf('最佳交叉验证准确率: %.2f%%\n', bestAccuracy*100); fprintf('最佳参数 - BoxConstraint: %.4f, KernelScale: %.4f\n', ... bestParams.BoxConstraint, bestParams.KernelScale); % 用最佳参数重新训练最终模型 finalTemplate = templateSVM('KernelFunction', 'gaussian', ... 'BoxConstraint', bestParams.BoxConstraint, ... 'KernelScale', bestParams.KernelScale, ... 'Standardize', false); finalSVMModel = fitcecoc(Z_train, Y_train, 'Learners', finalTemplate, ... 'Coding', 'onevsone');网格搜索计算量较大,但对于提升模型性能至关重要。BoxConstraint值越大,模型对分类错误的惩罚越重,越倾向于在训练集上做到完美分类,但可能导致过拟合。KernelScale值越小,决策边界越复杂,同样容易过拟合;值越大,边界越平滑,可能欠拟合。
7. 从模型到系统:部署考量与性能提升思路
训练出一个高准确率的模型只是第一步。要将其应用于实际工业监测系统,还需要考虑更多工程问题。
7.1 模型轻量化与实时性
上述流程中,特征提取(尤其是时频特征)和SVM预测都可能比较耗时。在嵌入式设备或边缘计算网关上进行实时诊断时,需要考虑:
- 特征简化:优先选用计算量小的时域和频域特征,甚至研究深度学习模型进行端到端的特征学习与分类。
- 模型压缩:将训练好的SVM模型参数(支持向量、系数等)导出,用C/C++等语言实现轻量级推理。或者考虑更轻量的模型,如决策树、随机森林(在MATLAB中可用
fitctree,fitcensemble)。 - 分段与降采样:对于长时间序列,可以分段处理。在不损失故障信息的前提下,适当降低采样频率也能减少数据量。
7.2 处理类别不平衡与未知故障
实际数据中,正常样本远多于故障样本,这会导致模型偏向于预测“正常”。解决方法包括:
- 重采样:对少数类样本过采样(如SMOTE算法),或对多数类样本欠采样。
- 调整代价:在SVM中设置
'Cost'矩阵,提高误判故障的惩罚。
更棘手的是未知故障或故障严重程度分级。我们的模型是在已知故障类型上训练的,可能无法识别全新的故障模式。一个思路是将其构建为异常检测问题:先用大量正常数据训练一个模型(如单类SVM、自编码器),学习正常状态的模式;任何显著偏离该模式的状态即视为异常。对于严重程度分级,则可以将其建模为回归问题(预测故障尺寸)或有序多分类问题。
7.3 结合深度学习:卷积神经网络(CNN)的尝试
对于振动信号,也可以直接利用一维卷积神经网络(1D-CNN)进行端到端学习。CNN能自动从原始信号或简单的时频图(如STFT谱图)中学习层次化特征。
% 这是一个简化的1D-CNN网络结构示例 layers = [ sequenceInputLayer(1) % 输入为一维序列 convolution1dLayer(64, 10, 'Padding', 'same') % 卷积层 batchNormalizationLayer reluLayer maxPooling1dLayer(2, 'Stride', 2) convolution1dLayer(128, 10, 'Padding', 'same') batchNormalizationLayer reluLayer maxPooling1dLayer(2, 'Stride', 2) globalAveragePooling1dLayer fullyConnectedLayer(4) % 假设有4个故障类别 softmaxLayer classificationLayer]; options = trainingOptions('adam', ... 'MaxEpochs', 30, ... 'MiniBatchSize', 32, ... 'ValidationData', {X_val, Y_val}, ... % 需要提前准备好验证集 'Plots', 'training-progress', ... 'Verbose', false); % 注意:X_train需要重塑为 [1, sequenceLength, numSamples] 格式 net = trainNetwork(X_train_reshaped, categorical(Y_train), layers, options);深度学习的优势在于免去了复杂的手工特征工程,但其成功严重依赖于大量标注数据,且模型可解释性较差。在实际工业场景中,结合传统特征提取与机器学习模型,往往在数据量有限时能获得更稳定可靠的结果。
8. 源码框架整合与工程实践建议
最后,我将提供一个顶层的主程序框架,将上述模块串联起来,形成一个完整的、可运行的故障诊断流程示例。
%% 主程序:滚珠轴承故障诊断系统示例 clear; close all; clc; % 步骤1: 参数配置 config.Fs = 12000; % 采样频率 config.rpm = 1797; % 转速 config.bearingType = 'SKF6205'; % 轴承型号 config.faultTypes = {'Normal', 'IR007', 'IR014', 'OR007', 'OR014', 'B007', 'B014'}; % 故障类型标签 config.dataPath = './CWRU_Data/'; % 数据路径 % 步骤2: 加载并预处理数据 [allSignals, allLabels] = loadAndPreprocessData(config); % 步骤3: 特征提取 fprintf('开始特征提取...\n'); [allFeatures, featureNames] = extractAllFeatures(allSignals, config.Fs); fprintf('特征提取完成,共提取 %d 个特征。\n', size(allFeatures, 2)); % 步骤4: 特征后处理(标准化、降维) [featuresProcessed, pcaCoeff] = processFeatures(allFeatures); % 步骤5: 划分数据集 [trainIdx, testIdx] = splitData(allLabels, 0.7); X_train = featuresProcessed(trainIdx, :); Y_train = allLabels(trainIdx); X_test = featuresProcessed(testIdx, :); Y_test = allLabels(testIdx); % 步骤6: 训练SVM分类器 fprintf('训练SVM模型...\n'); SVMModel = trainSVMClassifier(X_train, Y_train); % 步骤7: 评估模型 fprintf('评估模型性能...\n'); evaluateModel(SVMModel, X_test, Y_test, config.faultTypes); % 步骤8: (可选)保存模型与参数 save('bearingFaultDiagnosisModel.mat', 'SVMModel', 'config', 'featureNames', 'pcaCoeff', 'mu', 'sigma'); fprintf('模型与参数已保存。\n'); %% 辅助函数定义(需在单独文件或脚本末尾实现) function [allSignals, allLabels] = loadAndPreprocessData(config) % 实现数据加载、分段、去趋势、滤波等 % 返回 cell 数组 allSignals 和对应的标签向量 allLabels end function [allFeatures, featureNames] = extractAllFeatures(signalCell, Fs) % 调用 extractTimeDomainFeatures, extractFrequencyDomainFeatures 等 % 将所有特征拼接,并生成特征名称列表 end function [featuresProcessed, pcaCoeff] = processFeatures(rawFeatures) % 实现标准化、PCA降维等 end function [trainIdx, testIdx] = splitData(labels, trainRatio) % 按比例分层划分训练集和测试集索引 end function model = trainSVMClassifier(X_train, Y_train) % 包含交叉验证网格搜索的SVM训练流程 end function evaluateModel(model, X_test, Y_test, classNames) % 实现预测、计算准确率、绘制混淆矩阵等 end给实践者的最后几点建议:
- 数据为王:再好的算法也弥补不了糟糕的数据。确保数据采集的传感器安装正确、采样参数合理、标签准确。对数据做充分的探索性分析(EDA),可视化观察不同故障信号的区别。
- 理解物理背景:不要盲目套用算法。理解轴承故障的机理、特征频率的计算方法、信号处理每一步的物理意义(比如为什么包络分析有效),这能帮助你在算法失效时快速定位问题。
- 搭建基线模型:先从简单的模型(如KNN、决策树)和基础特征(时域统计量)开始,建立一个性能基线。然后再逐步引入更复杂的特征和模型,并确认每一步都带来了实质性的性能提升。
- 重视可解释性:在工业界,很多时候“为什么模型这么判断”比“判断准确率有多高”更重要。使用像决策树、逻辑回归这类可解释性强的模型,或者通过特征重要性分析(如SVM的权重、随机森林的Gini重要性)来理解哪些特征对诊断贡献最大。
- 持续验证与更新:部署到现场的模型需要定期用新数据验证其性能。设备工况、环境噪声可能变化,模型可能需要在线更新或增量学习。
故障诊断是一个结合了信号处理、机械原理和机器学习的交叉领域。通过MATLAB这个强大的平台,我们可以系统地实践从数据到决策的完整链路。这套源码框架为你提供了一个坚实的起点,但真正的优化和适配,还需要你根据具体的轴承型号、设备工况和数据特点去深入打磨。
本文还有配套的精品资源,点击获取