view scripts/control/hinfsyn.m @ 3385:10f21f7ccc7f

[project @ 1999-12-15 22:28:26 by jwe]
author jwe
date Wed, 15 Dec 1999 22:28:52 +0000
parents 69b167451491
children 1a8e2c0d627a
line wrap: on
line source

## 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{K}, @var{g}, @var{GW}, @var{Xinf}, @var{Yinf}] =} hinfsyn(@var{Asys}, @var{nu}, @var{ny}, @var{gmin}, @var{gmax}, @var{gtol}@{, @var{ptol}, @var{tol}@})
## 
## @strong{Inputs} input system is passed as either
## @table @var
## @item Asys
## system data structure (see ss2sys, sys2ss)
## @itemize @bullet
## @item controller is implemented for continuous time systems 
## @item controller is NOT implemented for discrete time systems  (see
## bilinear transforms in @code{c2d}, @code{d2c})
## @end itemize
## @item nu
## number of controlled inputs
## @item ny
## number of measured outputs
## @item gmin
## initial lower bound on H-infinity optimal gain
## @item gmax
## initial upper bound on H-infinity optimal gain
## @item gtol
## gain threshhold.  Routine quits when gmax/gmin < 1+tol
## @item ptol
## poles with abs(real(pole)) < ptol*||H|| (H is appropriate
## Hamiltonian) are considered to be on the imaginary axis.  
## Default: 1e-9
## @item tol
## threshhold for 0.  Default: 200*eps
## 
## @var{gmax}, @var{min}, @var{tol}, and @var{tol} must all be postive scalars.
## @end table 
## @strong{Outputs}
## @table @var
## @item K
## system controller
## @item g
## designed gain value
## @item GW
## closed loop system
## @item Xinf
## ARE solution matrix for regulator subproblem
## @item Yinf
## ARE solution matrix for filter subproblem
## @end table
## 
## @enumerate
## @item Doyle, Glover, Khargonekar, Francis, "State Space Solutions
##      to Standard H2 and Hinf Control Problems," IEEE TAC August 1989
## 
## @item Maciejowksi, J.M., "Multivariable feedback design,"
##      Addison-Wesley, 1989, ISBN 0-201-18243-2
## 
## @item Keith Glover and John C. Doyle, "State-space formulae for all
##      stabilizing controllers that satisfy and h-infinity-norm bound
##      and relations to risk sensitivity,"
##      Systems & Control Letters 11, Oct. 1988, pp 167-172.
## @end enumerate
## @end deftypefn
 
