新手案例-基于卷积神经网络的航空发动机剩余寿命预测方法

 1、文章概括

本文利用NASA提供的涡扇发动机退化数据集(数据链接),进行数据预处理,构建训练样本和测试样本。然后,搭建卷积神经网络(Convolutional Neural Network,CNN),学习训练数据。最后,利用测试数据,分析神经网络模型预测剩余使用寿命(Remaining useful life,RUL)的效果。

该例子来自于Mathwork官方教程:https://ww2.mathworks.cn/help/predmaint/ug/remaining-useful-life-estimation-using-convolutional-neural-network.html

分享的目的是希望新手能更好地理解基于深度学习的RUL预测流程。

1.1 技术路线

1.2 结果展示

上述结果分别为测试集的RSME偏差分布直方图和某个案例的RUL预测结果图。

从RSME偏差分布直方图中能发现,CNN网络模型对航天发动机的RUL预测偏差主要分布为10至15之间。

从RUL预测结果图能发现,随着RUL的逐渐降低,预测的RUL曲线逐渐逼近真实的RUL曲线,验证了CNN网络的可行性。

以上这些结果表明了卷积神经网络在航空发动机RUL预测可行性,但网络模型有待进一步的优化和改进。

代码采用了Matlab 2023a进行运行,欢迎大家测试和提出问题!

2.基于卷积神经网络的航空发动机剩余寿命预测方法

技术路线:

第一步:读取航空发动机的退化数据集,并开展数据预处理操作,整理训练样本和测试样本。

第二步:搭建卷积神经网络模型,并利用训练数据训练神经网络模型。

第三步:采用已训练的神经网络模型,预测测试样本的剩余使用寿命,并采用RMSE评估网络的预测效果。

2.1 故障模式识别OR剩余寿命预测的区别

基于卷积神经网络和连续小波变换的滚动轴承智能诊断研究是故障模式识别研究,本篇文章是剩余寿命预测研究。

两者的区别是前者是神经网络的分类研究,后者是神经网络的回归研究,分类和回归的区别是输出存在差异,分类的输出是1,2,3,4等已知的数值类别,回归的输出是一个区间的所有数值,这个数值是无法被完全列举出来的,而分类的输出可以。

2.2 卷积神经网络?

卷积神经网络(Convolutional Neural Networks,CNNs)是一种深度学习模型,它在图像处理、语音识别、自然语言处理等多个领域都有着广泛的应用。

CNNs的设计灵感来源于人类视觉系统的工作原理,它特别适合处理具有网格状拓扑结构的数据,如图像。著名的卷积神经网络模型有AlexNet、InceptionNet、VGGNet和ResNet等。

值得注意是,上述的这些卷积神经网络是对图片进行卷积操作,它会利用当前位置的前后四周的数据。而在本文案例中,在进行卷积操作时,处理的对象是时间序列,如果还按照上述的卷积方式,会将未来数据带入计算,这是矛盾的,因此需要改变卷积网络的参数。

3. 实验分析

该数据集为C-MAPSS模拟数据,该数据是模拟大型商用涡扇发动机的数据, 发动机简图如上图所示。该数据的代码采用了MATLAB及其Simulink模块。该模型的详细细节见参考文献1和2。

数据解读链接:C-MAPSS涡扇发动机仿真数据(PHM2008)

第一步:读取航空发动机的退化数据集,并开展数据预处理操作,整理训练样本和测试样本。

clc
close all
clear all
​
%数据变量的维度的含义
% data文件夹现在包含包含26列数字的文本文件,用空格分隔。
% 每一行都是在单个操作周期中获取的数据,每列表示不同的变量:
% 列 1 —  发动机单元编号
% 列 2 —  时间步
% 列 3–5 —  运行设置
% 列 6–26 —   传感器1–21
% 数据介绍页面(数据集A) https://mp.weixin.qq.com/s/RPToBmMvt5EJth42eXL2JA   
​
%% 数据预处理
dataFolder = "D:\我的文档\硕士\信息\副业\公众号\公众号" + ...
    "\20240518基于卷积神经网络的航空发动机剩余寿命预测方法\" + ...
    "20240518基于卷积神经网络的航空发动机剩余寿命预测方法\data";
