Commit aa57ce05 authored by Jakob Gabriel's avatar Jakob Gabriel
Browse files

new scripts to enease use of state space models (ss())

parent 1a365bda
......@@ -99,7 +99,7 @@ classdef Gains < handle & matlab.mixin.Copyable
gainSeries = misc.Gains();
interconnectionGain = obj.get(gainType);
typesAll = unique([obj.type(:); gainNext.type(:)]).';
typesAll = unique([obj.type(:); gainNext.type(:)], 'stable').';
for thisType = typesAll
thisType = thisType{:};
if strcmp(thisType, gainType)
......
function myStateSpace = changeSsSignalName(myStateSpace, oldName, newName)
% CHANGESSSIGNALNAME sets the property 'OutputName' or 'InputName' of the ss
% myStateSpace by replacing oldName with newName.
%
% Inputs:
% myStateSpace state space whoms OutputName and InputName should be modified
% oldName cell array of signal names that should be applied to
% myStateSpace.OutputName
% newName cell array of same size as signal names. Each element defines the
% length of the signal that is named in signal names
% Outputs:
% myStateSpace the state space with modified parameters
%
% Example:
% -------------------------------------------------------------------------
% mySimulationModel = ss(1, 1, [1; 2; 3], []);
% mySimulationModel = misc.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
% mySimulationModel = misc.changeSsSignalName(mySimulationModel, {'a'}, {'c'});
% -------------------------------------------------------------------------
% input checks
if ~iscell(oldName)
oldName = {oldName};
end
if ~iscell(newName)
newName = {newName};
end
assert(isa(myStateSpace, 'ss'), '1st input must be state space model');
assert(numel(newName) == numel(oldName), 'number of elements of newName and oldName must be equal');
% split signal names
oldOutputNames = misc.removeEnumeration(myStateSpace.OutputName);
oldInputNames = misc.removeEnumeration(myStateSpace.InputName);
for it = 1 : numel(newName)
% exchange names
if ~isempty(strcmp(oldInputNames, oldName{it})) ...
&& any(strcmp(oldInputNames, oldName{it}))
[oldInputNames{strcmp(oldInputNames, oldName{it})}] ...
= deal(newName{it});
end
if ~isempty(strcmp(oldOutputNames, oldName{it})) ...
&& any(strcmp(oldOutputNames, oldName{it}))
[oldOutputNames{strcmp(oldOutputNames, oldName{it})}] ...
= deal(newName{it});
end
end
uniqueInputNames = unique(oldInputNames, 'stable');
inputLength = cellfun(@(v) sum(strcmp(oldInputNames, v)), uniqueInputNames);
uniqueOutputNames = unique(oldOutputNames, 'stable');
outputLength = cellfun(@(v) sum(strcmp(oldOutputNames, v)), uniqueOutputNames);
% set input and ouput names
myStateSpace = misc.setSsSignalName(myStateSpace, 'input', uniqueInputNames, inputLength);
myStateSpace = misc.setSsSignalName(myStateSpace, 'output', uniqueOutputNames, outputLength);
end
function unenumerateNames = removeEnumeration(enumeratedNames)
% REMOVEENUMERATION removes braces with numbers from every char array that is an
% element of the cell array enumeratedNames. This is for instance useful, to deal
% with InputName or OutputName properties of large state-space models (ss).
% Example:
% misc.removeEnumeration({'a(1)'})
unenumerateNames = cell(size(enumeratedNames));
for it = 1 : numel(enumeratedNames)
namesSplittedTemp = split(enumeratedNames{it}, '(');
unenumerateNames{it} = namesSplittedTemp{1};
end
end
\ No newline at end of file
function myStateSpace = setSsSignalName(myStateSpace, signalType, signalNames, signalLength)
% SETSSSIGNALNAME sets the property 'OutputName' or 'InputName' of the ss
% myStateSpace to signalNames. Therein, signalLength how many output elements belong
% to a signalName. Wheather the InputName or the OutputName properties should be set
% is determined by signalType \in {'input', 'output'}
%
% Inputs:
% myStateSpace state space whoms OutputName should be modified
% signalType must be either 'input' or 'output' and determines of OutputName
% or InputName are set
% signalNames cell array of signal names that should be applied to
% myStateSpace.OutputName
% signalLength cell array of same size as signal names. Each element defines the
% length of the signal that is named in signal names
% Outputs:
% myStateSpace the state space with modified parameters
%
% Example:
% -------------------------------------------------------------------------
% mySimulationModel = ss(1, 1, [1; 2; 3], []);
% mySimulationModel = misc.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
% -------------------------------------------------------------------------
% input checks
assert(isa(myStateSpace, 'ss'), '1st input must be state space model');
assert(iscell(signalNames), 'signalNames must be a cell array');
assert(iscell(signalLength) || isvector(signalLength), 'signalLength must be a cell array or a vector');
if iscell(signalLength)
signalLength = cell2mat(signalLength);
end
if strcmp(signalType, 'input')
assert(size(myStateSpace, 2) == sum([signalLength(:)]), 'signalLength does not fit to state space');
elseif strcmp(signalType, 'output')
assert(size(myStateSpace, 1) == sum([signalLength(:)]), 'signalLength does not fit to state space');
else
error("signalType must be 'input' or 'output'");
end
assert(numel(signalNames) == numel(signalLength), 'signalNames must have same number as signalLength');
% create name cell array
myNewSignalNames = cell(sum([signalLength(:)]), 1);
myCurrentSignal = 1;
for it = 1 : numel(signalNames)
for jt = 1 : signalLength(it)
if signalLength(it) == 1
myNewSignalNames{myCurrentSignal} = signalNames{it};
else
myNewSignalNames{myCurrentSignal} = [signalNames{it}, '(', num2str(jt), ')'];
end
myCurrentSignal = myCurrentSignal + 1;
end
end
% set property
if strcmp(signalType, 'input')
myStateSpace.InputName = myNewSignalNames;
else
myStateSpace.OutputName = myNewSignalNames;
end
end
function quantityStruct = simulationOutput2Quantity(simOutput, time, outputNames, varargin)
% SIMULATIONOUTPUT2QUANTITY separates the output of a simulation of a state-space
% simulation model into quantities according to the names of the output
% signals specified by the OutputName-property of the state space
%
% Inputs:
% myOutput double array of the size timeSteps x numel(outputNames)
% time double array of the time values with numel(time) = timeSteps
% outputNames cell array of char-arrays that specify the signal name. For
% instance, outputNames can be the OutputName propertie of a ss.
% Optional Inputs:
% 'z' cell-array of name value pairs of signal-names and grids of a
% spatial coordinate 'z'. For instance, if spatially distributed
% states x(t, z) and v(t, z) in R^2 are simulated
% with the spatial grid grid_1 = linspace(0, 1, 11)
% belonging to the spatial domain of x_1 and v_1 and
% grid_2 = linspace(0, 1, 21) belonging to x_2 and v_2, then
% add 'z', {{'x', 'v'}, {{grid_1, grid_2}, {grid_1, grid_2}}
% to the input, i.e.
% 'z', {{signalNames}, {gridVectors of signalNames{1}}, ...
% {gridVectors of signalNames{2}}, ...}
% Outputs:
% quantityStruct a struct containg quantity.Discretes with the names specified by
% outputNames and the time grid time with the gridName 't'.
%
% Example:
% -------------------------------------------------------------------------
% mySimulationModel = ss(1, 1, [1; 2], [], 'OutputName', {'a', 'b'});
% myIc = 0.5;
% time = linspace(0, 1, 51);
% myInput = 0 * time;
% simulationOutputArray = lsim(mySimulationModel, myInput, time);
% simulationOutputQuantity = misc.simulationOuput2Quantity( ...
% simulationOutputArray, time, mySimulationModel.OutputName);
% plot([simulationOutputQuantity.a; simulationOutputQuantity.b]);
% -------------------------------------------------------------------------
% input checks
assert(iscell(outputNames) && ischar(outputNames{1}), 'outputNames must be a cell-array of char-arrays')
assert(isvector(time) && isnumeric(time) && issorted(time(:), 'ascend'), ...
'time-vector must be numeric ans a vector and ascending');
assert(isequal(size(simOutput), [numel(time), numel(outputNames)]), ...
'size of simOutput does not fit to time or outputNames');
% outputName elements are char arrays. If there is only one output named, for
% instance, 'a', then this element only contains 'a'. If there are two (or more)
% outputs with the same name, then they are enumerated as 'a(1)', 'a(2)', ...
% In the following the enumeration is removed from outputNames, since it hinders
% elegant string operations.
outputNamesUnenumerated = misc.removeEnumeration(outputNames);
signalNames = unique(outputNamesUnenumerated, 'stable');
% input check for optional parameter z that defines spatial grids
myParser = misc.Parser();
myParser.addParameter('z', {}, @(z) iscell(z));
myParser.parse(varargin{:})
if ~isempty(myParser.Results.z)
signalsDependentOnZ = myParser.Results.z{1};
gridOfSignalsDependentOnZ = myParser.Results.z{2};
assert(numel(signalsDependentOnZ) == numel(gridOfSignalsDependentOnZ), ...
'input z is not defined properly');
for it = 1 : numel(signalsDependentOnZ)
assert(any(strcmp(signalNames, signalsDependentOnZ{it})), ...
'z grid specified for a signal that is not part of outputNames');
end
else
signalsDependentOnZ = '';
end
% read data and add to struct
for idx = 1 : numel(signalNames)
% consider z-grid
zGridSelector = strcmp(signalsDependentOnZ, signalNames{idx});
if any(zGridSelector)
thisSignalUnsorted = simOutput(:, strcmp(outputNamesUnenumerated, signalNames{idx}));
thisGrid = gridOfSignalsDependentOnZ{zGridSelector};
thisGridLength = cellfun(@(v) numel(v), thisGrid);
thisGridHr = thisGrid{1}; % select finest grid of thisGrid = thisGridHr
for it = 2 : numel(thisGrid)
if thisGridLength(it) > numel(thisGridHr)
thisGridHr = thisGrid{it};
end
end
thisSignalSorted = zeros(numel(time), numel(thisGridHr), numel(thisGrid));
for it = 1 : numel(thisGrid)
thisSignalItTemp = thisSignalUnsorted(:, sum(thisGridLength(1:it-1))+(1:thisGridLength(it)));
thisSignalSorted(:, :, it) = misc.translate_to_grid(thisSignalItTemp, ...
{time, thisGridHr}, 'gridOld', {time, thisGrid{it}});
end
quantityStruct.(signalNames{idx}) = quantity.Discrete( thisSignalSorted, ...
'name', signalNames{idx}, 'grid', {time, thisGridHr}, 'gridName', {'t', 'z'});
else
quantityStruct.(signalNames{idx}) = quantity.Discrete( ...
simOutput(:, strcmp(outputNamesUnenumerated, signalNames{idx})), ...
'name', signalNames{idx}, 'grid', {time}, 'gridName', {'t'});
end
end
end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment