学习路径

MPC 学习路径

从 LQR 基础到约束优化和控制,逐步掌握 MPC 的核心原理与实践技能。本路径采用四层递进法,适合从入门到进阶的系统学习。



💡 0. 核心理念

一句话总结 MPC:MPC = LQR + 约束 + 滚动时域。LQR 是无限时域离线求解,MPC 是有限时域在线滚动求解。

为什么很多人学不透 MPC?

常见的错误学习方式:

四层递进法

第一层 基础原理 状态空间 + LQR + 离散化 2-3 周 第二层 MPC 核心 预测模型 + QP 组装 + 约束 3-4 周 第三层 NMPC 进阶 非线性求解 + CasADi 实现 2-3 周 第四层 深入理论 稳定性 + 鲁棒 + 随机 MPC 可选 贯穿始终的黄金法则 手推一次预测方程 + 手写一次 QP 矩阵组装 比看十遍书都透彻。从最简单的 SISO 系统开始,一行行理解每步的含义
黄金法则:每学一层,必须同时做两件事 —— 手推公式(纸笔)+ 手写代码(Python/Matlab)。只看不练等于没学。

1 第一层:基础原理(2-3 周)

在接触 MPC 之前,必须先掌握以下三个基础工具。MPC 本质上是 LQR 的在线滚动版本,没有 LQR 基础就去学 MPC,代价函数的由来永远搞不清楚。

1.1 状态空间模型

MPC 使用状态空间模型进行预测,这是最核心的数学工具。

$$\dot{x}(t) = A x(t) + B u(t) \quad \text{(连续时间)}$$ $$x_{k+1} = A_d x_k + B_d u_k \quad \text{(离散时间)}$$

必须掌握

📝
练习:写出双积分器 \(\ddot{y} = u\) 的状态空间表示,判断能控性。再到倒立摆、DC 电机等典型系统。

1.2 LQR 最优控制

LQR 是 MPC 代价函数的直接前身。理解 LQR = 理解 MPC 代价函数的灵魂。

LQR 代价函数

$$J = \int_0^\infty \left( x^T Q x + u^T R u \right) dt$$ $$J = \sum_{k=0}^\infty \left( x_k^T Q x_k + u_k^T R u_k \right) \quad \text{(离散)}$$

LQR 解

$$u = -K x, \quad K = (R + B^T P B)^{-1} B^T P A$$

其中 \(P\) 满足代数 Riccati 方程 (ARE):

$$P = A^T P A - A^T P B (R + B^T P B)^{-1} B^T P A + Q$$

必须理解

关键洞见:如果你把 MPC 的预测时域 N 设成无穷大,去掉约束,MPC 就退化为 LQR。MPC = LQR + 约束 + 滚动时域。

1.3 离散化方法

物理系统大多是连续的,但 MPC 在计算机上实现必须是离散的。

方法公式精度
零阶保持 (ZOH)\(A_d = e^{AT_s},\; B_d = \int_0^{T_s} e^{A\tau} d\tau \cdot B\)一阶(精确匹配阶跃响应)
欧拉前向\(A_d = I + AT_s,\; B_d = B T_s\)一阶(\(T_s\) 需很小)
RK4四步龙格-库塔积分四阶(适用于非线性)
💡
建议:线性系统用 ZOH(Matlab `c2d`),非线性系统用 RK4 或欧拉法。

1.4 状态估计基础

实际 MPC 中状态往往不能直接测量,需要观测器。

⚠️
注意:初学阶段可以先假设状态完全可测(全状态反馈),再逐步加入观测器。

1.5 自查清单

进入第二层之前,确认你能:

2 第二层:MPC 核心(3-4 周)

这是最关键的阶段。目标:手推 MPC 的 QP 形式 + 手写一个能跑的 MPC 控制器

2.1 预测模型推导

给定系统 \(x_{k+1} = Ax_k + Bu_k\),在时刻 \(k\) 已知 \(x_k = x_0\):

$$\begin{aligned} x_1 &= A x_0 + B u_0 \\ x_2 &= A^2 x_0 + A B u_0 + B u_1 \\ x_3 &= A^3 x_0 + A^2 B u_0 + A B u_1 + B u_2 \\ &\vdots \\ x_N &= A^N x_0 + \sum_{i=0}^{N-1} A^{N-1-i} B u_i \end{aligned}$$

写成矩阵形式:

$$\mathbf{x} = \mathcal{A} x_0 + \mathcal{B} \mathbf{u}$$

其中:

$$\mathcal{A} = \begin{bmatrix} A \\ A^2 \\ \vdots \\ A^N \end{bmatrix},\quad \mathcal{B} = \begin{bmatrix} B & 0 & \cdots & 0 \\ AB & B & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ A^{N-1}B & A^{N-2}B & \cdots & B \end{bmatrix}$$

这是 MPC 最重要的一组公式。必须亲手推一遍,理解每个矩阵块的来龙去脉。

练习:对 SISO 系统 \(A=[1,1;0,1], B=[0.5;1], N=3\),手写出 \(\mathcal{A}\) 和 \(\mathcal{B}\)。再用 Python 的 `np.linalg.matrix_power` 验证。

2.2 QP 矩阵组装

把代价函数写成标准 QP 形式,这是 MPC 工程的精髓。

标准代价函数

$$J = \sum_{i=0}^{N-1} \left( x_i^T Q x_i + u_i^T R u_i \right) + x_N^T P x_N$$

步骤1:定义块对角权重矩阵

$$\bar{Q} = \text{blockdiag}(Q, Q, \ldots, Q, P),\quad \bar{R} = \text{blockdiag}(R, R, \ldots, R)$$

步骤2:代入预测方程 \(\mathbf{x} = \mathcal{A}x_0 + \mathcal{B}\mathbf{u}\)

$$\begin{aligned} J &= (\mathcal{A}x_0 + \mathcal{B}\mathbf{u})^T \bar{Q} (\mathcal{A}x_0 + \mathcal{B}\mathbf{u}) + \mathbf{u}^T \bar{R} \mathbf{u} \\ &= \mathbf{u}^T (\mathcal{B}^T \bar{Q} \mathcal{B} + \bar{R}) \mathbf{u} + 2 x_0^T \mathcal{A}^T \bar{Q} \mathcal{B} \mathbf{u} + x_0^T \mathcal{A}^T \bar{Q} \mathcal{A} x_0 \end{aligned}$$

步骤3:得到标准 QP:

$$\min_{\mathbf{u}} \frac{1}{2} \mathbf{u}^T H \mathbf{u} + f^T \mathbf{u}$$ $$H = 2(\mathcal{B}^T \bar{Q} \mathcal{B} + \bar{R}), \quad f = 2 \mathcal{B}^T \bar{Q} \mathcal{A} x_0$$

常数项 \(x_0^T \mathcal{A}^T \bar{Q} \mathcal{A} x_0\) 与优化变量无关,直接省略。

⚠️
常见坑:不同教科书/代码中 H 前面的 1/2 因子处理方式不同。有的定义 \(J = \frac{1}{2} u^T H u + f^T u\),有的直接用 \(J = u^T H u + f^T u\)。使用 QP 求解器时要看清其标准形式。

2.3 约束处理

这是 MPC 相对于 LQR 的核心优势。

输入约束

$$u_{\min} \leq u_i \leq u_{\max} \quad \Rightarrow \quad \begin{bmatrix} -I \\ I \end{bmatrix} \mathbf{u} \leq \begin{bmatrix} -u_{\min}\mathbf{1} \\ u_{\max}\mathbf{1} \end{bmatrix}$$

状态约束(通过预测矩阵转化):

$$x_{\min} \leq x_i \leq x_{\max} \quad \Rightarrow \quad \begin{bmatrix} -\mathcal{B} \\ \mathcal{B} \end{bmatrix} \mathbf{u} \leq \begin{bmatrix} \mathcal{A}x_0 - x_{\min}\mathbf{1} \\ x_{\max}\mathbf{1} - \mathcal{A}x_0 \end{bmatrix}$$

变化率约束

$$\Delta u_{\min} \leq u_i - u_{i-1} \leq \Delta u_{\max}$$

软约束:当硬约束导致 QP 无解时,引入松弛变量:

$$J_{\text{soft}} = J + \rho \epsilon^2,\quad x_{\min} - \epsilon \leq x_i \leq x_{\max} + \epsilon$$

2.4 从零手写 MPC

这是最重要的环节。用 Python + OSQP 或 cvxpy 写一个能跑的 MPC。

手写线性 MPC — 双积分器示例Python
import numpy as np
import cvxpy as cp

# 系统:双积分器 x = [p, v], u = a
dt = 0.1
A = np.array([[1, dt], [0, 1]])
B = np.array([[0.5*dt**2], [dt]])

# MPC 参数
N = 10  # 预测时域
Q = np.diag([10, 1])  # 状态权重
R = np.array([[0.1]]) # 控制权重
P = np.diag([100, 10]) # 终端权重

# 约束
u_max, u_min = 1, -1
x_max, x_min = np.array([5, 5]), np.array([-5, -5])

