Advanced: optimal control and MPC

13 min read
On this page

Pole placement specifies dynamics, but not the relative cost of error and action. Optimal control makes that tradeoff explicit; MPC includes a finite future and constraints in repeated decisions. This chapter builds on state feedback, digital control and quadratic functions.

LQR: define the objective

For continuous , consider

penalizes state deviation and action. Coordinates and units matter: changing meters to centimeters without changing weights changes the physical preference. Allowable errors and actions can provide normalization scales.

Under standard stabilizability and detectability conditions, the stabilizing Riccati solution satisfies

The feedback is , . Here is a cost matrix, not the state. Basic LQR has no hard actuator constraints; clipping its result changes its optimality and guarantees.

A hand-computable optimum

For , , , the equation is . The stabilizing solution gives

At , . Raising to 4 reduces gain to 0.5 and slows convergence. For , the respective optimal costs are 4 and 8. Their objectives differ, so those numbers cannot directly rank the controllers under one common preference.

MPC: optimize a sequence, execute one action

For discrete , solve at each instant

subject to , dynamics, , , and any terminal constraint. Execute only the first action, then measure or estimate again and reoptimize.

This incorporates new information after disturbances or prediction errors and can use known future references. Predicted and realized trajectories are different objects. The do-mpc introduction describes finite horizons, estimation and constraints.

Inspect a finite-action example

Our dimensionless model is , , target 0, with actions . Define the specific cost

There is no extra terminal term. Unlike the preceding notation, this penalizes each post-action state. Searching all sequences finds the global optimum within this finite set, not the general continuous-input MPC optimum.

Preparing the visual
Advanced: optimal control and MPC · Experiment

x(k+1)=x(k)+u(k), x0=2.5; actions 0, ±0.5, ±1; cost Σ[x(i+1)²+ρu(i)²]. Search all 5^N candidates, execute the first action, and reoptimize. Dashed initial prediction has no advance knowledge of the disturbance.

Change horizon and action weight. Compare the initial prediction with the realized receding-horizon trajectory and actions. An optional +1 disturbance is applied after the third action; it is not predicted. At equal cost, prefer smaller absolute first action, then enumeration order.

For , action −1 costs , while −0.5 costs . Choose −1. For continuous input constrained to , the stationary point is , projected onto the interval. A finite set additionally requires comparing neighboring candidates.

Feasibility and stability need their own arguments

A feasible optimization now does not ensure feasibility after a disturbance: recursive feasibility is a separate property. Finite-horizon optimality also does not automatically imply infinite-time convergence. Suitable terminal costs, terminal sets and local controllers are common ingredients in guarantees, with model-specific conditions.

Longer horizons see farther but cost computation. Missing the sample deadline introduces delay. Define fallback actions for timeout or infeasibility, constraint priorities, estimation uncertainty and model updates. Soft constraints need explicit allowed violations and penalties; do not silently soften hard limits.

Check your understanding

Is a clipped LQR action still the optimum of the original unconstrained problem?

Reasoning

No. Clipping changes the loop. Analyze saturation or formulate the constrained problem, then reassess stability and feasibility.

Why not compute one sequence and execute it forever?

Reasoning

Disturbances, model errors and updated estimates change the state. Repeated measurement and optimization use that new information; computation delay remains part of the implementation.

Reproduce and continue

python-control lqr returns gain, Riccati solution and closed-loop eigenvalues. This checks the scalar example using SciPy:

import control as ct
K, X, poles = ct.lqr([[0.0]], [[1.0]], [[1.0]], [[4.0]], method="scipy")
print(K, X, poles)
# [[0.5]] [[2.0]] [-0.5]

Continue with system identification for better models, nonlinear/robust control for broader guarantees, or stochastic estimation for noise. Return to the reading route to choose a path.