%% Logging States in Structure Format
% This example shows how logging state trajectories of a Simulink(R) 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.  

% Copyright 1990-2012 The MathWorks, Inc.

%% Problem with Logging in Array Format 
% 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(R). 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)

%% Using Structure Format Logging
% 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);

%%
% 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)

%% Obtaining States Matrix with Fixed State Order
% 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)

%%
% 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

displayEndOfDemoMessage(mfilename)

