Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
This example shows how to use Robust Control Toolbox to design a robust controller (using D-K iteration) and
to do robustness analysis on a process control problem. In our example, the plant is a simple two-tank system.
Additional experimental work relating to this system is described by Smith et al. in the following references:
Smith, R.S., J. Doyle, M. Morari, and A. Skjellum, "A Case Study Using mu: Laboratory Process Control
Problem," Proceedings of the 10th IFAC World Congress, vol. 8, pp. 403-415, 1987.
Smith, R.S, and J. Doyle, "The Two Tank Experiment: A Benchmark Control Problem," in Proceedings
American Control Conference, vol. 3, pp. 403-415, 1988.
Smith, R.S., and J. C. Doyle, "Closed Loop Relay Estimation of Uncertainty Bounds for Robust Control
Models," in Proceedings of the 12th IFAC World Congress, vol. 9, pp. 57-60, July 1993.
Plant Description
The plant in our example consists of two water tanks in cascade as shown schematically in Figure 1. The upper
tank (tank 1) is fed by hot and cold water via computer-controlled valves. The lower tank (tank 2) is fed by water
from an exit at the bottom of tank 1. An overflow maintains a constant level in tank 2. A cold water bias stream
also feeds tank 2 and enables the tanks to have different steady-state temperatures.
Our design objective is to control the temperatures of both tanks 1 and 2. The controller has access to the
reference commands and the temperature measurements.
Variable
--------
Unit Name
---------
0 means:
--------
temperature tunit
height
flow
hunit
funit
1 means:
--------
tank full
max. input flow
A1 = 0.0256;
% Area of tank 1 (hunits^2)
A2 = 0.0477;
% Area of tank 2 (hunits^2)
h2 = 0.241;
% Height of tank 2, fixed by overflow (hunits)
fb = 3.28e-5; % Bias stream flow (hunits^3/sec)
fs = 0.00028;
% Flow scaling (hunits^3/sec/funit)
th = 1.0; % Hot water supply temp (tunits)
tc = 0.0;
% Cold water supply temp (tunits)
tb = tc;
% Cold bias stream temp (tunits)
alpha = 4876; % Constant for flow/height relation (hunits/funits)
beta = 0.59; % Constant for flow/height relation (hunits)
The variable fs is a flow-scaling factor that converts the input (0 to 1 funits) to flow in hunits^3/second. The
constants alpha and beta describe the flow/height relationship for tank 1:
h1 = alpha*f1-beta.
Nominal Tank Models
We can obtain the nominal tank models by linearizing around the following operating point (all normalized
values):
h1ss = 0.75;
% Water level for tank 1
t1ss = 0.75;
% Temperature of tank 1
f1ss = (h1ss+beta)/alpha;
% Flow tank 1 -> tank 2
fss = [th,tc;1,1]\[t1ss*f1ss;f1ss];
fhss = fss(1);
% Hot flow
fcss = fss(2);
% Cold flow
t2ss = (f1ss*t1ss + fb*tb)/(f1ss + fb); % Temperature of tank 2
The nominal model for tank 1 has inputs [ fh; fc] and outputs [ h1; t1]:
A = [ -1/(A1*alpha),
0;
(beta*t1ss)/(A1*h1ss), -(h1ss+beta)/(alpha*A1*h1ss)];
B = fs*[ 1/(A1*alpha), 1/(A1*alpha);
th/A1,
tc/A1];
C = [ alpha,
0;
-alpha*t1ss/h1ss, 1/h1ss];
D = zeros(2,2);
tank1nom = ss(A,B,C,D,'InputName',{'fh','fc'},'OutputName',{'h1','t1'});
clf
step(tank1nom), title('Step responses of Tank 1')
act_BW = 20;
% Actuator bandwidth (rad/sec)
actuator = [ tf(act_BW,[1 act_BW]); tf([act_BW 0],[1 act_BW]) ];
actuator.OutputName = {'Flow','Flow rate'};
bodemag(actuator)
title('Valve actuator dynamics')
hot_act = actuator;
set(hot_act,'InputName','fhc','OutputName',{'fh','fh_rate'});
cold_act =actuator;
set(cold_act,'InputName','fcc','OutputName',{'fc','fc_rate'});
fbw = 2.25;
% Anti-aliasing filter cut-off (Hz)
filter = mkfilter(fbw,4,'Butterw');
h1F = filter;
t1F = filter;
t2F = filter;
Uncertainty on Model Dynamics
Open-loop experiments reveal some variability in the system responses and suggest that the linear models are
good at low frequency. If we fail to take this information into account during the design, our controller might
perform poorly on the real system. For this reason, we will build an uncertainty model that matches our estimate
of uncertainty in the physical system as closely as possible. Because the amount of model uncertainty or
variability typically depends on frequency, our uncertainty model involves frequency-dependent weighting
functions to normalize modeling errors across frequency.
For example, open-loop experiments indicate a significant amount of dynamic uncertainty in the t1 response.
This is due primarily to mixing and heat loss. We can model it as a multiplicative (relative) model error Delta2 at
the t1 output. Similarly, we can add multiplicative model errors Delta1 and Delta3 to the h1 and t2 outputs as
shown in Figure 5.
Limit-cycle experiments in the t1 loop suggest that uncertainty should dominate above 0.02 Hz.
There are about 180 degrees of additional phase lag in the t1 model at about 0.02 Hz. There is also a
significant gain loss at this frequency. These effects result from the unmodeled mixing dynamics.
Limit cycle experiments in the t2 loop suggest that uncertainty should dominate above 0.03 Hz.
This data suggests the following choices for the frequency-dependent modeling error bounds.
Wh1 = 0.01+tf([0.5,0],[0.25,1]);
Wt1 = 0.1+tf([20*h1ss,0],[0.2,1]);
Wt2 = 0.1+tf([100,0],[1,21]);
clf
bodemag(Wh1,Wt1,Wt2), title('Relative bounds on modeling errors')
legend('h1 dynamics','t1 dynamics','t2 dynamics','Location','NorthWest')
t1cmd = Wt1cmd * w1
t2cmd = Wt1cmd * w1 + Wtdiffcmd * w2
where w1, w2 are white noise inputs. Adequate weight choices are:
Wt1cmd = zpk(0.1);
Wtdiffcmd = zpk(0.01);
Finally, we would like to penalize both the amplitude and the rate of the actuator. We do this by
weighting fhc (and fcc) with a function that rolls up at high frequencies. Alternatively, we can create an actuator
model with fh and d|fh|/dt as outputs, and weight each output separately with constant weights. This approach
has the advantage of reducing the number of states in the weighted open-loop model.
'y_t1Fn', 'y_t2Fn'};
hot_act.InputName = 'fhc'; hot_act.OutputName = {'fh' 'fh_rate'};
cold_act.InputName = 'fcc'; cold_act.OutputName = {'fc' 'fc_rate'};
tank1and2u.InputName = {'fh','fc'};
tank1and2u.OutputName = {'t1','t2'};
t1F.InputName = 't1'; t1F.OutputName = 'y_t1F';
t2F.InputName = 't2'; t2F.OutputName = 'y_t2F';
Wt1cmd.InputName = 't1cmd'; Wt1cmd.OutputName = 'y_Wt1cmd';
Wtdiffcmd.InputName = 'tdiffcmd'; Wtdiffcmd.OutputName = 'y_Wtdiffcmd';
Whact.InputName = 'fh'; Whact.OutputName = 'y_Whact';
Wcact.InputName = 'fc'; Wcact.OutputName = 'y_Wcact';
Whrate.InputName = 'fh_rate'; Whrate.OutputName = 'y_Whrate';
Wcrate.InputName = 'fc_rate'; Wcrate.OutputName = 'y_Wcrate';
Wt1perf.InputName = 'u_Wt1perf'; Wt1perf.OutputName = 'y_Wt1perf';
Wt2perf.InputName = 'u_Wt2perf'; Wt2perf.OutputName = 'y_Wt2perf';
Wt1noise.InputName = 't1noise'; Wt1noise.OutputName = 'y_Wt1noise';
Wt2noise.InputName = 't2noise'; Wt2noise.OutputName = 'y_Wt2noise';
sum1
sum2
sum3
sum4
sum5
=
=
=
=
=
By constructing the weights and weighted open loop of Figure 8, we have recast the control problem as a closedloop gain minimization. Now we can easily compute a gain-minimizing control law for the nominal tank models:
nmeas = 4;
% Number of measurements
nctrls = 2;
% Number of controls
[k0,g0,gamma0] = hinfsyn(P.NominalValue,nmeas,nctrls);
gamma0
gamma0 =
0.9032
The smallest achievable closed-loop gain is about 0.9, which shows us that our frequency-domain tracking
performance specifications are met by the controller k0. Simulating this design in the time domain is a
reasonable way to check that we have correctly set the performance weights. First, we create a closed-loop
model mapping the input signals [ t1ref; t2ref; t1noise; t2noise] to the output signals
[ h1; t1; t2; fhc; fcc]:
time=0:800;
t1ref = (time>=80 & time<100).*(time-80)*-0.18/20 + ...
(time>=100)*-0.18;
t2ref = (time>=80 & time<100).*(time-80)*-0.2/20 + ...
(time>=100)*-0.2;
t1noise = Wt1noise.k * randn(size(time));
h1 = h1ss+y(:,1);
t1 = t1ss+y(:,2);
t2 = t2ss+y(:,3);
fhc = fhss/fs+y(:,4); % Note scaling to actuator
fcc = fcss/fs+y(:,5); % Limits (0<= fhc <= 1) etc.
In this code, we plot the outputs, t1 and t2, as well as the height h1 of tank 1:
plot(time,h1,'--',time,t1,'-',time,t2,'-.');
xlabel('Time (sec)')
ylabel('Measurements')
title('Step Response of H-infinity Controller k0')
legend('h1','t1','t2');
grid
plot(time,fhc,'-',time,fcc,'-.');
xlabel('Time: seconds')
ylabel('Actuators')
title('Actuator Commands for H-infinity Controller k0')
legend('fhc','fcc');
grid
frad = 2*pi*logspace(-5,1,30);
clpk0 = lft(P,k0);
clpk0_g = ufrd(clpk0,frad);
% Compute worst-case gain
opt = wcgainOptions('MaxOverFrequency','off');
[maxgain,wcu,info] = wcgain(clpk0_g,opt);
% Compare closed-loop gains
clf
semilogx(fnorm(clpk0_g.NominalValue),'b-',...
maxgain.UpperBound,'r--')
title('Performance Analysis for Controller k0')
xlabel('Frequency (rad/sec)')
legend('Nominal','Worst-case')
axis([1e-4 100 0 2.5])
sim_kmu = lft(simlft,kmu);
y = lsim(sim_kmu,[t1ref;t2ref;t1noise;t2noise],time);
h1 = h1ss+y(:,1);
t1 = t1ss+y(:,2);
t2 = t2ss+y(:,3);
fhc = fhss/fs+y(:,4); % Note scaling to actuator
fcc = fcss/fs+y(:,5); % Limits (0<= fhc <= 1) etc.
% Plot |t1| and |t2| as well as the height |h1| of tank 1
plot(time,h1,'--',time,t1,'-',time,t2,'-.');
xlabel('Time: seconds')
ylabel('Measurements')
title('Step Response of mu Controller kmu')
legend('h1','t1','t2');
grid
wcinfo.Sensitivity
ans =
delta1: 0
delta2: 57
delta3: 10