vp.control.lqr
The linear-quadratic regulator for xdot = A x + B u with cost int x^T Q x + u^T R u: the gain K = R^-1 B^T P, m by n, with u = -K x, and the Riccati solution P. As python-control's lqr without its third result.
Part of the distribution vipyr; it runs from a checkout of the
repository. Planned on PyPI as pip install vipyr.
Signature
vp.control.lqr(A, B, Q, R) Parameters
- A : ndarray[float64], required
- Range: rank 2, square.
- B : ndarray[float64], required
- Range: rank 2.
- Q : ndarray[float64], required
- Range: rank 2, square.
- R : ndarray[float64], required
- Range: rank 2, square.
Returns
A frozen LqrResult. Iterating it gives the fields below in order; it also has
params, tests, log and check().
- K : ndarray[float64]
- P : ndarray[float64]
Raises
- vipyr.ParameterError
- A ValueError: an argument outside its range, choices, rank or shape, or one of a group given without the rest; its .param names the argument.
- TypeError
- An argument of the wrong type, or an unknown keyword.
- vipyr.VivBuildError
- An ImportError: no C compiler, or the program's C does not build.
Examples
import numpy as np
import vipyr as vp
A, B = vp.control.cartpole_model(h=1e-5) # linearized about the upright
r = vp.control.lqr(A=A, B=B, Q=np.diag([1.0, 1.0, 20.0, 1.0]), R=np.array([[0.05]]))
print(np.round(r.K, 4)) # u = -K s
print(np.linalg.eigvals(A - B @ r.K).real.max() < 0) # the closed loop is stable
assert r.check() [[ -4.4721 -8.2239 -63.0331 -16.0163]]
TrueEach example ran as written when these pages were generated, and the output shown is what it printed.
Checked against
- Reference
- P = scipy.linalg.solve_continuous_are(A, B, Q, R), K = scipy.linalg.solve(R, B^T P)
- Compared by
- max|K - K_ref| / max|K_ref|; the closed loop A - B K must be stable
- Tolerance
- rel 10−9
- Why that tolerance
- K inherits the Riccati solution's conditioning; on the well-conditioned test systems both solvers agree far below this
Credits
- The Schur, Riccati and Lyapunov solvers use algorithms after SLICOT; no SLICOT code is copied.
Source
- Manifest: kernels/k1/k1.export.toml
- Viv: kernels/k1/control.viv
- Viv: lib/are.viv
- The defs it reaches and the calls between them: map of the code