Interview(MPC)
MPC相关

MPC的本质是什么?

MPC的典型优化过程是什么?

基于OSQP求解器的MPC优化过程是什么?

一、MPC问题到QP问题的转换

Model Predictive Control的典型形式:

\[\begin{aligned} \min_{x_k,u_k}\quad & (x_N-x_r)^\top Q_N (x_N-x_r) + \sum_{k=0}^{N-1} (x_k-x_r)^\top Q (x_k-x_r) + u_k^\top R u_k \\ \text{s.t.}\quad & x_{k+1} = A x_k + B u_k, \\ & x_{\min} \le x_k \le x_{\max}, \\ & u_{\min} \le u_k \le u_{\max}, \\ & x_0 = \bar{x}. \end{aligned}\]

标准QP形式:

\[\begin{aligned} \text{minimize}\quad & \tfrac{1}{2} z^\top P z + q^\top z \\ \text{subject to}\quad & l \le A_c\, z \le u \end{aligned}\]

其中,策变量按时间堆叠为$z = [x_0^\top,x_1^\top,\dots,x_N^\top,u_0^\top,\dots,u_{N-1}^\top]^\top$。

Hessian:$P$

\[P = \mathrm{diag}(Q,\,Q,\,\dots,\,Q_N,\,R,\,\dots,\,R)\]

Gradient:$q$

\[q = \begin{bmatrix} - Q x_r \\ - Q x_r \\ \vdots \\ - Q_N x_r \\ 0 \\ \vdots \\ 0 \end{bmatrix}\]

前面$N+1$个块对应状态项的线性项(一次项,也就是MPC代价函数乘开后获得的值),后面对应控制输入的零项。

线性约束矩阵:$A_c$

按示例构造的稀疏块矩阵(等式动力学 + 状态/输入的直接投影):

\[A_c = \left[ \begin{array}{ccccc|cccc} -I & 0 & 0 & \cdots & 0 & 0 & 0 & \cdots & 0\\ A & -I & 0 & \cdots & 0 & B & 0 & \cdots & 0\\ 0 & A & -I & \cdots & 0 & 0 & B & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & -I & 0 & 0 & \cdots & B\\ \hline I & 0 & 0 & \cdots & 0 & 0 & 0 & \cdots & 0\\ 0 & I & 0 & \cdots & 0 & 0 & 0 & \cdots & 0\\ 0 & 0 & I & \cdots & 0 & 0 & 0 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & I & 0 & 0 & \cdots & 0\\ 0 & 0 & 0 & \cdots & 0 & I & 0 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots & \ddots & \vdots \end{array} \right]\]

下界与上界:$l,u$

示例中将等式约束(初始条件)与不等式约束(状态/输入上下界)合并为:

\[\begin{aligned} l &= \begin{bmatrix} - x_0 \\ 0 \\ \vdots \\ 0 \\ x_{\min} \\ \vdots \\ x_{\min} \\ u_{\min} \\ \vdots \\ u_{\min} \end{bmatrix}, \qquad u = \begin{bmatrix} - x_0 \\ 0 \\ \vdots \\ 0 \\ x_{\max} \\ \vdots \\ x_{\max} \\ u_{\max} \\ \vdots \\ u_{\max} \end{bmatrix} \end{aligned}\]

二、QP问题在OSQP中的求解。

x-update

在 ADMM 的每次迭代中,OSQP的x-update要求解下面的最小化问题:

\[x^{k+1} = \arg\min_x \left( \frac{1}{2} x^\top H x + g^\top x + \frac{\rho}{2}\|Ax - (z^k - u^k)\|^2 \right)\]

这是一个标准的二次优化问题。对其求导并令梯度为零即可得到线性系统:

\[(H + \rho A^\top A)x^{k+1} = -g + \rho A^\top (z^k - u^k)\]

因此x-update 的本质就是解一个线性方程

\[Mx = q, \qquad M = H + \rho A^\top A,\ q = -g + \rho A^\top (z^k - u^k)\]

为了加速求解,OSQP 会在初始化时对矩阵 $M$(或更大的 KKT 系统)执行一次稀疏的LDLᵀ(KKT)分解
这样后续每次迭代只需进行快速的前代与回代即可求得 $x^{k+1}$,无需重新分解矩阵。

OCS2中的SQP优化过程是什么?

