%% Tune Fixed-Structure Control System
% Tune the controller elements of the following control system.
%
% The control elements are C, which is a PI controller with two free parameters, and F, a low-pass filter in the feedback path with one free parameter. For this example, load the plant G, a 9th-order model of the head-disk assembly (HDA) in a hard-disk drive.

load hinfstruct_demo G
bode(G), grid

% Tune the free parameters of this control system so that the head position y tracks a step change r with a response time of about 1 ms, little or no overshoot, and no steady-state error.
%
% First, create the tunable elements. Use tunablePID class to parameterize the PI block, and specify the filter F(s) as a transfer function depending on a tunable real parameter a.

C0 = tunablePID('C','pi');  

a = realp('a',1); 
F0 = tf(a,[1 a]);

% F0 is a genss model.
%
% Next, express the design goals as weights on the plant model, and append them to the closed-loop system. For reasons described in detail in Fixed-Structure H-infinity Synthesis with hinfstruct, a configuration of weighting functions that achieves the design requirements for this problem is the following.
%
% Here, LS is the desired shape of the open-loop response L(s) = F(s) G(s) C(s).

wc = 1000;  % target crossover
s = tf('s');
LS = (1+0.001*s/wc)/(0.001+s/wc);

%
% As discussed in Fixed-Structure H-infinity Synthesis with hinfstruct, the design requirements are satisfied if the H_{\infty } norm of this control structure is less than 1.
% Use connect to construct a genss model representing this control structure.

% Label the block I/Os
Wn = 1/LS;  Wn.u = 'nw';  Wn.y = 'n';
We = LS;    We.u = 'e';   We.y = 'ew';
C0.u = 'e';   C0.y = 'u';
F0.u = 'yn';  F0.y = 'yf';

% Specify summing junctions
Sum1 = sumblk('e = r - yf');
Sum2 = sumblk('yn = y + n');

% Connect the blocks together
T0 = connect(G,Wn,We,C0,F0,Sum1,Sum2,{'r','nw'},{'y','ew'});

%
% You can now use hinfstruct to find tuned values of the tunable parameters in C0 and F0 that minimize the H_{\infty } norm of T0. To mitigate the risk of local minima, run three optimizations, two of which are started from randomized initial values for C0 and F0:

rng('default')
opt = hinfstructOptions('Display','final','RandomStart',5);
T = hinfstruct(T0,opt);

%
% The best closed-loop gain is about 1.56, so the constraint $ \| T \|_\infty < 1 $ is nearly satisfied. The hinfstruct command returns the tuned closed-loop transfer T(s). To validate the design, plot the tuned open-loop response L = F*G*C and compare with the target loop shape LS. To compute L, use getBlockValue to get the tuned value of C(s) and use getValue to evaluate the filter F(s) for the tuned value of a:

C = getBlockValue(T,'C');
F = getValue(F0,T.Blocks);  % propagate tuned parameters from T to F

L = G*C*F;
bode(LS,'r--',G*C*F,'b',{1e1,1e6}), grid, 
title('Open-loop response'), legend('Target','Actual')

% The 0dB crossover frequency and overall loop shape are as expected. For further analysis of the result, see Fixed-Structure H-infinity Synthesis with hinfstruct.
%
% Copyright 2020 The MathWorks, Inc.