1## Copyright (C) 2009-2016 Lukas F. Reichlin 2## 3## This file is part of LTI Syncope. 4## 5## LTI Syncope is free software: you can redistribute it and/or modify 6## it under the terms of the GNU General Public License as published by 7## the Free Software Foundation, either version 3 of the License, or 8## (at your option) any later version. 9## 10## LTI Syncope is distributed in the hope that it will be useful, 11## but WITHOUT ANY WARRANTY; without even the implied warranty of 12## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13## GNU General Public License for more details. 14## 15## You should have received a copy of the GNU General Public License 16## along with LTI Syncope. If not, see <http://www.gnu.org/licenses/>. 17 18## -*- texinfo -*- 19## @deftypefn {Function File} {@var{sys} =} ss (@var{sys}) 20## @deftypefnx {Function File} {@var{sys} =} ss (@var{d}, @dots{}) 21## @deftypefnx {Function File} {@var{sys} =} ss (@var{a}, @var{b}, @dots{}) 22## @deftypefnx {Function File} {@var{sys} =} ss (@var{a}, @var{b}, @var{c}, @dots{}) 23## @deftypefnx {Function File} {@var{sys} =} ss (@var{a}, @var{b}, @var{c}, @var{d}, @dots{}) 24## @deftypefnx {Function File} {@var{sys} =} ss (@var{a}, @var{b}, @var{c}, @var{d}, @var{tsam}, @dots{}) 25## Create or convert to state-space model. 26## 27## @strong{Inputs} 28## @table @var 29## @item sys 30## @acronym{LTI} model to be converted to state-space. 31## @item a 32## State matrix (n-by-n). 33## @item b 34## Input matrix (n-by-m). 35## @item c 36## Output matrix (p-by-n). 37## If @var{c} is empty @code{[]} or not specified, an identity matrix is assumed. 38## @item d 39## Feedthrough matrix (p-by-m). 40## If @var{d} is empty @code{[]} or not specified, a zero matrix is assumed. 41## @item tsam 42## Sampling time in seconds. If @var{tsam} is not specified, a continuous-time model is assumed. 43## @item @dots{} 44## Optional pairs of properties and values. 45## Type @command{set (ss)} for more information. 46## @end table 47## 48## @strong{Outputs} 49## @table @var 50## @item sys 51## State-space model. 52## @end table 53## 54## @strong{Option Keys and Values} 55## @table @var 56## @item 'a', 'b', 'c', 'd', 'e' 57## State-space matrices. See 'Inputs' for details. 58## 59## @item 'stname' 60## The name of the states in @var{sys}. 61## Cell vector containing strings for each state. 62## Default names are @code{@{'x1', 'x2', ...@}} 63## 64## @item 'scaled' 65## Logical. If set to true, no automatic scaling is used, 66## e.g. for frequency response plots. 67## 68## @item 'tsam' 69## Sampling time. See 'Inputs' for details. 70## 71## @item 'inname' 72## The name of the input channels in @var{sys}. 73## Cell vector of length m containing strings. 74## Default names are @code{@{'u1', 'u2', ...@}} 75## 76## @item 'outname' 77## The name of the output channels in @var{sys}. 78## Cell vector of length p containing strings. 79## Default names are @code{@{'y1', 'y2', ...@}} 80## 81## @item 'ingroup' 82## Struct with input group names as field names and 83## vectors of input indices as field values. 84## Default is an empty struct. 85## 86## @item 'outgroup' 87## Struct with output group names as field names and 88## vectors of output indices as field values. 89## Default is an empty struct. 90## 91## @item 'name' 92## String containing the name of the model. 93## 94## @item 'notes' 95## String or cell of string containing comments. 96## 97## @item 'userdata' 98## Any data type. 99## @end table 100## 101## @strong{Equations} 102## @example 103## @group 104## . 105## x = A x + B u 106## y = C x + D u 107## @end group 108## @end example 109## 110## @strong{Example} 111## @example 112## @group 113## octave:1> a = [1 2 3; 4 5 6; 7 8 9]; 114## octave:2> b = [10; 11; 12]; 115## octave:3> stname = @{'V', 'A', 'kJ'@}; 116## octave:4> sys = ss (a, b, 'stname', stname) 117## @end group 118## @end example 119## 120## @example 121## @group 122## sys.a = 123## V A kJ 124## V 1 2 3 125## A 4 5 6 126## kJ 7 8 9 127## @end group 128## @end example 129## 130## @example 131## @group 132## sys.b = 133## u1 134## V 10 135## A 11 136## kJ 12 137## @end group 138## @end example 139## 140## @example 141## @group 142## sys.c = 143## V A kJ 144## y1 1 0 0 145## y2 0 1 0 146## y3 0 0 1 147## @end group 148## @end example 149## 150## @example 151## @group 152## sys.d = 153## u1 154## y1 0 155## y2 0 156## y3 0 157## 158## Continuous-time model. 159## octave:5> 160## @end group 161## @end example 162## 163## @strong{Note on compatibility} 164## 165## If the state-space model @var{sys} is converted from a transfer 166## function, the resulting state-space model can be transformed into 167## the form computed by Matlab (a controllable canonical form with 168## flipped state variables order) by using the following 169## similarity transformation: 170## 171## @example 172## @group 173## n = size (sys.a, 1) 174## QSi = inv (ctrb (sys)) 175## T(n,:) = QSi(n,:) 176## for i=n-1:-1:1, T(i,:) = T(i+1,:)*sys.a, endfor 177## sys_ml = ss2ss (sys, T) 178## @end group 179## @end example 180## 181## @seealso{tf, dss} 182## @end deftypefn 183 184## Author: Lukas Reichlin <lukas.reichlin@gmail.com> 185## Created: September 2009 186## Version: 0.4 187 188function sys = ss (varargin) 189 190 ## model precedence: frd > ss > zpk > tf > double 191 ## inferiorto ("frd"); 192 superiorto ("zpk", "tf", "double"); 193 194 if (nargin == 1) # shortcut for lti objects 195 if (isa (varargin{1}, "ss")) # already in ss form sys = ss (sssys) 196 sys = varargin{1}; 197 return; 198 elseif (isa (varargin{1}, "lti")) # another lti object sys = ss (sys) 199 [sys, lti] = __sys2ss__ (varargin{1}); 200 sys.lti = lti; # preserve lti properties 201 return; 202 endif 203 elseif (nargin == 2) # shortcut for lti objects plus 204 if (ischar (varargin{2}) && isa (varargin{1}, "lti")) 205 candidates = {"minimal", "explicit"}; 206 key = __match_key__ (varargin{2}, candidates, "ss"); 207 switch (key) 208 case "minimal" # ss (sys, 'minimal') 209 sys = minreal (ss (varargin{1})); 210 return; 211 case "explicit" # ss (sys, 'explicit') 212 sys = dss2ss (ss (varargin{1})); 213 return; 214 otherwise # this would be a silly bug 215 endswitch 216 endif 217 endif 218 219 a = []; b = []; c = []; d = []; # default state-space matrices 220 tsam = 0; # default sampling time 221 222 [mat_idx, opt_idx, obj_flg] = __lti_input_idx__ (varargin); 223 224 switch (numel (mat_idx)) 225 case 1 226 d = varargin{mat_idx}; 227 case 2 228 [a, b] = varargin{mat_idx}; 229 case 3 230 [a, b, c] = varargin{mat_idx}; 231 case 4 232 [a, b, c, d] = varargin{mat_idx}; 233 case 5 234 [a, b, c, d, tsam] = varargin{mat_idx}; 235 if (isempty (tsam) && is_real_matrix (tsam)) 236 tsam = -1; 237 elseif (! issample (tsam, -10)) 238 error ("ss: invalid sampling time"); 239 endif 240 case 0 241 ## nothing to do here, just prevent case 'otherwise' 242 otherwise 243 print_usage (); 244 endswitch 245 246 varargin = varargin(opt_idx); 247 if (obj_flg) 248 varargin = horzcat ({"lti"}, varargin); 249 endif 250 251 [a, b, c, d, tsam] = __adjust_ss_data__ (a, b, c, d, tsam); 252 [p, m, n] = __ss_dim__ (a, b, c, d); # determine number of outputs, inputs and states 253 254 stname = repmat ({""}, n, 1); # cell with empty state names 255 256 ssdata = struct ("a", a, "b", b, 257 "c", c, "d", d, 258 "e", [], 259 "stname", {stname}, 260 "scaled", false); # struct for ss-specific data 261 262 ltisys = lti (p, m, tsam); # parent class for general lti data 263 264 sys = class (ssdata, "ss", ltisys); # create ss object 265 266 if (numel (varargin) > 0) # if there are any properties and values, ... 267 sys = set (sys, varargin{:}); # use the general set function 268 endif 269 270endfunction 271 272 273## TODO: create a separate function @lti/dss2ss.m 274function G = dss2ss (G) 275 276 [G.a, G.b, G.c, G.d, G.e] = __dss2ss__ (G.a, G.b, G.c, G.d, G.e); 277 278endfunction 279