def solve_mpc(x0):
    x = cp.Variable((2, N+1))
    u = cp.Variable((1, N))

    cost = 0
    constraints = [x[:, 0] == x0]

    for i in range(N):
        cost += cp.quad_form(x[:, i], Q) + cp.quad_form(u[:, i], R)
        constraints += [x[:, i+1] == A @ x[:, i] + B @ u[:, i]]
        constraints += [u_min <= u[:, i], u[:, i] <= u_max]
        if i > 0:
            constraints += [x_min <= x[:, i], x[:, i] <= x_max]
    cost += cp.quad_form(x[:, N], P)
    constraints += [x_min <= x[:, N], x[:, N] <= x_max]

    prob = cp.Problem(cp.Minimize(cost), constraints)
    prob.solve(solver=cp.OSQP, warm_start=True)
    return u.value[:, 0], x.value, u.value
进阶练习
1. 去掉 cvxpy,直接用 `scipy.optimize.minimize` 或手写 QP 矩阵调用 OSQP
2. 加入参考轨迹跟踪(不再是调节到原点)
3. 加入干扰项,观察 MPC 的鲁棒性
4. 对比不同 N(预测时域)对控制效果的影响

2.5 自查清单

3 第三层:NMPC 进阶(2-3 周)

当系统有强非线性时(倒立摆大角度摆动、机械臂、飞行器),线性 MPC 不够用,需要 NMPC。

3.1 非线性模型处理

NMPC 问题

$$\min_{u_0,\ldots,u_{N-1}} \sum_{i=0}^{N-1} \ell(x_i, u_i) + V_f(x_N)$$ $$\text{s.t. } x_{i+1} = f(x_i, u_i),\; x_0 = x(t_k),\; x_i \in \mathcal{X},\; u_i \in \mathcal{U}$$

由于 \(f\) 是非线性的,QP 不再适用。需要求解非线性规划(NLP)。

三种主流方法

📉

直接配点法 (Direct Collocation)

同时离散化状态和控制轨迹,用分段多项式逼近状态轨迹

🔄

多重打靶法 (Multiple Shooting)

将轨迹分段,每段的起点作为决策变量,加连续性约束

实时迭代 (RTI)

每步只做一次 SQP 迭代,牺牲精度换实时性

💡
工程建议:大多数情况下用多重打靶法 + SQP 就够了。实时性要求高时用 RTI。

3.2 NLP 求解算法

NMPC 的核心求解器:

算法原理优缺点
SQP(序列二次规划)每步将 NLP 近似为 QP,迭代求解 QP 序列收敛快,适合中等规模;需精确梯度
内点法 (IPOPT)引入障碍函数,在可行域内部搜索大规模问题效果好;热启动不如 SQP
Real-Time Iteration每步只做一次 SQP,用热启动加速极快,适合实时 NMPC;精度略低

3.3 从零手写 NMPC

手写 NMPC — 倒立摆示例(简化)Python + CasADi
import casadi as ca
import numpy as np

# 倒立摆非线性模型 (x = [theta, omega])
def pendulum_dynamics(x, u):
    g, L, m, b = 9.81, 1.0, 1.0, 0.1
    theta, omega = x[0], x[1]
    dtheta = omega
    domega = (g/L)*ca.sin(theta) + (1/(m*L**2))*u[0] - (b/m)*omega
    return ca.vertcat(dtheta, domega)

# RK4 离散化
def rk4_step(x, u, dt):
    k1 = pendulum_dynamics(x, u)
    k2 = pendulum_dynamics(x + dt/2*k1, u)
    k3 = pendulum_dynamics(x + dt/2*k2, u)
    k4 = pendulum_dynamics(x + dt*k3, u)
    return x + dt/6*(k1 + 2*k2 + 2*k3 + k4)

# 构建 NMPC
N, dt = 10, 0.05
x_sym = ca.MX.sym('x', 2)  # 符号变量
u_sym = ca.MX.sym('u', 1)
F = ca.Function('F', [x_sym, u_sym], [rk4_step(x_sym, u_sym, dt)])

opti = ca.Opti()  # NLP 问题
X = opti.variable(2, N+1)
U = opti.variable(1, N)

# 代价
Q, R = ca.diag([10, 1]), ca.diag([0.1])
cost = 0
for i in range(N):
    cost += X[:, i].T @ Q @ X[:, i] + U[:, i].T @ R @ U[:, i]
cost += X[:, N].T @ ca.diag([100, 10]) @ X[:, N]
opti.minimize(cost)