filenameTrainPredictors = fullfile(dataFolder,"train_FD001.txt");
rawTrain = localLoadData(filenameTrainPredictors);  %训练样本 Table类型数据
​
head(rawTrain.X{1},8)   %展示部分数据的输入
​
rawTrain.Y{1}(1:8)    %展示部分数据的输出(RUL标签)
​
stackedplot(rawTrain.X{1},[3,5,6,7,8,15,16,24],XVariable='timeStamp')  %展示部分数据在单个样本周期的趋势
​
prog = prognosability(rawTrain.X,"timeStamp");% 判断单个样本全寿命周期中不随时间周期变换的特征,即无用的输入
 
idxToRemove = prog.Variables==0 | isnan(prog.Variables);   %无用的输入的索引
featToRetain = prog.Properties.VariableNames(~idxToRemove);
for i = 1:height(rawTrain)
    rawTrain.X{i} = rawTrain.X{i}{:,featToRetain};         %有用的输入
end
​
​
[~,Xmu,Xsigma] = zscore(vertcat(rawTrain.X{:}));         %归一化输入,准备进行Z标准化,
preTrain = table();
for i = 1:numel(rawTrain.X)                              %Z标准化
    preTrain.X{i} = (rawTrain.X{i} - Xmu) ./ Xsigma;
end
​
rulThreshold = 150;                                      %设置最大的RUL标签为150,过大的RUL没有指导意义,合适的RUL也有利于网络训练的收敛
for i = 1:numel(rawTrain.Y)                              %输出标签预处理
    preTrain.Y{i} = min(rawTrain.Y{i},rulThreshold);
end
​
​
for i = 1:size(preTrain,1)
    preTrain.X{i} = preTrain.X{i}';    %这是第一个维度为输入数据的特征维度
    preTrain.Y{i} = preTrain.Y{i}';    %输出也需要
    sequence = preTrain.X{i};
    sequenceLengths(i) = size(sequence,2); 
end
​
[sequenceLengths,idx] = sort(sequenceLengths,'descend');   %按照样本的时间长短进行排序,对网络训练有用
%  在后续trainingOptions中,每次epoch都不打乱样本的顺序(Shuffle='never'),这是排序是因为每次训练都是一个batch,
% 由于长度不同往往需要一个统一的长度,才能一同送入网络中,当根据样本长度差异较大,需要补0操作,占据存储空间且不利于网络的学习真正有用的特征
% 当排序后,需要补充的0少,所以相对于不排序是具有优势的
XTrain = preTrain.X(idx);
YTrain = preTrain.Y(idx); 

这一步中,展示了部分数据的输入和输出,上图为部分数据的部分输入。从图中能发现,一些变量在全寿命周期没有变换,是没有用的。因此剔除了与不随时间变换的无用特征,因为随着时间的增长RUL是单调递减的,这些特征不发生变化,那么它们对预测RUL是没有意义的,所以需要剔除掉。

除此之外,进行了Z标准化,RUL的标签进行了规整,限制输出的RUL标签最大为150,这有利于网络的收敛,可根据具体实际进行调制,过大的RUL对工程指导意义不大(个人观点)。

对数据进行了排序,这样对网络的收敛是有利的。不相信的小伙伴,可以不排序,同时训练参数的shuffle改为every-epoch,会发现网络很难收敛。

最终的训练集输入和输出分别保存在变量XTrain和YTrain。

第二步:搭建卷积神经网络模型,并利用训练数据训练神经网络模型。

%% 构建神经网络
numFeatures = size(XTrain{1},1);   %输入特征的个数,
​
numResponses = 1;
%神经网络结构
layers = [                              
    sequenceInputLayer(numFeatures)
    convolution1dLayer(5,32,Padding="causal")  %这里采用了因果填充的方式,确保模型的输出不会违反时间上的因果关系,参考时间卷积神经网络中的因果卷积
    batchNormalizationLayer()
    reluLayer()
    convolution1dLayer(7,64,Padding="causal")
    batchNormalizationLayer
    reluLayer()
    convolution1dLayer(11,128,Padding="causal")
    batchNormalizationLayer
    reluLayer()
    convolution1dLayer(13,256,Padding="causal")
    batchNormalizationLayer
    reluLayer()
    convolution1dLayer(15,512,Padding="causal")
    batchNormalizationLayer
    reluLayer()
    fullyConnectedLayer(100)
    reluLayer()
    dropoutLayer(0.5)
    fullyConnectedLayer(numResponses)
    regressionLayer()];
​
​
maxEpochs = 40; %最大Epoch数
miniBatchSize = 16;  %最小batchsize
​
options = trainingOptions('adam',...
    LearnRateSchedule='piecewise',...
    MaxEpochs=maxEpochs,...
    MiniBatchSize=miniBatchSize,...
    InitialLearnRate=0.01,...
    GradientThreshold=1,...
    Shuffle='never',...
    Plots='training-progress',...
    Verbose=0);
​
net = trainNetwork(XTrain,YTrain,layers,options);  %训练神经网络模型
%网络结构展示
figure;
lgraph = layerGraph(net.Layers);
plot(lgraph)

卷积神经网络的训练过程:

从上图结果看,RSME有待进一步提高。多次运行代码,网络收敛的曲线较为接近,无明显差异。我试着修改学习率、Epoch、batchsize大小,结果无明显变化,可能需要进一步进行网络结构的优化,增加新的输入层,欢迎各位小伙伴尝试,提出更好的网络模型。

卷积神经网络的结构为:

具体为:时间序列输入层sequenceinput→卷积层conv1d_1→批量归一化层batchnorm_1→激活层relu_1→卷积层conv1d_2→批量归一化层batchnorm_2→激活层relu_2→conv1d_3→批量归一化层batchnorm_3→激活层relu_3→卷积层conv1d_4→批量归一化层batchnorm_4→激活层relu_4→卷积层conv1d_5→批量归一化层batchnorm_5→激活层relu_5→全连接层fc_1→激活层relu_6→随机丢弃层dropout→全连接层fc_2→回归层regressionoutput。

第三步:采用已训练的神经网络模型,预测测试样本的剩余使用寿命,并采用RMSE评估网络的预测效果。

值得注意是,这个代码里面有两个函数:localLoadData(加载数据用的,同时制作RUL标签)和localLambdaPlot(画图函数)

%% 测试模型
filenameTestPredictors = fullfile(dataFolder,'test_FD001.txt');
filenameTestResponses = fullfile(dataFolder,'RUL_FD001.txt');
dataTest = localLoadData(filenameTestPredictors,filenameTestResponses);
%测试数据进行Z标准化
for i = 1:numel(dataTest.X)
    dataTest.X{i} = dataTest.X{i}{:,featToRetain};
    dataTest.X{i} = (dataTest.X{i} - Xmu) ./ Xsigma;
    dataTest.Y{i} = min(dataTest.Y{i},rulThreshold);
end
​
predictions = table(Size=[height(dataTest) 2],VariableTypes=["cell","cell"],VariableNames=["Y","YPred"]);
%预测
for i=1:height(dataTest)
    unit = dataTest.X{i}';   
    predictions.Y{i} = dataTest.Y{i}';
    predictions.YPred{i} = predict(net,unit,MiniBatchSize=1);
end
​
%计算RMSE 评估网络
for i = 1:size(predictions,1)
    predictions.RMSE(i) = sqrt(mean((predictions.Y{i} - predictions.YPred{i}).^2));
end
%RMSE直方图
figure;
histogram(predictions.RMSE,NumBins=10);
title("RMSE ( Mean: " + round(mean(predictions.RMSE),2) + " , StDev: " + round(std(predictions.RMSE),2) + " )");
ylabel('Frequency');
xlabel('RMSE');
%% 展示预测曲线
figure;
localLambdaPlot(predictions,"random");
figure;
localLambdaPlot(predictions,"best");
figure;
localLambdaPlot(predictions,"worst");
figure;
localLambdaPlot(predictions,"average");
​
%% 加载数据的函数
function data = localLoadData(filenamePredictors,varargin)
​
if isempty(varargin)
    filenameResponses = [];
else
    filenameResponses = varargin{:};
end
​
rawData = readtable(filenamePredictors);
% 输入数据的名称
VarNames = {...
    'id', 'timeStamp', 'op_setting_1', 'op_setting_2', 'op_setting_3', ...
    'sensor_1', 'sensor_2', 'sensor_3', 'sensor_4', 'sensor_5', ...
    'sensor_6', 'sensor_7', 'sensor_8', 'sensor_9', 'sensor_10', ...
    'sensor_11', 'sensor_12', 'sensor_13', 'sensor_14', 'sensor_15', ...
    'sensor_16', 'sensor_17', 'sensor_18', 'sensor_19', 'sensor_20', ...
    'sensor_21'};
