%
%     << 4-block L-inf optimal Controller (all solution formulae) >>
%               (derived by K. Glover & J. Doyle, 1988)
%
%   HINFKGJD is a script file which computes the H-inf optimal controller 
%   using G-D's all-solution "two-Riccati" formulae.
%   A particular controller F(s) is returned by default, however the
%   other solution can be generated by prespecifing the transfer function
%   in the workspace
%                       U(s):= (AU,BU,CU,DU)
%   where U(s) is a free stable contraction which parameterizes all the 
%   stabilizing controllers.
%
%   Input data (must be in Upper Case !!!): 
%              augmented plant (A,B1,B2,C1,C2,D11,D12,D21,D22) 
%              stable contraction U(s):= (AU,BU,CU,DU) (optional)
%   Output data: H-inf controller F(s):= (acp,bcp,ccp,dcp),
%                CLTF Ty1u1:= (acl,bcl,ccl,dcl).
%

% R. Y. Chiang & M. G. Safonov 2/10/88
% Copyright (c) 1988 by the MathWorks, Inc.
% All Rights Reserved.
% ------------------------------------------------------------------------
disp('   ')
disp('                << H-inf Optimal Control Synthesis >>')
disp(' ')
disp(' - - - Computing 4-block L-inf optimal controller ')
disp('       (using the all-solution formulae of Glover and Doyle) - - -')
%
flagcase1 = exist('b1');
flagcase2 = exist('B1');
if (flagcase1 > 0) & (flagcase2 < 1)
 error('   THIS SCRIPT FILE REQUIRES THE INPUT VARIABLE NAMES IN UPPER CASE !!!')
end
%
FLAG = exist('AU');
if FLAG < 1
   disp('  ')
   disp(' - - - Solving a particular solution F(s) (U(s) = 0 case) - - -');
end
if FLAG > 0
   disp('  ')
   disp(' - - - Solving the all-solution F(s) (U(s):=(AU,BU,CU,DU)) - - -');
end
AREFLAG = exist('aretype');
%
% ------------------------------------------- Pre-process the augmented plant:
%
% ------------------------------------------- 1) Zero out D22 term:
%
[mD22,nD22] = size(D22);
d22 = zeros(mD22,nD22);
%
% ------------------------------------------- 2) Find the scaling factors:
%
[n,n] = size(A);
[p1,m2] = size(D12);
[uu,sig12,vv] = svd(D12);
u1 = uu(:,1:m2);
u2 = uu(:,m2+1:p1);
su = vv*inv(sig12(1:m2,1:m2));
sz = [u2';u1'];
%
[p2,m1] = size(D21);
[uuu,sig21,vvv] = svd(D21);
v1 = vvv(:,1:p2);
v2 = vvv(:,p2+1:m1);
sy = inv(sig21(1:p2,1:p2))*uuu';
sw = [v2 v1];
%
b1  = B1*sw;
b2  = B2*su;
c1  = sz*C1;
c2  = sy*C2;
d11 = sz*D11*sw;
d21 = sy*D21*sw;
d12 = sz*D12*su;
%
% ----------------------------------------- 3) Check frequency @ infinity:
%
d1111 = d11(1:p1-m2,1:m1-p2);
d1121 = d11(p1-m2+1:p1,1:m1-p2);
d1112 = d11(1:p1-m2,m1-p2+1:m1);
d1122 = d11(p1-m2+1:p1,m1-p2+1:m1);
mxsvd11r = max(svd([d1111 d1112]));
mxsvd11c = max(svd([d1111;d1121]));
if mxsvd11r >= 1 | mxsvd11c >= 1
     disp('  ')
     disp('    ------------------------------------------------------------');
     disp('       NO CONTROLLER MEETS THE SPEC. EVEN AT FREQ. INF ALONE !!')
     disp('       ADJUST "Gam" AND TRY AGAIN ...')
     disp('    ------------------------------------------------------------');
     break
end
%
% ----------------------------------------------------------------------------
%
% ----------------------------------------- Start to compute the controller:
gam = 1;
gam2 = gam*gam;
%
% ----------------------------------------- Fixing D11 matrix:
%
if m1 == p2 | p1 == m2
   dk11 = -d1122;
   dk12 = eye(m2);
   dk21 = eye(p2);
else
   gamd1  = gam2*eye(p1-m2)-d1111*d1111';
   gamd2  = gam2*eye(m1-p2)-d1111'*d1111;
   dk11   = -d1121*d1111'*inv(gamd1)*d1112-d1122;
   dk1212 = eye(m2) - d1121*inv(gamd2)*d1121';
   dk12   = chol(dk1212); dk12 = dk12';
   dk2121 = eye(p2) - d1112'*inv(gamd1)*d1112;
   dk21   = chol(dk2121);
end
%                                                 
% ---------------------------------------- Solving X Riccati:
%
Zr = zeros(m1+m2,m1+m2);
Zr(1:m1,1:m1) = gam2*eye(m1);
d1d = [d11 d12];
R = d1d'*d1d - Zr;
Ri = inv(R); 
B = [b1 b2];
ax = A-B*Ri*d1d'*c1;
rx = B*Ri*B';
qx = c1'*c1 - c1'*d1d*Ri*d1d'*c1;
%
disp(' ');
disp(' - - - Solving the 1st Riccati - - -');
if AREFLAG > 0
   [X1,X2,lamXc,Xerr,wellposed,X] = aresolv(ax,qx,rx,aretype);
else
   [X1,X2,lamXc,Xerr,wellposed,X] = aresolv(ax,qx,rx);
