Main Content

Generate Code That Preserves RUL Model State for System Restart

This example shows how to generate code for predicting remaining useful life (RUL) that preserves the state of the RUL model when the prediction algorithm is stopped and restarted. This example builds on the workflow shown in Generate Code for Predicting Remaining Useful Life.

The workflow of this example is useful for degradation-based RUL models, linearDegradationModel and exponentialDegradationModel. With these models, you can use the update command to update the RUL model with incoming data during system operation, as described in Update RUL Prediction as Data Arrives. When you perform such an update in a deployed prediction algorithm, on system shutdown, you risk losing any updates you made to the model during operation. This example shows how to write an entry-point function to preserve updates made to the model at run time. To do so, incorporate the readState and restoreState commands into the entry-point function.

Fit RUL Model

Before generating code for RUL prediction, you must fit an RUL model using historical data. For this example, load the data in linTrainTables.mat. This file contains measurements of some condition indicator taken over time, organized into tables with column labels "Time" and "Condition". Use this data to train a linear degradation model. (For more information about configuring and training this type of RUL model, see linearDegradationModel.)

load('linTrainTables.mat')

mdl = linearDegradationModel;
fit(mdl,linTrainTables,"Time","Condition")

Prepare Model for Code Generation

As described in Generate Code for Predicting Remaining Useful Life, to prepare the model for code generation, use saveRULModelForCoder to store the RUL model as a data structure in a MAT file. Later, in the entry-point function, you use loadRULModelForCoder to load and reconstruct the linearDegradationModel object.

saveMATfilename = 'savedModel.mat';
saveRULModelForCoder(mdl,saveMATfilename);

Optionally, you can update the model parameters using additional data collected after the training data. For this example, load linTestData1, which is a 121-row table of times and condition-indicator values. Use the first two entries in this table to update the model.

load('linTestData.mat','linTestData1')
updateData = linTestData1(1:2,:);
update(mdl,updateData);

Next, read the model state using readState. This command converts the RUL model object into a structure that you can pass to the entry-point function as an input argument.

savedState = readState(mdl);

Define Entry-Point Function

The entry-point function is the function for which you want to generate code. For this example, create the entry-point function degradationRULPreserveState.m, as shown here.

type degradationRULPreserveState.m
function [estRULOut,ciOut,newState] = degradationRULPreserveState(data,restoreStateFlag,savedState)
%#codegen

persistent mdl

% Load the model the first time function is called
if isempty(mdl)
   mdl = loadRULModelForCoder('savedModel');  
end

% Restore the saved model parameters if needed
if restoreStateFlag
   restoreState(mdl,savedState);
end

% Update model and prediction with new data
threshold = 60;
update(mdl,data);
[estRULOut,ciOut] = predictRUL(mdl,threshold);

% Read the updated model parameters 
newState = readState(mdl);

end

This function updates the RUL prediction model using the update command each time it is called with new input data. Declaring mdl as a persistent variable preserves the updated model parameters between calls while the function remains in memory. This function writes the updated model parameters to the output argument newState. Save this value outside the entry-point function to preserve the updated model state when the function is cleared from memory. Thus, for example, when restarting the prediction algorithm after a system shutdown, you can set restoreStateFlag to true and pass in the most recently saved state value as savedState, ensuring that the system resumes prediction using the most recently updated model parameters.

Generate Code

To generate code, you must provide sample data having the data type and format of each input argument expected by the entry-point function. For this example, use the next row in linTestData1. Also, set restoreStateFlag to the logical value true.

sampleData = linTestData1(3,:);
restoreStateFlag = true;

Now you can generate code using the following codegen (MATLAB Coder) command. The list of variables {sampleData,restoreStateFlag,savedState} tells the codegen command that the function takes as arguments a table row consisting of a time and a numerical value, a logical value, and a structure of the form savedState, as returned by readState.

codegen degradationRULPreserveState -args {sampleData,restoreStateFlag,savedState} -nargout 3
Code generation successful.

This command generates a MEX file, which is an executable that you can call from within MATLAB®. You can use procedures similar to this example to generate code for any other target that codegen supports. Alternatively, you can use the MATLAB Coder™ app, as shown in Generate Code for Predicting Remaining Useful Life.

Validate the Generated Code

To validate the generated code, at the MATLAB command prompt, run the entry-point MATLAB function on the sample data. Then, run the generated MEX file on the same data and confirm that the results are the same.

[estRUL,ci,newState] = degradationRULPreserveState(sampleData,restoreStateFlag,savedState);
[estRUL_mex,ci_mex,newState_mex] = degradationRULPreserveState_mex(sampleData,restoreStateFlag,savedState);

For example, compare the estimated RUL obtained with the MATLAB function and the generated MEX file.

estRUL,ci
estRUL = 
113.8920
ci = 1×2

   83.0901  172.5393

estRUL_mex,ci_mex
estRUL_mex = 
113.8920
ci_mex = 1×2

   83.0901  172.5393

You can now use the generated code as part of your deployed system for predicting remaining useful life. Store the value of newState to use when you need to restart the system. For example, take the next data point in linTestData1 and use it to update the prediction, starting with newState_mex, the model state generated in the previous call to the MEX file.

nextData = linTestData1(4,:);
[estRUL2_mex,ci2_mex,newState2_mex] = degradationRULPreserveState_mex(nextData,restoreStateFlag,newState_mex);

estRUL2_mex,ci2_mex
estRUL2_mex = 
104.4336
ci2_mex = 1×2

   77.8216  154.1263

Note that the MATLAB function and the MEX file each manage their own persistent variables. Therefore, the MEX file value of mdl now incorporates the update from nextData, which the function value of mdl does not. To reset the values of these persistent variables, explicitly clear the function and the MEX file from memory.

clear degradationRULPreserveState
clear degradationRULPreserveState_mex

See Also

| | | | | | | | | |

Related Topics