Commit 1e485c8f authored by Ferdinand Fischer's avatar Ferdinand Fischer
Browse files

Merge branch 'master' of gitlab.cs.fau.de:lrt_infinite_dimensional_systems/coni

parents c96ce659 30b279fb
......@@ -35,7 +35,7 @@ classdef Odes < handle & matlab.mixin.Copyable
obj.type = type;
for it = 1 : numel(stateSpaces)
[obj.ss{it}, obj.C{it}, obj.D{it}] ...
= obj.seperateOutputfromSs(stateSpaces{it}, type{it});
= obj.separateOutputfromSs(stateSpaces{it}, type{it});
end % for it = 1 : numel(stateSpaces)
obj.verifyProperties();
end % if nargin > 0
......@@ -83,7 +83,7 @@ classdef Odes < handle & matlab.mixin.Copyable
% Ode = misc.ss.Odes(ss1, 'ss1');
% Ode.exchange('ss1', ss2)
[obj.ss{obj.index(myType)}, obj.C{obj.index(myType)}, obj.D{obj.index(myType)}] ...
= obj.seperateOutputfromSs(newSs, myType);
= obj.separateOutputfromSs(newSs, myType);
obj.verifyProperties();
end % exchange()
......@@ -206,6 +206,16 @@ classdef Odes < handle & matlab.mixin.Copyable
end
end % isequal()
function B = BofInputName(obj, inputName)
arguments
obj misc.ss.Odes;
inputName (1, 1) string;
end
InputNames = misc.ss.removeEnumeration(obj.InputName);
B = obj.odes.B;
B = B(:, strcmp(InputNames, inputName));
end % BofInputName
function [ic, stateName] = getInitialCondition(obj, varargin)
% getInitialCondition reads varargin if there are initial conditions
% defined as name-value-pair with the name according to obj.stateName and
......@@ -231,7 +241,7 @@ classdef Odes < handle & matlab.mixin.Copyable
stateName = [obj.type(:)];
end % getInitialCondition()
function [texString, nameValuePairs] = print(obj)
function [texString, nameValuePairs] = printParameter(obj)
myOdes = obj.odes;
nameValuePairs = {
'A', myOdes.A, ...
......@@ -240,6 +250,72 @@ classdef Odes < handle & matlab.mixin.Copyable
'D', myOdes.D, ...
};
texString = misc.variables2tex([], nameValuePairs);
end % printParameter()
function texString = print(obj, NameValue)
arguments
obj misc.ss.Odes;
NameValue.stateName string = "v";
end
% prepare signal names
thisOutputName = string(misc.ss.removeEnumeration(obj.OutputName, true));
thisOutputName = thisOutputName.extractBefore(2) + "_{" ...
+ thisOutputName.extractAfter(1) + "}(t)";
thisInputName = string(misc.ss.removeEnumeration(obj.InputName, true));
thisInputName = thisInputName.extractBefore(2) + "_{" ...
+ thisInputName.extractAfter(1) + "}(t)";
if strlength(NameValue.stateName) > 1
myOdeString = "\dot{" + NameValue.stateName.extractBefore(2) + "}" ...
+ "_{" + NameValue.stateName.extractAfter(1) + "}(t) &= ";
NameValue.stateName = NameValue.stateName.extractBefore(2) ...
+ "_{" + NameValue.stateName.extractAfter(1) + "}(t)";
else
myOdeString = "\dot{" + NameValue.stateName + "}(t) &= ";
NameValue.stateName = NameValue.stateName + "(t)";
end
% get ODE-lines
myOdeString = myOdeString + misc.latexChar(obj.odes.A) + NameValue.stateName;
if any(obj.odes.B ~= 0)
myOdeString = myOdeString + " + ";
if ~misc.iseye(obj.odes.B)
myOdeString = myOdeString + misc.latexChar(obj.odes.B);
end
myOdeString = myOdeString + misc.latexChar(thisInputName);
end
% get output-lines
myOutputString = misc.latexChar(thisOutputName) + " &= ";
plusNeeded = false;
if any(obj.odes.C ~= 0)
if misc.iseye(obj.odes.C)
myOutputString = myOutputString + NameValue.stateName;
else
myOutputString = myOutputString + ...
misc.latexChar(obj.odes.C) + NameValue.stateName;
end
plusNeeded = true;
end
if any(obj.odes.D ~= 0)
if plusNeeded
myOutputString = myOutputString + " + ";
end
if ~misc.iseye(obj.odes.D)
myOutputString = myOutputString + misc.latexChar(obj.odes.D);
end
myOutputString = myOutputString + misc.latexChar(thisInputName);
end
myStringArray = [myOdeString; myOutputString];
% set output parameter or print
if nargout > 0
texString = myStringArray;
else
misc.printTex(myStringArray);
end
end % print()
%% get methods for Dependent properties
......@@ -283,14 +359,14 @@ classdef Odes < handle & matlab.mixin.Copyable
methods (Static = true)
function [mySs, C, D] = seperateOutputfromSs(mySs, type)
function [mySs, C, D] = separateOutputfromSs(mySs, type)
% separateCfromSs() removes the output matrix of a state space model mySs
% and replaces it with the identity matrix, in order to obtain the states
% of the ode as output variables. The old output matrix C results in a
% separate state space
if all(strcmp(misc.ss.removeEnumeration(mySs.OutputName), type))
assert(misc.iseye(mySs.C) && isequal(size(mySs.C), size(mySs.A)), ...
['output of states space model does not include all states']);
"output of states space model does not include all states");
C = ss();
D = ss();
else
......@@ -307,8 +383,14 @@ classdef Odes < handle & matlab.mixin.Copyable
end
% change C and D in mySs
mySs = set(mySs, 'C', eye(size(mySs.A)), 'D', zeros(size(mySs.A, 1), size(mySs.B, 2)));
mySs = misc.ss.setSignalName(mySs, 'output', {type}, size(mySs.A, 1));
if numel(mySs.A) == 1
mySsOutputName = type;
else
mySsOutputName = type + "(" + (1:1:size(mySs.A, 1)).' + ")";
end
mySs = ss(mySs.A, mySs.B, eye(size(mySs.A)), zeros(size(mySs.A, 1), size(mySs.B, 2)), ...
mySs.Ts, "InputName", mySs.InputName, ...
"OutputName", mySsOutputName);
end % if
end % function [ss, C] = seperateCfromSs(ss)
......
......@@ -4,20 +4,18 @@ function mySs = add2signalName(mySs, signalType, position, newText)
% Example:
% misc.ss.add2signalName(ss(1, 1, [1; 1], [], 'OutputName', {'a', 'b'}), ...
% 'OutputName', 'front', 'ode.');
assert(any(strcmp(position, {'front', 'back'})));
assert(any(strcmp(signalType, {'OutputName', 'InputName'})));
assert(ischar(newText) || isstring(newText), 'prefix must be a char-array or string');
myNames = mySs.(signalType);
if strcmp(position, 'front')
for it = 1 : numel(myNames)
myNames{it} = [newText, myNames{it}];
end
elseif strcmp(position, 'back')
for it = 1 : numel(myNames)
myNames{it} = [myNames{it}, newText];
end
arguments
mySs ss;
signalType (1, 1) string {mustBeMember(signalType, ["OutputName", "InputName"])};
position (1, 1) string {mustBeMember(position, ["front", "back"])};
newText (1, 1) string;
end
assert(any(strcmp(position, ["front", "back"])));
assert(any(strcmp(signalType, ["OutputName", "InputName"])));
mySs.(signalType) = myNames;
if strcmp(position, "front")
mySs.(signalType) = strcat(newText, string(mySs.(signalType)));
elseif strcmp(position, "back")
mySs.(signalType) = strcat(string(mySs.(signalType)), newText);
end
end
\ No newline at end of file
......@@ -11,33 +11,49 @@ function myStateSpace = addInput2Output(myStateSpace)
% -------------------------------------------------------------------------
% mySimulationModel = ss(1, [1, 2, 3], [1; 2; 3], [1, 0, 0; 0, 0, 0; 0, 0, 0], ...
% 'OutputName', {'x', 'y', 'z'}, 'InputName', {'u(1)', 'u(2)', 'a'});
% mySimulationModel = misc.ss.addInput2Output(mySimulationModel);
% mySimulationModel = misc.ss.addInput2Output(mySimulationModel)
% -------------------------------------------------------------------------
arguments
myStateSpace ss;
end
% read InputName and OutputName
inputNameAll = misc.ss.removeEnumeration(unique(myStateSpace.InputName, 'stable'));
outputNameAll = misc.ss.removeEnumeration(unique(myStateSpace.OutputName, 'stable'));
inputNameAll = misc.ss.removeEnumeration(myStateSpace.InputName);
outputNameAll = misc.ss.removeEnumeration(myStateSpace.OutputName);
% count
inputName = unique(inputNameAll, 'stable');
inputLength = zeros(size(inputName));
for it = 1 : numel(inputName)
inputLength(it) = sum(strcmp(inputNameAll, inputName(it)));
end
outputName = unique(outputNameAll, 'stable');
inputNameCount = cellfun(@(v) sum(strcmp(inputNameAll, v)), inputName);
outputNameCount = cellfun(@(v) sum(strcmp(outputNameAll, v)), outputName);
outputLength = zeros(size(outputName));
for it = 1 : numel(outputLength)
outputLength(it) = sum(strcmp(outputNameAll, outputName(it)));
end
% add feedthrough
isFeedThroughNeccessary = false([numel(inputName), 1]);
for it = 1 : numel(inputName)
if any(strcmp(outputName, inputName{it}))
if any(strcmp(outputName, inputName(it)))
% if the input is already part of the output, assert that it has the same
% size
assert(inputNameCount(it) == outputNameCount(strcmp(outputName, inputName{it})), ...
assert(inputLength(it) == outputLength(strcmp(outputName, inputName(it))), ...
'There is already an output with the same name as an input, but they have different size!?');
isFeedThroughNeccessary(it) = false;
else
% Create a feedthrough and add it to myStateSpace
% feedthrough:
feedthroughTemp = ss([], [], [], eye(inputNameCount(it)), ...
'OutputName', inputName(it), 'InputName', inputName(it));
if inputLength(it) > 1
feedthroughTemp = ss([], [], [], eye(inputLength(it)), ...
"OutputName", inputName(it) + "(" + string(1:1:inputLength(it)).' + ")", ...
"InputName", inputName(it) + "(" + string(1:1:inputLength(it)).' + ")");
else
feedthroughTemp = ss([], [], [], eye(inputLength(it)), ...
"OutputName", inputName(it), ...
"InputName", inputName(it));
end
% connection:
% first myStateSpace is appended, then the input of the feedthrough and the
% state space are interconneted using series()
......@@ -46,20 +62,18 @@ for it = 1 : numel(inputName)
end
end
% create short cut of feedthrough and input
shortCutMatrix = eye(sum(inputNameCount));
shortCutMatrix = eye(sum(inputLength));
shortCutMatrixSelector = true(size(shortCutMatrix));
% remove rows that have now feedthrough
for it = 1 : numel(inputName)
if ~isFeedThroughNeccessary(it)
shortCutMatrixSelector(sum(inputNameCount(1:(it-1)))+(1:inputNameCount(it)), :) ...
= false;
shortCutMatrixSelector(sum(inputLength(1:(it-1)))+(1:inputLength(it)), :) = false;
end
end
shortCutMatrix = reshape(shortCutMatrix(shortCutMatrixSelector), ...
[sum(inputNameCount(isFeedThroughNeccessary)), sum(inputNameCount)]);
shortCut = ss([], [], [], [eye(sum(inputNameCount)); shortCutMatrix]);
shortCut = misc.ss.setSignalName(shortCut, 'input', inputName, inputNameCount);
[sum(inputLength(isFeedThroughNeccessary)), sum(inputLength)]);
shortCut = ss([], [], [], [eye(sum(inputLength)); shortCutMatrix]);
shortCut = misc.ss.setSignalName(shortCut, 'input', inputName, inputLength);
myStateSpace = series(shortCut, myStateSpace);
end
end % addInput2Output()
\ No newline at end of file
......@@ -23,11 +23,11 @@ function myStateSpace = changeSignalName(myStateSpace, oldName, newName, varargi
% -------------------------------------------------------------------------
% input checks
if ~iscell(oldName)
oldName = {oldName};
if ~isstring(oldName)
oldName = string(oldName);
end
if ~iscell(newName)
newName = {newName};
if ~isstring(newName)
newName = string(newName);
end
myParser = misc.Parser();
myParser.addRequired('myStateSpace', @(v) isa(v, 'ss'));
......@@ -57,42 +57,42 @@ function myStateSpace = changeInputName(myStateSpace, oldName, newName)
oldInputName = misc.ss.removeEnumeration(myStateSpace.InputName, false);
for it = 1 : numel(oldName)
% input check:
if any(strcmp(oldName{it}, uniqueOldInputName))
assert(~any(strcmp(oldName{it}, newName)), ...
if any(strcmp(oldName(it), uniqueOldInputName))
assert(~any(strcmp(oldName(it), newName)), ...
'overlaps in oldName and newName are not supported for InputName-changes');
end
end
for it = 1 : numel(oldName)
if any(strcmp(oldName{it}, uniqueOldInputName))
% there is an InputName with the name oldName{it} to be replaced.
numberOfThisInput = sum(strcmp(oldInputName, oldName{it}));
if any(strcmp(newName{it}, uniqueOldInputName))
% there is already a InputName with the name of newName{it}
if any(strcmp(oldName(it), uniqueOldInputName))
% there is an InputName with the name oldName(it) to be replaced.
numberOfThisInput = sum(strcmp(oldInputName, oldName(it)));
if any(strcmp(newName(it), uniqueOldInputName))
% there is already a InputName with the name of newName(it)
% -> they are interconnected via thisConnectorGain
thisConnectorGain = ss([], [], [], ...
vertcat(eye(numberOfThisInput), eye(numberOfThisInput)), ...
'InputName', newName{it});
'InputName', newName(it));
thisConnectorGain = misc.ss.setSignalName(thisConnectorGain, 'output', ...
{oldName{it}, [newName{it}, 'tempChangeSignalName']}, ...
{numberOfThisInput, numberOfThisInput});
[oldName(it); newName(it) + "tempChangeSignalName"], ...
[numberOfThisInput; numberOfThisInput]);
myStateSpace = misc.ss.changeSignalName(myStateSpace, ...
newName{it}, [newName{it}, 'tempChangeSignalName'], 'output', false);
newName(it), newName(it) + "tempChangeSignalName", 'output', false);
else
% there is no InputName with the name of newName{it}
% -> thisConnectorGain is just an identy with input newName{it} and
% output oldName{it}
% there is no InputName with the name of newName(it)
% -> thisConnectorGain is just an identy with input newName(it) and
% output oldName(it)
thisConnectorGain = ss([], [], [], ...
vertcat(eye(numberOfThisInput)), ...
'InputName', newName{it}, 'OutputName', oldName{it});
'InputName', newName(it), 'OutputName', oldName(it));
end
inputNameIntermediate = misc.ss.removeEnumeration(myStateSpace.InputName, false);
newInputNames = [inputNameIntermediate(...
~strcmp(inputNameIntermediate, oldName{it}) & ...
~strcmp(inputNameIntermediate, [newName{it}, 'tempChangeSignalName']))];
if ~any(strcmp(newInputNames, newName{it}))
~strcmp(inputNameIntermediate, oldName(it)) & ...
~strcmp(inputNameIntermediate, newName(it) + "tempChangeSignalName"))];
if ~any(strcmp(newInputNames, newName(it)))
newInputNames = [newInputNames; ...
repmat(newName(it), sum(strcmp(oldInputName, oldName{it})), 1)];
repmat(newName(it), sum(strcmp(oldInputName, oldName(it))), 1)];
end
myStateSpace = misc.ss.connect(...
newInputNames, myStateSpace.OutputName, ...
......@@ -107,22 +107,22 @@ function myStateSpace = changeOutputName(myStateSpace, oldName, newName)
% OutputName property, replacing the strings, and setting them in the end again.
uniqueOldInputName = misc.ss.removeEnumeration(myStateSpace.OutputName, true);
for it = 1 : numel(newName)
assert(~any(strcmp(uniqueOldInputName, newName{it})), ...
'newName is already OutputName of myStateSpace - not implemented');
assert(~any(strcmp(uniqueOldInputName, newName(it))), ...
"newName is already OutputName of myStateSpace - not implemented");
end
% split signal names
oldOutputNames = misc.ss.removeEnumeration(myStateSpace.OutputName);
newOutputNames = misc.ss.removeEnumeration(myStateSpace.OutputName);
oldOutputNames = string(misc.ss.removeEnumeration(myStateSpace.OutputName));
%newOutputNames = misc.ss.removeEnumeration(myStateSpace.OutputName);
% Exchange names of newOutputNames cell array:
for it = 1 : numel(newName)
if ~isempty(strcmp(oldOutputNames, oldName{it})) ...
&& any(strcmp(oldOutputNames, oldName{it}))
[oldOutputNames{strcmp(oldOutputNames, oldName{it})}] = deal(newName{it});
if ~isempty(strcmp(oldOutputNames, oldName(it))) ...
&& any(strcmp(oldOutputNames, oldName(it)))
[oldOutputNames(strcmp(oldOutputNames, oldName(it)))] = deal(newName(it));
end
end
uniqueOutputNames = unique(oldOutputNames, 'stable');
outputLength = cellfun(@(v) sum(strcmp(oldOutputNames, v)), uniqueOutputNames);
uniqueOutputNames = unique(oldOutputNames, "stable");
outputLength = arrayfun(@(v) sum(strcmp(oldOutputNames, v)), uniqueOutputNames);
% set output names
myStateSpace = misc.ss.setSignalName(myStateSpace, 'output', uniqueOutputNames, outputLength);
myStateSpace = misc.ss.setSignalName(myStateSpace, "output", uniqueOutputNames, outputLength);
end
\ No newline at end of file
......@@ -14,13 +14,11 @@ function u = combineInputSignals(myStateSpace, t, varargin)
%
% Example:
% -------------------------------------------------------------------------
% myStateSpace = ss(-1, [1, 2], 1, [], 'InputName', {'control', 'disturbance'});
% t = linspace(0, 4, 201);
% disturbanceSignal = quantity.Symbolic(sin(sym('t')), 'grid', t, ...
% 'variable', sym('t'), 'name', 'disturbance');
% u = misc.ss.combineInputSignals(myStateSpace, t, 'disturbance', disturbanceSignal);
% y = quantity.Discrete(lsim(myStateSpace, u.on(), t), 'grid', t, ...
% 'gridName', 't', 'name', 'y');
% myStateSpace = ss(-1, [1, 2], 1, [], "InputName", {'control', 'disturbance'});
% t = quantity.Domain("t", linspace(0, 4, 201));
% disturbanceSignal = quantity.Symbolic(sin(sym("t")), t, "name", "disturbance");
% u = misc.ss.combineInputSignals(myStateSpace, t.grid, "disturbance", disturbanceSignal);
% y = quantity.Discrete(lsim(myStateSpace, u.on(), t.grid), t, "name", "y");
% plot([y; u]);
% -------------------------------------------------------------------------
......@@ -45,8 +43,8 @@ end
% replace '.' in varargin names, to obtain valid fieldnames
newVarargin = varargin;
for it = 1 : numel(newVarargin)
if ischar(newVarargin{it}) || isstring(newVarargin{it})
newVarargin{it} = strrep(newVarargin{it}, '.', 'POINT');
if isstring(newVarargin{it}) || ischar(newVarargin{it})
newVarargin{it} = strrep(newVarargin{it}, ".", "POINT");
end
end
myParser.parse(newVarargin{:});
......
......@@ -7,15 +7,15 @@ function resultSs = connect(InputName, OutputName, options, varargin)
% remove empty elements of varargin
% note that empty(ss) does not work, since state space models without inputs are
% considered as empty. Hence, size(v, 1) > 0 is used instead.
if isa(options, 'ltioptions.connect')
if isa(options, "ltioptions.connect")
inputSs = varargin(cellfun(@(v) size(v, 1) > 0, varargin));
else
if isa(options, 'numlti')
if isa(options, "numlti")
inputSs = [{options}, varargin(cellfun(@(v) size(v, 1) > 0, varargin))];
elseif ~isempty(options)
error("third input must be a connectOptions() or a StateSpaceModel");
end
options = connectOptions('Simplify', false);
options = connectOptions("Simplify", false);
end
% clean state-spaces
......@@ -27,18 +27,18 @@ for it = 1 : numel(inputSs)
end
% get InputNames of result
resultInputNames = unique(misc.ss.removeSingularEnumeration(InputName), 'stable');
resultOutputNames = unique(misc.ss.removeSingularEnumeration(OutputName), 'stable');
resultInputNames = unique(misc.ss.removeSingularEnumeration(InputName), "stable");
resultOutputNames = unique(misc.ss.removeSingularEnumeration(OutputName), "stable");
if isempty(resultInputNames)
% as ss/connect does not support empty cell array for inputNames or outputNames, this dummy
% object is added for those cases.
resultInputNames = {"dummy.input"};
resultInputNames = "dummy.input";
resultOutputNames = [resultOutputNames; "dummy.output"];
inputSs = [inputSs, ...
{ss([], [], [], 0, "InputName", {"dummy.input"}, "OutputName", {"dummy.output"})}];
{ss([], [], [], 0, "InputName", "dummy.input", "OutputName", "dummy.output")}];
end
% call built-in function
resultSs = connect(inputSs{:}, resultInputNames, resultOutputNames, options);
end
\ No newline at end of file
end % misc.ss.connect()
\ No newline at end of file
function texStringFinal = printSumblk(thisSumblk, NameValue)
%PRINTSUMBLK creates a string containing latex syntax description of a sumblk ss block ase on
%sumblks parameter D, OutputName, InputName.
arguments
thisSumblk ss;
NameValue.subscript = false;
end
thisOutputName = string(misc.ss.removeEnumeration(thisSumblk.OutputName, true));
thisInputName = string(misc.ss.removeEnumeration(thisSumblk.InputName, true));
if NameValue.subscript
thisOutputName = extractBefore(thisOutputName, 2) + "_{" + extractAfter(thisOutputName, 1) + "}";
thisInputName = extractBefore(thisInputName, 2) + "_{" + extractAfter(thisInputName, 1) + "}";
end
texString = misc.latexChar(thisOutputName + "(t)") ...
+ " &= " + misc.latexChar(thisSumblk.D) ...
+ " " + misc.latexChar(thisInputName + "(t)");
if nargout < 1
misc.printTex(texString, "align", false);
else
texStringFinal = texString;
end
end
function unenumerateNames = removeEnumeration(enumeratedNames, makeUnique)
% 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
function unenumeratedNames = removeEnumeration(enumeratedNames, makeUnique)
% REMOVEENUMERATION removes braces with numbers from every string that is an
% element of the array enumeratedNames. This is for instance useful, to deal
% with InputName or OutputName properties of large state-space models (ss).
%
% unenumerateNames = removeEnumeration(enumeratedNames) returns the
% enumeratedNames cell-array without enumeration.
% enumeratedNames string-array without enumeration.
%
% unenumerateNames = removeEnumeration(enumeratedNames, true) returns enumeratedNames
% without enumeration, but only unique names. The order of names is not changed.
%
% Examples:
% misc.ss.removeEnumeration({'a(1)', 'a(2)', 'b'})
% misc.ss.removeEnumeration({'a(1)', 'a(2)', 'b'}, true)
unenumerateNames = cell(size(enumeratedNames));
for it = 1 : numel(enumeratedNames)
namesSplittedTemp = split(enumeratedNames{it}, '(');
unenumerateNames{it} = namesSplittedTemp{1};
% misc.ss.removeEnumeration(["a(1)", "a(2)", "b"])
% misc.ss.removeEnumeration(["a(1)", "a(2)", "b"], true)
arguments
enumeratedNames (:, 1) string;
makeUnique (1, 1) logical = false;
end
if nargin > 1 && makeUnique
unenumerateNames = unique(unenumerateNames, 'stable');
unenumeratedNames = enumeratedNames;
enumeratedIndex = endsWith(enumeratedNames, ")") & contains(enumeratedNames, "(");
if any(enumeratedIndex)
splittedEnumeratedNames = split(enumeratedNames(enumeratedIndex), "(", 2);
unenumeratedNames(enumeratedIndex) = splittedEnumeratedNames(:, 1);
end
if makeUnique
unenumeratedNames = unique(unenumeratedNames, "stable");
end
end % removeEnumeration
\ No newline at end of file
function newNames = removeSingularEnumeration(enumeratedNames)
% REMOVESINGULARENUMERATION removes braces with numbers from char-arrays of singular
% names that are an element of the cell-array enumeratedNames.
% REMOVESINGULARENUMERATION removes braces with numbers from string-arrays of singular
% names that are an element of the array enumeratedNames.
% This is for instance useful, to deal with InputName or OutputName properties of
% large state-space models (ss).
%
% Examples:
% misc.ss.removeSingularEnumeration({'a(1)', 'a(2)', 'b(1)', 'c(1)', 'b', 'c(2)', 'd(1)'})
% misc.ss.removeSingularEnumeration(["a(1)", "a(2)", "b(1)", "c(1)", "b", "c(2)", "d(1)"])
newNames = enumeratedNames;
for it = 1 : numel(enumeratedNames)
if contains(enumeratedNames{it}, '(1)')
namesSplittedTemp = split(enumeratedNames{it}, '(');
if sum(contains(newNames, [namesSplittedTemp{1}, '('])) == 1
newNames{it} = strrep(enumeratedNames{it}, '(1)', '');
end
end
arguments
enumeratedNames (:, 1) string;
end
newNames = enumeratedNames;
endWith1Idx = endsWith(enumeratedNames, "(1)");
newNames(endWith1Idx) = strrep(enumeratedNames(endWith1Idx), "(1)", "");
for it = 1 : numel(newNames)
if endWith1Idx(it) && any(strcmp(newNames, newNames(it) + "(2)"))
newNames(it) = newNames(it) + "(1)";
end % if
end
end % misc.ss.removeSingularEnumeration()
\ No newline at end of file
......@@ -18,37 +18,39 @@ function myStateSpace = setSignalName(myStateSpace, signalType, signalNames, sig
% Example:
% -------------------------------------------------------------------------
% mySimulationModel = ss(1, 1, [1; 2; 3], []);
% mySimulationModel = misc.ss.setSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
% mySimulationModel = misc.ss.setSignalName(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);
arguments
myStateSpace ss;
signalType (1, 1) string;
signalNames (:, 1) string;
signalLength (:, 1) double;
end
% input checks
if strcmp(signalType, "input")
assert(size(myStateSpace, 2) == sum([signalLength(:)]), "signalLength does not fit to state space");
assert(size(myStateSpace, 2) == sum(signalLength), "signalLength does not fit to state space");
elseif strcmp(signalType, "output")
assert(size(my