# 约束
opti.subject_to(X[:, 0] == [0.5, 0])  # 初始角度 0.5 rad
for i in range(N):
    opti.subject_to(X[:, i+1] == F(X[:, i], U[:, i]))
    opti.subject_to(U[:, i] <= 2)
    opti.subject_to(U[:, i] >= -2)

opti.solver('ipopt')
sol = opti.solve()
u_opt = sol.value(U[:, 0])

3.4 MPC vs NMPC 对比实验

同一个倒立摆系统,分别用线性 MPC(在平衡点线性化)和 NMPC 控制,对比效果:

线性 MPC(小角度) 参考 MPC 响应 初始角度 0.1 rad(线性化有效) 线性 MPC(大角度) 参考 MPC 发散/振荡 初始角度 0.8 rad(线性化误差大) NMPC 在大角度下仍能稳定跟踪(无需线性化近似) 但每步计算时间从 MPC 的 <1ms 增加到 NMPC 的 10-100ms

3.5 自查清单

4 第四层:深入理论(可选)

第四层是学术研究方向的进阶内容。如果你只是为了工程应用,第三层已经足够。

4.1 稳定性证明

MPC 的理论核心:证明闭环系统渐近稳定。

关键定理:如果满足以下条件,MPC 闭环渐近稳定:

  1. 阶段代价 \(\ell(x,u) \geq \alpha(\|x\|)\),正定(只在原点为零)
  2. 终端代价 \(V_f\) 是终端局部控制器 \(\kappa_f(x)\) 的 Lyapunov 函数:
    $$V_f(f(x, \kappa_f(x))) - V_f(x) \leq -\ell(x, \kappa_f(x)), \quad \forall x \in \mathcal{X}_f$$
  3. 终端约束集 \(\mathcal{X}_f\) 是 \(\kappa_f\) 的控制不变集
  4. 初始时刻优化问题可行

证明思路:以最优代价 \(V_N^*(x_k)\) 作为 Lyapunov 候选函数,证明沿闭环轨迹单调下降:

$$V_N^*(x_{k+1}) - V_N^*(x_k) \leq -\ell(x_k, u_k^*) \leq -\alpha(\|x_k\|)$$

这保证 \(x_k \to 0\)(渐近稳定)。

4.2 鲁棒 MPC

当系统存在模型不确定性或外部扰动时:

方法思想计算量
Min-Max MPC在最坏扰动下优化极高(双层优化)
Tube MPC使用名义系统 + 反馈管(不变集)中等(离线算管,在线优化名义系统)
随机 MPC概率约束代替确定性约束中等
💡
Tube MPC 直观理解:相当于让名义轨迹在一个"管道"中运行,真实状态被反馈控制器约束在管道内。在线只需要优化管道中心线的名义轨迹。

4.3 其他高级专题

🏃

显式 MPC (Explicit MPC)

离线计算参数化 QP 的解分区,在线查表。适合嵌入式系统。

🔄

经济 MPC (Economic MPC)

代价函数直接使用经济指标(利润、能耗),而非跟踪误差。

🎶

学习 MPC (Learning MPC)

结合机器学习在线更新模型(Gaussian Process, LSTM, Koopman)

🧩

分布式 MPC (DMPC)

大规模系统分解为多个子系统,各自运行 MPC 并通信协调。

📅 5. 学习计划与资源

5.1 建议时间线

第1层 (2-3周) 第2层 (3-4周) 第3层 (2-3周) 第4层 (可选) → 继续 第1-2周 状态空间 + LQR 第3-4周 离散化 + Kalman 第5-6周 预测方程 + QP 组装 第7-8周 NMPC + CasADi 关键产出物 你的 GitHub 上应有 3 个仓库 1. LQR 仿真 / 2. 线性 MPC / 3. NMPC 致命错误 只看书不写代码 永远学不会

5.2 推荐书目(按优先级)

书名作者难度推荐理由
Model Predictive ControlKouvaritakis & Cannon入门最友好的 MPC 入门书,篇幅适中,有 Matlab 代码
Predictive Control with MATLAB王谨入门MATLAB 实现为主,适合中国读者,实用性强
Model Predictive Control: Theory and DesignRawlings, Mayne & Diehl进阶MPC 圣经,理论完整但难度大。作为参考书而非入门书
Nonlinear Model Predictive ControlGrüne & Pannek进阶NMPC 的全面教材,配 Python 代码
Optimal ControlKirk基础最优控制经典教材,帮你理解变分法/Pontryagin 基础
⚠️
不推荐:初学就啃 Rawlings 大部头。应该先看 Kouvaritakis(150页),跑通代码后再读 Rawlings 深入理论。

5.3 代码资源

