LQR

.pdf

School

University of Illinois, Urbana Champaign *

*We aren’t endorsed by this school

Course

353

Subject

Computer Science

Date

Apr 3, 2024

Type

pdf

Pages

7

Uploaded by elgelie7

Report
LQR March 1, 2024 1 LQR [1]: import numpy as np from scipy import linalg import sympy as sym This is the infinite-horizon L inear Q uadratic R egulator (LQR) optimal control problem: minimize u [ t 0 , ) t 0 ( x ( t ) T Qx ( t ) + u ( t ) T Ru ( t ) ) dt subject to ˙ x ( t ) = Ax ( t ) + Bu ( t ) , x ( t 0 ) = x 0 The integrand is cost . The integral is total cost . The square matrices Q and R are weights — you, as a control designer, get to choose these weights. The minimizer (i.e., the input that achieves minimum total cost) is u ( t ) = Kx ( t ) and the minimum (i.e., the minimum total cost) is x T 0 Px 0 where P and K can be found in python as follows: P = linalg.solve_continuous_are(A, B, Q, R) K = linalg.inv(R) @ B.T @ P There are a number of reasons why LQR is a good choice for control design. At this point, we will simply say that LQR makes it easy to get a working controller. Why? Notice that, for this optimal control problem to make any sense, its minimum total cost — i.e., the value of the integral for the “best” choice of K — has to be finite. Since the upper limit of the integral is infinity, then — in order for the integral to be finite — the integrand has to converge to zero (quickly). The only way for it to do that is if the closed-loop system is asymptotically stable. In other words, the “best” choice of K has to produce a closed-loop system that is asymptotically stable. Put simply, the solution to the LQR problem, for any choice of weights, is a controller that produces a stable closed-loop system — i.e., a “working controller.” 1
Let’s look at an example. Suppose we want to design a controller by solving the LQR problem for the system described by A = [ 0 1 0 0 ] B = [ 0 1 ] and for weights that are both identity matrices: Q = I 2 × 2 = [ 1 0 0 1 ] R = I 1 × 1 = [ 1 ] First, we define the system: [32]: A = np . array([[ 0. , 1. ], [ 0. , 0. ]]) print ( f'A = { A . tolist() } ' ) B = np . array([[ 0. ], [ 1. ]]) print ( f'B = { B . tolist() } ' ) A = [[0.0, 1.0], [0.0, 0.0]] B = [[0.0], [1.0]] Second, we define the weights: [33]: Q = np . eye( 2 ) print ( f'Q = { Q . tolist() } ' ) R = np . eye( 1 ) print ( f'R = { R . tolist() } ' ) Q = [[1.0, 0.0], [0.0, 1.0]] R = [[1.0]] Third, we find the optimal cost matrix: [34]: P = linalg . solve_continuous_are(A, B, Q, R) print ( f'P = { P . tolist() } ' ) P = [[1.7320508075688763, 0.9999999999999993], [0.9999999999999993, 1.7320508075688772]] Fourth, and finally, we find the optimal gain matrix: [35]: K = linalg . inv(R) @ B . T @ P print ( f'K = { K . tolist() } ' ) K = [[0.9999999999999993, 1.7320508075688772]] As we claimed, this gain matrix makes the closed-loop system stable: 2
[36]: linalg . eigvals(A - B @ K) [36]: array([-0.8660254+0.5j, -0.8660254-0.5j]) Suppose we start with the following initial condition: x 0 = [ 1 2 ] [37]: x0 = np . array([ 1. , -2. ]) The input that we would apply at time t 0 is, of course, the following: u ( t 0 ) = Kx ( t 0 ) = Kx 0 Let’s compute it: [38]: u = - K @ x0 print ( f'u = { u . tolist() } ' ) u = [2.4641016151377553] Let’s also compute the total cost x T 0 Px 0 that we would accumulate if we continued to apply this same controller u ( t ) = Kx ( t ) for all time, starting from x ( t 0 ) = x 0 [39]: total_cost = x0 . T @ P @ x0 print ( f'total_cost = { total_cost } ' ) total_cost = 4.660254037844388 Note that the total cost is a scalar quantity (just one real number, not a vector or matrix). You try. Consider this system: A = [ 1 3 2 2 ] B = [ 1 1 ] 3
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help