Manually compute LQI() gains using Algebraic Riccati Equation / Hamiltonian
Show older comments
I'm attempting to compile a Matlab program for embedded use, and that program also includes lqr() and lqi(). Since neither are compilable functions for compiling, I'm solving LQR and LQI manually, ultimately hoping to end up only with functions that can be compiled.
I'm doing this via two Hamiltonian methods, with pole placement or to find the Algebraic Riccati Equation solution P. This is working correctly (solutions P and gains K match lqr() outputs) for a continuous-time basic plant without integrator. But, for the discrete case it's failing for both methods I try, with results that don't match Matlab's results (i won't go into the discrete implementation in detail, for clarity, unless asked)
My question is:
- Is there a better manual method to finding lqi gains, especially one that generalizes to the discrete case more easily? I'm having trouble using the below methods for the discrete case, even with needed changes (see links in this post) to handle the discrete case. I can create a separate post for troubleshooting that, but for now, i'm just curious if there are simpler manual methods -- or built-in methods that Matlab allows for compiling into executables.
- If I set Q = eye(3) for LQI case, it's suspicious that all lqi gains are 1's, and that lqr() and lqi(1:2) gains don't match. Why would gains be almost exactly 1 from Q = eye(3)?
Details
I'm using two manual processes. One uses poles placement via acker(), and the other works via Schur decomposition via schur(), as seen in this link.
Both methods work for LQR (plant without integral action). But neither works with LQI (plant with integral action), insofar as matching the base lqr() gains. Of course, the plant with integral action won't use the integral action in open-loop, so it's more a structural addition.
Method 1: Pole placement method
Method 2: Schur method
Code
clc
close all
A = [0 1;
-4e5 -400];
B = [0; 4e5];
C = [1 0];
sys = ss(A, B, C, 0);
% i denotes "integral"
Ai = [A, zeros(2,1); -C, 0];
Bi = [B; 0];
Ci = [C 0];
sys_aug = ss(Ai, Bi, Ci, 0);
% ========================
% LQR
% x = [x1; x2]
Q = eye(size(A));
Q(1,1) = 1e5;
Q(2,2) = 0.1;
R = 1;
K_lqr = lqr(sys, Q, R)
% ~~~ Method 1 ~~~
hamiltonian = [A, -B/R*B';
-Q, -A'];
eigs_H = eig(hamiltonian);
whichNegEig = find(real(eigs_H)<0);
% This matches K_lqr
K_hamilt = acker(A, B, eigs_H(whichNegEig))
% ~~~ Method 2 ~~~
[U, S] = schur(hamiltonian);
[U, S] = ordschur(U, S, 'lhp');
% Find U21 and U11: U is a square matrix.
[m,n] = size(U);
U11 = U(1:(m/2), 1:(n/2));
U21 = U((m/2+1):m, 1:(n/2));
% Find solution P to A.R.E.
P = U21 * inv(U11);
% Double-check solution using built-in care()
P_care = care(A, B, Q, R) ;
% This matches K_lqr
K_schur = inv(R) * B' * P
Acl_lqr_manual = [sys.A - sys.B * K_schur];
syscl_lqr_manual = ss(Acl_lqr_manual, B* K_lqr * [1;0], C, 0);
figure;
step(syscl_lqr_manual)
hold on;
% ========================
% LQI: Integral action
% x = [x1; x2; xi]
Qi = eye(size(Ai));
Qi(1,1) = Q(1,1);
Qi(2,2) = Q(2,2);
Qi(3,3) = 1e12;
Ri = 1;
K_lqr_i = lqr(sys_aug, Qi, Ri)
K_lqi_i2 = lqi(sys, Qi, Ri) % just double-check
% ~~~ Method 1 ~~~
hamiltonian_i = [Ai, -Bi/Ri*Bi';
-Qi, -Ai'];
eigs_Hi = eig(hamiltonian_i);
whichNegEig_i = find(real(eigs_Hi)<0);
% This is all NaN due to 0 column
K_hamilt_i = acker(Ai, Bi, eigs_Hi(whichNegEig_i))
% ~~~ Method 2 ~~~
[Ui, Si] = schur(hamiltonian_i);
[Ui, Si] = ordschur(Ui, Si, 'lhp');
% Find U21 and U11: U is a square matrix.
[m,n] = size(Ui);
U11i = Ui(1:(m/2), 1:(n/2));
U21i = Ui((m/2+1):m, 1:(n/2));
% Find solution P to A.R.E.
Pi = U21i * inv(U11i);
% Double-check solution using built-in care()
Pi_care = care(Ai, Bi, Qi, Ri);
% This ~matches K_lqr_i, but not K_lqi_i.
K_schur_i = inv(Ri) * Bi' * Pi
Acl_lqi_manual = [sys.A - sys.B * K_schur_i(1:2), -sys.B * K_schur_i(3);
-sys.C, 0];
% Ref is through integ K(Ki*xi - x), ie
% Ref feedthrough only to xi, ie K(r-x), vs above w/ ref through integ K(Ki*xi - x)
Bcl_lqi_manual = [0; 0; 1];
Ccl_lqi_manual = [sys.C 0];
syscl_lqi_manual = ss(Acl_lqi_manual, Bcl_lqi_manual, Ccl_lqi_manual, 0);
step(syscl_lqi_manual)
step(sys)
legend('manual lqr', ' manual lqi', 'OL')
Accepted Answer
More Answers (0)
Categories
Find more on State-Space Control Design 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!