function [K, g, GW, Xinf, Yinf] = hinfsyn (Asys, nu, ny, gmin, gmax, gtol, ptol, tol)

  ## A. S. Hodel August 1995
  ## Updated for Packed system structures December 1996 by John Ingram
  ## 
  ## 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).

  if( (nargin < 1) | (nargin > 8) )
    usage("[K,g,GW,Xinf,Yinf] = hinfsyn(Asys,nu,ny,gmin,gmax,gtol,ptol,tol)");
  endif
  ## set default arguments
  if(nargin < 8)
    tol = 200*eps;
  elseif(!is_sample(tol))
    error("tol must be a positive scalar.")
  endif
  if(nargin < 7)
    ptol = 1e-9;
  elseif(!is_sample(ptol))
    error("hinfsyn: ptol must be a positive scalar");
  endif
    
  if(!is_sample(gmax) | !is_sample(gmin) | !is_sample(gtol) )
    error(["hinfsyn: gmax=",num2str(gmax),", gmin=",num2str(gmin), ...
      "gtol=",num2str(gtol), " must be positive scalars."])
  endif

  [chkdgkf,dgs] = is_dgkf(Asys,nu,ny,tol);

  if (! chkdgkf )
    disp("hinfsyn: system does not meet required assumptions")
    help is_dgkf
    error("hinfsyn: exit");
  endif

  ## extract dgs information
  			nw = dgs.nw;	nu = dgs.nu;
  A = dgs.A;		B1 = dgs.Bw;	B2 = dgs.Bu;
  C1 = dgs.Cz;		D11 = dgs.Dzw;	D12 = dgs.Dzu;		nz = dgs.nz;
  C2 = dgs.Cy;		D21 = dgs.Dyw;	D22 = dgs.Dyu;		ny = dgs.ny;
  d22nz = dgs.Dyu_nz;
  dflg = dgs.dflg;

  ## recover i/o transformations
  R12 = dgs.Ru;		R21 = dgs.Ry;
  [ncstates, ndstates, nin, nout] = sysdimensions(Asys);
  Atsam = sysgettsam(Asys);
  [Ast, Ain, Aout] = sysgetsignals(Asys);

  BB = [B1, B2];
  CC = [C1 ; C2];
  DD = [D11, D12 ; D21,  D22];

  if (dflg == 0)
    n = ncstates;
    ## perform binary search to find gamma min
    ghi = gmax;
    ## derive a lower lower bound for gamma from D matrices
    xx1 = norm((eye(nz) - (D12/(D12'*D12))*D12')*D11);
    xx2 = norm(D11*(eye(nw)-(D21'/(D21*D21'))*D21));
    glo = max(xx1, xx2);
    if (glo > gmin)
      disp(" *** D matrices indicate a greater value of gamma min.");
      fprintf("     gamma min (%f) superseeded by %f.", gmin, glo);
      glo = xx1;
    else
      glo = gmin;
    endif
    if (glo > ghi)
      fprintf(" *** lower bound of gamma greater than upper bound(%f)", ...
	      glo, ghi);
      disp(" *** unable to continue, Goodbye.");
      return;
    endif

    de = ghi - glo;
    g = glo;
    search_state = 0;
    iteration_finished = 0;
    disp(" o structural tests passed, start of iteration...");
    disp("        o <-> test passed   # <-> test failed   - <-> cannot test");
    printf("----------------------------------------");
    printf("--------------------------------------\n");

    ## ------123456789012345678901234567890123456789012345678901234567890
    printf("           .........X......... .........Y......... ");
    printf(".Z. PASS REMARKS\n");
    printf("        ga iax nev ene sym pos iax nev ene sym pos ");
    printf("rho  y/n ======>\n");
    printf("----------------------------------------");
    printf("--------------------------------------\n");

    ## set up error messages
    errmesg = list(" o   o   o   o   o  ", ...
	" #   -   -   -   -  ", ...
	" o   #   -   -   -  ", ...
	" o   o   #   -   -  ", ...
	" o   o   o   #   -  ", ...
	" o   o   o   o   #  ", ...
	" -   -   -   -   -  ");
    errdesx = list("", ...
	"X im eig.", ...
	"Hx not Ham.", ...
	"X inf.eig", ...
	"X not symm.", ...
	"X not pos", ...
	"R singular");

    errdesy = list(" ", ...
	"Y im eig.", ...
	"Hy not Ham.", ...
	"Y inf.eig", ...
	"Y not symm.", ...
	"Y not pos", ...
	"Rtilde singular");


    ## now do the search
    while (!iteration_finished)
      switch (search_state)
        case (0) 	g = ghi;
        case (1) 	g = glo;
        case (2) 	g = 0.5 * (ghi + glo);
        otherwise 	error(" *** This should never happen!");
      endswitch
      printf("%10.4f ", g);

      ## computing R and R~
      d1dot = [D11, D12];
      R = zeros(nin, nin);
      R(1:nw,1:nw) = -g*g*eye(nw);
      R = R + d1dot' * d1dot;
      ddot1 = [D11; D21];
      Rtilde = zeros(nout, nout);
      Rtilde(1:nz,1:nz) = -g*g*eye(nz);
      Rtilde = Rtilde + ddot1 * ddot1';

      [Xinf,x_ha_err] = hinfsyn_ric(A,BB,C1,d1dot,R,ptol);
      [Yinf,y_ha_err] = hinfsyn_ric(A',CC',B1',ddot1',Rtilde,ptol);

      ## assume failure for this gamma
      passed = 0;
      rerr="";
      if (!x_ha_err && !y_ha_err)
	## test spectral radius condition
	rho = max(abs(eig(Xinf * Yinf)));
	if (rho < g*g)
	  ## spectral radius condition passed
	  passed = 1;
        else
          rerr = sprintf("rho=%f",rho);
	endif
      endif

      if(x_ha_err >= 0 & x_ha_err <= 6)
        printf("%s",nth(errmesg,x_ha_err+1));
        xerr = nth(errdesx,x_ha_err+1);
      else
        error(" *** Xinf fail: this should never happen!");
      endif

      if(y_ha_err >= 0 & y_ha_err <= 6)
        printf("%s",nth(errmesg,y_ha_err+1));
        yerr = nth(errdesy,y_ha_err+1);
      else
        error(" *** Yinf fail: this should never happen!");
      endif

      if(passed)  printf("  y all tests passed.\n");
      else        printf("  n %s/%s%s\n",xerr,yerr,rerr);          endif

      if (passed && (de/g < gtol))
	search_state = 3;
      endif

      switch (search_state)
        case (0)
	  if (!passed)
	    ## upper bound must pass but did not
	    fprintf(" *** the upper bound of gamma (%f) is too small.\n", g);
	    iteration_finished = 2;
	  else
            search_state = 1;
	  endif
        case (1)
	  if (!passed)      search_state = 2;
	  else
	    ## lower bound must not pass but passed
	    fprintf(" *** the lower bound of gamma (%f) passed.\n", g);
	    iteration_finished = 3;
	  endif
        case (2)
          ## Normal case; must check that singular R, Rtilde wasn't the problem.
	  if ((!passed) & (x_ha_err != 6) & (y_ha_err != 6) ) glo = g;
	  else         ghi = g;        endif
	  de = ghi - glo;
        case (3)       iteration_finished = 1;        # done
        otherwise      error(" *** This should never happen!");
      endswitch
    endwhile

    printf("----------------------------------------");
    printf("--------------------------------------\n");
    if (iteration_finished != 1)
      K = [];
    else
      ## success: compute controller
      fprintf("   hinfsyn final: glo=%f ghi=%f, test gain g=%f\n", \
              glo, ghi, g);
      printf("----------------------------------------");
      printf("--------------------------------------\n");
      Z = inv(eye(ncstates) - Yinf*Xinf/g/g);
      F = -R \ (d1dot'*C1 + BB'*Xinf);
      H = -(B1*ddot1' + Yinf*CC') / Rtilde;
      K = hinf_ctr(dgs,F,H,Z,g);

      Kst = strappend(Ast,"_K");
      Kin = strappend(Aout((nout-ny+1):(nout)),"_K");
      Kout = strappend(Ain((nin-nu+1):(nin)),"_K");
      [Ac, Bc, Cc, Dc] = sys2ss(K);
      K = ss2sys(Ac,Bc,Cc,Dc,Atsam,ncstates,ndstates,Kst,Kin,Kout);
      if (nargout >= 3)
	GW = starp(Asys, K);
      endif
    endif
    
  elseif(ndstates)

    ## discrete time solution
    error("hinfsyn: discrete-time case not yet implemented")

  endif

endfunction