Reference Tracking and Optimal Control · Lesson
English translation
Topics covered
Examine why reference error remains even with a stable controller, and compare tracking performance with control-input cost.
Stability and reference tracking have different conditions
u=−Kx is a regulator that drives the state to the origin. For a reference r, use and calculate N from the nominal model's steady-state equation.
Assess stability using , and calculate the tracked output including the reference path.
Interpreting LQR cost
Define the cost of state deviations and input use as . Increasing Q assigns a higher cost to that state deviation.
This does not mean that all metrics improve simultaneously. States with different units require normalization by reference magnitudes or interpretation of the weights' units.
This model is a 2nd-order system with normalized states and input. Under and suitable controllability conditions, solve the CARE to obtain . If the input saturates, the optimality of this linear, unconstrained design no longer applies directly.
Checking the same design in MATLAB
Reference gain adjusts the input amplitude to achieve the desired steady-state output. LQR state-feedback gain is determined by the costs assigned to state error and control input.
Same poles, different reference tracking
Keep the control poles fixed and change only the reference gain to examine differences in the steady-state value.
import numpy as np
from scipy.signal import place_poles,StateSpace,lsim
from scipy.linalg import solve_continuous_are
import matplotlib.pyplot as plt
A=np.array([[0.,1.],[-2.,-3.]])
B=np.array([[0.],[1.]]);C=np.array([[1.,0.]])
K=place_poles(A,B,[-2.,-4.]).gain_matrix
N=float((-1/(C@np.linalg.solve(A-B@K,B))).item())
print('K:',K,'N:',N);assert np.isclose(N,8)
t=np.linspace(0,5,1001)
for gain in [1.,N]:
_,y,_=lsim(StateSpace(A-B@K,B*gain,C,0),np.ones(len(t)),t)
plt.plot(t,y,label=f'N={gain:g}')
plt.xlabel('Time [s]');plt.ylabel('Position');plt.legend();plt.grid()
P=solve_continuous_are(A,B,np.diag([4.,1.]),np.array([[1.]]))
klqr=B.T@P
print('LQR gain:',klqr,'closed-loop poles:',np.linalg.eigvals(A-B@klqr))
K: [[6. 3.]] N: 7.999999999999995 LQR gain: [[0.82842712 0.41421356]] closed-loop poles: [-1.41421356 -2. ]