end
%                                                  
% ---------------------------------------- Solving Y Riccati:
%
Zrw = zeros(p1+p2,p1+p2);
Zrw(1:p1,1:p1) = gam2*eye(p1);
dd1 = [d11;d21];
Rw = dd1*dd1' - Zrw;
Rwi = inv(Rw);
C = [c1;c2];
ay = A' - C'*Rwi*dd1*b1';
ry = C'*Rwi*C;
qy = b1*b1' - b1*dd1'*Rwi*dd1*b1';
disp('   ');
disp(' - - - Solving the 2nd Riccati - - -');
if AREFLAG > 0
   [Y1,Y2,lamYc,Yerr,wellposed,Y] = aresolv(ay,qy,ry,aretype);
else
   [Y1,Y2,lamYc,Yerr,wellposed,Y] = aresolv(ay,qy,ry);
end
lamX = min(real(eig(X)));
lamY = min(real(eig(Y)));
format long
lamXY = max(real(eig(X*Y)))
if (lamX<0 & abs(lamX)>1e-10) | (lamY<0 & abs(lamY)>1e-10) | lamXY > 1
         disp('  ')
         disp('    ----------------------------------------------------');
         disp('       NO STABILIZING CONTROLLER MEETS THE SPEC. !!')
         disp('       ADJUST "Gam" AND TRY AGAIN ...')
         disp('    ----------------------------------------------------');
         break
end
%
% ---------------------------- Constant Matrices:
%
F   = - Ri*(d1d'*c1+B'*X);
F11 = F(1:m1-p2,:);
F12 = F(m1-p2+1:m1,:);
F2  = F(m1+1:m1+m2,:);
%
H   = - (b1*dd1'+Y*C')*Rwi;
H11 = H(:,1:p1-m2);
H12 = H(:,p1-m2+1:p1);
H2  = H(:,p1+1:p1+p2);
%
% ---------------------------- Controller in Descriptor form:
%
Z   = eye(n) - inv(gam2)*Y*X;
%
bk2    = (b2+H12)*dk12;
ck2    = -dk21*(c2+F12);
bk1    = -H2+bk2*inv(dk12)*dk11;
ck1    = F2+dk11*inv(dk21)*ck2;
ak     = A*Z + H*C*Z + bk2*inv(dk12)*ck1;
%
% ------------------------------------- Post-process the controller:
%
% ------------------------------------- 1) Reverse the controller scaling:
%
bk1 = bk1*sy;
ck1 = su*ck1;
dk11 = su*dk11*sy;
dk12 = su*dk12;
dk21 = dk21*sy;
%
% ------------------------------------- 2) Shifting D22 term:
%
temp = inv(eye(size(dk11)*[1;0]) + dk11*D22);
ak   = ak-bk1*D22*temp*ck1;
bk2  = bk2-bk1*D22*temp*dk12;
ck2  = ck2-dk21*D22*temp*ck1;
ck1  = temp*ck1;
dk22 = dk22-dk21*D22*temp*dk12;
dk12 = temp*dk12;
dk11 = temp*dk11;
temp = eye(size(D22)*[1;0])-D22*dk11;
bk1  = bk1*temp;
dk21 = dk21*temp;
dk22 = zeros(size(dk21)*[1;0],size(dk12)*[0;1]);
%
% ----------------  Putting descriptor controller K(s) in state space form:
%
se = svd(Z);
nullZ = size(find(se<1.e-7))*[1;0];
[ak,bk,ck,dk] = des2ss(ak,[bk1,bk2],[ck1;ck2],...
                         [dk11,dk12;dk21,dk22],Z,nullZ);
[rbk1,cbk1] = size(bk1);
[rbk2,cbk2] = size(bk2);
[rck1,cck1] = size(ck1);
[rck2,cck2] = size(ck2);
bk1=bk(:,1:cbk1);
bk2=bk(:,cbk1+1:cbk1+cbk2);
ck1=ck(1:rck1,:);
ck2=ck(rck1+1:rck1+rck2,:);
dk11=dk(1:rck1,1:cbk1);
dk12=dk(1:rck1,cbk1+1:cbk1+cbk2);
dk21=dk(rck1+1:rck1+rck2,1:cbk1);
dk22=dk(rck1+1:rck1+rck2,cbk1+1:cbk1+cbk2);
%
% --------------------- computing controller F(s) = (acp,bcp,ccp,dcp):
%
sysk = [ak,bk1,bk2;ck1,dk11,dk12;ck2,dk21,dk22];
dimk = [size(ak)*[1 0]',size(bk1)*[0 1]',size(bk2)*[0 1]',...
            size(ck1)*[1 0]',size(ck2)*[1 0]'];
if ~( exist('AU') & exist('BU') & exist('CU') & exist('DU'))
   acp = ak; bcp = bk1; ccp = ck1; dcp = dk11;
else
   [acp,bcp,ccp,dcp] = lftf(sysk,dimk,AU,BU,CU,DU);
end
%
% ---------------------------------------------------------------------------
%
% ------------------------------------ Closed-loop TF (Ty1u1):
%
sysp = [A B1 B2;C1 D11 D12;C2 D21 D22];
dimp = [n,size(B1)*[0 1]',size(B2)*[0 1]',...
       size(C1)*[1 0]',size(C2)*[1 0]'];
[acl,bcl,ccl,dcl] = lftf(sysp,dimp,acp,bcp,ccp,dcp);
%
clear sysp, clear dimp, clear a, clear b1, clear b2, clear c1, clear c2
clear d11, clear d12, clear d21, clear d22, clear syscp, clear dimcp
clear temp
%
% ---------- End of HINFKGJD.M --- RYC/MGS -- %
