Clear Filters
Clear Filters

Structured H infinity synthesis can't find a controller that makes closed loop stable even with an asymptotically stable plant?

9 views (last 30 days)
So I have an asymptotically stable 2 input-8 output system with 17 states. I think It's pretty stable too, with a maximum real eigenvalue part of -6.
I connected a system which specified the 2 inputs as a summation of 16 tunable PI controllers (8 PI controllers for each input) with a tunable low pass filter in feedback, pretty much following the example here:
But, I keep getting that hinfstruct can't synthesize a controller that stabalizes the closed loop. I was wondering how is this even possible? Shouldn't there automatically be a zero gain stabalizing solution if my plant is already asymptotically stable? Linked below is the plant I am attempting to control named 'Plin', and also below is the code I am currently running:
G=tf(Plin);
%% Fixed structure H infinity suynthesis
%With a fixed PI controller with a low pass frequency filter, we perform H
%infinity synthesis to find gains which minimize the LFT gain
%Just used to get a specific variable of the output error to feed into 8
%SISO PI controllers below
CsMat=eye(8);
%8 SISO PI controllers (for first input)
C0=tunablePID('C0','pid');
C1=tunablePID('C1','pid');
C2=tunablePID('C2','pid');
C3=tunablePID('C3','pid');
C4=tunablePID('C4','pid');
C5=tunablePID('C5','pid');
C6=tunablePID('C6','pid');
C7=tunablePID('C7','pid');
%8 SISO PI controllers (for second input)
C0b=tunablePID('C0b','pid');
C1b=tunablePID('C1b','pid');
C2b=tunablePID('C2b','pid');
C3b=tunablePID('C3b','pid');
C4b=tunablePID('C4b','pid');
C5b=tunablePID('C5b','pid');
C6b=tunablePID('C6b','pid');
C7b=tunablePID('C7b','pid');
CTotPi=[C0,C1,C2,C3,C4,C5,C6,C7;
C0b,C1b,C2b,C3b,C4b,C5b,C6b,C7b]; %Just specifies the two inputs as the addition of 8 PI controllers on the 8 outputs of the system
%{
CTotPi= [C0,zeros(1,7);
zeros(1,1),C1,zeros(1,6);
zeros(1,2),C2,zeros(1,5);
zeros(1,3),C3,zeros(1,4);
zeros(1,4),C4,zeros(1,3);
zeros(1,5),C5,zeros(1,2);
zeros(1,6),C6,zeros(1,1);
zeros(1,7),C7];
%}
%For now just have all 8 outputs in feedback pass through the same filter
a = realp('a',1);
F0 = eye(8)*tf(a,[1 a]); %Low pass filter filters out high frequencies from the output
wc = 1000; % target crossover
s = tf('s');
Tar = (1+0.001*s/wc)/(0.001+s/wc); %Target transfer function
We = eye(8)*1/Tar;
Wn = eye(8)*Tar;
%%
% Label the block I/Os,
G.u='u'; G.y='y';
CTotPi.u = 'e'; CTotPi.y = 'u';
We.u = 'e'; We.y = 'ew';
Wn.u = 'nw'; Wn.y = 'n';
F0.u = 'yn'; F0.y = 'yf';
% Specify summing junctions
Sum1 = sumblk('yn = y + n',8);
Sum2 = sumblk('e = r - yf',8);
% Connect the blocks together
T0 = connect(G,Wn,We,CTotPi,F0,Sum1,Sum2,{'r','nw'},{'y','ew'});
rng('default')
opt = hinfstructOptions('Display','final','RandomStart',5);
T = hinfstruct(T0,opt);
showTunable(T)
Edit: Just to give a bit more info, it does successfuly spit out a tuning for the PI controllers, and here is the warning message I get:
Warning: Gain goal: Feedback configuration has fixed integrators that cannot be stabilized with available tuning parameters. Make
sure these are modeling artifacts rather than physical instabilities.
and it has a corresponding output of
Final: Failed to enforce closed-loop stability (max Re(s) = 6e-10)
  2 Comments
Paul
Paul on 19 Jan 2024
Hi Vinh,
It sounds like the system has one or more poles at the origin that are not influenced by the tunable parameters. Hard to say much more without seeing the the plant model and the code that builds the model input to hinfstruct.
Vinh
Vinh on 19 Jan 2024
Edited: Vinh on 19 Jan 2024
Thank you for the response. The plant I am controlling is linked below. There are no poles at the origin. All of the poles of my plant are in the LHP which is why I am confused.

Sign in to comment.

Accepted Answer

