MATLAB Examples

F14 H-Infinity Loop-Shaping Design Example

Illustration of H-infinity loop-shaping with Robust Control Toolbox


This example illustrates the use of Robust Control Toolbox to design a controller using the Glover-McFarlane H-infinity loop-shaping method. This control design method is conceptually similar to Bode's frequency response methods. H-infinity loop-shaping can be applied to multivariable design problems, and uses optimization to produce robust performance and stabilization.


We start with a blank workspace, but we'll load the F14 model configuration data again to avoid 'issues' with open models.

freq_range = logspace(-2, 4, 501); % useful for bode & sigma plots.

Linearize model

I've done this the 'old fashioned way', using the basic LINMOD function applied to a 'standalone' model of the plant. There are more sophisticated ways of doing this these days, but this has the virtue of simplicity. (The newer linearization methods have several advantages like the ability to use a single model file for everything - check them out if you can.)

[a_mat, b_mat,c_mat, d_mat] = linmod('f14_plant_model');
P = ss(a_mat, b_mat, c_mat, d_mat);
P.OutputName = {'Angle of Attack', 'Pilot G force'};
clear a_mat b_mat c_mat d_mat

sigma(P, 'b-', freq_range)
ylim([-70 70]);
grid on
legend('P', 'Location', 'NorthEast')

Design the closed-loop response

Because we have two highly-coupled outputs controlled from a single input, it's a good idea to design our closed-loop response - this tells us what we can achieve and what sort of closed-loop bandwidth to aim for.

The code shown below designs a closed-loop response that cancels the resonant pole pair with a third-order critically-damped filter. The frequency of this filter was chosen experimentally - it's the fastest possible value that avoids a gradient reversal in the pilot-experienced force.

I chose this behaviour because it seemed close to be what the original F14 example achieved.

s = zpk('s');
the_poles = pole(P);
the_poles = the_poles(abs(imag(the_poles))>1e-6); % the oscillatory ones
om_filt = 6; % chosen experimentally
M = zpk(the_poles, om_filt*[-1 -1 -1],1);
M = M/(dcgain(M)*dcgain(P(1,:)));

R_ideal = P*M;
R_ideal = minreal(R_ideal,[],false);

step(P, 'b-', 5);
title('Plant Step Response')
step(R_ideal, 'm-', 5)
title('Target Step Response')

Design weights for H-infinity loop-shaping

Here we design 'weighting' functions for H-infinity loop-shaping. I've set the crossover frequency to equal the target closed-loop bandwidth, and added some integral weighting to give a greater slope - this should result in higher gain at low frequencies and lower gain at high frequencies - good for disturbance/noise rejection.

om_c = bandwidth(P(1,:)*M); % same as closed-loop target, can be higher

% Initial attempt at weights - get the overall shape
Wo = 1;
Wi = 1/s;
Pw = Wo*P*Wi;
Pw = minreal(Pw, [], false);

% Adjust Wi to set the closed-loop bandwidth as desired
sg = max(sigma(Pw, om_c));
Wi = Wi/sg;
Pw = Pw/sg;

sigma(P, 'b-', Pw, 'g-', freq_range)
ylim([-70 70]);
grid on
legend('P', 'Pw', 'Location', 'NorthEast')

Synthesize a controller using ncfsyn

This is where we use Robust Control Toolbox's NCFSYN function to design an optimally-robust feedback compensator. This needs to be combined with the weights to get the complete feedback controller.

[Cinf,~,gam] = ncfsyn(Pw);
Cinf = -Cinf; % I prefer a negative feedback convention
perf_margin = 1/gam %#ok<NOPTS>

% Form the overall controller
C = Wi*Cinf*Wo;

% Work out the overall loop gain
L = P*C;

sigma(P, 'b', Pw, 'g', L, 'm', freq_range)
ylim([-70 70]);
grid on
legend('P', 'Pw', 'L', 'Location', 'NorthEast')
perf_margin =


Plot the sensitivity functions

As for SISO control, the sensitivity functions tell us a lot about our noise and disturbance rejection. The following code plots them.

T = feedback(L, eye(2));
S = eye(2) - T;

sigma(S, 'k-', T, 'm-', freq_range);
grid on
legend('Sensitivity', 'Comp. Sens.')
ylim([-80 20]);

Prefilter design

To get the target closed-loop response, we'll need a prefilter of some kind. The following code achieves this.

As our system has two coupled outputs which we cannot control independently, I have done some matrix manipulation to work out how the control system's two channels relate to the single axis of control.

% Work out a 'unit vector' to map one input to two values
[u,~,~] = svd(dcgain(T));
Q0 = u(:,1);

% Work out the prefilter.
Qhat = (T(1,:)*Q0) \ R_ideal(1,:);
Qhat = minreal(Qhat,[],false);

step(T*Q, 5)

Form the overall controller

This includes the weighted feedback compensator and the prefilter.

Controller = C*[Q -eye(2)];
Controller = minreal(Controller, [], false);

% Save the data so we can automatically load it as needed.
save f14dat_hinfctrl Controller

Open and run Simulink model

open_system f14_hinf_controller
sim f14_hinf_controller