This example shows how logging state trajectories of a Simulink® model in a structure format can be better than the traditional method of logging states in an array format. The ordering of the states along the columns in the logged matrix depends on the block sorted order, which the Simulink software determines during model compilation. Various factors can affect the block sorted order, which can alter the ordering of the states.
This example illustrates how logging the states in the Structure format, which stores the block names with the state trajectories, can help prevent the state ordering problem.
By default, the Simulink software logs the state trajectories in array format, which is a matrix with N columns, where N is the number of states. The matrix has M rows, with each row corresponding to a single simulation time step. This M-by-N matrix form is easy to manipulate in MATLAB®. However, the ordering of the state variables along the columns of the logged matrix depends on the block sorted order. Therefore, any MATLAB code which expects a fixed mapping between the states of blocks in the model and the columns of the states matrix is prone to breaking when the block sorted order changes due to changes in the model.
For example, consider the following two block diagrams:
mdl1 = 'sldemo_state_logging1'; mdl2 = 'sldemo_state_logging2'; open_system(mdl1); open_system(mdl2);
The two diagrams have the same blocks, the only difference is the ordering of output ports. Simulate the models and log the states in array format:
simOut1 = sim(mdl1, 'SaveFormat','Array'); simOut2 = sim(mdl2, 'SaveFormat','Array');
Extract the states vectors from the Simulink.SimulationOutput object, which contains the output logs of the simulation:
x1 = simOut1.get('xout'); x2 = simOut2.get('xout');
Note that the relative ordering of the integrator blocks is different in the two block diagrams. This causes the logged states x1
and x2
to differ because the mapping between the columns and the states is different:
isequal(x1, x2)
ans = logical 0
Simulate the models again, but this time log the states in structure format:
simOut1=sim(mdl1,'SaveFormat','Structure'); simOut2=sim(mdl2,'SaveFormat','Structure');
Extract the structures, which contain the state logs, from the simulation output object:
x1s = simOut1.get('xout'); x2s = simOut2.get('xout');
Display these structures. Note that these structures have two fields: time and signals. The field 'time' is empty because we chose 'Structure' for the model parameter 'SaveFormat'. We could have chosen 'StructureWithTime' to store the time vector in the states structure:
disp(x1s); disp(x2s);
time: [] signals: [1x2 struct] time: [] signals: [1x2 struct]
The software logs the state trajectories into xs.signals(k).values
along with the names of blocks xs.signals(k).blockName
that correspond to these states. Extract the states into a matrix (like in array format) like this:
x1a = [x1s.signals.values]; x2a = [x2s.signals.values];
Note that the state ordering problem still exists (x1a
and x2a
are the same as x1
and x2
, obtained via array format):
isequal(x1a, x2a)
ans = logical 0
To fix the state ordering problem, use the block names stored along with the values to map the states to a fixed order, for example, the alphabetical order of the block names:
[~, idx1] = sort({x1s.signals.blockName}); x1 = [x1s.signals(idx1).values]; [~, idx2] = sort({x2s.signals.blockName}); x2 = [x2s.signals(idx2).values]; isequal(x1, x2)
ans = logical 1
By re-ordering the signals arrays in x1
and x2
into the alphabetical order of the block names, and extracting the values fields, in that order, into the matrices x1
and x2
, we have a mechanism for logging the states into a matrix with a fixed mapping of the block states to columns of the logged matrix.
Close the models and clear the variables which were used in this example:
close_system(mdl1); close_system(mdl2); clear ans idx1 idx2 mdl1 mdl2 simOut1 simOut2 x1 x1a x1s x2 x2a x2s