Commit 7dd6bd80 authored by Jakob Gabriel's avatar Jakob Gabriel
Browse files

misc: removed methods for state spaces to misc.ss and added new function addInput2Output

parent f894d261
# misc.ss
This folder misc.ss contains functions that are specifically designed for use with state-space models with the Control System Toolbox. For more Information on this, type "doc ss" in your Command Window.
Most of the files are written to deal with large state-spaces, i.e., approximations of pde systems.
function myStateSpace = addInput2Output(myStateSpace)
% ADDINPUT2OUTPUTNAME adds all inputs to the outputs of the state space model, by
% designing feedthroughs.
%
% Inputs:
% myStateSpace state space which is modified
% Outputs:
% myStateSpace the state space with modified parameters
%
% Example:
% -------------------------------------------------------------------------
% 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);
% -------------------------------------------------------------------------
% read InputName and OutputName
inputNameAll = misc.ss.removeEnumeration(myStateSpace.InputName);
outputNameAll = misc.ss.removeEnumeration(myStateSpace.OutputName);
% count
inputName = unique(inputNameAll, 'stable');
outputName = unique(outputNameAll, 'stable');
inputNameCount = cellfun(@(v) sum(count(inputNameAll, v)), inputName);
outputNameCount = cellfun(@(v) sum(count(outputNameAll, v)), outputName);
% add feedthrough
isFeedThroughNeccessary = false([numel(inputName), 1]);
for it = 1 : numel(inputName)
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})));
isFeedThroughNeccessary(it) = false;
else
% Create a feedthrough and add it to myStateSpace
% feedthrough:
feedthroughTemp = ss([], [], [], eye(inputNameCount(it)), ...
'OutputName', inputName(it), 'InputName', inputName(it));
% connection:
% first myStateSpace is appended, then the input of the feedthrough and the
% state space are interconneted using series()
myStateSpace = append(myStateSpace, feedthroughTemp);
isFeedThroughNeccessary(it) = true;
end
end
% create short cut of feedthrough and input
shortCutMatrix = eye(sum(inputNameCount));
shortCutMatrixSelector = true(size(shortCutMatrix));
% remove rows that have now feedthrough
for it = 1 : numel(inputName)
if ~isFeedThroughNeccessary(it)
shortCutMatrixSelector(inputNameCount(1:(it-1))+(1:inputNameCount(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);
myStateSpace = series(shortCut, myStateSpace);
end
function myStateSpace = changeSsSignalName(myStateSpace, oldName, newName, varargin)
function myStateSpace = changeSignalName(myStateSpace, oldName, newName, varargin)
% CHANGESSSIGNALNAME sets the property 'OutputName' or 'InputName' of the ss
% myStateSpace by replacing oldName with newName.
%
......@@ -17,8 +17,8 @@ function myStateSpace = changeSsSignalName(myStateSpace, oldName, newName, varar
% Example:
% -------------------------------------------------------------------------
% mySimulationModel = ss(1, 1, [1; 2; 3], []);
% mySimulationModel = misc.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
% mySimulationModel = misc.changeSsSignalName(mySimulationModel, {'a'}, {'c'});
% mySimulationModel = misc.ss.setSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
% mySimulationModel = misc.ss.changeSignalName(mySimulationModel, {'a'}, {'c'});
% -------------------------------------------------------------------------
% input checks
......@@ -36,8 +36,8 @@ myParser.parse(myStateSpace, varargin{:});
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);
oldOutputNames = misc.ss.removeEnumeration(myStateSpace.OutputName);
oldInputNames = misc.ss.removeEnumeration(myStateSpace.InputName);
for it = 1 : numel(newName)
% exchange names
......@@ -59,10 +59,10 @@ outputLength = cellfun(@(v) sum(strcmp(oldOutputNames, v)), uniqueOutputNames);
% set input and ouput names
if myParser.Results.input
myStateSpace = misc.setSsSignalName(myStateSpace, 'input', uniqueInputNames, inputLength);
myStateSpace = misc.ss.setSignalName(myStateSpace, 'input', uniqueInputNames, inputLength);
end
if myParser.Results.output
myStateSpace = misc.setSsSignalName(myStateSpace, 'output', uniqueOutputNames, outputLength);
myStateSpace = misc.ss.setSignalName(myStateSpace, 'output', uniqueOutputNames, outputLength);
end
end
......
......@@ -3,7 +3,7 @@ function unenumerateNames = removeEnumeration(enumeratedNames)
% 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)'})
% misc.ss.removeEnumeration({'a(1)'})
unenumerateNames = cell(size(enumeratedNames));
for it = 1 : numel(enumeratedNames)
namesSplittedTemp = split(enumeratedNames{it}, '(');
......
function myStateSpace = setSsSignalName(myStateSpace, signalType, signalNames, signalLength)
function myStateSpace = setSignalName(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
......@@ -18,7 +18,7 @@ function myStateSpace = setSsSignalName(myStateSpace, signalType, signalNames, s
% Example:
% -------------------------------------------------------------------------
% mySimulationModel = ss(1, 1, [1; 2; 3], []);
% mySimulationModel = misc.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
% mySimulationModel = misc.ss.setSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
% -------------------------------------------------------------------------
% input checks
......
......@@ -47,7 +47,7 @@ assert(isequal(size(simOutput), [numel(time), numel(outputNames)]), ...
% 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);
outputNamesUnenumerated = misc.ss.removeEnumeration(outputNames);
signalNames = unique(outputNamesUnenumerated, 'stable');
% input check for optional parameter z that defines spatial grids
......
......@@ -4,33 +4,6 @@ function [tests] = testMisc()
tests = functiontests(localfunctions());
end
function testChangeSsSignalName(testCase)
mySimulationModel = ss(1, 1, [1; 2; 3], []);
mySimulationModel = misc.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
mySimulationModel = misc.changeSsSignalName(mySimulationModel, {'a'}, {'c'});
testCase.verifyEqual(mySimulationModel.OutputName, {'c(1)'; 'c(2)'; 'b'})
end
function testSetSsSignalName(testCase)
mySimulationModel = ss(1, [1, 0], [1; 2; 3], []);
mySimulationModel = misc.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
mySimulationModel = misc.setSsSignalName(mySimulationModel, 'input', {'c'}, {2});
testCase.verifyEqual(mySimulationModel.OutputName, {'a(1)'; 'a(2)'; 'b'})
testCase.verifyEqual(mySimulationModel.InputName, {'c(1)'; 'c(2)'})
end
function testSimulationOuput2Quantity(testCase)
mySimulationModelA = ss(1, 1, [1; 2], [], 'OutputName', {'a'}, 'InputName', 'u');
mySimulationModelB = ss(1, 1, [1; 2], [], 'OutputName', {'b'}, 'InputName', 'u');
mySimulationModel = append(mySimulationModelA, mySimulationModelB);
myIc = 0.5*ones(size(mySimulationModel.A, 1), 1);
time = linspace(0, 1, 51);
myInput = zeros(numel(time), size(mySimulationModel, 2));
simulationOutputArray = lsim(mySimulationModel, myInput, time, myIc);
simulationOutputQuantity = misc.simulationOutput2Quantity( ...
simulationOutputArray, time, mySimulationModel.OutputName);
testCase.verifyEqual(simulationOutputQuantity.a.on(), simulationOutputQuantity.b.on());
end
function testIsunique(testCase)
testCase.verifyTrue(misc.isunique({'bli', 'bla', 'blu'}));
......
function [tests] = testSs()
%TESTMISC Summary of this function goes here
% Detailed explanation goes here
tests = functiontests(localfunctions());
end
function testAddInput2Output(testCase)
% first example
mySimulationModelOriginal = 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'});
mySimulationModelModified = misc.ss.addInput2Output(mySimulationModelOriginal);
verifyAddInput2Output(testCase, mySimulationModelModified, mySimulationModelOriginal);
% second example
mySimulationModelOriginal2 = ss(1, [1, 2, 3], [1; 2; 3], [1, 0, 0; 0, 0, 0; 0, 0, 0], ...
'OutputName', {'x(1)', 'x(2)', 'y'}, 'InputName', {'u(1)', 'u(2)', 'y'});
mySimulationModelModified2 = misc.ss.addInput2Output(mySimulationModelOriginal2);
verifyAddInput2Output(testCase, mySimulationModelModified2, mySimulationModelOriginal2);
function testCase = verifyAddInput2Output(testCase, ssModified, ssOriginal)
testCase.verifyEqual(ssModified.A, ssOriginal.A);
testCase.verifyEqual(ssModified.B, ssOriginal.B);
resultingOutputNames = unique([ssOriginal.OutputName; ssOriginal.InputName], 'stable');
testCase.verifyEqual(ssModified.C, ...
[ssOriginal.C; zeros(numel(resultingOutputNames)-size(ssOriginal.C, 1), size(ssOriginal.A, 1))]);
testCase.verifyEqual(ssModified.D(1:size(ssOriginal.C, 1), :), ssOriginal.D);
testCase.verifyEqual(size(ssModified.D), [numel(resultingOutputNames), size(ssOriginal.B, 2)]);
for it = 1 : size(ssOriginal.B, 2)
thisInputName = ssOriginal.InputName{it};
if ~any(strcmp(ssOriginal.OutputName, thisInputName))
testCase.verifyEqual(...
ssModified.D(strcmp(ssModified.OutputName, thisInputName), ...
strcmp(ssModified.InputName, thisInputName)), 1);
end
end
testCase.verifyEqual(ssModified.InputName, ssOriginal.InputName);
testCase.verifyEqual(ssModified.OutputName, resultingOutputNames);
end
end
function testChangeSsSignalName(testCase)
mySimulationModel = ss(1, 1, [1; 2; 3], []);
mySimulationModel = misc.ss.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
mySimulationModel = misc.ss.changeSsSignalName(mySimulationModel, {'a'}, {'c'});
testCase.verifyEqual(mySimulationModel.OutputName, {'c(1)'; 'c(2)'; 'b'})
end
function testSetSsSignalName(testCase)
mySimulationModel = ss(1, [1, 0], [1; 2; 3], []);
mySimulationModel = misc.ss.setSsSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
mySimulationModel = misc.ss.setSsSignalName(mySimulationModel, 'input', {'c'}, {2});
testCase.verifyEqual(mySimulationModel.OutputName, {'a(1)'; 'a(2)'; 'b'})
testCase.verifyEqual(mySimulationModel.InputName, {'c(1)'; 'c(2)'})
end
function testSimulationOuput2Quantity(testCase)
mySimulationModelA = ss(1, 1, [1; 2], [], 'OutputName', {'a'}, 'InputName', 'u');
mySimulationModelB = ss(1, 1, [1; 2], [], 'OutputName', {'b'}, 'InputName', 'u');
mySimulationModel = append(mySimulationModelA, mySimulationModelB);
myIc = 0.5*ones(size(mySimulationModel.A, 1), 1);
time = linspace(0, 1, 51);
myInput = zeros(numel(time), size(mySimulationModel, 2));
simulationOutputArray = lsim(mySimulationModel, myInput, time, myIc);
simulationOutputQuantity = misc.simulationOutput2Quantity( ...
simulationOutputArray, time, mySimulationModel.OutputName);
testCase.verifyEqual(simulationOutputQuantity.a.on(), simulationOutputQuantity.b.on());
end
\ No newline at end of file
function [tests] = testSs()
%TESTMISC Summary of this function goes here
% Detailed explanation goes here
tests = functiontests(localfunctions());
end
function testAddInput2Output(testCase)
% first example
mySimulationModelOriginal = 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'});
mySimulationModelModified = misc.ss.addInput2Output(mySimulationModelOriginal);
verifyAddInput2Output(testCase, mySimulationModelModified, mySimulationModelOriginal);
% second example
mySimulationModelOriginal2 = ss(1, [1, 2, 3], [1; 2; 3], [1, 0, 0; 0, 0, 0; 0, 0, 0], ...
'OutputName', {'x(1)', 'x(2)', 'y'}, 'InputName', {'u(1)', 'u(2)', 'y'});
mySimulationModelModified2 = misc.ss.addInput2Output(mySimulationModelOriginal2);
verifyAddInput2Output(testCase, mySimulationModelModified2, mySimulationModelOriginal2);
function testCase = verifyAddInput2Output(testCase, ssModified, ssOriginal)
testCase.verifyEqual(ssModified.A, ssOriginal.A);
testCase.verifyEqual(ssModified.B, ssOriginal.B);
resultingOutputNames = unique([ssOriginal.OutputName; ssOriginal.InputName], 'stable');
testCase.verifyEqual(ssModified.C, ...
[ssOriginal.C; zeros(numel(resultingOutputNames)-size(ssOriginal.C, 1), size(ssOriginal.A, 1))]);
testCase.verifyEqual(ssModified.D(1:size(ssOriginal.C, 1), :), ssOriginal.D);
testCase.verifyEqual(size(ssModified.D), [numel(resultingOutputNames), size(ssOriginal.B, 2)]);
for it = 1 : size(ssOriginal.B, 2)
thisInputName = ssOriginal.InputName{it};
if ~any(strcmp(ssOriginal.OutputName, thisInputName))
testCase.verifyEqual(...
ssModified.D(strcmp(ssModified.OutputName, thisInputName), ...
strcmp(ssModified.InputName, thisInputName)), 1);
end
end
testCase.verifyEqual(ssModified.InputName, ssOriginal.InputName);
testCase.verifyEqual(ssModified.OutputName, resultingOutputNames);
end
end
function testChangeSignalName(testCase)
mySimulationModel = ss(1, 1, [1; 2; 3], []);
mySimulationModel = misc.ss.setSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
mySimulationModel = misc.ss.changeSignalName(mySimulationModel, {'a'}, {'c'});
testCase.verifyEqual(mySimulationModel.OutputName, {'c(1)'; 'c(2)'; 'b'})
end
function testSetSignalName(testCase)
mySimulationModel = ss(1, [1, 0], [1; 2; 3], []);
mySimulationModel = misc.ss.setSignalName(mySimulationModel, 'output', {'a', 'b'}, {2, 1});
mySimulationModel = misc.ss.setSignalName(mySimulationModel, 'input', {'c'}, {2});
testCase.verifyEqual(mySimulationModel.OutputName, {'a(1)'; 'a(2)'; 'b'})
testCase.verifyEqual(mySimulationModel.InputName, {'c(1)'; 'c(2)'})
end
function testSimulationOuput2Quantity(testCase)
mySimulationModelA = ss(1, 1, [1; 2], [], 'OutputName', {'a'}, 'InputName', 'u');
mySimulationModelB = ss(1, 1, [1; 2], [], 'OutputName', {'b'}, 'InputName', 'u');
mySimulationModel = append(mySimulationModelA, mySimulationModelB);
myIc = 0.5*ones(size(mySimulationModel.A, 1), 1);
time = linspace(0, 1, 51);
myInput = zeros(numel(time), size(mySimulationModel, 2));
simulationOutputArray = lsim(mySimulationModel, myInput, time, myIc);
simulationOutputQuantity = misc.ss.simulationOutput2Quantity( ...
simulationOutputArray, time, mySimulationModel.OutputName);
testCase.verifyEqual(simulationOutputQuantity.a.on(), simulationOutputQuantity.b.on());
end
\ No newline at end of file
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