ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

哈密尔顿函数法详解:从变分法到最优控制的核心框架

哈密尔顿函数法详解:从变分法到最优控制的核心框架 1. 为什么讲完变分法还要单独补一节哈密尔顿函数先说结论哈密尔顿函数法是整个最优控制理论里最值得反复抄写的一页笔记。最近在整理“最优控制理论”系列二这一讲本来是上一讲变分法的补充结果越写越觉得它才真正的主线。很多人学到这里会有个困惑上一讲用变分法求泛函极值已经推导出欧拉-拉格朗日方程了为什么还要重新定义一个哈密尔顿函数甚至有些教材把它放在庞特里亚金极大值原理里一闪而过导致初学者觉得这只是一个数学技巧。实际上哈密尔顿函数法不只是“技巧”它是把带状态方程约束的泛函极值问题转化成一族常微分方程两点边值问题的标准框架。你后面会遇到的所有东西——动态规划、LQR、模型预测控制里的终端约束、燃料最优控制里的开关结构和奇异弧——最后都能从这一页笔记里长出来。这篇补充分享适合刚学过变分法但对哈密尔顿函数法还不够熟的读者也适合那些已经会列公式、但一遇到横截条件或数值求解就翻车的同学。1.1 拉格朗日乘子的“升级版”先回到最一般的问题。假设要最小化[ J\phi(x(t_f),t_f)\int_{t_0}^{t_f} L(t,x,u),dt ]同时系统满足状态方程[ \dot xf(t,x,u),\quad x(t_0)x_0 ]如果只是普通函数约束极值我们很自然会引入拉格朗日乘子。但这里约束是一条随时间变化的微分方程所以乘子不再是一个常数而是一个随时间变化的函数 (\lambda(t))。把这个想法写进增广泛函[ J_a\phi(x(t_f),t_f)\int_{t_0}^{t_f}\left[L(t,x,u)\lambda^T(t)\left(f(t,x,u)-\dot x\right)\right]dt ]然后定义哈密尔顿函数[ H(t,x,u,\lambda)L(t,x,u)\lambda^T(t)f(t,x,u) ]为什么说这是升级版因为原来的问题是在满足状态方程的前提下找极值现在把约束“装”进了被积函数变成了一个在全部时间点上对状态、控制、协状态同时求极值的问题。这里 (\lambda(t)) 的物理含义也很有用它表示“如果当前状态发生微小变化最优代价会怎么变”也就是最优代价函数对状态的梯度。沿着最优轨迹它时刻反映了状态的边际价值。1.2 哈密尔顿函数把问题拆成了“两层”很多教材直接扔出三个必要条件然后开始刷题。但我想先讲清楚一个更直观的理解哈密尔顿函数法把原来的优化问题拆成了两层。第一层是“微观层”在任意时刻 (t)当状态 (x(t)) 和协状态 (\lambda(t)) 已知时我们要选择一个控制 (u(t))让哈密尔顿函数在当前时刻取最小值对于最小化问题。这就是最优控制所满足的瞬时最优性条件。第二层是“宏观层”状态和协状态不是随便选它们要满足一组常微分方程并且两端还要满足边界条件。状态方程描述系统物理演化协状态方程描述代价的边际信息如何随时间传播。这两层合在一起才构成完整的最优性必要条件。你可能会问为什么还要第二层因为如果只做瞬时优化我们根本不知道选哪个 (u) 才是整体最优。比如开车从A点到B点每一时刻都猛踩油门可能让当前速度最快但整体未必最早到达。协状态方程就是用来把这些局部决策“串”成全局最优的。2. 正则方程与横截条件先把最容易记混的边界条件钉死进入实操之前必须把哈密尔顿函数法的三个必要条件和边界条件理清楚。很多同学能默写出状态方程但一写到协状态方程的负号就要翻书一遇到终端状态自由就不知道 (\lambda(t_f)) 到底等于几。这一节我们把整套框架钉死。2.1 正则方程状态与协状态的对称结构对增广泛函取一阶变分令变分为零可以得到最优解必须满足的必要条件[ \dot x\frac{\partial H}{\partial \lambda}f(t,x,u) ][ \dot \lambda-\frac{\partial H}{\partial x} ][ \frac{\partial H}{\partial u}0 ]第一条就是状态方程第二条是协状态方程第三条是控制方程。当控制没有约束、并且哈密尔顿函数对 (u) 光滑时第三条就是 (\partial H/\partial u0)。如果控制有界第三条要改写成更一般的形式这个我们下一节说。一个容易被忽略的细节是协状态方程为什么带负号直观理解是协状态度量的是“状态变化带来的代价敏感性”代价越往后越清楚所以这个敏感性的时间演化方向天然与系统状态方程相反。不可避免的后果是状态方程从初始条件向前推协状态方程通常要从终端条件向后推问题变成典型的两点边值问题。这也是为什么最优控制很少能像仿真那样直接一步步向前算。如果哈密尔顿函数不显含时间 (t)并且系统是时不变的那么沿着最优轨迹有[ \frac{dH}{dt}0 ]也就是说 (H) 是最优轨迹上的常数。这个性质在做最短时间控制、计算自由终端时间时特别有用后面会看到。2.2 横截条件终端的“边界补缺”如果状态初始值给定一般不需要额外条件。问题集中在终端。不同终端情况对应不同的横截条件这一步错了整个数值解就废了。最常见的情况可以整理成一张表终端条件类型横截条件(t_f) 固定(x(t_f)) 给定不需要 (\lambda(t_f)) 的横截条件直接用 (x(t_f)x_f)(t_f) 固定(x(t_f)) 自由无终端代价(\lambda(t_f)0)(t_f) 固定(x(t_f)) 自由有终端代价 (\phi(x(t_f)))(\lambda(t_f)\dfrac{\partial \phi}{\partial x(t_f)})(t_f) 固定(x(t_f)) 满足等式约束 (\psi(x(t_f))0)(\lambda(t_f)\dfrac{\partial \phi}{\partial x(t_f)}\nu^T\dfrac{\partial \psi}{\partial x(t_f)})并满足约束本身(t_f) 自由其他条件不变增加一个标量条件(H(t_f)\dfrac{\partial \Phi}{\partial t_f}0)其中 (\Phi\phi\nu^T\psi)注意上表中 (\nu) 是终端约束对应的拉格朗日乘子。如果问题没有终端代价但 (x(t_f)) 固定那么自由终端时间条件下就是 (H(t_f)0)。这个条件经常被漏掉漏掉之后自由时间问题会变成欠定问题怎么调初值都收敛不了。还需要提醒一下如果 (x(t_0)) 本身是自由的初始端也会有类似条件比如 (\lambda(t_0)-\partial \phi_0/\partial x(t_0))。实际工程里初始状态大多给定但做某些估计问题或路径规划时会遇到两端状态都不完全确定的情况那时要记得把两端的横截条件都列出来。注意不同教材对哈密尔顿函数的定义符号不同。如果看到协状态方程写成 (\dot\lambda\partial H/\partial x)先检查对方是不是把哈密尔顿函数定义成了 (L-\lambda^T f)或者把最优条件写成了极大值形式。符号错一个后面所有量都会跟着错。3. 控制约束和状态约束来了别再用 (\partial H/\partial u0) 硬刚上一节我们讨论的是控制不受限制的“光滑”问题。但实际工程里控制几乎都有界比如电机输出有限、阀门开度有限、机器人关节力矩有限。这时如果还强行用 (\partial H/\partial u0)很可能得到一组不满足约束的虚假最优解。3.1 控制有界从梯度为零变成哈密尔顿函数取最小值庞特里亚金极大值原理其实对最小化问题应叫极小值原理给出了一般形式[ u^*(t)\arg\min_{u\in U} H(t,x,\lambda,u) ]也就是说在每个时刻控制量要在可行集 (U) 内让哈密尔顿函数取最小值。当 (U) 是开集、内部光滑时极小值点满足梯度为零退化为 (\partial H/\partial u0)。当 (U) 是闭区间或者哈密尔顿函数关于 (u) 是线性函数时最优控制往往落在边界上。以最小时间控制为例典型性能指标是[ J\int_{t_0}^{t_f}1,dt ]这时哈密尔顿函数为[ H1\lambda^T f(t,x,u) ]如果控制 (u) 只以线性形式进入 (f)那么 (H) 关于 (u) 是线性的。让 (H) 最小自然要把 (u) 推到可行域的一端。这就是“砰-砰控制”的来源。很多人第一次看到 bang-bang 控制觉得反直觉为什么最优控制不是平缓调节而是不停切换因为性能指标没有惩罚控制量大小自然会把控制推到极限。如果切换函数在一段时间内恒等于零情况会变得麻烦。此时一阶条件无法确定控制最优轨迹可能进入“奇异弧”。这种情况在燃料最优控制里很常见控制量既有界又出现在性能指标中被惩罚所以最优解往往包含“全力段—滑行段—全力段”的组合。判断奇异弧是否最优需要用到广义勒让德-克莱布施条件这已经超出基础课范围。但至少要知道遇到切换函数持续为零时别硬猜先考虑奇异弧是否存在。3.2 状态约束与内部点约束协状态会“跳”状态约束比控制约束难得多。原因很简单控制约束只影响当前时刻的控制量状态约束却会影响未来一段时间的轨迹。比如机器人末端不能碰到障碍物这会让轨迹在接触约束边界前后出现分段。处理状态约束的标准思路是在约束边界上把问题分成若干段每一段单独用哈密尔顿函数法求解再在拼接点上满足“连续性”条件。如果中间存在内部点约束比如轨迹必须在某时刻经过指定位置那么协状态在内部点处会发生跳跃[ \lambda(t_i^)\lambda(t_i^-)\nu^T\frac{\partial q}{\partial x(t_i)} ]其中 (q(x(t_i),t_i)0) 是内部点约束。这个公式的本质和有限维约束优化里的拉格朗日乘子完全一样只是作用在协状态的跨段跳跃上。我的建议是如果刚接触最优控制先不要死磕状态约束的解析求解。工程上最稳的做法是先用直接法或数值优化软件得到一条候选轨迹观察它是否触碰了约束边界然后再回到间接法用哈密尔顿函数法验证并精化。直接从数学上硬解状态约束很容易被分段边界条件淹没。4. 从哈密尔顿函数到LQR同样是H为什么最后解出的是Riccati方程很多讲哈密尔顿函数法的课程会突然跳到线性二次型调节器问题。学生一脸懵刚才还在讲一阶必要条件怎么下一秒就出现了黎卡提方程这里我建议把连接过程看清楚它其实是一次非常漂亮的“降维”。4.1 线性二次型问题里为什么突然冒出来一个 (P(t))考虑标准LQR问题[ \min J\frac{1}{2}x^T(t_f)S_f x(t_f)\frac{1}{2}\int_{t_0}^{t_f}\left(x^TQxu^TRu\right)dt ]系统为线性时不变[ \dot xAxBu ]哈密尔顿函数为[ H\frac{1}{2}x^TQx\frac{1}{2}u^TRu\lambda^T(AxBu) ]由于控制无约束控制方程为[ \frac{\partial H}{\partial u}RuB^T\lambda0 ]解得[ u-R^{-1}B^T\lambda ]协状态方程为[ \dot\lambda-\frac{\partial H}{\partial x}-Qx-A^T\lambda ]到这里还看不出黎卡提方程的影子。关键一步是猜既然问题是线性的最优代价函数应当是状态 (x) 的二次型那么协状态与状态之间应该存在线性关系[ \lambda(t)P(t)x(t) ]把这个关系代入状态方程和协状态方程经过整理就得到[ -\dot PA^TPPA-PBR^{-1}B^TPQ ]这就是微分黎卡提方程。终端条件由终端代价给出[ P(t_f)S_f ]所以真实求解方向是从 (t_f) 向 (t_0) 反向积分而不是从初始时刻向前积分。初次自己推导一遍这个关系比背十遍“LQR就是解Riccati方程”要有用得多。作为验证看一个最简单的标量系统[ \dot xu,\quad \min \frac{1}{2}\int_{0}^{T}\left(qx^2ru^2\right)dt ]这时黎卡提方程退化为[ \dot p\frac{p^2}{r}-q ]如果时间足够长稳态解满足[ p\sqrt{qr} ]最优反馈控制为[ u-\frac{1}{r}px-\sqrt{\frac{q}{r}}x ]这个结果和经典LQR完全一致但它是从哈密尔顿函数法推出来的。这就是为什么我总说哈密尔顿函数法并没有在LQR里消失它只是在一个具体的二次型结构里变成了P(t)。4.2 协状态的另一种解读如果从动态规划角度再看会得到一个更漂亮的解释协状态等于最优值函数对状态的梯度[ \lambda(t)\frac{\partial V(t,x)}{\partial x} ]其中 (V(t,x)) 是从当前状态 (x(t)) 出发到终点的最优剩余代价。在LQR里因为值函数是二次型所以这个梯度就是 (P(t)x)。在一般非线性问题里这个关系也成立虽然我们无法显式写出 (V(t,x))但 (\lambda(t)) 始终携带“当前状态的边际代价”信息。理解这一层有什么实际意义它帮你在调初始协状态时建立直觉。比如终端代价越大终端附近的 (|\lambda(t)|) 通常也越大如果最优轨迹需要强烈避开某个区域那么 (\lambda(t)) 会在进入该区域前出现明显变化。打靶法猜初值时这种定性判断能省很多时间。5. 数值求解时最容易翻车的四个细节理论上哈密尔顿函数法把最优控制问题化成了两点边值问题。可惜大多数真实系统不能解析求解必须上数值方法。这里我根据自己的经验把最长踩的坑按优先级列一下。5.1 间接法数值求解从猜初始协状态开始间接法打靶的流程很直接写出哈密尔顿函数求出最优控制关于状态和协状态的表达式。把控制表达式代回状态方程和协状态方程形成一个关于 ((x,\lambda)) 的增广常微分方程组。猜测缺失的初始边界条件通常是 (\lambda(t_0))如果终时自由还要猜 (t_f)。从 (t_0) 正向积分到 (t_f)检查终端横截条件是否满足。不满足就用牛顿法或拟牛顿法更新猜测值继续迭代。这套方法看起来简单实际用起来很考验初始猜测。尤其当系统具有不稳定模态时状态、协状态会在积分末端指数爆炸稍微偏差一点就面目全非。更稳的选择是多重打靶把时间区间分成若干段每一段都从段首积分并引入连续的接续条件。这样能显著降低对初始猜测的敏感度。现在的边界值问题求解器比如 SciPy 的 solve_bvp本质上就是这类思路适合解决中小规模问题。5.2 四个非常具体的踩坑点第一个坑符号混乱。哈密尔顿函数定义、协状态方程符号、控制方程符号三者必须保持一致。我见过太多人从不同教材各抄一半公式最后解出来的“最优控制”其实是最大化哈密尔顿函数而不是最小化。建议每个新问题都在草稿纸上从头推一遍不要直接套记忆。第二个坑横截条件漏项。尤其是自由终端时间很多人记得 (H(t_f)0)但忘记如果有终端代价 (\phi) 还要加上 (\partial \phi/\partial t_f)或者终端约束里带着乘子 (\nu)忘了把 (\nu^T\psi_t) 加入终端哈密尔顿条件。这个坑的表现很迷惑目标函数看起来在下降但每个迭代点的“最优性”残差都压不下去。第三个坑量纲和尺度没有归一化。状态可能是0.01量级协状态可能是上万量级终端时间可能是几十秒。如果不做尺度变换牛顿法的雅可比矩阵会病态收敛非常慢。比较实用的做法是把时间归一化到 ([0,1])把状态和控制也缩放到接近1的量级然后再求解。第四个坑强制用 (\partial H/\partial u0) 处理有界控制。只要控制进入饱和区域梯度条件就不成立需要改用庞特里亚金极小值条件或者引入开关函数检测边界切换点。数值积分时如果检测到开关函数过零要精确找到过零点而不是在粗网格上强行近似否则轨迹会在开关点附近出现很奇怪的抖动。我把常见问题整理成一个速查表现象可能原因处理方式打靶法发散初始协状态猜测太差用直接法先粗解或用同伦法从简单问题起步最优控制总是对手动边界忽略了控制有界性改用极小值原理检测开关结构黎卡提积分数值爆炸积分方向反了从 (t_f) 反向积分到 (t_0)自由终端时间有多个解缺少 (H(t_f)...0) 条件补上终端哈密尔顿横截条件开关点附近解抖动网格太粗或未检测过零加密网格显式求开关函数零点6. 一个能验证全部理论的例子双积分器时间最优控制理论说多了容易飘我们用一个真正算得出来的经典例子把上面的内容串起来。6.1 问题设置与哈密尔顿函数考虑双积分器系统[ \dot x_1x_2,\quad \dot x_2u,\quad |u|\le 1 ]要求从初始状态到达原点 ((0,0))并且耗时最短。性能指标是[ J\int_{0}^{T}1,dt ]这个问题的哈密尔顿函数为[ H1\lambda_1 x_2\lambda_2 u ]协状态方程为[ \dot\lambda_10,\quad \dot\lambda_2-\lambda_1 ]所以 (\lambda_2) 是时间的线性函数。因为 (H) 关于 (u) 线性最优控制为[ u-\operatorname{sign}(\lambda_2) ]也就是说控制量要么 1要么 -1只在 (\lambda_2) 过零时切换。由于 (\lambda_2) 是线性函数它最多只能穿越零点一次所以最优控制最多只有一个切换点。终端状态固定所以不需要 (\lambda(T)) 的横截条件。但终端时间自由因此必须有[ H(T)1\lambda_1 x_2(T)\lambda_2(T)u(T)0 ]因为目标点是 ((0,0))所以 (x_2(T)0)于是得到[ \lambda_2(T)u(T)-1 ]这正好说明在终端时刻(\lambda_2) 非零并且符号与终端控制相反。6.2 Bang-Bang控制与开关曲线假设初始状态为 (x_1(0)a0)、(x_2(0)0)也就是静止在正半轴某个位置。先从直觉判断需要先向左加速再反向制动轨迹才会停在原点。第一阶段 (u-1)[ x_2(t)-t,\quad x_1(t)a-\frac{t^2}{2} ]第二阶段 (u1) 之前状态要落在开关曲线上。目标原点对应最后一段的进入曲线满足[ x_2-\sqrt{2x_1} ]这个关系来自 (u1) 时 (x_2^22x_1C)代入原点定常数 (C0)。于是开关时刻满足[ -t-\sqrt{2\left(a-\frac{t^2}{2}\right)} ]解得[ t_s\sqrt{a} ]此时[ x_1\frac{a}{2},\quad x_2-\sqrt{a} ]之后施加 (u1)经过同样长的时间把速度减到零。所以总时间为[ T2\sqrt{a} ]这个例子虽然简单但把所有关键要素都过了一遍哈密尔顿函数构造、协状态方程、线性切换函数、庞特里亚金极小值条件、自由终端时间的横截条件。如果你能自己把完整过程推一遍并且画出不同初始位置下的开关曲线哈密尔顿函数法的基础就真正过关了。7. 最后聊点我自己的实战习惯理论框架讲完了最后分享几个我实际动手时养成的习惯。7.1 拿到一个新问题先不要急着列 (\partial H/\partial u0)我发现自己早期最容易犯的错是拿到一个最优控制问题就条件反射地写 (\partial H/\partial u0)。后来改成先做四件事第一写清楚性能指标第二写清楚系统状态方程第三写清楚终端条件第四写清楚控制可行域。只有这四件事都列完了才去写哈密尔顿函数和必要条件。这样虽然慢一点但能避免很多无意义的返工。7.2 用“小问题”检验符号哈密尔顿函数的符号问题靠脑子记不靠谱。我的验证方法是用一个自己能解析求解的小例子比如标量积分器[ \dot xu,\quad J\int \frac{1}{2}u^2dt ]这个问题的解可以直接用变分法算出来。如果哈密尔顿函数法写出来的结果和解析解不一致那就一定是符号定义出了问题。把这个“校验器”固定下来后面每次换教材、换软件我都先用它跑一遍确认自己的公式体系没有漂移。最后再说一个我觉得被低估的操作把哈密尔顿函数法得到的必要条件当成一个“可验证的标准答案”和直接数值优化法的结果交叉验证。我很多次以为打靶法不收敛最后发现其实是横截条件漏了一项。这个坑踩过之后我养成了一个习惯——每解一道最优控制题都先花两分钟把终端条件逐条列出来。这个习惯帮我省下的调试时间远比那两分钟多。
返回列表