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{s} =} tf (@var{'s'}) 20## @deftypefnx {Function File} {@var{z} =} tf (@var{'z'}, @var{tsam}) 21## @deftypefnx {Function File} {@var{sys} =} tf (@var{sys}) 22## @deftypefnx {Function File} {@var{sys} =} tf (@var{mat}, @dots{}) 23## @deftypefnx {Function File} {@var{sys} =} tf (@var{num}, @var{den}, @dots{}) 24## @deftypefnx {Function File} {@var{sys} =} tf (@var{num}, @var{den}, @var{tsam}, @dots{}) 25## Create or convert to transfer function model. 26## 27## @strong{Inputs} 28## @table @var 29## @item sys 30## @acronym{LTI} model to be converted to transfer function. 31## @item mat 32## Gain matrix to be converted to static transfer function. 33## @item num 34## Numerator or cell of numerators. Each numerator must be a row vector 35## containing the coefficients of the polynomial in descending powers of 36## the transfer function variable. 37## num@{i,j@} contains the numerator polynomial from input j to output i. 38## In the SISO case, a single vector is accepted as well. 39## @item den 40## Denominator or cell of denominators. Each denominator must be a row vector 41## containing the coefficients of the polynomial in descending powers of 42## the transfer function variable. 43## den@{i,j@} contains the denominator polynomial from input j to output i. 44## In the SISO case, a single vector is accepted as well. 45## @item tsam 46## Sampling time in seconds. If @var{tsam} is not specified, a continuous-time 47## model is assumed. 48## @item @dots{} 49## Optional pairs of properties and values. 50## Type @command{set (tf)} for more information. 51## @end table 52## 53## @strong{Outputs} 54## @table @var 55## @item sys 56## Transfer function model. 57## @end table 58## 59## @strong{Option Keys and Values} 60## @table @var 61## @item 'num' 62## Numerator. See 'Inputs' for details. 63## 64## @item 'den' 65## Denominator. See 'Inputs' for details. 66## 67## @item 'tfvar' 68## String containing the transfer function variable. 69## 70## @item 'inv' 71## Logical. True for negative powers of the transfer function variable. 72## 73## @item 'tsam' 74## Sampling time. See 'Inputs' for details. 75## 76## @item 'inname' 77## The name of the input channels in @var{sys}. 78## Cell vector of length m containing strings. 79## Default names are @code{@{'u1', 'u2', ...@}} 80## 81## @item 'outname' 82## The name of the output channels in @var{sys}. 83## Cell vector of length p containing strings. 84## Default names are @code{@{'y1', 'y2', ...@}} 85## 86## @item 'ingroup' 87## Struct with input group names as field names and 88## vectors of input indices as field values. 89## Default is an empty struct. 90## 91## @item 'outgroup' 92## Struct with output group names as field names and 93## vectors of output indices as field values. 94## Default is an empty struct. 95## 96## @item 'name' 97## String containing the name of the model. 98## 99## @item 'notes' 100## String or cell of string containing comments. 101## 102## @item 'userdata' 103## Any data type. 104## @end table 105## 106## @strong{Example} 107## @example 108## @group 109## octave:1> s = tf ('s'); 110## octave:2> G = 1/(s+1) 111## 112## Transfer function 'G' from input 'u1' to output ... 113## 114## 1 115## y1: ----- 116## s + 1 117## 118## Continuous-time model. 119## @end group 120## @end example 121## @example 122## @group 123## octave:3> z = tf ('z', 0.2); 124## octave:4> H = 0.095/(z-0.9) 125## 126## Transfer function 'H' from input 'u1' to output ... 127## 128## 0.095 129## y1: ------- 130## z - 0.9 131## 132## Sampling time: 0.2 s 133## Discrete-time model. 134## @end group 135## @end example 136## @example 137## @group 138## octave:5> num = @{[1, 5, 7], [1]; [1, 7], [1, 5, 5]@}; 139## octave:6> den = @{[1, 5, 6], [1, 2]; [1, 8, 6], [1, 3, 2]@}; 140## octave:7> sys = tf (num, den) 141## @end group 142## @end example 143## 144## @example 145## @group 146## Transfer function 'sys' from input 'u1' to output ... 147## 148## s^2 + 5 s + 7 149## y1: ------------- 150## s^2 + 5 s + 6 151## 152## s + 7 153## y2: ------------- 154## s^2 + 8 s + 6 155## @end group 156## @end example 157## 158## @example 159## @group 160## Transfer function 'sys' from input 'u2' to output ... 161## 162## 1 163## y1: ----- 164## s + 2 165## 166## s^2 + 5 s + 5 167## y2: ------------- 168## s^2 + 3 s + 2 169## 170## Continuous-time model. 171## octave:8> 172## @end group 173## @end example 174## 175## @seealso{filt, ss, dss} 176## @end deftypefn 177 178## Author: Lukas Reichlin <lukas.reichlin@gmail.com> 179## Created: September 2009 180## Version: 0.4 181 182function sys = tf (varargin) 183 184 ## model precedence: frd > ss > zpk > tf > double 185 ## inferiorto ("frd", "ss", "zpk"); # error if de-commented. bug in octave? 186 superiorto ("double"); 187 188 if (nargin == 1) 189 if (isa (varargin{1}, "tf")) # tf (tfsys) 190 sys = varargin{1}; 191 return; 192 elseif (isa (varargin{1}, "lti")) # tf (ltisys) 193 [sys, lti] = __sys2tf__ (varargin{1}); 194 sys.lti = lti; 195 return; 196 elseif (ischar (varargin{1})) # s = tf ('s') 197 sys = tf ([1, 0], 1, "tfvar", varargin{:}); 198 return; 199 endif 200 elseif (nargin == 2 ... 201 && ischar (varargin{1}) ... 202 && is_zp_vector (varargin{2}) ... 203 && length (varargin{2}) <= 1) # z = tf ('z', tsam) 204 sys = tf ([1, 0], 1, varargin{2}, "tfvar", varargin{[1,3:end]}); 205 return; 206 endif 207 208 num = {}; den = {}; # default transfer matrix 209 tsam = -2; # default sampling time 210 211 [mat_idx, opt_idx, obj_flg] = __lti_input_idx__ (varargin); 212 213 switch (numel (mat_idx)) 214 case 1 215 num = varargin{mat_idx}; 216 case 2 217 [num, den] = varargin{mat_idx}; 218 tsam = 0; 219 case 3 220 [num, den, tsam] = varargin{mat_idx}; 221 if (isempty (tsam) && is_real_matrix (tsam)) 222 tsam = -1; 223 elseif (! issample (tsam, -10)) 224 error ("tf: invalid sampling time"); 225 endif 226 case 0 227 ## nothing to do here, just prevent case 'otherwise' 228 otherwise 229 print_usage (); 230 endswitch 231 232 varargin = varargin(opt_idx); 233 if (obj_flg) 234 varargin = horzcat ({"lti"}, varargin); 235 endif 236 237 [num, den, tsam, tfvar] = __adjust_tf_data__ (num, den, tsam); 238 [p, m] = __tf_dim__ (num, den); # determine number of outputs and inputs 239 240 tfdata = struct ("num", {num}, 241 "den", {den}, 242 "tfvar", tfvar, 243 "inv", false); # struct for tf-specific data 244 245 ltisys = lti (p, m, tsam); # parent class for general lti data 246 247 sys = class (tfdata, "tf", ltisys); # create tf object 248 249 if (numel (varargin) > 0) # if there are any properties and values, ... 250 sys = set (sys, varargin{:}); # use the general set function 251 endif 252 253endfunction 254