LQI with time-delay system
18 views (last 30 days)
Show older comments
Matlab's documentation mentions that state-space systems with dead-time (eg. plant or measurement delays) can be defined with ss(), using 'inputDelay' and 'outputDelay'.
But, documentation (and Matlab error messages) also say that time-delay Pade approximations must be used for lqr() or lqi(), ie those functions cannot take ss() with time delays as defined above with 'inputDelay' or 'outputDelay'.
If I have a feedback loop period (the delay in the measurement I'm looking to take into account), I can use lqi() with a discretized model input, which should yield the correct gains for the corresponding loop delay.
But for a continuous system modeled in Simulink with a transport delay, there is no discretization step, and I'd need to find lqi() gains using the continuous system as approximated by the model and pade.
But in this case, what is the Q used? I'm unclear on what Matlab would like as Q matrix input to lqi() for a continuous system.
As a guess, I tried the following, which yielded error messages. Say the loop period is ts, and I have some basic 2nd-order plant model (attached).
load("lqiWithDelay")
plant
ts = 1 / 100e3;
[num, den] = pade(ts, 3); % Nth-order
loopDelayPadeApproxTf = tf(num, den);
plantWithDelay = plant * loopDelayPadeApproxTf;
% Find non-delayed CL gains
wnTarget_rPs = 10 * 2 * pi;
H_lqi = [2 * 0.7 * wnTarget_rPs, 0.5, -wnTarget_rPs^2];
Q_lqi = H_lqi.'* H_lqi;
R_lqi = 1;
K_lqi = lqi(model, Q_lqi, R_lqi)
% Find delayed CL gains
neededDelayedQsize = size(plantWithDelay.A, 1) + 1; % +1 needed for LQI
neededQlqiSize = size(modelWithDelay.A, 1) + 1
bigDelayedQ = zeros(neededDelayedQsize);
bigDelayedQ(1:3, 1:3) = Q_lqi
K_lqi_delayed = lqi(modelWithDelay, bigDelayedQ, R_lqi)
This uses zeros(), and i also tried eye() -- but im only guessing, since i don't know what lqi() does under the hood for those additional pade states that lead to a bigger needed Q matrix.
0 Comments
Answers (1)
Paul
on 14 Jan 2024
Edited: Paul
on 15 Jan 2024
Yes, if using a Pade apporoximant for the time delay, then the Q matrix will have to be expanded to include the additional state(s). In principle, you could buld the new Q matrix using the symmetric root locus technique, as I think is being done here, to drive the closed-loop poles to desirable locations. Maybe not penalizing that state(s) might be reasonable as well.
In addition, the Pade state(s) isn't available for feedback in the actual system, so they'd have to be reconstructed somehow, perhaps with a reduced order state estimator.
In the question you mentioned that the time delay is on the plant measurements, but the code has the time delay on the plant input. I'm going to assume it's on the input for what follows.
For this particular problem, the time delay at the input to the plant seems to be small enough that it is easily accomodated by the very large stability margins at the plant input that are guaranteed by LQ state feedback.
load("lqiWithDelay")
plant;
ts = 1 / 100e3;
%[num, den] = pade(ts, 3); % Nth-order
%loopDelayPadeApproxTf = tf(num, den);
%plantWithDelay = plant * loopDelayPadeApproxTf; % delay is at the plant input
% Find non-delayed CL gains
wnTarget_rPs = 10 * 2 * pi;
H_lqi = [2 * 0.7 * wnTarget_rPs, 0.5, -wnTarget_rPs^2];
Q_lqi = H_lqi.'* H_lqi;
R_lqi = 1;
%K_lqi = lqi(model, Q_lqi, R_lqi) % what was model? not defined ... assume it's supposed to be plant
K_lqi = lqi(plant, Q_lqi, R_lqi);
sysp = ss(plant.A,plant.B,[eye(2);plant.C],[zeros(2,1);plant.D],'InputName','u','OutputName',{'x1' 'x2' 'y'});
int = tf(K_lqi(3),[1 0],'InputName','e','OutputName','ui');
Kfb = ss(K_lqi(1:2),'InputName',{'x1' 'x2'},'OutputName','ufb');
esum = sumblk('e = r - y');
usum = sumblk('u = -ui - ufb');
sysc = connect(sysp,int,Kfb,esum,usum,'r','y','u');
Bode plot of the open-loop transfer function (w/o delay) at the plant input and of the delay.
L = getLoopTransfer(sysc,'u',-1);
figure
bode(L,exp(-tf('s')*ts))
As expected from an LQ design, the gain margin is infinite and the phase margin is quite large, about 90 deg in this case. The phase lag that would be introduced by the time delay at the input to the plant is quite small at the open-loop gain crossover frequency (~5000 rads/sec) and the phase margin will hardly be changed. The additional phase lag will cause an open-loop phase cross-over at very high frequency, but there the gain will be quite low and the gain margin quite large.
The effect of the delay on the closed-loop step response is negligible.
sysp = ss(plant.A,plant.B,[eye(2);plant.C],[zeros(2,1);plant.D],'InputName','u','OutputName',{'x1' 'x2' 'y'},'InputDelay',ts);
int = tf(K_lqi(3),[1 0],'InputName','e','OutputName','ui');
Kfb = ss(K_lqi(1:2),'InputName',{'x1' 'x2'},'OutputName','ufb');
esum = sumblk('e = r - y');
usum = sumblk('u = -ui - ufb');
syscdelay = connect(sysp,int,Kfb,esum,usum,'r','y','u');
figure
step(sysc,syscdelay)
28 Comments
Paul
on 16 Feb 2024
In the Simulink model in this comment it looked like the Transport Delay blocks were Commented Through. Yes, the transport delay should go before the Rate Transition blocks.
I don't see any difference at all between the results from connect/getLoopTransfer and from linearizing the Simulink model using linearize (which I'm sure is the same as what you'd get using any other method to linearize the model).
Load the system parameters and set the sample time.
load newPlantAndGains
plant.C = [eye(2);plant.C];
plant.Ts
Ts = 1e-6;
Buld the Simulink model with the continuous-time plant, discrete-time integrator, and feedback signals sampled at Ts.
bdclose('all');
hsys = new_system('lqitest');
hstep = add_block('simulink/Sources/Constant','lqitest/Step');
herror = add_block('simulink/Math Operations/Subtract','lqitest/error');
%hint = add_block('simulink/Continuous/Integrator','lqitest/int');
hint = add_block('simulink/Discrete/Discrete-Time Integrator','lqitest/int');
set_param(hint,'SampleTime','Ts');
hintgain = add_block('simulink/Math Operations/Gain','lqitest/intgain');
set_param(hintgain,'Gain','K_lqi(3)')
hcontrol = add_block('simulink/Math Operations/Subtract','lqitest/control');
set_param(hcontrol,'Inputs','--');
hplant = add_block('cstblocks/LTI System','lqitest/plant');
set_param(hplant,'MaskValues',{'plant';'[]';'0'});
hdemux = add_block('simulink/Signal Routing/Demux','lqitest/demux');
set_param(hdemux,'Outputs','[2 1]');
hstategain = add_block('simulink/Math Operations/Gain','lqitest/stategain');
set_param(hstategain,'Gain','K_lqi(1:2)');
set_param(hstategain,'Multiplication','Matrix(K*u)');
% hdelay1 = add_block('simulink/Continuous/Transport Delay','lqitest/delay1');
% set_param(hdelay1,'DelayTime','0');
%
% hdelay2 = add_block('simulink/Continuous/Transport Delay','lqitest/delay2');
% set_param(hdelay2,'DelayTime','0');
hzoh1 = add_block('simulink/Discrete/Zero-Order Hold','lqitest/zoh1');
set_param(hzoh1,'SampleTime','Ts');
hzoh2 = add_block('simulink/Discrete/Zero-Order Hold','lqitest/zoh2');
set_param(hzoh2,'SampleTime','Ts');
hout = add_block('simulink/Sinks/To Workspace','lqitest/output');
set_param(hout,'VariableName','y');
PH = 'PortHandles';
add_line(hsys, ...
get_param(hstep,PH).Outport,...
get_param(herror,PH).Inport(1));
add_line(hsys,...
get_param(herror,PH).Outport,...
get_param(hint,PH).Inport);
add_line(hsys,...
get_param(hint,PH).Outport,...
get_param(hintgain,PH).Inport);
add_line(hsys,...
get_param(hintgain,PH).Outport,...
get_param(hcontrol,PH).Inport(2));
add_line(hsys,...
get_param(hstategain,PH).Outport,...
get_param(hcontrol,PH).Inport(1));
add_line(hsys,...
get_param(hcontrol,PH).Outport,...
get_param(hplant,PH).Inport);
add_line(hsys,...
get_param(hplant,PH).Outport,...
get_param(hdemux,PH).Inport);
add_line(hsys,...
get_param(hdemux,PH).Outport(2),...
get_param(hout,PH).Inport);
add_line(hsys,...
get_param(hdemux,PH).Outport(2),...
get_param(hzoh2,PH).Inport);
add_line(hsys,...
get_param(hdemux,PH).Outport(1),...
get_param(hzoh1,PH).Inport);
add_line(hsys,...
get_param(hzoh1,PH).Outport,...
get_param(hstategain,PH).Inport);
add_line(hsys,...
get_param(hzoh2,PH).Outport,...
get_param(herror,PH).Inport(2));
Uncomment this line to open the model on the Simulink canvas for by-hand editing, execution, etc.
% open_system(hsys);
Simulate the model in the time domain with a fixed step solver with a simulation solver step size of 1e-8
cset = getActiveConfigSet(hsys);
set_param(cset,'StopTime','0.015');
set_param(cset,'Solver','FixedStepAuto');
set_param(cset,'FixedStep','1e-8');
out = sim('lqitest',cset);
figure
plot(out.y),grid
Get the open loop system at the input to the plant. linearize automagically deals with the hybrid model
sysolsimulink = -1*linearize('lqitest',linio('lqitest/control',1,'looptransfer'));
sysp = ss(plant.A,plant.B,plant.C,plant.D,'InputName','u','OutputName',{'x1' 'x2' 'y'});
%int = tf(K_lqi(3),[1 0],'InputName','e','OutputName','ui');
Kfb = ss(K_lqi(1:2),'InputName',{'x1' 'x2'},'OutputName','ufb');
esum = sumblk('e = r - y');
usum = sumblk('u = -ui - ufb');
syspdiscrete = c2d(sysp,Ts,'zoh');
intdiscrete = tf(Ts*K_lqi(3),[1 -1],Ts,'InputName','e','OutputName','ui');
syscdiscrete = connect(syspdiscrete,intdiscrete,Kfb,esum,usum,'r','y','u');
Compare the Bode plots of the open loop system derived by linearize() and derived by connect() followed by getLoopTransfer
figure
bode(sysolsimulink,getLoopTransfer(syscdiscrete,'u',-1),{10 1e7});
The results match.
See Also
Categories
Find more on Time and Frequency Domain Analysis in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!