1. 哈密尔顿函数法到底在补什么先说清楚这篇“补充”的定位。最优控制理论的主线里哈密尔顿函数法几乎是绕不开的关卡但很多教材在讲完基本推导之后就直接跳到例子留下的问题反而最多协态变量的初值怎么猜末端条件到底该套哪一条控制量碰到边界约束时驻点条件为什么突然就失效了这些内容恰恰是实际做课题、写论文、调代码时最容易卡住的地方。我用一个场景来定位这篇内容假设你已经看过最优控制理论的基本章节知道怎么把性能指标、状态方程、哈密尔顿函数写出来也见过几个教科书例题但一遇到自己的工程问题就开始手足无措。那么这篇补充就是给你准备的。它不重复最基础的推导而是把哈密尔顿函数法里最容易被略过、却又最影响求解成败的细节单独拿出来讲透。哈密尔顿函数法解决的核心问题是带微分方程约束的泛函极值问题。说得直白一点就是在系统状态必须满足状态方程的前提下找一条控制轨迹让某个积分型的性能指标最小。这个方法把状态方程当作约束用拉格朗日乘子向量把它“吸收”进性能指标里从而把有约束寻优问题变成无约束寻优问题。从这个角度看它和静态优化里的拉格朗日乘子法是一脉相承的区别在于这里的约束不是代数方程而是逐时刻成立的微分方程所以乘子也从常数变成了时间的函数。这个“乘子随时间变化”就是整个方法的灵魂所在。静态优化里拉格朗日乘子是一个数值而最优控制里协态变量是一条曲线。这条曲线本身没有太直观的物理意义但它的动态行为决定了最优控制律的结构所以几乎所有求解方法都围绕协态方程和横截条件展开。2. 横截条件的工程直觉与速查用法2.1 协态变量到底是个什么东西很多资料把协态变量直接定义为哈密尔顿函数对状态求偏导的结果这个定义严谨但没什么手感。我更习惯把它理解成“目标函数对状态变化的敏感度”。设想你在最优轨迹上往前走某个瞬间如果系统状态被外力推偏了一点点性能指标会恶化多少这个恶化率就是协态变量在当前时刻的取值。这个思路和经济学里的影子价格一模一样——资源的边际价值不是它的市场价格而是它对你最终目标的影响程度。理解了这一点横截条件就不再是死记硬背的公式了。末端状态被严格固定时末端扰动并不存在因为无论怎么扰动状态最终都得回到规定值上目标函数不允许因为末端偏差而变化所以协态变量在末端是自由的。反过来末端状态完全自由时末端偏差会直接进入目标函数如果目标函数对末端状态不敏感那就必然取零于是得到协态变量末端为零的条件。这个对称关系是整张横截条件速查表的内在逻辑。我把几种常见情况整理成了一张表方便对照使用末端状态类型边界条件写法直觉解读末端固定x(T) x_Tλ(T) 自由状态被锁死乘子无需约束末端自由λ(T) 0x(T) 自由末端偏差不惩罚敏感度归零末端受约束等式φ(x(T)) 0λ(T) μ ∂φ/∂x(T)目标与约束在那个点相切末端有限制但允许滑动λ(T) 与约束面垂直扰动顺着约束曲面滑动无代价我在实际课题里遇到最多的情况是第二种末端自由。因为很多控制器设计问题不要求精确落在某个点而是希望“差不多到达目标附近、同时控制能量尽可能小”这时候 λ(T)0 就是最常用的横截条件。2.2 为什么端点条件会差一个符号横截条件推导过程中最容易出错的就是符号。先看性能指标的变分δJ ∫ [∂H/∂x δx ∂H/∂u δu] dt 边界项边界项来源于分部积分仔细做一遍会发现它是 λ(T)ᵀδx(T) − λ(t₀)ᵀδx(t₀) 的形式。如果初端状态已知那么 δx(t₀)0这一项直接消失。末端若是自由的要让 δJ0 对任意的 δx(T) 都成立只能令 λ(T)0。但很多初学者会把负号丢掉结果写成 λ(T)0 之后发现怎么也凑不出正确解。一个非常实用的检查技巧写出哈密尔顿函数之后先把正则方程和目标函数对状态的求导比对一遍然后用“末端自由→λ(T)0末端固定→λ(T)自由”这种极端情况校一遍符号。如果末端自由情况下算出的协态轨迹明显发散那大概率就是正负号方向反了。3. 控制量碰到边界约束时该怎么办3.1 驻点条件失效的那一刻哈密尔顿函数法的标准操作是让 ∂H/∂u 0这个条件来自“控制量在可行域内部时最优解处对控制的一阶变分为零”。但工程问题里控制量几乎都有幅值约束比如电机电流不能无限大、阀门开度只能从0到100%。当最优解恰好落在约束边界上时目标函数沿着可行方向的路已经变成了单侧极值一阶导数为零的条件不再成立因为另一侧的取值根本不允许。这个时候要启用庞特里亚金极小值原理。它的表述是对每一个时刻最优控制 u*(t) 必须让哈密尔顿函数在允许控制集合内取到最小值u*(t) argmin_{u ∈ U} H(x*(t), u, λ*(t), t)这个形式和 ∂H/∂u0 的区别在于它不假设内部极值而是直接做全局搜索。对于一个边界清晰的约束集合最优点往往就出现在边界上这对应工程里大名鼎鼎的 bang-bang 控制。3.2 一个 bang-bang 控制的判断流程以线性系统、控制量约束 |u|≤1、性能指标是最短时间的经典问题为例。哈密尔顿函数写出来之后会发现它关于 u 是线性的∂H/∂u 等于某个与状态和协态有关的系数与 u 本身无关。这个系数就是切换函数。要最小化 H控制量的取值必须和切换函数的符号反着来切换函数为正u 取最小值切换函数为负u 取最大值。实际代码里我会这么处理def optimal_control(switch): if switch 0: return -u_max elif switch 0: return u_max else: return 0 # 奇异情况需要额外讨论这里的 singulary case 是个坑。如果切换函数在某一段区间内恒等于零控制量无法由极小值原理直接确定就进入了所谓的奇异控制区间。遇到这种情况需要继续对切换函数求导直到 u 显式出现再用 ∂²H/∂u² 之类的条件补充求解。很多教材把奇异控制当作高级话题但工程里并不罕见尤其在轨道机动和机械臂时间最优轨迹规划里经常撞上。3.3 奇异控制的检测与处理我自己的经验是遇到奇异情况的概率比你想象的高。处理分三步走第一沿着最优轨迹计算切换函数并检查它是否在一段区间内恒为零第二如果恒为零就对切换函数关于时间连续求导直到推导出 u 的显式表达式第三把求出的奇异控制代回去验证它是否确实让哈密尔顿函数取最小值。这个流程看起来繁琐但在数值求解时非常有用因为很多通用求解器遇到奇异控制会直接不收敛提前识别并单独处理能让收敛速度提升一个量级。4. 哈密尔顿函数不随时间显式变化时的守恒律4.1 一个被忽视的强有力检查工具如果哈密尔顿函数不显式依赖时间 t也就是 ∂H/∂t0那么沿着最优轨迹哈密尔顿函数是常数。这个结论是守恒律的直接推论它的证明只需要对 H 求全导数dH/dt ∂H/∂t ∂H/∂x·ẋ ∂H/∂λ·λ̇ ∂H/∂u·u̇代入正则方程和控制方程交叉项全部抵消只剩下 ∂H/∂t。所以只要 ∂H/∂t0H 沿最优轨迹恒定。很多教材把这个当作一个纯粹的数学结果但它实际上是求解时的免费校验工具。我做过一个最小能量轨迹规划问题性能指标只含控制量的平方积分系统本身是定常的所以 H 应当沿最优轨迹等于常数。我检查数值结果时发现后半段轨迹的 H 值明显偏离了初始值仔细排查后发现是协态方程的数值积分步长太大造成的。把步长减半之后H 常数性质恢复最终结果也合理了。4.2 用守恒律推断最优解的形态守恒律还能用来做定性分析。一个典型的例子是最小能量巡航问题飞行器从一个速度巡航到另一个速度要求在给定时间内到达控制量是推力加速度性能指标是推力平方的积分。哈密尔顿函数不显含时间于是守恒律成立。结合驻点条件可以推出来最优推力剖面的大致形状它往往不是简单常数而是两头大、中间平的形态。如果不借助守恒律这个结论需要解完整的边值问题才能看到而守恒律直接给了先验结构。这个技巧特别适合写论文时的理论分析部分。审稿人看到你不仅给了数值解还能用哈密尔顿函数守恒性解释最优解的形态特征说服力会强很多。5. 线性二次型问题的完整实操示例5.1 问题建模与哈密尔顿函数构造这里给一个可以直接上手算的线性二次型问题。一维系统ẋ a x b u性能指标J ∫₀ᵀ (q x² r u²) dt末端状态自由初始状态给定为 x(0)x₀。这个设定对应的是“有限时间调节器”工程意义是状态偏离零点的惩罚由 q 控制控制能耗的惩罚由 r 控制需要在两者之间取平衡。构造哈密尔顿函数H q x² r u² λ (a x b u)正则方程有两个ẋ ∂H/∂λ a x b u λ̇ −∂H/∂x −2 q x − a λ控制方程来自 ∂H/∂u 02 r u b λ 0 → u −b λ / (2 r)5.2 从协态到状态反馈的推导控制量表达式中含有 λ而 λ 本身是未知的。线性二次型问题有一个很漂亮的结构可以假设 λ 与 x 成线性关系。令λ −2 r P x / b这里 P 是一个待定的时变系数。把这个关系代入控制量表达式得到u −b λ / (2 r) −(b² / (2 r)) · (−2 r P x / b) / 1?这里需要重新整理一下。直接令 u −K x且 K 待定。把 λ −(2 r / b) u −(2 r / b)(−K x) (2 r K / b) x 代入 λ̇ −2 q x − a λ再联立 ẋ (a − bK) x就能推出 K 满足的微分方程。更常规的推导是设 λ −P x代入控制律得 u −(b/(2r))P x −K x即 K bP/(2r)。把 λ −P x 和 ẋ (a − b²P/(2r))x 代入 λ̇ −2qx − aλ注意到 λ̇ −Ṗx − P ẋ整理后得到黎卡提方程Ṗ −2aP − 2q b²P²/(2r)终端条件来自 λ(T) 0因此 P(T)0。这样就把一个两点边值问题转化成单点初值问题的反向积分。5.3 具体数值计算与结果解读给一组非常简单的参数a1, b1, q1, r1, T2, x₀1。黎卡提方程变成Ṗ −2P − 2 P²/2 0.5P² − 2P − 2从 P(2)0 反向积分到 t0。手算不方便我用 Python 写了一个四阶龙格库塔积分import numpy as np def riccati(P, t): return 0.5 * P * P - 2.0 * P - 2.0 def rk4_step(P, t, dt): k1 riccati(P, t) k2 riccati(P 0.5 * dt * k1, t 0.5 * dt) k3 riccati(P 0.5 * dt * k2, t 0.5 * dt) k4 riccati(P dt * k3, t dt) return P dt * (k1 2 * k2 2 * k3 k4) / 6.0 dt 0.01 t 2.0 P 0.0 while t 0: P rk4_step(P, t, -dt) t - dt print(P at t0:, P)用步长 0.01 积分P(0) 大约在 4.472 附近。这和代数黎卡提方程的正定解 √(2q/b² a²) a √3 1 有明显差异原因是有限时域问题的 P(t) 会随时间从 0 逐渐增大到 t0 时已经接近但尚未完全收敛到无穷时域解。这个差异在工程上非常重要它说明控制器增益在初始时刻和末端时刻并不相同时变增益能比恒定增益做得更好。得到 P(t) 后最优控制律可以实时计算 u(t) −[bP(t)/(2r)]x(t)。比如在 t0 时刻 K 1 × 4.472 / (2 × 1) ≈ 2.236初始控制量 u(0) ≈ −2.236×1 −2.236。如果约束是 |u|≤1那么初始最优解超出约束范围实际会贴着边界取 u−1这就是上一节讲的约束边界情况在数值例子中的现身。6. 常见问题速查表与避坑经验哈密尔顿函数法的实现过程中问题往往集中在几步边界条件的设定、协态变量的初值猜测、以及数值积分的稳定性。我把这几年实践中遇到频率最高的坑整理成了一个速查表症状可能原因处理方式末端状态不满足横截条件符号写反用末端自由→λ(T)0 校验逻辑迭代不收敛协态初值猜得太离谱先用 H 守恒律粗筛初值范围控制量反复振荡切换函数在零附近抖动加入滞回或者用较细的时间步长数值解严重依赖步长系统的刚性较高换隐式积分或自适应步长奇异控制被忽略切换函数局部恒等于零对切换函数求导直到导出 u 的显式形式时变增益导致实现复杂与恒定增益混淆先用无限时域代数黎卡提解做对比有一个容易被忽略的实操经验在写数值求解代码前先花十分钟把哈密尔顿函数对时间的导数算一遍。如果 ∂H/∂t0那么 H 沿轨迹恒定这个性质可以在整个求解过程中作为免费的“健康指示灯”。我自己的习惯是每跑完一组参数就把 H(t) 的曲线画出来只要它在中段出现明显的鼓包我就知道数值结果有问题不管最终性能指标长得多么漂亮都要回头查积分精度或边界条件。另一个经验来自协态初值的猜测。协态变量没有直接物理意义初值很难猜很多初学者在这里卡很久。我的做法是先用无约束问题把协态变量的量级跑出来再逐步收缩到实际问题。也就是说先用很大的约束范围甚至不加约束去解一次得到协态变量的量级和大致形状然后用这个结果作为带约束问题的初值。这样一来迭代次数能从几十次降到十次以内稳定性也明显好很多。还有一点关于数值积分方向。协态方程在末端有边界条件、状态方程在初端有边界条件所以标准的策略是反向积分协态方程、正向积分状态方程中间用打靶法迭代。对大多数问题这样做比同时正向积分两条方程要稳定得多。有些人为了省事把协态初值随便设一个然后让求解器自动调结果往往陷入局部极小值或直接发散。7. 哈密尔顿函数法在系列课程中的真正价值回到系列课程的语境里哈密尔顿函数法从来不是孤立的工具它是连接变分法、庞特里亚金极小值原理和动态规划的桥梁。变分法提供了一阶必要条件哈密尔顿函数法给出了这些条件在控制问题中的具体形态而极小值原理把适用范围扩展到了带约束的工程问题动态规划则从全局最优性的角度给出了充分性的保障。四个工具放在一起才能构成完整的最优控制方法论。我接触过不少初学者学了哈密尔顿函数法之后就开始套公式遇到带约束问题就不知所措。如果能把这一篇里讲的几个补充点真正吸收——横截条件的物理含义、约束边界的处理、守恒律的校验技巧、线性二次问题的完整推导——那么后续再看动态规划、鲁棒控制、模型预测控制都会顺畅很多。这个系列写到这里最想传达的其实不是某个具体公式而是一种工作方式拿到一个最优控制问题先别急着上求解器而是把哈密尔顿函数写出来把协态变量的大致行为想明白把边界条件逐一确认再用数值工具去补足最后一步。这种“先分析后计算”的习惯才是哈密尔顿函数法教给我最值钱的东西。