rawData.Properties.VariableNames = VarNames;
​
if ~isempty(filenameResponses)
    RULTest = readmatrix(filenameResponses);
end
​
IDs = rawData{:,1};
nID = unique(IDs);
numObservations = numel(nID);
​
% 初始化
data = table(Size=[numObservations 2],...
    VariableTypes={'cell','cell'},...
    VariableNames={'X','Y'});
​
for i=1:numObservations
    idx = IDs == nID(i);
    data.X{i} = rawData(idx,:);
    if isempty(filenameResponses)
        % 计算RUL
        data.Y{i} = flipud(rawData.timeStamp(idx))-1;
    else
        sequenceLength = sum(idx);
        endRUL = RULTest(i);
        data.Y{i} = [endRUL+sequenceLength-1:-1:endRUL]'; 
    end
end
end
​
%%
function localLambdaPlot(predictions,lambdaCase)
​
if isnumeric(lambdaCase)
    idx = lambdaCase;
else
    switch lambdaCase   %展示结果
        case {"Random","random","r"}
            idx = randperm(height(predictions),1);
        case {"Best","best","b"}
            idx = find(predictions.RMSE == min(predictions.RMSE)); 
        case {"Worst","worst","w"}
            idx = find(predictions.RMSE == max(predictions.RMSE)); 
        case {"Average","average","a"}
            err = abs(predictions.RMSE-mean(predictions.RMSE));
            idx = find(err==min(err),1);
    end
end
y = predictions.Y{idx};
yPred = predictions.YPred{idx};
x = 0:numel(y)-1;
plot(x,y,x,yPred)
legend("True RUL","Predicted RUL")
xlabel("Time stamp (Test data sequence)")
ylabel("RUL (Cycles)")
​
title("RUL for Test engine #"+idx+ " ("+lambdaCase+" case)")
end

上图为测试样本的RMSE偏差分布的直方图,从图中能发现测试样本的RMSE偏差集中在10-15之间,有待进一步优化和提高。

下图为部分样本的RUL预测结果,分别对应了随机选择样本的RUL预测结果、RMSE偏差最小样本的RUL预测结果、RMSE偏差最大样本的预测结果和RMSE偏差适中样本的预测结果。

随机选择样本的RUL预测结果

RMSE偏差最小样本的RUL预测结果

RMSE偏差最大样本的预测结果

RMSE偏差适中样本的预测结果

从上图中能发现,虽然第二个样本的RMSE偏差最小,但预测的RUL较真实的RUL偏差较大。相反,第四个图片展示的结果,随着RUL的减小,预测的RUL不断逼近、跟踪真实的RUL,这表明了CNN网络在预测RUL方面也有一定的可行性。

总结与讨论

上述是一个基于卷积神经网络的航空发动机剩余寿命预测方法例子。首先,对数据进行预处理操作,构建训练样本和测试样本。然后,搭建卷积神经网络模型,学习训练样本。最后,利用测试数据和RMSE,分析卷积神经网络预测RUL的可行性和效果。

参考的资料和文献

附件

源码以及数据文件

8ae1

1、上述源码及其数据文件

     ①data文件夹(所有的训练数据和测试数据)以及压缩包TurbofanEngineDegradationSimulationData.zip

     ②代码文件:main.m(主程序)

2、参考文献

    ①Saxena A, Goebel K, Simon D, et al. Damage propagation modeling for aircraft engine run-to-failure simulation[C]//2008 international conference on prognostics and health management. IEEE, 2008: 1-9.(数据解读)

   ②Ramasso E, Saxena A. Performance Benchmarking and Analysis of Prognostic Methods for CMAPSS Datasets[J]. International Journal of Prognostics and Health Management, 2014, 5(2): 1-15.(CMAPSS数据集的性能和预测方法分析)

    ③https://ww2.mathworks.cn/help/predmaint/ug/remaining-useful-life-estimation-using-convolutional-neural-network.html(Mathwork官网的RUL预测例子)

关注公众号“故障诊断与寿命预测工具箱”,每天进步一点点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值