# HG changeset patch # User jwe # Date 947823161 0 # Node ID 99ab64f4a09dfc1e64c00c064f87351e641a139e # Parent 65b3519ac3a1fc15785d5b70dd548952e1fdc51e [project @ 2000-01-14 03:53:03 by jwe] diff --git a/scripts/control/DEMOcontrol.m b/scripts/control/DEMOcontrol.m deleted file mode 100644 --- a/scripts/control/DEMOcontrol.m +++ /dev/null @@ -1,82 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} DEMOcontrol -## Octave Control Systems Toolbox demo/tutorial program. The demo -## allows the user to select among several categories of OCST function: -## @example -## @group -## octave:1> DEMOcontrol -## O C T A V E C O N T R O L S Y S T E M S T O O L B O X -## Octave Controls System Toolbox Demo -## -## [ 1] System representation -## [ 2] Block diagram manipulations -## [ 3] Frequency response functions -## [ 4] State space analysis functions -## [ 5] Root locus functions -## [ 6] LQG/H2/Hinfinity functions -## [ 7] End -## @end group -## @end example -## Command examples are interactively run for users to observe the use -## of OCST functions. -## @end deftypefn -## @seealso{Demo Programs: bddemo.m, frdemo.m, analdemo.m, -## moddmeo.m, rldemo.m} - -## Author: David Clem -## Created: August 15, 1994 - -function DEMOcontrol () - - puts ("O C T A V E C O N T R O L S Y S T E M S T O O L B O X") - - while (1) - - clc (); - - k = 0; - - while (k > 8 || k < 1), - k = menu ("Octave Controls System Toolbox Demo", - "System representation", - "Block diagram manipulations", - "Frequency response functions", - "State space analysis functions", - "System model manipulations", - "Root locus functions", - "LQG/H2/Hinfinity functions", - "End"); - endwhile - - switch (k) - case (1) sysrepdemo (); - case (2) bddemo (); - case (3) frdemo (); - case (4) analdemo (); - case (5) moddemo (); - case (6) rldemo (); - case (7) dgkfdemo (); - case (8) return; - endswitch - - endwhile - -endfunction diff --git a/scripts/control/Makefile.in b/scripts/control/Makefile.in --- a/scripts/control/Makefile.in +++ b/scripts/control/Makefile.in @@ -20,7 +20,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -SUBDIRS = base hinf obsolete system +SUBDIRS = base hinf obsolete system util DISTSUBDIRS = $(SUBDIRS) diff --git a/scripts/control/abcddim.m b/scripts/control/abcddim.m deleted file mode 100644 --- a/scripts/control/abcddim.m +++ /dev/null @@ -1,129 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{n}, @var{m}, @var{p}] =} abcddim (@var{a}, @var{b}, @var{c}, @var{d}) -## Check for compatibility of the dimensions of the matrices defining -## the linear system -## @iftex -## @tex -## $[A, B, C, D]$ corresponding to -## $$ -## \eqalign{ -## {dx\over dt} &= A x + B u\cr -## y &= C x + D u} -## $$ -## @end tex -## @end iftex -## @ifinfo -## [A, B, C, D] corresponding to -## -## @example -## dx/dt = a x + b u -## y = c x + d u -## @end example -## -## @end ifinfo -## or a similar discrete-time system. -## -## If the matrices are compatibly dimensioned, then @code{abcddim} returns -## -## @table @var -## @item n -## The number of system states. -## -## @item m -## The number of system inputs. -## -## @item p -## The number of system outputs. -## @end table -## -## Otherwise @code{abcddim} returns @var{n} = @var{m} = @var{p} = @minus{}1. -## -## Note: n = 0 (pure gain block) is returned without warning. -## -## @end deftypefn -## @seealso{is_abcd} - -## Author: A. S. Hodel -## Created: August 1993. -## a s hodel: modified to accept pure-gain systems aug 1996 - -function [n, m, p] = abcddim (a, b, c, d) - - if (nargin != 4) - error ("abcddim: four arguments required"); - endif - - n = m = p = -1; - - [a,an,am] = abcddims(a); - [b,bn,bm] = abcddims(b); - [c,cn,cm] = abcddims(c); - [d,dn,dm] = abcddims(d); - - if ( (!is_square(a)) & (!isempty(a)) ) - warning (["abcddim: a is not square (",num2str(an),"x",num2str(am),")"]); - return - endif - - if( (bm == 0) & (dm == 0) ) - warning("abcddim: no inputs"); - elseif (bn != am) - warning (["abcddim: a(",num2str(an),"x",num2str(am), ... - " and b(",num2str(bn),"x",num2str(bm),") are not compatible"]); - return - endif - - if( (cn == 0) & (dn == 0 ) ) - warning("abcddim: no outputs"); - elseif (cm != an) - warning (["abcddim: a(",num2str(an),"x",num2str(am), ... - " and c(",num2str(cn),"x",num2str(cm),") are not compatible"]); - return - endif - - have_connections = (bn*cn != 0); - - if( (dn == 0) & have_connections) - warning("abcddim: empty d matrix passed; setting compatibly with b, c"); - [d,dn,dm] = abcddims(zeros(cn,bm)); - endif - - if(an > 0) - [dn, dm] = size(d); - if ( (cn != dn) & have_connections ) - warning (["abcddim: c(",num2str(cn),"x",num2str(cm), ... - " and d(",num2str(dn),"x",num2str(dm),") are not compatible"]); - return - endif - - if ( (bm != dm) & have_connections ) - warning (["abcddim: b(",num2str(bn),"x",num2str(bm), ... - " and d(",num2str(dn),"x",num2str(dm),") are not compatible"]); - return - endif - - m = bm; - p = cn; - else - [p,m] = size(d); - endif - n = an; -endfunction diff --git a/scripts/control/abcddims.m b/scripts/control/abcddims.m deleted file mode 100644 --- a/scripts/control/abcddims.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 1997 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{y}, @var{my}, @var{ny}] =} abcddims (@var{x}) -## -## Used internally in @code{abcddim}. If @var{x} is a zero-size matrix, -## both dimensions are set to 0 in @var{y}. -## @var{my} and @var{ny} are the row and column dimensions of the result. -## @end deftypefn - -## Author: A. S. Hodel -## Created: February 1997 - -function [y, my, ny] = abcddims (x) - - y = x; - if(isempty(y)) - y = []; - endif - [my,ny] = size(y); - -endfunction diff --git a/scripts/control/analdemo.m b/scripts/control/analdemo.m deleted file mode 100644 --- a/scripts/control/analdemo.m +++ /dev/null @@ -1,243 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} analdemo () -## Octave Controls toolbox demo: State Space analysis demo -## @end deftypefn - -## Author: David Clem -## Created: August 15, 1994 -## Updated by John Ingram December 1996 - -function analdemo () - - while (1) - clc - k=0; - while(k > 8 || k < 1) - k = menu("Octave State Space Analysis Demo", ... - "System grammians (gram, dgram)", ... - "System zeros (tzero)", ... - "Continuous => Discrete and Discrete => Continuous conversions (c2d,d2c)", ... - "Algebraic Riccati Equation (are, dare)", ... - "Balanced realizations (balreal, dbalreal)", ... - "Open loop truncations via Hankel singular values (balreal, dbalreal)", ... - "SISO pole placement", ... - "Return to main demo menu"); - endwhile - if (k == 1) - clc - help dgram - prompt - - clc - disp("System Grammians: (see Moore, IEEE T-AC, 1981) \n"); - disp("Example #1, consider the discrete time state space system:\n"); - a=[1, 5, -8.4; 1.2, -3, 5; 1, 7, 9] - b=[1, 5; 2, 6; -4.4, 5] - c=[1, -1.5, 2; 6, -9.8, 1] - d=0 - prompt - disp("\nThe discrete controllability grammian is computed as follows:"); - cmd = "grammian = dgram(a, b);"; - run_cmd; - disp("Results:\n"); - grammian = dgram(a,b) - disp("Variable Description:\n"); - disp("grammian => discrete controllability grammian"); - disp("a, b => a and b matrices of discrete time system\n"); - disp("A dual approach may be used to compute the observability grammian."); - prompt - clc - - help gram - prompt - clc - - disp("Example #2, consider the continuous state space system:\n"); - a=[1, 3, -10.2; 3.7, -2, 9; n1, 3, 7] - b=[1, 12; 6, 2; -3.8, 7] - c=[1, -1.1, 7; 3, -9.8, 2] - d=0 - prompt - disp("\nThe continuous controllability grammian is computed as follows:"); - cmd = "grammian = gram(a, b);"; - run_cmd; - disp("Results:\n"); - grammian = gram(a,b) - disp("Variable Description:\n"); - disp("grammian => continuous controllability grammian"); - disp("a, b => a and b matrices of continuous time system\n"); - disp("A dual approach may be used to compute the observability grammian."); - prompt - clc - - - elseif (k == 2) - clc - help tzero - prompt - - disp("System zeros (tzero) example\n"); - disp("Example #1, consider the state space system:\n"); - a=[0, 1, 0; -10, -2, 0; -10, 0, -8] - b=[0; 1; 9] - c=[-10, 0, -4] - d=1 - prompt - disp("\nTo compute the zeros of this system, enter the following command:\n"); - cmd = "zer = tzero(a,b,c,d);"; - run_cmd; - disp("Results:\n"); - zer = tzero(a,b,c,d) - disp("Variable Description:\n"); - disp("zer => zeros of state space system"); - disp("a, b, c, d => state space system used as input argument"); - prompt - clc - - disp("Example #2, consider the state space system from example 1 again:"); - cmd = "sys = ss2sys(a,b,c,d);"; - disp(cmd); - eval(cmd); - sysout(sys); - disp("\nThe zeros of this system can also be calculated directly from the"); - disp("system variable:"); - cmd = "zer = tzero(sys);"; - run_cmd; - disp("Results:\n") - zer = tzero(sys) - disp("Variable Description:\n"); - disp("zer => zeros of state space system"); - disp("sys => state space system used as input argument"); - prompt - clc - - elseif (k == 3) - clc - help c2d - prompt - - clc - disp("Continuous => Discrete and Discrete => Continuous conversions (c2d,d2c)"); - disp("\nExample #1, consider the following continuous state space system"); - cmd = "sys_cont = ss2sys([-11, 6; -15, 8], [1; 2], [2, -1], 0);"; - eval(cmd); - disp(cmd); - disp("Examine the poles and zeros of the continuous system:"); - sysout(sys_cont,"all"); - disp("\nTo convert this to a discrete system, a sampling time is needed:"); - cmd = "Tsam = 0.5;"; - run_cmd; - disp("\nNow convert to a discrete system with the command:"); - cmd = "sys_disc = c2d(sys_cont,Tsam);"; - run_cmd; - disp("Examine the poles and zeros of the discrete system:"); - sysout(sys_disc,"all"); - prompt - clc - - disp("\nNow we will convert the discrete system back to a continuous system"); - disp("using the d2c command:"); - help d2c - prompt - cmd = "new_sys_cont = d2c(sys_disc);"; - run_cmd; - disp("\nExamine the poles and zeros of the discrete system:"); - sysout(new_sys_cont,"all"); - prompt - - elseif (k == 4) - clc - help are - prompt - clc - - disp("Algebraic Riccati Equation (are, dare)"); - - disp("\nExample #1, consider the continuous state space system:\n"); - a=[1, 3, -10.2; 3.7, -2, 9; 1, 3, 7] - b=[1, 12; 6, 2; -3.8, 7] - c=[1, -1.1, 7; 3, -9.8, 2] - d=0 - prompt - disp("\nThe solution to the continuous algebraic riccati equation"); - disp("is computed as follows:"); - cmd = "x_cont = are(a, b, c);"; - run_cmd; - disp("Results:\n") - x_cont = are(a,b,c) - disp("Variable Description:\n") - disp("x_cont => solution to the continuous algebraic riccati equation"); - disp("a, b, c => a, b, and c matrices of continuous time system\n"); - prompt - - clc - help dare - prompt - clc - - disp("Example #2, consider the discrete time state space system:\n"); - a=[1, 5, -8.4; 1.2, -3, 5; 1, 7, 9] - b=[1, 5; 2, 6; -4.4, 5] - c=[1, -1.5, 2; 6, -9.8, 1] - d=0 - r=eye(columns(b)) - prompt - disp("\nThe solution to the continuous algebraic riccati equation"); - disp("is computed as follows:"); - cmd = "x_disc = dare(a, b, c, r);"; - run_cmd; - disp("Results:\n") - x_disc = dare(a,b,c,r) - disp("Variable Description:\n"); - disp("x_disc => solution to the discrete algebraic riccati equation"); - disp("a, b, c => a, b and c matrices of discrete time system\n"); - prompt - clc - - elseif (k == 5) - disp("--- Balanced realization: not yet implemented") - elseif (k == 6) - disp("--- Open loop balanced truncation: not yet implemented") - elseif (k == 7) - disp("SISO pole placement example:") - cmd = "sys=tf2sys(1, [1, -2, 1]);"; - run_cmd - disp("System in zero-pole form is:") - cmd = "sysout(sys,\"zp\");"; - run_cmd - disp("and in state space form:") - cmd = "sysout(sys,\"ss\");"; - run_cmd - disp("Desired poles at -1, -1"); - cmd = "K=place(sys, [-1, -1])"; - run_cmd - disp("Check results:") - cmd = "[A,B] = sys2ss(sys);"; - run_cmd - cmd = "poles=eig(A-B*K)"; - run_cmd - prompt - elseif (k == 8) - return - endif - endwhile -endfunction - diff --git a/scripts/control/are.m b/scripts/control/are.m deleted file mode 100644 --- a/scripts/control/are.m +++ /dev/null @@ -1,118 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} are (@var{a}, @var{b}, @var{c}, @var{opt}) -## Solve the algebraic Riccati equation -## @iftex -## @tex -## $$ -## A^TX + XA - XBX + C = 0 -## $$ -## @end tex -## @end iftex -## @ifinfo -## @example -## a' * x + x * a - x * b * x + c = 0 -## @end example -## @end ifinfo -## -## @strong{Inputs} -## @noindent -## for identically dimensioned square matrices -## @table @var -## @item a -## @var{n}x@var{n} matrix. -## @item b -## @var{n}x@var{n} matrix or @var{n}x@var{m} matrix; in the latter case -## @var{b} is replaced by @math{b:=b*b'}. -## @item c -## @var{n}x@var{n} matrix or @var{p}x@var{m} matrix; in the latter case -## @var{c} is replaced by @math{c:=c'*c}. -## @item opt -## (optional argument; default = @code{"B"}): -## String option passed to @code{balance} prior to ordered Schur decomposition. -## @end table -## -## @strong{Outputs} -## @var{x}: solution of the ARE. -## -## @strong{Method} -## Laub's Schur method (IEEE Transactions on -## Automatic Control, 1979) is applied to the appropriate Hamiltonian -## matrix. -## -## @end deftypefn -## @seealso{balance and dare} - -## Author: A. S. Hodel -## Created: August 1993 - -function x = are (a, b, c, opt) - - if (nargin == 3 || nargin == 4) - if (nargin == 4) - if (! (strcmp (opt, "N") || strcmp (opt, "P") ... - || strcmp (opt, "S") || strcmp (opt, "B") ... - || strcmp (opt, "n") || strcmp (opt, "p") ... - || strcmp (opt, "s") || strcmp (opt, "b"))) - warning ("are: opt has an invalid value; setting to B"); - opt = "B"; - endif - else - opt = "B"; - endif - if ((n = is_square(a)) == 0) - error ("are: a is not square"); - endif - - if (is_controllable(a,b) == 0) - warning ("are: a, b are not controllable"); - endif - if ((m = is_square (b)) == 0) - b = b * b'; - m = rows (b); - endif - if (is_observable (a, c) == 0) - warning ("are: a,c are not observable"); - endif - if ((p = is_square (c)) == 0) - c = c' * c; - p = rows (c); - endif - if (n != m || n != p) - error ("are: a, b, c not conformably dimensioned."); - endif - -## Should check for controllability/observability here -## use Boley-Golub (Syst. Contr. Letters, 1984) method, not the -## -## n-1 -## rank ([ B A*B ... A^ *B]) method - - [d, h] = balance ([a, -b; -c, -a'], opt); - [u, s] = schur (h, "A"); - u = d * u; - n1 = n + 1; - n2 = 2 * n; - x = u (n1:n2, 1:n) / u (1:n, 1:n); - else - usage ("x = are (a, b, c)") - endif - -endfunction diff --git a/scripts/control/axis2dlim.m b/scripts/control/axis2dlim.m deleted file mode 100644 --- a/scripts/control/axis2dlim.m +++ /dev/null @@ -1,63 +0,0 @@ -## Copyright (C) 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn{Function File} {@var{axvec} =} axis2dlim (@var{axdata}) -## determine axis limits for 2-d data(column vectors); leaves a 10% margin -## around the plots. -## puts in margins of +/- 0.1 if data is one dimensional (or a single point) -## -## @strong{Inputs} -## @var{axdata} nx2 matrix of data [x,y] -## -## @strong{Outputs} -## @var{axvec} vector of axis limits appropriate for call to axis() function -## @end deftypefn - -function axvec = axis2dlim (axdata) - - if(isempty(axdata)) - axdata = 0; - endif - - ## compute axis limits - minv = min(axdata); - maxv = max(axdata); - delv = (maxv-minv)/2; # breadth of the plot - midv = (minv + maxv)/2; # midpoint of the plot - axmid = [midv(1), midv(1), midv(2), midv(2)]; - axdel = [-0.1, 0.1,-0.1,0.1]; # default plot width (if less than 2-d data) - if(max(delv) == 0) - if(midv(1) != 0) - axdel(1:2) = [-0.1*midv(1),0.1*midv(1)]; - endif - if(midv(2) != 0) - axdel(3:4) = [-0.1*midv(2),0.1*midv(2)]; - endif - else - ## they're at least one-dimensional - if(delv(1) != 0) - axdel(1:2) = 1.1*[-delv(1),delv(1)]; - endif - if(delv(2) != 0) - axdel(3:4) = 1.1*[-delv(2),delv(2)]; - endif - endif - axvec = axmid + axdel; -endfunction - diff --git a/scripts/control/base/DEMOcontrol.m b/scripts/control/base/DEMOcontrol.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/DEMOcontrol.m @@ -0,0 +1,82 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} DEMOcontrol +## Octave Control Systems Toolbox demo/tutorial program. The demo +## allows the user to select among several categories of OCST function: +## @example +## @group +## octave:1> DEMOcontrol +## O C T A V E C O N T R O L S Y S T E M S T O O L B O X +## Octave Controls System Toolbox Demo +## +## [ 1] System representation +## [ 2] Block diagram manipulations +## [ 3] Frequency response functions +## [ 4] State space analysis functions +## [ 5] Root locus functions +## [ 6] LQG/H2/Hinfinity functions +## [ 7] End +## @end group +## @end example +## Command examples are interactively run for users to observe the use +## of OCST functions. +## @end deftypefn +## @seealso{Demo Programs: bddemo.m, frdemo.m, analdemo.m, +## moddmeo.m, rldemo.m} + +## Author: David Clem +## Created: August 15, 1994 + +function DEMOcontrol () + + puts ("O C T A V E C O N T R O L S Y S T E M S T O O L B O X") + + while (1) + + clc (); + + k = 0; + + while (k > 8 || k < 1), + k = menu ("Octave Controls System Toolbox Demo", + "System representation", + "Block diagram manipulations", + "Frequency response functions", + "State space analysis functions", + "System model manipulations", + "Root locus functions", + "LQG/H2/Hinfinity functions", + "End"); + endwhile + + switch (k) + case (1) sysrepdemo (); + case (2) bddemo (); + case (3) frdemo (); + case (4) analdemo (); + case (5) moddemo (); + case (6) rldemo (); + case (7) dgkfdemo (); + case (8) return; + endswitch + + endwhile + +endfunction diff --git a/scripts/control/base/analdemo.m b/scripts/control/base/analdemo.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/analdemo.m @@ -0,0 +1,243 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} analdemo () +## Octave Controls toolbox demo: State Space analysis demo +## @end deftypefn + +## Author: David Clem +## Created: August 15, 1994 +## Updated by John Ingram December 1996 + +function analdemo () + + while (1) + clc + k=0; + while(k > 8 || k < 1) + k = menu("Octave State Space Analysis Demo", ... + "System grammians (gram, dgram)", ... + "System zeros (tzero)", ... + "Continuous => Discrete and Discrete => Continuous conversions (c2d,d2c)", ... + "Algebraic Riccati Equation (are, dare)", ... + "Balanced realizations (balreal, dbalreal)", ... + "Open loop truncations via Hankel singular values (balreal, dbalreal)", ... + "SISO pole placement", ... + "Return to main demo menu"); + endwhile + if (k == 1) + clc + help dgram + prompt + + clc + disp("System Grammians: (see Moore, IEEE T-AC, 1981) \n"); + disp("Example #1, consider the discrete time state space system:\n"); + a=[1, 5, -8.4; 1.2, -3, 5; 1, 7, 9] + b=[1, 5; 2, 6; -4.4, 5] + c=[1, -1.5, 2; 6, -9.8, 1] + d=0 + prompt + disp("\nThe discrete controllability grammian is computed as follows:"); + cmd = "grammian = dgram(a, b);"; + run_cmd; + disp("Results:\n"); + grammian = dgram(a,b) + disp("Variable Description:\n"); + disp("grammian => discrete controllability grammian"); + disp("a, b => a and b matrices of discrete time system\n"); + disp("A dual approach may be used to compute the observability grammian."); + prompt + clc + + help gram + prompt + clc + + disp("Example #2, consider the continuous state space system:\n"); + a=[1, 3, -10.2; 3.7, -2, 9; n1, 3, 7] + b=[1, 12; 6, 2; -3.8, 7] + c=[1, -1.1, 7; 3, -9.8, 2] + d=0 + prompt + disp("\nThe continuous controllability grammian is computed as follows:"); + cmd = "grammian = gram(a, b);"; + run_cmd; + disp("Results:\n"); + grammian = gram(a,b) + disp("Variable Description:\n"); + disp("grammian => continuous controllability grammian"); + disp("a, b => a and b matrices of continuous time system\n"); + disp("A dual approach may be used to compute the observability grammian."); + prompt + clc + + + elseif (k == 2) + clc + help tzero + prompt + + disp("System zeros (tzero) example\n"); + disp("Example #1, consider the state space system:\n"); + a=[0, 1, 0; -10, -2, 0; -10, 0, -8] + b=[0; 1; 9] + c=[-10, 0, -4] + d=1 + prompt + disp("\nTo compute the zeros of this system, enter the following command:\n"); + cmd = "zer = tzero(a,b,c,d);"; + run_cmd; + disp("Results:\n"); + zer = tzero(a,b,c,d) + disp("Variable Description:\n"); + disp("zer => zeros of state space system"); + disp("a, b, c, d => state space system used as input argument"); + prompt + clc + + disp("Example #2, consider the state space system from example 1 again:"); + cmd = "sys = ss2sys(a,b,c,d);"; + disp(cmd); + eval(cmd); + sysout(sys); + disp("\nThe zeros of this system can also be calculated directly from the"); + disp("system variable:"); + cmd = "zer = tzero(sys);"; + run_cmd; + disp("Results:\n") + zer = tzero(sys) + disp("Variable Description:\n"); + disp("zer => zeros of state space system"); + disp("sys => state space system used as input argument"); + prompt + clc + + elseif (k == 3) + clc + help c2d + prompt + + clc + disp("Continuous => Discrete and Discrete => Continuous conversions (c2d,d2c)"); + disp("\nExample #1, consider the following continuous state space system"); + cmd = "sys_cont = ss2sys([-11, 6; -15, 8], [1; 2], [2, -1], 0);"; + eval(cmd); + disp(cmd); + disp("Examine the poles and zeros of the continuous system:"); + sysout(sys_cont,"all"); + disp("\nTo convert this to a discrete system, a sampling time is needed:"); + cmd = "Tsam = 0.5;"; + run_cmd; + disp("\nNow convert to a discrete system with the command:"); + cmd = "sys_disc = c2d(sys_cont,Tsam);"; + run_cmd; + disp("Examine the poles and zeros of the discrete system:"); + sysout(sys_disc,"all"); + prompt + clc + + disp("\nNow we will convert the discrete system back to a continuous system"); + disp("using the d2c command:"); + help d2c + prompt + cmd = "new_sys_cont = d2c(sys_disc);"; + run_cmd; + disp("\nExamine the poles and zeros of the discrete system:"); + sysout(new_sys_cont,"all"); + prompt + + elseif (k == 4) + clc + help are + prompt + clc + + disp("Algebraic Riccati Equation (are, dare)"); + + disp("\nExample #1, consider the continuous state space system:\n"); + a=[1, 3, -10.2; 3.7, -2, 9; 1, 3, 7] + b=[1, 12; 6, 2; -3.8, 7] + c=[1, -1.1, 7; 3, -9.8, 2] + d=0 + prompt + disp("\nThe solution to the continuous algebraic riccati equation"); + disp("is computed as follows:"); + cmd = "x_cont = are(a, b, c);"; + run_cmd; + disp("Results:\n") + x_cont = are(a,b,c) + disp("Variable Description:\n") + disp("x_cont => solution to the continuous algebraic riccati equation"); + disp("a, b, c => a, b, and c matrices of continuous time system\n"); + prompt + + clc + help dare + prompt + clc + + disp("Example #2, consider the discrete time state space system:\n"); + a=[1, 5, -8.4; 1.2, -3, 5; 1, 7, 9] + b=[1, 5; 2, 6; -4.4, 5] + c=[1, -1.5, 2; 6, -9.8, 1] + d=0 + r=eye(columns(b)) + prompt + disp("\nThe solution to the continuous algebraic riccati equation"); + disp("is computed as follows:"); + cmd = "x_disc = dare(a, b, c, r);"; + run_cmd; + disp("Results:\n") + x_disc = dare(a,b,c,r) + disp("Variable Description:\n"); + disp("x_disc => solution to the discrete algebraic riccati equation"); + disp("a, b, c => a, b and c matrices of discrete time system\n"); + prompt + clc + + elseif (k == 5) + disp("--- Balanced realization: not yet implemented") + elseif (k == 6) + disp("--- Open loop balanced truncation: not yet implemented") + elseif (k == 7) + disp("SISO pole placement example:") + cmd = "sys=tf2sys(1, [1, -2, 1]);"; + run_cmd + disp("System in zero-pole form is:") + cmd = "sysout(sys,\"zp\");"; + run_cmd + disp("and in state space form:") + cmd = "sysout(sys,\"ss\");"; + run_cmd + disp("Desired poles at -1, -1"); + cmd = "K=place(sys, [-1, -1])"; + run_cmd + disp("Check results:") + cmd = "[A,B] = sys2ss(sys);"; + run_cmd + cmd = "poles=eig(A-B*K)"; + run_cmd + prompt + elseif (k == 8) + return + endif + endwhile +endfunction + diff --git a/scripts/control/base/are.m b/scripts/control/base/are.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/are.m @@ -0,0 +1,118 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} are (@var{a}, @var{b}, @var{c}, @var{opt}) +## Solve the algebraic Riccati equation +## @iftex +## @tex +## $$ +## A^TX + XA - XBX + C = 0 +## $$ +## @end tex +## @end iftex +## @ifinfo +## @example +## a' * x + x * a - x * b * x + c = 0 +## @end example +## @end ifinfo +## +## @strong{Inputs} +## @noindent +## for identically dimensioned square matrices +## @table @var +## @item a +## @var{n}x@var{n} matrix. +## @item b +## @var{n}x@var{n} matrix or @var{n}x@var{m} matrix; in the latter case +## @var{b} is replaced by @math{b:=b*b'}. +## @item c +## @var{n}x@var{n} matrix or @var{p}x@var{m} matrix; in the latter case +## @var{c} is replaced by @math{c:=c'*c}. +## @item opt +## (optional argument; default = @code{"B"}): +## String option passed to @code{balance} prior to ordered Schur decomposition. +## @end table +## +## @strong{Outputs} +## @var{x}: solution of the ARE. +## +## @strong{Method} +## Laub's Schur method (IEEE Transactions on +## Automatic Control, 1979) is applied to the appropriate Hamiltonian +## matrix. +## +## @end deftypefn +## @seealso{balance and dare} + +## Author: A. S. Hodel +## Created: August 1993 + +function x = are (a, b, c, opt) + + if (nargin == 3 || nargin == 4) + if (nargin == 4) + if (! (strcmp (opt, "N") || strcmp (opt, "P") ... + || strcmp (opt, "S") || strcmp (opt, "B") ... + || strcmp (opt, "n") || strcmp (opt, "p") ... + || strcmp (opt, "s") || strcmp (opt, "b"))) + warning ("are: opt has an invalid value; setting to B"); + opt = "B"; + endif + else + opt = "B"; + endif + if ((n = is_square(a)) == 0) + error ("are: a is not square"); + endif + + if (is_controllable(a,b) == 0) + warning ("are: a, b are not controllable"); + endif + if ((m = is_square (b)) == 0) + b = b * b'; + m = rows (b); + endif + if (is_observable (a, c) == 0) + warning ("are: a,c are not observable"); + endif + if ((p = is_square (c)) == 0) + c = c' * c; + p = rows (c); + endif + if (n != m || n != p) + error ("are: a, b, c not conformably dimensioned."); + endif + +## Should check for controllability/observability here +## use Boley-Golub (Syst. Contr. Letters, 1984) method, not the +## +## n-1 +## rank ([ B A*B ... A^ *B]) method + + [d, h] = balance ([a, -b; -c, -a'], opt); + [u, s] = schur (h, "A"); + u = d * u; + n1 = n + 1; + n2 = 2 * n; + x = u (n1:n2, 1:n) / u (1:n, 1:n); + else + usage ("x = are (a, b, c)") + endif + +endfunction diff --git a/scripts/control/base/bddemo.m b/scripts/control/base/bddemo.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/bddemo.m @@ -0,0 +1,612 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outputs} =} bddemo (@var{inputs}) +## Octave Controls toolbox demo: Block Diagram Manipulations demo +## @end deftypefn + +## Author: David Clem +## Created: August 15, 1994 +## Modified by A S Hodel Summer-Fall 1996 + +function bddemo () + + sav_page = page_screen_output; + page_screen_output = 1; + + while (1) + clc + k=0; + while(k > 14 || k < 1) + k = menu("Octave Block Diagram Manipulations Demo", ... + "sysadd/syssub: F(s) = G(s) +/- H(s)", ... + "sysappend: add new inputs/outputs", ... + "syssetsignals: change names of inputs, outputs, and/or states", ... + "sysconnect: connect specified system inputs/outputs", ... + "syscont/sysdisc: extract the continuous (discrete) part of a system", ... + "sysdup: duplicate specified inputs/outputs", ... + "sysgroup: group two systems into a single system,", ... + "sysmult: F(s) = G(s)*H(s) (series connection)", ... + "sysprune: keep only specified inputs/outputs", ... + "sysscale: scale inputs/outputs by specified gain matrices", ... + "parallel: parallel connection of two systems", ... + "buildssic: the combination of all", ... + "Design examples:", ... + "Return to main demo menu"); + endwhile + if (k == 1) + clc + disp("sysadd: add two systems together") + disp("syssub: subtract F = G - H") + prompt + help sysadd + prompt + help syssub + prompt + disp("Example #1, \n") + cmd = "sys1 = tf2sys([1 -1],[1 2 1]);"; + run_cmd + cmd = "sys2 = tf2sys([1 -1],[1 2 3]);"; + run_cmd + disp("sys1=") + sysout(sys1); + prompt + disp("sys2=") + sysout(sys2); + cmd = "sys_sum1 = sysadd(sys1,sys1);"; + run_cmd + disp("This example adds sys1 to itself.") + cmd = "sysout(sys_sum1)"; + run_cmd + disp("Notice that the numerator is twice what it used to be.") + prompt + disp("Example 2:") + cmd = "sys_sub1 = syssub(sys1,sys2);"; + run_cmd + disp("Notice that sysadd (actually sysgroup, called by sysadd) lets you") + disp("know that your two systems had identical names for their states,") + disp("inputs and outputs. The warning message is perfectly harmless,") + disp("and is provided for user information only.") + disp("sys_sub1=") + sysout(sys_sub1) + disp("Notice that, since the two transfer functions had different") + disp("denominators, syssub converted the primary system type to ") + disp("state space. This is the typical behavior unless the") + disp("the two systems are both SISO, they both have the same poles,") + disp("and at least one of them has tf for its primary system type."); + prompt + elseif (k == 2) + disp("sysappend: add new inputs and/or outputs to a system") + help sysappend + prompt + disp("Consider a double-integrator system:") + sys = tf2sys(1, [1, 0, 0]); + sys=sysupdate(sys,"ss"); + sysout(sys,"ss"); + disp("We add a velocity disturbance input as follows:") + cmd = "sys1=sysappend(sys,[1;0]);"; + run_cmd + sysout(sys1,"ss"); + disp("Names of inputs can be included as follows:") + cmd = "sys1=sysappend(sys,[1;0], [],[],[],\"Disturb\");"; + run_cmd + disp("Notice that empty matrices can be listed for the D matrix if") + disp("all entries are zeros.") + disp(" ") + disp("sys1 is thus:") + sysout(sys1); + prompt + elseif (k == 3) + disp("syssetsignals:") + help syssetsignals + disp("Example system"); + a = rand(3,3); + b = rand(3,2); + c = rand(2,3); + sys = ss2sys(a,b,c); + sysout(sys); + prompt + disp("Change state names to larry, moe, and curly as follows:") + cmd = "sys = syssetsignals(sys,\"st\",list(\"larry\",\"moe \" , \"curly\"));"; + run_cmd + disp("Indicate that output 2 is discrete-time:") + cmd = "sys = syssetsignals(sys,\"yd\",1,2);"; + run_cmd + disp("Change output 2 name to \"Vir\""); + cmd = "sys = syssetsignals(sys,\"out\",\"Vir\",2);"; + run_cmd + disp("Resulting system is:") + sysout(sys); + prompt + elseif (k == 4) + help sysconnect + prompt + disp("********* N O T E *********") + disp("sysconnect is demonstrated fully in the design examples (option 13)"); + prompt + elseif (k == 5) + disp("syscont and sysdisc: ") + disp("Example block diagram 1:") + disp(" ------------------ ---------------------"); + disp(" u_in ->| Discrete system |--->| Continuous system | ---> y_out"); + disp(" ------------------ ---------------------"); + sys1 = tf2sys([1, 2],[1, 2, 1], 1,"u_in","y_disc"); + sys2 = tf2sys([1, 0],[1, -3, -2],0,"c_in","y_out"); + sys = sysmult(sys2,sys1); + disp("Consider the hybrid system") + sysout(sys); + prompt + help syscont + disp("The continuous part of the system can be extracted with syscont") + cmd = "[csys,Acd,Ccd] = syscont(sys);"; + run_cmd + disp("The resulting csys is") + sysout(csys); + disp("Notice that B is 0; there is no purely continuous path from the") + disp("input to the output"); + prompt + help sysdisc + disp("The discrete part of the system can be extracted with sysdisc") + cmd = "[dsys,Adc,Cdc] = sysdisc(sys)"; + run_cmd + disp("The resulting dsys is") + sysout(dsys); + disp("sysdisc returns dsys=empty since sys has no discrete outputs."); + prompt + disp("Example block diagram 2:") + sys1 = tf2sys([1, 2],[1, 2, 1], 1,"u_in","y_disc"); + sys2 = tf2sys([1, 0],[1, -3, -2],0,"c_in","y_out"); + disp(" ---------------------") + disp(" u_in -->o-->| Discrete system | --------> y_disc") + disp(" ^ --------------------- |") + disp(" | | "); + disp(" -----------------------------|---") + disp(" | |") + disp(" ------------------------------ |") + disp(" | |") + disp(" v --------------------- |") + disp(" c_in -->o-->| continuous system | --------> y_out") + disp(" ---------------------") + disp("repeat the above example with sys=") + sys = sysgroup(sys1, sys2); + sysout(sys) + prompt + sys = sysconnect(sys,[1, 2],[2, 1]); + sysout(sys); + cmd = "[csys,Acd,Bcd] = syscont(sys);"; + run_cmd + cmd = "[dsys,Acd,Bcd] = sysdisc(sys);"; + run_cmd + disp("csys is now") + sysout(csys) + disp("dsys is now") + sysout(dsys); + prompt + elseif (k == 6) + help sysdup + prompt + disp("********* N O T E *********") + disp("sysdup is fully demonstrated in the design examples (option 13)") + prompt + elseif (k == 7) + help sysgroup + disp(" ") + prompt + disp("Example: combine two SISO systems together:") + cmd = "sys_a=tf2sys([1, 2],[3, 4]);"; + run_cmd + cmd = "sys_b=tf2sys([5, 6],[7, 8],1);"; + run_cmd + cmd = "sys_g=sysgroup(sys_a,sys_b);"; + run_cmd + disp("Notice that sysgroup warns you when you join a purely continuous") + disp("system to a purely discrete system. sysgroup also warns when") + disp("you join two systems that have common state, input, or output names.") + cmd = "sysout(sys_g)"; + run_cmd + disp("Since the grouped system is a multiple-input multiple-output system,") + disp("the output system is by default in state-space format.") + disp(" ") + disp("********* N O T E *********") + disp("sysgroup is further demonstrated in the design examples (option 13)") + prompt + elseif (k == 8) + help sysmult + disp("sysmult performs a series connection of two systems.") + disp("Example 1") + disp(" ") + disp(" ---------- ----------") + disp(" u --->| Bsys |---->| Asys |---> y") + disp(" ---------- ----------") + disp(" ") + Asys = tf2sys(1,[1, 2, 1],0,"a_in","a_out"); + Bsys = tf2sys([2, 3],[1, 3, 2],0,"b_in","b_out"); + disp("Asys=") + sysout(Asys); + disp("Bsys="); + sysout(Bsys); + cmd = "sys = sysmult(Asys,Bsys);"; + run_cmd + disp("sys =") + sysout(sys); + disp("Notice that sysmult automatically transforms to state space") + disp("internal representation. This is to avoid numerical problems") + disp("when multiplying polynomials"); + prompt + disp("Example 2: same system, except that Bsys is discrete-time"); + Bsys = tf2sys([2, 3],[1, 3, 2],1e-2,"b_in","b_out"); + sysout(Bsys); + cmd = "sys = sysmult(Asys,Bsys);"; + run_cmd + disp("sys =") + sysout(sys); + prompt + elseif (k == 9) + help sysprune + prompt + disp("********* N O T E *********") + disp("sysprune is demonstrated in the design examples (option 13)"); + prompt + elseif (k == 10) + help sysscale + disp(" ") + prompt + disp("********* N O T E *********") + disp("See the design examples (option 13) for use of sysscale.") + prompt + elseif ( k == 11) + help parallel + disp("parallel operates by making a call to sysgroup and sysscale.") + disp("Example:") + sys1 = tf2sys(1,[1, 1],0,"in1","out1"); + sys2 = tf2sys(2,[1, 2],0,"in2","out2"); + disp("sys1=") + sysout(sys1); + disp("sys2=") + sysout(sys2); + cmd = "sysp = parallel(sys1,sys2);"; + run_cmd + disp("sysp=") + sysout(sysp); + prompt + disp("parallel can be used for multiple input systems as well:") + + in1 = list("u1.1","u1.2"); + in2 = list("u2.1","u2.2"); + out1 = list("y1.1","y1.2"); + out2 = list("y2.1","y2.2"); + + sys1 = ss2sys([-1, 0; 0, -2],eye(2),eye(2),[]); + sys2 = ss2sys([-2, 0; 0, -4],eye(2),eye(2),[]); + + sys1 = syssetsignals(sys1,"in",in1); + sys1 = syssetsignals(sys1,"out",out1); + + sys2 = syssetsignals(sys2,"in",in2); + sys2 = syssetsignals(sys2,"out",out2); + + disp("sys1=") + sysout(sys1); + disp("sys2=") + sysout(sys2); + cmd = "sysp = parallel(sys1,sys2);"; + run_cmd + disp("sysp=") + sysout(sysp); + prompt + elseif (k == 12) + ## buildssic description + disp(" ") + disp(" ---------------------------------------") + disp(" b u i l d s s i c") + disp(" (BUILD State Space InterConnections)") + disp(" ---------------------------------------") + disp(" ") + disp("buildssic builds a single system from up to 8 systems.") + disp("It's primary pupose is the forming of interconnections") + disp("for H2/H_inf designs and the building of closed loop") + disp("systems.") + disp("The interconnections may be of arbitrary complexity.") + disp("The use of buildssic is an alternative to sysgroup,") + disp("sysadd/syssub, sysappend, sysconnect, sysdup, sysmult") + disp("sysprune, sysscale, parallel etc.") + disp("In contrast to these functions buildssic does not") + disp("handle mixed continuous and discrete systems. However,") + disp("discrete systems can be connected as long as their") + disp("sampling times are identical. Another drawback: the") + disp("names of input/output and state variables are clobbered.") + disp("Of course, buildsysic is useful in combination with sysgroup,") + disp("sysmult etc.") + prompt + disp("********* N O T E *********") + disp("buildssic is demonstrated in the design examples (option 13)"); + prompt + elseif (k == 13) + disp("Design examples") + disp("Packed system matrices may be connected and manipulated") + disp("With the functions listed below:") + disp(" sysdup: duplicate selected inputs/outputs") + disp(" sysconnect: connect selected inputs/outputs") + disp(" sysgroup: group two systems together") + disp(" sysprune: prune a system to keep only selected inputs and outputs") + disp(" sysscale:pre/post multiply a system by constant matrices") + disp(" buildssic: connect systems with arbitrary complexity.") + prompt + disp("As a simple example, we will construct the system block ") + disp("diagram shown below ") + disp(" ") + disp(" + -------- --------"); + disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); + disp(" -^ -------- -------- |"); + disp(" | |"); + disp(" ------------------------------"); + disp(" ") + disp("where P(s) is the plant, K(s) is the controller.") + prompt + disp("Simple example: P(s) is a first order lag, K(s) is a PI ") + disp("controller") + nump = 1; + denp = [1, 1]; + disp("P(s)=") + tfout(nump,denp) + numk = [1, 1]; + denk = [1, 0]; + disp("\nK(s)=") + tfout(numk,denk); + prompt + disp("We'll show three approaches. ") + P = tf2sys(nump,denp,0,"plant input","plant output"); + K = tf2sys(numk, denk,0,"controller input","controller output"); + + meth = 0; + while(meth != 5) + disp("The first method consists of the following steps:") + disp(" step 1: create systems P and K") + disp(" step 2: group P and K together") + disp(" step 3: create a summing junction") + disp(" step 4: connect outputs to respective inputs") + disp(" step 5: prune the desired i/o connections") + disp("The second method is done as follows:") + disp(" step 1: create systems P and K and a summing block S") + disp(" step 2: connect P, K, and S in series") + disp(" step 3: connect y to inverted summing connection") + disp(" step 4: prune the desired i/o connections") + disp("The third method uses buildssic:") + disp(" step 1: GW = buildssic(...,K,P)") + disp(" ") + disp("Other design examples are in dgkfdemo (controldemo option 7)") + disp(" ") + meth = menu("Select design example method", ... + "Method 1 ", ... + "Method 1 (w/o algebraic loop warning)", ... + "Method 2", ... + "Method 3", ... + "Exit design examples"); + if(meth == 1) + disp(" * * * Method 1 * * *") + disp(" ") + disp(" + -------- --------"); + disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); + disp(" -^ -------- -------- |"); + disp(" | |"); + disp(" ------------------------------"); + disp(" ") + disp("Step 1: put plants in system format:"); + nump + denp + cmd = "P = tf2sys(nump,denp,0,""plant input"",""plant output"");"; + run_cmd + disp("P=") + sysout(P) + prompt + numk + denk + cmd = "K = tf2sys(numk, denk,0,""controller input"",""controller output"");"; + run_cmd + sysout(K) + prompt + disp("Step 2: group the systems together") + cmd = "PK = sysgroup(P,K);"; + run_cmd + disp("PK=") + sysout(PK); + prompt + disp(" ") + disp(" y2 u1") + disp(" + -------- --------"); + disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); + disp(" u2 -^ -------- -------- | y1"); + disp(" u3 | |"); + disp(" --------------------------------"); + disp(" ") + disp("The controller has two inputs summed together, r(t)") + disp("and the negative feedback of y(t)") + disp("Step 3a: duplicate controller input: (input 2 of PK)") + prompt + cmd = "PK = sysdup(PK,[],2);"; + run_cmd + disp("PK=") + sysout(PK); + disp("Notice that PK now has three inputs (input 3 is a duplicate "); + prompt("of input 2). Press return to go on") + disp("Step 3b: scale input 3 by -1") + cmd = "PK = sysscale(PK,[],diag([1, 1, -1]));"; + run_cmd + disp("PK=") + sysout(PK); + prompt + disp("Step 4: connect:") + disp(" y(t) (output 1) to the negative sum junction (input 3)") + disp(" u(t) (output 2) to plant input (input 1)") + disp("and prune extraneous inputs/outputs (retain input 2, output 1)") + prompt + out_connect = [1, 2] + in_connect = [3, 1] + cmd = "PK0 = sysconnect(PK,out_connect,in_connect);"; + run_cmd + prompt + disp("Notice that sysconnect detects the possibility of algebraic") + disp("connections when connecting inputs. Option 2 (Method 1 ") + disp("without algebraic loops) shows how to avoid this warning") + disp("by performing connections one at a time.") + prompt + disp("PK0=") + sysout(PK0); + disp("Notice that the connected inputs now have stars on their") + disp("names. This is how the Octave controls toolbox reminds you") + disp("that the loop has been closed around these inputs.") + prompt("Press return to prune extra inputs/outputs from system") + disp("Only keep plant output (output 1) and r(t) (input 2)") + cmd = "PK0 = sysprune(PK0,1,2);"; + run_cmd + disp("PK0=") + sysout(PK0); + prompt + disp("The resulting closed-loop transfer function is obtained as follows:") + cmd = "[num,den] = sys2tf(PK0);"; + run_cmd + prompt + disp("Transfer function is now") + tfout(num,den) + disp("You can check this: Pk0=PK/(1+PK), as expected") + prompt + elseif(meth == 2) + disp("Method 1 without algebraic loops") + disp(" ") + disp(" y2 u1") + disp(" + -------- --------"); + disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); + disp(" u2 -^ -------- -------- | y1"); + disp(" u3 | |"); + disp(" --------------------------------"); + disp(" ") + disp("Recall that sysconnect checks for algebraic loops. Although") + disp("Design option 1 gets a warning message about a possible"); + disp("algebraic loop, such a loop does not exist.") + disp("This can be seen by performing the connections one at a time"); + cmd = "PK = sysgroup(P,K);"; + run_cmd + disp("PK=") + sysout(PK); + disp("Create an additial inverted input to the controller.") + cmd = "PK = sysdup(PK,[],2);"; + run_cmd + cmd = "PK = sysscale(PK,[],diag([1,1,-1]));"; + run_cmd + disp("PK=") + sysout(PK); + disp("Connect controller to plant:") + cmd = "PK0 = sysconnect(PK,2,1);"; + run_cmd + disp("Plant output to negative control input") + cmd = "PK0 = sysconnect(PK0,1,3);"; + run_cmd + disp("Only keep plant output (output 1) and r(t) (input 2)") + cmd = "PK0 = sysprune(PK0,1,2);"; + run_cmd + disp("PK0=") + sysout(PK0); + prompt + disp("The transfer function form of PK0 is:") + sysout(PK0,"tf"); + prompt + elseif(meth == 3) + disp(" * * * Method 2 * * *") + disp(" ") + disp(" + -------- --------"); + disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); + disp(" -^ -------- -------- |"); + disp(" | |"); + disp(" ------------------------------"); + disp(" ") + disp("Step 1: We've already created systems P and K. Create a sum ") + disp("block as follows:") + cmd = "S = ss2sys([],[],[],[1, -1],0,0,0,[],list(""r(t)"",""y(t)""),""e(t)"");"; + run_cmd + disp("(You may wish to look at help ss2sys to see what the above does)"); + disp("S=") + sysout(S) + disp("notice that this is just a gain block that outputs e = r - y") + prompt + disp("Step 2: series connections of P, K, and S") + cmd = "PKS = sysmult(P,sysmult(K,S));"; + run_cmd + disp("PKS=") + sysout(PKS) + disp("Step 3: connect y to inverted input") + cmd = "PKcl = sysconnect(PKS,1,2);"; + run_cmd + disp("PKcl=") + sysout(PKcl) + disp("Step 4: prune desired inputs/outputs") + cmd = "PKcl=sysprune(PKcl,1,1);"; + run_cmd + disp("PKcl=") + sysout(PKcl) + prompt + elseif(meth == 4) + disp(" * * * Method 3 * * *") + disp(" ") + disp(" + -------- --------"); + disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); + disp(" -^ -------- -------- |"); + disp(" | |"); + disp(" ------------------------------"); + disp(" ") + disp("Step 1: We've already created systems P and K.") + disp(" Let us call buildssic:") + disp(" PKcl = buildssic([1, 2; 2, -1],[],[1],[2],P,K)") + disp(" ") + disp(" ^ ^ ^ ^ ^ ^") + disp(" | | | | | |") + disp(" Connection list ----+ | | | | |") + disp(" internal input list -----------+ | | | +-- controller") + disp(" output list --------------+ | |") + disp(" input list ------------------+ +---- plant") + disp(" ") + disp(" Connection list: connect input 1 (P) with output 2 (K)") + disp(" connect input 2 (K) with neg. outp. 1 (P)") + disp(" ") + disp(" int. inp. list: do not append internal inputs") + disp(" (e.g. the internal input of K (r-y))") + disp(" ") + disp(" output list: the only output is 1 (P), positive") + disp(" ") + disp(" input list: the only input is 2 (K), positive") + disp(" ") + cmd = "PKcl = buildssic([1, 2; 2, -1],[],[1],[2],P,K);" + run_cmd + sysout(PKcl) + prompt + disp("The transfer function form of PKcl is:") + sysout(PKcl,"tf"); + disp("You can check this: PKcl = PK / (1 + PK), as expected") + prompt + elseif(meth != 5) + disp("invalid selection") + endif + endwhile + + elseif (k == 14) + return + endif + endwhile + implict_str_to_num_ok = str_sav; + page_screen_output = sav_page; +endfunction diff --git a/scripts/control/base/bode.m b/scripts/control/base/bode.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/bode.m @@ -0,0 +1,212 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{mag}, @var{phase}, @var{w}] =} bode(@var{sys}@{,@var{w}, @var{out_idx}, @var{in_idx}@}) +## If no output arguments are given: produce Bode plots of a system; otherwise, +## compute the frequency response of a system data structure +## +## @strong{Inputs} +## @table @var +## @item sys +## a system data structure (must be either purely continuous or discrete; +## see is_digital) +## @item w +## frequency values for evaluation. +## +## if @var{sys} is continuous, then bode evaluates @math{G(jw)} where +## @math{G(s)} is the system transfer function. +## +## if @var{sys} is discrete, then bode evaluates G(@code{exp}(jwT)), where +## @itemize @bullet +## @item @var{T}=@code{sysgettsam(@var{sys})} (the system sampling time) and +## @item @math{G(z)} is the system transfer function. +## @end itemize +## +## @strong{ Default} the default frequency range is selected as follows: (These +## steps are NOT performed if @var{w} is specified) +## @enumerate +## @item via routine bodquist, isolate all poles and zeros away from +## @var{w}=0 (@var{jw}=0 or @math{@code{exp}(jwT)}=1) and select the frequency +## range based on the breakpoint locations of the frequencies. +## @item if @var{sys} is discrete time, the frequency range is limited +## to @math{jwT} in +## @ifinfo +## [0,2 pi /T] +## @end ifinfo +## @iftex +## @tex +## $[0,2\pi/T]$ +## @end tex +## @end iftex +## @item A "smoothing" routine is used to ensure that the plot phase does +## not change excessively from point to point and that singular +## points (e.g., crossovers from +/- 180) are accurately shown. +## +## @end enumerate +## @item out_idx +## @itemx in_idx +## the indices of the output(s) and input(s) to be used in +## the frequency response; see @code{sysprune}. +## @end table +## @strong{Outputs} +## @table @var +## @item mag +## @itemx phase +## the magnitude and phase of the frequency response @math{G(jw)} or +## @math{G(@code{exp}(jwT))} at the selected frequency values. +## @item w +## the vector of frequency values used +## @end table +## +## @strong{Notes} +## @enumerate +## @item If no output arguments are given, e.g., +## @example +## bode(sys); +## @end example +## bode plots the results to the screen. Descriptive labels are +## automatically placed. +## +## Failure to include a concluding semicolon will yield some garbage +## being printed to the screen (@code{ans = []}). +## +## @item If the requested plot is for an MIMO system, mag is set to +## @math{||G(jw)||} or @math{||G(@code{exp}(jwT))||} +## and phase information is not computed. +## @end enumerate +## @end deftypefn + +## Author: John Ingram +## Created: July 10, 1996 +## Based on previous code by R. Bruce Tenison, July 13, 1994 +## Modified by David Clem November 13, 1994 +## again by A. S. Hodel July 1995 (smart plot range, etc.) +## Modified by Kai P. Mueller September 28, 1997 (multiplot mode) + +function [mag_r, phase_r, w_r] = bode (sys, w, outputs, inputs, plot_style) + + ## check number of input arguments given + if (nargin < 1 | nargin > 5) + usage("[mag,phase,w] = bode(sys[,w,outputs,inputs,plot_style])"); + endif + if(nargin < 2) + w = []; + endif + if(nargin < 3) + outputs = []; + endif + if(nargin < 4) + inputs = []; + endif + if(nargin < 5) + plot_style = "dB"; + endif + + if (strcmp (plot_style, "dB")) + do_db_plot = 1; + elseif (strcmp (plot_style, "mag")) + do_db_plot = 0; + else + error ("bode: invalid value of plot_style specified"); + endif + + [f, w] = bodquist(sys,w,outputs,inputs,"bode"); + + [stname,inname,outname] = sysgetsignals(sys); + systsam = sysgettsam(sys); + + ## Get the magnitude and phase of f. + mag = abs(f); + phase = arg(f)*180.0/pi; + + if (nargout < 1), + ## Plot the information + if(gnuplot_has_multiplot) + oneplot(); + endif + gset autoscale; + if(gnuplot_has_multiplot) + gset nokey; + endif + clearplot(); + gset data style lines; + if(is_digital(sys)) + xlstr = ["Digital frequency w=rad/sec. pi/T=",num2str(pi/systsam)]; + tistr = "(exp(jwT)) "; + else + xlstr = "Frequency in rad/sec"; + tistr = "(jw)"; + endif + xlabel(xlstr); + if(is_siso(sys)) + if (gnuplot_has_multiplot) + subplot(2,1,1); + endif + title(["|[Y/U]",tistr,"|, u=", nth(inname,1),", y=",nth(outname,1)]); + else + title([ "||Y(", tistr, ")/U(", tistr, ")||"]); + disp("MIMO plot from") + disp(outlist(inname," ")); + disp("to") + disp(outlist(outname," ")); + endif + wv = [min(w), max(w)]; + if(do_db_plot && max(mag) > 0) + ylabel("Gain in dB"); + md = 20*log10(mag); + axvec = axis2dlim([vec(w),vec(md)]); + axvec(1:2) = wv; + axis(axvec); + else + ylabel("Gain |Y/U|") + md = mag; + endif + + grid("on"); + if (do_db_plot) + semilogx(w,md); + else + loglog(w,md); + endif + if (is_siso(sys)) + if (gnuplot_has_multiplot) + subplot(2,1,2); + else + prompt("Press any key for phase plot"); + endif + axvec = axis2dlim([vec(w),vec(phase)]); + axvec(1:2) = wv; + axis(axvec); + xlabel(xlstr); + ylabel("Phase in deg"); + title([ "phase([Y/U]", tistr, ... + "), u=", nth(inname,1),", y=",nth(outname,1)]); + grid("on"); + semilogx(w,phase); + ## This should be the default for subsequent plot commands. + if(gnuplot_has_multiplot) + oneplot(); + endif + endif + else + mag_r = mag; + phase_r = phase; + w_r = w; + endif +endfunction diff --git a/scripts/control/base/bode_bounds.m b/scripts/control/base/bode_bounds.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/bode_bounds.m @@ -0,0 +1,74 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{wmin}, @var{wmax}] =} bode_bounds (@var{zer}, @var{pol}, @var{dflg}@{, @var{tsam} @}) +## Get default range of frequencies based on cutoff frequencies of system +## poles and zeros. +## Frequency range is the interval [10^wmin,10^wmax] +## +## Used internally in freqresp (@code{bode}, @code{nyquist}) +## @end deftypefn + +function [wmin, wmax] = bode_bounds (zer, pol, DIGITAL, tsam) + + ## make sure zer,pol are row vectors + if(!isempty(pol)) pol = reshape(pol,1,length(pol)); endif + if(!isempty(zer)) zer = reshape(zer,1,length(zer)); endif + + ## check for natural frequencies away from omega = 0 + if (DIGITAL) + ## The 2nd conditions prevents log(0) in the next log command + iiz = find(abs(zer - 1) > norm(zer) * eps && abs(zer) > norm(zer) * eps); + iip = find(abs(pol - 1) > norm(pol) * eps && abs(pol) > norm(pol) * eps); + + ## avoid dividing empty matrices, it would work but looks nasty + if (!isempty(iiz)) czer = log(zer(iiz))/tsam; + else czer = []; endif + + if (!isempty(iip)) cpol = log(pol(iip))/tsam; + else cpol = []; endif + + else + ## continuous + iip = find((abs(pol)) > (norm(pol) * eps)); + iiz = find((abs(zer)) > (norm(zer) * eps)); + + if(!isempty(zer)) czer = zer(iiz); + else czer = []; endif + if(!isempty(pol)) cpol = pol(iip); + else cpol = []; endif + endif + + if(max(size(iip)) + max(size(iiz)) ) + wmin = floor(log10(min(abs([cpol,czer])))); + wmax = ceil(log10(max(abs([cpol,czer])))); + else + ## no poles/zeros away from omega = 0; pick defaults + wmin = -1; + wmax = 3; + endif + + ## expand to show the entirety of the "interesting" portion of the plot + wmin--; + wmax++; + + ## run digital frequency all the way to pi + if (DIGITAL) wmax = log10(pi/tsam); endif + +endfunction diff --git a/scripts/control/base/bodquist.m b/scripts/control/base/bodquist.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/bodquist.m @@ -0,0 +1,156 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{f}, @var{w}] =} bodquist (@var{sys}, @var{w}, @var{out_idx}, @var{in_idx}) +## used internally by bode, nyquist; compute system frequency response. +## +## @strong{Inputs} +## @table @var +## @item sys +## input system structure +## @item w +## range of frequencies; empty if user wants default +## @item out_idx +## list of outputs; empty if user wants all +## @item in_idx +## list of inputs; empty if user wants all +## @item rname +## name of routine that called bodquist ("bode" or "nyquist") +## @end table +## @strong{Outputs} +## @table @var +## @item w +## list of frequencies +## @item f +## frequency response of sys; @math{f(ii) = f(omega(ii))} +## @end table +## @strong{Note} bodquist could easily be incorporated into a Nichols +## plot function; this is in a "to do" list. +## +## Both bode and nyquist share the same introduction, so the common parts are +## in bodquist. It contains the part that finds the number of arguments, +## determines whether or not the system is SISO, and computes the frequency +## response. Only the way the response is plotted is different between the +## two functions. +## @end deftypefn + +function [f, w] = bodquist (sys, w, outputs, inputs, rname) + + ## check number of input arguments given + if (nargin != 5) + usage("[f,w] = bodquist(sys,w,outputs,inputs,rname)"); + endif + + ## check each argument to see if it's in the correct form + if (!is_struct(sys)) + error("sys must be a system data structure"); + endif + + ## let freqresp determine w if it's not already given + USEW = freqchkw(w); + + ## get initial dimensions (revised below if sysprune is called) + [nn,nz,mm,pp ] = sysdimensions(sys); + + ## check for an output vector and to see whether it`s correct + if (!isempty(outputs)) + if (isempty(inputs)) + inputs = 1:mm; # use all inputs + warning([rname,": outputs specified but not inputs"]); + endif + sys = sysprune(sys,outputs,inputs); + [nn,nz,mm,pp ] = sysdimensions(sys); + endif + + ## for speed in computation, convert local copy of + ## SISO state space systems to zero-pole form + if( is_siso(sys) & strcmp( sysgettype(sys), "ss") ) + [zer,pol,k,tsam,inname,outname] = sys2zp(sys); + sys = zp2sys(zer,pol,k,tsam,inname,outname); + endif + + ## get system frequency response + [f,w] = freqresp(sys,USEW,w); + + phase = arg(f)*180.0/pi; + + if(!USEW) + ## smooth plots + pcnt = 5; # max number of refinement steps + dphase = 5; # desired max change in phase + dmag = 0.2; # desired max change in magnitude + while(pcnt) + pd = abs(diff(phase)); # phase variation + pdbig = vec(find(pd > dphase)); + + lp = length(f); lp1 = lp-1; # relative variation + fd = abs(diff(f)); + fm = max(abs([f(1:lp1); f(2:lp)])); + fdbig = vec(find(fd > fm/10)); + + bigpts = union(fdbig, pdbig); + + if(isempty(bigpts) ) + pcnt = 0; + else + pcnt = pcnt - 1; + wnew = []; + crossover_points = find ( phase(1:lp1).*phase(2:lp) < 0); + pd(crossover_points) = abs(359.99+dphase - pd(crossover_points)); + np_pts = max(3,ceil(pd/dphase)+2); # phase points + nm_pts = max(3,ceil(log(fd./fm)/log(dmag))+2); # magnitude points + npts = min(5,max(np_pts, nm_pts)); + + w1 = log10(w(1:lp1)); + w2 = log10(w(2:lp)); + for ii=bigpts + if(npts(ii)) + wtmp = logspace(w1(ii),w2(ii),npts(ii)); + wseg(ii,1:(npts(ii)-2)) = wtmp(2:(npts(ii)-1)); + endif + endfor + wnew = vec(wseg)'; # make a row vector + wnew = wnew(find(wnew != 0)); + wnew = sort(wnew); + wnew = create_set(wnew); + if(isempty(wnew)) # all small crossovers + pcnt = 0; + else + [fnew,wnew] = freqresp(sys,1,wnew); # get new freq resp points + w = [w,wnew]; # combine with old freq resp + f = [f,fnew]; + [w,idx] = sort(w); # sort into order + f = f(idx); + phase = arg(f)*180.0/pi; + endif + endif + endwhile + endif + + ## ensure unique frequency values + [w,idx] = sort(w); + f = f(idx); + + w_diff = diff(w); + w_dup = find(w_diff == 0); + w_idx = complement(w_dup,1:length(w)); + w = w(w_idx); + f = f(w_idx); + +endfunction diff --git a/scripts/control/base/controldemo.m b/scripts/control/base/controldemo.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/controldemo.m @@ -0,0 +1,30 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} controldemo () +## Controls toolbox demo. +## @end deftypefn +## @seealso{Demo programs: bddemo, frdemo, analdemo, moddmeo, rldemo} + +## Author: David Clem +## Created: August 15, 1994 + +function controldemo () + DEMOcontrol (); +endfunction diff --git a/scripts/control/base/dare.m b/scripts/control/base/dare.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/dare.m @@ -0,0 +1,122 @@ +## Copyright (C) 1996, 1997 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place - Suite 330, Boston, MA +## 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} dare (@var{a}, @var{b}, @var{c}, @var{r}, @var{opt}) +## +## Return the solution, @var{x} of the discrete-time algebraic Riccati +## equation +## @iftex +## @tex +## $$ +## A^TXA - X + A^TXB (R + B^TXB)^{-1} B^TXA + C = 0 +## $$ +## @end tex +## @end iftex +## @ifinfo +## @example +## a' x a - x + a' x b (r + b' x b)^(-1) b' x a + c = 0 +## @end example +## @end ifinfo +## @noindent +## +## @strong{Inputs} +## @table @var +## @item a +## @var{n} by @var{n}. +## +## @item b +## @var{n} by @var{m}. +## +## @item c +## @var{n} by @var{n}, symmetric positive semidefinite, or @var{p} by @var{n}. +## In the latter case @math{c:=c'*c} is used. +## +## @item r +## @var{m} by @var{m}, symmetric positive definite (invertible). +## +## @item opt +## (optional argument; default = @code{"B"}): +## String option passed to @code{balance} prior to ordered @var{QZ} decomposition. +## @end table +## +## @strong{Outputs} +## @var{x} solution of DARE. +## +## @strong{Method} +## Generalized eigenvalue approach (Van Dooren; SIAM J. +## Sci. Stat. Comput., Vol 2) applied to the appropriate symplectic pencil. +## +## See also: Ran and Rodman, "Stable Hermitian Solutions of Discrete +## Algebraic Riccati Equations," Mathematics of Control, Signals and +## Systems, Vol 5, no 2 (1992) pp 165-194. +## +## @end deftypefn +## @seealso{balance and are} + +## Author: A. S. Hodel +## Created: August 1993 +## Adapted-By: jwe + +function x = dare (a, b, c, r, opt) + + if (nargin == 4 | nargin == 5) + if (nargin == 5) + if (opt != "N" || opt != "P" || opt != "S" || opt != "B") + warning ("dare: opt has an invalid value -- setting to B"); + opt = "B"; + endif + else + opt = "B"; + endif + + ## dimension checks are done in is_controllable, is_observable + if (is_controllable (a, b) == 0) + warning ("dare: a,b are not controllable"); + elseif (is_observable (a, c) == 0) + warning ("dare: a,c are not observable"); + endif + + if ((p = is_square (c)) == 0) + c = c'*c; + p = rows (c); + endif + + ## Check r dimensions. + n = rows(a); + m = columns(b); + if ((m1 = is_square (r)) == 0) + warning ("dare: r is not square"); + elseif (m1 != m) + warning ("b,r are not conformable"); + endif + + s1 = [a, zeros(n) ; -c, eye(n)]; + s2 = [eye(n), (b/r)*b' ; zeros(n), a']; + [c,d,s1,s2] = balance(s1,s2,opt); + [aa,bb,u,lam] = qz(s1,s2,"S"); + u = d*u; + n1 = n+1; + n2 = 2*n; + x = u (n1:n2, 1:n)/u(1:n, 1:n); + else + usage ("x = dare (a, b, c, r {,opt})"); + endif + +endfunction diff --git a/scripts/control/base/dgkfdemo.m b/scripts/control/base/dgkfdemo.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/dgkfdemo.m @@ -0,0 +1,354 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} dgkfdemo () +## Octave Controls toolbox demo: H2/Hinfinity options demos +## @end deftypefn + +## Author: A. S. Hodel +## Created: June 1995 + +function dgkfdemo () + + save_val = page_screen_output; + page_screen_output = 1; + while (1) + clc + sel = 0; + while (sel > 10 || sel < 1) + sel = menu ("Octave H2/Hinfinity options demo", + "LQ regulator", + "LG state estimator", + "LQG optimal control design", + "H2 gain of a system", + "H2 optimal controller of a system", + "Hinf gain of a system", + "Hinf optimal controller of a SISO system", + "Hinf optimal controller of a MIMO system", + "Discrete-time Hinf optimal control by bilinear transform", + "Return to main demo menu"); + endwhile + if (sel == 1) + disp("Linear/Quadratic regulator design:") + disp("Compute optimal state feedback via the lqr command...") + help lqr + disp(" ") + disp("Example:") + A = [0, 1; -2, -1] + B = [0; 1] + Q = [1, 0; 0, 0] + R = 1 + disp("Q = state penalty matrix; R = input penalty matrix") + prompt + disp("Compute state feedback gain k, ARE solution P, and closed-loop") + disp("poles as follows:"); + cmd = "[k, p, e] = lqr(A,B,Q,R)"; + run_cmd + prompt + disp("A similar approach can be used for LTI discrete-time systems") + disp("by using the dlqr command in place of lqr (see LQG example).") + elseif (sel == 2) + disp("Linear/Gaussian estimator design:") + disp("Compute optimal state estimator via the lqe command...") + help lqe + disp(" ") + disp("Example:") + A = [0, 1; -2, -1] + disp("disturbance entry matrix G") + G = eye(2) + disp("Output measurement matrix C") + C = [0, 1] + SigW = [1, 0; 0, 1] + SigV = 1 + disp("SigW = input disturbance intensity matrix;") + disp("SigV = measurement noise intensity matrix") + prompt + disp("Compute estimator feedback gain k, ARE solution P, and estimator") + disp("poles via the command: ") + cmd = "[k, p, e] = lqe(A,G,C,SigW,SigV)"; + run_cmd + disp("A similar approach can be used for LTI discrete-time systems") + disp("by using the dlqe command in place of lqe (see LQG example).") + elseif (sel == 3) + disp("LQG optimal controller of a system:") + disp("Input accepted as either A,B,C matrices or in system data structure form") + disp("in both discrete and continuous time.") + disp("Example 1: continuous time design:") + prompt + help lqg + disp("Example system") + A = [0, 1; .5, .5]; + B = [0; 2]; + G = eye(2) + C = [1, 1]; + sys = ss2sys(A, [B, G], C); + sys = syssetsignals(sys,"in", ... + ["control input"; "disturbance 1"; "disturbance 2"]); + sysout(sys) + prompt + disp("Filtering/estimator parameters:") + SigW = eye(2) + SigV = 1 + prompt + disp("State space (LQR) parameters Q and R are:") + Q = eye(2) + R = 1 + cmd = "[K,Q1,P1,Ee,Er] = lqg(sys,SigW,SigV,Q,R,1);"; + run_cmd + disp("Check: closed loop system A-matrix is") + disp(" [A, B*Cc]") + disp(" [Bc*C, Ac ]") + cmd = "[Ac, Bc, Cc] = sys2ss(K);"; + run_cmd + cmd = "Acl = [A, B*Cc; Bc*C, Ac]"; + run_cmd + disp("Check: poles of Acl:") + Acl_poles = sortcom(eig(Acl)) + disp("Predicted poles from design = union(Er,Ee)") + cmd = "pred_poles = sortcom([Er; Ee])"; + run_cmd + disp("Example 2: discrete-time example") + cmd1 = "Dsys = ss2sys(A, [G, B], C, [0, 0, 0], 1);"; + cmd2 = "[K,Q1,P1,Ee,Er] = lqg(Dsys,SigW, SigV,Q,R);"; + disp("Run commands:") + cmd = cmd1; + run_cmd + cmd = cmd2; + run_cmd + prompt + disp("Check: closed loop system A-matrix is") + disp(" [A, B*Cc]") + disp(" [Bc*C, Ac ]") + [Ac,Bc,Cc] = sys2ss(K); + Acl = [A, B*Cc; Bc*C, Ac] + prompt + disp("Check: poles of Acl:") + Acl_poles = sortcom(eig(Acl)) + disp("Predicted poles from design = union(Er,Ee)") + pred_poles = sortcom([Er;Ee]) + elseif (sel == 4) + disp("H2 gain of a system: (Energy in impulse response)") + disp("Example 1: Stable plant:") + cmd = "A = [0, 1; -2, -1]; B = [0; 1]; C = [1, 0]; sys_poles = eig(A)"; + run_cmd + disp("Put into Packed system form:") + cmd = "Asys = ss2sys(A,B,C);"; + run_cmd + disp("Evaluate system 2-norm (impulse response energy):"); + cmd = "AsysH2 = h2norm(Asys)"; + run_cmd + disp("Compare with a plot of the system impulse response:") + tt = 0:0.1:20; + for ii=1:length(tt) + ht(ii) = C*expm(A*tt(ii))*B; + endfor + plot(tt,ht) + title("impulse response of example plant") + prompt + disp("Example 2: unstable plant") + cmd = "A = [0, 1; 2, 1]"; + eval(cmd); + cmd = "B = [0; 1]"; + eval(cmd); + cmd = "C = [1, 0]"; + eval(cmd); + cmd = "sys_poles = eig(A)"; + run_cmd + prompt + disp("Put into system data structure form:") + cmd="Bsys = ss2sys(A,B,C);"; + run_cmd + disp("Evaluate 2-norm:") + cmd = "BsysH2 = h2norm(Bsys)"; + run_cmd + disp(" ") + prompt("NOTICE: program returns a value without an error signal.") + disp("") + + elseif (sel == 5) + disp("H2 optimal controller of a system: command = h2syn:") + prompt + help h2syn + prompt + disp("Example system: double integrator with output noise and") + disp("input disturbance:") + disp(" "); + disp(" -------------------->y2"); + disp(" | _________"); + disp("u(t)-->o-->| 1/s^2 |-->o-> y1"); + disp(" ^ --------- ^"); + disp(" | |"); + disp(" w1(t) w2(t)"); + disp(" ") + disp("w enters the system through B1, u through B2") + disp("z = [y1; y2] is obtained through C1, y=y1 through C2"); + disp(" ") + cmd = "A = [0, 1; 0, 0]; B1 = [0, 0; 1, 0]; B2 = [0; 1];"; + disp(cmd) + eval(cmd); + cmd = "C1 = [1, 0; 0, 0]; C2 = [1, 0]; D11 = zeros(2);"; + disp(cmd) + eval(cmd); + cmd = "D12 = [0; 1]; D21 = [0, 1]; D22 = 0; D = [D11, D12; D21, D22];"; + disp(cmd) + eval(cmd); + disp("Design objective: compute U(s)=K(s)Y1(s) to minimize the closed") + disp("loop impulse response from w(t) =[w1; w2] to z(t) = [y1; y2]"); + prompt + disp("First: pack system:") + cmd="Asys = ss2sys(A, [B1, B2], [C1; C2], D);"; + run_cmd + disp("Open loop multivariable Bode plot: (will take a moment)") + cmd="bode(Asys);"; + run_cmd + prompt("Press a key to close plot and continue"); + closeplot + disp("Controller design command: (only need 1st two output arguments)") + cmd="[K,gain, Kc, Kf, Pc, Pf] = h2syn(Asys,1,1);"; + run_cmd + disp("Controller is:") + cmd = "sysout(K)"; + run_cmd + disp(["returned gain value is: ",num2str(gain)]); + disp("Check: close the loop and then compute h2norm:") + prompt + cmd="K_loop = sysgroup(Asys,K);"; + run_cmd + cmd = "Kcl = sysconnect(K_loop,[3,4],[4,3]);"; + run_cmd + cmd = "Kcl = sysprune(Kcl,[1,2],[1,2]);"; + run_cmd + cmd="gain_Kcl = h2norm(Kcl)"; + run_cmd + cmd="gain_err = gain_Kcl - gain"; + run_cmd + disp("Check: multivarible bode plot:") + cmd="bode(Kcl);"; + run_cmd + prompt + disp("Related functions: is_dgkf, is_controllable, is_stabilizable,") + disp(" is_observable, is_detectable") + elseif (sel == 6) + disp("Hinfinity gain of a system: (max gain over all j-omega)") + disp("Example 1: Stable plant:") + cmd = "A = [0, 1; -2, -1]; B = [0; 1]; C = [1, 0]; sys_poles = eig(A)"; + run_cmd + disp("Pack into system format:") + cmd = "Asys = ss2sys(A,B,C);"; + run_cmd + disp("The infinity norm must be computed iteratively by") + disp("binary search. For this example, we select tolerance tol = 0.01, ") + disp("min gain gmin = 1e-2, max gain gmax=1e4.") + disp("Search quits when upper bound <= (1+tol)*lower bound.") + cmd = "tol = 0.01; gmin = 1e-2; gmax = 1e+4;"; + run_cmd + cmd = "[AsysHinf,gmin,gmax] = hinfnorm(Asys,tol,gmin,gmax)" + run_cmd + disp("Check: look at max value of magntude Bode plot of Asys:"); + [M,P,w] = bode(Asys); + xlabel("Omega") + ylabel("|Asys(j omega)| ") + grid(); + semilogx(w,M); + disp(["Max magnitude is ",num2str(max(M)), ... + ", compared with gmin=",num2str(gmin)," and gmax=", ... + num2str(gmax),"."]) + prompt + disp("Example 2: unstable plant") + cmd = "A = [0, 1; 2, 1]; B = [0; 1]; C = [1, 0]; sys_poles = eig(A)"; + run_cmd + disp("Pack into system format:") + cmd = "Bsys = ss2sys(A,B,C);"; + run_cmd + disp("Evaluate with BsysH2 = hinfnorm(Bsys,tol,gmin,gmax)") + BsysH2 = hinfnorm(Bsys,tol,gmin,gmax) + disp(" ") + disp("NOTICE: program returns a value without an error signal.") + disp("") + + elseif (sel == 7) + disp("Hinfinity optimal controller of a system: command = hinfsyn:") + prompt + help hinfsyn + prompt + disp("Example system: double integrator with output noise and") + disp("input disturbance:") + A = [0, 1; 0, 0] + B1 = [0, 0; 1, 0] + B2 = [0; 1] + C1 = [1, 0; 0, 0] + C2 = [1, 0] + D11 = zeros(2); + D12 = [0; 1]; + D21 = [0, 1]; + D22 = 0; + D = [D11, D12; D21, D22] + prompt + disp("First: pack system:") + cmd="Asys = ss2sys(A, [B1, B2], [C1; C2], D);"; + run_cmd + prompt + disp("Open loop multivariable Bode plot: (will take a moment)") + cmd="bode(Asys);"; + run_cmd + prompt + disp("Controller design command: (only need 1st two output arguments)") + gmax = 1000 + gmin = 0.1 + gtol = 0.01 + cmd="[K,gain] = hinfsyn(Asys,1,1,gmin,gmax,gtol);"; + run_cmd + disp("Check: close the loop and then compute h2norm:") + prompt + cmd="K_loop = sysgroup(Asys,K);"; + run_cmd + cmd = "Kcl = sysconnect(K_loop,[3,4],[4,3]);"; + run_cmd + cmd = "Kcl = sysprune(Kcl,[1,2],[1,2]);"; + run_cmd + cmd="gain_Kcl = hinfnorm(Kcl)"; + run_cmd + cmd="gain_err = gain_Kcl - gain"; + run_cmd + disp("Check: multivarible bode plot:") + cmd="bode(Kcl);"; + run_cmd + prompt + disp("Related functions: is_dgkf, is_controllable, is_stabilizable,") + disp(" is_observable, is_detectable, buildssic") + elseif (sel == 8) + disp("Hinfinity optimal controller of MIMO system: command = hinfsyn:") + prompt + help hinfsyn + prompt + disp("Example system: Boeing 707-321 airspeed/pitch angle control") + disp(" ") + hinfdemo + elseif (sel == 9) + disp("Discrete time H-infinity control via bilinear transform"); + prompt + dhinfdemo + elseif (sel == 10) + return + endif + prompt + endwhile + page_screen_output = save_val; + +endfunction diff --git a/scripts/control/base/dgram.m b/scripts/control/base/dgram.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/dgram.m @@ -0,0 +1,49 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{m} =} dgram (@var{a}, @var{b}) +## Return controllability grammian of discrete time system +## @example +## x(k+1) = a x(k) + b u(k) +## @end example +## +## @strong{Inputs} +## @table @var +## @item a +## @var{n} by @var{n} matrix +## @item b +## @var{n} by @var{m} matrix +## @end table +## +## @strong{Outputs} +## @var{m} (@var{n} by @var{n}) satisfies +## @example +## a m a' - m + b*b' = 0 +## @end example +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 1995 + +function m = dgram (a, b) + + ## let dlyap do the error checking... + m = dlyap(a,b*b'); + +endfunction diff --git a/scripts/control/base/dlqe.m b/scripts/control/base/dlqe.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/dlqe.m @@ -0,0 +1,125 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{l}, @var{m}, @var{p}, @var{e}] =} dlqe (@var{a}, @var{g}, @var{c}, @var{sigw}, @var{sigv}, @var{z}) +## Construct the linear quadratic estimator (Kalman filter) for the +## discrete time system +## @iftex +## @tex +## $$ +## x_{k+1} = A x_k + B u_k + G w_k +## $$ +## $$ +## y_k = C x_k + D u_k + w_k +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## x[k+1] = A x[k] + B u[k] + G w[k] +## y[k] = C x[k] + D u[k] + w[k] +## @end example +## +## @end ifinfo +## where @var{w}, @var{v} are zero-mean gaussian noise processes with +## respective intensities @code{@var{sigw} = cov (@var{w}, @var{w})} and +## @code{@var{sigv} = cov (@var{v}, @var{v})}. +## +## If specified, @var{z} is @code{cov (@var{w}, @var{v})}. Otherwise +## @code{cov (@var{w}, @var{v}) = 0}. +## +## The observer structure is +## @iftex +## @tex +## $$ +## z_{k+1} = A z_k + B u_k + k (y_k - C z_k - D u_k) +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## z[k+1] = A z[k] + B u[k] + k (y[k] - C z[k] - D u[k]) +## @end example +## @end ifinfo +## +## @noindent +## The following values are returned: +## +## @table @var +## @item l +## The observer gain, +## @iftex +## @tex +## $(A - ALC)$. +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{a}@var{l}@var{c}). +## @end ifinfo +## is stable. +## +## @item m +## The Riccati equation solution. +## +## @item p +## The estimate error covariance after the measurement update. +## +## @item e +## The closed loop poles of +## @iftex +## @tex +## $(A - ALC)$. +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{a}@var{l}@var{c}). +## @end ifinfo +## @end table +## @end deftypefn + +## Author: A. S. Hodel +## Created: August 1993 +## Modified for discrete time by R. Bruce Tenison (btenison@eng.auburn.edu) +## October, 1993 + +function [l, m, p, e] = dlqe (a, g, c, sigw, sigv, s) + + if (nargin != 5 && nargin != 6) + error ("dlqe: invalid number of arguments"); + endif + + ## The problem is dual to the regulator design, so transform to dlqr call. + + if (nargin == 5) + [k, p, e] = dlqr (a', c', g*sigw*g', sigv); + m = p; + l = k'; + else + [k, p, e] = dlqr (a', c', g*sigw*g', sigv, g*s); + m = p; + l = k'; + a = a-g*t/sigv*c; + sigw = sigw-t/sigv; + endif + + p = a\(m-g*sigw*g')/a'; + +endfunction diff --git a/scripts/control/base/dlqr.m b/scripts/control/base/dlqr.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/dlqr.m @@ -0,0 +1,166 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{k}, @var{p}, @var{e}] =} dlqr (@var{a}, @var{b}, @var{q}, @var{r}, @var{z}) +## Construct the linear quadratic regulator for the discrete time system +## @iftex +## @tex +## $$ +## x_{k+1} = A x_k + B u_k +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## x[k+1] = A x[k] + B u[k] +## @end example +## +## @end ifinfo +## to minimize the cost functional +## @iftex +## @tex +## $$ +## J = \sum x^T Q x + u^T R u +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## J = Sum (x' Q x + u' R u) +## @end example +## @end ifinfo +## +## @noindent +## @var{z} omitted or +## @iftex +## @tex +## $$ +## J = \sum x^T Q x + u^T R u + 2 x^T Z u +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## J = Sum (x' Q x + u' R u + 2 x' Z u) +## @end example +## +## @end ifinfo +## @var{z} included. +## +## The following values are returned: +## +## @table @var +## @item k +## The state feedback gain, +## @iftex +## @tex +## $(A - B K)$ +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{b}@var{k}) +## @end ifinfo +## is stable. +## +## @item p +## The solution of algebraic Riccati equation. +## +## @item e +## The closed loop poles of +## @iftex +## @tex +## $(A - B K)$. +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{b}@var{k}). +## @end ifinfo +## @end table +## @strong{References} +## @enumerate +## @item Anderson and Moore, Optimal Control: Linear Quadratic Methods, +## Prentice-Hall, 1990, pp. 56-58 +## @item Kuo, Digital Control Systems, Harcourt Brace Jovanovich, 1992, +## section 11-5-2. +## @end enumerate +## @end deftypefn + +## Author: A. S. Hodel +## Created: August 1993 +## Converted to discrete time by R. B. Tenison +## (btenison@eng.auburn.edu) October 1993 + +function [k, p, e] = dlqr (a, b, q, r, s) + + if (nargin != 4 && nargin != 5) + error ("dlqr: invalid number of arguments"); + endif + + ## Check a. + if ((n = is_square (a)) == 0) + error ("dlqr: requires 1st parameter(a) to be square"); + endif + + ## Check b. + [n1, m] = size (b); + if (n1 != n) + error ("dlqr: a,b not conformal"); + endif + + ## Check q. + if ((n1 = is_square (q)) == 0 || n1 != n) + error ("dlqr: q must be square and conformal with a"); + endif + + ## Check r. + if((m1 = is_square(r)) == 0 || m1 != m) + error ("dlqr: r must be square and conformal with column dimension of b"); + endif + + ## Check if n is there. + if (nargin == 5) + [n1, m1] = size (s); + if (n1 != n || m1 != m) + error ("dlqr: z must be identically dimensioned with b"); + endif + + ## Incorporate cross term into a and q. + + ao = a - (b/r)*s'; + qo = q - (s/r)*s'; + else + s = zeros (n, m); + ao = a; + qo = q; + endif + + ## Check that q, (r) are symmetric, positive (semi)definite + if (is_symmetric (q) && is_symmetric (r) ... + && all (eig (q) >= 0) && all (eig (r) > 0)) + p = dare (ao, b, qo, r); + k = (r+b'*p*b)\b'*p*a + r\s'; + e = eig (a - b*k); + else + error ("dlqr: q (r) must be symmetric positive (semi) definite"); + endif + +endfunction diff --git a/scripts/control/base/dlyap.m b/scripts/control/base/dlyap.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/dlyap.m @@ -0,0 +1,130 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{x} =} dlyap (@var{a}, @var{b}) +## Solve the discrete-time Lyapunov equation +## +## @strong{Inputs} +## @table @var +## @item a +## @var{n} by @var{n} matrix +## @item b +## Matrix: @var{n} by @var{n}, @var{n} by @var{m}, or @var{p} by @var{n}. +## @end table +## +## @strong{Outputs} +## @var{x}: matrix satisfying appropriate discrete time Lyapunov equation. +## Options: +## @itemize @bullet +## @item @var{b} is square: solve @code{a x a' - x + b = 0} +## @item @var{b} is not square: @var{x} satisfies either +## @example +## a x a' - x + b b' = 0 +## @end example +## @noindent +## or +## @example +## a' x a - x + b' b = 0, +## @end example +## @noindent +## whichever is appropriate. +## @end itemize +## +## @strong{Method} +## Uses Schur decomposition method as in Kitagawa, +## @cite{An Algorithm for Solving the Matrix Equation @var{X} = +## @var{F}@var{X}@var{F}' + @var{S}}, +## International Journal of Control, Volume 25, Number 5, pages 745--753 +## (1977). +## +## Column-by-column solution method as suggested in +## Hammarling, @cite{Numerical Solution of the Stable, Non-Negative +## Definite Lyapunov Equation}, IMA Journal of Numerical Analysis, Volume +## 2, pages 303--323 (1982). +## @end deftypefn + +## Author: A. S. Hodel +## Created: August 1993 + +function x = dlyap (a, b) + + if ((n = is_square (a)) == 0) + warning ("dlyap: a must be square"); + endif + + if ((m = is_square (b)) == 0) + [n1, m] = size (b); + if (n1 == n) + b = b*b'; + m = n1; + else + b = b'*b; + a = a'; + endif + endif + + if (n != m) + warning ("dlyap: a,b not conformably dimensioned"); + endif + + ## Solve the equation column by column. + + [u, s] = schur (a); + b = u'*b*u; + + j = n; + while (j > 0) + j1 = j; + + ## Check for Schur block. + + if (j == 1) + blksiz = 1; + elseif (s (j, j-1) != 0) + blksiz = 2; + j = j - 1; + else + blksiz = 1; + endif + + Ajj = kron (s (j:j1, j:j1), s) - eye (blksiz*n); + + rhs = reshape (b (:, j:j1), blksiz*n, 1); + + if (j1 < n) + rhs2 = s*(x (:, (j1+1):n) * s (j:j1, (j1+1):n)'); + rhs = rhs + reshape (rhs2, blksiz*n, 1); + endif + + v = - Ajj\rhs; + x (:, j) = v (1:n); + + if(blksiz == 2) + x (:, j1) = v ((n+1):blksiz*n); + endif + + j = j - 1; + + endwhile + + ## Back-transform to original coordinates. + + x = u*x*u'; + +endfunction diff --git a/scripts/control/base/dre.m b/scripts/control/base/dre.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/dre.m @@ -0,0 +1,155 @@ +## Copyright (C) 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{tvals},@var{Plist}] =} dre(@var{sys},@var{Q},@var{R},@var{Qf},@var{t0},@var{tf}[,@var{Ptol},@var{maxits}]); +## Solve the differential Riccati equation +## @ifinfo +## @example +## -d P/dt = A'P + P A - P B inv(R) B' P + Q +## P(tf) = Qf +## @example +## @end ifinfo +## @iftex +## @tex +## \(-\frac{dP}{dt} = A^{T}P+PA-PBR^{-1}B^{T}P+Q\) +## @end tex +## @end iftex +## for the LTI system sys. Solution of standard LTI +## state feedback optimization +## min \int_{t_0}^{t_f} x' Q x + u' R u dt + x(t_f)' Qf x(t_f) +## optimal input is +## u = - inv(R) B' P(t) x +## @strong{Inputs} +## @table +## @item sys +## continuous time system data structure +## @item Q +## state integral penalty +## @item R +## input integral penalty +## @item Qf +## state terminal penalty +## @item t0 +## @itemx tf +## limits on the integral +## @item Ptol +## tolerance (used to select time samples; see below); default = 0.1 +## @item maxits +## number of refinement iterations (default=10) +## @end table +## @strong{Outputs} +## @table +## @item tvals +## time values at which @var{P}(@var{t}) is computed +## @item Plist +## list values of @var{P}(@var{t}); nth(@var{Plist},@var{ii}) +## is @var{P}(@var{tvals}(@var{ii})). +## +## @item tvals +## @example +## is selected so that || nth(Plist,ii) - nth(Plist,ii-1) || < Ptol +## for ii=2:length(tvals) +## @end example +## @end table +## @end deftypefn + +function [tvals, Plist] = dre (sys, Q, R, Qf, t0, tf, Ptol, maxits) + + if(nargin < 6 | nargin > 8 | nargout != 2) + usage("[tvals,Plist] = dre(sys,Q,R,Qf,t0,tf{,Ptol})"); + elseif(!is_struct(sys)) + error("sys must be a system data structure") + elseif(is_digital(sys)) + error("sys must be a continuous time system") + elseif(!is_matrix(Q) | !is_matrix(R) | !is_matrix(Qf)) + error("Q, R, and Qf must be matrices."); + elseif(!is_scalar(t0) | !is_scalar(tf)) + error("t0 and tf must be scalars") + elseif(t0 >= tf) error("t0=%e >= tf=%e",t0,tf); + elseif(nargin == 6) Ptol = 0.1; + elseif(!is_scalar(Ptol)) error("Ptol must be a scalar"); + elseif(Ptol <= 0) error("Ptol must be positive"); + endif + + if(nargin < 8) maxits = 10; + elseif(!is_scalar(maxits)) error("maxits must be a scalar"); + elseif(maxits <= 0) error("maxits must be positive"); + endif + maxits = ceil(maxits); + + [aa,bb] = sys2ss(sys); + nn = sysdimensions(sys,"cst"); + mm = sysdimensions(sys,"in"); + pp = sysdimensions(sys,"out"); + + if(size(Q) != [nn, nn]) + error("Q(%dx%d); sys has %d states",rows(Q),columns(Q),nn); + elseif(size(Qf) != [nn, nn]) + error("Qf(%dx%d); sys has %d states",rows(Qf),columns(Qf),nn); + elseif(size(R) != [mm, mm]) + error("R(%dx%d); sys has %d inputs",rows(R),columns(R),mm); + endif + + ## construct Hamiltonian matrix + H = [aa , -(bb/R)*bb' ; -Q, -aa']; + + ## select time step to avoid numerical overflow + fast_eig = max(abs(eig(H))); + tc = log(10)/fast_eig; + nst = ceil((tf-t0)/tc); + tvals = -linspace(-tf,-t0,nst); + Plist = list(Qf); + In = eye(nn); + n1 = nn+1; + n2 = nn+nn; + done = 0; + while(!done) + done = 1; # assume this pass will do the job + ## sort time values in reverse order + tvals = -sort(-tvals); + tvlen = length(tvals); + maxerr = 0; + ## compute new values of P(t); recompute old values just in case + for ii=2:tvlen + uv_i_minus_1 = [ In ; nth(Plist,ii-1) ]; + delta_t = tvals(ii-1) - tvals(ii); + uv = expm(-H*delta_t)*uv_i_minus_1; + Qi = uv(n1:n2,1:nn)/uv(1:nn,1:nn); + Plist(ii) = (Qi+Qi')/2; + ## check error + Perr = norm(nth(Plist,ii) - nth(Plist,ii-1))/norm(nth(Plist,ii)); + maxerr = max(maxerr,Perr); + if(Perr > Ptol) + new_t = mean(tvals([ii,ii-1])); + tvals = [tvals, new_t]; + done = 0; + endif + endfor + + ## check number of iterations + maxits = maxits - 1; + done = done+(maxits==0); + endwhile + if(maxerr > Ptol) + warning("dre: \n\texiting with%4d points, max rel chg. =%e, Ptol=%e\n", ... + tvlen,maxerr,Ptol); + tvals = tvals(1:length(Plist)); + endif + +endfunction diff --git a/scripts/control/base/frdemo.m b/scripts/control/base/frdemo.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/frdemo.m @@ -0,0 +1,601 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} frdemo () +## Octave Controls toolbox demo: Frequency Response demo +## @end deftypefn + +## Author: David Clem +## Created: August 15, 1994 +## a s hodel: updated to match new order of ss2zp outputs +## J Ingram: updated for system data structure format August 1996 + +function frdemo () + + disp("") + clc + j = 0; + while (j != 4) + disp(""); + j = menu("Octave Controls Systems Toolbox Frequency Response Demo", + "Bode analysis (bode)", + "Nyquist analysis (nyquist)", + "Nichols analysis (nichols)", + "Return to main demo menu"); + + if (j == 1) + k1 = 0; + while (k1 != 4) + disp("\n"); + clc + + k1 = menu("Bode analysis (bode)", + "Continuous system bode analysis", + "Discrete system bode analysis", + "Bode command description", + "Return to frdemo menu"); + + if( k1 == 1 ) + disp(" ") + clc + disp("\nContinuous system bode analysis\n"); + disp("Example #1:") + disp("\nConsider the system sys1="); + sys1=tf2sys([1, 1], [1, 0, -1]); + sysout(sys1); + disp("\nPole-zero form can be obtained as follows:") + cmd = "sysout(sys1,""zp"");"; + run_cmd; + disp("The systems bode plot is obtained as follows:"); + cmd = "bode(sys1);"; + run_cmd; + disp("\nNotice that bode automatically labels the plots according to") + disp("the selected input/output combinations.") + disp(" ") + disp("If the frequency range is not specified, bode automatically") + disp("selects a frequency range based on the natural frequencies of") + disp("of all poles away from s=0 (or z=1 in discrete time). Bode") + disp("then checks to make sure that the phase plot is sufficiently") + disp("smooth that relevant plot behavior is captured.") + disp("") + disp("Bode exits with an error if the system is mixed (both continuous") + disp("and discrete; see is_digital for conditions)") + prompt + disp("\nIf the plot magnitude, phase and frequency data is desired, the"); + disp("user can enter the following command:"); + disp("\n[Mag,Phase,w] = bode(sys);"); + disp("\nThis will return three vectors containing the magnitude,"); + disp("phase and frequency.\n"); + prompt; + + disp("") + clc + disp("Example #2, sys2=") + cmd = "sys2=zp2sys(1, [-1, -5], 10);"; + eval(cmd); + cmd = "sysout(sys2);"; + eval(cmd); + disp("\nThe bode plot command is identical to the tf form:") + cmd = "bode(sys2);"; + run_cmd; + disp("\nThe internal representation of the system is not important;") + disp("bode automatically sorts it out internally.") + prompt; + + disp("") + clc + disp("Example #3, Consider the following state space system sys3=:\n"); + cmd = "sys3=ss2sys([0, 1; -1000, -1001], [0; 1], [0, -891], 1);"; + eval(cmd); + cmd = "sysout(sys3);"; + eval(cmd); + disp("\nOnce again, the bode plot command is the same:"); + cmd = "bode(sys3);"; + run_cmd; + disp("\nSuppose the user is interested in the response of the system"); + disp("defined over the input frequency range of 1 - 1000 rad/s.\n"); + disp("First, a frequency vector is required. It can be created"); + disp("with the command:\n"); + cmd = "wrange = logspace(log10(1),log10(1000),100);"; + disp(cmd); + eval(cmd); + disp("\nThis creates a logarithmically scaled frequency vector with"); + disp("100 values between 1 and 1000 rad/s\n"); + disp("Then, the bode command includes wrange in the input arguments"); + disp("like this:"); + cmd = "bode(sys3,wrange);"; + run_cmd; + prompt; + + disp("") + clc + disp("\nExample #4, The state-space system from example 3 will be"); + disp("grouped with the system from example 2 to form a MIMO system"); + disp("The commands to do this grouping are as follows (changing signal"); + disp("names for clarity):"); + cmd = "sys2 = syssetsignals(sys2,\"out\",\"y_sys2\");"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"in\",\"u_sys2\");"; + disp(cmd); eval(cmd); + cmd = "nn = sysdimensions(sys2);"; + disp(cmd); eval(cmd); + cmd = "[nn,nz] = sysdimensions(sys2);"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"st\",sysdefioname(nn+nz,\"x_sys2\"));"; + disp(cmd); eval(cmd); + cmd = "sys_mimo = sysgroup(sys2,sys3);"; + disp(cmd); eval(cmd); + disp("The resulting state-space system (after changing signal names"); + disp("in sys2) is"); + cmd = "sysout(sys_mimo)"; + eval(cmd); + disp("\nNotice that there are now 2 inputs and 2 outputs, and that it did"); + disp("not matter what form the two systems were in when they were grouped."); + disp(["\nTo view the system's bode plots, execute the", + " following command:\n"]) + cmd = "bode(sys_mimo);"; + run_cmd; + prompt + disp("\nTo view the bode plots for selected channels, the command form changes:") + cmd = "wrange = [];"; + disp(cmd) + eval(cmd); + cmd = "out = 1;"; + disp(cmd) + eval(cmd); + cmd = "in = 1;"; + disp(cmd) + eval(cmd); + cmd = "bode(sys_mimo,wrange,out,in);"; + run_cmd; + disp("\nNotice that this bode plot is the same as the plot from example 2."); + prompt + closeplot + + elseif( k1 == 2 ) + disp("") + clc + disp("\nDiscrete system bode analysis\n"); + disp("Display bode plots of a discrete SISO system (dbode)\n") + disp("Example #1, Consider the following discrete transfer"); + disp(" function:\n"); + cmd = "sys1 = tf2sys([0.00100502, -0.00099502], [1, -2, 1], 0.001);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys1)"; + disp(cmd); + eval(cmd); + disp("\nTo examine open loop zeros and poles of the system,"); + disp("use the command:\n") + cmd = "sysout(sys1,""zp"");"; + run_cmd; + disp("\nTo view the system's bode plots, execute the following"); + disp("command:\n") + cmd = "bode(sys1);"; + run_cmd; + disp("\nNotice (1) the plot label uses exp(jwT) for its title axis. This") + disp(" allows the user to determine what kind of system was") + disp(" used to generate the bode plot"); + disp(" (2) the system poles are both at z=1, (break frequency at") + disp(" jwT = 0); pure integrator poles like this are discarded") + disp(" by Octave when computing the plot frequency range.") + + disp("\nIf magnitude, phase, and frequency data are also desired,"); + disp(" perform the following command instead:\n"); + disp("[M,P,w]=dbode(num,den,T,wrange).\n Where:"); + disp("M => Bode magnitude response data"); + disp("P => Bode phase response data"); + disp("w => frequencies that M and P were evaluated at"); + disp("sys1 => system data structure") + disp("T => sample period") + disp("wrange => optional vector of frequencies") + disp(" if wrange is entered in the argument list, the"); + disp(" system will be evaluated at these specific"); + disp(" frequencies\n"); + + prompt + disp("") + clc + disp("Example #2, Consider the following set of discrete poles and"); + disp("zeros:\n") + cmd = "sys2 = zp2sys([0.99258;0.99745],[0.99961;0.99242],1,0.001);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys2)"; + disp(cmd); + eval(cmd); + disp("\nTo view the system's bode plots, execute the following"); + disp("command:\n") + cmd = "bode(sys2);"; + run_cmd; + disp("Notice that the bode command is the same in both of the previous"); + disp("examples. The bode command is also the same for the continuous case."); + disp("The function, dbode, is no longer used."); + + prompt + disp("") + clc + disp("\nExample #3, Now consider the following state space system:\n"); + cmd = "sys3 = ss2sys([.857, .0011; 0, .99930],[1;1],[-.6318, .0057096],5.2, .001);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys3);"; + disp(cmd); + eval(cmd); + disp("\nTo view the system's bode plots, execute the following command:\n") + cmd = "bode(sys3);"; + run_cmd; + disp("\nAgain, notice that the bode command is the same regardless of the form"); + disp("of the system."); + disp("\nSuppose the user is interested in the response of the system"); + disp("defined over the input frequency range of 1 - 1000 rad/s.\n"); + disp("First, a frequency vector is required. It can be created"); + disp("with the command:\n"); + cmd = "wrange = logspace(log10(1),log10(1000),100);"; + disp(cmd); + eval(cmd); + disp("\nThis creates a logrithmetically scaled frequency vector with"); + disp("100 values between 1 and 1000 rad/s\n"); + disp("Then, the bode command includes wrange in the input arguments"); + disp("like this:"); + cmd = "bode(sys3,wrange);"; + run_cmd; + prompt; + + disp("") + clc + disp("\nExample #4, We will now examine a MIMO state-space system. Systems"); + disp("two and three will be grouped."); + cmd = "[nn,nz] = sysdimensions(sys2);"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"out\",\"y_sys2\");"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"in\",\"u_sys2\");"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"st\",sysdefioname(nn+nz,\"x_sys2\"));"; + disp(cmd); eval(cmd); + cmd = "sys_mimo = sysgroup(sys2,sys3);"; + disp(cmd); eval(cmd); + cmd = "sysout(sys_mimo);"; + disp(cmd); + eval(cmd); + disp("\nTo view the system's bode plots, execute the following command:\n") + cmd = "bode(sys_mimo);"; + run_cmd; + prompt + + disp("\nThe bode plot of a single channel is viewed as follows:") + cmd = "wrange = [];"; + disp(cmd) + eval(cmd); + cmd = "out = 1;"; + disp(cmd) + eval(cmd); + cmd = "in = 1;"; + disp(cmd) + eval(cmd); + cmd = "bode(sys_mimo,wrange,out,in);"; + run_cmd; + disp("\nNotice that this bode plot is the same as the plot from example 2."); + prompt + closeplot + + elseif( k1 == 3 ) + help bode + prompt + endif + endwhile + elseif (j == 2) + k2 = 0; + disp(""); + while (k2 != 4) + disp("\n"); + help nyquist + prompt; + disp("") + clc; + + k2 = menu("Nyquist analysis (Nyquist)", + "Continuous system nyquist analysis", + "Discrete system nyquist analysis", + "Mixed system nyquist analysis", + "Return to frdemo menu"); + + if( k2 == 1 ) + disp("") + clc + disp("\nContinuous system nyquist analysis\n"); + disp("Display Nyquist plots of a SISO system (nyquist)\n") + disp("Example #1, Consider the following transfer function:\n") + cmd = "sys1 = tf2sys(1, [1, 0.8, 1]);"; + disp(cmd); + eval(cmd); + disp("To examine the transfer function, use the command:"); + cmd = "sysout(sys1);"; + disp(cmd); + eval(cmd); + disp("\nTo examine the open loop zeros and poles, use the command:"); + cmd = "sysout(sys1,""zp"");"; + run_cmd; + disp("\nTo view the system""s nyquist plot, execute the following"); + disp("command:\n") + cmd = "nyquist(sys1);"; + run_cmd; + disp("\nIf the real and imaginary parts of the response are desired,"); + disp("use the following command:"); + disp("command: [R,I,w]=nyquist(sys1);\n"); + disp("If the user desires to evaluate the response in a certain"); + disp("frequency range, he may do so by entering the following:"); + disp("command: [M,P,w]=nyquist(num,den,wrange).\n") + disp("wrange is a vector of frequencies that spans the desired"); + disp("viewing range.\n"); + disp("This will be illustrated in the third nyquist example.\n") + disp("Variable Description:\n") + disp("R => real part of response") + disp("I => imaginary part of response") + disp("w => frequencies that the transfer function was evaluated at") + disp("sys1 => system data structure") + disp("wrange => optional vector of frequencies") + disp(" if wrange is entered in the argument list, the"); + disp(" system will be evaluated at these specific"); + disp(" frequencies\n") + prompt + + disp("") + clc + disp("Example #2, Consider the following set of poles and zeros:\n") + cmd = "sys2 = zp2sys([-1;-4],[-2+1.4142i;-2-1.4142i],1);"; + disp(cmd); + eval(cmd); + disp("\nTo examine the poles and zeros, use the command:"); + cmd = "sysout(sys2)"; + disp(cmd); + eval(cmd); + disp("\nTo view the system""s nyquist plot, execute the following"); + disp("command:\n") + cmd = "nyquist(sys2);"; + run_cmd; + prompt + + disp("") + clc + disp("\nExample #3, Consider the following state space system:\n") + cmd = "sys3 = ss2sys([0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1; 0, 0, -20, -12],[0;0;0;1],[50, 100, 0, 0],0);"; + disp(cmd); + eval(cmd); + disp("\nTo examine the state-space system, use the command:"); + cmd = "sysout(sys3)"; + disp(cmd); + eval(cmd); + disp("\nTo examine the poles and zeros, use the command:"); + cmd = "sysout(sys3,""zp"")"; + run_cmd; + disp("\nTo view the system""s nyquist plot, execute the following"); + disp("commands:\n") + cmd = "nyquist(sys3);"; + run_cmd; + prompt + + disp("Example #3 (continued), If the user wishes to evaluate the"); + disp("system response over a desired frequency range, he must first"); + disp("create a frequency vector.\n") + disp("For example, suppose the user is interested in the response"); + disp("of the system defined above over input frequency range of"); + disp("3 - 100 rad/s.\n") + disp("A frequency vector can be created using the command:\n"); + cmd = "wrange = logspace(log10(3),log10(100),100);"; + disp(cmd); + eval(cmd); + disp("\nNyquist can be run again using the frequency vector as"); + disp("follows:\n") + cmd = "nyquist(sys3,wrange);"; + run_cmd; + prompt + + disp("") + clc + disp("Example #4, Nyquist can be used for MIMO systems if the system has"); + disp("an equal number of inputs and outputs. Otherwise, nyquist returns"); + disp("an error. To examine a MIMO system, systems 2 and 3 will be grouped"); + cmd = "[nn,nz] = sysdimensions(sys2);"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"out\",\"y_sys2\");"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"in\",\"u_sys2\");"; + disp(cmd); eval(cmd); + cmd = "sys2 = syssetsignals(sys2,\"st\",sysdefioname(nn+nz,\"x_sys2\"));"; + disp(cmd); eval(cmd); + cmd = "sys_mimo = sysgroup(sys2,sys3);"; + disp(cmd); eval(cmd); + cmd = "sysout(sys_mimo);"; + disp(cmd); + eval(cmd); + disp("\nTo view the system's nyquist plot, execute the following command:\n") + cmd = "nyquist(sys_mimo);"; + run_cmd; + prompt + disp("\nTo view the nyquist plots for selected channels, the command form changes:") + cmd = "nyquist(sys_mimo,[],1,1);"; + run_cmd; + disp("\nNotice that this bode plot is the same as the plot from example 2."); + prompt + closeplot + + + + elseif( k2 == 2 ) + disp("") + clc + disp("\nDiscrete system nyquist analysis\n"); + disp("Display Nyquist plots of a discrete SISO system (nyquist)\n") + disp("We will first define a sampling time, T"); + cmd = "T = 0.01;"; + disp(cmd); + eval(cmd); + disp("\nExample #1, Consider the following transfer function:\n") + cmd = "sys1 = tf2sys([2, -3.4, 1.5],[1, -1.6, 0.8],T);"; + disp(cmd); + eval(cmd); + disp("To examine the transfer function, use the command:"); + cmd = "sysout(sys1);"; + disp(cmd); + eval(cmd); + disp("\nTo examine the open loop zeros and poles, use the command:"); + cmd = "sysout(sys1,""zp"")"; + disp(cmd); + eval(cmd); + disp("\nTo view the system""s nyquist plot, execute the following"); + disp("command:") + cmd = "nyquist(sys1);"; + run_cmd; + disp("To change the range used for the frequency, a frequency"); + disp("is needed. Suppose the user would like to examine the"); + disp("nyquist plot in the frequency range of 0.01 - 31.6 rad/s."); + disp("\nThe frequency vector needed to do this is created with the"); + disp("command:"); + cmd = "wrange = logspace(-2,1.5,200);"; + disp(cmd); + eval(cmd); + disp("\nNyquist can be run again with this frequency vector"); + cmd = "nyquist(sys1,wrange);"; + run_cmd; + disp("\nIf the real and imaginary parts of the response are desired,"); + disp("perform the following command:\n"); + disp("[R,I,w]=nyquist(sys,wrange)\n") + disp("Variable Description:\n") + disp("R => real part of response") + disp("I => imaginary part of response") + disp("w => frequencies that the transfer function was evaluated at") + disp("sys => The system data structure"); + disp("wrange => optional vector of frequencies") + disp(" if wrange is entered in the argument list, the"); + disp(" system will be evaluated at these specific"); + prompt + + disp("") + clc + disp("\nExample #2, Consider the following set of poles and zeros:\n") + cmd = "sys2 = zp2sys([0.98025 + 0.01397i; 0.98025 - 0.01397i],[0.96079;0.99005],1,T);"; + disp(cmd); + eval(cmd); + disp("\nTo examine the open loop zeros and poles, use the command:"); + cmd = "sysout(sys2)"; + disp(cmd); + eval(cmd); + disp("\nTo view the system's nyquist plot between the frequencies"); + disp("0.01 - 100 rad/s, execute the following commands:\n") + cmd = "wrange = logspace(-2,2,100);"; + disp(cmd); + eval(cmd); + cmd = "nyquist(sys2,wrange);"; + run_cmd; + prompt; + + disp("") + clc + disp("\nExample #3, Consider the following discrete state space"); + disp("system:\n"); + disp("This example will use the same system used in the third"); + disp("example in the continuous nyquist demo. First, that system"); + disp("will have to be re-entered useing the following commands:\n"); + cmd = "sys3 = ss2sys([0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1; 0, 0, -20, -12],[0;0;0;1],[50, 100, 0, 0],0);"; + disp(cmd); + eval(cmd); + disp("\nTo examine the state-space system, use the command:"); + cmd = "sysout(sys3)"; + disp(cmd); + eval(cmd); + disp("\nTo examine the poles and zeros, use the command:"); + cmd = "sysout(sys3,""zp"")"; + disp(cmd); + eval(cmd); + disp("\nTo convert the system to discrete time, we need a sampling"); + disp("time which can be entered like this:"); + cmd = "T = 0.01"; + disp(cmd); + eval(cmd); + disp("\nNow the command, c2d, is used to convert the system from"); + disp("continuous to discrete time, with the following command"); + cmd = "dsys3 = c2d(sys3,T);"; + run_cmd; + disp("\nTo examine the new discrete state-space system, use the"); + disp("command"); + cmd = "sysout(dsys3);"; + disp(cmd); + eval(cmd); + disp("\nTo examine the new discrete poles and zeros, use the command:"); + cmd = "sysout(dsys3,""zp"")"; + disp(cmd); + eval(cmd); + disp("\nTo view the system's nyquist plot, execute the following"); + disp("commands:\n"); + cmd = "gset xrange [-4:2];"; + disp(cmd); eval(cmd); + cmd = "gset yrange [-2.5:2.5];"; + disp(cmd); eval(cmd); + cmd = "nyquist(dsys3);"; + run_cmd; + disp("Notice that the asymptotes swamp out the behavior of the plot") + disp("near the origin. You may use interactive nyquist plots") + disp("to \"zoom in\" on a plot as follows:") + + cmd = "atol = 1;"; + disp(cmd) + eval(cmd) + cmd = "nyquist(dsys3,[],[],[],atol);"; + run_cmd + prompt + + + disp("") + clc + disp("MIMO SYSTEM: Nyquist cannot be used for discrete MIMO systems"); + disp("at this time."); + ## cmd = "dsys_mimo = sysgroup(sys2,dsys3);"; + ## disp(cmd); + ## eval(cmd); + ## cmd = "sysout(dsys_mimo);"; + ## disp(cmd); + ## eval(cmd); + ## disp("\nTo view the system's nyquist plot, execute the following command:\n") + ## cmd = "nyquist(dsys_mimo);"; + ## run_cmd; + ## prompt + ## disp("\nTo view the nyquist plots for selected channels, the command form changes:") + ## cmd = "nyquist(dsys_mimo,[],1,1);"; + ## run_cmd; + ## disp("\nNotice that this bode plot is the same as the plot from example 2."); + prompt + closeplot + + + elseif( k2 == 3 ) + disp("\nMixed system nyquist analysis\n"); + disp("Nyquist exits with an error if it is passed a ""mixed"" system (one") + disp("with both continuous and discrete states). Use c2d or d2c to") + disp("convert the system to either pure digital or pure continuous form"); + endif + endwhile + elseif (j == 3) + help nichols + prompt + endif + endwhile + +endfunction diff --git a/scripts/control/base/freqchkw.m b/scripts/control/base/freqchkw.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/freqchkw.m @@ -0,0 +1,43 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retval} =} freqchkw (@var{w}) +## Used by @code{freqresp} to check that input frequency vector @var{w} +## is valid. +## Returns boolean value. +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 1996 + +function USEW = freqchkw (w) + + if(isempty(w)) + USEW = 0; + elseif(!is_vector(w)) + error(["w (",num2str(rows(w)),"x",num2str(columns(w)), ... + "): must be [], a vector or a scalar"]); + elseif( (max(abs(imag(w))) != 0) && (min(real(w)) <= 0) ) + error("w must have real positive entries"); + else + w = sort(w); + USEW = 1; # vector provided (check values later) + endif + +endfunction diff --git a/scripts/control/base/freqresp.m b/scripts/control/base/freqresp.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/freqresp.m @@ -0,0 +1,133 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{out} =} freqresp (@var{sys}, @var{USEW}@{,@var{w}@}); +## Frequency response function - used internally by @code{bode}, @code{nyquist}. +## minimal argument checking; "do not attempt to do this at home" +## +## @strong{Inputs} +## @table @var +## @item sys +## system data structure +## @item USEW +## returned by @code{freqchkw} +## @item optional +## must be present if @var{USEW} is true (nonzero) +## @end table +## @strong{Outputs} +## @table @var +## @item @var{out} +## vector of finite @math{G(j*w)} entries (or @math{||G(j*w)||} for MIMO) +## @item w +## vector of corresponding frequencies +## @end table +## @end deftypefn + +## Author: R. Bruce Tenison +## Created: July 11, 1994 + +function [ff, w] = freqresp (sys, USEW, w); + + ## SYS_INTERNAL accesses members of system data structure + + save_val = empty_list_elements_ok; + empty_list_elements_ok = 1; + + ## Check Args + if( (nargin < 2) || (nargin > 4) ) + usage ("[ff,w] = freqresp(sys,USEW{,w})"); + elseif( USEW & (nargin < 3) ) + error("USEW=1 but w was not passed."); + elseif( USEW & isempty(w)) + warning("USEW=1 but w is empty; setting USEW=0"); + USEW=0; + endif + + DIGITAL = is_digital(sys); + + ## compute default w if needed + if(!USEW) + if(is_siso(sys)) + sys = sysupdate(sys,"zp"); + [zer,pol] = sys2zp(sys); + else + zer = tzero(sys); + pol = eig(sys2ss(sys)); + endif + + ## get default frequency range + [wmin,wmax] = bode_bounds(zer,pol,DIGITAL,sysgettsam(sys)); + w = logspace(wmin,wmax,50); + else + w = reshape(w,1,length(w)); # make sure it's a row vector + endif + + ## now get complex values of s or z + if(DIGITAL) + jw = exp(i*w*sysgettsam(sys)); + else + jw = i*w; + endif + + [nn,nz,mm,pp] = sysdimensions(sys); + + ## now compute the frequency response - divide by zero yields a warning + if (strcmp(sysgettype(sys),"zp")) + ## zero-pole form (preferred) + [zer,pol,sysk] = sys2zp(sys); + ff = ones(size(jw)); + l1 = min(length(zer)*(1-isempty(zer)),length(pol)*(1-isempty(pol))); + for ii=1:l1 + ff = ff .* (jw - zer(ii)) ./ (jw - pol(ii)); + endfor + + ## require proper transfer function, so now just get poles. + for ii=(l1+1):length(pol) + ff = ff ./ (jw - pol(ii)); + endfor + ff = ff*sysk; + + elseif (strcmp(sysgettype(sys),"tf")) + ## transfer function form + [num,den] = sys2tf(sys); + ff = polyval(num,jw)./polyval(den,jw); + elseif (mm==pp) + ## The system is square; do state-space form bode plot + [sysa,sysb,sysc,sysd,tsam,sysn,sysnz] = sys2ss(sys); + n = sysn + sysnz; + for ii=1:length(jw); + ff(ii) = det(sysc*((jw(ii).*eye(n)-sysa)\sysb)+sysd); + endfor; + else + ## Must be state space... bode + [sysa,sysb,sysc,sysd,tsam,sysn,sysnz] = sys2ss(sys); + n = sysn + sysnz; + for ii=1:length(jw); + ff(ii) = norm(sysc*((jw(ii)*eye(n)-sysa)\sysb)+sysd); + endfor + + endif + + w = reshape(w,1,length(w)); + ff = reshape(ff,1,length(ff)); + + ## restore global variable + empty_list_elements_ok = save_val; +endfunction + diff --git a/scripts/control/base/gram.m b/scripts/control/base/gram.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/gram.m @@ -0,0 +1,34 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{m} =} gram (@var{a}, @var{b}) +## Return controllability grammian @var{m} of the continuous time system +## @math{ dx/dt = a x + b u}. +## +## @var{m} satisfies @math{ a m + m a' + b b' = 0 }. +## @end deftypefn + +## Author: A. S. Hodel + +function m = gram (a, b) + + ## let lyap do the error checking... + m = lyap(a,b*b'); + +endfunction diff --git a/scripts/control/base/impulse.m b/scripts/control/base/impulse.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/impulse.m @@ -0,0 +1,89 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{y}, @var{t}] =} impulse (@var{sys}@{, @var{inp},@var{tstop}, @var{n}@}) +## Impulse response for a linear system. +## The system can be discrete or multivariable (or both). +## If no output arguments are specified, @code{impulse} +## produces a plot or the impulse response data for system @var{sys}. +## +## @strong{Inputs} +## @table @var +## @item sys +## System data structure. +## @item inp +## Index of input being excited +## @item tstop +## The argument @var{tstop} (scalar value) denotes the time when the +## simulation should end. +## @item n +## the number of data values. +## +## Both parameters @var{tstop} and @var{n} can be omitted and will be +## computed from the eigenvalues of the A-Matrix. +## @end table +## @strong{Outputs} +## @var{y}, @var{t}: impulse response +## @end deftypefn +## @seealso{step and stepimp} + +## Author: Kai P. Mueller +## Created: October 2, 1997 +## based on lsim.m of Scottedward Hodel +## modified by + +function [y, t] = impulse (sys, inp, tstop, n) + + if((nargin < 1) || (nargin > 4)) + usage("[y, u] = impulse(sys[, inp, tstop, n])"); + endif + + if(nargout > 2) + usage("[y, u] = impulse(sys[, inp, tstop, n])"); + endif + + if(!is_struct(sys)) + error("impulse: sys must be a system data structure."); + endif + + if (nargout == 0) + switch (nargin) + case (1) + stepimp(2, sys); + case (2) + stepimp(2, sys, inp); + case (3) + stepimp(2, sys, inp, tstop); + case (4) + stepimp(2, sys, inp, tstop, n); + endswitch + else + switch (nargin) + case (1) + [y, t] = stepimp(2, sys); + case (2) + [y, t] = stepimp(2, sys, inp); + case (3) + [y, t] = stepimp(2, sys, inp, tstop); + case (4) + [y, t] = stepimp(2, sys, inp, tstop, n); + endswitch + endif + +endfunction diff --git a/scripts/control/base/is_controllable.m b/scripts/control/base/is_controllable.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/is_controllable.m @@ -0,0 +1,114 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{retval}, @var{U}] =} is_controllable (@var{sys}@{, @var{tol}@}) +## @deftypefnx {Function File} {[@var{retval}, @var{U}] =} is_controllable (@var{a}@{, @var{b}, @var{tol}@}) +## Logical check for system controllability. +## +## @strong{Inputs} +## @table @var +## @item sys +## system data structure +## @item a +## @itemx b +## @var{n} by @var{n}, @var{n} by @var{m} matrices, respectively +## @item tol +## optional roundoff paramter. default value: @code{10*eps} +## @end table +## +## @strong{Outputs} +## @table @var +## @item retval +## Logical flag; returns true (1) if the system @var{sys} or the +## pair (@var{a},@var{b}) is controllable, whichever was passed as input +## arguments. +## @item U +## U is an orthogonal basis of the controllable subspace. +## @end table +## +## @strong{Method} +## Controllability is determined by applying Arnoldi iteration with +## complete re-orthogonalization to obtain an orthogonal basis of the +## Krylov subspace +## @example +## span ([b,a*b,...,a^@{n-1@}*b]). +## @end example +## The Arnoldi iteration is executed with @code{krylov} if the system +## has a single input; otherwise a block Arnoldi iteration is performed +## with @code{krylovb}. +## @end deftypefn +## @seealso{size, rows, columns, length, is_matrix, is_scalar, is_vector +## is_observable, is_stabilizable, is_detectable, krylov, and krylovb} + +## Author: A. S. Hodel +## Created: August 1993 +## Updated by A. S. Hodel (scotte@eng.auburn.edu) Aubust, 1995 to use krylovb +## Updated by John Ingram (ingraje@eng.auburn.edu) July, 1996 for packed systems + +function [retval, U] = is_controllable (a, b, tol) + + deftol = 1; # assume default tolerance + if(nargin < 1 | nargin > 3) + usage("[retval,U] = %s\n\t%s", "is_controllable(a {, b, tol})", ... + "is_controllable(sys{,tol})"); + elseif(is_struct(a)) + ## system structure passed. + sys = sysupdate(a,"ss"); + [a,bs] = sys2ss(sys); + if(nargin > 2) + usage("[retval,U] = is_controllable(sys{,tol})"); + elseif(nargin == 2) + tol = b; % get tolerance + deftol = 0; + endif + b = bs; + else + ## a,b arguments sent directly. + if(nargin < 2) + usage("[retval,U] = is_controllable(a {, b ,tol})"); + else + deftol = 1; + endif + endif + + ## check for default tolerance + if(deftol) tol = 1000*eps; endif + + ## check tol dimensions + if( !is_scalar(tol) ) + error("is_controllable: tol(%dx%d) must be a scalar", ... + rows(tol),columns(tol)); + elseif( !is_sample(tol) ) + error("is_controllable: tol=%e must be positive",tol); + endif + + ## check dimensions compatibility + n = is_square (a); + [nr, nc] = size (b); + + if (n == 0 | n != nr | nc == 0) + warning("is_controllable: a=(%dx%d), b(%dx%d)",rows(a),columns(a),nr,nc); + retval = 0; + else + ## call block-krylov subspace routine to get an orthogonal basis + ## of the controllable subspace. + [U,H,Ucols] = krylov(a,b,n,tol,1); + retval = (Ucols == n); + endif +endfunction diff --git a/scripts/control/base/is_detectable.m b/scripts/control/base/is_detectable.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/is_detectable.m @@ -0,0 +1,64 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{retval}, @var{U}] =} is_detectable (@var{a}, @var{c}@{, @var{tol}@}) +## @deftypefnx {Function File} {[@var{retval}, @var{U}] =} is_detectable (@var{sys}@{, @var{tol}@}) +## Test for detactability (observability of unstable modes) of +## (@var{a},@var{c}). +## +## Returns 1 if the system @var{a} or the pair (@var{a},@var{c})is +## detectable, 0 if not. +## +## @strong{See} @code{is_stabilizable} for detailed description of +## arguments and computational method. +## +## Default: tol = 10*norm(a,'fro')*eps +## +## @end deftypefn +## @seealso{is_stabilizable, size, rows, columns, length, is_matrix, +## is_scalar, and is_vector} + +## Author: A. S. Hodel +## Created: August 1993 +## Updated by John Ingram (ingraje@eng.auburn.edu) July 1996. + +function [retval, U] = is_detectable (a, c, tol) + + if( nargin < 1) + usage("[retval,U] = is_detectable(a , c {, tol})"); + elseif(is_struct(a)) + ## system form + if(nargin == 2) + tol = c; + elseif(nargin > 2) + usage("[retval,U] = is_detectable(sys {, tol})"); + endif + [a,b,c] = sys2ss(a); + elseif(nargin > 3) + usage("[retval,U] = is_detectable(a , c {, tol})"); + endif + if(exist("tol")) + [retval,U] = is_stabilizable (a', c', tol); + else + [retval,U] = is_stabilizable (a', c'); + endif + + +endfunction + diff --git a/scripts/control/base/is_dgkf.m b/scripts/control/base/is_dgkf.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/is_dgkf.m @@ -0,0 +1,258 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{retval}, @var{dgkf_struct} ] =} is_dgkf (@var{Asys}, @var{nu}, @var{ny}, @var{tol} ) +## Determine whether a continuous time state space system meets +## assumptions of DGKF algorithm. +## Partitions system into: +## @example +## [dx/dt] = [A | Bw Bu ][w] +## [ z ] [Cz | Dzw Dzu ][u] +## [ y ] [Cy | Dyw Dyu ] +## @end example +## or similar discrete-time system. +## If necessary, orthogonal transformations @var{Qw}, @var{Qz} and nonsingular +## transformations @var{Ru}, @var{Ry} are applied to respective vectors +## @var{w}, @var{z}, @var{u}, @var{y} in order to satisfy DGKF assumptions. +## Loop shifting is used if @var{Dyu} block is nonzero. +## +## @strong{Inputs} +## @table @var +## @item Asys +## system data structure +## @item nu +## number of controlled inputs +## @item ny +## number of measured outputs +## @item tol +## threshhold for 0. Default: 200@var{eps} +## @end table +## @strong{Outputs} +## @table @var +## @item retval +## true(1) if system passes check, false(0) otherwise +## @item dgkf_struct +## data structure of @code{is_dgkf} results. Entries: +## @table @var +## @item nw +## @itemx nz +## dimensions of @var{w}, @var{z} +## @item A +## system @var{A} matrix +## @item Bw +## (@var{n} x @var{nw}) @var{Qw}-transformed disturbance input matrix +## @item Bu +## (@var{n} x @var{nu}) @var{Ru}-transformed controlled input matrix; +## +## @strong{Note} @math{B = [Bw Bu] } +## @item Cz +## (@var{nz} x @var{n}) Qz-transformed error output matrix +## @item Cy +## (@var{ny} x @var{n}) @var{Ry}-transformed measured output matrix +## +## @strong{Note} @math{C = [Cz; Cy] } +## @item Dzu +## @item Dyw +## off-diagonal blocks of transformed @var{D} matrix that enter +## @var{z}, @var{y} from @var{u}, @var{w} respectively +## @item Ru +## controlled input transformation matrix +## @item Ry +## observed output transformation matrix +## @item Dyu_nz +## nonzero if the @var{Dyu} block is nonzero. +## @item Dyu +## untransformed @var{Dyu} block +## @item dflg +## nonzero if the system is discrete-time +## @end table +## @end table +## @code{is_dgkf} exits with an error if the system is mixed +## discrete/continuous +## +## @strong{References} +## @table @strong +## @item [1] +## Doyle, Glover, Khargonekar, Francis, "State Space Solutions +## to Standard H2 and Hinf Control Problems," IEEE TAC August 1989 +## @item [2] +## Maciejowksi, J.M.: "Multivariable feedback design," +## @end table +## @end deftypefn + +## Author: A. S. Hodel +## Updated by John Ingram July 1996 to accept structured systems + +## Revised by Kai P. Mueller April 1998 to solve the general H_infinity +## problem using unitary transformations Q (on w and z) +## and non-singular transformations R (on u and y) such +## that the Dzu and Dyw matrices of the transformed plant +## +## ~ +## P (the variable Asys here) +## +## become +## +## ~ -1 T +## D = Q D R = [ 0 I ] or [ I ], +## 12 12 12 12 +## +## ~ T +## D = R D Q = [ 0 I ] or [ I ]. +## 21 21 21 21 +## +## This transformation together with the algorithm in [1] solves +## the general problem (see [2] for example). + +function [retval, dgkf_struct] = is_dgkf (Asys, nu, ny, tol) + + if (nargin < 3) | (nargin > 4) + usage("[retval,dgkf_struct] = is_dgkf(Asys,nu,ny{,tol})"); + elseif (! is_scalar(nu) | ! is_scalar(ny) ) + error("is_dgkf: arguments 2 and 3 must be scalars") + elseif (! is_struct(Asys) ) + error("Argument 1 must be a system data structure"); + endif + if(nargin < 4) + tol = 200*eps; + elseif( !is_sample(tol) ) + error("is_dgkf: tol must be a positive scalar") + endif + + retval = 1; # assume passes test + + dflg = is_digital(Asys); + [Anc, Anz, nin, nout ] = sysdimensions(Asys); + + if( Anz == 0 & Anc == 0 ) + error("is_dgkf: no system states"); + elseif( nu >= nin ) + error("is_dgkf: insufficient number of disturbance inputs"); + elseif( ny >= nout ) + error("is_dgkf: insufficient number of regulated outputs"); + endif + + nw = nin - nu; nw1 = nw + 1; + nz = nout - ny; nz1 = nz + 1; + + [A,B,C,D] = sys2ss(Asys); + ## scale input/output for numerical reasons + if(norm (C, "fro") * norm (B, "fro") == 0) + error("||C||*||B|| = 0; no dynamic connnection from inputs to outputs"); + endif + xx = sqrt(norm(B, Inf) / norm(C, Inf)); + B = B / xx; C = C * xx; + + ## partition matrices + Bw = B(:,1:nw); Bu = B(:,nw1:nin); + Cz = C(1:nz,:); Dzw = D(1:nz,1:nw); Dzu = D(1:nz,nw1:nin); + Cy = C(nz1:nout,:); Dyw = D(nz1:nout,1:nw); Dyu = D(nz1:nout,nw1:nin); + + ## Check for loopo shifting + Dyu_nz = (norm(Dyu,Inf) != 0); + if (Dyu_nz) + warning("is_dgkf: D22 nonzero; performing loop shifting"); + endif + + ## 12 - rank condition at w = 0 + xx =[A, Bu; Cz, Dzu]; + [nr, nc] = size(xx); + irank = rank(xx); + if (irank != nc) + retval = 0; + warning(sprintf("rank([A Bu; Cz Dzu]) = %d, need %d; n=%d, nz=%d, nu=%d", ... + irank,nc,(Anc+Anz),nz,nu)); + warning(" *** 12-rank condition violated at w = 0."); + endif + + ## 21 - rank condition at w = 0 + xx =[A, Bw; Cy, Dyw]; + [nr, nc] = size(xx); + irank = rank(xx); + if (irank != nr) + retval = 0; + warning(sprintf("rank([A Bw; Cy Dyw]) = %d, need %d; n=%d, ny=%d, nw=%d", ... + irank,nr,(Anc+Anz),ny,nw)); + warning(" *** 21-rank condition violated at w = 0."); + endif + + ## can Dzu be transformed to become [0 I]' or [I]? + ## This ensures a normalized weight + [Qz, Ru] = qr(Dzu); + irank = rank(Ru); + if (irank != nu) + retval = 0; + warning(sprintf("*** rank(Dzu(%d x %d) = %d", nz, nu, irank)); + warning(" *** Dzu does not have full column rank."); + endif + if (nu >= nz) + Qz = Qz(:,1:nu)'; + else + Qz = [Qz(:,(nu+1):nz), Qz(:,1:nu)]'; + endif + Ru = Ru(1:nu,:); + + ## can Dyw be transformed to become [0 I] or [I]? + ## This ensures a normalized weight + [Qw, Ry] = qr(Dyw'); + irank = rank(Ry); + if (irank != ny) + retval = 0; + warning(sprintf("*** rank(Dyw(%d x %d) = %d", ny, nw, irank)); + warning(" *** Dyw does not have full row rank."); + endif + + if (ny >= nw) + Qw = Qw(:,1:ny); + else + Qw = [Qw(:,(ny+1):nw), Qw(:,1:ny)]; + endif + Ry = Ry(1:ny,:)'; + + ## transform P by Qz/Ru and Qw/Ry + Bw = Bw*Qw; + Bu = Bu/Ru; + B = [Bw, Bu]; + Cz = Qz*Cz; + Cy = Ry\Cy; + C = [Cz; Cy]; + Dzw = Qz*Dzw*Qw; + Dzu = Qz*Dzu/Ru; + Dyw = Ry\Dyw*Qw; + + ## pack the return structure + dgkf_struct.nw = nw; + dgkf_struct.nu = nu; + dgkf_struct.nz = nz; + dgkf_struct.ny = ny; + dgkf_struct.A = A; + dgkf_struct.Bw = Bw; + dgkf_struct.Bu = Bu; + dgkf_struct.Cz = Cz; + dgkf_struct.Cy = Cy; + dgkf_struct.Dzw = Dzw; + dgkf_struct.Dzu = Dzu; + dgkf_struct.Dyw = Dyw; + dgkf_struct.Dyu = Dyu; + dgkf_struct.Ru = Ru; + dgkf_struct.Ry = Ry; + dgkf_struct.Dyu_nz = Dyu_nz; + dgkf_struct.dflg = dflg; + +endfunction diff --git a/scripts/control/base/is_observable.m b/scripts/control/base/is_observable.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/is_observable.m @@ -0,0 +1,60 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{retval},@var{U}] =} is_observable (@var{a}, @var{c}@{,@var{tol}@}) +## @deftypefnx {Function File} {[@var{retval},@var{U}] =} is_observable (@var{sys}@{, @var{tol}@}) +## Logical check for system observability. +## +## Default: tol = 10*norm(a,'fro')*eps +## +## Returns 1 if the system @var{sys} or the pair (@var{a},@var{c}) is +## observable, 0 if not. +## +## @strong{See} @code{is_controllable} for detailed description of arguments +## and default values. +## @end deftypefn +## @seealso{size, rows, columns, length, is_matrix, is_scalar, and is_vector} + +## Author: A. S. Hodel +## Created: August 1993 +## Updated by John Ingram (ingraje@eng.auburn.edu) July 1996. + +function [retval, U] = is_observable (a, c, tol) + + if( nargin < 1) + usage("[retval,U] = is_observable(a , c {, tol})"); + elseif(is_struct(a)) + ## system form + if(nargin == 2) + tol = c; + elseif(nargin > 2) + usage("[retval,U] = is_observable(sys {, tol})"); + endif + [a,b,c] = sys2ss(a); + elseif(nargin > 3) + usage("[retval,U] = is_observable(a , c {, tol})"); + endif + if(exist("tol")) + [retval,U] = is_controllable (a', c', tol); + else + [retval,U] = is_controllable (a', c'); + endif + +endfunction + diff --git a/scripts/control/base/is_stabilizable.m b/scripts/control/base/is_stabilizable.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/is_stabilizable.m @@ -0,0 +1,89 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{retval}, @var{U}] =} is_stabilizable (@var{sys}@{, @var{tol}@}) +## @deftypefnx {Function File } {[@var{retval}, @var{U}] =} is_stabilizable (@var{a}@{, @var{b} ,@var{tol}@}) +## Logical check for system stabilizability (i.e., all unstable modes are controllable). +## +## Test for stabilizability is performed via an ordered Schur decomposition +## that reveals the unstable subspace of the system @var{A} matrix. +## +## Returns @code{retval} = 1 if the system, @code{a}, is stabilizable, +## if the pair (@code{a}, @code{b}) is stabilizable, or 0 if not. +## @code{U} = orthogonal basis of controllable subspace. +## +## Controllable subspace is determined by applying Arnoldi iteration with +## complete re-orthogonalization to obtain an orthogonal basis of the +## Krylov subspace. +## @example +## span ([b,a*b,...,a^ b]). +## @end example +## tol is a roundoff paramter, set to 200*eps if omitted. +## @end deftypefn + +## See also: size, rows, columns, length, is_matrix, is_scalar, is_vector +## is_observable, is_stabilizable, is_detectable + +## Author: A. S. Hodel +## Created: August 1993 +## Updated by A. S. Hodel (scotte@eng.auburn.edu) Aubust, 1995 to use krylovb +## Updated by John Ingram (ingraje@eng.auburn.edu) July, 1996 to accept systems + +function [retval, U] = is_stabilizable (a, b, tol) + + if(nargin < 1) usage("[retval,U] = is_stabilizable(a {, b ,tol})"); + elseif(is_struct(a)) + ## sustem passed. + if(nargin == 2) + tol = b; % get tolerance + elseif(nargin > 2) + usage("[retval,U] = is_stabilizable(sys{,tol})"); + endif + [a,b] = sys2ss(sys); + else + ## a,b arguments sent directly. + if(nargin > 3) + usage("[retval,U] = is_stabilizable(a {, b ,tol})"); + endif + endif + + if(exist("tol")) + [retval,U] = is_controllable(a,b,tol); + else + [retval,U] = is_controllable(a,b); + tol = 1e2*rows(b)*eps; + endif + + if( !retval & columns(U) > 0) + ## now use an ordered Schur decomposition to get an orthogonal + ## basis of the unstable subspace... + n = rows(a); + [ua, s] = schur (-(a+eye(n)*tol), "A"); + k = sum( real(eig(a)) >= 0 ); # count unstable poles + + if( k > 0 ) + ua = ua(:,1:k); + ## now see if span(ua) is contained in span(U) + retval = (norm(ua - U*U'*ua) < tol); + else + retval = 1; # all poles stable + endif + endif + +endfunction diff --git a/scripts/control/base/is_stable.m b/scripts/control/base/is_stable.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/is_stable.m @@ -0,0 +1,76 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retval} =} is_stable (@var{a}@{,@var{tol},@var{dflg}@}) +## @deftypefnx {Function File} {@var{retval} =} is_stable (@var{sys}@{,@var{tol}@}) +## Returns retval = 1 if the matrix @var{a} or the system @var{sys} +## is stable, or 0 if not. +## +## @strong{Inputs} +## @table @var +## @item tol +## is a roundoff paramter, set to 200*@var{eps} if omitted. +## @item dflg +## Digital system flag (not required for system data structure): +## @table @code +## @item @var{dflg} != 0 +## stable if eig(a) in unit circle +## +## @item @var{dflg} == 0 +## stable if eig(a) in open LHP (default) +## @end table +## @end table +## @end deftypefn +## @seealso{size, rows, columns, length, is_matrix, is_scalar, is_vector +## is_observable, is_stabilizable, is_detectable, krylov, and krylovb} + +## Author: A. S. Hodel +## Created: August 1993 +## Updated by John Ingram (ingraje@eng.auburn.edu) July, 1996 for systems +## Updated to simpler form by a.s.hodel 1998 + +function retval = is_stable (a, tol, disc) + + if( (nargin < 1) | (nargin > 3) ) usage("is_stable(a {,tol,disc})"); + elseif(is_struct(a)) + ## system was passed + if(nargin < 3) disc = is_digital(a); + elseif(disc != is_digital(a)) + warning("is_stable: disc =%d does not match system",disc) + endif + sys = sysupdate(a,"ss"); + a = sys2ss(sys); + else + if(nargin < 3) disc = 0; endif + if(is_square(a) == 0) + error("A(%dx%d) must be square",rows(A), columns(A)); + endif + endif + + if(nargin < 2) tol = 200*eps; + elseif( !is_scalar(tol) ) + error("is_stable: tol(%dx%d) must be a scalar",rows(tol),columns(tol)); + endif + + l = eig(a); + if(disc) nbad = sum(abs(l)*(1+tol) > 1); + else nbad = sum(real(l)+tol > 0); endif + retval = (nbad == 0); + +endfunction diff --git a/scripts/control/base/lqe.m b/scripts/control/base/lqe.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/lqe.m @@ -0,0 +1,109 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{k}, @var{p}, @var{e}] =} lqe (@var{a}, @var{g}, @var{c}, @var{sigw}, @var{sigv}, @var{z}) +## Construct the linear quadratic estimator (Kalman filter) for the +## continuous time system +## @iftex +## @tex +## $$ +## {dx\over dt} = A x + B u +## $$ +## $$ +## y = C x + D u +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## dx +## -- = a x + b u +## dt +## +## y = c x + d u +## @end example +## +## @end ifinfo +## where @var{w} and @var{v} are zero-mean gaussian noise processes with +## respective intensities +## +## @example +## sigw = cov (w, w) +## sigv = cov (v, v) +## @end example +## +## The optional argument @var{z} is the cross-covariance +## @code{cov (@var{w}, @var{v})}. If it is omitted, +## @code{cov (@var{w}, @var{v}) = 0} is assumed. +## +## Observer structure is @code{dz/dt = A z + B u + k (y - C z - D u)} +## +## The following values are returned: +## +## @table @var +## @item k +## The observer gain, +## @iftex +## @tex +## $(A - K C)$ +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{k}@var{c}) +## @end ifinfo +## is stable. +## +## @item p +## The solution of algebraic Riccati equation. +## +## @item e +## The vector of closed loop poles of +## @iftex +## @tex +## $(A - K C)$. +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{k}@var{c}). +## @end ifinfo +## @end table +## @end deftypefn + +## Author: A. S. Hodel +## Created: August 1993 + +function [k, p, e] = lqe (a, g, c, sigw, sigv, zz) + + if ( (nargin != 5) && (nargin != 6)) + error ("lqe: invalid number of arguments"); + endif + + ## The problem is dual to the regulator design, so transform to lqr + ## call. + + if (nargin == 5) + [k, p, e] = lqr (a', c', g*sigw*g', sigv); + else + [k, p, e] = lqr (a', c', g*sigw*g', sigv, g*zz); + endif + + k = k'; + +endfunction diff --git a/scripts/control/base/lqg.m b/scripts/control/base/lqg.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/lqg.m @@ -0,0 +1,150 @@ +## Copyright (C) 1996, 1997 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{K}, @var{Q}, @var{P}, @var{Ee}, @var{Er}] =} lqg(@var{sys}, @var{Sigw}, @var{Sigv}, @var{Q}, @var{R}, @var{in_idx}) +## Design a linear-quadratic-gaussian optimal controller for the system +## @example +## dx/dt = A x + B u + G w [w]=N(0,[Sigw 0 ]) +## y = C x + v [v] ( 0 Sigv ]) +## @end example +## or +## @example +## x(k+1) = A x(k) + B u(k) + G w(k) [w]=N(0,[Sigw 0 ]) +## y(k) = C x(k) + v(k) [v] ( 0 Sigv ]) +## @end example +## +## @strong{Inputs} +## @table @var +## @item sys +## system data structure +## @item Sigw +## @itemx Sigv +## intensities of independent Gaussian noise processes (as above) +## @item Q +## @itemx R +## state, control weighting respectively. Control ARE is +## @item in_idx +## indices of controlled inputs +## +## default: last dim(R) inputs are assumed to be controlled inputs, all +## others are assumed to be noise inputs. +## @end table +## @strong{Outputs} +## @table @var +## @item K +## system data structure format LQG optimal controller (Obtain A,B,C +## matrices with @code{sys2ss}, @code{sys2tf}, or @code{sys2zp} as +## appropriate) +## @item P +## Solution of control (state feedback) algebraic Riccati equation +## @item Q +## Solution of estimation algebraic Riccati equation +## @item Ee +## estimator poles +## @item Es +## controller poles +## @end table +## @end deftypefn +## @seealso{h2syn, lqe, and lqr} + +## Author: A. S. Hodel +## Created: August 1995 +## revised for new system format August 1996 + +function [K, Q1, P1, Ee, Er] = lqg (sys, Sigw, Sigv, Q, R, input_list) + + if ( (nargin < 5) | (nargin > 6)) + usage("[K,Q1,P1,Ee,Er] = lqg(sys,Sigw, Sigv,Q,R{,input_list})"); + + elseif(!is_struct(sys) ) + error("sys must be in system data structure"); + endif + + DIG = is_digital(sys); + [A,B,C,D,tsam,n,nz,stname,inname,outname] = sys2ss(sys); + [n,nz,nin,nout] = sysdimensions(sys); + if(nargin == 5) + ## construct default input_list + input_list = (columns(Sigw)+1):nin; + endif + + if( !(n+nz) ) + error(["lqg: 0 states in system"]); + + elseif(nin != columns(Sigw)+ columns(R)) + error(["lqg: sys has ",num2str(nin)," inputs, dim(Sigw)=", ... + num2str(columns(Sigw)),", dim(u)=",num2str(columns(R))]) + + elseif(nout != columns(Sigv)) + error(["lqg: sys has ",num2str(nout)," outputs, dim(Sigv)=", ... + num2str(columns(Sigv)),")"]) + elseif(length(input_list) != columns(R)) + error(["lqg: length(input_list)=",num2str(length(input_list)), ... + ", columns(R)=", num2str(columns(R))]); + endif + + varname = list("Sigw","Sigv","Q","R"); + for kk=1:length(varname); + eval(sprintf("chk = is_square(%s);",nth(varname,kk))); + if(! chk ) error("lqg: %s is not square",nth(varname,kk)); endif + endfor + + ## permute (if need be) + if(nargin == 6) + all_inputs = sysreorder(nin,input_list); + B = B(:,all_inputs); + inname = inname(all_inputs); + endif + + ## put parameters into correct variables + m1 = columns(Sigw); + m2 = m1+1; + G = B(:,1:m1); + B = B(:,m2:nin); + + ## now we can just do the design; call dlqr and dlqe, since all matrices + ## are not given in Cholesky factor form (as in h2syn case) + if(DIG) + [Ks, P1, Er] = dlqr(A,B,Q,R); + [Ke, Q1, jnk, Ee] = dlqe(A,G,C,Sigw,Sigv); + else + [Ks, P1, Er] = lqr(A,B,Q,R); + [Ke, Q1, Ee] = lqe(A,G,C,Sigw,Sigv); + endif + Ac = A - Ke*C - B*Ks; + Bc = Ke; + Cc = -Ks; + Dc = zeros(rows(Cc),columns(Bc)); + + ## fix state names + stname1 = strappend(stname,"_e"); + + ## fix controller output names + outname1 = strappend(inname(m2:nin),"_K"); + + ## fix controller input names + inname1 = strappend(outname,"_K"); + + if(DIG) + K = ss2sys(Ac,Bc,Cc,Dc,tsam,n,nz,stname1,inname1,outname1,1:rows(Cc)); + else + K = ss2sys(Ac,Bc,Cc,Dc,tsam,n,nz,stname,inname1,outname1); + endif + +endfunction diff --git a/scripts/control/base/lqr.m b/scripts/control/base/lqr.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/lqr.m @@ -0,0 +1,174 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{k}, @var{p}, @var{e}] =} lqr (@var{a}, @var{b}, @var{q}, @var{r}, @var{z}) +## construct the linear quadratic regulator for the continuous time system +## @iftex +## @tex +## $$ +## {dx\over dt} = A x + B u +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## dx +## -- = A x + B u +## dt +## @end example +## +## @end ifinfo +## to minimize the cost functional +## @iftex +## @tex +## $$ +## J = \int_0^\infty x^T Q x + u^T R u +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## infinity +## / +## J = | x' Q x + u' R u +## / +## t=0 +## @end example +## @end ifinfo +## +## @noindent +## @var{z} omitted or +## @iftex +## @tex +## $$ +## J = \int_0^\infty x^T Q x + u^T R u + 2 x^T Z u +## $$ +## @end tex +## @end iftex +## @ifinfo +## +## @example +## infinity +## / +## J = | x' Q x + u' R u + 2 x' Z u +## / +## t=0 +## @end example +## +## @end ifinfo +## @var{z} included. +## +## The following values are returned: +## +## @table @var +## @item k +## The state feedback gain, +## @iftex +## @tex +## $(A - B K)$ +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{b}@var{k}) +## @end ifinfo +## is stable and minimizes the cost functional +## +## @item p +## The stabilizing solution of appropriate algebraic Riccati equation. +## +## @item e +## The vector of the closed loop poles of +## @iftex +## @tex +## $(A - B K)$. +## @end tex +## @end iftex +## @ifinfo +## (@var{a} - @var{b}@var{k}). +## @end ifinfo +## @end table +## +## @strong{Reference} +## Anderson and Moore, OPTIMAL CONTROL: LINEAR QUADRATIC METHODS, +## Prentice-Hall, 1990, pp. 56-58 +## @end deftypefn + +## Author: A. S. Hodel +## Created: August 1993. + +function [k, p, e] = lqr (a, b, q, r, s) + + ## disp("lqr: entry"); + + if ((nargin != 4) && (nargin != 5)) + error ("lqr: invalid number of arguments"); + endif + + ## Check a. + if ((n = is_square (a)) == 0) + error ("lqr: requires 1st parameter(a) to be square"); + endif + + ## Check b. + [n1, m] = size (b); + if (n1 != n) + error ("lqr: a,b not conformal"); + endif + + ## Check q. + if ( ((n1 = is_square (q)) == 0) || (n1 != n)) + error ("lqr: q must be square and conformal with a"); + endif + + ## Check r. + if ( ((m1 = is_square(r)) == 0) || (m1 != m)) + error ("lqr: r must be square and conformal with column dimension of b"); + endif + + ## Check if n is there. + if (nargin == 5) + [n1, m1] = size (s); + if ( (n1 != n) || (m1 != m)) + error ("lqr: z must be identically dimensioned with b"); + endif + + ## Incorporate cross term into a and q. + ao = a - (b/r)*s'; + qo = q - (s/r)*s'; + else + s = zeros (n, m); + ao = a; + qo = q; + endif + + ## Check that q, (r) are symmetric, positive (semi)definite + + if (is_symmetric (q) && is_symmetric (r) ... + && all (eig (q) >= 0) && all (eig (r) > 0)) + p = are (ao, (b/r)*b', qo); + k = r\(b'*p + s'); + e = eig (a - b*k); + else + error ("lqr: q (r) must be symmetric positive (semi) definite"); + endif + + ## disp("lqr: exit"); +endfunction diff --git a/scripts/control/base/lyap.m b/scripts/control/base/lyap.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/lyap.m @@ -0,0 +1,142 @@ +## Copyright (C) 1996, 1997 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place - Suite 330, Boston, MA +## 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} lyap (@var{a}, @var{b}, @var{c}) +## @deftypefnx {Function File} {} lyap (@var{a}, @var{b}) +## Solve the Lyapunov (or Sylvester) equation via the Bartels-Stewart +## algorithm (Communications of the ACM, 1972). +## +## If @var{a}, @var{b}, and @var{c} are specified, then @code{lyap} returns +## the solution of the Sylvester equation +## @iftex +## @tex +## $$ A X + X B + C = 0 $$ +## @end tex +## @end iftex +## @ifinfo +## @example +## a x + x b + c = 0 +## @end example +## @end ifinfo +## If only @code{(a, b)} are specified, then @code{lyap} returns the +## solution of the Lyapunov equation +## @iftex +## @tex +## $$ A^T X + X A + B = 0 $$ +## @end tex +## @end iftex +## @ifinfo +## @example +## a' x + x a + b = 0 +## @end example +## @end ifinfo +## If @var{b} is not square, then @code{lyap} returns the solution of either +## @iftex +## @tex +## $$ A^T X + X A + B^T B = 0 $$ +## @end tex +## @end iftex +## @ifinfo +## @example +## a' x + x a + b' b = 0 +## @end example +## @end ifinfo +## @noindent +## or +## @iftex +## @tex +## $$ A X + X A^T + B B^T = 0 $$ +## @end tex +## @end iftex +## @ifinfo +## @example +## a x + x a' + b b' = 0 +## @end example +## @end ifinfo +## @noindent +## whichever is appropriate. +## +## Solves by using the Bartels-Stewart algorithm (1972). +## @end deftypefn + +## Author: A. S. Hodel +## Created: August 1993 +## Adapted-By: jwe + +function x = lyap (a, b, c) + + if (nargin != 3 && nargin != 2) + usage ("lyap (a, b {,c})"); + endif + + if ((n = is_square(a)) == 0) + error ("lyap: a is not square"); + endif + + if (nargin == 2) + + ## Transform Lyapunov equation to Sylvester equation form. + + if ((m = is_square (b)) == 0) + if ((m = rows (b)) == n) + + ## solve a x + x a' + b b' = 0 + + b = b * b'; + a = a'; + else + + ## Try to solve a'x + x a + b' b = 0. + + m = columns (b); + b = b' * b; + endif + + if (m != n) + error ("lyap: a, b not conformably dimensioned"); + endif + endif + + ## Set up Sylvester equation. + + c = b; + b = a; + a = b'; + + else + + ## Check dimensions. + + if ((m = is_square (b)) == 0) + error ("lyap: b must be square in a sylvester equation"); + endif + + [n1, m1] = size(c); + + if (n != n1 || m != m1) + error("lyap: a,b,c not conformably dimensioned"); + endif + endif + + ## Call octave built-in function. + + x = syl (a, b, c); + +endfunction diff --git a/scripts/control/base/nichols.m b/scripts/control/base/nichols.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/nichols.m @@ -0,0 +1,117 @@ +## Copyright (C) 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## [mag,phase,w] = nichols(sys[,w,outputs,inputs]) +## Produce Nichols plot of a system +## +## Compute the frequency response of a system. +## inputs: +## sys: system data structure (must be either purely continuous or discrete; +## see is_digital) +## w: frequency values for evaluation. +## if sys is continuous, then nichols evaluates G(jw) +## if sys is discrete, then nichols evaluates G(exp(jwT)), where T=sys.tsam +## (the system sampling time) +## default: the default frequency range is selected as follows: (These +## steps are NOT performed if w is specified) +## (1) via routine bodquist, isolate all poles and zeros away from +## w=0 (jw=0 or exp(jwT)=1) and select the frequency +## range based on the breakpoint locations of the frequencies. +## (2) if sys is discrete time, the frequency range is limited +## to jwT in [0,2p*pi] +## (3) A "smoothing" routine is used to ensure that the plot phase does +## not change excessively from point to point and that singular +## points (e.g., crossovers from +/- 180) are accurately shown. +## outputs, inputs: the indices of the output(s) and input(s) to be used in +## the frequency response; see sysprune. +## outputs: +## mag, phase: the magnitude and phase of the frequency response +## G(jw) or G(exp(jwT)) at the selected frequency values. +## w: the vector of frequency values used +## If no output arguments are given, nichols plots the results to the screen. +## Descriptive labels are automatically placed. See xlabel, ylable, title, +## and replot. +## +## Note: if the requested plot is for an MIMO system, mag is set to +## ||G(jw)|| or ||G(exp(jwT))|| and phase information is not computed. + +function [mag, phase, w] = nichols (sys, w, outputs, inputs) + + ## check number of input arguments given + if (nargin < 1 | nargin > 4) + usage("[mag,phase,w] = nichols(sys[,w,outputs,inputs])"); + endif + if(nargin < 2) + w = []; + endif + if(nargin < 3) + outputs = []; + endif + if(nargin < 4) + inputs = []; + endif + + [f, w] = bodquist(sys,w,outputs,inputs,"nichols"); + + [stname,inname,outname] = sysgetsignals(sys); + systsam = sysgettsam(sys); + + ## Get the magnitude and phase of f. + mag = abs(f); + phase = arg(f)*180.0/pi; + + if (nargout < 1), + ## Plot the information + if(gnuplot_has_multiplot) + oneplot(); + endif + gset autoscale; + if(gnuplot_has_multiplot) + gset nokey; + endif + clearplot(); + grid("on"); + gset data style lines; + if(is_digital(sys)) + tistr = "(exp(jwT)) "; + else + tistr = "(jw)"; + endif + xlabel("Phase (deg)"); + if(is_siso(sys)) + title(["Nichols plot of |[Y/U]",tistr,"|, u=", ... + sysgetsignals(sys,"in",1,1), ", y=",sysgetsignals(sys,"out",1,1)]); + else + title([ "||Y(", tistr, ")/U(", tistr, ")||"]); + printf("MIMO plot from\n%s\nto\n%s\n",outlist(inname," "), ... + outlist(outname," ")); + endif + if(max(mag) > 0) + ylabel("Gain in dB"); + md = 20*log10(mag); + else + ylabel("Gain |Y/U|") + md = mag; + endif + + axvec = axis2dlim([vec(phase),vec(md)]); + axis(axvec); + plot(phase,md); + mag = phase = w = []; + endif +endfunction diff --git a/scripts/control/base/nyquist.m b/scripts/control/base/nyquist.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/nyquist.m @@ -0,0 +1,207 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{realp}, @var{imagp}, @var{w}] =} nyquist (@var{sys}@{, @var{w}, @var{out_idx}, @var{in_idx}, @var{atol}@}) +## @deftypefnx {Function File } {} nyquist (@var{sys}@{, @var{w}, @var{out_idx}, @var{in_idx}, @var{atol}@}) +## Produce Nyquist plots of a system; if no output arguments are given, Nyquist +## plot is printed to the screen. +## +## Compute the frequency response of a system. +## @strong{Inputs} (pass as empty to get default values) +## @table @var +## @item sys +## system data structure (must be either purely continuous or discrete; +## see is_digital) +## @item w +## frequency values for evaluation. +## if sys is continuous, then bode evaluates @math{G(jw)} +## if sys is discrete, then bode evaluates @math{G(exp(jwT))}, where +## @math{@var{T}=sysgettsam(@var{sys})} (the system sampling time) +## @item default +## the default frequency range is selected as follows: (These +## steps are NOT performed if @var{w} is specified) +## @end table +## @enumerate +## @item via routine bodquist, isolate all poles and zeros away from +## @var{w}=0 (@var{jw}=0 or @math{exp(@var{jwT})=1}) and select the frequency +## range based on the breakpoint locations of the frequencies. +## @item if @var{sys} is discrete time, the frequency range is limited +## to @var{jwT} in +## @ifinfo +## [0,2p*pi] +## @end ifinfo +## @iftex +## $[0,2p*\pi]$ +## @end iftex +## @item A "smoothing" routine is used to ensure that the plot phase does +## not change excessively from point to point and that singular +## points (e.g., crossovers from +/- 180) are accurately shown. +## @end enumerate +## outputs, inputs: the indices of the output(s) and input(s) to be used in +## the frequency response; see sysprune. +## +## @strong{Inputs} (pass as empty to get default values) +## @table @var +## @item atol +## for interactive nyquist plots: atol is a change-in-slope tolerance +## for the of asymptotes (default = 0; 1e-2 is a good choice). This allows +## the user to ``zoom in'' on portions of the Nyquist plot too small to be +## seen with large asymptotes. +## @end table +## @strong{Outputs} +## @table @var +## @item realp +## @itemx imagp +## the real and imaginary parts of the frequency response +## @math{G(jw)} or @math{G(exp(jwT))} at the selected frequency values. +## @item w +## the vector of frequency values used +## @end table +## +## If no output arguments are given, nyquist plots the results to the screen. +## If @var{atol} != 0 and asymptotes are detected then the user is asked +## interactively if they wish to zoom in (remove asymptotes) +## Descriptive labels are automatically placed. +## +## Note: if the requested plot is for an MIMO system, a warning message is +## presented; the returned information is of the magnitude +## ||G(jw)|| or ||G(exp(jwT))|| only; phase information is not computed. +## @end deftypefn + +## Author: R. Bruce Tenison +## Created: July 13, 1994 +## A. S. Hodel July 1995 (adaptive frequency spacing, +## remove acura parameter, etc.) +## Revised by John Ingram July 1996 for system format + +function [realp, imagp, w] = nyquist (sys, w, outputs, inputs, atol) + + ## Both bode and nyquist share the same introduction, so the common + ## parts are in a file called bodquist.m. It contains the part that + ## finds the number of arguments, determines whether or not the system + ## is SISO, andd computes the frequency response. Only the way the + ## response is plotted is different between the two functions. + + ## check number of input arguments given + if (nargin < 1 | nargin > 5) + usage("[realp,imagp,w] = nyquist(sys[,w,outputs,inputs,atol])"); + endif + if(nargin < 2) + w = []; + endif + if(nargin < 3) + outputs = []; + endif + if(nargin < 4) + inputs = []; + endif + if(nargin < 5) + atol = 0; + elseif(!(is_sample(atol) | atol == 0)) + error("atol must be a nonnegative scalar.") + endif + + ## signal to bodquist who's calling + + [f,w] = bodquist(sys,w,outputs,inputs,"nyquist"); + + ## Get the real and imaginary part of f. + realp = real(f); + imagp = imag(f); + + ## No output arguments, then display plot, otherwise return data. + if (nargout == 0) + dnplot = 0; + while(!dnplot) + if(gnuplot_has_multiplot) + oneplot(); + gset key; + endif + clearplot(); + grid ("on"); + gset data style lines; + + if(is_digital(sys)) + tstr = " G(e^{jw}) "; + else + tstr = " G(jw) "; + endif + xlabel(["Re(",tstr,")"]); + ylabel(["Im(",tstr,")"]); + + [stn, inn, outn] = sysgetsignals(sys); + if(is_siso(sys)) + title(sprintf("Nyquist plot from %s to %s, w (rad/s) in [%e, %e]", ... + nth(inn,1), nth(outn,1), w(1), w(length(w))) ) + endif + + gset nologscale xy; + + axis(axis2dlim([[vec(realp),vec(imagp)];[vec(realp),-vec(imagp)]])); + plot(realp,imagp,"- ;+w;",realp,-imagp,"-@ ;-w;"); + + ## check for interactive plots + dnplot = 1; # assume done; will change later if atol is satisfied + if(atol > 0 & length(f) > 2) + + ## check for asymptotes + fmax = max(abs(f)); + fi = max(find(abs(f) == fmax)); + + ## compute angles from point to point + df = diff(f); + th = atan2(real(df),imag(df))*180/pi; + + ## get angle at fmax + if(fi == length(f)) fi = fi-1; endif + thm = th(fi); + + ## now locate consecutive angles within atol of thm + ith_same = find(abs(th - thm) < atol); + ichk = union(fi,find(diff(ith_same) == 1)); + + ## locate max, min consecutive indices in ichk + loval = max(complement(ichk,1:fi)); + if(isempty(loval)) loval = fi; + else loval = loval + 1; endif + + hival = min(complement(ichk,fi:length(th))); + if(isempty(hival)) hival = fi+1; endif + + keep_idx = complement(loval:hival,1:length(w)); + + if(length(keep_idx)) + resp = input("Remove asymptotes and zoom in (y or n): ",1); + if(resp(1) == "y") + dnplot = 0; # plot again + w = w(keep_idx); + f = f(keep_idx); + realp = real(f); + imagp = imag(f); + endif + endif + + endif + endwhile + w = []; + realp=[]; + imagp=[]; + endif + +endfunction diff --git a/scripts/control/base/obsv.m b/scripts/control/base/obsv.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/obsv.m @@ -0,0 +1,65 @@ +## Copyright (C) 1997 Kai P. Mueller +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +##@deftypefn {Function File} {@var{Qb} =} obsv (@var{sys}@{, @var{c}@}) +## Build observability matrix +## @example +## @group +## | C | +## | CA | +## Qb = | CA^2 | +## | ... | +## | CA^(n-1) | +## @end group +## @end example +## of a system data structure or the pair (A, C). +## +## Note: @code{obsv()} forms the observability matrix. +## +## The numerical properties of is_observable() +## are much better for observability tests. +## @end deftypefn + +## Author: Kai P. Mueller +## Created: November 4, 1997 + +function Qb = obsv (sys, c) + + if (nargin == 2) + a = sys; + elseif (nargin == 1 && is_struct(sys)) + sysupdate(sys,"ss"); + [a,b,c] = sys2ss(sys); + else + usage("obsv(sys [, c])") + endif + + if (!is_abcd(a,c')) + Qb = []; + else + ## no need to check dimensions, we trust is_abcd(). + [na, ma] = size(a); + [nc, mc] = size(c); + Qb = zeros(na*nc, ma); + for i = 1:na + Qb((i-1)*nc+1:i*nc, :) = c; + c = c * a; + endfor + endif +endfunction diff --git a/scripts/control/base/rldemo.m b/scripts/control/base/rldemo.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/rldemo.m @@ -0,0 +1,302 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +##@deftypefn {Function File} {@var{outputs} =} rldemo (@var{inputs}) +##Octave Controls toolbox demo: Root Locus demo +##@end deftypefn + +## Author: David Clem +## Created: August 15, 1994 +## Updated by John Ingram December 1996 + +function rldemo () + + while (1) + clc + k = menu("Octave Root Locus Demo", ... + "Display continuous system's open loop poles and zeros (pzmap)", ... + "Display discrete system's open loop poles and zeros (pzmap)", ... + "Display root locus diagram of SISO continuous system (rlocus)", ... + "Display root locus diagram of SISO discrete system (rlocus)", ... + "Return to main demo menu"); + gset autoscale + if (k == 1) + clc + help pzmap + prompt + + clc + disp("Display continuous system's open loop poles and zeros (pzmap)\n"); + disp("Example #1, Consider the following continuous transfer function:"); + cmd = "sys1 = tf2sys([1.5, 18.5, 6], [1, 4, 155, 302, 5050]);"; + disp(cmd); + eval(cmd); + cmd ="sysout(sys1);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys1,""zp"");"; + disp(cmd); + eval(cmd); + disp("View the system's open loop poles and zeros with the command:") + cmd = "pzmap(sys1);"; + run_cmd + prompt + + clc + disp("Example #2, Consider the following set of poles and zeros:"); + cmd = "sys2 = zp2sys([-1, 5, -23],[-1, -10, -7+5i, -7-5i],5);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys2);"; + disp(cmd); + eval(cmd); + disp("\nThe pzmap command for the zp form is the same as the tf form:") + cmd = "pzmap(sys2);"; + run_cmd; + disp("\nThe internal representation of the system is not important;"); + disp("pzmap automatically sorts it out internally."); + prompt; + + clc + disp("Example #3, Consider the following state space system:\n"); + cmd = "sys3=ss2sys([0, 1; -10, -11], [0; 1], [0, -2], 1);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys3);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys3,""zp"");"; + disp(cmd); + eval(cmd); + disp("\nOnce again, the pzmap command is the same:"); + cmd = "pzmap(sys3);"; + run_cmd; + prompt; + + closeplot + clc + + elseif (k == 2) + clc + help pzmap + prompt + + clc + disp("\nDisplay discrete system's open loop poles and zeros (pzmap)\n"); + disp("First we must define a sampling time, as follows:\n"); + cmd = "Tsam = 1;"; + run_cmd; + disp("Example #1, Consider the following discrete transfer function:"); + cmd = "sys1 = tf2sys([1.05, -0.09048], [1, -2, 1],Tsam);"; + disp(cmd); + eval(cmd); + cmd ="sysout(sys1);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys1,""zp"");"; + disp(cmd); + eval(cmd); + disp("View the system's open loop poles and zeros with the command:") + cmd = "pzmap(sys1);"; + run_cmd + prompt + + clc + disp("Example #2, Consider the following set of discrete poles and zeros:"); + cmd = "sys2 = zp2sys(-0.717, [1, -0.368], 3.68, Tsam);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys2);"; + disp(cmd); + eval(cmd); + disp("\nThe pzmap command for the zp form is the same as the tf form:") + cmd = "pzmap(sys2);"; + run_cmd; + disp("\nThe internal representation of the system is not important;"); + disp("pzmap automatically sorts it out internally."); + prompt; + + clc + disp("Example #3, Consider the following discrete state space system:\n"); + cmd = "sys3=ss2sys([1, 0.0952; 0, 0.905], [0.00484; 0.0952], [1, 0], 0, Tsam);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys3);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys3,""zp"");"; + disp(cmd); + eval(cmd); + disp("\nOnce again, the pzmap command is the same:"); + cmd = "pzmap(sys3);"; + run_cmd; + prompt; + + closeplot + clc + + elseif (k == 3) + clc + help rlocus + prompt; + + clc + disp("Display root locus of a continuous SISO system (rlocus)\n") + disp("Example #1, Consider the following continuous transfer function:"); + cmd = "sys1 = tf2sys([1.5, 18.5, 6],[1, 4, 155, 302, 5050]);"; + disp(cmd); + eval(cmd); + cmd ="sysout(sys1);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys1,""zp"");"; + disp(cmd); + eval(cmd); + disp("\nWhen using rlocus, inital system poles are displayed as X's.") + disp("Moving poles are displayed as diamonds. Zeros are displayed as") + disp("boxes. The simplest form of the rlocus command is as follows:") + cmd = "rlocus(sys1);"; + run_cmd + disp("\nrlocus automatically selects the minimum and maximum gains based") + disp("on the real-axis locus breakpoints. The plot limits are chosen") + disp("to be no more than 10 times the maximum magnitude of the open") + disp("loop poles/zeros."); + prompt + + clc + disp("Example #2, Consider the following set of poles and zeros:"); + cmd = "sys2 = zp2sys([],[0, -20, -2, -0.1],5);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys2);"; + disp(cmd); + eval(cmd); + disp("\nThe rlocus command for the zp form is the same as the tf form:") + cmd = "rlocus(sys2);"; + run_cmd; + disp("\nThe internal representation of the system is not important;"); + disp("rlocus automatically sorts it out internally."); + prompt; + + clc + disp("Example #3, Consider the following state space system:\n"); + cmd = "sys3=ss2sys([0, 1; -10, -11], [0; 1], [0, -2], 0);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys3);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys3,""zp"");"; + disp(cmd); + eval(cmd); + disp("\nOnce again, the rlocus command is the same:"); + cmd = "rlocus(sys3);"; + run_cmd; + + disp("\nNo matter what form the system is in, the rlocus command works the"); + disp("the same."); + prompt; + + closeplot + clc + + elseif (k == 4) + clc + help rlocus + prompt + + clc + disp("Display root locus of a discrete SISO system (rlocus)\n") + disp("First we must define a sampling time, as follows:\n"); + cmd = "Tsam = 1;"; + run_cmd; + disp("Example #1, Consider the following discrete transfer function:"); + cmd = "sys1 = tf2sys([1.05, -0.09048],[1, -2, 1],Tsam);"; + disp(cmd); + eval(cmd); + cmd ="sysout(sys1);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys1,""zp"");"; + disp(cmd); + eval(cmd); + disp("\nWhen using rlocus, inital system poles are displayed as X's.") + disp("Moving poles are displayed as diamonds. Zeros are displayed as") + disp("boxes. The simplest form of the rlocus command is as follows:") + cmd = "rlocus(sys1);"; + run_cmd + disp("\nrlocus automatically selects the minimum and maximum gains based") + disp("on the real-axis locus breakpoints. The plot limits are chosen") + disp("to be no more than 10 times the maximum magnitude of the open") + disp("loop poles/zeros."); + prompt + + clc + disp("Example #2, Consider the following set of discrete poles and zeros:"); + cmd = "sys2 = zp2sys(-0.717, [1, -0.368], 3.68, Tsam);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys2);"; + disp(cmd); + eval(cmd); + disp("\nThe rlocus command for the zp form is the same as the tf form:") + cmd = "rlocus(sys2);"; + run_cmd; + disp("\nThe internal representation of the system is not important;"); + disp("rlocus automatically sorts it out internally. Also, it does not"); + disp("matter if the system is continuous or discrete. rlocus also sorts"); + disp("this out automatically"); + prompt; + + clc + disp("Example #3, Consider the following discrete state space system:\n"); + cmd = "sys3=ss2sys([1, 0.0952; 0, 0.905], [0.00484; 0.0952], [1, 0], 0, Tsam);"; + disp(cmd); + eval(cmd); + cmd = "sysout(sys3);"; + disp(cmd); + eval(cmd); + disp("\nPole-zero form can be obtained as follows:"); + cmd = "sysout(sys3,""zp"");"; + disp(cmd); + eval(cmd); + disp("\nOnce again, the rlocus command is the same:"); + cmd = "rlocus(sys3);"; + run_cmd; + + disp("\nNo matter what form the system is in, the rlocus command works the"); + disp("the same."); + + prompt; + + closeplot + clc + + elseif (k == 5) + return + endif + endwhile +endfunction diff --git a/scripts/control/base/rlocus.m b/scripts/control/base/rlocus.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/rlocus.m @@ -0,0 +1,202 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outputs} =} rlocus (@var{inputs}) +## @format +## [rldata, k] = rlocus(sys[,increment,min_k,max_k]) +## Displays root locus plot of the specified SISO system. +## +## ----- --- -------- +## --->| + |---|k|---->| SISO |-----------> +## ----- --- -------- | +## - ^ | +## |_____________________________| +## +## inputs: sys = system data structure +## min_k, max_k,increment: minimum, maximum values of k and +## the increment used in computing gain values +## Outputs: plots the root locus to the screen. +## rldata: Data points plotted column 1: real values, column 2: imaginary +## values) +## k: gains for real axis break points. +## @end format +## @end deftypefn + +## Author: David Clem +## Author: R. Bruce Tenison +## Updated by Kristi McGowan July 1996 for intelligent gain selection +## Updated by John Ingram July 1996 for systems + +function [rldata, k_break, rlpol, gvec, real_ax_pts] = rlocus (sys, increment, min_k, max_k) + + if (nargin < 1) | (nargin > 4) + usage("rlocus(sys[,inc,mink,maxk])"); + endif + + ## Convert the input to a transfer function if necessary + + [num,den] = sys2tf(sys) # extract numerator/denom polyomials + lnum = length(num); lden = length(den); + if(lden < 2) + error(sprintf("length of derivative=%d, doesn't make sense",lden)); + elseif(lnum == 1) + num = [0, num]; # so that derivative is shortened by one + endif + + ## root locus plot axis limits + + ## compute real axis locus breakpoints + ## compute the derivative of the numerator and the denominator + dern=polyderiv(num); derd=polyderiv(den); + + ## compute real axis breakpoints + real_ax_pol = conv(den,dern) - conv(num,derd); + real_ax_pts = roots(real_ax_pol); + if(isempty(real_ax_pts)) + k_break = []; + maxk = 0; + else + ## compute gains that achieve the breakpoints + c1 = polyval(num,real_ax_pts); + c2 = polyval(den,real_ax_pts); + k_break = -real(c2 ./ c1); + maxk = max(max(k_break,0)); + endif + + ## compute gain ranges based on computed K values + if(maxk == 0) maxk = 1; + else maxk = 1.1*maxk; endif + mink = 0; + ngain = 20; + + ## check for input arguments: + if (nargin > 2) mink = min_k; endif + if (nargin > 3) maxk = max_k; endif + if (nargin > 1) + if(increment <= 0) error("increment must be positive"); + else + ngain = (maxk-mink)/increment; + endif + endif + + ## vector of gains + ngain = max(3,ngain); + gvec = linspace(mink,maxk,ngain); + + ## Find the open loop zeros and the initial poles + rlzer = roots(num); + + ## update num to be the same length as den + lnum = length(num); if(lnum < lden) num = [zeros(1,lden - lnum),num]; endif + + ## compute preliminary pole sets + nroots = lden-1; + for ii=1:ngain + gain = gvec(ii); + rlpol(1:nroots,ii) = vec(sortcom(roots(den + gain*num))); + endfor + + ## compute axis limits (isolate asymptotes) + olpol = roots(den); + real_axdat = union(real(rlzer), real(union(olpol,real_ax_pts)) ); + rmin = min(real_axdat); rmax = max(real_axdat); + + rlpolv = [vec(rlpol); vec(real_axdat)]; + idx = find(real(rlpolv) >= rmin & real(rlpolv) <= rmax); + axlim = axis2dlim([real(rlpolv(idx)),imag(rlpolv(idx))]); + xmin = axlim(1); + xmax = axlim(2); + + ## set smoothing tolerance per axis limits + smtol = 0.01*max(abs(axlim)); + + ## smooth poles if necessary, up to maximum of 1000 gain points + ## only smooth points within the axis limit window + ## smoothing done if max_k not specified as a command argument + done=(nargin == 4); # perform a smoothness check + while((!done) & ngain < 1000) + done = 1 ; # assume done + dp = abs(diff(rlpol'))'; + maxd = max(dp); + ## search for poles in the real axis limits whose neighbors are distant + idx = find(maxd > smtol); + for ii=1:length(idx) + i1 = idx(ii); g1 = gvec(i1); p1 = rlpol(:,i1); + i2 = idx(ii)+1; g2 = gvec(i2); p2 = rlpol(:,i2); + + ## isolate poles in p1, p2 that are inside the real axis limits + bidx = find( (real(p1) >= xmin & real(p1) <= xmax) ... + | (real(p2) >= xmin & real(p2) <= xmax) ); + if(!isempty(bidx)) + p1 = p1(bidx); + p2 = p2(bidx); + if( max(abs(p2-p1)) > smtol) + newg = linspace(g1,g2,5); + newg = newg(2:4); + if(isempty(newg)) + printf("rlocus: empty newg") + g1 + g2 + i1 + i2 + idx_i1 = idx(ii) + gvec_i1 = gvec(i1:i2) + delta_vec_i1 = diff(gvec(i1:i2)) + prompt + endif + gvec = [gvec,newg]; + done = 0; # need to process new gains + endif + endif + endfor + + ## process new gain values + ngain1 = length(gvec); + for ii=(ngain+1):ngain1 + gain = gvec(ii); + rlpol(1:nroots,ii) = vec(sortcom(roots(den + gain*num))); + endfor + + [gvec,idx] = sort(gvec); + rlpol = rlpol(:,idx); + ngain = length(gvec); + endwhile + + ## Plot the data + if(nargout == 0) + rlpolv = vec(rlpol); + idx = find(real(rlpolv) >= xmin & real(rlpolv) <= xmax); + axdata = [real(rlpolv(idx)),imag(rlpolv(idx))]; + axlim = axis2dlim(axdata); + axlim(1:2) = [xmin, xmax]; + gset nologscale xy; + grid("on"); + rldata = [real(rlpolv), imag(rlpolv) ]; + axis(axlim); + [stn,inname,outname] = sysgetsignals(sys); + xlabel(sprintf("Root locus from %s to %s, gain=[%f,%f]: Real axis", ... + nth(inname,1),nth(outname,1),gvec(1),gvec(ngain))); + ylabel("Imag. axis"); + + plot(real(rlpolv),imag(rlpolv),".1;locus points;", ... + real(olpol),imag(olpol),"x2;open loop poles;", ... + real(rlzer),imag(rlzer),"o3;zeros;"); + rldata = []; + endif +endfunction diff --git a/scripts/control/base/step.m b/scripts/control/base/step.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/step.m @@ -0,0 +1,90 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{y}, @var{t}] =} step (@var{sys}@{, @var{inp},@var{tstop}, @var{n}@}) +## Step response for a linear system. +## The system can be discrete or multivariable (or both). +## If no output arguments are specified, @code{step} +## produces a plot or the step response data for system @var{sys}. +## +## @strong{Inputs} +## @table @var +## @item sys +## System data structure. +## @item inp +## Index of input being excited +## @item tstop +## The argument @var{tstop} (scalar value) denotes the time when the +## simulation should end. +## @item n +## the number of data values. +## +## Both parameters @var{tstop} and @var{n} can be omitted and will be +## computed from the eigenvalues of the A-Matrix. +## @end table +## @strong{Outputs} +## @var{y}, @var{t}: impulse response +## +## When invoked with the output paramter y the plot is not displayed. +## @end deftypefn +## @seealso{impulse and stepimp} + +## Author: Kai P. Mueller +## Created: September 30, 1997 +## based on lsim.m of Scottedward Hodel + +function [y, t] = step (sys, inp, tstop, n) + + if((nargin < 1) || (nargin > 4)) + usage("[y, u] = step(sys[, inp, tstop, n])"); + endif + + if(nargout > 2) + usage("[y, u] = step(sys[, inp, tstop, n])"); + endif + + if(!is_struct(sys)) + error("step: sys must be a system data structure."); + endif + + if (nargout == 0) + switch (nargin) + case (1) + stepimp(1, sys); + case (2) + stepimp(1, sys, inp); + case (3) + stepimp(1, sys, inp, tstop); + case (4) + stepimp(1, sys, inp, tstop, n); + endswitch + else + switch (nargin) + case (1) + [y, t] = stepimp(1, sys); + case (2) + [y, t] = stepimp(1, sys, inp); + case (3) + [y, t] = stepimp(1, sys, inp, tstop); + case (4) + [y, t] = stepimp(1, sys, inp, tstop, n); + endswitch + endif + +endfunction diff --git a/scripts/control/base/stepimp.m b/scripts/control/base/stepimp.m new file mode 100644 --- /dev/null +++ b/scripts/control/base/stepimp.m @@ -0,0 +1,279 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{y}, @var{t}] = } stepimp (@var{sitype}, @var{sys} [, @var{inp}, @var{tstop}, @var{n}]) +## Impulse or step response for a linear system. +## The system can be discrete or multivariable (or both). +## This m-file contains the "common code" of step and impulse. +## +## Produces a plot or the response data for system sys. +## +## Limited argument checking; "do not attempt to do this at home". +## Used internally in @code{impulse}, @code{step}. Use @code{step} +## or @code{impulse} instead. +## @end deftypefn +## @seealso{step and impulse} + +## Author: Kai P. Mueller +## Created: October 2, 1997 +## based on lsim.m of Scottedward Hodel + +function [y, t] = stepimp (sitype, sys, inp, tstop, n) + + if (sitype == 1) IMPULSE = 0; + elseif (sitype == 2) IMPULSE = 1; + else error("stepimp: invalid sitype argument.") + endif + sys = sysupdate(sys,"ss"); + + USE_DEF = 0; # default tstop and n if we have to give up + N_MIN = 50; # minimum number of points + N_MAX = 2000; # maximum number of points + T_DEF = 10.0; # default simulation time + + ## collect useful information about the system + [ncstates,ndstates,NIN,NOUT] = sysdimensions(sys); + TSAMPLE = sysgettsam(sys); + + if (nargin < 3) inp = 1; + elseif (inp < 1 | inp > NIN) error("Argument inp out of range") + endif + + DIGITAL = is_digital(sys); + if (DIGITAL) + NSTATES = ndstates; + if (TSAMPLE < eps) + error("stepimp: sampling time of discrete system too small.") + endif + else NSTATES = ncstates; endif + if (NSTATES < 1) + error("step: pure gain block (n_states < 1), step response is trivial"); + endif + if (nargin < 5) + ## we have to compute the time when the system reaches steady state + ## and the step size + ev = eig(sys2ss(sys)); + if (DIGITAL) + ## perform bilinear transformation on poles in z + for i = 1:NSTATES + pole = ev(i); + if (abs(pole + 1) < 1.0e-10) + ev(i) = 0; + else + ev(i) = 2 / TSAMPLE * (pole - 1) / (pole + 1); + endif + endfor + endif + ## remove poles near zero from eigenvalue array ev + nk = NSTATES; + for i = 1:NSTATES + if (abs(ev(i)) < 1.0e-10) + ev(i) = 0; + nk = nk - 1; + endif + endfor + if (nk == 0) + USE_DEF = 1; + ## printf("##STEPIMP-DEBUG: using defaults.\n"); + else + ev = ev(find(ev)); + x = max(abs(ev)); + t_step = 0.2 * pi / x; + x = min(abs(real(ev))); + t_sim = 5.0 / x; + ## round up + yy = 10^(ceil(log10(t_sim)) - 1); + t_sim = yy * ceil(t_sim / yy); + ## printf("##STEPIMP-DEBUG: nk=%d t_step=%f t_sim=%f\n", + ## nk, t_step, t_sim); + endif + endif + + if (DIGITAL) + ## ---- sampled system + if (nargin == 5) + n = round(n); + if (n < 2) + error("stepimp: n must not be less than 2.") + endif + else + if (nargin == 4) + ## n is unknown + elseif (nargin >= 1) + ## tstop and n are unknown + if (USE_DEF) + tstop = (N_MIN - 1) * TSAMPLE; + else + tstop = t_sim; + endif + endif + n = floor(tstop / TSAMPLE) + 1; + if (n < 2) n = 2; endif + if (n > N_MAX) + n = N_MAX; + printf("Hint: number of samples limited to %d by default.\n", \ + N_MAX); + printf(" ==> increase \"n\" parameter for longer simulations.\n"); + endif + endif + tstop = (n - 1) * TSAMPLE; + t_step = TSAMPLE; + else + ## ---- continuous system + if (nargin == 5) + n = round(n); + if (n < 2) + error("step: n must not be less than 2.") + endif + t_step = tstop / (n - 1); + else + if (nargin == 4) + ## only n in unknown + if (USE_DEF) + n = N_MIN; + t_step = tstop / (n - 1); + else + n = floor(tstop / t_step) + 1; + endif + else + ## tstop and n are unknown + if (USE_DEF) + tstop = T_DEF; + n = N_MIN; + t_step = tstop / (n - 1); + else + tstop = t_sim; + n = floor(tstop / t_step) + 1; + endif + endif + if (n < N_MIN) + n = N_MIN; + t_step = tstop / (n - 1); + endif + if (n > N_MAX) + tstop = (n - 1) * t_step; + t_step = tstop / (N_MAX - 1); + n = N_MAX; + endif + endif + tstop = (n - 1) * t_step; + [jnk,B] = sys2ss(sys); + B = B(:,inp); + sys = c2d(sys, t_step); + endif + ## printf("##STEPIMP-DEBUG: t_step=%f n=%d tstop=%f\n", t_step, n, tstop); + + F = sys.a; + G = sys.b(:,inp); + C = sys.c; + D = sys.d(:,inp); + y = zeros(NOUT, n); + t = linspace(0, tstop, n); + + if (IMPULSE) + if (!DIGITAL && (D'*D > 0)) + error("impulse: D matrix is nonzero, impulse response infinite.") + endif + if (DIGITAL) + y(:,1) = D / t_step; + x = G / t_step; + else + x = B; + y(:,1) = C * x; + x = F * x; + endif + for i = 2:n + y(:,i) = C * x; + x = F * x; + endfor + else + x = zeros(NSTATES, 1); + for i = 1:n + y(:,i) = C * x + D; + x = F * x + G; + endfor + endif + + if(nargout == 0) + ## Plot the information + oneplot(); + gset nogrid + gset nologscale + gset autoscale + gset nokey + clearplot(); + if (gnuplot_has_multiplot) + if (IMPULSE) + gm = zeros(NOUT, 1); + tt = "impulse"; + else + ssys = ss2sys(F, G, C, D, t_step); + gm = dcgain(ssys); + tt = "step"; + endif + ncols = floor(sqrt(NOUT)); + nrows = ceil(NOUT / ncols); + for i = 1:NOUT + subplot(nrows, ncols, i); + title(sprintf("%s: | %s -> %s", tt,sysgetsignals(sys,"in",inp,1), ... + sysgetsignals(sys,"out",i,1))); + if (DIGITAL) + [ts, ys] = stairs(t, y(i,:)); + ts = ts(1:2*n-2)'; ys = ys(1:2*n-2)'; + if (length(gm) > 0) + yy = [ys; gm(i)*ones(size(ts))]; + else + yy = ys; + endif + grid("on"); + xlabel("time [s]"); + ylabel("y(t)"); + plot(ts, yy); + else + if (length(gm) > 0) + yy = [y(i,:); gm(i)*ones(size(t))]; + else + yy = y(i,:); + endif + grid("on"); + xlabel("time [s]"); + ylabel("y(t)"); + plot(t, yy); + endif + endfor + ## leave gnuplot in multiplot mode is bad style + oneplot(); + else + ## plot everything in one diagram + title([tt, " response | ", sysgetsignals(sys,"in",inp,1), ... + " -> all outputs"]); + if (DIGITAL) + stairs(t, y(i,:)); + else + grid("on"); + xlabel("time [s]"); + ylabel("y(t)"); + plot(t, y(i,:)); + endif + endif + y=[]; + t=[]; + endif + ## printf("##STEPIMP-DEBUG: gratulations, successfull completion.\n"); +endfunction diff --git a/scripts/control/bddemo.m b/scripts/control/bddemo.m deleted file mode 100644 --- a/scripts/control/bddemo.m +++ /dev/null @@ -1,612 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outputs} =} bddemo (@var{inputs}) -## Octave Controls toolbox demo: Block Diagram Manipulations demo -## @end deftypefn - -## Author: David Clem -## Created: August 15, 1994 -## Modified by A S Hodel Summer-Fall 1996 - -function bddemo () - - sav_page = page_screen_output; - page_screen_output = 1; - - while (1) - clc - k=0; - while(k > 14 || k < 1) - k = menu("Octave Block Diagram Manipulations Demo", ... - "sysadd/syssub: F(s) = G(s) +/- H(s)", ... - "sysappend: add new inputs/outputs", ... - "syssetsignals: change names of inputs, outputs, and/or states", ... - "sysconnect: connect specified system inputs/outputs", ... - "syscont/sysdisc: extract the continuous (discrete) part of a system", ... - "sysdup: duplicate specified inputs/outputs", ... - "sysgroup: group two systems into a single system,", ... - "sysmult: F(s) = G(s)*H(s) (series connection)", ... - "sysprune: keep only specified inputs/outputs", ... - "sysscale: scale inputs/outputs by specified gain matrices", ... - "parallel: parallel connection of two systems", ... - "buildssic: the combination of all", ... - "Design examples:", ... - "Return to main demo menu"); - endwhile - if (k == 1) - clc - disp("sysadd: add two systems together") - disp("syssub: subtract F = G - H") - prompt - help sysadd - prompt - help syssub - prompt - disp("Example #1, \n") - cmd = "sys1 = tf2sys([1 -1],[1 2 1]);"; - run_cmd - cmd = "sys2 = tf2sys([1 -1],[1 2 3]);"; - run_cmd - disp("sys1=") - sysout(sys1); - prompt - disp("sys2=") - sysout(sys2); - cmd = "sys_sum1 = sysadd(sys1,sys1);"; - run_cmd - disp("This example adds sys1 to itself.") - cmd = "sysout(sys_sum1)"; - run_cmd - disp("Notice that the numerator is twice what it used to be.") - prompt - disp("Example 2:") - cmd = "sys_sub1 = syssub(sys1,sys2);"; - run_cmd - disp("Notice that sysadd (actually sysgroup, called by sysadd) lets you") - disp("know that your two systems had identical names for their states,") - disp("inputs and outputs. The warning message is perfectly harmless,") - disp("and is provided for user information only.") - disp("sys_sub1=") - sysout(sys_sub1) - disp("Notice that, since the two transfer functions had different") - disp("denominators, syssub converted the primary system type to ") - disp("state space. This is the typical behavior unless the") - disp("the two systems are both SISO, they both have the same poles,") - disp("and at least one of them has tf for its primary system type."); - prompt - elseif (k == 2) - disp("sysappend: add new inputs and/or outputs to a system") - help sysappend - prompt - disp("Consider a double-integrator system:") - sys = tf2sys(1, [1, 0, 0]); - sys=sysupdate(sys,"ss"); - sysout(sys,"ss"); - disp("We add a velocity disturbance input as follows:") - cmd = "sys1=sysappend(sys,[1;0]);"; - run_cmd - sysout(sys1,"ss"); - disp("Names of inputs can be included as follows:") - cmd = "sys1=sysappend(sys,[1;0], [],[],[],\"Disturb\");"; - run_cmd - disp("Notice that empty matrices can be listed for the D matrix if") - disp("all entries are zeros.") - disp(" ") - disp("sys1 is thus:") - sysout(sys1); - prompt - elseif (k == 3) - disp("syssetsignals:") - help syssetsignals - disp("Example system"); - a = rand(3,3); - b = rand(3,2); - c = rand(2,3); - sys = ss2sys(a,b,c); - sysout(sys); - prompt - disp("Change state names to larry, moe, and curly as follows:") - cmd = "sys = syssetsignals(sys,\"st\",list(\"larry\",\"moe \" , \"curly\"));"; - run_cmd - disp("Indicate that output 2 is discrete-time:") - cmd = "sys = syssetsignals(sys,\"yd\",1,2);"; - run_cmd - disp("Change output 2 name to \"Vir\""); - cmd = "sys = syssetsignals(sys,\"out\",\"Vir\",2);"; - run_cmd - disp("Resulting system is:") - sysout(sys); - prompt - elseif (k == 4) - help sysconnect - prompt - disp("********* N O T E *********") - disp("sysconnect is demonstrated fully in the design examples (option 13)"); - prompt - elseif (k == 5) - disp("syscont and sysdisc: ") - disp("Example block diagram 1:") - disp(" ------------------ ---------------------"); - disp(" u_in ->| Discrete system |--->| Continuous system | ---> y_out"); - disp(" ------------------ ---------------------"); - sys1 = tf2sys([1, 2],[1, 2, 1], 1,"u_in","y_disc"); - sys2 = tf2sys([1, 0],[1, -3, -2],0,"c_in","y_out"); - sys = sysmult(sys2,sys1); - disp("Consider the hybrid system") - sysout(sys); - prompt - help syscont - disp("The continuous part of the system can be extracted with syscont") - cmd = "[csys,Acd,Ccd] = syscont(sys);"; - run_cmd - disp("The resulting csys is") - sysout(csys); - disp("Notice that B is 0; there is no purely continuous path from the") - disp("input to the output"); - prompt - help sysdisc - disp("The discrete part of the system can be extracted with sysdisc") - cmd = "[dsys,Adc,Cdc] = sysdisc(sys)"; - run_cmd - disp("The resulting dsys is") - sysout(dsys); - disp("sysdisc returns dsys=empty since sys has no discrete outputs."); - prompt - disp("Example block diagram 2:") - sys1 = tf2sys([1, 2],[1, 2, 1], 1,"u_in","y_disc"); - sys2 = tf2sys([1, 0],[1, -3, -2],0,"c_in","y_out"); - disp(" ---------------------") - disp(" u_in -->o-->| Discrete system | --------> y_disc") - disp(" ^ --------------------- |") - disp(" | | "); - disp(" -----------------------------|---") - disp(" | |") - disp(" ------------------------------ |") - disp(" | |") - disp(" v --------------------- |") - disp(" c_in -->o-->| continuous system | --------> y_out") - disp(" ---------------------") - disp("repeat the above example with sys=") - sys = sysgroup(sys1, sys2); - sysout(sys) - prompt - sys = sysconnect(sys,[1, 2],[2, 1]); - sysout(sys); - cmd = "[csys,Acd,Bcd] = syscont(sys);"; - run_cmd - cmd = "[dsys,Acd,Bcd] = sysdisc(sys);"; - run_cmd - disp("csys is now") - sysout(csys) - disp("dsys is now") - sysout(dsys); - prompt - elseif (k == 6) - help sysdup - prompt - disp("********* N O T E *********") - disp("sysdup is fully demonstrated in the design examples (option 13)") - prompt - elseif (k == 7) - help sysgroup - disp(" ") - prompt - disp("Example: combine two SISO systems together:") - cmd = "sys_a=tf2sys([1, 2],[3, 4]);"; - run_cmd - cmd = "sys_b=tf2sys([5, 6],[7, 8],1);"; - run_cmd - cmd = "sys_g=sysgroup(sys_a,sys_b);"; - run_cmd - disp("Notice that sysgroup warns you when you join a purely continuous") - disp("system to a purely discrete system. sysgroup also warns when") - disp("you join two systems that have common state, input, or output names.") - cmd = "sysout(sys_g)"; - run_cmd - disp("Since the grouped system is a multiple-input multiple-output system,") - disp("the output system is by default in state-space format.") - disp(" ") - disp("********* N O T E *********") - disp("sysgroup is further demonstrated in the design examples (option 13)") - prompt - elseif (k == 8) - help sysmult - disp("sysmult performs a series connection of two systems.") - disp("Example 1") - disp(" ") - disp(" ---------- ----------") - disp(" u --->| Bsys |---->| Asys |---> y") - disp(" ---------- ----------") - disp(" ") - Asys = tf2sys(1,[1, 2, 1],0,"a_in","a_out"); - Bsys = tf2sys([2, 3],[1, 3, 2],0,"b_in","b_out"); - disp("Asys=") - sysout(Asys); - disp("Bsys="); - sysout(Bsys); - cmd = "sys = sysmult(Asys,Bsys);"; - run_cmd - disp("sys =") - sysout(sys); - disp("Notice that sysmult automatically transforms to state space") - disp("internal representation. This is to avoid numerical problems") - disp("when multiplying polynomials"); - prompt - disp("Example 2: same system, except that Bsys is discrete-time"); - Bsys = tf2sys([2, 3],[1, 3, 2],1e-2,"b_in","b_out"); - sysout(Bsys); - cmd = "sys = sysmult(Asys,Bsys);"; - run_cmd - disp("sys =") - sysout(sys); - prompt - elseif (k == 9) - help sysprune - prompt - disp("********* N O T E *********") - disp("sysprune is demonstrated in the design examples (option 13)"); - prompt - elseif (k == 10) - help sysscale - disp(" ") - prompt - disp("********* N O T E *********") - disp("See the design examples (option 13) for use of sysscale.") - prompt - elseif ( k == 11) - help parallel - disp("parallel operates by making a call to sysgroup and sysscale.") - disp("Example:") - sys1 = tf2sys(1,[1, 1],0,"in1","out1"); - sys2 = tf2sys(2,[1, 2],0,"in2","out2"); - disp("sys1=") - sysout(sys1); - disp("sys2=") - sysout(sys2); - cmd = "sysp = parallel(sys1,sys2);"; - run_cmd - disp("sysp=") - sysout(sysp); - prompt - disp("parallel can be used for multiple input systems as well:") - - in1 = list("u1.1","u1.2"); - in2 = list("u2.1","u2.2"); - out1 = list("y1.1","y1.2"); - out2 = list("y2.1","y2.2"); - - sys1 = ss2sys([-1, 0; 0, -2],eye(2),eye(2),[]); - sys2 = ss2sys([-2, 0; 0, -4],eye(2),eye(2),[]); - - sys1 = syssetsignals(sys1,"in",in1); - sys1 = syssetsignals(sys1,"out",out1); - - sys2 = syssetsignals(sys2,"in",in2); - sys2 = syssetsignals(sys2,"out",out2); - - disp("sys1=") - sysout(sys1); - disp("sys2=") - sysout(sys2); - cmd = "sysp = parallel(sys1,sys2);"; - run_cmd - disp("sysp=") - sysout(sysp); - prompt - elseif (k == 12) - ## buildssic description - disp(" ") - disp(" ---------------------------------------") - disp(" b u i l d s s i c") - disp(" (BUILD State Space InterConnections)") - disp(" ---------------------------------------") - disp(" ") - disp("buildssic builds a single system from up to 8 systems.") - disp("It's primary pupose is the forming of interconnections") - disp("for H2/H_inf designs and the building of closed loop") - disp("systems.") - disp("The interconnections may be of arbitrary complexity.") - disp("The use of buildssic is an alternative to sysgroup,") - disp("sysadd/syssub, sysappend, sysconnect, sysdup, sysmult") - disp("sysprune, sysscale, parallel etc.") - disp("In contrast to these functions buildssic does not") - disp("handle mixed continuous and discrete systems. However,") - disp("discrete systems can be connected as long as their") - disp("sampling times are identical. Another drawback: the") - disp("names of input/output and state variables are clobbered.") - disp("Of course, buildsysic is useful in combination with sysgroup,") - disp("sysmult etc.") - prompt - disp("********* N O T E *********") - disp("buildssic is demonstrated in the design examples (option 13)"); - prompt - elseif (k == 13) - disp("Design examples") - disp("Packed system matrices may be connected and manipulated") - disp("With the functions listed below:") - disp(" sysdup: duplicate selected inputs/outputs") - disp(" sysconnect: connect selected inputs/outputs") - disp(" sysgroup: group two systems together") - disp(" sysprune: prune a system to keep only selected inputs and outputs") - disp(" sysscale:pre/post multiply a system by constant matrices") - disp(" buildssic: connect systems with arbitrary complexity.") - prompt - disp("As a simple example, we will construct the system block ") - disp("diagram shown below ") - disp(" ") - disp(" + -------- --------"); - disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); - disp(" -^ -------- -------- |"); - disp(" | |"); - disp(" ------------------------------"); - disp(" ") - disp("where P(s) is the plant, K(s) is the controller.") - prompt - disp("Simple example: P(s) is a first order lag, K(s) is a PI ") - disp("controller") - nump = 1; - denp = [1, 1]; - disp("P(s)=") - tfout(nump,denp) - numk = [1, 1]; - denk = [1, 0]; - disp("\nK(s)=") - tfout(numk,denk); - prompt - disp("We'll show three approaches. ") - P = tf2sys(nump,denp,0,"plant input","plant output"); - K = tf2sys(numk, denk,0,"controller input","controller output"); - - meth = 0; - while(meth != 5) - disp("The first method consists of the following steps:") - disp(" step 1: create systems P and K") - disp(" step 2: group P and K together") - disp(" step 3: create a summing junction") - disp(" step 4: connect outputs to respective inputs") - disp(" step 5: prune the desired i/o connections") - disp("The second method is done as follows:") - disp(" step 1: create systems P and K and a summing block S") - disp(" step 2: connect P, K, and S in series") - disp(" step 3: connect y to inverted summing connection") - disp(" step 4: prune the desired i/o connections") - disp("The third method uses buildssic:") - disp(" step 1: GW = buildssic(...,K,P)") - disp(" ") - disp("Other design examples are in dgkfdemo (controldemo option 7)") - disp(" ") - meth = menu("Select design example method", ... - "Method 1 ", ... - "Method 1 (w/o algebraic loop warning)", ... - "Method 2", ... - "Method 3", ... - "Exit design examples"); - if(meth == 1) - disp(" * * * Method 1 * * *") - disp(" ") - disp(" + -------- --------"); - disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); - disp(" -^ -------- -------- |"); - disp(" | |"); - disp(" ------------------------------"); - disp(" ") - disp("Step 1: put plants in system format:"); - nump - denp - cmd = "P = tf2sys(nump,denp,0,""plant input"",""plant output"");"; - run_cmd - disp("P=") - sysout(P) - prompt - numk - denk - cmd = "K = tf2sys(numk, denk,0,""controller input"",""controller output"");"; - run_cmd - sysout(K) - prompt - disp("Step 2: group the systems together") - cmd = "PK = sysgroup(P,K);"; - run_cmd - disp("PK=") - sysout(PK); - prompt - disp(" ") - disp(" y2 u1") - disp(" + -------- --------"); - disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); - disp(" u2 -^ -------- -------- | y1"); - disp(" u3 | |"); - disp(" --------------------------------"); - disp(" ") - disp("The controller has two inputs summed together, r(t)") - disp("and the negative feedback of y(t)") - disp("Step 3a: duplicate controller input: (input 2 of PK)") - prompt - cmd = "PK = sysdup(PK,[],2);"; - run_cmd - disp("PK=") - sysout(PK); - disp("Notice that PK now has three inputs (input 3 is a duplicate "); - prompt("of input 2). Press return to go on") - disp("Step 3b: scale input 3 by -1") - cmd = "PK = sysscale(PK,[],diag([1, 1, -1]));"; - run_cmd - disp("PK=") - sysout(PK); - prompt - disp("Step 4: connect:") - disp(" y(t) (output 1) to the negative sum junction (input 3)") - disp(" u(t) (output 2) to plant input (input 1)") - disp("and prune extraneous inputs/outputs (retain input 2, output 1)") - prompt - out_connect = [1, 2] - in_connect = [3, 1] - cmd = "PK0 = sysconnect(PK,out_connect,in_connect);"; - run_cmd - prompt - disp("Notice that sysconnect detects the possibility of algebraic") - disp("connections when connecting inputs. Option 2 (Method 1 ") - disp("without algebraic loops) shows how to avoid this warning") - disp("by performing connections one at a time.") - prompt - disp("PK0=") - sysout(PK0); - disp("Notice that the connected inputs now have stars on their") - disp("names. This is how the Octave controls toolbox reminds you") - disp("that the loop has been closed around these inputs.") - prompt("Press return to prune extra inputs/outputs from system") - disp("Only keep plant output (output 1) and r(t) (input 2)") - cmd = "PK0 = sysprune(PK0,1,2);"; - run_cmd - disp("PK0=") - sysout(PK0); - prompt - disp("The resulting closed-loop transfer function is obtained as follows:") - cmd = "[num,den] = sys2tf(PK0);"; - run_cmd - prompt - disp("Transfer function is now") - tfout(num,den) - disp("You can check this: Pk0=PK/(1+PK), as expected") - prompt - elseif(meth == 2) - disp("Method 1 without algebraic loops") - disp(" ") - disp(" y2 u1") - disp(" + -------- --------"); - disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); - disp(" u2 -^ -------- -------- | y1"); - disp(" u3 | |"); - disp(" --------------------------------"); - disp(" ") - disp("Recall that sysconnect checks for algebraic loops. Although") - disp("Design option 1 gets a warning message about a possible"); - disp("algebraic loop, such a loop does not exist.") - disp("This can be seen by performing the connections one at a time"); - cmd = "PK = sysgroup(P,K);"; - run_cmd - disp("PK=") - sysout(PK); - disp("Create an additial inverted input to the controller.") - cmd = "PK = sysdup(PK,[],2);"; - run_cmd - cmd = "PK = sysscale(PK,[],diag([1,1,-1]));"; - run_cmd - disp("PK=") - sysout(PK); - disp("Connect controller to plant:") - cmd = "PK0 = sysconnect(PK,2,1);"; - run_cmd - disp("Plant output to negative control input") - cmd = "PK0 = sysconnect(PK0,1,3);"; - run_cmd - disp("Only keep plant output (output 1) and r(t) (input 2)") - cmd = "PK0 = sysprune(PK0,1,2);"; - run_cmd - disp("PK0=") - sysout(PK0); - prompt - disp("The transfer function form of PK0 is:") - sysout(PK0,"tf"); - prompt - elseif(meth == 3) - disp(" * * * Method 2 * * *") - disp(" ") - disp(" + -------- --------"); - disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); - disp(" -^ -------- -------- |"); - disp(" | |"); - disp(" ------------------------------"); - disp(" ") - disp("Step 1: We've already created systems P and K. Create a sum ") - disp("block as follows:") - cmd = "S = ss2sys([],[],[],[1, -1],0,0,0,[],list(""r(t)"",""y(t)""),""e(t)"");"; - run_cmd - disp("(You may wish to look at help ss2sys to see what the above does)"); - disp("S=") - sysout(S) - disp("notice that this is just a gain block that outputs e = r - y") - prompt - disp("Step 2: series connections of P, K, and S") - cmd = "PKS = sysmult(P,sysmult(K,S));"; - run_cmd - disp("PKS=") - sysout(PKS) - disp("Step 3: connect y to inverted input") - cmd = "PKcl = sysconnect(PKS,1,2);"; - run_cmd - disp("PKcl=") - sysout(PKcl) - disp("Step 4: prune desired inputs/outputs") - cmd = "PKcl=sysprune(PKcl,1,1);"; - run_cmd - disp("PKcl=") - sysout(PKcl) - prompt - elseif(meth == 4) - disp(" * * * Method 3 * * *") - disp(" ") - disp(" + -------- --------"); - disp(" r(t) ---> (+) --->| K(s) |--->| P(s) | ----> y(t)"); - disp(" -^ -------- -------- |"); - disp(" | |"); - disp(" ------------------------------"); - disp(" ") - disp("Step 1: We've already created systems P and K.") - disp(" Let us call buildssic:") - disp(" PKcl = buildssic([1, 2; 2, -1],[],[1],[2],P,K)") - disp(" ") - disp(" ^ ^ ^ ^ ^ ^") - disp(" | | | | | |") - disp(" Connection list ----+ | | | | |") - disp(" internal input list -----------+ | | | +-- controller") - disp(" output list --------------+ | |") - disp(" input list ------------------+ +---- plant") - disp(" ") - disp(" Connection list: connect input 1 (P) with output 2 (K)") - disp(" connect input 2 (K) with neg. outp. 1 (P)") - disp(" ") - disp(" int. inp. list: do not append internal inputs") - disp(" (e.g. the internal input of K (r-y))") - disp(" ") - disp(" output list: the only output is 1 (P), positive") - disp(" ") - disp(" input list: the only input is 2 (K), positive") - disp(" ") - cmd = "PKcl = buildssic([1, 2; 2, -1],[],[1],[2],P,K);" - run_cmd - sysout(PKcl) - prompt - disp("The transfer function form of PKcl is:") - sysout(PKcl,"tf"); - disp("You can check this: PKcl = PK / (1 + PK), as expected") - prompt - elseif(meth != 5) - disp("invalid selection") - endif - endwhile - - elseif (k == 14) - return - endif - endwhile - implict_str_to_num_ok = str_sav; - page_screen_output = sav_page; -endfunction diff --git a/scripts/control/bode.m b/scripts/control/bode.m deleted file mode 100644 --- a/scripts/control/bode.m +++ /dev/null @@ -1,212 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{mag}, @var{phase}, @var{w}] =} bode(@var{sys}@{,@var{w}, @var{out_idx}, @var{in_idx}@}) -## If no output arguments are given: produce Bode plots of a system; otherwise, -## compute the frequency response of a system data structure -## -## @strong{Inputs} -## @table @var -## @item sys -## a system data structure (must be either purely continuous or discrete; -## see is_digital) -## @item w -## frequency values for evaluation. -## -## if @var{sys} is continuous, then bode evaluates @math{G(jw)} where -## @math{G(s)} is the system transfer function. -## -## if @var{sys} is discrete, then bode evaluates G(@code{exp}(jwT)), where -## @itemize @bullet -## @item @var{T}=@code{sysgettsam(@var{sys})} (the system sampling time) and -## @item @math{G(z)} is the system transfer function. -## @end itemize -## -## @strong{ Default} the default frequency range is selected as follows: (These -## steps are NOT performed if @var{w} is specified) -## @enumerate -## @item via routine bodquist, isolate all poles and zeros away from -## @var{w}=0 (@var{jw}=0 or @math{@code{exp}(jwT)}=1) and select the frequency -## range based on the breakpoint locations of the frequencies. -## @item if @var{sys} is discrete time, the frequency range is limited -## to @math{jwT} in -## @ifinfo -## [0,2 pi /T] -## @end ifinfo -## @iftex -## @tex -## $[0,2\pi/T]$ -## @end tex -## @end iftex -## @item A "smoothing" routine is used to ensure that the plot phase does -## not change excessively from point to point and that singular -## points (e.g., crossovers from +/- 180) are accurately shown. -## -## @end enumerate -## @item out_idx -## @itemx in_idx -## the indices of the output(s) and input(s) to be used in -## the frequency response; see @code{sysprune}. -## @end table -## @strong{Outputs} -## @table @var -## @item mag -## @itemx phase -## the magnitude and phase of the frequency response @math{G(jw)} or -## @math{G(@code{exp}(jwT))} at the selected frequency values. -## @item w -## the vector of frequency values used -## @end table -## -## @strong{Notes} -## @enumerate -## @item If no output arguments are given, e.g., -## @example -## bode(sys); -## @end example -## bode plots the results to the screen. Descriptive labels are -## automatically placed. -## -## Failure to include a concluding semicolon will yield some garbage -## being printed to the screen (@code{ans = []}). -## -## @item If the requested plot is for an MIMO system, mag is set to -## @math{||G(jw)||} or @math{||G(@code{exp}(jwT))||} -## and phase information is not computed. -## @end enumerate -## @end deftypefn - -## Author: John Ingram -## Created: July 10, 1996 -## Based on previous code by R. Bruce Tenison, July 13, 1994 -## Modified by David Clem November 13, 1994 -## again by A. S. Hodel July 1995 (smart plot range, etc.) -## Modified by Kai P. Mueller September 28, 1997 (multiplot mode) - -function [mag_r, phase_r, w_r] = bode (sys, w, outputs, inputs, plot_style) - - ## check number of input arguments given - if (nargin < 1 | nargin > 5) - usage("[mag,phase,w] = bode(sys[,w,outputs,inputs,plot_style])"); - endif - if(nargin < 2) - w = []; - endif - if(nargin < 3) - outputs = []; - endif - if(nargin < 4) - inputs = []; - endif - if(nargin < 5) - plot_style = "dB"; - endif - - if (strcmp (plot_style, "dB")) - do_db_plot = 1; - elseif (strcmp (plot_style, "mag")) - do_db_plot = 0; - else - error ("bode: invalid value of plot_style specified"); - endif - - [f, w] = bodquist(sys,w,outputs,inputs,"bode"); - - [stname,inname,outname] = sysgetsignals(sys); - systsam = sysgettsam(sys); - - ## Get the magnitude and phase of f. - mag = abs(f); - phase = arg(f)*180.0/pi; - - if (nargout < 1), - ## Plot the information - if(gnuplot_has_multiplot) - oneplot(); - endif - gset autoscale; - if(gnuplot_has_multiplot) - gset nokey; - endif - clearplot(); - gset data style lines; - if(is_digital(sys)) - xlstr = ["Digital frequency w=rad/sec. pi/T=",num2str(pi/systsam)]; - tistr = "(exp(jwT)) "; - else - xlstr = "Frequency in rad/sec"; - tistr = "(jw)"; - endif - xlabel(xlstr); - if(is_siso(sys)) - if (gnuplot_has_multiplot) - subplot(2,1,1); - endif - title(["|[Y/U]",tistr,"|, u=", nth(inname,1),", y=",nth(outname,1)]); - else - title([ "||Y(", tistr, ")/U(", tistr, ")||"]); - disp("MIMO plot from") - disp(outlist(inname," ")); - disp("to") - disp(outlist(outname," ")); - endif - wv = [min(w), max(w)]; - if(do_db_plot && max(mag) > 0) - ylabel("Gain in dB"); - md = 20*log10(mag); - axvec = axis2dlim([vec(w),vec(md)]); - axvec(1:2) = wv; - axis(axvec); - else - ylabel("Gain |Y/U|") - md = mag; - endif - - grid("on"); - if (do_db_plot) - semilogx(w,md); - else - loglog(w,md); - endif - if (is_siso(sys)) - if (gnuplot_has_multiplot) - subplot(2,1,2); - else - prompt("Press any key for phase plot"); - endif - axvec = axis2dlim([vec(w),vec(phase)]); - axvec(1:2) = wv; - axis(axvec); - xlabel(xlstr); - ylabel("Phase in deg"); - title([ "phase([Y/U]", tistr, ... - "), u=", nth(inname,1),", y=",nth(outname,1)]); - grid("on"); - semilogx(w,phase); - ## This should be the default for subsequent plot commands. - if(gnuplot_has_multiplot) - oneplot(); - endif - endif - else - mag_r = mag; - phase_r = phase; - w_r = w; - endif -endfunction diff --git a/scripts/control/bode_bounds.m b/scripts/control/bode_bounds.m deleted file mode 100644 --- a/scripts/control/bode_bounds.m +++ /dev/null @@ -1,74 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{wmin}, @var{wmax}] =} bode_bounds (@var{zer}, @var{pol}, @var{dflg}@{, @var{tsam} @}) -## Get default range of frequencies based on cutoff frequencies of system -## poles and zeros. -## Frequency range is the interval [10^wmin,10^wmax] -## -## Used internally in freqresp (@code{bode}, @code{nyquist}) -## @end deftypefn - -function [wmin, wmax] = bode_bounds (zer, pol, DIGITAL, tsam) - - ## make sure zer,pol are row vectors - if(!isempty(pol)) pol = reshape(pol,1,length(pol)); endif - if(!isempty(zer)) zer = reshape(zer,1,length(zer)); endif - - ## check for natural frequencies away from omega = 0 - if (DIGITAL) - ## The 2nd conditions prevents log(0) in the next log command - iiz = find(abs(zer - 1) > norm(zer) * eps && abs(zer) > norm(zer) * eps); - iip = find(abs(pol - 1) > norm(pol) * eps && abs(pol) > norm(pol) * eps); - - ## avoid dividing empty matrices, it would work but looks nasty - if (!isempty(iiz)) czer = log(zer(iiz))/tsam; - else czer = []; endif - - if (!isempty(iip)) cpol = log(pol(iip))/tsam; - else cpol = []; endif - - else - ## continuous - iip = find((abs(pol)) > (norm(pol) * eps)); - iiz = find((abs(zer)) > (norm(zer) * eps)); - - if(!isempty(zer)) czer = zer(iiz); - else czer = []; endif - if(!isempty(pol)) cpol = pol(iip); - else cpol = []; endif - endif - - if(max(size(iip)) + max(size(iiz)) ) - wmin = floor(log10(min(abs([cpol,czer])))); - wmax = ceil(log10(max(abs([cpol,czer])))); - else - ## no poles/zeros away from omega = 0; pick defaults - wmin = -1; - wmax = 3; - endif - - ## expand to show the entirety of the "interesting" portion of the plot - wmin--; - wmax++; - - ## run digital frequency all the way to pi - if (DIGITAL) wmax = log10(pi/tsam); endif - -endfunction diff --git a/scripts/control/bodquist.m b/scripts/control/bodquist.m deleted file mode 100644 --- a/scripts/control/bodquist.m +++ /dev/null @@ -1,156 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{f}, @var{w}] =} bodquist (@var{sys}, @var{w}, @var{out_idx}, @var{in_idx}) -## used internally by bode, nyquist; compute system frequency response. -## -## @strong{Inputs} -## @table @var -## @item sys -## input system structure -## @item w -## range of frequencies; empty if user wants default -## @item out_idx -## list of outputs; empty if user wants all -## @item in_idx -## list of inputs; empty if user wants all -## @item rname -## name of routine that called bodquist ("bode" or "nyquist") -## @end table -## @strong{Outputs} -## @table @var -## @item w -## list of frequencies -## @item f -## frequency response of sys; @math{f(ii) = f(omega(ii))} -## @end table -## @strong{Note} bodquist could easily be incorporated into a Nichols -## plot function; this is in a "to do" list. -## -## Both bode and nyquist share the same introduction, so the common parts are -## in bodquist. It contains the part that finds the number of arguments, -## determines whether or not the system is SISO, and computes the frequency -## response. Only the way the response is plotted is different between the -## two functions. -## @end deftypefn - -function [f, w] = bodquist (sys, w, outputs, inputs, rname) - - ## check number of input arguments given - if (nargin != 5) - usage("[f,w] = bodquist(sys,w,outputs,inputs,rname)"); - endif - - ## check each argument to see if it's in the correct form - if (!is_struct(sys)) - error("sys must be a system data structure"); - endif - - ## let freqresp determine w if it's not already given - USEW = freqchkw(w); - - ## get initial dimensions (revised below if sysprune is called) - [nn,nz,mm,pp ] = sysdimensions(sys); - - ## check for an output vector and to see whether it`s correct - if (!isempty(outputs)) - if (isempty(inputs)) - inputs = 1:mm; # use all inputs - warning([rname,": outputs specified but not inputs"]); - endif - sys = sysprune(sys,outputs,inputs); - [nn,nz,mm,pp ] = sysdimensions(sys); - endif - - ## for speed in computation, convert local copy of - ## SISO state space systems to zero-pole form - if( is_siso(sys) & strcmp( sysgettype(sys), "ss") ) - [zer,pol,k,tsam,inname,outname] = sys2zp(sys); - sys = zp2sys(zer,pol,k,tsam,inname,outname); - endif - - ## get system frequency response - [f,w] = freqresp(sys,USEW,w); - - phase = arg(f)*180.0/pi; - - if(!USEW) - ## smooth plots - pcnt = 5; # max number of refinement steps - dphase = 5; # desired max change in phase - dmag = 0.2; # desired max change in magnitude - while(pcnt) - pd = abs(diff(phase)); # phase variation - pdbig = vec(find(pd > dphase)); - - lp = length(f); lp1 = lp-1; # relative variation - fd = abs(diff(f)); - fm = max(abs([f(1:lp1); f(2:lp)])); - fdbig = vec(find(fd > fm/10)); - - bigpts = union(fdbig, pdbig); - - if(isempty(bigpts) ) - pcnt = 0; - else - pcnt = pcnt - 1; - wnew = []; - crossover_points = find ( phase(1:lp1).*phase(2:lp) < 0); - pd(crossover_points) = abs(359.99+dphase - pd(crossover_points)); - np_pts = max(3,ceil(pd/dphase)+2); # phase points - nm_pts = max(3,ceil(log(fd./fm)/log(dmag))+2); # magnitude points - npts = min(5,max(np_pts, nm_pts)); - - w1 = log10(w(1:lp1)); - w2 = log10(w(2:lp)); - for ii=bigpts - if(npts(ii)) - wtmp = logspace(w1(ii),w2(ii),npts(ii)); - wseg(ii,1:(npts(ii)-2)) = wtmp(2:(npts(ii)-1)); - endif - endfor - wnew = vec(wseg)'; # make a row vector - wnew = wnew(find(wnew != 0)); - wnew = sort(wnew); - wnew = create_set(wnew); - if(isempty(wnew)) # all small crossovers - pcnt = 0; - else - [fnew,wnew] = freqresp(sys,1,wnew); # get new freq resp points - w = [w,wnew]; # combine with old freq resp - f = [f,fnew]; - [w,idx] = sort(w); # sort into order - f = f(idx); - phase = arg(f)*180.0/pi; - endif - endif - endwhile - endif - - ## ensure unique frequency values - [w,idx] = sort(w); - f = f(idx); - - w_diff = diff(w); - w_dup = find(w_diff == 0); - w_idx = complement(w_dup,1:length(w)); - w = w(w_idx); - f = f(w_idx); - -endfunction diff --git a/scripts/control/buildssic.m b/scripts/control/buildssic.m deleted file mode 100644 --- a/scripts/control/buildssic.m +++ /dev/null @@ -1,300 +0,0 @@ -## Copyright (C) 1998 Kai P. Mueller -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{sys} =} buildssic(@var{Clst}, @var{Ulst}, @var{Olst}, @var{Ilst}, @var{s1}, @var{s2}, @var{s3}, @var{s4}, @var{s5}, @var{s6}, @var{s7}, @var{s8}) -## -## Form an arbitrary complex (open or closed loop) system in -## state-space form from several systems. "@code{buildssic}" can -## easily (despite it's cryptic syntax) integrate transfer functions -## from a complex block diagram into a single system with one call. -## This function is especially useful for building open loop -## interconnections for H_infinity and H2 designs or for closing -## loops with these controllers. -## -## Although this function is general purpose, the use of "@code{sysgroup}" -## "@code{sysmult}", "@code{sysconnect}" and the like is recommended for -## standard operations since they can handle mixed discrete and continuous -## systems and also the names of inputs, outputs, and states. -## -## The parameters consist of 4 lists that describe the connections -## outputs and inputs and up to 8 systems s1-s8. -## Format of the lists: -## @table @var -## @item Clst -## connection list, describes the input signal of -## each system. The maximum number of rows of Clst is -## equal to the sum of all inputs of s1-s8. -## -## Example: -## @code{[1 2 -1; 2 1 0]} ==> new input 1 is old inpout 1 -## + output 2 - output 1, new input 2 is old input 2 -## + output 1. The order of rows is arbitrary. -## -## @item Ulst -## if not empty the old inputs in vector Ulst will -## be appended to the outputs. You need this if you -## want to "pull out" the input of a system. Elements -## are input numbers of s1-s8. -## -## @item Olst -## output list, specifiy the outputs of the resulting -## systems. Elements are output numbers of s1-s8. -## The numbers are alowed to be negative and may -## appear in any order. An empty matrix means -## all outputs. -## -## @item Ilst -## input list, specifiy the inputs of the resulting -## systems. Elements are input numbers of s1-s8. -## The numbers are alowed to be negative and may -## appear in any order. An empty matrix means -## all inputs. -## @end table -## -## Example: Very simple closed loop system. -## @example -## @group -## w e +-----+ u +-----+ -## --->o--*-->| K |--*-->| G |--*---> y -## ^ | +-----+ | +-----+ | -## - | | | | -## | | +----------------> u -## | | | -## | +-------------------------|---> e -## | | -## +----------------------------+ -## @end group -## @end example -## -## The closed loop system GW can be optained by -## @example -## GW = buildssic([1 2; 2 -1], 2, [1 2 3], 2, G, K); -## @end example -## @table @var -## @item Clst -## (1. row) connect input 1 (G) with output 2 (K). -## (2. row) connect input 2 (K) with neg. output 1 (G). -## @item Ulst -## append input of (2) K to the number of outputs. -## @item Olst -## Outputs are output of 1 (G), 2 (K) and appended output 3 (from Ulst). -## @item Ilst -## the only input is 2 (K). -## @end table -## -## Here is a real example: -## @example -## @group -## +----+ -## -------------------->| W1 |---> v1 -## z | +----+ -## ----|-------------+ || GW || => min. -## | | vz infty -## | +---+ v +----+ -## *--->| G |--->O--*-->| W2 |---> v2 -## | +---+ | +----+ -## | | -## | v -## u y -## @end group -## @end example -## -## The closed loop system GW from [z; u]' to [v1; v2; y]' can be -## obtained by (all SISO systems): -## @example -## GW = buildssic([1, 4; 2, 4; 3, 1], 3, [2, 3, 5], -## [3, 4], G, W1, W2, One); -## @end example -## where "One" is a unity gain (auxillary) function with order 0. -## (e.g. @code{One = ugain(1);}) -## @end deftypefn - -## Author: Kai P. Mueller -## Created: April 1998 - -function sys = buildssic (Clst, Ulst, Olst, Ilst, s1, s2, s3, s4, s5, s6, s7, s8) - - if((nargin < 5) || (nargin > 12)) - usage("sys = buildssic(Clst,Ulst,Olst,Ilst,s1,s2,s3,s4,s5,s6,s7,s8)"); - endif - if (nargin >= 5) - if (!is_struct(s1)) - error("---> s1 must be a structed system."); - endif - s1 = sysupdate(s1, "ss"); - [n, nz, m, p] = sysdimensions(s1); - if (!n && !nz) - error("---> pure static system must not be the first in list."); - endif - if (n && nz) - error("---> cannot handle mixed continuous and discrete systems."); - endif - D_SYS = (nz > 0); - [A,B,C,D,tsam] = sys2ss(s1); - nt = n + nz; - endif - for ii = 6:nargin - eval(["ss = s", num2str(ii-4), ";"]); - if (!is_struct(ss)) - error("---> Parameter must be a structed system."); - endif - ss = sysupdate(ss, "ss"); - [n1, nz1, m1, p1] = sysdimensions(ss); - if (n1 && nz1) - error("---> cannot handle mixed continuous and discrete systems."); - endif - if (D_SYS) - if (n1) - error("---> cannot handle mixed cont. and discr. systems."); - endif - if (tsam != sysgettsam(ss)) - error("---> sampling time of all systems must match."); - endif - endif - [as,bs,cs,ds] = sys2ss(ss); - nt1 = n1 + nz1; - if (!nt1) - ## pure gain (pad B, C with zeros) - B = [B, zeros(nt,m1)]; - C = [C; zeros(p1,nt)]; - else - A = [A, zeros(nt,nt1); zeros(nt1,nt), as]; - B = [B, zeros(nt,m1); zeros(nt1,m), bs]; - C = [C, zeros(p,nt1); zeros(p1,nt), cs]; - endif - D = [D, zeros(p,m1); zeros(p1,m), ds]; - n = n + n1; - nz = nz + nz1; - nt = nt + nt1; - m = m + m1; - p = p + p1; - endfor - - ## check maximum dimensions - [nx, mx] = size(Clst); - if (nx > m) - error("---> more rows in Clst than total number of inputs."); - endif - if (mx > p+1) - error("---> more cols in Clst than total number of outputs."); - endif - ## empty vector Ulst is OK - lul = length(Ulst); - if (lul) - if (!is_vector(Ulst)) - error("---> Input u list Ulst must be a vector."); - endif - if (lul > m) - error("---> more values in Ulst than number of inputs."); - endif - endif - if (!length(Olst)) Olst = [1:(p+lul)]; endif - if (!length(Ilst)) Ilst = [1:m]; endif - if (!is_vector(Olst)) - error("---> Output list Olst must be a vector."); - endif - if (!is_vector(Ilst)) - error("---> Input list Ilst must be a vector."); - endif - - ## build the feedback "K" from the interconnection data Clst - K = zeros(m, p); - inp_used = zeros(m,1); - for ii = 1:nx - xx = Clst(ii,:); - iu = xx(1); - if ((iu < 1) || (iu > m)) - error("---> invalid value in first col of Clst."); - endif - if (inp_used(iu)) - error("---> Input specified more than once."); - endif - inp_used(iu) = 1; - for kk = 2:mx - it = xx(kk); - if (abs(it) > p) - error("---> invalid row value in Clst."); - elseif (it) - K(iu,abs(it)) = sign(it); - endif - endfor - endfor - - ## form the "closed loop", i.e replace u in - ## . - ## x = Ax + Bu - ## ~ - ## y = Cx + Du by u = K*y+u - ## - ## -1 - ## R = (I-D*K) must exist. - - R = eye(p) - D*K; - if (rank(R) < p) - error("---> singularity in algebraic loop."); - else - R = inv(R); - endif - A = A + B*K*R*C; - B = B + B*K*R*D; - C = R*C; - D = R*D; - - ## append old inputs u to the outputs (if lul > 0) - kc = K*C; - kdi = eye(m) + K*D; - for ii = 1:lul - it = Ulst(ii); - if ((it < 1) || (it > m)) - error("---> invalid value in Ulst."); - endif - C = [C; kc(it,:)]; - D = [D; kdi(it,:)]; - endfor - - ## select and rearrange outputs - nn = length(A); - lol = length(Olst); - Cnew = zeros(lol,nn); - Dnew = zeros(lol,m); - for ii = 1:lol - iu = Olst(ii); - if (!iu || (abs(iu) > p+lul)) - error("---> invalid value in Olst."); - endif - Cnew(ii,:) = sign(iu)*C(abs(iu),:); - Dnew(ii,:) = sign(iu)*D(abs(iu),:); - endfor - C = Cnew; - D = Dnew; - lil = length(Ilst); - Bnew = zeros(nn,lil); - Dnew = zeros(lol,lil); - for ii = 1:lil - iu = Ilst(ii); - if (!iu || (abs(iu) > m)) - error("---> invalid value in Ilst."); - endif - Bnew(:,ii) = sign(iu)*B(:,abs(iu)); - Dnew(:,ii) = sign(iu)*D(:,abs(iu)); - endfor - - sys = ss2sys(A, Bnew, C, Dnew, tsam, n, nz); - -endfunction diff --git a/scripts/control/c2d.m b/scripts/control/c2d.m deleted file mode 100644 --- a/scripts/control/c2d.m +++ /dev/null @@ -1,175 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 John W. Eaton -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{dsys} =} c2d (@var{sys}@{, @var{opt}, @var{T}@}) -## @deftypefnx {Function File} {@var{dsys} =} c2d (@var{sys}@{, @var{T}@}) -## -## @strong{Inputs} -## @table @var -## @item sys -## system data structure (may have both continuous time and discrete -## time subsystems) -## @item opt -## string argument; conversion option (optional argument; -## may be omitted as shown above) -## @table @code -## @item "ex" -## use the matrix exponential (default) -## @item "bi" -## use the bilinear transformation -## @end table -## @example -## 2(z-1) -## s = ----- -## T(z+1) -## @end example -## FIXME: This option exits with an error if @var{sys} is not purely -## continuous. (The @code{ex} option can handle mixed systems.) -## @item @var{T} -## sampling time; required if sys is purely continuous. -## -## @strong{Note} If the 2nd argument is not a string, @code{c2d} assumes that -## the 2nd argument is @var{T} and performs appropriate argument checks. -## @end table -## -## @strong{Outputs} -## @var{dsys} discrete time equivalent via zero-order hold, -## sample each @var{T} sec. -## -## converts the system data structure describing -## @example -## . -## x = Ac x + Bc u -## @end example -## into a discrete time equivalent model -## @example -## x[n+1] = Ad x[n] + Bd u[n] -## @end example -## via the matrix exponential or bilinear transform -## -## @strong{Note} This function adds the suffix @code{_d} -## to the names of the new discrete states. -## @end deftypefn - -## Author: R. Bruce Tenison -## Created: October 1993 -## Updated by John Ingram for system data structure August 1996 - -function dsys = c2d (sys, opt, T) - ## parse input arguments - if(nargin < 1 | nargin > 3) - usage("dsys=c2d(sys[,T])"); - elseif (!is_struct(sys)) - error("sys must be a system data structure"); - elseif (nargin == 1) - opt = "ex"; - elseif (nargin == 2 & !isstr(opt) ) - T = opt; - opt = "ex"; - endif - - ## check if sampling period T was passed. - Ts = sysgettsam(sys); - if(!exist("T")) - T = Ts; - if(T == 0) - error("sys is purely continuous; no sampling period T provided"); - endif - elseif (T != Ts & Ts > 0) - warning(["c2d: T=",num2str(T),", system tsam==",num2str(Ts), ... - ": using T=", num2str(min(T,Ts))]); - T = min(T,Ts); - endif - - if (!is_sample(T)) - error("sampling period T must be a postive, real scalar"); - elseif( ! (strcmp(opt,"ex") | strcmp(opt,"bi") ) ) - error(["invalid option passed: ",opt]) - endif - - sys = sysupdate(sys,"ss"); - [n,nz,m,p] = sysdimensions(sys); - if(n == 0) - dsys = syssetsignals(sys,"yd",ones(1:p)); - elseif(strcmp(opt,"ex")); - [aa,bb,cc,dd] = sys2ss(sys); - crng= 1:n; - drng = n+(1:nz); - - ## partition state equations into continuous, imaginary subsystems - Ac = aa(crng,crng); - Bc = bb(crng,:); - if(nz == 0) - Acd = Adc = Add = Bd = 0; - else - Acd = aa(crng,drng); - Adc = aa(drng,crng); - Add = aa(drng,drng); - Bd = bb(drng,:); - Bc = [Bc, Acd]; ## append discrete states as inputs to cont system - endif - - ## convert state equations - mat = [Ac, Bc; zeros(m+nz,n+nz+m)]; - matexp = expm(mat * T); - - ## replace Ac - aa(crng,crng) = matexp(crng,crng); ## discretized homegenous diff eqn - - ## replace Bc - bb(crng,:) = matexp(crng,n+(1:m)); - - ## replace Acd - if(nz) - aa(crng,drng) = matexp(crng,n+m+(1:nz)); - end - - stnames = sysgetsignals(sys,"st"); ## continuous states renamed below - innames = sysgetsignals(sys,"in"); - outnames = sysgetsignals(sys,"out"); - outlist = 1:p; - dsys = ss2sys(aa,bb,cc,dd,T,0,n+nz,stnames,innames, ... - outnames,outlist); - ## rename states - for ii=1:n - strval = sprintf("%s_d",sysgetsignals(dsys,"st",ii,1)); - dsys = syssetsignals(dsys,"st",strval,ii); - endfor - - elseif(strcmp(opt,"bi")) - if(is_digital(sys)) - error("c2d: system is already digital") - else - ## convert with bilinear transform - [a,b,c,d,tsam,n,nz,stname,inname,outname,yd] = sys2ss(sys); - IT = (2/T)*eye(size(a)); - A = (IT+a)/(IT-a); - iab = (IT-a)\b; - tk=2/sqrt(T); - B = tk*iab; - C = tk*(c/(IT-a)); - D = d + (c*iab); - stnamed = strappend(stname,"_d"); - dsys = ss2sys(A,B,C,D,T,0,rows(A),stnamed,inname,outname); - endif - else - error(["Bad option=",opt]) - endif - -endfunction diff --git a/scripts/control/com2str.m b/scripts/control/com2str.m deleted file mode 100644 --- a/scripts/control/com2str.m +++ /dev/null @@ -1,82 +0,0 @@ -## Copyright (C) 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retval} =} com2str(@var{zz}[,@var{flg}]) -## -## convert complex number to a string -## @strong{Inputs} -## @table @var -## @item zz -## complex number -## @item flg -## format flag -## 0 (default): -1, 0, 1, 1i, 1 + 0.5i -## 1 (for use with zpout): -1, 0, + 1, + 1i, + 1 + 0.5i -## @end table -## @end deftypefn - -function retval = com2str (zz, flg) - - if (nargin < 1 | nargin > 2) - usage("com2str(zz{,flg})"); - endif - if(nargin == 1) - flg = 0; - endif - - if( !(is_scalar(zz) & is_scalar(flg) ) ) - error("com2str: arguments must be a scalar."); - endif - - if(flg != 0 & flg != 1) - error(["invalid flg value: ",num2str(flg)]); - endif - - sgns = "+-"; - rz = real(zz); - iz = imag(zz); - az = abs(zz); - if(iz == 0) - ## strictly a real number - switch(flg) - case(0) - retval = num2str(rz); - case(1) - retval = [ sgns(1+(rz< 0))," ", num2str(abs(rz))]; - endswitch - elseif(rz == 0) - ## strictly an imaginary number - switch(flg) - case(0) - retval = num2str(iz); - case(1) - retval = [ sgns(1+(iz< 0))," ", num2str(abs(iz)),"i"]; - endswitch - else - ## complex number - ## strictly an imaginary number - switch(flg) - case(0) - retval = [num2str(rz)," ",com2str(i*iz,1)]; - case(1) - retval = [ sgns(1+(rz< 0))," ", num2str(abs(rz))," ",com2str(i*iz,1)]; - endswitch - endif - -endfunction diff --git a/scripts/control/controldemo.m b/scripts/control/controldemo.m deleted file mode 100644 --- a/scripts/control/controldemo.m +++ /dev/null @@ -1,30 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} controldemo () -## Controls toolbox demo. -## @end deftypefn -## @seealso{Demo programs: bddemo, frdemo, analdemo, moddmeo, rldemo} - -## Author: David Clem -## Created: August 15, 1994 - -function controldemo () - DEMOcontrol (); -endfunction diff --git a/scripts/control/d2c.m b/scripts/control/d2c.m deleted file mode 100644 --- a/scripts/control/d2c.m +++ /dev/null @@ -1,222 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{csys} =} d2c (@var{sys}@{,@var{tol}@}) -## @deftypefnx {Function File} {@var{csys} =} d2c (@var{sys}, @var{opt}) -## Convert discrete (sub)system to a purely continuous system. Sampling -## time used is @code{sysgettsam(@var{sys})} -## -## @strong{Inputs} -## @table @var -## @item sys -## system data structure with discrete components -## @item tol -## Scalar value. -## tolerance for convergence of default @code{"log"} option (see below) -## @item opt -## conversion option. Choose from: -## @table @code -## @item "log" -## (default) Conversion is performed via a matrix logarithm. -## Due to some problems with this computation, it is -## followed by a steepest descent algorithm to identify continuous time -## @var{A}, @var{B}, to get a better fit to the original data. -## -## If called as @code{d2c}(@var{sys},@var{tol}), @var{tol=}positive scalar, -## the @code{"log"} option is used. The default value for @var{tol} is -## @code{1e-8}. -## @item "bi" -## Conversion is performed via bilinear transform -## @math{z = (1 + s T / 2)/(1 - s T / 2)} where @var{T} is the -## system sampling time (see @code{sysgettsam}). -## -## FIXME: bilinear option exits with an error if @var{sys} is not purely -## discrete -## @end table -## @end table -## @strong{Outputs} @var{csys} continuous time system (same dimensions and -## signal names as in @var{sys}). -## @end deftypefn - -## Author: R. Bruce Tenison -## Created: August 23, 1994 -## Updated by John Ingram for system data structure August 1996 - -function csys = d2c (sys, opt) - - ## SYS_INTERNAL accesses members of system data structure - - if( (nargin != 1) & (nargin != 2) ) - usage("csys = d2c(sys[,tol]), csys = d2c(sys,opt)"); - elseif (!is_struct(sys)) - error("sys must be in system data structure"); - elseif(nargin == 1) - opt = "log"; - tol = 1e-12; - elseif(isstr(opt)) # all remaining cases are for nargin == 2 - tol = 1e-12; - if( !(strcmp(opt,"log") | strcmp(opt,"bi") ) ) - error(["d2c: invalid opt passed=",opt]); - endif - elseif(!is_sample(opt)) - error("tol must be a postive scalar") - elseif(opt > 1e-2) - warning(["d2c: ridiculous error tolerance passed=",num2str(opt); ... - ", intended c2d call?"]) - else - tol = opt; - opt = "log"; - endif - T = sysgettsam(sys); - - if(strcmp(opt,"bi")) - ## bilinear transform - ## convert with bilinear transform - if (! is_digital(sys) ) - error("d2c requires a discrete time system for input") - endif - [a,b,c,d,tsam,n,nz,stname,inname,outname,yd] = sys2ss(sys); - - poles = eig(a); - if( find(abs(poles-1) < 200*(n+nz)*eps) ) - warning("d2c: some poles very close to one. May get bad results."); - endif - - I = eye(size(a)); - tk = 2/sqrt(T); - A = (2/T)*(a-I)/(a+I); - iab = (I+a)\b; - B = tk*iab; - C = tk*(c/(I+a)); - D = d- (c*iab); - stnamec = strappend(stname,"_c"); - csys = ss2sys(A,B,C,D,0,rows(A),0,stnamec,inname,outname); - elseif(strcmp(opt,"log")) - sys = sysupdate(sys,"ss"); - [n,nz,m,p] = sysdimensions(sys); - - if(nz == 0) - warning("d2c: all states continuous; setting outputs to agree"); - csys = syssetsignals(sys,"yd",zeros(1,1:p)); - return; - elseif(n != 0) - warning(["d2c: n=",num2str(n),">0; performing c2d first"]); - sys = c2d(sys,T); - endif - [a,b] = sys2ss(sys); - - [ma,na] = size(a); - [mb,nb] = size(b); - - if(isempty(b) ) - warning("d2c: empty b matrix"); - Amat = a; - else - Amat = [a, b; zeros(nb,na), eye(nb)]; - endif - - poles = eig(a); - if( find(abs(poles) < 200*(n+nz)*eps) ) - warning("d2c: some poles very close to zero. logm not performed"); - Mtop = zeros(ma, na+nb); - elseif( find(abs(poles-1) < 200*(n+nz)*eps) ) - warning("d2c: some poles very close to one. May get bad results."); - logmat = real(logm(Amat)/T); - Mtop = logmat(1:na,:); - else - logmat = real(logm(Amat)/T); - Mtop = logmat(1:na,:); - endif - - ## perform simplistic, stupid optimization approach. - ## should re-write with a Davidson-Fletcher CG approach - mxthresh = norm(Mtop); - if(mxthresh == 0) - mxthresh = 1; - endif - eps1 = mxthresh; #gradient descent step size - cnt = max(20,(n*nz)*4); #max number of iterations - newgrad=1; #signal for new gradient - while( (eps1/mxthresh > tol) & cnt) - cnt = cnt-1; - ## calculate the gradient of error with respect to Amat... - geps = norm(Mtop)*1e-8; - if(geps == 0) - geps = 1e-8; - endif - DMtop = Mtop; - if(isempty(b)) - Mall = Mtop; - DMall = DMtop; - else - Mall = [Mtop; zeros(nb,na+nb)]; - DMall = [DMtop; zeros(nb,na+nb) ]; - endif - - if(newgrad) - GrMall = zeros(size(Mall)); - for ii=1:rows(Mtop) - for jj=1:columns(Mtop) - DMall(ii,jj) = Mall(ii,jj) + geps; - GrMall(ii,jj) = norm (Amat - expm (DMall*T), "fro") ... - - norm (Amat - expm (Mall*T), "fro"); - DMall(ii,jj) = Mall(ii,jj); - endfor - endfor - GrMall = GrMall/norm(GrMall,1); - newgrad = 0; - endif - - ## got a gradient, now try to use it - DMall = Mall-eps1*GrMall; - - FMall = expm(Mall*T); - FDMall = expm(DMall*T); - FmallErr = norm(Amat - FMall); - FdmallErr = norm(Amat - FDMall); - if( FdmallErr < FmallErr) - Mtop = DMall(1:na,:); - eps1 = min(eps1*2,1e12); - newgrad = 1; - else - eps1 = eps1/2; - endif - - if(FmallErr == 0) - eps1 = 0; - endif - - endwhile - - [aa,bb,cc,dd,tsam,nn,nz,stnam,innam,outnam,yd] = sys2ss(sys); - aa = Mall(1:na,1:na); - if(!isempty(b)) - bb = Mall(1:na,(na+1):(na+nb)); - endif - csys = ss2sys(aa,bb,cc,dd,0,na,0,stnam,innam,outnam); - - ## update names - nn = sysdimensions(sys); - for ii = (nn+1):na - strval = sprintf("%s_c",sysgetsignals(csys,"st",ii,1)); - csys = syssetsignals(csys,"st",strval,ii); - endfor - endif - -endfunction diff --git a/scripts/control/dare.m b/scripts/control/dare.m deleted file mode 100644 --- a/scripts/control/dare.m +++ /dev/null @@ -1,122 +0,0 @@ -## Copyright (C) 1996, 1997 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2, or (at your option) -## any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place - Suite 330, Boston, MA -## 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} dare (@var{a}, @var{b}, @var{c}, @var{r}, @var{opt}) -## -## Return the solution, @var{x} of the discrete-time algebraic Riccati -## equation -## @iftex -## @tex -## $$ -## A^TXA - X + A^TXB (R + B^TXB)^{-1} B^TXA + C = 0 -## $$ -## @end tex -## @end iftex -## @ifinfo -## @example -## a' x a - x + a' x b (r + b' x b)^(-1) b' x a + c = 0 -## @end example -## @end ifinfo -## @noindent -## -## @strong{Inputs} -## @table @var -## @item a -## @var{n} by @var{n}. -## -## @item b -## @var{n} by @var{m}. -## -## @item c -## @var{n} by @var{n}, symmetric positive semidefinite, or @var{p} by @var{n}. -## In the latter case @math{c:=c'*c} is used. -## -## @item r -## @var{m} by @var{m}, symmetric positive definite (invertible). -## -## @item opt -## (optional argument; default = @code{"B"}): -## String option passed to @code{balance} prior to ordered @var{QZ} decomposition. -## @end table -## -## @strong{Outputs} -## @var{x} solution of DARE. -## -## @strong{Method} -## Generalized eigenvalue approach (Van Dooren; SIAM J. -## Sci. Stat. Comput., Vol 2) applied to the appropriate symplectic pencil. -## -## See also: Ran and Rodman, "Stable Hermitian Solutions of Discrete -## Algebraic Riccati Equations," Mathematics of Control, Signals and -## Systems, Vol 5, no 2 (1992) pp 165-194. -## -## @end deftypefn -## @seealso{balance and are} - -## Author: A. S. Hodel -## Created: August 1993 -## Adapted-By: jwe - -function x = dare (a, b, c, r, opt) - - if (nargin == 4 | nargin == 5) - if (nargin == 5) - if (opt != "N" || opt != "P" || opt != "S" || opt != "B") - warning ("dare: opt has an invalid value -- setting to B"); - opt = "B"; - endif - else - opt = "B"; - endif - - ## dimension checks are done in is_controllable, is_observable - if (is_controllable (a, b) == 0) - warning ("dare: a,b are not controllable"); - elseif (is_observable (a, c) == 0) - warning ("dare: a,c are not observable"); - endif - - if ((p = is_square (c)) == 0) - c = c'*c; - p = rows (c); - endif - - ## Check r dimensions. - n = rows(a); - m = columns(b); - if ((m1 = is_square (r)) == 0) - warning ("dare: r is not square"); - elseif (m1 != m) - warning ("b,r are not conformable"); - endif - - s1 = [a, zeros(n) ; -c, eye(n)]; - s2 = [eye(n), (b/r)*b' ; zeros(n), a']; - [c,d,s1,s2] = balance(s1,s2,opt); - [aa,bb,u,lam] = qz(s1,s2,"S"); - u = d*u; - n1 = n+1; - n2 = 2*n; - x = u (n1:n2, 1:n)/u(1:n, 1:n); - else - usage ("x = dare (a, b, c, r {,opt})"); - endif - -endfunction diff --git a/scripts/control/demomarsyas.m b/scripts/control/demomarsyas.m deleted file mode 100644 --- a/scripts/control/demomarsyas.m +++ /dev/null @@ -1,116 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -page_screen_output = 1; -opt = 0; -QUITOPT = 7; -while (opt != QUITOPT) - opt = menu("Marsyas interface update demo:", ... - "run Marsyas on the magnetically suspended ball example", ... - "load continuous time marsyas example system", ... - "load discrete-time marsyas example system", ... - "bode plot of loaded system (MIMO)", ... - "bode plot of loaded system (SISO)", ... - "Design example", ... - "Quit"); - - if(opt == 1) - cmd = "system(""marsyas mag1d.mar"")"; - run_cmd - cmd = "system(""marplot -i"")"; - run_cmd - elseif(opt == 2) - cmd = "ballsys = margetsys();"; - run_cmd; - cmd = "sysout(ballsys);" - run_cmd - elseif(opt == 3) - cmd = "ballsys = margetsys(""disc"");"; - run_cmd - cmd = "sysout(ballsys);" - run_cmd - elseif(opt == 4) - cmd = "bode(ballsys);"; - run_cmd - elseif(opt == 5) - cmd = "bode(ballsys,[],1,1);"; - run_cmd - elseif(opt == 6) - if(!exist("ballsys")) - warning("You didn't load a system yet (option 2 or 3)"); - else - disp("Design LQG controller"); - cmd = "sysout(ballsys)"; - run_cmd - disp("add noise inputs to system...") - if(ballsys.n) - disp("continuous system:") - cmd = "ballsys1 = sysappend(ballsys,eye(ballsys.n));"; - else - disp("discrete system:") - cmd = "ballsys1 = sysappend(ballsys,eye(ballsys.nz));"; - endif - run_cmd - cmd = "sysout(ballsys1)"; - run_cmd - disp("Notice the two additional inputs, u_2, and u_3. These are the "); - disp("""entry points"" for the gaussian noise disturbance."); - disp(" "); - disp("We'll design the controller to use only position feedback:") - cmd = "ballsys1=sysprune(ballsys1,1,[]);"; - run_cmd - cmd = "sysout(ballsys1)"; - run_cmd - disp("Now design an LQG controller: Sigw: input noise") - Sigw = eye(2) - disp("Now design an LQG controller: Sigv: measurement noise") - Sigv = eye(rows(ballsys1.c)) - disp("State and input penalties:") - Q = eye(2) - R = 1 - disp("Controlled input is input 1"); - cmd="Ksys = lqg(ballsys1,Sigw,Sigv,Q,R,1);"; - run_cmd - disp("sysout(Ksys);"); - sysout(Ksys); - - disp("marsyas conversion: output in scalar form:") - cmd = "maroutsys(Ksys, ""ball_controller"",""scalar"");"; - run_cmd - disp("here's the output file:") - prompt - system("more ball_controller.mar"); - - disp("marsyas conversion: output in state space form: (default option;") - disp("the ""ss"" in the command below is not needed)") - cmd = "maroutsys(Ksys, ""ball_controller_ss"",""ss"");"; - run_cmd - disp("here's the output file:") - prompt - system("more ball_controller_ss.mar"); - - disp("marsyas conversion: output in transfer function form:") - cmd = "maroutsys(Ksys, ""ball_controller_tf"",""tf"")" - run_cmd - disp("here's the output file:") - prompt - system("more ball_controller_tf.mar"); - - endif - endif -endwhile diff --git a/scripts/control/dgkfdemo.m b/scripts/control/dgkfdemo.m deleted file mode 100644 --- a/scripts/control/dgkfdemo.m +++ /dev/null @@ -1,354 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} dgkfdemo () -## Octave Controls toolbox demo: H2/Hinfinity options demos -## @end deftypefn - -## Author: A. S. Hodel -## Created: June 1995 - -function dgkfdemo () - - save_val = page_screen_output; - page_screen_output = 1; - while (1) - clc - sel = 0; - while (sel > 10 || sel < 1) - sel = menu ("Octave H2/Hinfinity options demo", - "LQ regulator", - "LG state estimator", - "LQG optimal control design", - "H2 gain of a system", - "H2 optimal controller of a system", - "Hinf gain of a system", - "Hinf optimal controller of a SISO system", - "Hinf optimal controller of a MIMO system", - "Discrete-time Hinf optimal control by bilinear transform", - "Return to main demo menu"); - endwhile - if (sel == 1) - disp("Linear/Quadratic regulator design:") - disp("Compute optimal state feedback via the lqr command...") - help lqr - disp(" ") - disp("Example:") - A = [0, 1; -2, -1] - B = [0; 1] - Q = [1, 0; 0, 0] - R = 1 - disp("Q = state penalty matrix; R = input penalty matrix") - prompt - disp("Compute state feedback gain k, ARE solution P, and closed-loop") - disp("poles as follows:"); - cmd = "[k, p, e] = lqr(A,B,Q,R)"; - run_cmd - prompt - disp("A similar approach can be used for LTI discrete-time systems") - disp("by using the dlqr command in place of lqr (see LQG example).") - elseif (sel == 2) - disp("Linear/Gaussian estimator design:") - disp("Compute optimal state estimator via the lqe command...") - help lqe - disp(" ") - disp("Example:") - A = [0, 1; -2, -1] - disp("disturbance entry matrix G") - G = eye(2) - disp("Output measurement matrix C") - C = [0, 1] - SigW = [1, 0; 0, 1] - SigV = 1 - disp("SigW = input disturbance intensity matrix;") - disp("SigV = measurement noise intensity matrix") - prompt - disp("Compute estimator feedback gain k, ARE solution P, and estimator") - disp("poles via the command: ") - cmd = "[k, p, e] = lqe(A,G,C,SigW,SigV)"; - run_cmd - disp("A similar approach can be used for LTI discrete-time systems") - disp("by using the dlqe command in place of lqe (see LQG example).") - elseif (sel == 3) - disp("LQG optimal controller of a system:") - disp("Input accepted as either A,B,C matrices or in system data structure form") - disp("in both discrete and continuous time.") - disp("Example 1: continuous time design:") - prompt - help lqg - disp("Example system") - A = [0, 1; .5, .5]; - B = [0; 2]; - G = eye(2) - C = [1, 1]; - sys = ss2sys(A, [B, G], C); - sys = syssetsignals(sys,"in", ... - ["control input"; "disturbance 1"; "disturbance 2"]); - sysout(sys) - prompt - disp("Filtering/estimator parameters:") - SigW = eye(2) - SigV = 1 - prompt - disp("State space (LQR) parameters Q and R are:") - Q = eye(2) - R = 1 - cmd = "[K,Q1,P1,Ee,Er] = lqg(sys,SigW,SigV,Q,R,1);"; - run_cmd - disp("Check: closed loop system A-matrix is") - disp(" [A, B*Cc]") - disp(" [Bc*C, Ac ]") - cmd = "[Ac, Bc, Cc] = sys2ss(K);"; - run_cmd - cmd = "Acl = [A, B*Cc; Bc*C, Ac]"; - run_cmd - disp("Check: poles of Acl:") - Acl_poles = sortcom(eig(Acl)) - disp("Predicted poles from design = union(Er,Ee)") - cmd = "pred_poles = sortcom([Er; Ee])"; - run_cmd - disp("Example 2: discrete-time example") - cmd1 = "Dsys = ss2sys(A, [G, B], C, [0, 0, 0], 1);"; - cmd2 = "[K,Q1,P1,Ee,Er] = lqg(Dsys,SigW, SigV,Q,R);"; - disp("Run commands:") - cmd = cmd1; - run_cmd - cmd = cmd2; - run_cmd - prompt - disp("Check: closed loop system A-matrix is") - disp(" [A, B*Cc]") - disp(" [Bc*C, Ac ]") - [Ac,Bc,Cc] = sys2ss(K); - Acl = [A, B*Cc; Bc*C, Ac] - prompt - disp("Check: poles of Acl:") - Acl_poles = sortcom(eig(Acl)) - disp("Predicted poles from design = union(Er,Ee)") - pred_poles = sortcom([Er;Ee]) - elseif (sel == 4) - disp("H2 gain of a system: (Energy in impulse response)") - disp("Example 1: Stable plant:") - cmd = "A = [0, 1; -2, -1]; B = [0; 1]; C = [1, 0]; sys_poles = eig(A)"; - run_cmd - disp("Put into Packed system form:") - cmd = "Asys = ss2sys(A,B,C);"; - run_cmd - disp("Evaluate system 2-norm (impulse response energy):"); - cmd = "AsysH2 = h2norm(Asys)"; - run_cmd - disp("Compare with a plot of the system impulse response:") - tt = 0:0.1:20; - for ii=1:length(tt) - ht(ii) = C*expm(A*tt(ii))*B; - endfor - plot(tt,ht) - title("impulse response of example plant") - prompt - disp("Example 2: unstable plant") - cmd = "A = [0, 1; 2, 1]"; - eval(cmd); - cmd = "B = [0; 1]"; - eval(cmd); - cmd = "C = [1, 0]"; - eval(cmd); - cmd = "sys_poles = eig(A)"; - run_cmd - prompt - disp("Put into system data structure form:") - cmd="Bsys = ss2sys(A,B,C);"; - run_cmd - disp("Evaluate 2-norm:") - cmd = "BsysH2 = h2norm(Bsys)"; - run_cmd - disp(" ") - prompt("NOTICE: program returns a value without an error signal.") - disp("") - - elseif (sel == 5) - disp("H2 optimal controller of a system: command = h2syn:") - prompt - help h2syn - prompt - disp("Example system: double integrator with output noise and") - disp("input disturbance:") - disp(" "); - disp(" -------------------->y2"); - disp(" | _________"); - disp("u(t)-->o-->| 1/s^2 |-->o-> y1"); - disp(" ^ --------- ^"); - disp(" | |"); - disp(" w1(t) w2(t)"); - disp(" ") - disp("w enters the system through B1, u through B2") - disp("z = [y1; y2] is obtained through C1, y=y1 through C2"); - disp(" ") - cmd = "A = [0, 1; 0, 0]; B1 = [0, 0; 1, 0]; B2 = [0; 1];"; - disp(cmd) - eval(cmd); - cmd = "C1 = [1, 0; 0, 0]; C2 = [1, 0]; D11 = zeros(2);"; - disp(cmd) - eval(cmd); - cmd = "D12 = [0; 1]; D21 = [0, 1]; D22 = 0; D = [D11, D12; D21, D22];"; - disp(cmd) - eval(cmd); - disp("Design objective: compute U(s)=K(s)Y1(s) to minimize the closed") - disp("loop impulse response from w(t) =[w1; w2] to z(t) = [y1; y2]"); - prompt - disp("First: pack system:") - cmd="Asys = ss2sys(A, [B1, B2], [C1; C2], D);"; - run_cmd - disp("Open loop multivariable Bode plot: (will take a moment)") - cmd="bode(Asys);"; - run_cmd - prompt("Press a key to close plot and continue"); - closeplot - disp("Controller design command: (only need 1st two output arguments)") - cmd="[K,gain, Kc, Kf, Pc, Pf] = h2syn(Asys,1,1);"; - run_cmd - disp("Controller is:") - cmd = "sysout(K)"; - run_cmd - disp(["returned gain value is: ",num2str(gain)]); - disp("Check: close the loop and then compute h2norm:") - prompt - cmd="K_loop = sysgroup(Asys,K);"; - run_cmd - cmd = "Kcl = sysconnect(K_loop,[3,4],[4,3]);"; - run_cmd - cmd = "Kcl = sysprune(Kcl,[1,2],[1,2]);"; - run_cmd - cmd="gain_Kcl = h2norm(Kcl)"; - run_cmd - cmd="gain_err = gain_Kcl - gain"; - run_cmd - disp("Check: multivarible bode plot:") - cmd="bode(Kcl);"; - run_cmd - prompt - disp("Related functions: is_dgkf, is_controllable, is_stabilizable,") - disp(" is_observable, is_detectable") - elseif (sel == 6) - disp("Hinfinity gain of a system: (max gain over all j-omega)") - disp("Example 1: Stable plant:") - cmd = "A = [0, 1; -2, -1]; B = [0; 1]; C = [1, 0]; sys_poles = eig(A)"; - run_cmd - disp("Pack into system format:") - cmd = "Asys = ss2sys(A,B,C);"; - run_cmd - disp("The infinity norm must be computed iteratively by") - disp("binary search. For this example, we select tolerance tol = 0.01, ") - disp("min gain gmin = 1e-2, max gain gmax=1e4.") - disp("Search quits when upper bound <= (1+tol)*lower bound.") - cmd = "tol = 0.01; gmin = 1e-2; gmax = 1e+4;"; - run_cmd - cmd = "[AsysHinf,gmin,gmax] = hinfnorm(Asys,tol,gmin,gmax)" - run_cmd - disp("Check: look at max value of magntude Bode plot of Asys:"); - [M,P,w] = bode(Asys); - xlabel("Omega") - ylabel("|Asys(j omega)| ") - grid(); - semilogx(w,M); - disp(["Max magnitude is ",num2str(max(M)), ... - ", compared with gmin=",num2str(gmin)," and gmax=", ... - num2str(gmax),"."]) - prompt - disp("Example 2: unstable plant") - cmd = "A = [0, 1; 2, 1]; B = [0; 1]; C = [1, 0]; sys_poles = eig(A)"; - run_cmd - disp("Pack into system format:") - cmd = "Bsys = ss2sys(A,B,C);"; - run_cmd - disp("Evaluate with BsysH2 = hinfnorm(Bsys,tol,gmin,gmax)") - BsysH2 = hinfnorm(Bsys,tol,gmin,gmax) - disp(" ") - disp("NOTICE: program returns a value without an error signal.") - disp("") - - elseif (sel == 7) - disp("Hinfinity optimal controller of a system: command = hinfsyn:") - prompt - help hinfsyn - prompt - disp("Example system: double integrator with output noise and") - disp("input disturbance:") - A = [0, 1; 0, 0] - B1 = [0, 0; 1, 0] - B2 = [0; 1] - C1 = [1, 0; 0, 0] - C2 = [1, 0] - D11 = zeros(2); - D12 = [0; 1]; - D21 = [0, 1]; - D22 = 0; - D = [D11, D12; D21, D22] - prompt - disp("First: pack system:") - cmd="Asys = ss2sys(A, [B1, B2], [C1; C2], D);"; - run_cmd - prompt - disp("Open loop multivariable Bode plot: (will take a moment)") - cmd="bode(Asys);"; - run_cmd - prompt - disp("Controller design command: (only need 1st two output arguments)") - gmax = 1000 - gmin = 0.1 - gtol = 0.01 - cmd="[K,gain] = hinfsyn(Asys,1,1,gmin,gmax,gtol);"; - run_cmd - disp("Check: close the loop and then compute h2norm:") - prompt - cmd="K_loop = sysgroup(Asys,K);"; - run_cmd - cmd = "Kcl = sysconnect(K_loop,[3,4],[4,3]);"; - run_cmd - cmd = "Kcl = sysprune(Kcl,[1,2],[1,2]);"; - run_cmd - cmd="gain_Kcl = hinfnorm(Kcl)"; - run_cmd - cmd="gain_err = gain_Kcl - gain"; - run_cmd - disp("Check: multivarible bode plot:") - cmd="bode(Kcl);"; - run_cmd - prompt - disp("Related functions: is_dgkf, is_controllable, is_stabilizable,") - disp(" is_observable, is_detectable, buildssic") - elseif (sel == 8) - disp("Hinfinity optimal controller of MIMO system: command = hinfsyn:") - prompt - help hinfsyn - prompt - disp("Example system: Boeing 707-321 airspeed/pitch angle control") - disp(" ") - hinfdemo - elseif (sel == 9) - disp("Discrete time H-infinity control via bilinear transform"); - prompt - dhinfdemo - elseif (sel == 10) - return - endif - prompt - endwhile - page_screen_output = save_val; - -endfunction diff --git a/scripts/control/dgram.m b/scripts/control/dgram.m deleted file mode 100644 --- a/scripts/control/dgram.m +++ /dev/null @@ -1,49 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{m} =} dgram (@var{a}, @var{b}) -## Return controllability grammian of discrete time system -## @example -## x(k+1) = a x(k) + b u(k) -## @end example -## -## @strong{Inputs} -## @table @var -## @item a -## @var{n} by @var{n} matrix -## @item b -## @var{n} by @var{m} matrix -## @end table -## -## @strong{Outputs} -## @var{m} (@var{n} by @var{n}) satisfies -## @example -## a m a' - m + b*b' = 0 -## @end example -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 1995 - -function m = dgram (a, b) - - ## let dlyap do the error checking... - m = dlyap(a,b*b'); - -endfunction diff --git a/scripts/control/dlqe.m b/scripts/control/dlqe.m deleted file mode 100644 --- a/scripts/control/dlqe.m +++ /dev/null @@ -1,125 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{l}, @var{m}, @var{p}, @var{e}] =} dlqe (@var{a}, @var{g}, @var{c}, @var{sigw}, @var{sigv}, @var{z}) -## Construct the linear quadratic estimator (Kalman filter) for the -## discrete time system -## @iftex -## @tex -## $$ -## x_{k+1} = A x_k + B u_k + G w_k -## $$ -## $$ -## y_k = C x_k + D u_k + w_k -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## x[k+1] = A x[k] + B u[k] + G w[k] -## y[k] = C x[k] + D u[k] + w[k] -## @end example -## -## @end ifinfo -## where @var{w}, @var{v} are zero-mean gaussian noise processes with -## respective intensities @code{@var{sigw} = cov (@var{w}, @var{w})} and -## @code{@var{sigv} = cov (@var{v}, @var{v})}. -## -## If specified, @var{z} is @code{cov (@var{w}, @var{v})}. Otherwise -## @code{cov (@var{w}, @var{v}) = 0}. -## -## The observer structure is -## @iftex -## @tex -## $$ -## z_{k+1} = A z_k + B u_k + k (y_k - C z_k - D u_k) -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## z[k+1] = A z[k] + B u[k] + k (y[k] - C z[k] - D u[k]) -## @end example -## @end ifinfo -## -## @noindent -## The following values are returned: -## -## @table @var -## @item l -## The observer gain, -## @iftex -## @tex -## $(A - ALC)$. -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{a}@var{l}@var{c}). -## @end ifinfo -## is stable. -## -## @item m -## The Riccati equation solution. -## -## @item p -## The estimate error covariance after the measurement update. -## -## @item e -## The closed loop poles of -## @iftex -## @tex -## $(A - ALC)$. -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{a}@var{l}@var{c}). -## @end ifinfo -## @end table -## @end deftypefn - -## Author: A. S. Hodel -## Created: August 1993 -## Modified for discrete time by R. Bruce Tenison (btenison@eng.auburn.edu) -## October, 1993 - -function [l, m, p, e] = dlqe (a, g, c, sigw, sigv, s) - - if (nargin != 5 && nargin != 6) - error ("dlqe: invalid number of arguments"); - endif - - ## The problem is dual to the regulator design, so transform to dlqr call. - - if (nargin == 5) - [k, p, e] = dlqr (a', c', g*sigw*g', sigv); - m = p; - l = k'; - else - [k, p, e] = dlqr (a', c', g*sigw*g', sigv, g*s); - m = p; - l = k'; - a = a-g*t/sigv*c; - sigw = sigw-t/sigv; - endif - - p = a\(m-g*sigw*g')/a'; - -endfunction diff --git a/scripts/control/dlqr.m b/scripts/control/dlqr.m deleted file mode 100644 --- a/scripts/control/dlqr.m +++ /dev/null @@ -1,166 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{k}, @var{p}, @var{e}] =} dlqr (@var{a}, @var{b}, @var{q}, @var{r}, @var{z}) -## Construct the linear quadratic regulator for the discrete time system -## @iftex -## @tex -## $$ -## x_{k+1} = A x_k + B u_k -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## x[k+1] = A x[k] + B u[k] -## @end example -## -## @end ifinfo -## to minimize the cost functional -## @iftex -## @tex -## $$ -## J = \sum x^T Q x + u^T R u -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## J = Sum (x' Q x + u' R u) -## @end example -## @end ifinfo -## -## @noindent -## @var{z} omitted or -## @iftex -## @tex -## $$ -## J = \sum x^T Q x + u^T R u + 2 x^T Z u -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## J = Sum (x' Q x + u' R u + 2 x' Z u) -## @end example -## -## @end ifinfo -## @var{z} included. -## -## The following values are returned: -## -## @table @var -## @item k -## The state feedback gain, -## @iftex -## @tex -## $(A - B K)$ -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{b}@var{k}) -## @end ifinfo -## is stable. -## -## @item p -## The solution of algebraic Riccati equation. -## -## @item e -## The closed loop poles of -## @iftex -## @tex -## $(A - B K)$. -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{b}@var{k}). -## @end ifinfo -## @end table -## @strong{References} -## @enumerate -## @item Anderson and Moore, Optimal Control: Linear Quadratic Methods, -## Prentice-Hall, 1990, pp. 56-58 -## @item Kuo, Digital Control Systems, Harcourt Brace Jovanovich, 1992, -## section 11-5-2. -## @end enumerate -## @end deftypefn - -## Author: A. S. Hodel -## Created: August 1993 -## Converted to discrete time by R. B. Tenison -## (btenison@eng.auburn.edu) October 1993 - -function [k, p, e] = dlqr (a, b, q, r, s) - - if (nargin != 4 && nargin != 5) - error ("dlqr: invalid number of arguments"); - endif - - ## Check a. - if ((n = is_square (a)) == 0) - error ("dlqr: requires 1st parameter(a) to be square"); - endif - - ## Check b. - [n1, m] = size (b); - if (n1 != n) - error ("dlqr: a,b not conformal"); - endif - - ## Check q. - if ((n1 = is_square (q)) == 0 || n1 != n) - error ("dlqr: q must be square and conformal with a"); - endif - - ## Check r. - if((m1 = is_square(r)) == 0 || m1 != m) - error ("dlqr: r must be square and conformal with column dimension of b"); - endif - - ## Check if n is there. - if (nargin == 5) - [n1, m1] = size (s); - if (n1 != n || m1 != m) - error ("dlqr: z must be identically dimensioned with b"); - endif - - ## Incorporate cross term into a and q. - - ao = a - (b/r)*s'; - qo = q - (s/r)*s'; - else - s = zeros (n, m); - ao = a; - qo = q; - endif - - ## Check that q, (r) are symmetric, positive (semi)definite - if (is_symmetric (q) && is_symmetric (r) ... - && all (eig (q) >= 0) && all (eig (r) > 0)) - p = dare (ao, b, qo, r); - k = (r+b'*p*b)\b'*p*a + r\s'; - e = eig (a - b*k); - else - error ("dlqr: q (r) must be symmetric positive (semi) definite"); - endif - -endfunction diff --git a/scripts/control/dlyap.m b/scripts/control/dlyap.m deleted file mode 100644 --- a/scripts/control/dlyap.m +++ /dev/null @@ -1,130 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{x} =} dlyap (@var{a}, @var{b}) -## Solve the discrete-time Lyapunov equation -## -## @strong{Inputs} -## @table @var -## @item a -## @var{n} by @var{n} matrix -## @item b -## Matrix: @var{n} by @var{n}, @var{n} by @var{m}, or @var{p} by @var{n}. -## @end table -## -## @strong{Outputs} -## @var{x}: matrix satisfying appropriate discrete time Lyapunov equation. -## Options: -## @itemize @bullet -## @item @var{b} is square: solve @code{a x a' - x + b = 0} -## @item @var{b} is not square: @var{x} satisfies either -## @example -## a x a' - x + b b' = 0 -## @end example -## @noindent -## or -## @example -## a' x a - x + b' b = 0, -## @end example -## @noindent -## whichever is appropriate. -## @end itemize -## -## @strong{Method} -## Uses Schur decomposition method as in Kitagawa, -## @cite{An Algorithm for Solving the Matrix Equation @var{X} = -## @var{F}@var{X}@var{F}' + @var{S}}, -## International Journal of Control, Volume 25, Number 5, pages 745--753 -## (1977). -## -## Column-by-column solution method as suggested in -## Hammarling, @cite{Numerical Solution of the Stable, Non-Negative -## Definite Lyapunov Equation}, IMA Journal of Numerical Analysis, Volume -## 2, pages 303--323 (1982). -## @end deftypefn - -## Author: A. S. Hodel -## Created: August 1993 - -function x = dlyap (a, b) - - if ((n = is_square (a)) == 0) - warning ("dlyap: a must be square"); - endif - - if ((m = is_square (b)) == 0) - [n1, m] = size (b); - if (n1 == n) - b = b*b'; - m = n1; - else - b = b'*b; - a = a'; - endif - endif - - if (n != m) - warning ("dlyap: a,b not conformably dimensioned"); - endif - - ## Solve the equation column by column. - - [u, s] = schur (a); - b = u'*b*u; - - j = n; - while (j > 0) - j1 = j; - - ## Check for Schur block. - - if (j == 1) - blksiz = 1; - elseif (s (j, j-1) != 0) - blksiz = 2; - j = j - 1; - else - blksiz = 1; - endif - - Ajj = kron (s (j:j1, j:j1), s) - eye (blksiz*n); - - rhs = reshape (b (:, j:j1), blksiz*n, 1); - - if (j1 < n) - rhs2 = s*(x (:, (j1+1):n) * s (j:j1, (j1+1):n)'); - rhs = rhs + reshape (rhs2, blksiz*n, 1); - endif - - v = - Ajj\rhs; - x (:, j) = v (1:n); - - if(blksiz == 2) - x (:, j1) = v ((n+1):blksiz*n); - endif - - j = j - 1; - - endwhile - - ## Back-transform to original coordinates. - - x = u*x*u'; - -endfunction diff --git a/scripts/control/dmr2d.m b/scripts/control/dmr2d.m deleted file mode 100644 --- a/scripts/control/dmr2d.m +++ /dev/null @@ -1,259 +0,0 @@ -## Copyright (C) 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{dsys}, @var{fidx}] =} dmr2d (@var{sys}, @var{idx}, @var{sprefix}, @var{Ts2} @{,@var{cuflg}@}) -## convert a multirate digital system to a single rate digital system -## states specified by @var{idx}, @var{sprefix} are sampled at @var{Ts2}, all -## others are assumed sampled at @var{Ts1} = @code{sysgettsam(@var{sys})}. -## -## @strong{Inputs} -## @table @var -## @item sys -## discrete time system; -## @code{dmr2d} exits with an error if @var{sys} is not discrete -## @item idx -## list of states with sampling time @code{sysgettsam(@var{sys})} (may -## be empty) -## @item sprefix -## list of string prefixes of states with sampling time -## @code{sysgettsam(@var{sys})} -## (may be empty) -## @item Ts2 -## sampling time of states not specified by @var{idx}, @var{sprefix} -## must be an integer multiple of @code{sysgettsam(@var{sys})} -## @item cuflg -## "constant u flag" if @var{cuflg} is nonzero then the system inputs are -## assumed to be constant over the revised sampling interval @var{Ts2}. -## Otherwise, since the inputs can change during the interval -## @var{t} in @math{[k Ts2, (k+1) Ts2]}, an additional set of inputs is -## included in the revised B matrix so that these intersample inputs -## may be included in the single-rate system. -## default @var{cuflg} = 1. -## @end table -## -## @strong{Outputs} -## @table @var -## @item dsys -## equivalent discrete time system with sampling time @var{Ts2}. -## -## The sampling time of sys is updated to @var{Ts2}. -## -## if @var{cuflg}=0 then a set of additional inputs is added to -## the system with suffixes _d1, ..., _dn to indicate their -## delay from the starting time k @var{Ts2}, i.e. -## u = [u_1; u_1_d1; ..., u_1_dn] where u_1_dk is the input -## k*Ts1 units of time after u_1 is sampled. (Ts1 is -## the original sampling time of discrete time sys and -## @var{Ts2} = (n+1)*Ts1) -## -## @item fidx -## indices of "formerly fast" states specified by @var{idx} and @var{sprefix}; -## these states are updated to the new (slower) sampling interval @var{Ts2}. -## @end table -## -## @strong{WARNING} Not thoroughly tested yet; especially when -## @var{cuflg} == 0. -## @end deftypefn - -## Adapted from c2d by a.s.hodel@eng.auburn.edu - -function [dsys, fidx] = dmr2d (sys, idx, sprefix, Ts2, cuflg) - - ## parse input arguments - if(nargin != 4 | nargout > 2) - usage("[dsys,fidx] = dmr2d (sys, idx, sprefix, Ts2 {,cuflg})"); - - elseif (!is_struct(sys)) - error("sys must be in system data structure form"); - - elseif(!is_digital(sys)) - error("sys must be discrete-time; continuous time passed"); - - elseif (!(is_vector(idx) | isempty(idx))) - error(["idx(",num2str(rows(idx)),"x",num2str(columns(idx)), ... - ") must be a vector"]); - - elseif (any(idx <= 0)) - idv = find(idx <= 0); - ii = idv(1); - error(["idx(",num2str(ii),")=",num2str(idx(ii)), ... - "; entries of idx must be positive"]); - - elseif(!(is_signal_list(sprefix) | isempty(sprefix))) - error("sprefix must be a signal list (see is_signal_list) or empty"); - - elseif(!is_sample(Ts2)) - error(["Ts2=",num2str(Ts2),"; invalid sampling time"]); - - endif - - ## optional argument: cuflg - if(nargin <= 4) - cuflg = 1; # default: constant inputs over Ts2 sampling interv. - elseif( !is_scalar(cuflg) ) - error("cuflg must be a scalar") - elseif( cuflg != 0 | cuflg != 1) - error(["cuflg = ",num2str(cuflg),", should be 0 or 1"]); - endif - - ## extract state space information - [da,db,dc,dd,Ts1,nc,nz,stname,inname,outname,yd] = sys2ss(sys); - - ## compute number of steps - if(Ts1 > Ts2) - error(["Current sampling time=",num2str(Ts1),"< Ts2=",num2str(Ts2)]); - endif - nstp = floor(Ts2/Ts1+0.5); - if(abs((Ts2 - Ts1*nstp)/Ts1) > 1e-12) - warning(["dmr2d: Ts1=",num2str(Ts1),", Ts2=",num2str(Ts2), ... - ", selecting nsteps=",num2str(nstp),"; mismatch"]); - endif - - if(isempty(sprefix) & isempty(idx)) - warning("both sprefix and idx are empty; returning dsys=sys"); - fidx = []; - dsys = sys; - return - elseif(isempty(sprefix)) - fidx = idx; - else - fidx = reshape(idx,1,length(idx)); - ## find states whose name begins with any strings in sprefix. - ns = length(sprefix); - for kk=1:ns - spk = nth(sprefix,kk); # get next prefix and length - spl = length(spk); - - ## check each state name - for ii=1:nz - sti = nth(stname,ii); # compare spk with this state name - if(length(sti) >= spl) - ## if the prefix matches and ii isn't already in the list, add ii - if(strcmp(sti(1:spl),spk) & !any(fidx == ii) ) - fidx = sort([fidx,ii]); - endif - endif - endfor - endfor - endif - - if(nstp == 0) - warning("dmr2d: nstp = 0; setting tsam and returning"); - dsys = syschtsam(sys,Ts2); - return - elseif(nstp < 0) - error(["nstp = ", num2str(nstp)," < 0; this shouldn't be!"]); - endif - - ## permute system matrices - pv = sysreorder(nz,fidx); - pv = pv(nz:-1:1); # reverse order to put fast modes in leading block - - ## construct inverse permutation - Inz = eye(nz); - pvi = (Inz(pv,:)'*[1:nz]')'; - - ## permute A, B (stname permuted for debugging only) - da = da(pv,pv); - db = db(pv,:); - stname = stname(pv,:); - - ## partition A, B: - lfidx = length(fidx); - bki = 1:lfidx; - a11 = da(bki,bki); - b1 = db(bki,:); - - if(lfidx < nz) - lfidx1 = lfidx+1; - bki2 = (lfidx1):nz; - a12 = da(bki,bki2); - b2 = db(bki2,:); - else - warning("dmr2d: converting entire A,B matrices to new sampling rate"); - lfidx1 = -1; - bki2 = []; - endif - - ## begin system conversion: nstp steps - - ## compute abar_{n-1}*a12 and appropriate b matrix stuff - a12b = a12; # running total of abar_{n-1}*a12 - a12w = a12; # current a11^n*a12 (start with n = 0) - if(cuflg) - b1b = b1; - b1w = b1; - else - ## cuflg == 0, need to keep track of intersample inputs too - nzdx = find(max(abs(b1)) != 0); # FIXME: check tolerance relative to ||b1|| - b1w = b1(nzdx); - innamenz = inname(nzdx); - b1b = b1; # initial b1 must match columns in b2 - endif - - ## compute a11h = a11^nstp by squaring - a11h = eye(size(a11)); - p2 = 1; - a11p2 = a11; #a11^p2 - - nstpw = nstp; # workspace for computing a11^nstp - while(nstpw > 0.5) - oddv = rem(nstpw,2); - if(oddv) - a11h = a11h*a11p2; - endif - nstpw = (nstpw-oddv)/2; - if(nstpw > 0.5) - a11p2 = a11p2*a11p2; # a11^(next power of 2) - endif - endwhile - - ## FIXME: this part should probably also use squaring, but - ## that would require exponentially growing memory. What do do? - for kk=2:nstp - ## update a12 block to sum(a12 + ... + a11^(kk-1)*a12) - a12w = a11*a12w; - a12b = a12b + a12w; - - ## similar for b1 block (checking for cuflg first!) - b1w = a11*b1w; - if(cuflg) - b1b = b1b + b1w; # update b1 block just like we did a12 - else - b1b = [b1b, b1w]; # append new inputs - newin = strappend(innamenz,["_d",num2str(kk-1)]); - inname = append(inname,newin); - endif - endfor - - ## reconstruct system and return - da(bki,bki) = a11h; - db(bki,1:columns(b1b)) = b1b; - if(!isempty(bki2)) - da(bki,bki2) = a12b; - endif - - da = da(pvi,pvi); - db = db(pvi,:); - stname = stname(pvi,:); - - ## construct new system and return - dsys = ss2sys(da,db,dc,dd,Ts2,0,nz,stname,inname,outname,find(yd == 1)); - -endfunction diff --git a/scripts/control/dre.m b/scripts/control/dre.m deleted file mode 100644 --- a/scripts/control/dre.m +++ /dev/null @@ -1,155 +0,0 @@ -## Copyright (C) 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{tvals},@var{Plist}] =} dre(@var{sys},@var{Q},@var{R},@var{Qf},@var{t0},@var{tf}[,@var{Ptol},@var{maxits}]); -## Solve the differential Riccati equation -## @ifinfo -## @example -## -d P/dt = A'P + P A - P B inv(R) B' P + Q -## P(tf) = Qf -## @example -## @end ifinfo -## @iftex -## @tex -## \(-\frac{dP}{dt} = A^{T}P+PA-PBR^{-1}B^{T}P+Q\) -## @end tex -## @end iftex -## for the LTI system sys. Solution of standard LTI -## state feedback optimization -## min \int_{t_0}^{t_f} x' Q x + u' R u dt + x(t_f)' Qf x(t_f) -## optimal input is -## u = - inv(R) B' P(t) x -## @strong{Inputs} -## @table -## @item sys -## continuous time system data structure -## @item Q -## state integral penalty -## @item R -## input integral penalty -## @item Qf -## state terminal penalty -## @item t0 -## @itemx tf -## limits on the integral -## @item Ptol -## tolerance (used to select time samples; see below); default = 0.1 -## @item maxits -## number of refinement iterations (default=10) -## @end table -## @strong{Outputs} -## @table -## @item tvals -## time values at which @var{P}(@var{t}) is computed -## @item Plist -## list values of @var{P}(@var{t}); nth(@var{Plist},@var{ii}) -## is @var{P}(@var{tvals}(@var{ii})). -## -## @item tvals -## @example -## is selected so that || nth(Plist,ii) - nth(Plist,ii-1) || < Ptol -## for ii=2:length(tvals) -## @end example -## @end table -## @end deftypefn - -function [tvals, Plist] = dre (sys, Q, R, Qf, t0, tf, Ptol, maxits) - - if(nargin < 6 | nargin > 8 | nargout != 2) - usage("[tvals,Plist] = dre(sys,Q,R,Qf,t0,tf{,Ptol})"); - elseif(!is_struct(sys)) - error("sys must be a system data structure") - elseif(is_digital(sys)) - error("sys must be a continuous time system") - elseif(!is_matrix(Q) | !is_matrix(R) | !is_matrix(Qf)) - error("Q, R, and Qf must be matrices."); - elseif(!is_scalar(t0) | !is_scalar(tf)) - error("t0 and tf must be scalars") - elseif(t0 >= tf) error("t0=%e >= tf=%e",t0,tf); - elseif(nargin == 6) Ptol = 0.1; - elseif(!is_scalar(Ptol)) error("Ptol must be a scalar"); - elseif(Ptol <= 0) error("Ptol must be positive"); - endif - - if(nargin < 8) maxits = 10; - elseif(!is_scalar(maxits)) error("maxits must be a scalar"); - elseif(maxits <= 0) error("maxits must be positive"); - endif - maxits = ceil(maxits); - - [aa,bb] = sys2ss(sys); - nn = sysdimensions(sys,"cst"); - mm = sysdimensions(sys,"in"); - pp = sysdimensions(sys,"out"); - - if(size(Q) != [nn, nn]) - error("Q(%dx%d); sys has %d states",rows(Q),columns(Q),nn); - elseif(size(Qf) != [nn, nn]) - error("Qf(%dx%d); sys has %d states",rows(Qf),columns(Qf),nn); - elseif(size(R) != [mm, mm]) - error("R(%dx%d); sys has %d inputs",rows(R),columns(R),mm); - endif - - ## construct Hamiltonian matrix - H = [aa , -(bb/R)*bb' ; -Q, -aa']; - - ## select time step to avoid numerical overflow - fast_eig = max(abs(eig(H))); - tc = log(10)/fast_eig; - nst = ceil((tf-t0)/tc); - tvals = -linspace(-tf,-t0,nst); - Plist = list(Qf); - In = eye(nn); - n1 = nn+1; - n2 = nn+nn; - done = 0; - while(!done) - done = 1; # assume this pass will do the job - ## sort time values in reverse order - tvals = -sort(-tvals); - tvlen = length(tvals); - maxerr = 0; - ## compute new values of P(t); recompute old values just in case - for ii=2:tvlen - uv_i_minus_1 = [ In ; nth(Plist,ii-1) ]; - delta_t = tvals(ii-1) - tvals(ii); - uv = expm(-H*delta_t)*uv_i_minus_1; - Qi = uv(n1:n2,1:nn)/uv(1:nn,1:nn); - Plist(ii) = (Qi+Qi')/2; - ## check error - Perr = norm(nth(Plist,ii) - nth(Plist,ii-1))/norm(nth(Plist,ii)); - maxerr = max(maxerr,Perr); - if(Perr > Ptol) - new_t = mean(tvals([ii,ii-1])); - tvals = [tvals, new_t]; - done = 0; - endif - endfor - - ## check number of iterations - maxits = maxits - 1; - done = done+(maxits==0); - endwhile - if(maxerr > Ptol) - warning("dre: \n\texiting with%4d points, max rel chg. =%e, Ptol=%e\n", ... - tvlen,maxerr,Ptol); - tvals = tvals(1:length(Plist)); - endif - -endfunction diff --git a/scripts/control/frdemo.m b/scripts/control/frdemo.m deleted file mode 100644 --- a/scripts/control/frdemo.m +++ /dev/null @@ -1,601 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} frdemo () -## Octave Controls toolbox demo: Frequency Response demo -## @end deftypefn - -## Author: David Clem -## Created: August 15, 1994 -## a s hodel: updated to match new order of ss2zp outputs -## J Ingram: updated for system data structure format August 1996 - -function frdemo () - - disp("") - clc - j = 0; - while (j != 4) - disp(""); - j = menu("Octave Controls Systems Toolbox Frequency Response Demo", - "Bode analysis (bode)", - "Nyquist analysis (nyquist)", - "Nichols analysis (nichols)", - "Return to main demo menu"); - - if (j == 1) - k1 = 0; - while (k1 != 4) - disp("\n"); - clc - - k1 = menu("Bode analysis (bode)", - "Continuous system bode analysis", - "Discrete system bode analysis", - "Bode command description", - "Return to frdemo menu"); - - if( k1 == 1 ) - disp(" ") - clc - disp("\nContinuous system bode analysis\n"); - disp("Example #1:") - disp("\nConsider the system sys1="); - sys1=tf2sys([1, 1], [1, 0, -1]); - sysout(sys1); - disp("\nPole-zero form can be obtained as follows:") - cmd = "sysout(sys1,""zp"");"; - run_cmd; - disp("The systems bode plot is obtained as follows:"); - cmd = "bode(sys1);"; - run_cmd; - disp("\nNotice that bode automatically labels the plots according to") - disp("the selected input/output combinations.") - disp(" ") - disp("If the frequency range is not specified, bode automatically") - disp("selects a frequency range based on the natural frequencies of") - disp("of all poles away from s=0 (or z=1 in discrete time). Bode") - disp("then checks to make sure that the phase plot is sufficiently") - disp("smooth that relevant plot behavior is captured.") - disp("") - disp("Bode exits with an error if the system is mixed (both continuous") - disp("and discrete; see is_digital for conditions)") - prompt - disp("\nIf the plot magnitude, phase and frequency data is desired, the"); - disp("user can enter the following command:"); - disp("\n[Mag,Phase,w] = bode(sys);"); - disp("\nThis will return three vectors containing the magnitude,"); - disp("phase and frequency.\n"); - prompt; - - disp("") - clc - disp("Example #2, sys2=") - cmd = "sys2=zp2sys(1, [-1, -5], 10);"; - eval(cmd); - cmd = "sysout(sys2);"; - eval(cmd); - disp("\nThe bode plot command is identical to the tf form:") - cmd = "bode(sys2);"; - run_cmd; - disp("\nThe internal representation of the system is not important;") - disp("bode automatically sorts it out internally.") - prompt; - - disp("") - clc - disp("Example #3, Consider the following state space system sys3=:\n"); - cmd = "sys3=ss2sys([0, 1; -1000, -1001], [0; 1], [0, -891], 1);"; - eval(cmd); - cmd = "sysout(sys3);"; - eval(cmd); - disp("\nOnce again, the bode plot command is the same:"); - cmd = "bode(sys3);"; - run_cmd; - disp("\nSuppose the user is interested in the response of the system"); - disp("defined over the input frequency range of 1 - 1000 rad/s.\n"); - disp("First, a frequency vector is required. It can be created"); - disp("with the command:\n"); - cmd = "wrange = logspace(log10(1),log10(1000),100);"; - disp(cmd); - eval(cmd); - disp("\nThis creates a logarithmically scaled frequency vector with"); - disp("100 values between 1 and 1000 rad/s\n"); - disp("Then, the bode command includes wrange in the input arguments"); - disp("like this:"); - cmd = "bode(sys3,wrange);"; - run_cmd; - prompt; - - disp("") - clc - disp("\nExample #4, The state-space system from example 3 will be"); - disp("grouped with the system from example 2 to form a MIMO system"); - disp("The commands to do this grouping are as follows (changing signal"); - disp("names for clarity):"); - cmd = "sys2 = syssetsignals(sys2,\"out\",\"y_sys2\");"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"in\",\"u_sys2\");"; - disp(cmd); eval(cmd); - cmd = "nn = sysdimensions(sys2);"; - disp(cmd); eval(cmd); - cmd = "[nn,nz] = sysdimensions(sys2);"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"st\",sysdefioname(nn+nz,\"x_sys2\"));"; - disp(cmd); eval(cmd); - cmd = "sys_mimo = sysgroup(sys2,sys3);"; - disp(cmd); eval(cmd); - disp("The resulting state-space system (after changing signal names"); - disp("in sys2) is"); - cmd = "sysout(sys_mimo)"; - eval(cmd); - disp("\nNotice that there are now 2 inputs and 2 outputs, and that it did"); - disp("not matter what form the two systems were in when they were grouped."); - disp(["\nTo view the system's bode plots, execute the", - " following command:\n"]) - cmd = "bode(sys_mimo);"; - run_cmd; - prompt - disp("\nTo view the bode plots for selected channels, the command form changes:") - cmd = "wrange = [];"; - disp(cmd) - eval(cmd); - cmd = "out = 1;"; - disp(cmd) - eval(cmd); - cmd = "in = 1;"; - disp(cmd) - eval(cmd); - cmd = "bode(sys_mimo,wrange,out,in);"; - run_cmd; - disp("\nNotice that this bode plot is the same as the plot from example 2."); - prompt - closeplot - - elseif( k1 == 2 ) - disp("") - clc - disp("\nDiscrete system bode analysis\n"); - disp("Display bode plots of a discrete SISO system (dbode)\n") - disp("Example #1, Consider the following discrete transfer"); - disp(" function:\n"); - cmd = "sys1 = tf2sys([0.00100502, -0.00099502], [1, -2, 1], 0.001);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys1)"; - disp(cmd); - eval(cmd); - disp("\nTo examine open loop zeros and poles of the system,"); - disp("use the command:\n") - cmd = "sysout(sys1,""zp"");"; - run_cmd; - disp("\nTo view the system's bode plots, execute the following"); - disp("command:\n") - cmd = "bode(sys1);"; - run_cmd; - disp("\nNotice (1) the plot label uses exp(jwT) for its title axis. This") - disp(" allows the user to determine what kind of system was") - disp(" used to generate the bode plot"); - disp(" (2) the system poles are both at z=1, (break frequency at") - disp(" jwT = 0); pure integrator poles like this are discarded") - disp(" by Octave when computing the plot frequency range.") - - disp("\nIf magnitude, phase, and frequency data are also desired,"); - disp(" perform the following command instead:\n"); - disp("[M,P,w]=dbode(num,den,T,wrange).\n Where:"); - disp("M => Bode magnitude response data"); - disp("P => Bode phase response data"); - disp("w => frequencies that M and P were evaluated at"); - disp("sys1 => system data structure") - disp("T => sample period") - disp("wrange => optional vector of frequencies") - disp(" if wrange is entered in the argument list, the"); - disp(" system will be evaluated at these specific"); - disp(" frequencies\n"); - - prompt - disp("") - clc - disp("Example #2, Consider the following set of discrete poles and"); - disp("zeros:\n") - cmd = "sys2 = zp2sys([0.99258;0.99745],[0.99961;0.99242],1,0.001);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys2)"; - disp(cmd); - eval(cmd); - disp("\nTo view the system's bode plots, execute the following"); - disp("command:\n") - cmd = "bode(sys2);"; - run_cmd; - disp("Notice that the bode command is the same in both of the previous"); - disp("examples. The bode command is also the same for the continuous case."); - disp("The function, dbode, is no longer used."); - - prompt - disp("") - clc - disp("\nExample #3, Now consider the following state space system:\n"); - cmd = "sys3 = ss2sys([.857, .0011; 0, .99930],[1;1],[-.6318, .0057096],5.2, .001);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys3);"; - disp(cmd); - eval(cmd); - disp("\nTo view the system's bode plots, execute the following command:\n") - cmd = "bode(sys3);"; - run_cmd; - disp("\nAgain, notice that the bode command is the same regardless of the form"); - disp("of the system."); - disp("\nSuppose the user is interested in the response of the system"); - disp("defined over the input frequency range of 1 - 1000 rad/s.\n"); - disp("First, a frequency vector is required. It can be created"); - disp("with the command:\n"); - cmd = "wrange = logspace(log10(1),log10(1000),100);"; - disp(cmd); - eval(cmd); - disp("\nThis creates a logrithmetically scaled frequency vector with"); - disp("100 values between 1 and 1000 rad/s\n"); - disp("Then, the bode command includes wrange in the input arguments"); - disp("like this:"); - cmd = "bode(sys3,wrange);"; - run_cmd; - prompt; - - disp("") - clc - disp("\nExample #4, We will now examine a MIMO state-space system. Systems"); - disp("two and three will be grouped."); - cmd = "[nn,nz] = sysdimensions(sys2);"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"out\",\"y_sys2\");"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"in\",\"u_sys2\");"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"st\",sysdefioname(nn+nz,\"x_sys2\"));"; - disp(cmd); eval(cmd); - cmd = "sys_mimo = sysgroup(sys2,sys3);"; - disp(cmd); eval(cmd); - cmd = "sysout(sys_mimo);"; - disp(cmd); - eval(cmd); - disp("\nTo view the system's bode plots, execute the following command:\n") - cmd = "bode(sys_mimo);"; - run_cmd; - prompt - - disp("\nThe bode plot of a single channel is viewed as follows:") - cmd = "wrange = [];"; - disp(cmd) - eval(cmd); - cmd = "out = 1;"; - disp(cmd) - eval(cmd); - cmd = "in = 1;"; - disp(cmd) - eval(cmd); - cmd = "bode(sys_mimo,wrange,out,in);"; - run_cmd; - disp("\nNotice that this bode plot is the same as the plot from example 2."); - prompt - closeplot - - elseif( k1 == 3 ) - help bode - prompt - endif - endwhile - elseif (j == 2) - k2 = 0; - disp(""); - while (k2 != 4) - disp("\n"); - help nyquist - prompt; - disp("") - clc; - - k2 = menu("Nyquist analysis (Nyquist)", - "Continuous system nyquist analysis", - "Discrete system nyquist analysis", - "Mixed system nyquist analysis", - "Return to frdemo menu"); - - if( k2 == 1 ) - disp("") - clc - disp("\nContinuous system nyquist analysis\n"); - disp("Display Nyquist plots of a SISO system (nyquist)\n") - disp("Example #1, Consider the following transfer function:\n") - cmd = "sys1 = tf2sys(1, [1, 0.8, 1]);"; - disp(cmd); - eval(cmd); - disp("To examine the transfer function, use the command:"); - cmd = "sysout(sys1);"; - disp(cmd); - eval(cmd); - disp("\nTo examine the open loop zeros and poles, use the command:"); - cmd = "sysout(sys1,""zp"");"; - run_cmd; - disp("\nTo view the system""s nyquist plot, execute the following"); - disp("command:\n") - cmd = "nyquist(sys1);"; - run_cmd; - disp("\nIf the real and imaginary parts of the response are desired,"); - disp("use the following command:"); - disp("command: [R,I,w]=nyquist(sys1);\n"); - disp("If the user desires to evaluate the response in a certain"); - disp("frequency range, he may do so by entering the following:"); - disp("command: [M,P,w]=nyquist(num,den,wrange).\n") - disp("wrange is a vector of frequencies that spans the desired"); - disp("viewing range.\n"); - disp("This will be illustrated in the third nyquist example.\n") - disp("Variable Description:\n") - disp("R => real part of response") - disp("I => imaginary part of response") - disp("w => frequencies that the transfer function was evaluated at") - disp("sys1 => system data structure") - disp("wrange => optional vector of frequencies") - disp(" if wrange is entered in the argument list, the"); - disp(" system will be evaluated at these specific"); - disp(" frequencies\n") - prompt - - disp("") - clc - disp("Example #2, Consider the following set of poles and zeros:\n") - cmd = "sys2 = zp2sys([-1;-4],[-2+1.4142i;-2-1.4142i],1);"; - disp(cmd); - eval(cmd); - disp("\nTo examine the poles and zeros, use the command:"); - cmd = "sysout(sys2)"; - disp(cmd); - eval(cmd); - disp("\nTo view the system""s nyquist plot, execute the following"); - disp("command:\n") - cmd = "nyquist(sys2);"; - run_cmd; - prompt - - disp("") - clc - disp("\nExample #3, Consider the following state space system:\n") - cmd = "sys3 = ss2sys([0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1; 0, 0, -20, -12],[0;0;0;1],[50, 100, 0, 0],0);"; - disp(cmd); - eval(cmd); - disp("\nTo examine the state-space system, use the command:"); - cmd = "sysout(sys3)"; - disp(cmd); - eval(cmd); - disp("\nTo examine the poles and zeros, use the command:"); - cmd = "sysout(sys3,""zp"")"; - run_cmd; - disp("\nTo view the system""s nyquist plot, execute the following"); - disp("commands:\n") - cmd = "nyquist(sys3);"; - run_cmd; - prompt - - disp("Example #3 (continued), If the user wishes to evaluate the"); - disp("system response over a desired frequency range, he must first"); - disp("create a frequency vector.\n") - disp("For example, suppose the user is interested in the response"); - disp("of the system defined above over input frequency range of"); - disp("3 - 100 rad/s.\n") - disp("A frequency vector can be created using the command:\n"); - cmd = "wrange = logspace(log10(3),log10(100),100);"; - disp(cmd); - eval(cmd); - disp("\nNyquist can be run again using the frequency vector as"); - disp("follows:\n") - cmd = "nyquist(sys3,wrange);"; - run_cmd; - prompt - - disp("") - clc - disp("Example #4, Nyquist can be used for MIMO systems if the system has"); - disp("an equal number of inputs and outputs. Otherwise, nyquist returns"); - disp("an error. To examine a MIMO system, systems 2 and 3 will be grouped"); - cmd = "[nn,nz] = sysdimensions(sys2);"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"out\",\"y_sys2\");"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"in\",\"u_sys2\");"; - disp(cmd); eval(cmd); - cmd = "sys2 = syssetsignals(sys2,\"st\",sysdefioname(nn+nz,\"x_sys2\"));"; - disp(cmd); eval(cmd); - cmd = "sys_mimo = sysgroup(sys2,sys3);"; - disp(cmd); eval(cmd); - cmd = "sysout(sys_mimo);"; - disp(cmd); - eval(cmd); - disp("\nTo view the system's nyquist plot, execute the following command:\n") - cmd = "nyquist(sys_mimo);"; - run_cmd; - prompt - disp("\nTo view the nyquist plots for selected channels, the command form changes:") - cmd = "nyquist(sys_mimo,[],1,1);"; - run_cmd; - disp("\nNotice that this bode plot is the same as the plot from example 2."); - prompt - closeplot - - - - elseif( k2 == 2 ) - disp("") - clc - disp("\nDiscrete system nyquist analysis\n"); - disp("Display Nyquist plots of a discrete SISO system (nyquist)\n") - disp("We will first define a sampling time, T"); - cmd = "T = 0.01;"; - disp(cmd); - eval(cmd); - disp("\nExample #1, Consider the following transfer function:\n") - cmd = "sys1 = tf2sys([2, -3.4, 1.5],[1, -1.6, 0.8],T);"; - disp(cmd); - eval(cmd); - disp("To examine the transfer function, use the command:"); - cmd = "sysout(sys1);"; - disp(cmd); - eval(cmd); - disp("\nTo examine the open loop zeros and poles, use the command:"); - cmd = "sysout(sys1,""zp"")"; - disp(cmd); - eval(cmd); - disp("\nTo view the system""s nyquist plot, execute the following"); - disp("command:") - cmd = "nyquist(sys1);"; - run_cmd; - disp("To change the range used for the frequency, a frequency"); - disp("is needed. Suppose the user would like to examine the"); - disp("nyquist plot in the frequency range of 0.01 - 31.6 rad/s."); - disp("\nThe frequency vector needed to do this is created with the"); - disp("command:"); - cmd = "wrange = logspace(-2,1.5,200);"; - disp(cmd); - eval(cmd); - disp("\nNyquist can be run again with this frequency vector"); - cmd = "nyquist(sys1,wrange);"; - run_cmd; - disp("\nIf the real and imaginary parts of the response are desired,"); - disp("perform the following command:\n"); - disp("[R,I,w]=nyquist(sys,wrange)\n") - disp("Variable Description:\n") - disp("R => real part of response") - disp("I => imaginary part of response") - disp("w => frequencies that the transfer function was evaluated at") - disp("sys => The system data structure"); - disp("wrange => optional vector of frequencies") - disp(" if wrange is entered in the argument list, the"); - disp(" system will be evaluated at these specific"); - prompt - - disp("") - clc - disp("\nExample #2, Consider the following set of poles and zeros:\n") - cmd = "sys2 = zp2sys([0.98025 + 0.01397i; 0.98025 - 0.01397i],[0.96079;0.99005],1,T);"; - disp(cmd); - eval(cmd); - disp("\nTo examine the open loop zeros and poles, use the command:"); - cmd = "sysout(sys2)"; - disp(cmd); - eval(cmd); - disp("\nTo view the system's nyquist plot between the frequencies"); - disp("0.01 - 100 rad/s, execute the following commands:\n") - cmd = "wrange = logspace(-2,2,100);"; - disp(cmd); - eval(cmd); - cmd = "nyquist(sys2,wrange);"; - run_cmd; - prompt; - - disp("") - clc - disp("\nExample #3, Consider the following discrete state space"); - disp("system:\n"); - disp("This example will use the same system used in the third"); - disp("example in the continuous nyquist demo. First, that system"); - disp("will have to be re-entered useing the following commands:\n"); - cmd = "sys3 = ss2sys([0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1; 0, 0, -20, -12],[0;0;0;1],[50, 100, 0, 0],0);"; - disp(cmd); - eval(cmd); - disp("\nTo examine the state-space system, use the command:"); - cmd = "sysout(sys3)"; - disp(cmd); - eval(cmd); - disp("\nTo examine the poles and zeros, use the command:"); - cmd = "sysout(sys3,""zp"")"; - disp(cmd); - eval(cmd); - disp("\nTo convert the system to discrete time, we need a sampling"); - disp("time which can be entered like this:"); - cmd = "T = 0.01"; - disp(cmd); - eval(cmd); - disp("\nNow the command, c2d, is used to convert the system from"); - disp("continuous to discrete time, with the following command"); - cmd = "dsys3 = c2d(sys3,T);"; - run_cmd; - disp("\nTo examine the new discrete state-space system, use the"); - disp("command"); - cmd = "sysout(dsys3);"; - disp(cmd); - eval(cmd); - disp("\nTo examine the new discrete poles and zeros, use the command:"); - cmd = "sysout(dsys3,""zp"")"; - disp(cmd); - eval(cmd); - disp("\nTo view the system's nyquist plot, execute the following"); - disp("commands:\n"); - cmd = "gset xrange [-4:2];"; - disp(cmd); eval(cmd); - cmd = "gset yrange [-2.5:2.5];"; - disp(cmd); eval(cmd); - cmd = "nyquist(dsys3);"; - run_cmd; - disp("Notice that the asymptotes swamp out the behavior of the plot") - disp("near the origin. You may use interactive nyquist plots") - disp("to \"zoom in\" on a plot as follows:") - - cmd = "atol = 1;"; - disp(cmd) - eval(cmd) - cmd = "nyquist(dsys3,[],[],[],atol);"; - run_cmd - prompt - - - disp("") - clc - disp("MIMO SYSTEM: Nyquist cannot be used for discrete MIMO systems"); - disp("at this time."); - ## cmd = "dsys_mimo = sysgroup(sys2,dsys3);"; - ## disp(cmd); - ## eval(cmd); - ## cmd = "sysout(dsys_mimo);"; - ## disp(cmd); - ## eval(cmd); - ## disp("\nTo view the system's nyquist plot, execute the following command:\n") - ## cmd = "nyquist(dsys_mimo);"; - ## run_cmd; - ## prompt - ## disp("\nTo view the nyquist plots for selected channels, the command form changes:") - ## cmd = "nyquist(dsys_mimo,[],1,1);"; - ## run_cmd; - ## disp("\nNotice that this bode plot is the same as the plot from example 2."); - prompt - closeplot - - - elseif( k2 == 3 ) - disp("\nMixed system nyquist analysis\n"); - disp("Nyquist exits with an error if it is passed a ""mixed"" system (one") - disp("with both continuous and discrete states). Use c2d or d2c to") - disp("convert the system to either pure digital or pure continuous form"); - endif - endwhile - elseif (j == 3) - help nichols - prompt - endif - endwhile - -endfunction diff --git a/scripts/control/freqchkw.m b/scripts/control/freqchkw.m deleted file mode 100644 --- a/scripts/control/freqchkw.m +++ /dev/null @@ -1,43 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retval} =} freqchkw (@var{w}) -## Used by @code{freqresp} to check that input frequency vector @var{w} -## is valid. -## Returns boolean value. -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 1996 - -function USEW = freqchkw (w) - - if(isempty(w)) - USEW = 0; - elseif(!is_vector(w)) - error(["w (",num2str(rows(w)),"x",num2str(columns(w)), ... - "): must be [], a vector or a scalar"]); - elseif( (max(abs(imag(w))) != 0) && (min(real(w)) <= 0) ) - error("w must have real positive entries"); - else - w = sort(w); - USEW = 1; # vector provided (check values later) - endif - -endfunction diff --git a/scripts/control/freqresp.m b/scripts/control/freqresp.m deleted file mode 100644 --- a/scripts/control/freqresp.m +++ /dev/null @@ -1,133 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{out} =} freqresp (@var{sys}, @var{USEW}@{,@var{w}@}); -## Frequency response function - used internally by @code{bode}, @code{nyquist}. -## minimal argument checking; "do not attempt to do this at home" -## -## @strong{Inputs} -## @table @var -## @item sys -## system data structure -## @item USEW -## returned by @code{freqchkw} -## @item optional -## must be present if @var{USEW} is true (nonzero) -## @end table -## @strong{Outputs} -## @table @var -## @item @var{out} -## vector of finite @math{G(j*w)} entries (or @math{||G(j*w)||} for MIMO) -## @item w -## vector of corresponding frequencies -## @end table -## @end deftypefn - -## Author: R. Bruce Tenison -## Created: July 11, 1994 - -function [ff, w] = freqresp (sys, USEW, w); - - ## SYS_INTERNAL accesses members of system data structure - - save_val = empty_list_elements_ok; - empty_list_elements_ok = 1; - - ## Check Args - if( (nargin < 2) || (nargin > 4) ) - usage ("[ff,w] = freqresp(sys,USEW{,w})"); - elseif( USEW & (nargin < 3) ) - error("USEW=1 but w was not passed."); - elseif( USEW & isempty(w)) - warning("USEW=1 but w is empty; setting USEW=0"); - USEW=0; - endif - - DIGITAL = is_digital(sys); - - ## compute default w if needed - if(!USEW) - if(is_siso(sys)) - sys = sysupdate(sys,"zp"); - [zer,pol] = sys2zp(sys); - else - zer = tzero(sys); - pol = eig(sys2ss(sys)); - endif - - ## get default frequency range - [wmin,wmax] = bode_bounds(zer,pol,DIGITAL,sysgettsam(sys)); - w = logspace(wmin,wmax,50); - else - w = reshape(w,1,length(w)); # make sure it's a row vector - endif - - ## now get complex values of s or z - if(DIGITAL) - jw = exp(i*w*sysgettsam(sys)); - else - jw = i*w; - endif - - [nn,nz,mm,pp] = sysdimensions(sys); - - ## now compute the frequency response - divide by zero yields a warning - if (strcmp(sysgettype(sys),"zp")) - ## zero-pole form (preferred) - [zer,pol,sysk] = sys2zp(sys); - ff = ones(size(jw)); - l1 = min(length(zer)*(1-isempty(zer)),length(pol)*(1-isempty(pol))); - for ii=1:l1 - ff = ff .* (jw - zer(ii)) ./ (jw - pol(ii)); - endfor - - ## require proper transfer function, so now just get poles. - for ii=(l1+1):length(pol) - ff = ff ./ (jw - pol(ii)); - endfor - ff = ff*sysk; - - elseif (strcmp(sysgettype(sys),"tf")) - ## transfer function form - [num,den] = sys2tf(sys); - ff = polyval(num,jw)./polyval(den,jw); - elseif (mm==pp) - ## The system is square; do state-space form bode plot - [sysa,sysb,sysc,sysd,tsam,sysn,sysnz] = sys2ss(sys); - n = sysn + sysnz; - for ii=1:length(jw); - ff(ii) = det(sysc*((jw(ii).*eye(n)-sysa)\sysb)+sysd); - endfor; - else - ## Must be state space... bode - [sysa,sysb,sysc,sysd,tsam,sysn,sysnz] = sys2ss(sys); - n = sysn + sysnz; - for ii=1:length(jw); - ff(ii) = norm(sysc*((jw(ii)*eye(n)-sysa)\sysb)+sysd); - endfor - - endif - - w = reshape(w,1,length(w)); - ff = reshape(ff,1,length(ff)); - - ## restore global variable - empty_list_elements_ok = save_val; -endfunction - diff --git a/scripts/control/gram.m b/scripts/control/gram.m deleted file mode 100644 --- a/scripts/control/gram.m +++ /dev/null @@ -1,34 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{m} =} gram (@var{a}, @var{b}) -## Return controllability grammian @var{m} of the continuous time system -## @math{ dx/dt = a x + b u}. -## -## @var{m} satisfies @math{ a m + m a' + b b' = 0 }. -## @end deftypefn - -## Author: A. S. Hodel - -function m = gram (a, b) - - ## let lyap do the error checking... - m = lyap(a,b*b'); - -endfunction diff --git a/scripts/control/impulse.m b/scripts/control/impulse.m deleted file mode 100644 --- a/scripts/control/impulse.m +++ /dev/null @@ -1,89 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{y}, @var{t}] =} impulse (@var{sys}@{, @var{inp},@var{tstop}, @var{n}@}) -## Impulse response for a linear system. -## The system can be discrete or multivariable (or both). -## If no output arguments are specified, @code{impulse} -## produces a plot or the impulse response data for system @var{sys}. -## -## @strong{Inputs} -## @table @var -## @item sys -## System data structure. -## @item inp -## Index of input being excited -## @item tstop -## The argument @var{tstop} (scalar value) denotes the time when the -## simulation should end. -## @item n -## the number of data values. -## -## Both parameters @var{tstop} and @var{n} can be omitted and will be -## computed from the eigenvalues of the A-Matrix. -## @end table -## @strong{Outputs} -## @var{y}, @var{t}: impulse response -## @end deftypefn -## @seealso{step and stepimp} - -## Author: Kai P. Mueller -## Created: October 2, 1997 -## based on lsim.m of Scottedward Hodel -## modified by - -function [y, t] = impulse (sys, inp, tstop, n) - - if((nargin < 1) || (nargin > 4)) - usage("[y, u] = impulse(sys[, inp, tstop, n])"); - endif - - if(nargout > 2) - usage("[y, u] = impulse(sys[, inp, tstop, n])"); - endif - - if(!is_struct(sys)) - error("impulse: sys must be a system data structure."); - endif - - if (nargout == 0) - switch (nargin) - case (1) - stepimp(2, sys); - case (2) - stepimp(2, sys, inp); - case (3) - stepimp(2, sys, inp, tstop); - case (4) - stepimp(2, sys, inp, tstop, n); - endswitch - else - switch (nargin) - case (1) - [y, t] = stepimp(2, sys); - case (2) - [y, t] = stepimp(2, sys, inp); - case (3) - [y, t] = stepimp(2, sys, inp, tstop); - case (4) - [y, t] = stepimp(2, sys, inp, tstop, n); - endswitch - endif - -endfunction diff --git a/scripts/control/is_abcd.m b/scripts/control/is_abcd.m deleted file mode 100644 --- a/scripts/control/is_abcd.m +++ /dev/null @@ -1,97 +0,0 @@ -## Copyright (C) 1997 Kai P. Mueller -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retval} =} is_abcd (@var{a}@{, @var{b}, @var{c}, @var{d}@}) -## Returns @var{retval} = 1 if the dimensions of @var{a}, @var{b}, -## @var{c}, @var{d} are compatible, otherwise @var{retval} = 0 with an -## appropriate diagnostic message printed to the screen. The matrices -## b, c, or d may be omitted. -## @end deftypefn -## @seealso{abcddim} - -## Author: Kai P. Mueller -## Created: November 4, 1997 -## based on is_controllable.m of Scottedward Hodel - -function retval = is_abcd (a, b, c, d) - - retval = 0; - switch (nargin) - case (1) - ## A only - [na, ma] = size(a); - if (na != ma) - disp("Matrix A ist not square.") - endif - case (2) - ## A, B only - [na, ma] = size(a); [nb, mb] = size(b); - if (na != ma) - disp("Matrix A ist not square.") - return; - endif - if (na != nb) - disp("A and B column dimension different.") - return; - endif - case (3) - ## A, B, C only - [na, ma] = size(a); [nb, mb] = size(b); [nc, mc] = size(c); - if (na != ma) - disp("Matrix A ist not square.") - return; - endif - if (na != nb) - disp("A and B column dimensions not compatible.") - return; - endif - if (ma != mc) - disp("A and C row dimensions not compatible.") - return; - endif - case (4) - ## all matrices A, B, C, D - [na, ma] = size(a); [nb, mb] = size(b); - [nc, mc] = size(c); [nd, md] = size(d); - if (na != ma) - disp("Matrix A ist not square.") - return; - endif - if (na != nb) - disp("A and B column dimensions not compatible.") - return; - endif - if (ma != mc) - disp("A and C row dimensions not compatible.") - return; - endif - if (mb != md) - disp("B and D row dimensions not compatible.") - return; - endif - if (nc != nd) - disp("C and D column dimensions not compatible.") - return; - endif - otherwise - usage("retval = is_abcd(a [, b, c, d])") - endswitch - ## all tests passed, signal ok. - retval = 1; -endfunction diff --git a/scripts/control/is_controllable.m b/scripts/control/is_controllable.m deleted file mode 100644 --- a/scripts/control/is_controllable.m +++ /dev/null @@ -1,114 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{retval}, @var{U}] =} is_controllable (@var{sys}@{, @var{tol}@}) -## @deftypefnx {Function File} {[@var{retval}, @var{U}] =} is_controllable (@var{a}@{, @var{b}, @var{tol}@}) -## Logical check for system controllability. -## -## @strong{Inputs} -## @table @var -## @item sys -## system data structure -## @item a -## @itemx b -## @var{n} by @var{n}, @var{n} by @var{m} matrices, respectively -## @item tol -## optional roundoff paramter. default value: @code{10*eps} -## @end table -## -## @strong{Outputs} -## @table @var -## @item retval -## Logical flag; returns true (1) if the system @var{sys} or the -## pair (@var{a},@var{b}) is controllable, whichever was passed as input -## arguments. -## @item U -## U is an orthogonal basis of the controllable subspace. -## @end table -## -## @strong{Method} -## Controllability is determined by applying Arnoldi iteration with -## complete re-orthogonalization to obtain an orthogonal basis of the -## Krylov subspace -## @example -## span ([b,a*b,...,a^@{n-1@}*b]). -## @end example -## The Arnoldi iteration is executed with @code{krylov} if the system -## has a single input; otherwise a block Arnoldi iteration is performed -## with @code{krylovb}. -## @end deftypefn -## @seealso{size, rows, columns, length, is_matrix, is_scalar, is_vector -## is_observable, is_stabilizable, is_detectable, krylov, and krylovb} - -## Author: A. S. Hodel -## Created: August 1993 -## Updated by A. S. Hodel (scotte@eng.auburn.edu) Aubust, 1995 to use krylovb -## Updated by John Ingram (ingraje@eng.auburn.edu) July, 1996 for packed systems - -function [retval, U] = is_controllable (a, b, tol) - - deftol = 1; # assume default tolerance - if(nargin < 1 | nargin > 3) - usage("[retval,U] = %s\n\t%s", "is_controllable(a {, b, tol})", ... - "is_controllable(sys{,tol})"); - elseif(is_struct(a)) - ## system structure passed. - sys = sysupdate(a,"ss"); - [a,bs] = sys2ss(sys); - if(nargin > 2) - usage("[retval,U] = is_controllable(sys{,tol})"); - elseif(nargin == 2) - tol = b; % get tolerance - deftol = 0; - endif - b = bs; - else - ## a,b arguments sent directly. - if(nargin < 2) - usage("[retval,U] = is_controllable(a {, b ,tol})"); - else - deftol = 1; - endif - endif - - ## check for default tolerance - if(deftol) tol = 1000*eps; endif - - ## check tol dimensions - if( !is_scalar(tol) ) - error("is_controllable: tol(%dx%d) must be a scalar", ... - rows(tol),columns(tol)); - elseif( !is_sample(tol) ) - error("is_controllable: tol=%e must be positive",tol); - endif - - ## check dimensions compatibility - n = is_square (a); - [nr, nc] = size (b); - - if (n == 0 | n != nr | nc == 0) - warning("is_controllable: a=(%dx%d), b(%dx%d)",rows(a),columns(a),nr,nc); - retval = 0; - else - ## call block-krylov subspace routine to get an orthogonal basis - ## of the controllable subspace. - [U,H,Ucols] = krylov(a,b,n,tol,1); - retval = (Ucols == n); - endif -endfunction diff --git a/scripts/control/is_detectable.m b/scripts/control/is_detectable.m deleted file mode 100644 --- a/scripts/control/is_detectable.m +++ /dev/null @@ -1,64 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{retval}, @var{U}] =} is_detectable (@var{a}, @var{c}@{, @var{tol}@}) -## @deftypefnx {Function File} {[@var{retval}, @var{U}] =} is_detectable (@var{sys}@{, @var{tol}@}) -## Test for detactability (observability of unstable modes) of -## (@var{a},@var{c}). -## -## Returns 1 if the system @var{a} or the pair (@var{a},@var{c})is -## detectable, 0 if not. -## -## @strong{See} @code{is_stabilizable} for detailed description of -## arguments and computational method. -## -## Default: tol = 10*norm(a,'fro')*eps -## -## @end deftypefn -## @seealso{is_stabilizable, size, rows, columns, length, is_matrix, -## is_scalar, and is_vector} - -## Author: A. S. Hodel -## Created: August 1993 -## Updated by John Ingram (ingraje@eng.auburn.edu) July 1996. - -function [retval, U] = is_detectable (a, c, tol) - - if( nargin < 1) - usage("[retval,U] = is_detectable(a , c {, tol})"); - elseif(is_struct(a)) - ## system form - if(nargin == 2) - tol = c; - elseif(nargin > 2) - usage("[retval,U] = is_detectable(sys {, tol})"); - endif - [a,b,c] = sys2ss(a); - elseif(nargin > 3) - usage("[retval,U] = is_detectable(a , c {, tol})"); - endif - if(exist("tol")) - [retval,U] = is_stabilizable (a', c', tol); - else - [retval,U] = is_stabilizable (a', c'); - endif - - -endfunction - diff --git a/scripts/control/is_dgkf.m b/scripts/control/is_dgkf.m deleted file mode 100644 --- a/scripts/control/is_dgkf.m +++ /dev/null @@ -1,258 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{retval}, @var{dgkf_struct} ] =} is_dgkf (@var{Asys}, @var{nu}, @var{ny}, @var{tol} ) -## Determine whether a continuous time state space system meets -## assumptions of DGKF algorithm. -## Partitions system into: -## @example -## [dx/dt] = [A | Bw Bu ][w] -## [ z ] [Cz | Dzw Dzu ][u] -## [ y ] [Cy | Dyw Dyu ] -## @end example -## or similar discrete-time system. -## If necessary, orthogonal transformations @var{Qw}, @var{Qz} and nonsingular -## transformations @var{Ru}, @var{Ry} are applied to respective vectors -## @var{w}, @var{z}, @var{u}, @var{y} in order to satisfy DGKF assumptions. -## Loop shifting is used if @var{Dyu} block is nonzero. -## -## @strong{Inputs} -## @table @var -## @item Asys -## system data structure -## @item nu -## number of controlled inputs -## @item ny -## number of measured outputs -## @item tol -## threshhold for 0. Default: 200@var{eps} -## @end table -## @strong{Outputs} -## @table @var -## @item retval -## true(1) if system passes check, false(0) otherwise -## @item dgkf_struct -## data structure of @code{is_dgkf} results. Entries: -## @table @var -## @item nw -## @itemx nz -## dimensions of @var{w}, @var{z} -## @item A -## system @var{A} matrix -## @item Bw -## (@var{n} x @var{nw}) @var{Qw}-transformed disturbance input matrix -## @item Bu -## (@var{n} x @var{nu}) @var{Ru}-transformed controlled input matrix; -## -## @strong{Note} @math{B = [Bw Bu] } -## @item Cz -## (@var{nz} x @var{n}) Qz-transformed error output matrix -## @item Cy -## (@var{ny} x @var{n}) @var{Ry}-transformed measured output matrix -## -## @strong{Note} @math{C = [Cz; Cy] } -## @item Dzu -## @item Dyw -## off-diagonal blocks of transformed @var{D} matrix that enter -## @var{z}, @var{y} from @var{u}, @var{w} respectively -## @item Ru -## controlled input transformation matrix -## @item Ry -## observed output transformation matrix -## @item Dyu_nz -## nonzero if the @var{Dyu} block is nonzero. -## @item Dyu -## untransformed @var{Dyu} block -## @item dflg -## nonzero if the system is discrete-time -## @end table -## @end table -## @code{is_dgkf} exits with an error if the system is mixed -## discrete/continuous -## -## @strong{References} -## @table @strong -## @item [1] -## Doyle, Glover, Khargonekar, Francis, "State Space Solutions -## to Standard H2 and Hinf Control Problems," IEEE TAC August 1989 -## @item [2] -## Maciejowksi, J.M.: "Multivariable feedback design," -## @end table -## @end deftypefn - -## Author: A. S. Hodel -## Updated by John Ingram July 1996 to accept structured systems - -## Revised by Kai P. Mueller April 1998 to solve the general H_infinity -## problem using unitary transformations Q (on w and z) -## and non-singular transformations R (on u and y) such -## that the Dzu and Dyw matrices of the transformed plant -## -## ~ -## P (the variable Asys here) -## -## become -## -## ~ -1 T -## D = Q D R = [ 0 I ] or [ I ], -## 12 12 12 12 -## -## ~ T -## D = R D Q = [ 0 I ] or [ I ]. -## 21 21 21 21 -## -## This transformation together with the algorithm in [1] solves -## the general problem (see [2] for example). - -function [retval, dgkf_struct] = is_dgkf (Asys, nu, ny, tol) - - if (nargin < 3) | (nargin > 4) - usage("[retval,dgkf_struct] = is_dgkf(Asys,nu,ny{,tol})"); - elseif (! is_scalar(nu) | ! is_scalar(ny) ) - error("is_dgkf: arguments 2 and 3 must be scalars") - elseif (! is_struct(Asys) ) - error("Argument 1 must be a system data structure"); - endif - if(nargin < 4) - tol = 200*eps; - elseif( !is_sample(tol) ) - error("is_dgkf: tol must be a positive scalar") - endif - - retval = 1; # assume passes test - - dflg = is_digital(Asys); - [Anc, Anz, nin, nout ] = sysdimensions(Asys); - - if( Anz == 0 & Anc == 0 ) - error("is_dgkf: no system states"); - elseif( nu >= nin ) - error("is_dgkf: insufficient number of disturbance inputs"); - elseif( ny >= nout ) - error("is_dgkf: insufficient number of regulated outputs"); - endif - - nw = nin - nu; nw1 = nw + 1; - nz = nout - ny; nz1 = nz + 1; - - [A,B,C,D] = sys2ss(Asys); - ## scale input/output for numerical reasons - if(norm (C, "fro") * norm (B, "fro") == 0) - error("||C||*||B|| = 0; no dynamic connnection from inputs to outputs"); - endif - xx = sqrt(norm(B, Inf) / norm(C, Inf)); - B = B / xx; C = C * xx; - - ## partition matrices - Bw = B(:,1:nw); Bu = B(:,nw1:nin); - Cz = C(1:nz,:); Dzw = D(1:nz,1:nw); Dzu = D(1:nz,nw1:nin); - Cy = C(nz1:nout,:); Dyw = D(nz1:nout,1:nw); Dyu = D(nz1:nout,nw1:nin); - - ## Check for loopo shifting - Dyu_nz = (norm(Dyu,Inf) != 0); - if (Dyu_nz) - warning("is_dgkf: D22 nonzero; performing loop shifting"); - endif - - ## 12 - rank condition at w = 0 - xx =[A, Bu; Cz, Dzu]; - [nr, nc] = size(xx); - irank = rank(xx); - if (irank != nc) - retval = 0; - warning(sprintf("rank([A Bu; Cz Dzu]) = %d, need %d; n=%d, nz=%d, nu=%d", ... - irank,nc,(Anc+Anz),nz,nu)); - warning(" *** 12-rank condition violated at w = 0."); - endif - - ## 21 - rank condition at w = 0 - xx =[A, Bw; Cy, Dyw]; - [nr, nc] = size(xx); - irank = rank(xx); - if (irank != nr) - retval = 0; - warning(sprintf("rank([A Bw; Cy Dyw]) = %d, need %d; n=%d, ny=%d, nw=%d", ... - irank,nr,(Anc+Anz),ny,nw)); - warning(" *** 21-rank condition violated at w = 0."); - endif - - ## can Dzu be transformed to become [0 I]' or [I]? - ## This ensures a normalized weight - [Qz, Ru] = qr(Dzu); - irank = rank(Ru); - if (irank != nu) - retval = 0; - warning(sprintf("*** rank(Dzu(%d x %d) = %d", nz, nu, irank)); - warning(" *** Dzu does not have full column rank."); - endif - if (nu >= nz) - Qz = Qz(:,1:nu)'; - else - Qz = [Qz(:,(nu+1):nz), Qz(:,1:nu)]'; - endif - Ru = Ru(1:nu,:); - - ## can Dyw be transformed to become [0 I] or [I]? - ## This ensures a normalized weight - [Qw, Ry] = qr(Dyw'); - irank = rank(Ry); - if (irank != ny) - retval = 0; - warning(sprintf("*** rank(Dyw(%d x %d) = %d", ny, nw, irank)); - warning(" *** Dyw does not have full row rank."); - endif - - if (ny >= nw) - Qw = Qw(:,1:ny); - else - Qw = [Qw(:,(ny+1):nw), Qw(:,1:ny)]; - endif - Ry = Ry(1:ny,:)'; - - ## transform P by Qz/Ru and Qw/Ry - Bw = Bw*Qw; - Bu = Bu/Ru; - B = [Bw, Bu]; - Cz = Qz*Cz; - Cy = Ry\Cy; - C = [Cz; Cy]; - Dzw = Qz*Dzw*Qw; - Dzu = Qz*Dzu/Ru; - Dyw = Ry\Dyw*Qw; - - ## pack the return structure - dgkf_struct.nw = nw; - dgkf_struct.nu = nu; - dgkf_struct.nz = nz; - dgkf_struct.ny = ny; - dgkf_struct.A = A; - dgkf_struct.Bw = Bw; - dgkf_struct.Bu = Bu; - dgkf_struct.Cz = Cz; - dgkf_struct.Cy = Cy; - dgkf_struct.Dzw = Dzw; - dgkf_struct.Dzu = Dzu; - dgkf_struct.Dyw = Dyw; - dgkf_struct.Dyu = Dyu; - dgkf_struct.Ru = Ru; - dgkf_struct.Ry = Ry; - dgkf_struct.Dyu_nz = Dyu_nz; - dgkf_struct.dflg = dflg; - -endfunction diff --git a/scripts/control/is_digital.m b/scripts/control/is_digital.m deleted file mode 100644 --- a/scripts/control/is_digital.m +++ /dev/null @@ -1,73 +0,0 @@ -## Copyright (C) 1996, 1999 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retval} =} is_digital (@var{sys}) -## Return nonzero if system is digital; -## inputs: -## sys: system data structure -## eflg: 0 [default] exit with an error if system is mixed (continuous and -## discrete components) -## : 1 print a warning if system is mixed (continuous and discrete) -## : 2 silent operation -## outputs: -## DIGITAL: 0: system is purely continuous -## : 1: system is purely discrete -## : -1: system is mixed continuous and discrete -## Exits with an error of sys is a mixed (continuous and discrete) system -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 1996 - -function DIGITAL = is_digital (sys, eflg) - - switch(nargin) - case(1), eflg = 0; - case(2), - if( isempty(find(eflg == [0, 1, 2])) ) - error("invalid value of eflg=%d (%e)",eflg,eflg); - endif - otherwise, - usage("DIGITAL = is_digital(sys{,eflg})"); - endswitch - - ## checked for sampled data system (mixed) - ## discrete system - sysyd = sysgetsignals(sys,"yd"); - [nn,nz] = sysdimensions(sys); - cont = sum(sysyd == 0) + nn; - tsam = sysgettsam(sys); - dig = sum(sysyd != 0) + nz + tsam; - - ## check for mixed system - if( cont*dig != 0) - switch(eflg) - case(0), - error("continuous/discrete system; use syscont, sysdisc, or c2d first"); - case(1), - warning("is_digital: mixed continuous/discrete system"); - endswitch - dig_sign = -1; - else - dig_sign = 1; - endif - - DIGITAL = dig_sign*(tsam > 0); - -endfunction diff --git a/scripts/control/is_observable.m b/scripts/control/is_observable.m deleted file mode 100644 --- a/scripts/control/is_observable.m +++ /dev/null @@ -1,60 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{retval},@var{U}] =} is_observable (@var{a}, @var{c}@{,@var{tol}@}) -## @deftypefnx {Function File} {[@var{retval},@var{U}] =} is_observable (@var{sys}@{, @var{tol}@}) -## Logical check for system observability. -## -## Default: tol = 10*norm(a,'fro')*eps -## -## Returns 1 if the system @var{sys} or the pair (@var{a},@var{c}) is -## observable, 0 if not. -## -## @strong{See} @code{is_controllable} for detailed description of arguments -## and default values. -## @end deftypefn -## @seealso{size, rows, columns, length, is_matrix, is_scalar, and is_vector} - -## Author: A. S. Hodel -## Created: August 1993 -## Updated by John Ingram (ingraje@eng.auburn.edu) July 1996. - -function [retval, U] = is_observable (a, c, tol) - - if( nargin < 1) - usage("[retval,U] = is_observable(a , c {, tol})"); - elseif(is_struct(a)) - ## system form - if(nargin == 2) - tol = c; - elseif(nargin > 2) - usage("[retval,U] = is_observable(sys {, tol})"); - endif - [a,b,c] = sys2ss(a); - elseif(nargin > 3) - usage("[retval,U] = is_observable(a , c {, tol})"); - endif - if(exist("tol")) - [retval,U] = is_controllable (a', c', tol); - else - [retval,U] = is_controllable (a', c'); - endif - -endfunction - diff --git a/scripts/control/is_sample.m b/scripts/control/is_sample.m deleted file mode 100644 --- a/scripts/control/is_sample.m +++ /dev/null @@ -1,32 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retval} =} is_sample (@var{Ts}) -## return true if @var{Ts} is a valid sampling time -## (real,scalar, > 0) -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 1995 - -function out = is_sample (Ts) - - out = (is_scalar(Ts) && (Ts == abs(Ts)) && (Ts != 0) ); - -endfunction diff --git a/scripts/control/is_signal_list.m b/scripts/control/is_signal_list.m deleted file mode 100644 --- a/scripts/control/is_signal_list.m +++ /dev/null @@ -1,34 +0,0 @@ -## Copyright (C) 1996, 1998, 2000 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - -## function flg = is_signal_list (mylist) -## returns true if mylist is a list of individual strings. - -function flg = is_signal_list(mylist) - - flg = is_list(mylist); - - if (flg) - for ii = 1:length (mylist) - if (! (isstr (nth (mylist,ii)) & rows (nth (mylist,ii)) == 1)) - flg = 0; - endif - endfor - endif - -endfunction diff --git a/scripts/control/is_siso.m b/scripts/control/is_siso.m deleted file mode 100644 --- a/scripts/control/is_siso.m +++ /dev/null @@ -1,40 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retval} =} is_siso (@var{sys}) -## return nonzero if the system data structure -## @var{sys} is single-input, single-output. -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 1996, 1998 - -function SISO = is_siso (sys) - - if(nargin != 1) - usage("SISO = is_siso(sys)"); - elseif( !is_struct(sys)) - error("input must be a system structure (see ss2sys, tf2sys, zp2sys)"); - endif - - [n,nz,m,p] = sysdimensions(sys); - - SISO = (m == 1 & p == 1); - -endfunction diff --git a/scripts/control/is_stabilizable.m b/scripts/control/is_stabilizable.m deleted file mode 100644 --- a/scripts/control/is_stabilizable.m +++ /dev/null @@ -1,89 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{retval}, @var{U}] =} is_stabilizable (@var{sys}@{, @var{tol}@}) -## @deftypefnx {Function File } {[@var{retval}, @var{U}] =} is_stabilizable (@var{a}@{, @var{b} ,@var{tol}@}) -## Logical check for system stabilizability (i.e., all unstable modes are controllable). -## -## Test for stabilizability is performed via an ordered Schur decomposition -## that reveals the unstable subspace of the system @var{A} matrix. -## -## Returns @code{retval} = 1 if the system, @code{a}, is stabilizable, -## if the pair (@code{a}, @code{b}) is stabilizable, or 0 if not. -## @code{U} = orthogonal basis of controllable subspace. -## -## Controllable subspace is determined by applying Arnoldi iteration with -## complete re-orthogonalization to obtain an orthogonal basis of the -## Krylov subspace. -## @example -## span ([b,a*b,...,a^ b]). -## @end example -## tol is a roundoff paramter, set to 200*eps if omitted. -## @end deftypefn - -## See also: size, rows, columns, length, is_matrix, is_scalar, is_vector -## is_observable, is_stabilizable, is_detectable - -## Author: A. S. Hodel -## Created: August 1993 -## Updated by A. S. Hodel (scotte@eng.auburn.edu) Aubust, 1995 to use krylovb -## Updated by John Ingram (ingraje@eng.auburn.edu) July, 1996 to accept systems - -function [retval, U] = is_stabilizable (a, b, tol) - - if(nargin < 1) usage("[retval,U] = is_stabilizable(a {, b ,tol})"); - elseif(is_struct(a)) - ## sustem passed. - if(nargin == 2) - tol = b; % get tolerance - elseif(nargin > 2) - usage("[retval,U] = is_stabilizable(sys{,tol})"); - endif - [a,b] = sys2ss(sys); - else - ## a,b arguments sent directly. - if(nargin > 3) - usage("[retval,U] = is_stabilizable(a {, b ,tol})"); - endif - endif - - if(exist("tol")) - [retval,U] = is_controllable(a,b,tol); - else - [retval,U] = is_controllable(a,b); - tol = 1e2*rows(b)*eps; - endif - - if( !retval & columns(U) > 0) - ## now use an ordered Schur decomposition to get an orthogonal - ## basis of the unstable subspace... - n = rows(a); - [ua, s] = schur (-(a+eye(n)*tol), "A"); - k = sum( real(eig(a)) >= 0 ); # count unstable poles - - if( k > 0 ) - ua = ua(:,1:k); - ## now see if span(ua) is contained in span(U) - retval = (norm(ua - U*U'*ua) < tol); - else - retval = 1; # all poles stable - endif - endif - -endfunction diff --git a/scripts/control/is_stable.m b/scripts/control/is_stable.m deleted file mode 100644 --- a/scripts/control/is_stable.m +++ /dev/null @@ -1,76 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retval} =} is_stable (@var{a}@{,@var{tol},@var{dflg}@}) -## @deftypefnx {Function File} {@var{retval} =} is_stable (@var{sys}@{,@var{tol}@}) -## Returns retval = 1 if the matrix @var{a} or the system @var{sys} -## is stable, or 0 if not. -## -## @strong{Inputs} -## @table @var -## @item tol -## is a roundoff paramter, set to 200*@var{eps} if omitted. -## @item dflg -## Digital system flag (not required for system data structure): -## @table @code -## @item @var{dflg} != 0 -## stable if eig(a) in unit circle -## -## @item @var{dflg} == 0 -## stable if eig(a) in open LHP (default) -## @end table -## @end table -## @end deftypefn -## @seealso{size, rows, columns, length, is_matrix, is_scalar, is_vector -## is_observable, is_stabilizable, is_detectable, krylov, and krylovb} - -## Author: A. S. Hodel -## Created: August 1993 -## Updated by John Ingram (ingraje@eng.auburn.edu) July, 1996 for systems -## Updated to simpler form by a.s.hodel 1998 - -function retval = is_stable (a, tol, disc) - - if( (nargin < 1) | (nargin > 3) ) usage("is_stable(a {,tol,disc})"); - elseif(is_struct(a)) - ## system was passed - if(nargin < 3) disc = is_digital(a); - elseif(disc != is_digital(a)) - warning("is_stable: disc =%d does not match system",disc) - endif - sys = sysupdate(a,"ss"); - a = sys2ss(sys); - else - if(nargin < 3) disc = 0; endif - if(is_square(a) == 0) - error("A(%dx%d) must be square",rows(A), columns(A)); - endif - endif - - if(nargin < 2) tol = 200*eps; - elseif( !is_scalar(tol) ) - error("is_stable: tol(%dx%d) must be a scalar",rows(tol),columns(tol)); - endif - - l = eig(a); - if(disc) nbad = sum(abs(l)*(1+tol) > 1); - else nbad = sum(real(l)+tol > 0); endif - retval = (nbad == 0); - -endfunction diff --git a/scripts/control/listidx.m b/scripts/control/listidx.m deleted file mode 100644 --- a/scripts/control/listidx.m +++ /dev/null @@ -1,100 +0,0 @@ -## Copyright (C) 2000 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## [idxvec, errmsg] = listidx(listvar, strlist) -## return indices of string entries in listvar that match strings in strlist -## Inputs: -## listvar: list of strings to be searched -## strlist: list of strings to be located in listvar. -## Note: listvar, strlist may be passed as strings or string matrices; -## in this case, each entry is processed by deblank() prior to searching -## for the entries of strlist in listvar. -## Outputs: -## idxvec -## vector of indices in listvar; -## listvar(idxvec(k)) == strlist(kk). -## errmsg -## if strlist contains a string not in listvar, then -## an error message is returned in errmsg. If only one output -## argument is requested, e.g., idxvec = listidx(listvar, strlist), -## then listidx prints errmsg to the screen and exits with -## an error. -## - -function [idxvec,errmsg] = listidx(listvar,strlist) - -if(nargin != 2) - usage("idxvec = listidx(listvar,strlist)"); -endif - -if(isstr(strlist)) - tmp = strlist; - strlist = list(); - for kk=1:rows(tmp) - strlist(kk) = deblank(tmp(kk,:)); - endfor -endif - -if(isstr(listvar)) - tmp = listvar; - listvar = list(); - for kk=1:rows(tmp) - listvar(kk) = deblank(tmp(kk,:)); - endfor -endif - -## initialize size of idxvec (for premature return) -idxvec = zeros(length(strlist),1); - -errmsg = ""; -if(!is_signal_list(listvar)) - errmsg = "listvar must be a list of strings"; -elseif(!is_signal_list(strlist)) - errmsg = "strlist must be a list of strings"; -endif - -if(length(errmsg)) - if(nargout < 2) error(errmsg); - else return; - endif -endif - -nsigs = length(listvar); -for idx = 1:length(strlist) - signame = nth(strlist,idx); - for jdx = 1:nsigs - if( strcmp(signame,nth(listvar,jdx)) ) - if(idxvec(idx) != 0) - warning("Duplicate signal name %s (%d,%d)\n", ... - nth(listvar,jdx),jdx,idxvec(idx)); - else - idxvec(idx) = jdx; - endif - endif - endfor - if(idxvec(idx) == 0) - errmsg = sprintf("Did not find %s",signame); - if(nargout == 1) - error(errmsg); - else - break - end - endif -endfor - -endfunction diff --git a/scripts/control/lqe.m b/scripts/control/lqe.m deleted file mode 100644 --- a/scripts/control/lqe.m +++ /dev/null @@ -1,109 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{k}, @var{p}, @var{e}] =} lqe (@var{a}, @var{g}, @var{c}, @var{sigw}, @var{sigv}, @var{z}) -## Construct the linear quadratic estimator (Kalman filter) for the -## continuous time system -## @iftex -## @tex -## $$ -## {dx\over dt} = A x + B u -## $$ -## $$ -## y = C x + D u -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## dx -## -- = a x + b u -## dt -## -## y = c x + d u -## @end example -## -## @end ifinfo -## where @var{w} and @var{v} are zero-mean gaussian noise processes with -## respective intensities -## -## @example -## sigw = cov (w, w) -## sigv = cov (v, v) -## @end example -## -## The optional argument @var{z} is the cross-covariance -## @code{cov (@var{w}, @var{v})}. If it is omitted, -## @code{cov (@var{w}, @var{v}) = 0} is assumed. -## -## Observer structure is @code{dz/dt = A z + B u + k (y - C z - D u)} -## -## The following values are returned: -## -## @table @var -## @item k -## The observer gain, -## @iftex -## @tex -## $(A - K C)$ -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{k}@var{c}) -## @end ifinfo -## is stable. -## -## @item p -## The solution of algebraic Riccati equation. -## -## @item e -## The vector of closed loop poles of -## @iftex -## @tex -## $(A - K C)$. -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{k}@var{c}). -## @end ifinfo -## @end table -## @end deftypefn - -## Author: A. S. Hodel -## Created: August 1993 - -function [k, p, e] = lqe (a, g, c, sigw, sigv, zz) - - if ( (nargin != 5) && (nargin != 6)) - error ("lqe: invalid number of arguments"); - endif - - ## The problem is dual to the regulator design, so transform to lqr - ## call. - - if (nargin == 5) - [k, p, e] = lqr (a', c', g*sigw*g', sigv); - else - [k, p, e] = lqr (a', c', g*sigw*g', sigv, g*zz); - endif - - k = k'; - -endfunction diff --git a/scripts/control/lqg.m b/scripts/control/lqg.m deleted file mode 100644 --- a/scripts/control/lqg.m +++ /dev/null @@ -1,150 +0,0 @@ -## Copyright (C) 1996, 1997 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{K}, @var{Q}, @var{P}, @var{Ee}, @var{Er}] =} lqg(@var{sys}, @var{Sigw}, @var{Sigv}, @var{Q}, @var{R}, @var{in_idx}) -## Design a linear-quadratic-gaussian optimal controller for the system -## @example -## dx/dt = A x + B u + G w [w]=N(0,[Sigw 0 ]) -## y = C x + v [v] ( 0 Sigv ]) -## @end example -## or -## @example -## x(k+1) = A x(k) + B u(k) + G w(k) [w]=N(0,[Sigw 0 ]) -## y(k) = C x(k) + v(k) [v] ( 0 Sigv ]) -## @end example -## -## @strong{Inputs} -## @table @var -## @item sys -## system data structure -## @item Sigw -## @itemx Sigv -## intensities of independent Gaussian noise processes (as above) -## @item Q -## @itemx R -## state, control weighting respectively. Control ARE is -## @item in_idx -## indices of controlled inputs -## -## default: last dim(R) inputs are assumed to be controlled inputs, all -## others are assumed to be noise inputs. -## @end table -## @strong{Outputs} -## @table @var -## @item K -## system data structure format LQG optimal controller (Obtain A,B,C -## matrices with @code{sys2ss}, @code{sys2tf}, or @code{sys2zp} as -## appropriate) -## @item P -## Solution of control (state feedback) algebraic Riccati equation -## @item Q -## Solution of estimation algebraic Riccati equation -## @item Ee -## estimator poles -## @item Es -## controller poles -## @end table -## @end deftypefn -## @seealso{h2syn, lqe, and lqr} - -## Author: A. S. Hodel -## Created: August 1995 -## revised for new system format August 1996 - -function [K, Q1, P1, Ee, Er] = lqg (sys, Sigw, Sigv, Q, R, input_list) - - if ( (nargin < 5) | (nargin > 6)) - usage("[K,Q1,P1,Ee,Er] = lqg(sys,Sigw, Sigv,Q,R{,input_list})"); - - elseif(!is_struct(sys) ) - error("sys must be in system data structure"); - endif - - DIG = is_digital(sys); - [A,B,C,D,tsam,n,nz,stname,inname,outname] = sys2ss(sys); - [n,nz,nin,nout] = sysdimensions(sys); - if(nargin == 5) - ## construct default input_list - input_list = (columns(Sigw)+1):nin; - endif - - if( !(n+nz) ) - error(["lqg: 0 states in system"]); - - elseif(nin != columns(Sigw)+ columns(R)) - error(["lqg: sys has ",num2str(nin)," inputs, dim(Sigw)=", ... - num2str(columns(Sigw)),", dim(u)=",num2str(columns(R))]) - - elseif(nout != columns(Sigv)) - error(["lqg: sys has ",num2str(nout)," outputs, dim(Sigv)=", ... - num2str(columns(Sigv)),")"]) - elseif(length(input_list) != columns(R)) - error(["lqg: length(input_list)=",num2str(length(input_list)), ... - ", columns(R)=", num2str(columns(R))]); - endif - - varname = list("Sigw","Sigv","Q","R"); - for kk=1:length(varname); - eval(sprintf("chk = is_square(%s);",nth(varname,kk))); - if(! chk ) error("lqg: %s is not square",nth(varname,kk)); endif - endfor - - ## permute (if need be) - if(nargin == 6) - all_inputs = sysreorder(nin,input_list); - B = B(:,all_inputs); - inname = inname(all_inputs); - endif - - ## put parameters into correct variables - m1 = columns(Sigw); - m2 = m1+1; - G = B(:,1:m1); - B = B(:,m2:nin); - - ## now we can just do the design; call dlqr and dlqe, since all matrices - ## are not given in Cholesky factor form (as in h2syn case) - if(DIG) - [Ks, P1, Er] = dlqr(A,B,Q,R); - [Ke, Q1, jnk, Ee] = dlqe(A,G,C,Sigw,Sigv); - else - [Ks, P1, Er] = lqr(A,B,Q,R); - [Ke, Q1, Ee] = lqe(A,G,C,Sigw,Sigv); - endif - Ac = A - Ke*C - B*Ks; - Bc = Ke; - Cc = -Ks; - Dc = zeros(rows(Cc),columns(Bc)); - - ## fix state names - stname1 = strappend(stname,"_e"); - - ## fix controller output names - outname1 = strappend(inname(m2:nin),"_K"); - - ## fix controller input names - inname1 = strappend(outname,"_K"); - - if(DIG) - K = ss2sys(Ac,Bc,Cc,Dc,tsam,n,nz,stname1,inname1,outname1,1:rows(Cc)); - else - K = ss2sys(Ac,Bc,Cc,Dc,tsam,n,nz,stname,inname1,outname1); - endif - -endfunction diff --git a/scripts/control/lqr.m b/scripts/control/lqr.m deleted file mode 100644 --- a/scripts/control/lqr.m +++ /dev/null @@ -1,174 +0,0 @@ -## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{k}, @var{p}, @var{e}] =} lqr (@var{a}, @var{b}, @var{q}, @var{r}, @var{z}) -## construct the linear quadratic regulator for the continuous time system -## @iftex -## @tex -## $$ -## {dx\over dt} = A x + B u -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## dx -## -- = A x + B u -## dt -## @end example -## -## @end ifinfo -## to minimize the cost functional -## @iftex -## @tex -## $$ -## J = \int_0^\infty x^T Q x + u^T R u -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## infinity -## / -## J = | x' Q x + u' R u -## / -## t=0 -## @end example -## @end ifinfo -## -## @noindent -## @var{z} omitted or -## @iftex -## @tex -## $$ -## J = \int_0^\infty x^T Q x + u^T R u + 2 x^T Z u -## $$ -## @end tex -## @end iftex -## @ifinfo -## -## @example -## infinity -## / -## J = | x' Q x + u' R u + 2 x' Z u -## / -## t=0 -## @end example -## -## @end ifinfo -## @var{z} included. -## -## The following values are returned: -## -## @table @var -## @item k -## The state feedback gain, -## @iftex -## @tex -## $(A - B K)$ -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{b}@var{k}) -## @end ifinfo -## is stable and minimizes the cost functional -## -## @item p -## The stabilizing solution of appropriate algebraic Riccati equation. -## -## @item e -## The vector of the closed loop poles of -## @iftex -## @tex -## $(A - B K)$. -## @end tex -## @end iftex -## @ifinfo -## (@var{a} - @var{b}@var{k}). -## @end ifinfo -## @end table -## -## @strong{Reference} -## Anderson and Moore, OPTIMAL CONTROL: LINEAR QUADRATIC METHODS, -## Prentice-Hall, 1990, pp. 56-58 -## @end deftypefn - -## Author: A. S. Hodel -## Created: August 1993. - -function [k, p, e] = lqr (a, b, q, r, s) - - ## disp("lqr: entry"); - - if ((nargin != 4) && (nargin != 5)) - error ("lqr: invalid number of arguments"); - endif - - ## Check a. - if ((n = is_square (a)) == 0) - error ("lqr: requires 1st parameter(a) to be square"); - endif - - ## Check b. - [n1, m] = size (b); - if (n1 != n) - error ("lqr: a,b not conformal"); - endif - - ## Check q. - if ( ((n1 = is_square (q)) == 0) || (n1 != n)) - error ("lqr: q must be square and conformal with a"); - endif - - ## Check r. - if ( ((m1 = is_square(r)) == 0) || (m1 != m)) - error ("lqr: r must be square and conformal with column dimension of b"); - endif - - ## Check if n is there. - if (nargin == 5) - [n1, m1] = size (s); - if ( (n1 != n) || (m1 != m)) - error ("lqr: z must be identically dimensioned with b"); - endif - - ## Incorporate cross term into a and q. - ao = a - (b/r)*s'; - qo = q - (s/r)*s'; - else - s = zeros (n, m); - ao = a; - qo = q; - endif - - ## Check that q, (r) are symmetric, positive (semi)definite - - if (is_symmetric (q) && is_symmetric (r) ... - && all (eig (q) >= 0) && all (eig (r) > 0)) - p = are (ao, (b/r)*b', qo); - k = r\(b'*p + s'); - e = eig (a - b*k); - else - error ("lqr: q (r) must be symmetric positive (semi) definite"); - endif - - ## disp("lqr: exit"); -endfunction diff --git a/scripts/control/lyap.m b/scripts/control/lyap.m deleted file mode 100644 --- a/scripts/control/lyap.m +++ /dev/null @@ -1,142 +0,0 @@ -## Copyright (C) 1996, 1997 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2, or (at your option) -## any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place - Suite 330, Boston, MA -## 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} lyap (@var{a}, @var{b}, @var{c}) -## @deftypefnx {Function File} {} lyap (@var{a}, @var{b}) -## Solve the Lyapunov (or Sylvester) equation via the Bartels-Stewart -## algorithm (Communications of the ACM, 1972). -## -## If @var{a}, @var{b}, and @var{c} are specified, then @code{lyap} returns -## the solution of the Sylvester equation -## @iftex -## @tex -## $$ A X + X B + C = 0 $$ -## @end tex -## @end iftex -## @ifinfo -## @example -## a x + x b + c = 0 -## @end example -## @end ifinfo -## If only @code{(a, b)} are specified, then @code{lyap} returns the -## solution of the Lyapunov equation -## @iftex -## @tex -## $$ A^T X + X A + B = 0 $$ -## @end tex -## @end iftex -## @ifinfo -## @example -## a' x + x a + b = 0 -## @end example -## @end ifinfo -## If @var{b} is not square, then @code{lyap} returns the solution of either -## @iftex -## @tex -## $$ A^T X + X A + B^T B = 0 $$ -## @end tex -## @end iftex -## @ifinfo -## @example -## a' x + x a + b' b = 0 -## @end example -## @end ifinfo -## @noindent -## or -## @iftex -## @tex -## $$ A X + X A^T + B B^T = 0 $$ -## @end tex -## @end iftex -## @ifinfo -## @example -## a x + x a' + b b' = 0 -## @end example -## @end ifinfo -## @noindent -## whichever is appropriate. -## -## Solves by using the Bartels-Stewart algorithm (1972). -## @end deftypefn - -## Author: A. S. Hodel -## Created: August 1993 -## Adapted-By: jwe - -function x = lyap (a, b, c) - - if (nargin != 3 && nargin != 2) - usage ("lyap (a, b {,c})"); - endif - - if ((n = is_square(a)) == 0) - error ("lyap: a is not square"); - endif - - if (nargin == 2) - - ## Transform Lyapunov equation to Sylvester equation form. - - if ((m = is_square (b)) == 0) - if ((m = rows (b)) == n) - - ## solve a x + x a' + b b' = 0 - - b = b * b'; - a = a'; - else - - ## Try to solve a'x + x a + b' b = 0. - - m = columns (b); - b = b' * b; - endif - - if (m != n) - error ("lyap: a, b not conformably dimensioned"); - endif - endif - - ## Set up Sylvester equation. - - c = b; - b = a; - a = b'; - - else - - ## Check dimensions. - - if ((m = is_square (b)) == 0) - error ("lyap: b must be square in a sylvester equation"); - endif - - [n1, m1] = size(c); - - if (n != n1 || m != m1) - error("lyap: a,b,c not conformably dimensioned"); - endif - endif - - ## Call octave built-in function. - - x = syl (a, b, c); - -endfunction diff --git a/scripts/control/marsyas/demomarsyas.m b/scripts/control/marsyas/demomarsyas.m new file mode 100644 --- /dev/null +++ b/scripts/control/marsyas/demomarsyas.m @@ -0,0 +1,116 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +page_screen_output = 1; +opt = 0; +QUITOPT = 7; +while (opt != QUITOPT) + opt = menu("Marsyas interface update demo:", ... + "run Marsyas on the magnetically suspended ball example", ... + "load continuous time marsyas example system", ... + "load discrete-time marsyas example system", ... + "bode plot of loaded system (MIMO)", ... + "bode plot of loaded system (SISO)", ... + "Design example", ... + "Quit"); + + if(opt == 1) + cmd = "system(""marsyas mag1d.mar"")"; + run_cmd + cmd = "system(""marplot -i"")"; + run_cmd + elseif(opt == 2) + cmd = "ballsys = margetsys();"; + run_cmd; + cmd = "sysout(ballsys);" + run_cmd + elseif(opt == 3) + cmd = "ballsys = margetsys(""disc"");"; + run_cmd + cmd = "sysout(ballsys);" + run_cmd + elseif(opt == 4) + cmd = "bode(ballsys);"; + run_cmd + elseif(opt == 5) + cmd = "bode(ballsys,[],1,1);"; + run_cmd + elseif(opt == 6) + if(!exist("ballsys")) + warning("You didn't load a system yet (option 2 or 3)"); + else + disp("Design LQG controller"); + cmd = "sysout(ballsys)"; + run_cmd + disp("add noise inputs to system...") + if(ballsys.n) + disp("continuous system:") + cmd = "ballsys1 = sysappend(ballsys,eye(ballsys.n));"; + else + disp("discrete system:") + cmd = "ballsys1 = sysappend(ballsys,eye(ballsys.nz));"; + endif + run_cmd + cmd = "sysout(ballsys1)"; + run_cmd + disp("Notice the two additional inputs, u_2, and u_3. These are the "); + disp("""entry points"" for the gaussian noise disturbance."); + disp(" "); + disp("We'll design the controller to use only position feedback:") + cmd = "ballsys1=sysprune(ballsys1,1,[]);"; + run_cmd + cmd = "sysout(ballsys1)"; + run_cmd + disp("Now design an LQG controller: Sigw: input noise") + Sigw = eye(2) + disp("Now design an LQG controller: Sigv: measurement noise") + Sigv = eye(rows(ballsys1.c)) + disp("State and input penalties:") + Q = eye(2) + R = 1 + disp("Controlled input is input 1"); + cmd="Ksys = lqg(ballsys1,Sigw,Sigv,Q,R,1);"; + run_cmd + disp("sysout(Ksys);"); + sysout(Ksys); + + disp("marsyas conversion: output in scalar form:") + cmd = "maroutsys(Ksys, ""ball_controller"",""scalar"");"; + run_cmd + disp("here's the output file:") + prompt + system("more ball_controller.mar"); + + disp("marsyas conversion: output in state space form: (default option;") + disp("the ""ss"" in the command below is not needed)") + cmd = "maroutsys(Ksys, ""ball_controller_ss"",""ss"");"; + run_cmd + disp("here's the output file:") + prompt + system("more ball_controller_ss.mar"); + + disp("marsyas conversion: output in transfer function form:") + cmd = "maroutsys(Ksys, ""ball_controller_tf"",""tf"")" + run_cmd + disp("here's the output file:") + prompt + system("more ball_controller_tf.mar"); + + endif + endif +endwhile diff --git a/scripts/control/marsyas/susball.m b/scripts/control/marsyas/susball.m new file mode 100644 --- /dev/null +++ b/scripts/control/marsyas/susball.m @@ -0,0 +1,99 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outputs} =} susball (@var{inputs}) +## @end deftypefn + +cmd = "ballsys = margetsys(""disc"")"; +eval(cmd); + +disp("Design LQG controller"); +cmd = "sysout(ballsys)"; +run_cmd +disp("add noise inputs to system...") + +disp("discrete system:") +[nn,nz,mm,pp] = sysdimensions(ballsys); +cmd = "ballsys = sysappend(ballsys,nz);"; +run_cmd + +cmd = "sysout(ballsys)"; +run_cmd + +disp("Notice the two additional inputs, u_2, and u_3. These are the "); +disp("""entry points"" for the gaussian noise disturbance."); +disp(" "); +disp("We'll design the controller to use only position feedback:") + +cmd = "ballsys=sysprune(ballsys,1,[]);"; +run_cmd +cmd = "sysout(ballsys)"; +run_cmd + +disp("Now design an LQG controller: Sigw: input noise") +Sigw = eye(2) +disp("Now design an LQG controller: Sigv: measurement noise") +Sigv = eye(pp); + +disp("State and input penalties:") +Q = eye(2) +R = 1 +disp("Controlled input is input 1"); + +cmd="Ksys = lqg(ballsys,Sigw,Sigv,Q,R,1);"; +run_cmd + +disp("sysout(Ksys);"); +sysout(Ksys); + +disp("\nGet rid of the disturbance inputs"); +cmd = "ballsys = sysprune(ballsys,1,1);" +run_cmd; +sysout(ballsys); +sysout(ballsys,"zp"); + +disp("\nGrouping the plant and the controller"); +cmd = "closed_loop = sysgroup(ballsys,Ksys);" +run_cmd; +sysout(closed_loop); + +disp("\nduplicating the plant input"); +cmd = "closed_loop = sysdup(closed_loop,[],1);" +run_cmd; +sysout(closed_loop); + +## disp("\nscaling the duplicated input by -1"); +## cmd = "closed_loop = sysscale(closed_loop,[],diag([1,1,1]));" +## run_cmd; +## sysout(closed_loop); + +disp("\nconnecting plant output to controller input and controller output"); +disp("to the duplicated plant input"); +cmd = "closed_loop = sysconnect(closed_loop,[1 2],[2 3]);" +run_cmd; +sysout(closed_loop); + +disp("\nkeeping only the original plant input and plant output"); +cmd = "closed_loop = sysprune(closed_loop,1,1);" +run_cmd; +sysout(closed_loop); + +sysout(closed_loop,"zp"); + + diff --git a/scripts/control/moddemo.m b/scripts/control/moddemo.m deleted file mode 100644 --- a/scripts/control/moddemo.m +++ /dev/null @@ -1,205 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outputs} =} moddemo (@var{inputs}) -## Octave Controls toolbox demo: Model Manipulations demo -## @end deftypefn - -## Author: David Clem -## Created: August 15, 1994 -## a s hodel: updated to reflect updated output order in ss2zp - -function moddemo () - - while (1) - clc - disp("Octave Model Manipulations Demo") - disp("=======================================") - disp(" 1) Perform continuous to discrete time conversion (c2d)") - disp(" 2) Convert from state space to zero / pole form (ss2zp)") - disp(" Convert from zero / pole to state space form (zp2ss)") - disp(" 3) Convert from state space to transfer function form (ss2tf)") - disp(" Convert from transfer function to state space form (tf2ss)") - disp(" 4) Convert from transfer function to zero / pole form (tf2zp)") - disp(" Convert from zero / pole to transfer function form (zp2tf)") - disp(" 5) Return to main demo menu") - disp(" ") - k=6; - while(k > 5 || k < 1) - k = input("Please enter a number:"); - endwhile - if (k == 1) - clc - disp("Perform continuous to discrete time conversion (c2d)\n") - disp("Example #1, Consider the following continuous time state space system:\n") - a=[0, 1; -25, -4] - b=[0; 1] - c=[1, 1] - d=1 - prompt - disp("\nTo convert this to a discrete time system (using a zero order hold),") - disp("use the following commands:\n") - cmd="sys=ss2sys(a,b,c,d);"; - run_cmd - cmd="dsys = c2d(sys,0.2);"; - run_cmd - cmd="sysout(dsys);"; - run_cmd - disp("Function check\n") - disp("Check the poles of sys vs dsys:\n") - cmd="[da,db]=sys2ss(dsys);"; - run_cmd - cmd="lam = eig(a);"; - run_cmd - disp("Discretize the continuous time eigenvalues using the matrix exponential:\n") - disp("lambc = exp(lam*0.2)\n") - lambc = exp(lam*0.2) - disp("Check the eigenvalues of da\n") - lambd = eig(da) - disp("Calculate the difference between lambd and lambc:\n") - cmd = "error = sort(lambd)-sort(lambc)\n"; - run_cmd - disp("The error is on the order of roundoff noise, so we're o.k.") - prompt - clc - elseif (k == 2) - clc - disp("Convert from state space to zero / pole form (ss2zp)\n") - disp("Example #1, Consider the following state space system:\n") - a=[0, 3, 1; -2, -4, 5; 5, 8, 2] - b=[0; 5; 2.5] - c=[6, -1.9, 2] - d=[-20] - prompt - disp(" ") - disp("\nTo find the poles and zeros of this sytstem, use the following command:\n") - disp("\n[zer, pol] = ss2zp(a, b, c, d)\n") - prompt - disp("Results:\n") - [zer, pol] = ss2zp(a, b, c, d) - disp("Variable Description:\n") - disp("zer, pol => zeros and poles of the state space system") - disp("a, b, c, d => state space system\n") - prompt - clc - disp("Convert from zero / pole to state space form (zp2ss)\n") - disp("Example #1, Consider the following set of zeros and poles:\n") - zer - pol - prompt - disp("\nTo find an equivalent state space representation for this set of poles") - disp("and zeros, use the following commands:\n") - k=1 - disp("\n[na, nb, nc, nd] = zp2ss(zer, pol, k)\n") - prompt - disp("Results:\n") - [na, nb, nc, nd] = zp2ss(zer, pol, k) - disp("Variable Description:\n") - disp("na, nb, nc, nd => state space system equivalent to zero / pole input") - disp("zer, pol => zeros and poles of desired state space system") - disp("k => gain associated with the zeros\n") - prompt - disp("Function check\n") - disp("Are the eigenvalues of the origonal state space system the same as the") - disp("eigenvalues of the newly constructed state space system ?\n") - disp("Find the difference between the two sets of eigenvalues") - disp("error = sort(eig(a)) - sort(eig(na))\n") - error = sort(eig(a)) - sort(eig(na)) - prompt - clc - elseif (k == 3) - clc - disp("Convert from state space to transfer function (ss2tf)\n") - disp("Example #1, Consider the following state space system:\n") - a=[0, 1; -2, -3] - b=[1; 1] - c=[1, 9] - d=[1] - prompt - disp("\nTo find an equivalent transfer function for this system, use") - disp("the following command:\n") - disp("[num, den] = ss2tf(a, b, c, d)\n") - prompt - disp("Results:\n") - [num,den] = ss2tf(a, b, c, d) - disp("Variable Description:\n") - disp("num, den => numerator and denominator of transfer function that is") - disp(" equivalent to the state space system") - disp("a, b, c, d => state space system\n") - prompt - clc - disp("Convert from transfer function to state space form (tf2ss)\n") - disp("Example #1, Consider the following transfer function:\n") - num - den - prompt - disp("\nTo find an equivalent state space representation for this system, use") - disp("the following command:\n") - disp("[a, b, c, d] = tf2ss(num, den)\n") - prompt - disp("Results:\n") - [a, b, c, d] = tf2ss(num, den) - disp("Variable Description:\n") - disp("a, b, c, d => state space system equivalent to transfer function input") - disp("num, den => numerator and denominator of transfer function that is equivalent") - disp(" to the state space system\n") - prompt - clc - elseif (k == 4) - clc - disp("Convert from transfer function to zero / pole form (tf2zp)\n") - disp("Example #1, Consider the following transfer function:\n") - num=[1, 2, 3, 4, 5, ] - den=[1, 2, 3, 4, 5, 6, 7] - prompt - disp("\nTo find the zeros and poles of this system, use the following command:\n") - disp("[zer,pol] = tf2zp(num,den)\n") - prompt - disp("Results:\n") - [zer,pol] = tf2zp(num,den) - disp("Variable Description:\n") - disp("zer,pol => zeros and poles of the transfer function") - disp("num, den => numerator and denominator of transfer function\n") - prompt - clc - disp("Convert from zero / pole to transfer function (zp2tf)\n") - disp("Example #1, Consider the following set of zeros and poles:\n") - zer - pol - prompt - disp("\nTo find an equivalent transfer function representation for this set") - disp("of poles and zeros, use the following commands:\n") - k=1 - disp("\n[num, den] = zp2tf(zer, pol, k)\n") - prompt - disp("Results:\n") - [num, den] = zp2tf(zer, pol, k) - disp("Variable Description:\n") - disp("[num, den] => transfer function representation of desired set of zeros") - disp(" and poles") - disp("a, b, c, d => state space system") - disp("zer, pol => zeros and poles of desired state space system") - disp("k => gain associated with the zeros\n") - prompt - clc - elseif (k == 5) - return - endif - endwhile -endfunction diff --git a/scripts/control/nichols.m b/scripts/control/nichols.m deleted file mode 100644 --- a/scripts/control/nichols.m +++ /dev/null @@ -1,117 +0,0 @@ -## Copyright (C) 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## [mag,phase,w] = nichols(sys[,w,outputs,inputs]) -## Produce Nichols plot of a system -## -## Compute the frequency response of a system. -## inputs: -## sys: system data structure (must be either purely continuous or discrete; -## see is_digital) -## w: frequency values for evaluation. -## if sys is continuous, then nichols evaluates G(jw) -## if sys is discrete, then nichols evaluates G(exp(jwT)), where T=sys.tsam -## (the system sampling time) -## default: the default frequency range is selected as follows: (These -## steps are NOT performed if w is specified) -## (1) via routine bodquist, isolate all poles and zeros away from -## w=0 (jw=0 or exp(jwT)=1) and select the frequency -## range based on the breakpoint locations of the frequencies. -## (2) if sys is discrete time, the frequency range is limited -## to jwT in [0,2p*pi] -## (3) A "smoothing" routine is used to ensure that the plot phase does -## not change excessively from point to point and that singular -## points (e.g., crossovers from +/- 180) are accurately shown. -## outputs, inputs: the indices of the output(s) and input(s) to be used in -## the frequency response; see sysprune. -## outputs: -## mag, phase: the magnitude and phase of the frequency response -## G(jw) or G(exp(jwT)) at the selected frequency values. -## w: the vector of frequency values used -## If no output arguments are given, nichols plots the results to the screen. -## Descriptive labels are automatically placed. See xlabel, ylable, title, -## and replot. -## -## Note: if the requested plot is for an MIMO system, mag is set to -## ||G(jw)|| or ||G(exp(jwT))|| and phase information is not computed. - -function [mag, phase, w] = nichols (sys, w, outputs, inputs) - - ## check number of input arguments given - if (nargin < 1 | nargin > 4) - usage("[mag,phase,w] = nichols(sys[,w,outputs,inputs])"); - endif - if(nargin < 2) - w = []; - endif - if(nargin < 3) - outputs = []; - endif - if(nargin < 4) - inputs = []; - endif - - [f, w] = bodquist(sys,w,outputs,inputs,"nichols"); - - [stname,inname,outname] = sysgetsignals(sys); - systsam = sysgettsam(sys); - - ## Get the magnitude and phase of f. - mag = abs(f); - phase = arg(f)*180.0/pi; - - if (nargout < 1), - ## Plot the information - if(gnuplot_has_multiplot) - oneplot(); - endif - gset autoscale; - if(gnuplot_has_multiplot) - gset nokey; - endif - clearplot(); - grid("on"); - gset data style lines; - if(is_digital(sys)) - tistr = "(exp(jwT)) "; - else - tistr = "(jw)"; - endif - xlabel("Phase (deg)"); - if(is_siso(sys)) - title(["Nichols plot of |[Y/U]",tistr,"|, u=", ... - sysgetsignals(sys,"in",1,1), ", y=",sysgetsignals(sys,"out",1,1)]); - else - title([ "||Y(", tistr, ")/U(", tistr, ")||"]); - printf("MIMO plot from\n%s\nto\n%s\n",outlist(inname," "), ... - outlist(outname," ")); - endif - if(max(mag) > 0) - ylabel("Gain in dB"); - md = 20*log10(mag); - else - ylabel("Gain |Y/U|") - md = mag; - endif - - axvec = axis2dlim([vec(phase),vec(md)]); - axis(axvec); - plot(phase,md); - mag = phase = w = []; - endif -endfunction diff --git a/scripts/control/nyquist.m b/scripts/control/nyquist.m deleted file mode 100644 --- a/scripts/control/nyquist.m +++ /dev/null @@ -1,207 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{realp}, @var{imagp}, @var{w}] =} nyquist (@var{sys}@{, @var{w}, @var{out_idx}, @var{in_idx}, @var{atol}@}) -## @deftypefnx {Function File } {} nyquist (@var{sys}@{, @var{w}, @var{out_idx}, @var{in_idx}, @var{atol}@}) -## Produce Nyquist plots of a system; if no output arguments are given, Nyquist -## plot is printed to the screen. -## -## Compute the frequency response of a system. -## @strong{Inputs} (pass as empty to get default values) -## @table @var -## @item sys -## system data structure (must be either purely continuous or discrete; -## see is_digital) -## @item w -## frequency values for evaluation. -## if sys is continuous, then bode evaluates @math{G(jw)} -## if sys is discrete, then bode evaluates @math{G(exp(jwT))}, where -## @math{@var{T}=sysgettsam(@var{sys})} (the system sampling time) -## @item default -## the default frequency range is selected as follows: (These -## steps are NOT performed if @var{w} is specified) -## @end table -## @enumerate -## @item via routine bodquist, isolate all poles and zeros away from -## @var{w}=0 (@var{jw}=0 or @math{exp(@var{jwT})=1}) and select the frequency -## range based on the breakpoint locations of the frequencies. -## @item if @var{sys} is discrete time, the frequency range is limited -## to @var{jwT} in -## @ifinfo -## [0,2p*pi] -## @end ifinfo -## @iftex -## $[0,2p*\pi]$ -## @end iftex -## @item A "smoothing" routine is used to ensure that the plot phase does -## not change excessively from point to point and that singular -## points (e.g., crossovers from +/- 180) are accurately shown. -## @end enumerate -## outputs, inputs: the indices of the output(s) and input(s) to be used in -## the frequency response; see sysprune. -## -## @strong{Inputs} (pass as empty to get default values) -## @table @var -## @item atol -## for interactive nyquist plots: atol is a change-in-slope tolerance -## for the of asymptotes (default = 0; 1e-2 is a good choice). This allows -## the user to ``zoom in'' on portions of the Nyquist plot too small to be -## seen with large asymptotes. -## @end table -## @strong{Outputs} -## @table @var -## @item realp -## @itemx imagp -## the real and imaginary parts of the frequency response -## @math{G(jw)} or @math{G(exp(jwT))} at the selected frequency values. -## @item w -## the vector of frequency values used -## @end table -## -## If no output arguments are given, nyquist plots the results to the screen. -## If @var{atol} != 0 and asymptotes are detected then the user is asked -## interactively if they wish to zoom in (remove asymptotes) -## Descriptive labels are automatically placed. -## -## Note: if the requested plot is for an MIMO system, a warning message is -## presented; the returned information is of the magnitude -## ||G(jw)|| or ||G(exp(jwT))|| only; phase information is not computed. -## @end deftypefn - -## Author: R. Bruce Tenison -## Created: July 13, 1994 -## A. S. Hodel July 1995 (adaptive frequency spacing, -## remove acura parameter, etc.) -## Revised by John Ingram July 1996 for system format - -function [realp, imagp, w] = nyquist (sys, w, outputs, inputs, atol) - - ## Both bode and nyquist share the same introduction, so the common - ## parts are in a file called bodquist.m. It contains the part that - ## finds the number of arguments, determines whether or not the system - ## is SISO, andd computes the frequency response. Only the way the - ## response is plotted is different between the two functions. - - ## check number of input arguments given - if (nargin < 1 | nargin > 5) - usage("[realp,imagp,w] = nyquist(sys[,w,outputs,inputs,atol])"); - endif - if(nargin < 2) - w = []; - endif - if(nargin < 3) - outputs = []; - endif - if(nargin < 4) - inputs = []; - endif - if(nargin < 5) - atol = 0; - elseif(!(is_sample(atol) | atol == 0)) - error("atol must be a nonnegative scalar.") - endif - - ## signal to bodquist who's calling - - [f,w] = bodquist(sys,w,outputs,inputs,"nyquist"); - - ## Get the real and imaginary part of f. - realp = real(f); - imagp = imag(f); - - ## No output arguments, then display plot, otherwise return data. - if (nargout == 0) - dnplot = 0; - while(!dnplot) - if(gnuplot_has_multiplot) - oneplot(); - gset key; - endif - clearplot(); - grid ("on"); - gset data style lines; - - if(is_digital(sys)) - tstr = " G(e^{jw}) "; - else - tstr = " G(jw) "; - endif - xlabel(["Re(",tstr,")"]); - ylabel(["Im(",tstr,")"]); - - [stn, inn, outn] = sysgetsignals(sys); - if(is_siso(sys)) - title(sprintf("Nyquist plot from %s to %s, w (rad/s) in [%e, %e]", ... - nth(inn,1), nth(outn,1), w(1), w(length(w))) ) - endif - - gset nologscale xy; - - axis(axis2dlim([[vec(realp),vec(imagp)];[vec(realp),-vec(imagp)]])); - plot(realp,imagp,"- ;+w;",realp,-imagp,"-@ ;-w;"); - - ## check for interactive plots - dnplot = 1; # assume done; will change later if atol is satisfied - if(atol > 0 & length(f) > 2) - - ## check for asymptotes - fmax = max(abs(f)); - fi = max(find(abs(f) == fmax)); - - ## compute angles from point to point - df = diff(f); - th = atan2(real(df),imag(df))*180/pi; - - ## get angle at fmax - if(fi == length(f)) fi = fi-1; endif - thm = th(fi); - - ## now locate consecutive angles within atol of thm - ith_same = find(abs(th - thm) < atol); - ichk = union(fi,find(diff(ith_same) == 1)); - - ## locate max, min consecutive indices in ichk - loval = max(complement(ichk,1:fi)); - if(isempty(loval)) loval = fi; - else loval = loval + 1; endif - - hival = min(complement(ichk,fi:length(th))); - if(isempty(hival)) hival = fi+1; endif - - keep_idx = complement(loval:hival,1:length(w)); - - if(length(keep_idx)) - resp = input("Remove asymptotes and zoom in (y or n): ",1); - if(resp(1) == "y") - dnplot = 0; # plot again - w = w(keep_idx); - f = f(keep_idx); - realp = real(f); - imagp = imag(f); - endif - endif - - endif - endwhile - w = []; - realp=[]; - imagp=[]; - endif - -endfunction diff --git a/scripts/control/obsolete/rotg.m b/scripts/control/obsolete/rotg.m new file mode 100644 --- /dev/null +++ b/scripts/control/obsolete/rotg.m @@ -0,0 +1,28 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## function [c,s] = rotg(a,b) +## givens rotation calculation +## +## NOTE: Use [c,s] = givens(a,b) instead. + +function [c, s] = rotg (a, b) + + [c,s] = givens(a,b); + +endfunction diff --git a/scripts/control/obsv.m b/scripts/control/obsv.m deleted file mode 100644 --- a/scripts/control/obsv.m +++ /dev/null @@ -1,65 +0,0 @@ -## Copyright (C) 1997 Kai P. Mueller -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -##@deftypefn {Function File} {@var{Qb} =} obsv (@var{sys}@{, @var{c}@}) -## Build observability matrix -## @example -## @group -## | C | -## | CA | -## Qb = | CA^2 | -## | ... | -## | CA^(n-1) | -## @end group -## @end example -## of a system data structure or the pair (A, C). -## -## Note: @code{obsv()} forms the observability matrix. -## -## The numerical properties of is_observable() -## are much better for observability tests. -## @end deftypefn - -## Author: Kai P. Mueller -## Created: November 4, 1997 - -function Qb = obsv (sys, c) - - if (nargin == 2) - a = sys; - elseif (nargin == 1 && is_struct(sys)) - sysupdate(sys,"ss"); - [a,b,c] = sys2ss(sys); - else - usage("obsv(sys [, c])") - endif - - if (!is_abcd(a,c')) - Qb = []; - else - ## no need to check dimensions, we trust is_abcd(). - [na, ma] = size(a); - [nc, mc] = size(c); - Qb = zeros(na*nc, ma); - for i = 1:na - Qb((i-1)*nc+1:i*nc, :) = c; - c = c * a; - endfor - endif -endfunction diff --git a/scripts/control/ord2.m b/scripts/control/ord2.m deleted file mode 100644 --- a/scripts/control/ord2.m +++ /dev/null @@ -1,63 +0,0 @@ -## Copyright (C) 1997 Kai P. Mueller -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outsys} =} ord2 (@var{nfreq}, @var{damp}@{[, @var{gain}@}) -## Creates a continuous 2nd order system with parameters: -## @strong{Inputs} -## @table @var -## @item nfreq: natural frequency [Hz]. (not in rad/s) -## @item damp: damping coefficient -## @item gain: dc-gain -## This is steady state value only for damp > 0. -## gain is assumed to be 1.0 if ommitted. -## @end table -## @strong{Outputs} -## @var{outsys} -## system data structure has representation with @math{w = 2 * pi * nfreq}: -## @example -## / \ -## | / -2w*damp -w \ / w \ | -## G = | | |, | |, [ 0 gain ], 0 | -## | \ w 0 / \ 0 / | -## \ / -## @end example -## @strong{See also} @code{jet707} (MIMO example, Boeing 707-321 -## aircraft model) -## @end deftypefn - -## Author: Kai P. Mueller -## Created: September 28, 1997 - -function outsys = ord2 (nfreq, damp, gain) - - ## Updates - - if(nargin != 2 & nargin != 3) - usage("outsys = ord2(nfreq, damp[, gain])") - endif - if (nargout > 1) - usage("outsys = ord2(nfreq, damp[, gain])") - endif - if (nargin == 2) - gain = 1.0; - endif - - w = 2.0 * pi * nfreq; - outsys = ss2sys([-2.0*w*damp, -w; w, 0], [w; 0], [0, gain]); -endfunction diff --git a/scripts/control/prompt.m b/scripts/control/prompt.m deleted file mode 100644 --- a/scripts/control/prompt.m +++ /dev/null @@ -1,46 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outputs} =} prompt (@var{inputs}) -## @format -## function prompt([str]) -## Prompt user to continue -## str: input string. Default value: "\n ---- Press a key to continue ---" -## @end format -## @end deftypefn - -## Author: David Clem -## Created: August 15, 1994 -## Modified A. S. Hodel June 1995 - -function prompt (str) - - if(nargin > 1) - usage("prompt([str])"); - elseif(nargin == 0) - str = "\n ---- Press a key to continue ---"; - elseif ( !isstr(str) ) - error("prompt: input must be a string"); - endif - - disp(str); - fflush(stdout); - kbhit; - -endfunction diff --git a/scripts/control/rldemo.m b/scripts/control/rldemo.m deleted file mode 100644 --- a/scripts/control/rldemo.m +++ /dev/null @@ -1,302 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -##@deftypefn {Function File} {@var{outputs} =} rldemo (@var{inputs}) -##Octave Controls toolbox demo: Root Locus demo -##@end deftypefn - -## Author: David Clem -## Created: August 15, 1994 -## Updated by John Ingram December 1996 - -function rldemo () - - while (1) - clc - k = menu("Octave Root Locus Demo", ... - "Display continuous system's open loop poles and zeros (pzmap)", ... - "Display discrete system's open loop poles and zeros (pzmap)", ... - "Display root locus diagram of SISO continuous system (rlocus)", ... - "Display root locus diagram of SISO discrete system (rlocus)", ... - "Return to main demo menu"); - gset autoscale - if (k == 1) - clc - help pzmap - prompt - - clc - disp("Display continuous system's open loop poles and zeros (pzmap)\n"); - disp("Example #1, Consider the following continuous transfer function:"); - cmd = "sys1 = tf2sys([1.5, 18.5, 6], [1, 4, 155, 302, 5050]);"; - disp(cmd); - eval(cmd); - cmd ="sysout(sys1);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys1,""zp"");"; - disp(cmd); - eval(cmd); - disp("View the system's open loop poles and zeros with the command:") - cmd = "pzmap(sys1);"; - run_cmd - prompt - - clc - disp("Example #2, Consider the following set of poles and zeros:"); - cmd = "sys2 = zp2sys([-1, 5, -23],[-1, -10, -7+5i, -7-5i],5);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys2);"; - disp(cmd); - eval(cmd); - disp("\nThe pzmap command for the zp form is the same as the tf form:") - cmd = "pzmap(sys2);"; - run_cmd; - disp("\nThe internal representation of the system is not important;"); - disp("pzmap automatically sorts it out internally."); - prompt; - - clc - disp("Example #3, Consider the following state space system:\n"); - cmd = "sys3=ss2sys([0, 1; -10, -11], [0; 1], [0, -2], 1);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys3);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys3,""zp"");"; - disp(cmd); - eval(cmd); - disp("\nOnce again, the pzmap command is the same:"); - cmd = "pzmap(sys3);"; - run_cmd; - prompt; - - closeplot - clc - - elseif (k == 2) - clc - help pzmap - prompt - - clc - disp("\nDisplay discrete system's open loop poles and zeros (pzmap)\n"); - disp("First we must define a sampling time, as follows:\n"); - cmd = "Tsam = 1;"; - run_cmd; - disp("Example #1, Consider the following discrete transfer function:"); - cmd = "sys1 = tf2sys([1.05, -0.09048], [1, -2, 1],Tsam);"; - disp(cmd); - eval(cmd); - cmd ="sysout(sys1);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys1,""zp"");"; - disp(cmd); - eval(cmd); - disp("View the system's open loop poles and zeros with the command:") - cmd = "pzmap(sys1);"; - run_cmd - prompt - - clc - disp("Example #2, Consider the following set of discrete poles and zeros:"); - cmd = "sys2 = zp2sys(-0.717, [1, -0.368], 3.68, Tsam);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys2);"; - disp(cmd); - eval(cmd); - disp("\nThe pzmap command for the zp form is the same as the tf form:") - cmd = "pzmap(sys2);"; - run_cmd; - disp("\nThe internal representation of the system is not important;"); - disp("pzmap automatically sorts it out internally."); - prompt; - - clc - disp("Example #3, Consider the following discrete state space system:\n"); - cmd = "sys3=ss2sys([1, 0.0952; 0, 0.905], [0.00484; 0.0952], [1, 0], 0, Tsam);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys3);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys3,""zp"");"; - disp(cmd); - eval(cmd); - disp("\nOnce again, the pzmap command is the same:"); - cmd = "pzmap(sys3);"; - run_cmd; - prompt; - - closeplot - clc - - elseif (k == 3) - clc - help rlocus - prompt; - - clc - disp("Display root locus of a continuous SISO system (rlocus)\n") - disp("Example #1, Consider the following continuous transfer function:"); - cmd = "sys1 = tf2sys([1.5, 18.5, 6],[1, 4, 155, 302, 5050]);"; - disp(cmd); - eval(cmd); - cmd ="sysout(sys1);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys1,""zp"");"; - disp(cmd); - eval(cmd); - disp("\nWhen using rlocus, inital system poles are displayed as X's.") - disp("Moving poles are displayed as diamonds. Zeros are displayed as") - disp("boxes. The simplest form of the rlocus command is as follows:") - cmd = "rlocus(sys1);"; - run_cmd - disp("\nrlocus automatically selects the minimum and maximum gains based") - disp("on the real-axis locus breakpoints. The plot limits are chosen") - disp("to be no more than 10 times the maximum magnitude of the open") - disp("loop poles/zeros."); - prompt - - clc - disp("Example #2, Consider the following set of poles and zeros:"); - cmd = "sys2 = zp2sys([],[0, -20, -2, -0.1],5);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys2);"; - disp(cmd); - eval(cmd); - disp("\nThe rlocus command for the zp form is the same as the tf form:") - cmd = "rlocus(sys2);"; - run_cmd; - disp("\nThe internal representation of the system is not important;"); - disp("rlocus automatically sorts it out internally."); - prompt; - - clc - disp("Example #3, Consider the following state space system:\n"); - cmd = "sys3=ss2sys([0, 1; -10, -11], [0; 1], [0, -2], 0);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys3);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys3,""zp"");"; - disp(cmd); - eval(cmd); - disp("\nOnce again, the rlocus command is the same:"); - cmd = "rlocus(sys3);"; - run_cmd; - - disp("\nNo matter what form the system is in, the rlocus command works the"); - disp("the same."); - prompt; - - closeplot - clc - - elseif (k == 4) - clc - help rlocus - prompt - - clc - disp("Display root locus of a discrete SISO system (rlocus)\n") - disp("First we must define a sampling time, as follows:\n"); - cmd = "Tsam = 1;"; - run_cmd; - disp("Example #1, Consider the following discrete transfer function:"); - cmd = "sys1 = tf2sys([1.05, -0.09048],[1, -2, 1],Tsam);"; - disp(cmd); - eval(cmd); - cmd ="sysout(sys1);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys1,""zp"");"; - disp(cmd); - eval(cmd); - disp("\nWhen using rlocus, inital system poles are displayed as X's.") - disp("Moving poles are displayed as diamonds. Zeros are displayed as") - disp("boxes. The simplest form of the rlocus command is as follows:") - cmd = "rlocus(sys1);"; - run_cmd - disp("\nrlocus automatically selects the minimum and maximum gains based") - disp("on the real-axis locus breakpoints. The plot limits are chosen") - disp("to be no more than 10 times the maximum magnitude of the open") - disp("loop poles/zeros."); - prompt - - clc - disp("Example #2, Consider the following set of discrete poles and zeros:"); - cmd = "sys2 = zp2sys(-0.717, [1, -0.368], 3.68, Tsam);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys2);"; - disp(cmd); - eval(cmd); - disp("\nThe rlocus command for the zp form is the same as the tf form:") - cmd = "rlocus(sys2);"; - run_cmd; - disp("\nThe internal representation of the system is not important;"); - disp("rlocus automatically sorts it out internally. Also, it does not"); - disp("matter if the system is continuous or discrete. rlocus also sorts"); - disp("this out automatically"); - prompt; - - clc - disp("Example #3, Consider the following discrete state space system:\n"); - cmd = "sys3=ss2sys([1, 0.0952; 0, 0.905], [0.00484; 0.0952], [1, 0], 0, Tsam);"; - disp(cmd); - eval(cmd); - cmd = "sysout(sys3);"; - disp(cmd); - eval(cmd); - disp("\nPole-zero form can be obtained as follows:"); - cmd = "sysout(sys3,""zp"");"; - disp(cmd); - eval(cmd); - disp("\nOnce again, the rlocus command is the same:"); - cmd = "rlocus(sys3);"; - run_cmd; - - disp("\nNo matter what form the system is in, the rlocus command works the"); - disp("the same."); - - prompt; - - closeplot - clc - - elseif (k == 5) - return - endif - endwhile -endfunction diff --git a/scripts/control/rlocus.m b/scripts/control/rlocus.m deleted file mode 100644 --- a/scripts/control/rlocus.m +++ /dev/null @@ -1,202 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outputs} =} rlocus (@var{inputs}) -## @format -## [rldata, k] = rlocus(sys[,increment,min_k,max_k]) -## Displays root locus plot of the specified SISO system. -## -## ----- --- -------- -## --->| + |---|k|---->| SISO |-----------> -## ----- --- -------- | -## - ^ | -## |_____________________________| -## -## inputs: sys = system data structure -## min_k, max_k,increment: minimum, maximum values of k and -## the increment used in computing gain values -## Outputs: plots the root locus to the screen. -## rldata: Data points plotted column 1: real values, column 2: imaginary -## values) -## k: gains for real axis break points. -## @end format -## @end deftypefn - -## Author: David Clem -## Author: R. Bruce Tenison -## Updated by Kristi McGowan July 1996 for intelligent gain selection -## Updated by John Ingram July 1996 for systems - -function [rldata, k_break, rlpol, gvec, real_ax_pts] = rlocus (sys, increment, min_k, max_k) - - if (nargin < 1) | (nargin > 4) - usage("rlocus(sys[,inc,mink,maxk])"); - endif - - ## Convert the input to a transfer function if necessary - - [num,den] = sys2tf(sys) # extract numerator/denom polyomials - lnum = length(num); lden = length(den); - if(lden < 2) - error(sprintf("length of derivative=%d, doesn't make sense",lden)); - elseif(lnum == 1) - num = [0, num]; # so that derivative is shortened by one - endif - - ## root locus plot axis limits - - ## compute real axis locus breakpoints - ## compute the derivative of the numerator and the denominator - dern=polyderiv(num); derd=polyderiv(den); - - ## compute real axis breakpoints - real_ax_pol = conv(den,dern) - conv(num,derd); - real_ax_pts = roots(real_ax_pol); - if(isempty(real_ax_pts)) - k_break = []; - maxk = 0; - else - ## compute gains that achieve the breakpoints - c1 = polyval(num,real_ax_pts); - c2 = polyval(den,real_ax_pts); - k_break = -real(c2 ./ c1); - maxk = max(max(k_break,0)); - endif - - ## compute gain ranges based on computed K values - if(maxk == 0) maxk = 1; - else maxk = 1.1*maxk; endif - mink = 0; - ngain = 20; - - ## check for input arguments: - if (nargin > 2) mink = min_k; endif - if (nargin > 3) maxk = max_k; endif - if (nargin > 1) - if(increment <= 0) error("increment must be positive"); - else - ngain = (maxk-mink)/increment; - endif - endif - - ## vector of gains - ngain = max(3,ngain); - gvec = linspace(mink,maxk,ngain); - - ## Find the open loop zeros and the initial poles - rlzer = roots(num); - - ## update num to be the same length as den - lnum = length(num); if(lnum < lden) num = [zeros(1,lden - lnum),num]; endif - - ## compute preliminary pole sets - nroots = lden-1; - for ii=1:ngain - gain = gvec(ii); - rlpol(1:nroots,ii) = vec(sortcom(roots(den + gain*num))); - endfor - - ## compute axis limits (isolate asymptotes) - olpol = roots(den); - real_axdat = union(real(rlzer), real(union(olpol,real_ax_pts)) ); - rmin = min(real_axdat); rmax = max(real_axdat); - - rlpolv = [vec(rlpol); vec(real_axdat)]; - idx = find(real(rlpolv) >= rmin & real(rlpolv) <= rmax); - axlim = axis2dlim([real(rlpolv(idx)),imag(rlpolv(idx))]); - xmin = axlim(1); - xmax = axlim(2); - - ## set smoothing tolerance per axis limits - smtol = 0.01*max(abs(axlim)); - - ## smooth poles if necessary, up to maximum of 1000 gain points - ## only smooth points within the axis limit window - ## smoothing done if max_k not specified as a command argument - done=(nargin == 4); # perform a smoothness check - while((!done) & ngain < 1000) - done = 1 ; # assume done - dp = abs(diff(rlpol'))'; - maxd = max(dp); - ## search for poles in the real axis limits whose neighbors are distant - idx = find(maxd > smtol); - for ii=1:length(idx) - i1 = idx(ii); g1 = gvec(i1); p1 = rlpol(:,i1); - i2 = idx(ii)+1; g2 = gvec(i2); p2 = rlpol(:,i2); - - ## isolate poles in p1, p2 that are inside the real axis limits - bidx = find( (real(p1) >= xmin & real(p1) <= xmax) ... - | (real(p2) >= xmin & real(p2) <= xmax) ); - if(!isempty(bidx)) - p1 = p1(bidx); - p2 = p2(bidx); - if( max(abs(p2-p1)) > smtol) - newg = linspace(g1,g2,5); - newg = newg(2:4); - if(isempty(newg)) - printf("rlocus: empty newg") - g1 - g2 - i1 - i2 - idx_i1 = idx(ii) - gvec_i1 = gvec(i1:i2) - delta_vec_i1 = diff(gvec(i1:i2)) - prompt - endif - gvec = [gvec,newg]; - done = 0; # need to process new gains - endif - endif - endfor - - ## process new gain values - ngain1 = length(gvec); - for ii=(ngain+1):ngain1 - gain = gvec(ii); - rlpol(1:nroots,ii) = vec(sortcom(roots(den + gain*num))); - endfor - - [gvec,idx] = sort(gvec); - rlpol = rlpol(:,idx); - ngain = length(gvec); - endwhile - - ## Plot the data - if(nargout == 0) - rlpolv = vec(rlpol); - idx = find(real(rlpolv) >= xmin & real(rlpolv) <= xmax); - axdata = [real(rlpolv(idx)),imag(rlpolv(idx))]; - axlim = axis2dlim(axdata); - axlim(1:2) = [xmin, xmax]; - gset nologscale xy; - grid("on"); - rldata = [real(rlpolv), imag(rlpolv) ]; - axis(axlim); - [stn,inname,outname] = sysgetsignals(sys); - xlabel(sprintf("Root locus from %s to %s, gain=[%f,%f]: Real axis", ... - nth(inname,1),nth(outname,1),gvec(1),gvec(ngain))); - ylabel("Imag. axis"); - - plot(real(rlpolv),imag(rlpolv),".1;locus points;", ... - real(olpol),imag(olpol),"x2;open loop poles;", ... - real(rlzer),imag(rlzer),"o3;zeros;"); - rldata = []; - endif -endfunction diff --git a/scripts/control/rotg.m b/scripts/control/rotg.m deleted file mode 100644 --- a/scripts/control/rotg.m +++ /dev/null @@ -1,28 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## function [c,s] = rotg(a,b) -## givens rotation calculation -## -## NOTE: Use [c,s] = givens(a,b) instead. - -function [c, s] = rotg (a, b) - - [c,s] = givens(a,b); - -endfunction diff --git a/scripts/control/run_cmd.m b/scripts/control/run_cmd.m deleted file mode 100644 --- a/scripts/control/run_cmd.m +++ /dev/null @@ -1,30 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## run_cmd: short script used in demos -## prints string cmd to the screen, then executes after a pause - -disp(["Command: ",cmd]) -puts("Press a key to execute command"); -fflush(stdout); -kbhit(); -disp(" executing"); -fflush(stdout); -eval(cmd); -disp("---") -disp(" ") diff --git a/scripts/control/sortcom.m b/scripts/control/sortcom.m deleted file mode 100644 --- a/scripts/control/sortcom.m +++ /dev/null @@ -1,84 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outputs} =} sortcom (@var{inputs}) -## @format -## [yy,idx] = sortcom(xx[,opt]): sort a complex vector -## xx: complex vector -## opt: sorting option: -## "re": real part (default) -## "mag": by magnitude -## "im": by imaginary part -## -## if opt != "im" then complex conjugate pairs are grouped together, -## a - jb followed by a + jb. -## yy: sorted values -## idx: permutation vector: yy = xx(idx) -## @end format -## @end deftypefn - -## Author: A. S. Hodel -## Created: June 1995 - -function [yy, idx] = sortcom (xx, opt) - - if( nargin < 1 | nargin > 2 ) - usage("yy = sortcom(xx[,opt]"); - elseif( !(is_vector(xx) | isempty(xx) )) - error("sortcom: first argument must be a vector"); - endif - - if(nargin == 1) opt = "re"; - else - if (!isstr(opt)) - error("sortcom: second argument must be a string"); - endif - endif - - if(isempty(xx)) - yy = idx = []; - else - if(strcmp(opt,"re")) datavec = real(xx); - elseif(strcmp(opt,"im")) datavec = imag(xx); - elseif(strcmp(opt,"mag")) datavec = abs(xx); - else error(["sortcom: invalid option = ", opt]) - endif - - [datavec,idx] = sort(datavec); - yy= xx(idx); - - if(strcmp(opt,"re") | strcmp(opt,"mag")) - ## sort so that complex conjugate pairs appear together - - ddiff = diff(datavec); - zidx = find(ddiff == 0); - - ## sort common datavec values - if(!isempty(zidx)) - for iv=create_set(datavec(zidx)) - vidx = find(datavec == iv); - [vals,imidx] = sort(imag(yy(vidx))); - yy(vidx) = yy(vidx(imidx)); - idx(vidx) = idx(vidx(imidx)); - endfor - endif - endif - endif -endfunction - diff --git a/scripts/control/step.m b/scripts/control/step.m deleted file mode 100644 --- a/scripts/control/step.m +++ /dev/null @@ -1,90 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{y}, @var{t}] =} step (@var{sys}@{, @var{inp},@var{tstop}, @var{n}@}) -## Step response for a linear system. -## The system can be discrete or multivariable (or both). -## If no output arguments are specified, @code{step} -## produces a plot or the step response data for system @var{sys}. -## -## @strong{Inputs} -## @table @var -## @item sys -## System data structure. -## @item inp -## Index of input being excited -## @item tstop -## The argument @var{tstop} (scalar value) denotes the time when the -## simulation should end. -## @item n -## the number of data values. -## -## Both parameters @var{tstop} and @var{n} can be omitted and will be -## computed from the eigenvalues of the A-Matrix. -## @end table -## @strong{Outputs} -## @var{y}, @var{t}: impulse response -## -## When invoked with the output paramter y the plot is not displayed. -## @end deftypefn -## @seealso{impulse and stepimp} - -## Author: Kai P. Mueller -## Created: September 30, 1997 -## based on lsim.m of Scottedward Hodel - -function [y, t] = step (sys, inp, tstop, n) - - if((nargin < 1) || (nargin > 4)) - usage("[y, u] = step(sys[, inp, tstop, n])"); - endif - - if(nargout > 2) - usage("[y, u] = step(sys[, inp, tstop, n])"); - endif - - if(!is_struct(sys)) - error("step: sys must be a system data structure."); - endif - - if (nargout == 0) - switch (nargin) - case (1) - stepimp(1, sys); - case (2) - stepimp(1, sys, inp); - case (3) - stepimp(1, sys, inp, tstop); - case (4) - stepimp(1, sys, inp, tstop, n); - endswitch - else - switch (nargin) - case (1) - [y, t] = stepimp(1, sys); - case (2) - [y, t] = stepimp(1, sys, inp); - case (3) - [y, t] = stepimp(1, sys, inp, tstop); - case (4) - [y, t] = stepimp(1, sys, inp, tstop, n); - endswitch - endif - -endfunction diff --git a/scripts/control/stepimp.m b/scripts/control/stepimp.m deleted file mode 100644 --- a/scripts/control/stepimp.m +++ /dev/null @@ -1,279 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{y}, @var{t}] = } stepimp (@var{sitype}, @var{sys} [, @var{inp}, @var{tstop}, @var{n}]) -## Impulse or step response for a linear system. -## The system can be discrete or multivariable (or both). -## This m-file contains the "common code" of step and impulse. -## -## Produces a plot or the response data for system sys. -## -## Limited argument checking; "do not attempt to do this at home". -## Used internally in @code{impulse}, @code{step}. Use @code{step} -## or @code{impulse} instead. -## @end deftypefn -## @seealso{step and impulse} - -## Author: Kai P. Mueller -## Created: October 2, 1997 -## based on lsim.m of Scottedward Hodel - -function [y, t] = stepimp (sitype, sys, inp, tstop, n) - - if (sitype == 1) IMPULSE = 0; - elseif (sitype == 2) IMPULSE = 1; - else error("stepimp: invalid sitype argument.") - endif - sys = sysupdate(sys,"ss"); - - USE_DEF = 0; # default tstop and n if we have to give up - N_MIN = 50; # minimum number of points - N_MAX = 2000; # maximum number of points - T_DEF = 10.0; # default simulation time - - ## collect useful information about the system - [ncstates,ndstates,NIN,NOUT] = sysdimensions(sys); - TSAMPLE = sysgettsam(sys); - - if (nargin < 3) inp = 1; - elseif (inp < 1 | inp > NIN) error("Argument inp out of range") - endif - - DIGITAL = is_digital(sys); - if (DIGITAL) - NSTATES = ndstates; - if (TSAMPLE < eps) - error("stepimp: sampling time of discrete system too small.") - endif - else NSTATES = ncstates; endif - if (NSTATES < 1) - error("step: pure gain block (n_states < 1), step response is trivial"); - endif - if (nargin < 5) - ## we have to compute the time when the system reaches steady state - ## and the step size - ev = eig(sys2ss(sys)); - if (DIGITAL) - ## perform bilinear transformation on poles in z - for i = 1:NSTATES - pole = ev(i); - if (abs(pole + 1) < 1.0e-10) - ev(i) = 0; - else - ev(i) = 2 / TSAMPLE * (pole - 1) / (pole + 1); - endif - endfor - endif - ## remove poles near zero from eigenvalue array ev - nk = NSTATES; - for i = 1:NSTATES - if (abs(ev(i)) < 1.0e-10) - ev(i) = 0; - nk = nk - 1; - endif - endfor - if (nk == 0) - USE_DEF = 1; - ## printf("##STEPIMP-DEBUG: using defaults.\n"); - else - ev = ev(find(ev)); - x = max(abs(ev)); - t_step = 0.2 * pi / x; - x = min(abs(real(ev))); - t_sim = 5.0 / x; - ## round up - yy = 10^(ceil(log10(t_sim)) - 1); - t_sim = yy * ceil(t_sim / yy); - ## printf("##STEPIMP-DEBUG: nk=%d t_step=%f t_sim=%f\n", - ## nk, t_step, t_sim); - endif - endif - - if (DIGITAL) - ## ---- sampled system - if (nargin == 5) - n = round(n); - if (n < 2) - error("stepimp: n must not be less than 2.") - endif - else - if (nargin == 4) - ## n is unknown - elseif (nargin >= 1) - ## tstop and n are unknown - if (USE_DEF) - tstop = (N_MIN - 1) * TSAMPLE; - else - tstop = t_sim; - endif - endif - n = floor(tstop / TSAMPLE) + 1; - if (n < 2) n = 2; endif - if (n > N_MAX) - n = N_MAX; - printf("Hint: number of samples limited to %d by default.\n", \ - N_MAX); - printf(" ==> increase \"n\" parameter for longer simulations.\n"); - endif - endif - tstop = (n - 1) * TSAMPLE; - t_step = TSAMPLE; - else - ## ---- continuous system - if (nargin == 5) - n = round(n); - if (n < 2) - error("step: n must not be less than 2.") - endif - t_step = tstop / (n - 1); - else - if (nargin == 4) - ## only n in unknown - if (USE_DEF) - n = N_MIN; - t_step = tstop / (n - 1); - else - n = floor(tstop / t_step) + 1; - endif - else - ## tstop and n are unknown - if (USE_DEF) - tstop = T_DEF; - n = N_MIN; - t_step = tstop / (n - 1); - else - tstop = t_sim; - n = floor(tstop / t_step) + 1; - endif - endif - if (n < N_MIN) - n = N_MIN; - t_step = tstop / (n - 1); - endif - if (n > N_MAX) - tstop = (n - 1) * t_step; - t_step = tstop / (N_MAX - 1); - n = N_MAX; - endif - endif - tstop = (n - 1) * t_step; - [jnk,B] = sys2ss(sys); - B = B(:,inp); - sys = c2d(sys, t_step); - endif - ## printf("##STEPIMP-DEBUG: t_step=%f n=%d tstop=%f\n", t_step, n, tstop); - - F = sys.a; - G = sys.b(:,inp); - C = sys.c; - D = sys.d(:,inp); - y = zeros(NOUT, n); - t = linspace(0, tstop, n); - - if (IMPULSE) - if (!DIGITAL && (D'*D > 0)) - error("impulse: D matrix is nonzero, impulse response infinite.") - endif - if (DIGITAL) - y(:,1) = D / t_step; - x = G / t_step; - else - x = B; - y(:,1) = C * x; - x = F * x; - endif - for i = 2:n - y(:,i) = C * x; - x = F * x; - endfor - else - x = zeros(NSTATES, 1); - for i = 1:n - y(:,i) = C * x + D; - x = F * x + G; - endfor - endif - - if(nargout == 0) - ## Plot the information - oneplot(); - gset nogrid - gset nologscale - gset autoscale - gset nokey - clearplot(); - if (gnuplot_has_multiplot) - if (IMPULSE) - gm = zeros(NOUT, 1); - tt = "impulse"; - else - ssys = ss2sys(F, G, C, D, t_step); - gm = dcgain(ssys); - tt = "step"; - endif - ncols = floor(sqrt(NOUT)); - nrows = ceil(NOUT / ncols); - for i = 1:NOUT - subplot(nrows, ncols, i); - title(sprintf("%s: | %s -> %s", tt,sysgetsignals(sys,"in",inp,1), ... - sysgetsignals(sys,"out",i,1))); - if (DIGITAL) - [ts, ys] = stairs(t, y(i,:)); - ts = ts(1:2*n-2)'; ys = ys(1:2*n-2)'; - if (length(gm) > 0) - yy = [ys; gm(i)*ones(size(ts))]; - else - yy = ys; - endif - grid("on"); - xlabel("time [s]"); - ylabel("y(t)"); - plot(ts, yy); - else - if (length(gm) > 0) - yy = [y(i,:); gm(i)*ones(size(t))]; - else - yy = y(i,:); - endif - grid("on"); - xlabel("time [s]"); - ylabel("y(t)"); - plot(t, yy); - endif - endfor - ## leave gnuplot in multiplot mode is bad style - oneplot(); - else - ## plot everything in one diagram - title([tt, " response | ", sysgetsignals(sys,"in",inp,1), ... - " -> all outputs"]); - if (DIGITAL) - stairs(t, y(i,:)); - else - grid("on"); - xlabel("time [s]"); - ylabel("y(t)"); - plot(t, y(i,:)); - endif - endif - y=[]; - t=[]; - endif - ## printf("##STEPIMP-DEBUG: gratulations, successfull completion.\n"); -endfunction diff --git a/scripts/control/strappend.m b/scripts/control/strappend.m deleted file mode 100644 --- a/scripts/control/strappend.m +++ /dev/null @@ -1,39 +0,0 @@ -## Copyright (C) 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## retval = strappend(strlist,suffix); -## append string suffix to each string in the list of strings strlist - -function retval = strappend (strlist, suffix); - - if(nargin != 2 | nargout > 1) - usage(" retval = strappend(strlist,suffix)"); - elseif(!is_signal_list(strlist)) - strlist - error("strlist must be a list of strings (see is_signal_list)"); - elseif(!(isstr(suffix) & rows(suffix) == 1)) - suffix - error("suffix must be a single string"); - endif - - retval = list(); - for ii=1:length(strlist) - retval(ii) = sprintf("%s%s",nth(strlist,ii),suffix); - endfor - -endfunction diff --git a/scripts/control/susball.m b/scripts/control/susball.m deleted file mode 100644 --- a/scripts/control/susball.m +++ /dev/null @@ -1,99 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outputs} =} susball (@var{inputs}) -## @end deftypefn - -cmd = "ballsys = margetsys(""disc"")"; -eval(cmd); - -disp("Design LQG controller"); -cmd = "sysout(ballsys)"; -run_cmd -disp("add noise inputs to system...") - -disp("discrete system:") -[nn,nz,mm,pp] = sysdimensions(ballsys); -cmd = "ballsys = sysappend(ballsys,nz);"; -run_cmd - -cmd = "sysout(ballsys)"; -run_cmd - -disp("Notice the two additional inputs, u_2, and u_3. These are the "); -disp("""entry points"" for the gaussian noise disturbance."); -disp(" "); -disp("We'll design the controller to use only position feedback:") - -cmd = "ballsys=sysprune(ballsys,1,[]);"; -run_cmd -cmd = "sysout(ballsys)"; -run_cmd - -disp("Now design an LQG controller: Sigw: input noise") -Sigw = eye(2) -disp("Now design an LQG controller: Sigv: measurement noise") -Sigv = eye(pp); - -disp("State and input penalties:") -Q = eye(2) -R = 1 -disp("Controlled input is input 1"); - -cmd="Ksys = lqg(ballsys,Sigw,Sigv,Q,R,1);"; -run_cmd - -disp("sysout(Ksys);"); -sysout(Ksys); - -disp("\nGet rid of the disturbance inputs"); -cmd = "ballsys = sysprune(ballsys,1,1);" -run_cmd; -sysout(ballsys); -sysout(ballsys,"zp"); - -disp("\nGrouping the plant and the controller"); -cmd = "closed_loop = sysgroup(ballsys,Ksys);" -run_cmd; -sysout(closed_loop); - -disp("\nduplicating the plant input"); -cmd = "closed_loop = sysdup(closed_loop,[],1);" -run_cmd; -sysout(closed_loop); - -## disp("\nscaling the duplicated input by -1"); -## cmd = "closed_loop = sysscale(closed_loop,[],diag([1,1,1]));" -## run_cmd; -## sysout(closed_loop); - -disp("\nconnecting plant output to controller input and controller output"); -disp("to the duplicated plant input"); -cmd = "closed_loop = sysconnect(closed_loop,[1 2],[2 3]);" -run_cmd; -sysout(closed_loop); - -disp("\nkeeping only the original plant input and plant output"); -cmd = "closed_loop = sysprune(closed_loop,1,1);" -run_cmd; -sysout(closed_loop); - -sysout(closed_loop,"zp"); - - diff --git a/scripts/control/swap.m b/scripts/control/swap.m deleted file mode 100644 --- a/scripts/control/swap.m +++ /dev/null @@ -1,37 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{outputs} =} swap (@var{inputs}) -## @format -## [a1,b1] = swap(a,b) -## interchange a and b -## @end format -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 24, 1992 -## Conversion to Octave R. Bruce Tenison July 4, 1994 - -function [a1, b1] = swap (a, b) - - a1 = b; - b1 = a; - -endfunction - diff --git a/scripts/control/system/abcddim.m b/scripts/control/system/abcddim.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/abcddim.m @@ -0,0 +1,129 @@ +## Copyright (C) 1993, 1994, 1995 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{n}, @var{m}, @var{p}] =} abcddim (@var{a}, @var{b}, @var{c}, @var{d}) +## Check for compatibility of the dimensions of the matrices defining +## the linear system +## @iftex +## @tex +## $[A, B, C, D]$ corresponding to +## $$ +## \eqalign{ +## {dx\over dt} &= A x + B u\cr +## y &= C x + D u} +## $$ +## @end tex +## @end iftex +## @ifinfo +## [A, B, C, D] corresponding to +## +## @example +## dx/dt = a x + b u +## y = c x + d u +## @end example +## +## @end ifinfo +## or a similar discrete-time system. +## +## If the matrices are compatibly dimensioned, then @code{abcddim} returns +## +## @table @var +## @item n +## The number of system states. +## +## @item m +## The number of system inputs. +## +## @item p +## The number of system outputs. +## @end table +## +## Otherwise @code{abcddim} returns @var{n} = @var{m} = @var{p} = @minus{}1. +## +## Note: n = 0 (pure gain block) is returned without warning. +## +## @end deftypefn +## @seealso{is_abcd} + +## Author: A. S. Hodel +## Created: August 1993. +## a s hodel: modified to accept pure-gain systems aug 1996 + +function [n, m, p] = abcddim (a, b, c, d) + + if (nargin != 4) + error ("abcddim: four arguments required"); + endif + + n = m = p = -1; + + [a,an,am] = abcddims(a); + [b,bn,bm] = abcddims(b); + [c,cn,cm] = abcddims(c); + [d,dn,dm] = abcddims(d); + + if ( (!is_square(a)) & (!isempty(a)) ) + warning (["abcddim: a is not square (",num2str(an),"x",num2str(am),")"]); + return + endif + + if( (bm == 0) & (dm == 0) ) + warning("abcddim: no inputs"); + elseif (bn != am) + warning (["abcddim: a(",num2str(an),"x",num2str(am), ... + " and b(",num2str(bn),"x",num2str(bm),") are not compatible"]); + return + endif + + if( (cn == 0) & (dn == 0 ) ) + warning("abcddim: no outputs"); + elseif (cm != an) + warning (["abcddim: a(",num2str(an),"x",num2str(am), ... + " and c(",num2str(cn),"x",num2str(cm),") are not compatible"]); + return + endif + + have_connections = (bn*cn != 0); + + if( (dn == 0) & have_connections) + warning("abcddim: empty d matrix passed; setting compatibly with b, c"); + [d,dn,dm] = abcddims(zeros(cn,bm)); + endif + + if(an > 0) + [dn, dm] = size(d); + if ( (cn != dn) & have_connections ) + warning (["abcddim: c(",num2str(cn),"x",num2str(cm), ... + " and d(",num2str(dn),"x",num2str(dm),") are not compatible"]); + return + endif + + if ( (bm != dm) & have_connections ) + warning (["abcddim: b(",num2str(bn),"x",num2str(bm), ... + " and d(",num2str(dn),"x",num2str(dm),") are not compatible"]); + return + endif + + m = bm; + p = cn; + else + [p,m] = size(d); + endif + n = an; +endfunction diff --git a/scripts/control/system/abcddims.m b/scripts/control/system/abcddims.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/abcddims.m @@ -0,0 +1,38 @@ +## Copyright (C) 1997 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{y}, @var{my}, @var{ny}] =} abcddims (@var{x}) +## +## Used internally in @code{abcddim}. If @var{x} is a zero-size matrix, +## both dimensions are set to 0 in @var{y}. +## @var{my} and @var{ny} are the row and column dimensions of the result. +## @end deftypefn + +## Author: A. S. Hodel +## Created: February 1997 + +function [y, my, ny] = abcddims (x) + + y = x; + if(isempty(y)) + y = []; + endif + [my,ny] = size(y); + +endfunction diff --git a/scripts/control/system/buildssic.m b/scripts/control/system/buildssic.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/buildssic.m @@ -0,0 +1,300 @@ +## Copyright (C) 1998 Kai P. Mueller +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{sys} =} buildssic(@var{Clst}, @var{Ulst}, @var{Olst}, @var{Ilst}, @var{s1}, @var{s2}, @var{s3}, @var{s4}, @var{s5}, @var{s6}, @var{s7}, @var{s8}) +## +## Form an arbitrary complex (open or closed loop) system in +## state-space form from several systems. "@code{buildssic}" can +## easily (despite it's cryptic syntax) integrate transfer functions +## from a complex block diagram into a single system with one call. +## This function is especially useful for building open loop +## interconnections for H_infinity and H2 designs or for closing +## loops with these controllers. +## +## Although this function is general purpose, the use of "@code{sysgroup}" +## "@code{sysmult}", "@code{sysconnect}" and the like is recommended for +## standard operations since they can handle mixed discrete and continuous +## systems and also the names of inputs, outputs, and states. +## +## The parameters consist of 4 lists that describe the connections +## outputs and inputs and up to 8 systems s1-s8. +## Format of the lists: +## @table @var +## @item Clst +## connection list, describes the input signal of +## each system. The maximum number of rows of Clst is +## equal to the sum of all inputs of s1-s8. +## +## Example: +## @code{[1 2 -1; 2 1 0]} ==> new input 1 is old inpout 1 +## + output 2 - output 1, new input 2 is old input 2 +## + output 1. The order of rows is arbitrary. +## +## @item Ulst +## if not empty the old inputs in vector Ulst will +## be appended to the outputs. You need this if you +## want to "pull out" the input of a system. Elements +## are input numbers of s1-s8. +## +## @item Olst +## output list, specifiy the outputs of the resulting +## systems. Elements are output numbers of s1-s8. +## The numbers are alowed to be negative and may +## appear in any order. An empty matrix means +## all outputs. +## +## @item Ilst +## input list, specifiy the inputs of the resulting +## systems. Elements are input numbers of s1-s8. +## The numbers are alowed to be negative and may +## appear in any order. An empty matrix means +## all inputs. +## @end table +## +## Example: Very simple closed loop system. +## @example +## @group +## w e +-----+ u +-----+ +## --->o--*-->| K |--*-->| G |--*---> y +## ^ | +-----+ | +-----+ | +## - | | | | +## | | +----------------> u +## | | | +## | +-------------------------|---> e +## | | +## +----------------------------+ +## @end group +## @end example +## +## The closed loop system GW can be optained by +## @example +## GW = buildssic([1 2; 2 -1], 2, [1 2 3], 2, G, K); +## @end example +## @table @var +## @item Clst +## (1. row) connect input 1 (G) with output 2 (K). +## (2. row) connect input 2 (K) with neg. output 1 (G). +## @item Ulst +## append input of (2) K to the number of outputs. +## @item Olst +## Outputs are output of 1 (G), 2 (K) and appended output 3 (from Ulst). +## @item Ilst +## the only input is 2 (K). +## @end table +## +## Here is a real example: +## @example +## @group +## +----+ +## -------------------->| W1 |---> v1 +## z | +----+ +## ----|-------------+ || GW || => min. +## | | vz infty +## | +---+ v +----+ +## *--->| G |--->O--*-->| W2 |---> v2 +## | +---+ | +----+ +## | | +## | v +## u y +## @end group +## @end example +## +## The closed loop system GW from [z; u]' to [v1; v2; y]' can be +## obtained by (all SISO systems): +## @example +## GW = buildssic([1, 4; 2, 4; 3, 1], 3, [2, 3, 5], +## [3, 4], G, W1, W2, One); +## @end example +## where "One" is a unity gain (auxillary) function with order 0. +## (e.g. @code{One = ugain(1);}) +## @end deftypefn + +## Author: Kai P. Mueller +## Created: April 1998 + +function sys = buildssic (Clst, Ulst, Olst, Ilst, s1, s2, s3, s4, s5, s6, s7, s8) + + if((nargin < 5) || (nargin > 12)) + usage("sys = buildssic(Clst,Ulst,Olst,Ilst,s1,s2,s3,s4,s5,s6,s7,s8)"); + endif + if (nargin >= 5) + if (!is_struct(s1)) + error("---> s1 must be a structed system."); + endif + s1 = sysupdate(s1, "ss"); + [n, nz, m, p] = sysdimensions(s1); + if (!n && !nz) + error("---> pure static system must not be the first in list."); + endif + if (n && nz) + error("---> cannot handle mixed continuous and discrete systems."); + endif + D_SYS = (nz > 0); + [A,B,C,D,tsam] = sys2ss(s1); + nt = n + nz; + endif + for ii = 6:nargin + eval(["ss = s", num2str(ii-4), ";"]); + if (!is_struct(ss)) + error("---> Parameter must be a structed system."); + endif + ss = sysupdate(ss, "ss"); + [n1, nz1, m1, p1] = sysdimensions(ss); + if (n1 && nz1) + error("---> cannot handle mixed continuous and discrete systems."); + endif + if (D_SYS) + if (n1) + error("---> cannot handle mixed cont. and discr. systems."); + endif + if (tsam != sysgettsam(ss)) + error("---> sampling time of all systems must match."); + endif + endif + [as,bs,cs,ds] = sys2ss(ss); + nt1 = n1 + nz1; + if (!nt1) + ## pure gain (pad B, C with zeros) + B = [B, zeros(nt,m1)]; + C = [C; zeros(p1,nt)]; + else + A = [A, zeros(nt,nt1); zeros(nt1,nt), as]; + B = [B, zeros(nt,m1); zeros(nt1,m), bs]; + C = [C, zeros(p,nt1); zeros(p1,nt), cs]; + endif + D = [D, zeros(p,m1); zeros(p1,m), ds]; + n = n + n1; + nz = nz + nz1; + nt = nt + nt1; + m = m + m1; + p = p + p1; + endfor + + ## check maximum dimensions + [nx, mx] = size(Clst); + if (nx > m) + error("---> more rows in Clst than total number of inputs."); + endif + if (mx > p+1) + error("---> more cols in Clst than total number of outputs."); + endif + ## empty vector Ulst is OK + lul = length(Ulst); + if (lul) + if (!is_vector(Ulst)) + error("---> Input u list Ulst must be a vector."); + endif + if (lul > m) + error("---> more values in Ulst than number of inputs."); + endif + endif + if (!length(Olst)) Olst = [1:(p+lul)]; endif + if (!length(Ilst)) Ilst = [1:m]; endif + if (!is_vector(Olst)) + error("---> Output list Olst must be a vector."); + endif + if (!is_vector(Ilst)) + error("---> Input list Ilst must be a vector."); + endif + + ## build the feedback "K" from the interconnection data Clst + K = zeros(m, p); + inp_used = zeros(m,1); + for ii = 1:nx + xx = Clst(ii,:); + iu = xx(1); + if ((iu < 1) || (iu > m)) + error("---> invalid value in first col of Clst."); + endif + if (inp_used(iu)) + error("---> Input specified more than once."); + endif + inp_used(iu) = 1; + for kk = 2:mx + it = xx(kk); + if (abs(it) > p) + error("---> invalid row value in Clst."); + elseif (it) + K(iu,abs(it)) = sign(it); + endif + endfor + endfor + + ## form the "closed loop", i.e replace u in + ## . + ## x = Ax + Bu + ## ~ + ## y = Cx + Du by u = K*y+u + ## + ## -1 + ## R = (I-D*K) must exist. + + R = eye(p) - D*K; + if (rank(R) < p) + error("---> singularity in algebraic loop."); + else + R = inv(R); + endif + A = A + B*K*R*C; + B = B + B*K*R*D; + C = R*C; + D = R*D; + + ## append old inputs u to the outputs (if lul > 0) + kc = K*C; + kdi = eye(m) + K*D; + for ii = 1:lul + it = Ulst(ii); + if ((it < 1) || (it > m)) + error("---> invalid value in Ulst."); + endif + C = [C; kc(it,:)]; + D = [D; kdi(it,:)]; + endfor + + ## select and rearrange outputs + nn = length(A); + lol = length(Olst); + Cnew = zeros(lol,nn); + Dnew = zeros(lol,m); + for ii = 1:lol + iu = Olst(ii); + if (!iu || (abs(iu) > p+lul)) + error("---> invalid value in Olst."); + endif + Cnew(ii,:) = sign(iu)*C(abs(iu),:); + Dnew(ii,:) = sign(iu)*D(abs(iu),:); + endfor + C = Cnew; + D = Dnew; + lil = length(Ilst); + Bnew = zeros(nn,lil); + Dnew = zeros(lol,lil); + for ii = 1:lil + iu = Ilst(ii); + if (!iu || (abs(iu) > m)) + error("---> invalid value in Ilst."); + endif + Bnew(:,ii) = sign(iu)*B(:,abs(iu)); + Dnew(:,ii) = sign(iu)*D(:,abs(iu)); + endfor + + sys = ss2sys(A, Bnew, C, Dnew, tsam, n, nz); + +endfunction diff --git a/scripts/control/system/c2d.m b/scripts/control/system/c2d.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/c2d.m @@ -0,0 +1,175 @@ +## Copyright (C) 1993, 1994, 1995 John W. Eaton +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{dsys} =} c2d (@var{sys}@{, @var{opt}, @var{T}@}) +## @deftypefnx {Function File} {@var{dsys} =} c2d (@var{sys}@{, @var{T}@}) +## +## @strong{Inputs} +## @table @var +## @item sys +## system data structure (may have both continuous time and discrete +## time subsystems) +## @item opt +## string argument; conversion option (optional argument; +## may be omitted as shown above) +## @table @code +## @item "ex" +## use the matrix exponential (default) +## @item "bi" +## use the bilinear transformation +## @end table +## @example +## 2(z-1) +## s = ----- +## T(z+1) +## @end example +## FIXME: This option exits with an error if @var{sys} is not purely +## continuous. (The @code{ex} option can handle mixed systems.) +## @item @var{T} +## sampling time; required if sys is purely continuous. +## +## @strong{Note} If the 2nd argument is not a string, @code{c2d} assumes that +## the 2nd argument is @var{T} and performs appropriate argument checks. +## @end table +## +## @strong{Outputs} +## @var{dsys} discrete time equivalent via zero-order hold, +## sample each @var{T} sec. +## +## converts the system data structure describing +## @example +## . +## x = Ac x + Bc u +## @end example +## into a discrete time equivalent model +## @example +## x[n+1] = Ad x[n] + Bd u[n] +## @end example +## via the matrix exponential or bilinear transform +## +## @strong{Note} This function adds the suffix @code{_d} +## to the names of the new discrete states. +## @end deftypefn + +## Author: R. Bruce Tenison +## Created: October 1993 +## Updated by John Ingram for system data structure August 1996 + +function dsys = c2d (sys, opt, T) + ## parse input arguments + if(nargin < 1 | nargin > 3) + usage("dsys=c2d(sys[,T])"); + elseif (!is_struct(sys)) + error("sys must be a system data structure"); + elseif (nargin == 1) + opt = "ex"; + elseif (nargin == 2 & !isstr(opt) ) + T = opt; + opt = "ex"; + endif + + ## check if sampling period T was passed. + Ts = sysgettsam(sys); + if(!exist("T")) + T = Ts; + if(T == 0) + error("sys is purely continuous; no sampling period T provided"); + endif + elseif (T != Ts & Ts > 0) + warning(["c2d: T=",num2str(T),", system tsam==",num2str(Ts), ... + ": using T=", num2str(min(T,Ts))]); + T = min(T,Ts); + endif + + if (!is_sample(T)) + error("sampling period T must be a postive, real scalar"); + elseif( ! (strcmp(opt,"ex") | strcmp(opt,"bi") ) ) + error(["invalid option passed: ",opt]) + endif + + sys = sysupdate(sys,"ss"); + [n,nz,m,p] = sysdimensions(sys); + if(n == 0) + dsys = syssetsignals(sys,"yd",ones(1:p)); + elseif(strcmp(opt,"ex")); + [aa,bb,cc,dd] = sys2ss(sys); + crng= 1:n; + drng = n+(1:nz); + + ## partition state equations into continuous, imaginary subsystems + Ac = aa(crng,crng); + Bc = bb(crng,:); + if(nz == 0) + Acd = Adc = Add = Bd = 0; + else + Acd = aa(crng,drng); + Adc = aa(drng,crng); + Add = aa(drng,drng); + Bd = bb(drng,:); + Bc = [Bc, Acd]; ## append discrete states as inputs to cont system + endif + + ## convert state equations + mat = [Ac, Bc; zeros(m+nz,n+nz+m)]; + matexp = expm(mat * T); + + ## replace Ac + aa(crng,crng) = matexp(crng,crng); ## discretized homegenous diff eqn + + ## replace Bc + bb(crng,:) = matexp(crng,n+(1:m)); + + ## replace Acd + if(nz) + aa(crng,drng) = matexp(crng,n+m+(1:nz)); + end + + stnames = sysgetsignals(sys,"st"); ## continuous states renamed below + innames = sysgetsignals(sys,"in"); + outnames = sysgetsignals(sys,"out"); + outlist = 1:p; + dsys = ss2sys(aa,bb,cc,dd,T,0,n+nz,stnames,innames, ... + outnames,outlist); + ## rename states + for ii=1:n + strval = sprintf("%s_d",sysgetsignals(dsys,"st",ii,1)); + dsys = syssetsignals(dsys,"st",strval,ii); + endfor + + elseif(strcmp(opt,"bi")) + if(is_digital(sys)) + error("c2d: system is already digital") + else + ## convert with bilinear transform + [a,b,c,d,tsam,n,nz,stname,inname,outname,yd] = sys2ss(sys); + IT = (2/T)*eye(size(a)); + A = (IT+a)/(IT-a); + iab = (IT-a)\b; + tk=2/sqrt(T); + B = tk*iab; + C = tk*(c/(IT-a)); + D = d + (c*iab); + stnamed = strappend(stname,"_d"); + dsys = ss2sys(A,B,C,D,T,0,rows(A),stnamed,inname,outname); + endif + else + error(["Bad option=",opt]) + endif + +endfunction diff --git a/scripts/control/system/d2c.m b/scripts/control/system/d2c.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/d2c.m @@ -0,0 +1,222 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{csys} =} d2c (@var{sys}@{,@var{tol}@}) +## @deftypefnx {Function File} {@var{csys} =} d2c (@var{sys}, @var{opt}) +## Convert discrete (sub)system to a purely continuous system. Sampling +## time used is @code{sysgettsam(@var{sys})} +## +## @strong{Inputs} +## @table @var +## @item sys +## system data structure with discrete components +## @item tol +## Scalar value. +## tolerance for convergence of default @code{"log"} option (see below) +## @item opt +## conversion option. Choose from: +## @table @code +## @item "log" +## (default) Conversion is performed via a matrix logarithm. +## Due to some problems with this computation, it is +## followed by a steepest descent algorithm to identify continuous time +## @var{A}, @var{B}, to get a better fit to the original data. +## +## If called as @code{d2c}(@var{sys},@var{tol}), @var{tol=}positive scalar, +## the @code{"log"} option is used. The default value for @var{tol} is +## @code{1e-8}. +## @item "bi" +## Conversion is performed via bilinear transform +## @math{z = (1 + s T / 2)/(1 - s T / 2)} where @var{T} is the +## system sampling time (see @code{sysgettsam}). +## +## FIXME: bilinear option exits with an error if @var{sys} is not purely +## discrete +## @end table +## @end table +## @strong{Outputs} @var{csys} continuous time system (same dimensions and +## signal names as in @var{sys}). +## @end deftypefn + +## Author: R. Bruce Tenison +## Created: August 23, 1994 +## Updated by John Ingram for system data structure August 1996 + +function csys = d2c (sys, opt) + + ## SYS_INTERNAL accesses members of system data structure + + if( (nargin != 1) & (nargin != 2) ) + usage("csys = d2c(sys[,tol]), csys = d2c(sys,opt)"); + elseif (!is_struct(sys)) + error("sys must be in system data structure"); + elseif(nargin == 1) + opt = "log"; + tol = 1e-12; + elseif(isstr(opt)) # all remaining cases are for nargin == 2 + tol = 1e-12; + if( !(strcmp(opt,"log") | strcmp(opt,"bi") ) ) + error(["d2c: invalid opt passed=",opt]); + endif + elseif(!is_sample(opt)) + error("tol must be a postive scalar") + elseif(opt > 1e-2) + warning(["d2c: ridiculous error tolerance passed=",num2str(opt); ... + ", intended c2d call?"]) + else + tol = opt; + opt = "log"; + endif + T = sysgettsam(sys); + + if(strcmp(opt,"bi")) + ## bilinear transform + ## convert with bilinear transform + if (! is_digital(sys) ) + error("d2c requires a discrete time system for input") + endif + [a,b,c,d,tsam,n,nz,stname,inname,outname,yd] = sys2ss(sys); + + poles = eig(a); + if( find(abs(poles-1) < 200*(n+nz)*eps) ) + warning("d2c: some poles very close to one. May get bad results."); + endif + + I = eye(size(a)); + tk = 2/sqrt(T); + A = (2/T)*(a-I)/(a+I); + iab = (I+a)\b; + B = tk*iab; + C = tk*(c/(I+a)); + D = d- (c*iab); + stnamec = strappend(stname,"_c"); + csys = ss2sys(A,B,C,D,0,rows(A),0,stnamec,inname,outname); + elseif(strcmp(opt,"log")) + sys = sysupdate(sys,"ss"); + [n,nz,m,p] = sysdimensions(sys); + + if(nz == 0) + warning("d2c: all states continuous; setting outputs to agree"); + csys = syssetsignals(sys,"yd",zeros(1,1:p)); + return; + elseif(n != 0) + warning(["d2c: n=",num2str(n),">0; performing c2d first"]); + sys = c2d(sys,T); + endif + [a,b] = sys2ss(sys); + + [ma,na] = size(a); + [mb,nb] = size(b); + + if(isempty(b) ) + warning("d2c: empty b matrix"); + Amat = a; + else + Amat = [a, b; zeros(nb,na), eye(nb)]; + endif + + poles = eig(a); + if( find(abs(poles) < 200*(n+nz)*eps) ) + warning("d2c: some poles very close to zero. logm not performed"); + Mtop = zeros(ma, na+nb); + elseif( find(abs(poles-1) < 200*(n+nz)*eps) ) + warning("d2c: some poles very close to one. May get bad results."); + logmat = real(logm(Amat)/T); + Mtop = logmat(1:na,:); + else + logmat = real(logm(Amat)/T); + Mtop = logmat(1:na,:); + endif + + ## perform simplistic, stupid optimization approach. + ## should re-write with a Davidson-Fletcher CG approach + mxthresh = norm(Mtop); + if(mxthresh == 0) + mxthresh = 1; + endif + eps1 = mxthresh; #gradient descent step size + cnt = max(20,(n*nz)*4); #max number of iterations + newgrad=1; #signal for new gradient + while( (eps1/mxthresh > tol) & cnt) + cnt = cnt-1; + ## calculate the gradient of error with respect to Amat... + geps = norm(Mtop)*1e-8; + if(geps == 0) + geps = 1e-8; + endif + DMtop = Mtop; + if(isempty(b)) + Mall = Mtop; + DMall = DMtop; + else + Mall = [Mtop; zeros(nb,na+nb)]; + DMall = [DMtop; zeros(nb,na+nb) ]; + endif + + if(newgrad) + GrMall = zeros(size(Mall)); + for ii=1:rows(Mtop) + for jj=1:columns(Mtop) + DMall(ii,jj) = Mall(ii,jj) + geps; + GrMall(ii,jj) = norm (Amat - expm (DMall*T), "fro") ... + - norm (Amat - expm (Mall*T), "fro"); + DMall(ii,jj) = Mall(ii,jj); + endfor + endfor + GrMall = GrMall/norm(GrMall,1); + newgrad = 0; + endif + + ## got a gradient, now try to use it + DMall = Mall-eps1*GrMall; + + FMall = expm(Mall*T); + FDMall = expm(DMall*T); + FmallErr = norm(Amat - FMall); + FdmallErr = norm(Amat - FDMall); + if( FdmallErr < FmallErr) + Mtop = DMall(1:na,:); + eps1 = min(eps1*2,1e12); + newgrad = 1; + else + eps1 = eps1/2; + endif + + if(FmallErr == 0) + eps1 = 0; + endif + + endwhile + + [aa,bb,cc,dd,tsam,nn,nz,stnam,innam,outnam,yd] = sys2ss(sys); + aa = Mall(1:na,1:na); + if(!isempty(b)) + bb = Mall(1:na,(na+1):(na+nb)); + endif + csys = ss2sys(aa,bb,cc,dd,0,na,0,stnam,innam,outnam); + + ## update names + nn = sysdimensions(sys); + for ii = (nn+1):na + strval = sprintf("%s_c",sysgetsignals(csys,"st",ii,1)); + csys = syssetsignals(csys,"st",strval,ii); + endfor + endif + +endfunction diff --git a/scripts/control/system/dmr2d.m b/scripts/control/system/dmr2d.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/dmr2d.m @@ -0,0 +1,259 @@ +## Copyright (C) 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{dsys}, @var{fidx}] =} dmr2d (@var{sys}, @var{idx}, @var{sprefix}, @var{Ts2} @{,@var{cuflg}@}) +## convert a multirate digital system to a single rate digital system +## states specified by @var{idx}, @var{sprefix} are sampled at @var{Ts2}, all +## others are assumed sampled at @var{Ts1} = @code{sysgettsam(@var{sys})}. +## +## @strong{Inputs} +## @table @var +## @item sys +## discrete time system; +## @code{dmr2d} exits with an error if @var{sys} is not discrete +## @item idx +## list of states with sampling time @code{sysgettsam(@var{sys})} (may +## be empty) +## @item sprefix +## list of string prefixes of states with sampling time +## @code{sysgettsam(@var{sys})} +## (may be empty) +## @item Ts2 +## sampling time of states not specified by @var{idx}, @var{sprefix} +## must be an integer multiple of @code{sysgettsam(@var{sys})} +## @item cuflg +## "constant u flag" if @var{cuflg} is nonzero then the system inputs are +## assumed to be constant over the revised sampling interval @var{Ts2}. +## Otherwise, since the inputs can change during the interval +## @var{t} in @math{[k Ts2, (k+1) Ts2]}, an additional set of inputs is +## included in the revised B matrix so that these intersample inputs +## may be included in the single-rate system. +## default @var{cuflg} = 1. +## @end table +## +## @strong{Outputs} +## @table @var +## @item dsys +## equivalent discrete time system with sampling time @var{Ts2}. +## +## The sampling time of sys is updated to @var{Ts2}. +## +## if @var{cuflg}=0 then a set of additional inputs is added to +## the system with suffixes _d1, ..., _dn to indicate their +## delay from the starting time k @var{Ts2}, i.e. +## u = [u_1; u_1_d1; ..., u_1_dn] where u_1_dk is the input +## k*Ts1 units of time after u_1 is sampled. (Ts1 is +## the original sampling time of discrete time sys and +## @var{Ts2} = (n+1)*Ts1) +## +## @item fidx +## indices of "formerly fast" states specified by @var{idx} and @var{sprefix}; +## these states are updated to the new (slower) sampling interval @var{Ts2}. +## @end table +## +## @strong{WARNING} Not thoroughly tested yet; especially when +## @var{cuflg} == 0. +## @end deftypefn + +## Adapted from c2d by a.s.hodel@eng.auburn.edu + +function [dsys, fidx] = dmr2d (sys, idx, sprefix, Ts2, cuflg) + + ## parse input arguments + if(nargin != 4 | nargout > 2) + usage("[dsys,fidx] = dmr2d (sys, idx, sprefix, Ts2 {,cuflg})"); + + elseif (!is_struct(sys)) + error("sys must be in system data structure form"); + + elseif(!is_digital(sys)) + error("sys must be discrete-time; continuous time passed"); + + elseif (!(is_vector(idx) | isempty(idx))) + error(["idx(",num2str(rows(idx)),"x",num2str(columns(idx)), ... + ") must be a vector"]); + + elseif (any(idx <= 0)) + idv = find(idx <= 0); + ii = idv(1); + error(["idx(",num2str(ii),")=",num2str(idx(ii)), ... + "; entries of idx must be positive"]); + + elseif(!(is_signal_list(sprefix) | isempty(sprefix))) + error("sprefix must be a signal list (see is_signal_list) or empty"); + + elseif(!is_sample(Ts2)) + error(["Ts2=",num2str(Ts2),"; invalid sampling time"]); + + endif + + ## optional argument: cuflg + if(nargin <= 4) + cuflg = 1; # default: constant inputs over Ts2 sampling interv. + elseif( !is_scalar(cuflg) ) + error("cuflg must be a scalar") + elseif( cuflg != 0 | cuflg != 1) + error(["cuflg = ",num2str(cuflg),", should be 0 or 1"]); + endif + + ## extract state space information + [da,db,dc,dd,Ts1,nc,nz,stname,inname,outname,yd] = sys2ss(sys); + + ## compute number of steps + if(Ts1 > Ts2) + error(["Current sampling time=",num2str(Ts1),"< Ts2=",num2str(Ts2)]); + endif + nstp = floor(Ts2/Ts1+0.5); + if(abs((Ts2 - Ts1*nstp)/Ts1) > 1e-12) + warning(["dmr2d: Ts1=",num2str(Ts1),", Ts2=",num2str(Ts2), ... + ", selecting nsteps=",num2str(nstp),"; mismatch"]); + endif + + if(isempty(sprefix) & isempty(idx)) + warning("both sprefix and idx are empty; returning dsys=sys"); + fidx = []; + dsys = sys; + return + elseif(isempty(sprefix)) + fidx = idx; + else + fidx = reshape(idx,1,length(idx)); + ## find states whose name begins with any strings in sprefix. + ns = length(sprefix); + for kk=1:ns + spk = nth(sprefix,kk); # get next prefix and length + spl = length(spk); + + ## check each state name + for ii=1:nz + sti = nth(stname,ii); # compare spk with this state name + if(length(sti) >= spl) + ## if the prefix matches and ii isn't already in the list, add ii + if(strcmp(sti(1:spl),spk) & !any(fidx == ii) ) + fidx = sort([fidx,ii]); + endif + endif + endfor + endfor + endif + + if(nstp == 0) + warning("dmr2d: nstp = 0; setting tsam and returning"); + dsys = syschtsam(sys,Ts2); + return + elseif(nstp < 0) + error(["nstp = ", num2str(nstp)," < 0; this shouldn't be!"]); + endif + + ## permute system matrices + pv = sysreorder(nz,fidx); + pv = pv(nz:-1:1); # reverse order to put fast modes in leading block + + ## construct inverse permutation + Inz = eye(nz); + pvi = (Inz(pv,:)'*[1:nz]')'; + + ## permute A, B (stname permuted for debugging only) + da = da(pv,pv); + db = db(pv,:); + stname = stname(pv,:); + + ## partition A, B: + lfidx = length(fidx); + bki = 1:lfidx; + a11 = da(bki,bki); + b1 = db(bki,:); + + if(lfidx < nz) + lfidx1 = lfidx+1; + bki2 = (lfidx1):nz; + a12 = da(bki,bki2); + b2 = db(bki2,:); + else + warning("dmr2d: converting entire A,B matrices to new sampling rate"); + lfidx1 = -1; + bki2 = []; + endif + + ## begin system conversion: nstp steps + + ## compute abar_{n-1}*a12 and appropriate b matrix stuff + a12b = a12; # running total of abar_{n-1}*a12 + a12w = a12; # current a11^n*a12 (start with n = 0) + if(cuflg) + b1b = b1; + b1w = b1; + else + ## cuflg == 0, need to keep track of intersample inputs too + nzdx = find(max(abs(b1)) != 0); # FIXME: check tolerance relative to ||b1|| + b1w = b1(nzdx); + innamenz = inname(nzdx); + b1b = b1; # initial b1 must match columns in b2 + endif + + ## compute a11h = a11^nstp by squaring + a11h = eye(size(a11)); + p2 = 1; + a11p2 = a11; #a11^p2 + + nstpw = nstp; # workspace for computing a11^nstp + while(nstpw > 0.5) + oddv = rem(nstpw,2); + if(oddv) + a11h = a11h*a11p2; + endif + nstpw = (nstpw-oddv)/2; + if(nstpw > 0.5) + a11p2 = a11p2*a11p2; # a11^(next power of 2) + endif + endwhile + + ## FIXME: this part should probably also use squaring, but + ## that would require exponentially growing memory. What do do? + for kk=2:nstp + ## update a12 block to sum(a12 + ... + a11^(kk-1)*a12) + a12w = a11*a12w; + a12b = a12b + a12w; + + ## similar for b1 block (checking for cuflg first!) + b1w = a11*b1w; + if(cuflg) + b1b = b1b + b1w; # update b1 block just like we did a12 + else + b1b = [b1b, b1w]; # append new inputs + newin = strappend(innamenz,["_d",num2str(kk-1)]); + inname = append(inname,newin); + endif + endfor + + ## reconstruct system and return + da(bki,bki) = a11h; + db(bki,1:columns(b1b)) = b1b; + if(!isempty(bki2)) + da(bki,bki2) = a12b; + endif + + da = da(pvi,pvi); + db = db(pvi,:); + stname = stname(pvi,:); + + ## construct new system and return + dsys = ss2sys(da,db,dc,dd,Ts2,0,nz,stname,inname,outname,find(yd == 1)); + +endfunction diff --git a/scripts/control/system/is_abcd.m b/scripts/control/system/is_abcd.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/is_abcd.m @@ -0,0 +1,97 @@ +## Copyright (C) 1997 Kai P. Mueller +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retval} =} is_abcd (@var{a}@{, @var{b}, @var{c}, @var{d}@}) +## Returns @var{retval} = 1 if the dimensions of @var{a}, @var{b}, +## @var{c}, @var{d} are compatible, otherwise @var{retval} = 0 with an +## appropriate diagnostic message printed to the screen. The matrices +## b, c, or d may be omitted. +## @end deftypefn +## @seealso{abcddim} + +## Author: Kai P. Mueller +## Created: November 4, 1997 +## based on is_controllable.m of Scottedward Hodel + +function retval = is_abcd (a, b, c, d) + + retval = 0; + switch (nargin) + case (1) + ## A only + [na, ma] = size(a); + if (na != ma) + disp("Matrix A ist not square.") + endif + case (2) + ## A, B only + [na, ma] = size(a); [nb, mb] = size(b); + if (na != ma) + disp("Matrix A ist not square.") + return; + endif + if (na != nb) + disp("A and B column dimension different.") + return; + endif + case (3) + ## A, B, C only + [na, ma] = size(a); [nb, mb] = size(b); [nc, mc] = size(c); + if (na != ma) + disp("Matrix A ist not square.") + return; + endif + if (na != nb) + disp("A and B column dimensions not compatible.") + return; + endif + if (ma != mc) + disp("A and C row dimensions not compatible.") + return; + endif + case (4) + ## all matrices A, B, C, D + [na, ma] = size(a); [nb, mb] = size(b); + [nc, mc] = size(c); [nd, md] = size(d); + if (na != ma) + disp("Matrix A ist not square.") + return; + endif + if (na != nb) + disp("A and B column dimensions not compatible.") + return; + endif + if (ma != mc) + disp("A and C row dimensions not compatible.") + return; + endif + if (mb != md) + disp("B and D row dimensions not compatible.") + return; + endif + if (nc != nd) + disp("C and D column dimensions not compatible.") + return; + endif + otherwise + usage("retval = is_abcd(a [, b, c, d])") + endswitch + ## all tests passed, signal ok. + retval = 1; +endfunction diff --git a/scripts/control/system/is_digital.m b/scripts/control/system/is_digital.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/is_digital.m @@ -0,0 +1,73 @@ +## Copyright (C) 1996, 1999 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retval} =} is_digital (@var{sys}) +## Return nonzero if system is digital; +## inputs: +## sys: system data structure +## eflg: 0 [default] exit with an error if system is mixed (continuous and +## discrete components) +## : 1 print a warning if system is mixed (continuous and discrete) +## : 2 silent operation +## outputs: +## DIGITAL: 0: system is purely continuous +## : 1: system is purely discrete +## : -1: system is mixed continuous and discrete +## Exits with an error of sys is a mixed (continuous and discrete) system +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 1996 + +function DIGITAL = is_digital (sys, eflg) + + switch(nargin) + case(1), eflg = 0; + case(2), + if( isempty(find(eflg == [0, 1, 2])) ) + error("invalid value of eflg=%d (%e)",eflg,eflg); + endif + otherwise, + usage("DIGITAL = is_digital(sys{,eflg})"); + endswitch + + ## checked for sampled data system (mixed) + ## discrete system + sysyd = sysgetsignals(sys,"yd"); + [nn,nz] = sysdimensions(sys); + cont = sum(sysyd == 0) + nn; + tsam = sysgettsam(sys); + dig = sum(sysyd != 0) + nz + tsam; + + ## check for mixed system + if( cont*dig != 0) + switch(eflg) + case(0), + error("continuous/discrete system; use syscont, sysdisc, or c2d first"); + case(1), + warning("is_digital: mixed continuous/discrete system"); + endswitch + dig_sign = -1; + else + dig_sign = 1; + endif + + DIGITAL = dig_sign*(tsam > 0); + +endfunction diff --git a/scripts/control/system/is_sample.m b/scripts/control/system/is_sample.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/is_sample.m @@ -0,0 +1,32 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retval} =} is_sample (@var{Ts}) +## return true if @var{Ts} is a valid sampling time +## (real,scalar, > 0) +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 1995 + +function out = is_sample (Ts) + + out = (is_scalar(Ts) && (Ts == abs(Ts)) && (Ts != 0) ); + +endfunction diff --git a/scripts/control/system/is_signal_list.m b/scripts/control/system/is_signal_list.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/is_signal_list.m @@ -0,0 +1,34 @@ +## Copyright (C) 1996, 1998, 2000 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +## function flg = is_signal_list (mylist) +## returns true if mylist is a list of individual strings. + +function flg = is_signal_list(mylist) + + flg = is_list(mylist); + + if (flg) + for ii = 1:length (mylist) + if (! (isstr (nth (mylist,ii)) & rows (nth (mylist,ii)) == 1)) + flg = 0; + endif + endfor + endif + +endfunction diff --git a/scripts/control/system/is_siso.m b/scripts/control/system/is_siso.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/is_siso.m @@ -0,0 +1,40 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retval} =} is_siso (@var{sys}) +## return nonzero if the system data structure +## @var{sys} is single-input, single-output. +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 1996, 1998 + +function SISO = is_siso (sys) + + if(nargin != 1) + usage("SISO = is_siso(sys)"); + elseif( !is_struct(sys)) + error("input must be a system structure (see ss2sys, tf2sys, zp2sys)"); + endif + + [n,nz,m,p] = sysdimensions(sys); + + SISO = (m == 1 & p == 1); + +endfunction diff --git a/scripts/control/system/listidx.m b/scripts/control/system/listidx.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/listidx.m @@ -0,0 +1,100 @@ +## Copyright (C) 2000 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## [idxvec, errmsg] = listidx(listvar, strlist) +## return indices of string entries in listvar that match strings in strlist +## Inputs: +## listvar: list of strings to be searched +## strlist: list of strings to be located in listvar. +## Note: listvar, strlist may be passed as strings or string matrices; +## in this case, each entry is processed by deblank() prior to searching +## for the entries of strlist in listvar. +## Outputs: +## idxvec +## vector of indices in listvar; +## listvar(idxvec(k)) == strlist(kk). +## errmsg +## if strlist contains a string not in listvar, then +## an error message is returned in errmsg. If only one output +## argument is requested, e.g., idxvec = listidx(listvar, strlist), +## then listidx prints errmsg to the screen and exits with +## an error. +## + +function [idxvec,errmsg] = listidx(listvar,strlist) + +if(nargin != 2) + usage("idxvec = listidx(listvar,strlist)"); +endif + +if(isstr(strlist)) + tmp = strlist; + strlist = list(); + for kk=1:rows(tmp) + strlist(kk) = deblank(tmp(kk,:)); + endfor +endif + +if(isstr(listvar)) + tmp = listvar; + listvar = list(); + for kk=1:rows(tmp) + listvar(kk) = deblank(tmp(kk,:)); + endfor +endif + +## initialize size of idxvec (for premature return) +idxvec = zeros(length(strlist),1); + +errmsg = ""; +if(!is_signal_list(listvar)) + errmsg = "listvar must be a list of strings"; +elseif(!is_signal_list(strlist)) + errmsg = "strlist must be a list of strings"; +endif + +if(length(errmsg)) + if(nargout < 2) error(errmsg); + else return; + endif +endif + +nsigs = length(listvar); +for idx = 1:length(strlist) + signame = nth(strlist,idx); + for jdx = 1:nsigs + if( strcmp(signame,nth(listvar,jdx)) ) + if(idxvec(idx) != 0) + warning("Duplicate signal name %s (%d,%d)\n", ... + nth(listvar,jdx),jdx,idxvec(idx)); + else + idxvec(idx) = jdx; + endif + endif + endfor + if(idxvec(idx) == 0) + errmsg = sprintf("Did not find %s",signame); + if(nargout == 1) + error(errmsg); + else + break + end + endif +endfor + +endfunction diff --git a/scripts/control/system/moddemo.m b/scripts/control/system/moddemo.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/moddemo.m @@ -0,0 +1,205 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outputs} =} moddemo (@var{inputs}) +## Octave Controls toolbox demo: Model Manipulations demo +## @end deftypefn + +## Author: David Clem +## Created: August 15, 1994 +## a s hodel: updated to reflect updated output order in ss2zp + +function moddemo () + + while (1) + clc + disp("Octave Model Manipulations Demo") + disp("=======================================") + disp(" 1) Perform continuous to discrete time conversion (c2d)") + disp(" 2) Convert from state space to zero / pole form (ss2zp)") + disp(" Convert from zero / pole to state space form (zp2ss)") + disp(" 3) Convert from state space to transfer function form (ss2tf)") + disp(" Convert from transfer function to state space form (tf2ss)") + disp(" 4) Convert from transfer function to zero / pole form (tf2zp)") + disp(" Convert from zero / pole to transfer function form (zp2tf)") + disp(" 5) Return to main demo menu") + disp(" ") + k=6; + while(k > 5 || k < 1) + k = input("Please enter a number:"); + endwhile + if (k == 1) + clc + disp("Perform continuous to discrete time conversion (c2d)\n") + disp("Example #1, Consider the following continuous time state space system:\n") + a=[0, 1; -25, -4] + b=[0; 1] + c=[1, 1] + d=1 + prompt + disp("\nTo convert this to a discrete time system (using a zero order hold),") + disp("use the following commands:\n") + cmd="sys=ss2sys(a,b,c,d);"; + run_cmd + cmd="dsys = c2d(sys,0.2);"; + run_cmd + cmd="sysout(dsys);"; + run_cmd + disp("Function check\n") + disp("Check the poles of sys vs dsys:\n") + cmd="[da,db]=sys2ss(dsys);"; + run_cmd + cmd="lam = eig(a);"; + run_cmd + disp("Discretize the continuous time eigenvalues using the matrix exponential:\n") + disp("lambc = exp(lam*0.2)\n") + lambc = exp(lam*0.2) + disp("Check the eigenvalues of da\n") + lambd = eig(da) + disp("Calculate the difference between lambd and lambc:\n") + cmd = "error = sort(lambd)-sort(lambc)\n"; + run_cmd + disp("The error is on the order of roundoff noise, so we're o.k.") + prompt + clc + elseif (k == 2) + clc + disp("Convert from state space to zero / pole form (ss2zp)\n") + disp("Example #1, Consider the following state space system:\n") + a=[0, 3, 1; -2, -4, 5; 5, 8, 2] + b=[0; 5; 2.5] + c=[6, -1.9, 2] + d=[-20] + prompt + disp(" ") + disp("\nTo find the poles and zeros of this sytstem, use the following command:\n") + disp("\n[zer, pol] = ss2zp(a, b, c, d)\n") + prompt + disp("Results:\n") + [zer, pol] = ss2zp(a, b, c, d) + disp("Variable Description:\n") + disp("zer, pol => zeros and poles of the state space system") + disp("a, b, c, d => state space system\n") + prompt + clc + disp("Convert from zero / pole to state space form (zp2ss)\n") + disp("Example #1, Consider the following set of zeros and poles:\n") + zer + pol + prompt + disp("\nTo find an equivalent state space representation for this set of poles") + disp("and zeros, use the following commands:\n") + k=1 + disp("\n[na, nb, nc, nd] = zp2ss(zer, pol, k)\n") + prompt + disp("Results:\n") + [na, nb, nc, nd] = zp2ss(zer, pol, k) + disp("Variable Description:\n") + disp("na, nb, nc, nd => state space system equivalent to zero / pole input") + disp("zer, pol => zeros and poles of desired state space system") + disp("k => gain associated with the zeros\n") + prompt + disp("Function check\n") + disp("Are the eigenvalues of the origonal state space system the same as the") + disp("eigenvalues of the newly constructed state space system ?\n") + disp("Find the difference between the two sets of eigenvalues") + disp("error = sort(eig(a)) - sort(eig(na))\n") + error = sort(eig(a)) - sort(eig(na)) + prompt + clc + elseif (k == 3) + clc + disp("Convert from state space to transfer function (ss2tf)\n") + disp("Example #1, Consider the following state space system:\n") + a=[0, 1; -2, -3] + b=[1; 1] + c=[1, 9] + d=[1] + prompt + disp("\nTo find an equivalent transfer function for this system, use") + disp("the following command:\n") + disp("[num, den] = ss2tf(a, b, c, d)\n") + prompt + disp("Results:\n") + [num,den] = ss2tf(a, b, c, d) + disp("Variable Description:\n") + disp("num, den => numerator and denominator of transfer function that is") + disp(" equivalent to the state space system") + disp("a, b, c, d => state space system\n") + prompt + clc + disp("Convert from transfer function to state space form (tf2ss)\n") + disp("Example #1, Consider the following transfer function:\n") + num + den + prompt + disp("\nTo find an equivalent state space representation for this system, use") + disp("the following command:\n") + disp("[a, b, c, d] = tf2ss(num, den)\n") + prompt + disp("Results:\n") + [a, b, c, d] = tf2ss(num, den) + disp("Variable Description:\n") + disp("a, b, c, d => state space system equivalent to transfer function input") + disp("num, den => numerator and denominator of transfer function that is equivalent") + disp(" to the state space system\n") + prompt + clc + elseif (k == 4) + clc + disp("Convert from transfer function to zero / pole form (tf2zp)\n") + disp("Example #1, Consider the following transfer function:\n") + num=[1, 2, 3, 4, 5, ] + den=[1, 2, 3, 4, 5, 6, 7] + prompt + disp("\nTo find the zeros and poles of this system, use the following command:\n") + disp("[zer,pol] = tf2zp(num,den)\n") + prompt + disp("Results:\n") + [zer,pol] = tf2zp(num,den) + disp("Variable Description:\n") + disp("zer,pol => zeros and poles of the transfer function") + disp("num, den => numerator and denominator of transfer function\n") + prompt + clc + disp("Convert from zero / pole to transfer function (zp2tf)\n") + disp("Example #1, Consider the following set of zeros and poles:\n") + zer + pol + prompt + disp("\nTo find an equivalent transfer function representation for this set") + disp("of poles and zeros, use the following commands:\n") + k=1 + disp("\n[num, den] = zp2tf(zer, pol, k)\n") + prompt + disp("Results:\n") + [num, den] = zp2tf(zer, pol, k) + disp("Variable Description:\n") + disp("[num, den] => transfer function representation of desired set of zeros") + disp(" and poles") + disp("a, b, c, d => state space system") + disp("zer, pol => zeros and poles of desired state space system") + disp("k => gain associated with the zeros\n") + prompt + clc + elseif (k == 5) + return + endif + endwhile +endfunction diff --git a/scripts/control/system/ord2.m b/scripts/control/system/ord2.m new file mode 100644 --- /dev/null +++ b/scripts/control/system/ord2.m @@ -0,0 +1,63 @@ +## Copyright (C) 1997 Kai P. Mueller +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outsys} =} ord2 (@var{nfreq}, @var{damp}@{[, @var{gain}@}) +## Creates a continuous 2nd order system with parameters: +## @strong{Inputs} +## @table @var +## @item nfreq: natural frequency [Hz]. (not in rad/s) +## @item damp: damping coefficient +## @item gain: dc-gain +## This is steady state value only for damp > 0. +## gain is assumed to be 1.0 if ommitted. +## @end table +## @strong{Outputs} +## @var{outsys} +## system data structure has representation with @math{w = 2 * pi * nfreq}: +## @example +## / \ +## | / -2w*damp -w \ / w \ | +## G = | | |, | |, [ 0 gain ], 0 | +## | \ w 0 / \ 0 / | +## \ / +## @end example +## @strong{See also} @code{jet707} (MIMO example, Boeing 707-321 +## aircraft model) +## @end deftypefn + +## Author: Kai P. Mueller +## Created: September 28, 1997 + +function outsys = ord2 (nfreq, damp, gain) + + ## Updates + + if(nargin != 2 & nargin != 3) + usage("outsys = ord2(nfreq, damp[, gain])") + endif + if (nargout > 1) + usage("outsys = ord2(nfreq, damp[, gain])") + endif + if (nargin == 2) + gain = 1.0; + endif + + w = 2.0 * pi * nfreq; + outsys = ss2sys([-2.0*w*damp, -w; w, 0], [w; 0], [0, gain]); +endfunction diff --git a/scripts/control/util/axis2dlim.m b/scripts/control/util/axis2dlim.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/axis2dlim.m @@ -0,0 +1,63 @@ +## Copyright (C) 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn{Function File} {@var{axvec} =} axis2dlim (@var{axdata}) +## determine axis limits for 2-d data(column vectors); leaves a 10% margin +## around the plots. +## puts in margins of +/- 0.1 if data is one dimensional (or a single point) +## +## @strong{Inputs} +## @var{axdata} nx2 matrix of data [x,y] +## +## @strong{Outputs} +## @var{axvec} vector of axis limits appropriate for call to axis() function +## @end deftypefn + +function axvec = axis2dlim (axdata) + + if(isempty(axdata)) + axdata = 0; + endif + + ## compute axis limits + minv = min(axdata); + maxv = max(axdata); + delv = (maxv-minv)/2; # breadth of the plot + midv = (minv + maxv)/2; # midpoint of the plot + axmid = [midv(1), midv(1), midv(2), midv(2)]; + axdel = [-0.1, 0.1,-0.1,0.1]; # default plot width (if less than 2-d data) + if(max(delv) == 0) + if(midv(1) != 0) + axdel(1:2) = [-0.1*midv(1),0.1*midv(1)]; + endif + if(midv(2) != 0) + axdel(3:4) = [-0.1*midv(2),0.1*midv(2)]; + endif + else + ## they're at least one-dimensional + if(delv(1) != 0) + axdel(1:2) = 1.1*[-delv(1),delv(1)]; + endif + if(delv(2) != 0) + axdel(3:4) = 1.1*[-delv(2),delv(2)]; + endif + endif + axvec = axmid + axdel; +endfunction + diff --git a/scripts/control/util/prompt.m b/scripts/control/util/prompt.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/prompt.m @@ -0,0 +1,46 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outputs} =} prompt (@var{inputs}) +## @format +## function prompt([str]) +## Prompt user to continue +## str: input string. Default value: "\n ---- Press a key to continue ---" +## @end format +## @end deftypefn + +## Author: David Clem +## Created: August 15, 1994 +## Modified A. S. Hodel June 1995 + +function prompt (str) + + if(nargin > 1) + usage("prompt([str])"); + elseif(nargin == 0) + str = "\n ---- Press a key to continue ---"; + elseif ( !isstr(str) ) + error("prompt: input must be a string"); + endif + + disp(str); + fflush(stdout); + kbhit; + +endfunction diff --git a/scripts/control/util/run_cmd.m b/scripts/control/util/run_cmd.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/run_cmd.m @@ -0,0 +1,30 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## run_cmd: short script used in demos +## prints string cmd to the screen, then executes after a pause + +disp(["Command: ",cmd]) +puts("Press a key to execute command"); +fflush(stdout); +kbhit(); +disp(" executing"); +fflush(stdout); +eval(cmd); +disp("---") +disp(" ") diff --git a/scripts/control/util/sortcom.m b/scripts/control/util/sortcom.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/sortcom.m @@ -0,0 +1,84 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outputs} =} sortcom (@var{inputs}) +## @format +## [yy,idx] = sortcom(xx[,opt]): sort a complex vector +## xx: complex vector +## opt: sorting option: +## "re": real part (default) +## "mag": by magnitude +## "im": by imaginary part +## +## if opt != "im" then complex conjugate pairs are grouped together, +## a - jb followed by a + jb. +## yy: sorted values +## idx: permutation vector: yy = xx(idx) +## @end format +## @end deftypefn + +## Author: A. S. Hodel +## Created: June 1995 + +function [yy, idx] = sortcom (xx, opt) + + if( nargin < 1 | nargin > 2 ) + usage("yy = sortcom(xx[,opt]"); + elseif( !(is_vector(xx) | isempty(xx) )) + error("sortcom: first argument must be a vector"); + endif + + if(nargin == 1) opt = "re"; + else + if (!isstr(opt)) + error("sortcom: second argument must be a string"); + endif + endif + + if(isempty(xx)) + yy = idx = []; + else + if(strcmp(opt,"re")) datavec = real(xx); + elseif(strcmp(opt,"im")) datavec = imag(xx); + elseif(strcmp(opt,"mag")) datavec = abs(xx); + else error(["sortcom: invalid option = ", opt]) + endif + + [datavec,idx] = sort(datavec); + yy= xx(idx); + + if(strcmp(opt,"re") | strcmp(opt,"mag")) + ## sort so that complex conjugate pairs appear together + + ddiff = diff(datavec); + zidx = find(ddiff == 0); + + ## sort common datavec values + if(!isempty(zidx)) + for iv=create_set(datavec(zidx)) + vidx = find(datavec == iv); + [vals,imidx] = sort(imag(yy(vidx))); + yy(vidx) = yy(vidx(imidx)); + idx(vidx) = idx(vidx(imidx)); + endfor + endif + endif + endif +endfunction + diff --git a/scripts/control/util/strappend.m b/scripts/control/util/strappend.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/strappend.m @@ -0,0 +1,39 @@ +## Copyright (C) 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## retval = strappend(strlist,suffix); +## append string suffix to each string in the list of strings strlist + +function retval = strappend (strlist, suffix); + + if(nargin != 2 | nargout > 1) + usage(" retval = strappend(strlist,suffix)"); + elseif(!is_signal_list(strlist)) + strlist + error("strlist must be a list of strings (see is_signal_list)"); + elseif(!(isstr(suffix) & rows(suffix) == 1)) + suffix + error("suffix must be a single string"); + endif + + retval = list(); + for ii=1:length(strlist) + retval(ii) = sprintf("%s%s",nth(strlist,ii),suffix); + endfor + +endfunction diff --git a/scripts/control/util/swap.m b/scripts/control/util/swap.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/swap.m @@ -0,0 +1,37 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{outputs} =} swap (@var{inputs}) +## @format +## [a1,b1] = swap(a,b) +## interchange a and b +## @end format +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 24, 1992 +## Conversion to Octave R. Bruce Tenison July 4, 1994 + +function [a1, b1] = swap (a, b) + + a1 = b; + b1 = a; + +endfunction + diff --git a/scripts/control/util/zgfmul.m b/scripts/control/util/zgfmul.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgfmul.m @@ -0,0 +1,81 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{y} =} zgfmul (@var{a}, @var{b}, @var{c}, @var{d}, @var{x}) +## +## Compute product of zgep incidence matrix @var{F} with vector @var{x}. +## Used by zgepbal (in zgscal) as part of generalized conjugate gradient +## iteration. +## @end deftypefn + +## References: +## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA +## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 + +## Author: A. S. Hodel +## Conversion to Octave July 3, 1994 + +function y = zgfmul (a, b, c, d, x) + + [n,m] = size(b); + [p,m1] = size(c); + nm = n+m; + y = zeros(nm+p,1); + + ## construct F column by column + for jj=1:n + Fj = zeros(nm+p,1); + + ## rows 1:n: F1 + aridx = complement(jj,find(a(jj,:) != 0)); + acidx = complement(jj,find(a(:,jj) != 0)); + bidx = find(b(jj,:) != 0); + cidx = find(c(:,jj) != 0); + + Fj(aridx) = Fj(aridx) - 1; # off diagonal entries of F1 + Fj(acidx) = Fj(acidx) - 1; + ## diagonal entry of F1 + Fj(jj) = length(aridx)+length(acidx) + length(bidx) + length(cidx); + + if(!isempty(bidx)) Fj(n+bidx) = 1; endif # B' incidence + if(!isempty(cidx)) Fj(n+m+cidx) = -1; endif # -C incidence + y = y + x(jj)*Fj; # multiply by corresponding entry of x + endfor + + for jj=1:m + Fj = zeros(nm+p,1); + bidx = find(b(:,jj) != 0); + if(!isempty(bidx)) Fj(bidx) = 1; endif # B incidence + didx = find(d(:,jj) != 0); + if(!isempty(didx)) Fj(n+m+didx) = 1; endif # D incidence + Fj(n+jj) = length(bidx) + length(didx); # F2 is diagonal + y = y + x(n+jj)*Fj; # multiply by corresponding entry of x + endfor + + for jj=1:p + Fj = zeros(nm+p,1); + cidx = find(c(jj,:) != 0); + if(!isempty(cidx)) Fj(cidx) = -1; endif # -C' incidence + didx = find(d(jj,:) != 0); + if(!isempty(didx)) Fj(n+didx) = 1; endif # D' incidence + Fj(n+m+jj) = length(cidx) + length(didx); # F2 is diagonal + y = y + x(n+m+jj)*Fj; # multiply by corresponding entry of x + endfor + +endfunction diff --git a/scripts/control/util/zgfslv.m b/scripts/control/util/zgfslv.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgfslv.m @@ -0,0 +1,67 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{x} =} zgfslv (@var{n}, @var{m}, @var{p}, @var{b}) +## Solve system of equations for dense zgep problem. +## @end deftypefn + +## Author: A. S. Hodel +## Converted to Octave by R Bruce Tenison, July 3, 1994 + +function x = zgfslv (n, m, p, b) + + nmp = n+m+p; + gam1 = (2*n)+m+p; gam2 = n+p; gam3 = n+m; + + G1 = givens(sqrt(m),-sqrt(p))'; + G2 = givens(m+p,sqrt(n*(m+p)))'; + + x = b; + + ## 1) U1 e^n = sqrt(n)e_1^n + ## 2) U2 e^m = sqrt(m)e_1^m + ## 3) U3 e^p = sqrt(p)e_1^p + xdx1 = 1:n; xdx2 = n+(1:m); xdx3 = n+m+(1:p); + x(xdx1,1) = zgshsr(x(xdx1,1)); + x(xdx2,1) = zgshsr(x(xdx2,1)); + x(xdx3,1) = zgshsr(x(xdx3,1)); + + ## 4) Givens rotations to reduce stray non-zero elements + idx1 = [n+1,n+m+1]; idx2 = [1,n+1]; + x(idx1) = G1'*x(idx1); + x(idx2) = G2'*x(idx2); + + ## 6) Scale x, then back-transform to get x + en = ones(n,1); em = ones(m,1); ep = ones(p,1); + lam = [gam1*en;gam2*em;gam3*ep]; + lam(1) = n+m+p; + lam(n+1) = 1; # dummy value to avoid divide by zero + lam(n+m+1)=n+m+p; + + x = x ./ lam; x(n+1) = 0; # minimum norm solution + + ## back transform now. + x(idx2) = G2*x(idx2); + x(idx1) = G1*x(idx1); + x(xdx3,1) = zgshsr(x(xdx3,1)); + x(xdx2,1) = zgshsr(x(xdx2,1)); + x(xdx1,1) = zgshsr(x(xdx1,1)); + +endfunction + diff --git a/scripts/control/util/zginit.m b/scripts/control/util/zginit.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zginit.m @@ -0,0 +1,90 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{zz} =} zginit (@var{a}, @var{b}, @var{c}, @var{d}) +## Construct right hand side vector zz +## for the zero-computation generalized eigenvalue problem +## balancing procedure. Called by zgepbal. +## @end deftypefn + +## References: +## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA +## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 + +## Author: A. S. Hodel +## Created: July 24, 1992 +## Conversion to Octave by R. Bruce Tenison, July 3, 1994 + +function zz = zginit (a, b, c, d) + + [nn,mm] = size(b); + [pp,mm] = size(d); + + nmp = nn+mm+pp; + + ## set up log vector zz + zz = zeros(nmp,1); + + ## zz part 1: + for i=1:nn + ## nonzero off diagonal entries of a + if(nn > 1) + nidx = complement(i,1:nn); + a_row_i = a(i,nidx); a_col_i = a(nidx,i); + arnz = a_row_i(find(a_row_i != 0)); acnz = a_col_i(find(a_col_i != 0)); + else + arnz = acnz = []; + endif + + ## row of b + bidx = find(b(i,:) != 0); + b_row_i = b(i,bidx); + + ## column of c + cidx = find(c(:,i) != 0); + c_col_i = c(cidx,i); + + ## sum the entries + zz(i) = sum(log(abs(acnz))) - sum(log(abs(arnz))) ... + - sum(log(abs(b_row_i))) + sum(log(abs(c_col_i))); + endfor + + ## zz part 2: + bd = [b;d]; + for i=1:mm + i1 = i+nn; + + ## column of [b;d] + bdidx = find(bd(:,i) != 0); + bd_col_i = bd(bdidx,i); + zz(i1) = sum(log(abs(bd_col_i))); + endfor + + ## zz part 3: + cd = [c, d]; + for i=1:pp + i1 = i+nn+mm; + cdidx = find(cd(i,:) != 0); + cd_row_i = cd(i,cdidx); + zz(i1) = -sum(log(abs(cd_row_i))); + endfor + + ## now set zz as log base 2 + zz = zz*(1/log(2)); +endfunction diff --git a/scripts/control/util/zgpbal.m b/scripts/control/util/zgpbal.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgpbal.m @@ -0,0 +1,109 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retsys} =} zgpbal (@var{Asys}) +## +## used internally in @code{tzero}; minimal argument checking performed +## +## implementation of zero computation generalized eigenvalue problem +## balancing method (Hodel and Tiller, Allerton Conference, 1991) +## Based on Ward's balancing algorithm (SIAM J. Sci Stat. Comput., 1981) +## +## zgpbal computes a state/input/output weighting that attempts to +## reduced the range of the magnitudes of the nonzero elements of [a,b,c,d] +## The weighting uses scalar multiplication by powers of 2, so no roundoff +## will occur. +## +## zgpbal should be followed by zgpred +## @end deftypefn + +## References: +## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA +## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 + +## Author: A. S. Hodel +## Created: July 24, 1992 +## Conversion to Octave by R. Bruce Tenison July 3, 1994 + +function retsys = zgpbal (Asys) + + if( (nargin != 1) | (!is_struct(Asys))) + usage("retsys = zgpbal(Asys)"); + endif + + Asys = sysupdate(Asys,"ss"); + [a,b,c,d] = sys2ss(Asys); + + [nn,mm,pp] = abcddim(a,b,c,d); + + np1 = nn+1; + nmp = nn+mm+pp; + + ## set up log vector zz, incidence matrix ff + zz = zginit(a,b,c,d); + + ## disp("zgpbal: zginit returns") + ## zz + ## disp("/zgpbal") + + if (norm(zz)) + ## generalized conjugate gradient approach + xx = zgscal(a,b,c,d,zz,nn,mm,pp); + + for i=1:nmp + xx(i) = floor(xx(i)+0.5); + xx(i) = 2.0^xx(i); + endfor + + ## now scale a + ## block 1: a = sigma a inv(sigma) + for i=1:nn + a(i,1:nn) = a(i,1:nn)*xx(i); + a(1:nn,i) = a(1:nn,i)/xx(i); + endfor + ## block 2: b= sigma a phi + for j=1:mm + j1 = j+nn; + b(1:nn,j) = b(1:nn,j)*xx(j1); + endfor + for i=1:nn + b(i,1:mm) = b(i,1:mm)*xx(i); + endfor + for i=1:pp + i1 = i+nn+mm; + ## block 3: c = psi C inv(sigma) + c(i,1:nn) = c(i,1:nn)*xx(i1); + endfor + for j=1:nn + c(1:pp,j) = c(1:pp,j)/xx(j); + endfor + ## block 4: d = psi D phi + for j=1:mm + j1 = j+nn; + d(1:pp,j) = d(1:pp,j)*xx(j1); + endfor + for i=1:pp + i1 = i + nn + mm; + d(i,1:mm) = d(i,1:mm)*xx(i1); + endfor + endif + + retsys = ss2sys(a,b,c,d); +endfunction + diff --git a/scripts/control/util/zgreduce.m b/scripts/control/util/zgreduce.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgreduce.m @@ -0,0 +1,142 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {retsys =} zgreduce (@var{Asys}, @var{meps}) +## Implementation of procedure REDUCE in (Emami-Naeini and Van Dooren, +## Automatica, # 1982). +## @end deftypefn + +function retsys = zgreduce (Asys, meps) + + ## SYS_INTERNAL accesses members of system data structure + + is_digital(Asys); # make sure it's pure digital/continuous + + exit_1 = 0; # exit_1 = 1 or 2 on exit of loop + + if(Asys.n + Asys.nz == 0) + exit_1 = 2; # there are no finite zeros + endif + + while (! exit_1) + [Q,R,Pi] = qr(Asys.d); # compress rows of D + Asys.d = Q'*Asys.d; + Asys.c = Q'*Asys.c; + + ## check row norms of Asys.d + [sig,tau] = zgrownorm(Asys.d,meps); + + ## disp("=======================================") + ## disp(["zgreduce: meps=",num2str(meps), ", sig=",num2str(sig), ... + ## ", tau=",num2str(tau)]) + ## sysout(Asys) + + if(tau == 0) + exit_1 = 1; # exit_1 - reduction complete and correct + else + Cb = Db = []; + if(sig) + Cb = Asys.c(1:sig,:); + Db = Asys.d(1:sig,:); + endif + Ct =Asys.c(sig+(1:tau),:); + + ## compress columns of Ct + [pp,nn] = size(Ct); + rvec = nn:-1:1; + [V,Sj,Pi] = qr(Ct'); + V = V(:,rvec); + [rho,gnu] = zgrownorm(Sj,meps); + + ## disp(["zgreduce: rho=",num2str(rho),", gnu=",num2str(gnu)]) + ## Cb + ## Db + ## Ct + ## Sj' + + if(rho == 0) + exit_1 = 1; # exit_1 - reduction complete and correct + elseif(gnu == 0) + exit_1 = 2; # there are no zeros at all + else + mu = rho + sig; + + ## update system with Q + M = [Asys.a , Asys.b ]; + [nn,mm] = size(Asys.b); + + pp = rows(Asys.d); + Vm =[V,zeros(nn,mm) ; zeros(mm,nn), eye(mm)]; + if(sig) + M = [M; Cb, Db]; + Vs =[V',zeros(nn,sig) ; zeros(sig,nn), eye(sig)]; + else + Vs = V'; + endif + ## disp("zgreduce: before transform: M="); + ## M + ## Vs + ## Vm + + M = Vs*M*Vm; + + ## disp("zgreduce: after transform: M="); + ## M + + ## disp("debugging code:") + ## Mtmp = [Asys.a Asys.b; Asys.c Asys.d] + ## Vl = [V', zeros(nn,mm); zeros(mm,nn),Q] + ## Vr =[V,zeros(nn,mm) ; zeros(mm,nn), eye(mm)]; + ## Mtmpf = Vl*Mtmp*Vr + + idx = 1:gnu; + jdx = nn + (1:mm); + sdx = gnu + (1:mu); + + Asys.a = M(idx,idx); + Asys.b = M(idx,jdx); + Asys.c = M(sdx,idx); + Asys.d = M(sdx,jdx); + + ## disp(["zgreduce: resulting system: nn =",num2str(nn)," mu=",num2str(mu)]) + ## sysout(Asys) + ## idx + ## jdx + ## sdx + endif + endif + endwhile + + ## disp(["zgreduce: while loop done: exit_1=",num2str(exit_1)]); + + if(exit_1 == 2) + ## there are no zeros at all! + Asys.a = Asys.b = Asys.c = []; + endif + + ## update dimensions + if(is_digital(Asys)) + Asys.nz = rows(Asys.a); + else + Asys.n = rows(Asys.a); + endif + + retsys = Asys; + +endfunction diff --git a/scripts/control/util/zgrownorm.m b/scripts/control/util/zgrownorm.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgrownorm.m @@ -0,0 +1,36 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{nonz}, @var{zer}] =} zgrownorm (@var{mat}, @var{meps}) +## Return @var{nonz} = number of rows of @var{mat} whose two norm +## exceeds @var{meps}, and @var{zer} = number of rows of mat whose two +## norm is less than @var{meps}. +## @end deftypefn + +function [sig, tau] = zgrownorm (mat, meps) + + rownorm = []; + for ii=1:rows(mat) + rownorm(ii) = norm(mat(ii,:)); + endfor + sig = sum(rownorm > meps); + tau = sum(rownorm <= meps); + +endfunction + diff --git a/scripts/control/util/zgscal.m b/scripts/control/util/zgscal.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgscal.m @@ -0,0 +1,145 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{x} =} zgscal (@var{f}, @var{z}, @var{n}, @var{m}, @var{p}) +## Generalized conjugate gradient iteration to +## solve zero-computation generalized eigenvalue problem balancing equation +## @math{fx=z}; +## called by @code{zgepbal} +## @end deftypefn + +## References: +## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA +## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 + +## Author: A. S. Hodel +## Created: July 24, 1992 +## Conversion to Octave R. Bruce Tenison July 3, 1994 + +function x = zgscal (a, b, c, d, z, n, m, p) + + ## initialize parameters: + ## Givens rotations, diagonalized 2x2 block of F, gcg vector initialization + + nmp = n+m+p; + + ## x_0 = x_{-1} = 0, r_0 = z + x = zeros(nmp,1); + xk1 = x; + xk2 = x; + rk1 = z; + k = 0; + + ## construct balancing least squares problem + F = eye(nmp); + for kk=1:nmp + F(1:nmp,kk) = zgfmul(a,b,c,d,F(:,kk)); + endfor + + [U,H,k1] = krylov(F,z,nmp,1e-12,1); + if(!is_square(H)) + if(columns(H) != k1) + error("zgscal(tzero): k1=%d, columns(H)=%d",k1,columns(H)); + elseif(rows(H) != k1+1) + error("zgscal: k1=%d, rows(H) = %d",k1,rows(H)); + elseif ( norm(H(k1+1,:)) > 1e-12*norm(H,"inf") ) + zgscal_last_row_of_H = H(k1+1,:) + error("zgscal: last row of H nonzero (norm(H)=%e)",norm(H,"inf")) + endif + H = H(1:k1,1:k1); + U = U(:,1:k1); + endif + + ## tridiagonal H can still be rank deficient, so do permuted qr + ## factorization + [qq,rr,pp] = qr(H); # H = qq*rr*pp' + nn = rank(rr); + qq = qq(:,1:nn); + rr = rr(1:nn,:); # rr may not be square, but "\" does least + xx = U*pp*(rr\qq'*(U'*z)); # squares solution, so this works + ## xx1 = pinv(F)*z; + ## zgscal_x_xx1_err = [xx,xx1,xx-xx1] + return; + + ## the rest of this is left from the original zgscal; + ## I've had some numerical problems with the GCG algorithm, + ## so for now I'm solving it with the krylov routine. + + ## initialize residual error norm + rnorm = norm(rk1,1); + + xnorm = 0; + fnorm = 1e-12 * norm([a,b;c,d],1); + + ## dummy defines for MATHTOOLS compiler + gamk2 = 0; omega1 = 0; ztmz2 = 0; + + ## do until small changes to x + len_x = length(x); + while ((k < 2*len_x) & (xnorm> 0.5) & (rnorm>fnorm))|(k == 0) + k = k+1; + + ## solve F_d z_{k-1} = r_{k-1} + zk1= zgfslv(n,m,p,rk1); + + ## Generalized CG iteration + ## gamk1 = (zk1'*F_d*zk1)/(zk1'*F*zk1); + ztMz1 = zk1'*rk1; + gamk1 = ztMz1/(zk1'*zgfmul(a,b,c,d,zk1)); + + if(rem(k,len_x) == 1) omega = 1; + else omega = 1/(1-gamk1*ztMz1/(gamk2*omega1*ztmz2)); + endif + + ## store x in xk2 to save space + xk2 = xk2 + omega*(gamk1*zk1 + xk1 - xk2); + + ## compute new residual error: rk = z - F xk, check end conditions + rk1 = z - zgfmul(a,b,c,d,xk2); + rnorm = norm(rk1); + xnorm = max(abs(xk1 - xk2)); + + ## printf("zgscal: k=%d, gamk1=%e, gamk2=%e, \nztMz1=%e ztmz2=%e\n", ... + ## k,gamk1, gamk2, ztMz1, ztmz2); + ## xk2_1_zk1 = [xk2 xk1 zk1] + ## ABCD = [a,b;c,d] + ## prompt + + ## get ready for next iteration + gamk2 = gamk1; + omega1 = omega; + ztmz2 = ztMz1; + [xk1,xk2] = swap(xk1,xk2); + endwhile + x = xk2; + + ## check convergence + if (xnorm> 0.5 & rnorm>fnorm) + warning("zgscal(tzero): GCG iteration failed; solving with pinv"); + + ## perform brute force least squares; construct F + Am = eye(nmp); + for ii=1:nmp + Am(:,ii) = zgfmul(a,b,c,d,Am(:,ii)); + endfor + + ## now solve with qr factorization + x = pinv(Am)*z; + endif +endfunction diff --git a/scripts/control/util/zgsgiv.m b/scripts/control/util/zgsgiv.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgsgiv.m @@ -0,0 +1,36 @@ +## Copyright (C) 1996, 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {[a, b] =} zgsgiv (@var{c}, @var{s}, @var{a}, @var{b}) +## apply givens rotation c,s to row vectors @var{a},@var{b} +## No longer used in zero-balancing (zgpbal); kept for backward compatibility. +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 29, 1992 +## Convertion to Octave by R. Bruce Tenison July 3, 1994 + +function [a, b] = zgsgiv (c, s, a, b) + + t1 = c*a + s*b; + t2 = -s*a + c*b; + a = t1; + b = t2; + +endfunction diff --git a/scripts/control/util/zgshsr.m b/scripts/control/util/zgshsr.m new file mode 100644 --- /dev/null +++ b/scripts/control/util/zgshsr.m @@ -0,0 +1,45 @@ +## Copyright (C) 1996 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{x} =} zgshsr (@var{y}) +## apply householder vector based on @math{e^(m)} to +## (column vector) y. +## Called by zgfslv +## @end deftypefn + +## Author: A. S. Hodel +## Created: July 24, 1992 +## Conversion to Octave by R. Bruce Tenison July 3, 1994 + +function x = zgshsr (y) + + if(!is_vector(y)) + error(sprintf("y(%dx%d) must be a vector",rows(y),columns(y))); + endif + x = vec(y); + m = length(x); + if (m>1) + beta = (1 + sqrt(m))*x(1) + sum(x(2:m)); + beta = beta/(m+sqrt(m)); + x(1) = x(1) - beta*(1.0d0+sqrt(m)); + x(2:m) = x(2:m) - beta*ones(m-1,1); + else + x = -x; + endif +endfunction diff --git a/scripts/control/zgfmul.m b/scripts/control/zgfmul.m deleted file mode 100644 --- a/scripts/control/zgfmul.m +++ /dev/null @@ -1,81 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{y} =} zgfmul (@var{a}, @var{b}, @var{c}, @var{d}, @var{x}) -## -## Compute product of zgep incidence matrix @var{F} with vector @var{x}. -## Used by zgepbal (in zgscal) as part of generalized conjugate gradient -## iteration. -## @end deftypefn - -## References: -## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA -## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 - -## Author: A. S. Hodel -## Conversion to Octave July 3, 1994 - -function y = zgfmul (a, b, c, d, x) - - [n,m] = size(b); - [p,m1] = size(c); - nm = n+m; - y = zeros(nm+p,1); - - ## construct F column by column - for jj=1:n - Fj = zeros(nm+p,1); - - ## rows 1:n: F1 - aridx = complement(jj,find(a(jj,:) != 0)); - acidx = complement(jj,find(a(:,jj) != 0)); - bidx = find(b(jj,:) != 0); - cidx = find(c(:,jj) != 0); - - Fj(aridx) = Fj(aridx) - 1; # off diagonal entries of F1 - Fj(acidx) = Fj(acidx) - 1; - ## diagonal entry of F1 - Fj(jj) = length(aridx)+length(acidx) + length(bidx) + length(cidx); - - if(!isempty(bidx)) Fj(n+bidx) = 1; endif # B' incidence - if(!isempty(cidx)) Fj(n+m+cidx) = -1; endif # -C incidence - y = y + x(jj)*Fj; # multiply by corresponding entry of x - endfor - - for jj=1:m - Fj = zeros(nm+p,1); - bidx = find(b(:,jj) != 0); - if(!isempty(bidx)) Fj(bidx) = 1; endif # B incidence - didx = find(d(:,jj) != 0); - if(!isempty(didx)) Fj(n+m+didx) = 1; endif # D incidence - Fj(n+jj) = length(bidx) + length(didx); # F2 is diagonal - y = y + x(n+jj)*Fj; # multiply by corresponding entry of x - endfor - - for jj=1:p - Fj = zeros(nm+p,1); - cidx = find(c(jj,:) != 0); - if(!isempty(cidx)) Fj(cidx) = -1; endif # -C' incidence - didx = find(d(jj,:) != 0); - if(!isempty(didx)) Fj(n+didx) = 1; endif # D' incidence - Fj(n+m+jj) = length(cidx) + length(didx); # F2 is diagonal - y = y + x(n+m+jj)*Fj; # multiply by corresponding entry of x - endfor - -endfunction diff --git a/scripts/control/zgfslv.m b/scripts/control/zgfslv.m deleted file mode 100644 --- a/scripts/control/zgfslv.m +++ /dev/null @@ -1,67 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{x} =} zgfslv (@var{n}, @var{m}, @var{p}, @var{b}) -## Solve system of equations for dense zgep problem. -## @end deftypefn - -## Author: A. S. Hodel -## Converted to Octave by R Bruce Tenison, July 3, 1994 - -function x = zgfslv (n, m, p, b) - - nmp = n+m+p; - gam1 = (2*n)+m+p; gam2 = n+p; gam3 = n+m; - - G1 = givens(sqrt(m),-sqrt(p))'; - G2 = givens(m+p,sqrt(n*(m+p)))'; - - x = b; - - ## 1) U1 e^n = sqrt(n)e_1^n - ## 2) U2 e^m = sqrt(m)e_1^m - ## 3) U3 e^p = sqrt(p)e_1^p - xdx1 = 1:n; xdx2 = n+(1:m); xdx3 = n+m+(1:p); - x(xdx1,1) = zgshsr(x(xdx1,1)); - x(xdx2,1) = zgshsr(x(xdx2,1)); - x(xdx3,1) = zgshsr(x(xdx3,1)); - - ## 4) Givens rotations to reduce stray non-zero elements - idx1 = [n+1,n+m+1]; idx2 = [1,n+1]; - x(idx1) = G1'*x(idx1); - x(idx2) = G2'*x(idx2); - - ## 6) Scale x, then back-transform to get x - en = ones(n,1); em = ones(m,1); ep = ones(p,1); - lam = [gam1*en;gam2*em;gam3*ep]; - lam(1) = n+m+p; - lam(n+1) = 1; # dummy value to avoid divide by zero - lam(n+m+1)=n+m+p; - - x = x ./ lam; x(n+1) = 0; # minimum norm solution - - ## back transform now. - x(idx2) = G2*x(idx2); - x(idx1) = G1*x(idx1); - x(xdx3,1) = zgshsr(x(xdx3,1)); - x(xdx2,1) = zgshsr(x(xdx2,1)); - x(xdx1,1) = zgshsr(x(xdx1,1)); - -endfunction - diff --git a/scripts/control/zginit.m b/scripts/control/zginit.m deleted file mode 100644 --- a/scripts/control/zginit.m +++ /dev/null @@ -1,90 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{zz} =} zginit (@var{a}, @var{b}, @var{c}, @var{d}) -## Construct right hand side vector zz -## for the zero-computation generalized eigenvalue problem -## balancing procedure. Called by zgepbal. -## @end deftypefn - -## References: -## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA -## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 - -## Author: A. S. Hodel -## Created: July 24, 1992 -## Conversion to Octave by R. Bruce Tenison, July 3, 1994 - -function zz = zginit (a, b, c, d) - - [nn,mm] = size(b); - [pp,mm] = size(d); - - nmp = nn+mm+pp; - - ## set up log vector zz - zz = zeros(nmp,1); - - ## zz part 1: - for i=1:nn - ## nonzero off diagonal entries of a - if(nn > 1) - nidx = complement(i,1:nn); - a_row_i = a(i,nidx); a_col_i = a(nidx,i); - arnz = a_row_i(find(a_row_i != 0)); acnz = a_col_i(find(a_col_i != 0)); - else - arnz = acnz = []; - endif - - ## row of b - bidx = find(b(i,:) != 0); - b_row_i = b(i,bidx); - - ## column of c - cidx = find(c(:,i) != 0); - c_col_i = c(cidx,i); - - ## sum the entries - zz(i) = sum(log(abs(acnz))) - sum(log(abs(arnz))) ... - - sum(log(abs(b_row_i))) + sum(log(abs(c_col_i))); - endfor - - ## zz part 2: - bd = [b;d]; - for i=1:mm - i1 = i+nn; - - ## column of [b;d] - bdidx = find(bd(:,i) != 0); - bd_col_i = bd(bdidx,i); - zz(i1) = sum(log(abs(bd_col_i))); - endfor - - ## zz part 3: - cd = [c, d]; - for i=1:pp - i1 = i+nn+mm; - cdidx = find(cd(i,:) != 0); - cd_row_i = cd(i,cdidx); - zz(i1) = -sum(log(abs(cd_row_i))); - endfor - - ## now set zz as log base 2 - zz = zz*(1/log(2)); -endfunction diff --git a/scripts/control/zgpbal.m b/scripts/control/zgpbal.m deleted file mode 100644 --- a/scripts/control/zgpbal.m +++ /dev/null @@ -1,109 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{retsys} =} zgpbal (@var{Asys}) -## -## used internally in @code{tzero}; minimal argument checking performed -## -## implementation of zero computation generalized eigenvalue problem -## balancing method (Hodel and Tiller, Allerton Conference, 1991) -## Based on Ward's balancing algorithm (SIAM J. Sci Stat. Comput., 1981) -## -## zgpbal computes a state/input/output weighting that attempts to -## reduced the range of the magnitudes of the nonzero elements of [a,b,c,d] -## The weighting uses scalar multiplication by powers of 2, so no roundoff -## will occur. -## -## zgpbal should be followed by zgpred -## @end deftypefn - -## References: -## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA -## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 - -## Author: A. S. Hodel -## Created: July 24, 1992 -## Conversion to Octave by R. Bruce Tenison July 3, 1994 - -function retsys = zgpbal (Asys) - - if( (nargin != 1) | (!is_struct(Asys))) - usage("retsys = zgpbal(Asys)"); - endif - - Asys = sysupdate(Asys,"ss"); - [a,b,c,d] = sys2ss(Asys); - - [nn,mm,pp] = abcddim(a,b,c,d); - - np1 = nn+1; - nmp = nn+mm+pp; - - ## set up log vector zz, incidence matrix ff - zz = zginit(a,b,c,d); - - ## disp("zgpbal: zginit returns") - ## zz - ## disp("/zgpbal") - - if (norm(zz)) - ## generalized conjugate gradient approach - xx = zgscal(a,b,c,d,zz,nn,mm,pp); - - for i=1:nmp - xx(i) = floor(xx(i)+0.5); - xx(i) = 2.0^xx(i); - endfor - - ## now scale a - ## block 1: a = sigma a inv(sigma) - for i=1:nn - a(i,1:nn) = a(i,1:nn)*xx(i); - a(1:nn,i) = a(1:nn,i)/xx(i); - endfor - ## block 2: b= sigma a phi - for j=1:mm - j1 = j+nn; - b(1:nn,j) = b(1:nn,j)*xx(j1); - endfor - for i=1:nn - b(i,1:mm) = b(i,1:mm)*xx(i); - endfor - for i=1:pp - i1 = i+nn+mm; - ## block 3: c = psi C inv(sigma) - c(i,1:nn) = c(i,1:nn)*xx(i1); - endfor - for j=1:nn - c(1:pp,j) = c(1:pp,j)/xx(j); - endfor - ## block 4: d = psi D phi - for j=1:mm - j1 = j+nn; - d(1:pp,j) = d(1:pp,j)*xx(j1); - endfor - for i=1:pp - i1 = i + nn + mm; - d(i,1:mm) = d(i,1:mm)*xx(i1); - endfor - endif - - retsys = ss2sys(a,b,c,d); -endfunction - diff --git a/scripts/control/zgreduce.m b/scripts/control/zgreduce.m deleted file mode 100644 --- a/scripts/control/zgreduce.m +++ /dev/null @@ -1,142 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {retsys =} zgreduce (@var{Asys}, @var{meps}) -## Implementation of procedure REDUCE in (Emami-Naeini and Van Dooren, -## Automatica, # 1982). -## @end deftypefn - -function retsys = zgreduce (Asys, meps) - - ## SYS_INTERNAL accesses members of system data structure - - is_digital(Asys); # make sure it's pure digital/continuous - - exit_1 = 0; # exit_1 = 1 or 2 on exit of loop - - if(Asys.n + Asys.nz == 0) - exit_1 = 2; # there are no finite zeros - endif - - while (! exit_1) - [Q,R,Pi] = qr(Asys.d); # compress rows of D - Asys.d = Q'*Asys.d; - Asys.c = Q'*Asys.c; - - ## check row norms of Asys.d - [sig,tau] = zgrownorm(Asys.d,meps); - - ## disp("=======================================") - ## disp(["zgreduce: meps=",num2str(meps), ", sig=",num2str(sig), ... - ## ", tau=",num2str(tau)]) - ## sysout(Asys) - - if(tau == 0) - exit_1 = 1; # exit_1 - reduction complete and correct - else - Cb = Db = []; - if(sig) - Cb = Asys.c(1:sig,:); - Db = Asys.d(1:sig,:); - endif - Ct =Asys.c(sig+(1:tau),:); - - ## compress columns of Ct - [pp,nn] = size(Ct); - rvec = nn:-1:1; - [V,Sj,Pi] = qr(Ct'); - V = V(:,rvec); - [rho,gnu] = zgrownorm(Sj,meps); - - ## disp(["zgreduce: rho=",num2str(rho),", gnu=",num2str(gnu)]) - ## Cb - ## Db - ## Ct - ## Sj' - - if(rho == 0) - exit_1 = 1; # exit_1 - reduction complete and correct - elseif(gnu == 0) - exit_1 = 2; # there are no zeros at all - else - mu = rho + sig; - - ## update system with Q - M = [Asys.a , Asys.b ]; - [nn,mm] = size(Asys.b); - - pp = rows(Asys.d); - Vm =[V,zeros(nn,mm) ; zeros(mm,nn), eye(mm)]; - if(sig) - M = [M; Cb, Db]; - Vs =[V',zeros(nn,sig) ; zeros(sig,nn), eye(sig)]; - else - Vs = V'; - endif - ## disp("zgreduce: before transform: M="); - ## M - ## Vs - ## Vm - - M = Vs*M*Vm; - - ## disp("zgreduce: after transform: M="); - ## M - - ## disp("debugging code:") - ## Mtmp = [Asys.a Asys.b; Asys.c Asys.d] - ## Vl = [V', zeros(nn,mm); zeros(mm,nn),Q] - ## Vr =[V,zeros(nn,mm) ; zeros(mm,nn), eye(mm)]; - ## Mtmpf = Vl*Mtmp*Vr - - idx = 1:gnu; - jdx = nn + (1:mm); - sdx = gnu + (1:mu); - - Asys.a = M(idx,idx); - Asys.b = M(idx,jdx); - Asys.c = M(sdx,idx); - Asys.d = M(sdx,jdx); - - ## disp(["zgreduce: resulting system: nn =",num2str(nn)," mu=",num2str(mu)]) - ## sysout(Asys) - ## idx - ## jdx - ## sdx - endif - endif - endwhile - - ## disp(["zgreduce: while loop done: exit_1=",num2str(exit_1)]); - - if(exit_1 == 2) - ## there are no zeros at all! - Asys.a = Asys.b = Asys.c = []; - endif - - ## update dimensions - if(is_digital(Asys)) - Asys.nz = rows(Asys.a); - else - Asys.n = rows(Asys.a); - endif - - retsys = Asys; - -endfunction diff --git a/scripts/control/zgrownorm.m b/scripts/control/zgrownorm.m deleted file mode 100644 --- a/scripts/control/zgrownorm.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{nonz}, @var{zer}] =} zgrownorm (@var{mat}, @var{meps}) -## Return @var{nonz} = number of rows of @var{mat} whose two norm -## exceeds @var{meps}, and @var{zer} = number of rows of mat whose two -## norm is less than @var{meps}. -## @end deftypefn - -function [sig, tau] = zgrownorm (mat, meps) - - rownorm = []; - for ii=1:rows(mat) - rownorm(ii) = norm(mat(ii,:)); - endfor - sig = sum(rownorm > meps); - tau = sum(rownorm <= meps); - -endfunction - diff --git a/scripts/control/zgscal.m b/scripts/control/zgscal.m deleted file mode 100644 --- a/scripts/control/zgscal.m +++ /dev/null @@ -1,145 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{x} =} zgscal (@var{f}, @var{z}, @var{n}, @var{m}, @var{p}) -## Generalized conjugate gradient iteration to -## solve zero-computation generalized eigenvalue problem balancing equation -## @math{fx=z}; -## called by @code{zgepbal} -## @end deftypefn - -## References: -## ZGEP: Hodel, "Computation of Zeros with Balancing," 1992, submitted to LAA -## Generalized CG: Golub and Van Loan, "Matrix Computations, 2nd ed" 1989 - -## Author: A. S. Hodel -## Created: July 24, 1992 -## Conversion to Octave R. Bruce Tenison July 3, 1994 - -function x = zgscal (a, b, c, d, z, n, m, p) - - ## initialize parameters: - ## Givens rotations, diagonalized 2x2 block of F, gcg vector initialization - - nmp = n+m+p; - - ## x_0 = x_{-1} = 0, r_0 = z - x = zeros(nmp,1); - xk1 = x; - xk2 = x; - rk1 = z; - k = 0; - - ## construct balancing least squares problem - F = eye(nmp); - for kk=1:nmp - F(1:nmp,kk) = zgfmul(a,b,c,d,F(:,kk)); - endfor - - [U,H,k1] = krylov(F,z,nmp,1e-12,1); - if(!is_square(H)) - if(columns(H) != k1) - error("zgscal(tzero): k1=%d, columns(H)=%d",k1,columns(H)); - elseif(rows(H) != k1+1) - error("zgscal: k1=%d, rows(H) = %d",k1,rows(H)); - elseif ( norm(H(k1+1,:)) > 1e-12*norm(H,"inf") ) - zgscal_last_row_of_H = H(k1+1,:) - error("zgscal: last row of H nonzero (norm(H)=%e)",norm(H,"inf")) - endif - H = H(1:k1,1:k1); - U = U(:,1:k1); - endif - - ## tridiagonal H can still be rank deficient, so do permuted qr - ## factorization - [qq,rr,pp] = qr(H); # H = qq*rr*pp' - nn = rank(rr); - qq = qq(:,1:nn); - rr = rr(1:nn,:); # rr may not be square, but "\" does least - xx = U*pp*(rr\qq'*(U'*z)); # squares solution, so this works - ## xx1 = pinv(F)*z; - ## zgscal_x_xx1_err = [xx,xx1,xx-xx1] - return; - - ## the rest of this is left from the original zgscal; - ## I've had some numerical problems with the GCG algorithm, - ## so for now I'm solving it with the krylov routine. - - ## initialize residual error norm - rnorm = norm(rk1,1); - - xnorm = 0; - fnorm = 1e-12 * norm([a,b;c,d],1); - - ## dummy defines for MATHTOOLS compiler - gamk2 = 0; omega1 = 0; ztmz2 = 0; - - ## do until small changes to x - len_x = length(x); - while ((k < 2*len_x) & (xnorm> 0.5) & (rnorm>fnorm))|(k == 0) - k = k+1; - - ## solve F_d z_{k-1} = r_{k-1} - zk1= zgfslv(n,m,p,rk1); - - ## Generalized CG iteration - ## gamk1 = (zk1'*F_d*zk1)/(zk1'*F*zk1); - ztMz1 = zk1'*rk1; - gamk1 = ztMz1/(zk1'*zgfmul(a,b,c,d,zk1)); - - if(rem(k,len_x) == 1) omega = 1; - else omega = 1/(1-gamk1*ztMz1/(gamk2*omega1*ztmz2)); - endif - - ## store x in xk2 to save space - xk2 = xk2 + omega*(gamk1*zk1 + xk1 - xk2); - - ## compute new residual error: rk = z - F xk, check end conditions - rk1 = z - zgfmul(a,b,c,d,xk2); - rnorm = norm(rk1); - xnorm = max(abs(xk1 - xk2)); - - ## printf("zgscal: k=%d, gamk1=%e, gamk2=%e, \nztMz1=%e ztmz2=%e\n", ... - ## k,gamk1, gamk2, ztMz1, ztmz2); - ## xk2_1_zk1 = [xk2 xk1 zk1] - ## ABCD = [a,b;c,d] - ## prompt - - ## get ready for next iteration - gamk2 = gamk1; - omega1 = omega; - ztmz2 = ztMz1; - [xk1,xk2] = swap(xk1,xk2); - endwhile - x = xk2; - - ## check convergence - if (xnorm> 0.5 & rnorm>fnorm) - warning("zgscal(tzero): GCG iteration failed; solving with pinv"); - - ## perform brute force least squares; construct F - Am = eye(nmp); - for ii=1:nmp - Am(:,ii) = zgfmul(a,b,c,d,Am(:,ii)); - endfor - - ## now solve with qr factorization - x = pinv(Am)*z; - endif -endfunction diff --git a/scripts/control/zgsgiv.m b/scripts/control/zgsgiv.m deleted file mode 100644 --- a/scripts/control/zgsgiv.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 1996, 1998 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {[a, b] =} zgsgiv (@var{c}, @var{s}, @var{a}, @var{b}) -## apply givens rotation c,s to row vectors @var{a},@var{b} -## No longer used in zero-balancing (zgpbal); kept for backward compatibility. -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 29, 1992 -## Convertion to Octave by R. Bruce Tenison July 3, 1994 - -function [a, b] = zgsgiv (c, s, a, b) - - t1 = c*a + s*b; - t2 = -s*a + c*b; - a = t1; - b = t2; - -endfunction diff --git a/scripts/control/zgshsr.m b/scripts/control/zgshsr.m deleted file mode 100644 --- a/scripts/control/zgshsr.m +++ /dev/null @@ -1,45 +0,0 @@ -## Copyright (C) 1996 Auburn University. All rights reserved. -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## Octave is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, write to the Free -## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{x} =} zgshsr (@var{y}) -## apply householder vector based on @math{e^(m)} to -## (column vector) y. -## Called by zgfslv -## @end deftypefn - -## Author: A. S. Hodel -## Created: July 24, 1992 -## Conversion to Octave by R. Bruce Tenison July 3, 1994 - -function x = zgshsr (y) - - if(!is_vector(y)) - error(sprintf("y(%dx%d) must be a vector",rows(y),columns(y))); - endif - x = vec(y); - m = length(x); - if (m>1) - beta = (1 + sqrt(m))*x(1) + sum(x(2:m)); - beta = beta/(m+sqrt(m)); - x(1) = x(1) - beta*(1.0d0+sqrt(m)); - x(2:m) = x(2:m) - beta*ones(m-1,1); - else - x = -x; - endif -endfunction diff --git a/scripts/strings/com2str.m b/scripts/strings/com2str.m new file mode 100644 --- /dev/null +++ b/scripts/strings/com2str.m @@ -0,0 +1,82 @@ +## Copyright (C) 1998 Auburn University. All rights reserved. +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## Octave is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, write to the Free +## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{retval} =} com2str(@var{zz}[,@var{flg}]) +## +## convert complex number to a string +## @strong{Inputs} +## @table @var +## @item zz +## complex number +## @item flg +## format flag +## 0 (default): -1, 0, 1, 1i, 1 + 0.5i +## 1 (for use with zpout): -1, 0, + 1, + 1i, + 1 + 0.5i +## @end table +## @end deftypefn + +function retval = com2str (zz, flg) + + if (nargin < 1 | nargin > 2) + usage("com2str(zz{,flg})"); + endif + if(nargin == 1) + flg = 0; + endif + + if( !(is_scalar(zz) & is_scalar(flg) ) ) + error("com2str: arguments must be a scalar."); + endif + + if(flg != 0 & flg != 1) + error(["invalid flg value: ",num2str(flg)]); + endif + + sgns = "+-"; + rz = real(zz); + iz = imag(zz); + az = abs(zz); + if(iz == 0) + ## strictly a real number + switch(flg) + case(0) + retval = num2str(rz); + case(1) + retval = [ sgns(1+(rz< 0))," ", num2str(abs(rz))]; + endswitch + elseif(rz == 0) + ## strictly an imaginary number + switch(flg) + case(0) + retval = num2str(iz); + case(1) + retval = [ sgns(1+(iz< 0))," ", num2str(abs(iz)),"i"]; + endswitch + else + ## complex number + ## strictly an imaginary number + switch(flg) + case(0) + retval = [num2str(rz)," ",com2str(i*iz,1)]; + case(1) + retval = [ sgns(1+(rz< 0))," ", num2str(abs(rz))," ",com2str(i*iz,1)]; + endswitch + endif + +endfunction