零、在第$k$次迭代中

  1. 线性化 dynamics 和 constraints
  2. 二次近似 cost
  3. 得到一个 quadratic program (QP)
  4. 求解 QP 得到一个 增量方向
  5. 更新轨迹,重复迭代

一、给定初始控制序列 $u_{0:N-1}$

通常来自:

二、Forward Rollout —— 生成名义轨迹

基于系统动力学: \(\dot{x}(t) = f(x(t), u(t))\)

从初始状态 $x_0$ 前向积分:

\(x_{k+1} = x_k + \int_0^{\Delta t} f(x(t), u_k)\, dt\)

注:OCS2中的积分实际上主要是直接加,RK4都没用,这可能是导致他性能不佳的原因。

得到名义轨迹: \(\{x_k, u_k\}_{k=0}^{N}\)

此轨迹满足动力学,用于后续线性化。

三、对动力学与成本函数进行二阶泰勒展开(Local Bellman Expansion)

动力学线性化:

\(\delta x_{k+1} \approx A_k \delta x_k + B_k \delta u_k\)

其中: \(A_k = \frac{\partial f}{\partial x}\Big|_{x_k,u_k}, \qquad B_k = \frac{\partial f}{\partial u}\Big|_{x_k,u_k}\)

Cost 二阶展开:

$$ \ell(x_k,u_k) \approx \ell_k

终端成本同理展开。

四、构造等效的 Quadratic Program (QP)

目标为: \(\min_{\delta x,\delta u} \sum_{k=0}^{N-1} \left( \frac12 \begin{bmatrix}\delta x_k \\ \delta u_k\end{bmatrix}^\top H_k \begin{bmatrix}\delta x_k \\ \delta u_k\end{bmatrix} + g_k^\top \begin{bmatrix}\delta x_k \\ \delta u_k\end{bmatrix} \right) + \frac12 \delta x_N^\top Q_N \delta x_N + q_N^\top\delta x_N\)

约束为线性化动力学: \(\delta x_{k+1} = A_k \delta x_k + B_k \delta u_k\)


五、用 Riccati-like backward sweep 求解 QP(也称 LQ Optimal Control)

利用动态规划,做一次 backward pass:

value function:

\(V_k(\delta x_k) = \frac12 \delta x_k^\top S_k \delta x_k + s_k^\top \delta x_k\)

Riccati 递推:

\(K_k = -(R_k + B_k^\top S_{k+1} B_k)^{-1}(P_k^\top + B_k^\top S_{k+1} A_k)\)

\[d_k = -(R_k + B_k^\top S_{k+1} B_k)^{-1}(r_k + B_k^\top s_{k+1})\]

更新: \(S_k = Q_k + A_k^\top S_{k+1} A_k + K_k^\top(R_k + B_k^\top S_{k+1}B_k)K_k\)

\[s_k = q_k + A_k^\top s_{k+1} + K_k^\top (R_k + B_k^\top S_{k+1}B_k)d_k\]

最终得到控制修正: \(\delta u_k = K_k\, \delta x_k + d_k\)


更新控制: \(u_k^{new} = u_k + \alpha \, \delta u_k\)

其中 $\alpha \in (0,1]$ 由 line search 确定,以保证成本下降。


七、重复迭代直到收敛

判断条件:

然后输出:

SQP中Riccati backward/forward pass 的具体步骤

A. 目标(Purpose)

在 SQP/ILQR 中,当我们把原非线性问题在第 $k$ 次迭代近似为线性动力学 + 二次代价(LQ subproblem)时,可以通过 Riccati backward recursion 求出局部最优控制增量: \(\delta u_i = k_i + K_i\,\delta x_i\) 其中:

该策略确保 LQ 子问题的 精确最优解,并具有线性复杂度 $O(N)$(对 horizon $N$)。


B. 局部增量代价定义(Quadratic approximation)

定义状态与控制的增量: \(\delta x_i = x_i - x_{k,i}, \quad \delta u_i = u_i - u_{k,i}.\)

二次近似的阶段代价写为: \(\ell_i(\delta x_i,\delta u_i) \approx \frac{1}{2} \begin{bmatrix} \delta x \\ \delta u \end{bmatrix}^\top \begin{bmatrix} Q_{xx} & Q_{xu} \\ Q_{ux} & Q_{uu} \end{bmatrix} \begin{bmatrix} \delta x \\ \delta u \end{bmatrix} + \begin{bmatrix} q_x \\ q_u \end{bmatrix}^\top \begin{bmatrix} \delta x \\ \delta u \end{bmatrix}.\)