Paul
Paul on 19 Jan 2024
Hi Vinh,
I'll say up front that I don't have a complete solution to your problem, but I have an observation that I'm pretty sure is in the right direction and I think found one error in the code. I modified the code a little bit to assign InputName and OutputName where each subsystem is defined, which made it a bit easier for me to follow.
load Plin
Plin comes in as a state space model. There is no need and it is not recommended to convert it to a tf. ss is always preferred, and all inputs to connect get converted to ss anyway, so by converting to tf here, we're potentially losing accuracy on the conversion ss -> tf -> ss.
% G=tf(Plin);
G = Plin;
G.u = 'u'; G.y = 'y';
%% Fixed structure H infinity suynthesis
%With a fixed PI controller with a low pass frequency filter, we perform H
%infinity synthesis to find gains which minimize the LFT gain
%Just used to get a specific variable of the output error to feed into 8
%SISO PI controllers below
% CsMat = eye(8);
I thought that the problem statement was to use PI control, but here the compensators are all PID.
%8 SISO PI controllers (for first input)
C0=tunablePID('C0','pid');
C1=tunablePID('C1','pid');
C2=tunablePID('C2','pid');
C3=tunablePID('C3','pid');
C4=tunablePID('C4','pid');
C5=tunablePID('C5','pid');
C6=tunablePID('C6','pid');
C7=tunablePID('C7','pid');
%8 SISO PI controllers (for second input)
C0b=tunablePID('C0b','pid');
C1b=tunablePID('C1b','pid');
C2b=tunablePID('C2b','pid');
C3b=tunablePID('C3b','pid');
C4b=tunablePID('C4b','pid');
C5b=tunablePID('C5b','pid');
C6b=tunablePID('C6b','pid');
C7b=tunablePID('C7b','pid');
CTotPi=[C0,C1,C2,C3,C4,C5,C6,C7;
C0b,C1b,C2b,C3b,C4b,C5b,C6b,C7b]; %Just specifies the two inputs as the addition of 8 PI controllers on the 8 outputs of the system
CTotPi.u = 'e'; CTotPi.y = 'u';
Here is where I think the problem is. Let's look at CTotPi
size(CTotPi)
Generalized state-space model with 2 outputs, 8 inputs, 16 states, and 16 blocks.
The number of inputs, outputs, and states are all as expected.
Now, let's replace the tunable parameters in CTotPi with actual values assuming PI. I think that hinfstruct must do something like this as it iterates over values of the tunable parameters.
fnames = fieldnames(CTotPi.Blocks);
Css = CTotPi;
for ii = 1:numel(fnames)
Css = replaceBlock(Css,fnames{ii},pid(10*ii,20*ii));
end
size(Css)
State-space model with 2 outputs, 8 inputs, and 16 states.
Again, 16 states.
But, 14 of those states are redundant, and Css can actually be realized with only 2 states.
Cssmin = minreal(Css);
14 states removed.
size(Cssmin)
State-space model with 2 outputs, 8 inputs, and 2 states.
Cssmin
Cssmin = A = x1 x2 x1 0 0 x2 0 0 B = e(1) e(2) e(3) e(4) e(5) e(6) e(7) e(8) x1 -0.9116 -0.723 -0.5345 -0.3459 -0.1573 0.03127 0.2198 0.4084 x2 0.04777 0.1576 0.2674 0.3772 0.487 0.5968 0.7066 0.8164 C = x1 x2 u(1) -2.616 368.8 u(2) -22.74 403.3 D = e(1) e(2) e(3) e(4) e(5) e(6) e(7) e(8) u(1) 10 30 50 70 90 110 130 150 u(2) 20 40 60 80 100 120 140 160 Continuous-time state-space model.
The 14 states that were removed are all at the origin. As hinfstruct inserts values for the PI gains, 14 poles at the origin are not affected by those PI gains. Hence, the message from hinfstruct. I think that this is the problem.
In the code as written, hinfstruct will try to opimize over PID gains (not just PI), but I think that the issue will be the same.
To solve it, you'd have to come up with a parameterized model for CTotPI that has only two states and is parameterized by 16 pairs of PI gains.
%For now just have all 8 outputs in feedback pass through the same filter
a = realp('a',1);
F0 = eye(8)*tf(a,[1 a]); %Low pass filter filters out high frequencies from the output
F0.u = 'yn'; F0.y = 'yf';
Here is an error, I believe. Based on my understanding of how hinfstruct works, and as shown on its doc page, We and Wn are backwards. Here's the code from the doc page
%wc = 1000; % target crossover
%s = tf('s');
%LS = (1+0.001*s/wc)/(0.001+s/wc);
%Wn = 1/LS; Wn.u = 'nw'; Wn.y = 'n';
%We = LS; We.u = 'e'; We.y = 'ew';
wc = 1000; % target crossover
s = tf('s');
Tar = (1+0.001*s/wc)/(0.001+s/wc); %Target transfer function
%We = eye(8)*1/Tar; We.u = 'e'; We.y = 'ew';
%Wn = eye(8)*Tar; Wn.u = 'nw'; Wn.y = 'n';
% match the doc page
We = eye(8)*Tar; We.u = 'e'; We.y = 'ew';
Wn = eye(8)/Tar; Wn.u = 'nw'; Wn.y = 'n';
% Specify summing junctions
Sum1 = sumblk('yn = y + n',8);
Sum2 = sumblk('e = r - yf',8);
% Connect the blocks together
T0 = connect(G,Wn,We,CTotPi,F0,Sum1,Sum2,{'r','nw'},{'y','ew'});
%{
rng('default')
opt = hinfstructOptions('Display','final','RandomStart',5);
T = hinfstruct(T0,opt);
showTunable(T)
%}
  1 Comment
Vinh
Vinh on 19 Jan 2024
Thank you so much for the help Paul. Also, yes I accidentally mixed up the error weighting and the noise weighting. And yes, the non-minimum realization was the issue, and it actually fixes another issue I was having with LQI. Thank you again, that is a huge help.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!