## How Does Model Predictive Control Work?
Imagine steering a self-driving car through traffic or optimizing a chemical plant's operations in real-time. These scenarios demand foresight—predicting future states and making optimal decisions under constraints. This is where **Model Predictive Control (MPC)** shines. MPC is an advanced control strategy that uses a dynamic model of the system to forecast its behavior over a future time window, then computes the best sequence of control actions to achieve desired performance while respecting limits like speed or temperature bounds.
Unlike traditional controllers like PID, which react based on current errors, MPC is proactive. It solves an optimization problem at every time step, rolling out predictions and adjusting plans dynamically. This makes it ideal for multivariable systems with constraints, common in industries from aerospace to energy.
## Why Choose MPC Over Other Control Methods?
MPC's power lies in its ability to handle **constraints explicitly**. For instance, a drone can't exceed battery limits or collide with obstacles—MPC incorporates these directly into its optimization. It also manages **multi-objective trade-offs**, balancing speed, energy use, and stability.
Historically, MPC emerged in the 1970s from the process industry and space programs, evolving with computational advances. Today, with faster solvers, it's accessible even for embedded systems. To explore hands-on, check out this [practical MPC repository](https://github.com/bartkeulen/mpc-basics) featuring code examples.
## Key Building Blocks of an MPC Controller
### 1. The System Model: Predicting the Future
At MPC's heart is a **model** approximating system dynamics. Typically, this is a linear state-space representation:
$$\\dot{x} = Ax + Bu$$
$$y = Cx + Du$$
Here, $x$ is the state vector (e.g., position, velocity), $u$ the inputs (e.g., forces), and $y$ the outputs. Nonlinear models are possible but computationally heavier.
For digital implementation, we discretize using zero-order hold:
$$x_{k+1} = A_d x_k + B_d u_k$$
Where $A_d = e^{A T_s}$, $B_d = \\int_0^{T_s} e^{A \\tau} B d\\tau$, and $T_s$ is the sample time. This predicts states over a **prediction horizon** $N_p$ steps ahead.
### 2. Prediction and Control Horizons
- **Prediction horizon ($N_p$)**: How far into the future to forecast (e.g., 10-50 steps). Longer horizons capture more dynamics but increase computation.
- **Control horizon ($N_c$)**: Number of future moves to optimize (often $N_c \\leq N_p$). Beyond this, inputs stay constant, reducing variables.
These horizons trade off foresight vs. solvability. Short $N_p$ risks shortsightedness; long ones amplify model errors.
### 3. Objective Function: What to Optimize
MPC minimizes a quadratic cost:
$$J = \\sum_{i=1}^{N_p} \\| \\hat{y}_{k+i|k} - r_{k+i} \\|^2_Q + \\sum_{i=0}^{N_c-1} \\| \\Delta u_{k+i|k} \\|^2_R + \\| u_{k+N_c|k} \\|^2_S$$
- $Q$: Output weighting (track references $r$).
- $R$: Input change penalties (smoothness).
- $S$: Terminal input weight.
This penalizes tracking errors and aggressive moves, with $\\Delta u = u_{k+i} - u_{k+i-1}$ for rate-limiting.
### 4. Constraints: Keeping It Safe
Hard limits ensure feasibility:
$$u_{min} \\leq u_{k+i|k} \\leq u_{max}$$
$$\\Delta u_{min} \\leq \\Delta u_{k+i|k} \\leq \\Delta u_{max}$$
$$y_{min} \\leq \\hat{y}_{k+i|k} \\leq y_{max}$$
Optional soft constraints use slack variables for robustness.
## Mathematical Setup: From Continuous to Optimization Problem
Consider a continuous system $\\dot{x} = f(x,u)$. Discretize to $x_{k+1} = f_d(x_k, u_k)$. Stack predictions:
$$\\hat{X} = \\Gamma x_k + \\Theta U$$
$$\\hat{Y} = C \\hat{X} + D U$$
Where $U = [u_k, \\dots, u_{k+N_c-1}]^T$. The optimization becomes a **Quadratic Program (QP)**:
$$\\min_U (Y - R)^T Q (Y - R) + U^T R U$$
Subject to linear inequalities on $U$, $\\Delta U$, $Y$. Solvers like qpOASES or OSQP handle this efficiently.
## Practical Example: Double Integrator for Position Control
Let's control a mass's position with force $u$, dynamics:
$$\\ddot{p} = u / m$$
States: $x = [p, v]^T$, $A = [[0,1],[0,0]]$, $B = [[0],[1/m]]$, $C = [1,0]$ for position output.
Discretized ($T_s=0.1s$, $m=1$):
```python
import numpy as np
Ts = 0.1
A = np.array([[1, Ts], [0, 1]])
B = np.array([[Ts**2/2], [Ts]])
C = np.array([[1, 0]])
```
Set $N_p=20$, $N_c=5$, $Q=1$, $R=0.1$. Optimize to track $r=1m$ from $p=0$, $v=0$, with $|u| \\leq 1$, $|\\Delta u| \\leq 0.5$.
In practice, only apply the first $u$, shift horizons, repeat.
## Hands-On Python Implementation with CVXPY
CVXPY makes QP solving straightforward. Here's a basic MPC loop:
```python
import cvxpy as cp
import numpy as np
# System matrices (double integrator)
A = np.array([[1, 0.1], [0, 1]])
B = np.array([[0.005], [0.1]])
C = np.array([[1, 0]])
Np, Nc = 20, 5
Q, R = 1, 0.1
x = np.zeros(2) # initial state [pos, vel]
r = 1.0 # reference
for k in range(50):
U = cp.Variable((Nc, 1))
X = []
x_next = x
for i in range(Np):
if i < Nc:
x_next = A @ x_next + B @ U[i]
else:
x_next = A @ x_next + B @ U[Nc-1]
X.append(C @ x_next)
Y = cp.vstack(X)
cost = cp.quad_form(Y - r, Q) + cp.quad_form(cp.diff(U, axis=0), R)
constraints = [cp.norm(U, 'inf') <= 1, cp.norm(cp.diff(U, axis=0), 'inf') <= 0.5]
prob = cp.Problem(cp.Minimize(cost), constraints)
prob.solve()
u = U.value[0]
x = A @ x + B @ u
print(f'Step {k}: pos={x[0]:.3f}, u={u[0]:.3f}')
```
This simulates tracking, applying only $u_0$ each step (**Receding Horizon Principle**). Tune horizons/Q/R for performance.
For full code and Jupyter notebooks, see the [MPC Basics GitHub repo](https://github.com/bartkeulen/mpc-basics).
## Real-World Applications: Where MPC Excels
- **Automotive**: Adaptive cruise control, balancing distance/speed/fuel.
- **Process Industry**: Distillation columns, respecting flow/pressure limits.
- **Energy**: Wind farm power optimization under turbulence.
- **Robotics**: Trajectory tracking with joint limits.
- **Aerospace**: Spacecraft attitude control.
MPC scales to nonlinear (NMPC) via successive linearization or direct nonlinear solvers like CasADi.
## Strengths and Limitations of MPC
**Pros**:
- Handles MIMO, constraints, offsets.
- Optimizes multivariable goals.
- Predicts disturbances.
**Cons**:
- Computationally intensive (mitigated by explicit MPC or fast QPs).
- Model-dependent (robust MPC adds uncertainty handling).
- Tuning horizons/weights requires expertise.
## Wrapping Up: Your Next Steps in MPC
MPC transforms control from reactive to predictive, unlocking performance in constrained environments. Start with linear cases like the double integrator, experiment in Python, and scale up. Dive deeper with the [GitHub repo](https://github.com/bartkeulen/mpc-basics) for simulations and extensions. Whether for research or industry, mastering MPC equips you for tomorrow's smart systems.
---
<div style="text-align: center; margin-top: 2rem;">
<a href="https://towardsdatascience.com/model-predictive-control-basics/" target="_blank" rel="noopener noreferrer" class="view-full-resource-btn" style="display: inline-block; background-color: #f97316; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600; transition: background-color 0.2s;">View Full Resource</a>
</div>