动力学线性化: \(\delta x_{i+1} = A_i\,\delta x_i + B_i\,\delta u_i + d_i.\)

最终代价: \(V_N(\delta x_N)= \frac12\, \delta x_N^\top V_{xx,N}\,\delta x_N + V_{x,N}^\top \delta x_N.\)


C. Q-function(Bellman 局部展开)

定义: $$ Q_i(\delta x_i,\delta u_i) = \ell_i(\delta x_i,\delta u_i)

代入值函数二次形式,可得: $$ Q(\delta x,\delta u) = \frac12 \begin{bmatrix} \delta x\ \delta u \end{bmatrix}^\top \begin{bmatrix} Q_{xx}^Q & Q_{xu}^Q
Q_{ux}^Q & Q_{uu}^Q \end{bmatrix} \begin{bmatrix} \delta x\ \delta u \end{bmatrix} + \begin{bmatrix} Q_x^Q\ Q_u^Q \end{bmatrix}^\top \begin{bmatrix} \delta x\ \delta u \end{bmatrix}

其中(常见计算公式): \(\begin{aligned} Q_{xx}^Q &= Q_{xx} + A_i^\top V_{xx,i+1} A_i, \\ Q_{uu}^Q &= Q_{uu} + B_i^\top V_{xx,i+1} B_i, \\ Q_{ux}^Q &= Q_{ux} + B_i^\top V_{xx,i+1} A_i, \\ Q_x^Q &= q_x + A_i^\top (V_{xx,i+1} d_i + V_{x,i+1}), \\ Q_u^Q &= q_u + B_i^\top (V_{xx,i+1} d_i + V_{x,i+1}). \end{aligned}\)


D. 求解局部最优控制增量(optimal $\delta u$)

对 $Q$ 关于 $\delta u$ 求导并置零: \(\frac{\partial Q}{\partial \delta u} = Q_{uu}^Q\,\delta u + Q_{ux}^Q\,\delta x + Q_u^Q = 0.\)

若 $Q_{uu}^Q$ 正定,可以得到: \(\delta u = k_i + K_i\delta x,\) 其中: \(k_i = - (Q_{uu}^Q)^{-1} Q_u^Q,\qquad K_i = - (Q_{uu}^Q)^{-1} Q_{ux}^Q.\)

数值上必须保证 $Q_{uu}^Q$ 正定,否则要做正则化
$Q_{uu}^Q \leftarrow Q_{uu}^Q + \lambda I$(Levenberg–Marquardt 样式)。


E. 值函数更新(Value function recursion)

将最优 $\delta u$ 代入 $Q$,得到新的时刻值函数: \(V_{xx,i} = Q_{xx}^Q + Q_{xu}^Q K_i,\) \(V_{x,i} = Q_x^Q + Q_{xu}^Q k_i.\)

这完成了一个时间步的 backward 递推。

Backward pass 从 $i=N-1$ 递推到 $i=0$:

# backward pass
V_x  = V_x_terminal
V_xx = V_xx_terminal

for i = N-1 ... 0:
    # build Q terms
    Q_xx, Q_uu, Q_ux, Q_x, Q_u = compute_Q_terms(A_i, B_i, V_xx, V_x)

    # regularize for positive-definite
    Q_uu = Q_uu + lambda * I

    # compute gains
    k_i = - inv(Q_uu) * Q_u
    K_i = - inv(Q_uu) * Q_ux

    # update value function
    V_x  = Q_x  + Q_xu * k_i
    V_xx = Q_xx + Q_xu * K_i

F. Forward pass(利用策略生成新轨迹)

向前滚动,用新的策略更新控制与状态:

x = x0
for i = 0 ... N-1:
    delta_x = x - x_nom[i]
    delta_u = k_i + K_i * delta_x
    u_new   = u_nom[i] + alpha * delta_u   # alpha: line search

    x = integrate_forward(x, u_new)        # ODE solver

Forward pass 的主要作用:

得到新的名义轨迹

评估真实 cost / KKT violation 是否下降

为下一次迭代提供线性化基点

*****
Written by Motaquillah Maddane on 23 November 2025