资源语言说明
do-mpcPython完整的 MPC/NMPC 工具箱,包含仿真器和求解器
CasADiPython/MATLAB符号 NLP 建模 + IPOPT/ACADOS 求解
OSQPPython/C嵌入式友好的 QP 求解器
ACADOSC/Python/MATLAB专为 NMPC 设计的高效求解器,支持 RTI
MPC.jlJuliaJulia 生态的 MPC 库

5.4 学习工具对比

Matlab/Simulink MPC Toolbox

  • 自带 `mpc` 函数,一行命令建 MPC
  • 优点:上手快,可视化好
  • 缺点:黑箱 —— 你不知道底层 QP 怎么构造的
  • 建议:用来验证,别用来学习核心原理

Python (cvxpy/OSQP/CasADi)

  • 手写每个矩阵,完全透明
  • 优点:真正理解每行公式
  • 缺点:需要自己处理所有细节
  • 建议:学习阶段用 Python,工作后用专用工具箱
最佳实践
1. 学习阶段:Python + cvxpy 手写(理解原理)
2. 验证阶段:Matlab MPC Toolbox(对照验证自己的实现)
3. 部署阶段:C++ / ACADOS / qpOASES(工业级性能)

6. 常见问题

Q1: 先学 LQR 还是直接学 MPC?

必须先学 LQR。MPC 的代价函数就是 LQR 的截断版本,终端代价 P 来自 Riccati 方程。没有 LQR 基础,你无法理解为什么 Q,R,P 要满足那些矩阵要求,也无法理解为什么加了终端代价就能保证稳定性。

Q2: 为什么我写的 MPC 仿真发散?

常见原因:
1. 预测时域 N 太小(无法"看到"稳定趋势)
2. 终端代价 P 没有正确设定(用 ARE 求解)
3. 离散化步长太大
4. 约束过于激进导致 QP 无解(引入软约束)
5. 模型与实际系统严重不匹配

Q3: 预测时域 N 选多大?

经验法则:
- N 应覆盖系统主导时间常数的 2-3 倍
- 对振荡系统,N 应覆盖至少半个振荡周期
- 从 N=10 开始调试,观察闭环响应
- N 越大越稳定,但计算越慢

Q4: NMPC 什么时候必须用?什么时候线性 MPC 就够?

线性 MPC 够用:系统工作点变化小、非线性弱(温度控制、液位控制、小角度运动)
必须 NMPC:系统大范围运动(机械臂全范围运动、飞行器姿态大机动)、强非线性(化学反应、生物过程)
折中方案:LTV MPC(在线线性化),精度介于两者之间,计算量接近线性 MPC。

Q5: 需要懂多少数学才能学好 MPC?

最低要求:线性代数(矩阵运算、特征值)、基本控制理论(状态空间、能控性)、基本优化(凸优化、QP)
深入需要:Lyapunov 稳定性理论、凸分析、数值优化(SQP、内点法)
实用建议:不需要等数学完美再开始。先跑通代码,遇到看不懂的数学再回头补。工程是数学最好的老师。

Q6: 我想在嵌入式系统上跑 MPC,怎么办?

嵌入式 MPC 的关键限制是计算资源和内存:
1. 使用高效的 QP 求解器(qpoases 的嵌入式版本、OSQP 的 C 版本)
2. 减小预测时域(N=3-5)
3. 使用显式 MPC(EFRAIM B 算法,离线分区在线查表)
4. 代码生成:ACADOS 和 FORCES Pro 支持将 MPC 编译为 C 代码
5. FPGA 实现的 NMPC 已有多篇论文验证

Q7: 代价函数中的 Q,R 矩阵怎么调?

没有标准答案,但有经验法:
1. Bryson's Rule:\(Q_{ii} = 1 / x_{i,\max}^2,\; R_{jj} = 1 / u_{j,\max}^2\)
2. 先只调对角元,对角占优就是够
3. Q/R 比值决定了"控制性能"和"控制能量"的权衡
4. 增加 Q 中的某个元素 → 对应的状态跟踪更紧
5. 增加 R → 控制动作更柔和(更省力)
6. 如果系统振荡,减少 Q 或增加 R

Q8: 学完 MPC 后下一步学什么?

根据你的方向:
- 机器人/自动驾驶:结合非线性优化 + 运动规划(Trajectory Optimization)
- 过程控制:学习经济 MPC + 实时优化(RTO)
- 航空/航天:学习鲁棒 MPC + 制导控制一体化
- AI/ML 方向:学习 Learning-based MPC(Koopman MPC, GP-MPC)
- 学术研究:读 Rawlings + Mayne,关注每年 CDC/ACC/ECC 论文

目录