一、最优控制理论回顾:变分法基础、庞特里亚金极小值原理、动态规划与HJB方程

各位同学,欢迎来到《最优制导律数值求解与代码实现》的第一章。

说实话,做制导控制这些年,我最大的体会是:最优控制理论不是一堆数学公式,而是我们设计“聪明”导弹的底层逻辑。你想想看,一枚导弹要拦截高速目标,怎么飞最省燃料?怎么转弯最敏捷?这些问题,归根结底都要回到我们今天要讲的这三个核心工具上。

我个人习惯把这一章叫做“工具箱”。变分法是螺丝刀,极小值原理是扳手,动态规划和HJB方程则是那把多功能瑞士军刀。咱们一个一个拆开看。

1.1 变分法基础:从“求极值”到“求轨迹”

咱们先从一个简单问题入手。普通函数求极值,你肯定熟悉——导数等于零。但最优控制里,我们要求的是一条轨迹,而不是一个点。

举个例子。你从A点开车到B点,想找一条时间最短的路径。这不是找一个坐标,而是找一条曲线。变分法就是干这个的。

核心思想其实就一句话:让性能指标J的“一阶变分”等于零

数学上,我们定义性能指标:

J = ∫ L(x, u, t) dt

其中L是拉格朗日函数,x是状态,u是控制。

变分法给出的必要条件——欧拉-拉格朗日方程:

∂L/∂x - d/dt(∂L/∂ẋ) = 0

嗯,这里要注意。这个方程只适用于无约束的情况。我在项目中遇到过有人直接拿它去解带控制约束的问题,结果算出来的轨迹根本不可行。为什么?因为导弹的舵面偏转角是有极限的,你不能让它转180度。

避坑指南: 我曾经在某个项目中,用变分法直接求解一个带饱和约束的制导问题,结果仿真时控制量一直超出限幅。后来才意识到,变分法处理不了不等式约束。这时候,就得请出庞特里亚金了。

1.2 庞特里亚金极小值原理:带约束的“最优开关”

庞特里亚金极小值原理(PMP),说白了就是变分法的“升级版”。它最大的贡献是:能处理控制有约束的情况

核心思路是引入协态变量λ(t)和哈密顿函数H:

H = L(x, u, t) + λᵀ · f(x, u, t)

然后最优控制u*必须满足:

H(x*, u*, λ*, t) ≤ H(x*, u, λ*, t)  对所有允许的u成立

这句话翻译成人话就是:在最优轨迹上,哈密顿函数取最小值。这就是“极小值”这个名字的由来。

我个人的经验是,PMP特别适合处理“bang-bang控制”问题。比如导弹在末端需要大过载机动,这时候控制量往往直接打到边界上。用PMP,你能清晰地看到什么时候该“开”,什么时候该“关”。

来看一个简单的代码示例,用数值方法求解一个带约束的最优控制问题:

import numpy as np
from scipy.optimize import minimize

# 定义系统动力学:dx/dt = u,控制约束 |u| ≤ 1
def dynamics(x, u):
    return u

# 定义哈密顿函数
def hamiltonian(x, u, lam):
    return 0.5 * u**2 + lam * u

# 数值求解协态方程
def solve_costate(x_history, u_history, dt):
    lam = np.zeros_like(x_history)
    lam[-1] = 0  # 终端条件
    for i in range(len(x_history)-2, -1, -1):
        # 协态方程:dλ/dt = -∂H/∂x = 0 (本例中H不显含x)
        lam[i] = lam[i+1]
    return lam

# 极小值条件:u* = -sat(λ)  (饱和函数)
def optimal_control(lam):
    u = -lam
    u = np.clip(u, -1.0, 1.0)  # 约束处理
    return u
个人技巧: 我建议你在写PMP求解代码时,先把哈密顿函数写清楚,再写协态方程。很多初学者搞反了顺序,结果符号搞错,仿真直接发散。

1.3 动态规划与HJB方程:从“全局最优”到“实时决策”

动态规划的思路很朴素:如果一个问题可以分解成子问题,那么最优策略的子策略也是最优的。这就是贝尔曼最优性原理。

但直接做动态规划有个致命问题——维度灾难。状态空间稍微大一点,网格就爆炸了。我记得有一次做三维制导问题,状态变量有6个,每个方向分100个网格,你猜内存要多大?根本算不动。

于是就有了HJB方程。它是动态规划的连续形式:

-∂V/∂t = min_u { L(x, u, t) + (∂V/∂x)ᵀ · f(x, u, t) }

其中V(x,t)是值函数,表示从当前状态到终点的最优代价。

HJB方程是个偏微分方程,解析解很难求。但在制导领域,我们经常用数值方法来近似求解。比如用有限差分法或者神经网络逼近。

下面是一个简单的值函数迭代代码框架:

import numpy as np

# 离散化状态空间
x_grid = np.linspace(-5, 5, 101)
V = np.zeros_like(x_grid)  # 初始猜测

# 迭代求解HJB方程
for iteration in range(100):
    V_new = V.copy()
    for i, x in enumerate(x_grid):
        # 对每个状态,搜索最优控制
        best_value = np.inf
        for u in [-1.0, 0.0, 1.0]:  # 离散控制集
            # 计算下一步状态(简单欧拉法)
            x_next = x + u * 0.1
            # 找到x_next对应的网格索引
            j = np.argmin(np.abs(x_grid - x_next))
            # 计算代价
            cost = 0.5 * u**2 * 0.1 + V[j]
            if cost < best_value:
                best_value = cost
        V_new[i] = best_value
    V = V_new

print("值函数迭代完成")
核心要点: 动态规划是“离线计算,在线查表”。HJB方程则是“在线求解,实时决策”。在实际工程中,我更倾向于用HJB方程的数值解作为制导律的基准,再用PMP做精细调整。

1.4 三者的关系与选择

讲了这么多,你可能有点晕。这三个工具到底什么时候用哪个?

我画了一张图,帮你理清思路:

变分法 无约束问题 欧拉-拉格朗日方程 解析解为主 庞特里亚金极小值原理 有约束问题 哈密顿函数极小化 数值求解为主 动态规划 / HJB 全局最优 值函数迭代 离线/在线结合 工程应用中的选择逻辑 1. 问题有无控制约束? 无 → 变分法(解析解) 有 → PMP(数值解) 2. 是否需要全局最优? 是 → 动态规划/HJB 否 → PMP(两点边值问题)

我个人在实际项目中的做法是:先用动态规划的思路理解问题结构,再用PMP写出必要条件,最后用数值方法求解。这三者不是互斥的,而是互补的。

一个实用建议: 如果你刚开始学,我建议你先从PMP入手。为什么?因为它在工程中最常用,而且数值求解方法相对成熟。变分法太理想化,HJB方程又太难算。PMP是“性价比”最高的。

好了,这一章的内容就到这里。记住这三个工具的名字和适用场景,后面几章我们会反复用到它们。


公众号:蓝海资料掘金营,微信deep3321