Main Content

Generate Generic C Code Using The Stateful Predict Block in Simulink

Since R2024a

This example shows how to generate generic C code in Simulink® using the Stateful Predict (Deep Learning Toolbox) block and the SIL workflow. You will use a long short-term memory (LSTM) network trained on the Japanese Vowels data set to identify the speaker for a given input sequence. For more information, see Predict and Update Network State in Simulink (Deep Learning Toolbox).

Load Test Data

Load the Japanese Vowels test data. XTest is a cell array containing 370 sequences of dimension 12 and varying sequence length.

load('JapaneseVowelsTestData.mat')
X = single(XTest{94});

Simulink Model for Predicting Responses

The Simulink model for predicting responses contains a Stateful Predict block to predict the scores and a From Workspace block to load the input data sequence over the time steps. Create a timetable modelInput with time-stamped rows to load using the From Workspace block.

To reset the state of recurrent neural network to its initial state during simulation, place the Stateful Predict block inside a Resettable Subsystem and use the Reset control signal as trigger.

modelInput = timetable(X','TimeStep',seconds(0.2));
modelName = 'StatefulPredictBlockExample';
modelHandle = load_system(modelName);
open_system(modelHandle);

Configure Model for Simulation

Set the network file path to the LSTM network 'JapaneseVowelsDlnet.mat', which was trained on the Japanese Vowels data set as described in [1] and [2]. The network expects the sequences representing the vowels as input and produces the classification scores for the nine different speakers as output.

The first dimension of the sequences in XTest is the channel dimension 'C', representing the vowels, whereas the second dimension represents the sequence length 'T'. Therefore, you must set the input data formats to 'CT'.

statefulPredictBlockHandle = getSimulinkBlockHandle([modelName '/Stateful Predict']);
set_param(statefulPredictBlockHandle, 'Network', 'Network from MAT-file');
set_param(statefulPredictBlockHandle, 'NetworkFilePath', 'JapaneseVowelsDlnet.mat');
set_param(statefulPredictBlockHandle, 'InputDataFormats', "{'input', 'CT'}");

The function getProdHWDeviceType returns the production hardware device type based on the host computer specifications. You can edit the function below if you are running this example on a computer with different specifications.

function prodHWDeviceType = getProdHWDeviceType()

if ismac
    prodHWDeviceType = 'Intel->x86-64 (MAC OS X)';
elseif isunix
    prodHWDeviceType = 'Intel->x86-64 (Linux 64)';   
else
    prodHWDeviceType = 'Intel->x86-64 (Windows64)';
end

end

Set the production hardware device type.

prodHWDeviceType = getProdHWDeviceType();
set_param(modelHandle, 'ProdHWDeviceType', prodHWDeviceType);

Run SIL simulation

To compute the responses using the generated code, use the sim command along with the software-in-the-loop (sil) option.

sim(modelHandle, 'SimulationMode', 'software-in-the-loop (sil)');
### Starting build procedure for: StatefulPredictBlockExample
### Successful completion of build procedure for: StatefulPredictBlockExample

Build Summary

Top model targets:

Model                        Build Reason                                         Status                        
================================================================================================================
StatefulPredictBlockExample  Information cache folder or artifacts were missing.  Code generated and compiled.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 40.183s
### Preparing to start SIL simulation ...
Building with 'MinGW64 Compiler (C)'.
MEX completed successfully.
### Starting SIL simulation for component: StatefulPredictBlockExample
### Application stopped
### Host application produced the following standard output (stdout) messages:
** created StatefulPredictBlockExample.mat **


### Stopping SIL simulation for component: StatefulPredictBlockExample

Load the model output from file. Squeeze the singleton dimension from the 9-by-1-by-16 output to obtain the classification scores over time as a 2-D array.

outStruct = load('StatefulPredictBlockExample.mat').rt_modelOutput.signals;
scores = squeeze(outStruct.values);
numTimeSteps = size(scores, 2);

Plot the prediction scores. TTest is a categorical vector of labels "1", "2", ... "9", which correspond to the nine speakers. The plot shows how the prediction scores change between time steps and highlights the prediction scores for the correct class.

classNames = string(categories(TTest));
figure
lines = plot(scores');
xlim([1 numTimeSteps])
legend("Class " + classNames,'Location','northwest')
xlabel("Time Step")
ylabel("Score")
title("Prediction Scores Over Time Steps")

trueLabel = TTest(94);
lines(trueLabel).LineWidth = 3;

Figure contains an axes object. The axes object with title Prediction Scores Over Time Steps, xlabel Time Step, ylabel Score contains 9 objects of type line. These objects represent Class 1, Class 2, Class 3, Class 4, Class 5, Class 6, Class 7, Class 8, Class 9.

Display the final time step prediction in a bar chart.

figure
bar(scores(:,end))
title("Final Prediction Scores")
xlabel("Class")
ylabel("Score")

Figure contains an axes object. The axes object with title Final Prediction Scores, xlabel Class, ylabel Score contains an object of type bar.

References

[1] Kudo, Mineichi, Jun Toyama, and Masaru Shimbo. “Multidimensional Curve Classification Using Passing-through Regions.” Pattern Recognition Letters 20, no. 11 (November 1, 1999): 1103–11. https://doi.org/10.1016/S0167-8655(99)00077-X.

[2] Mineichi Kudo, Jun Toyama. “Japanese Vowels.” UCI Machine Learning Repository, 1999. https://doi.org/10.24432/C5NS47.

See Also

(Deep Learning Toolbox) | (Deep Learning Toolbox)

Related Topics