日期:2026-04-12 | 类别:性能优化 · 核心架构升级
摘要
本次更新为 AL-iLQR 求解器引入了完整的解析求导能力,覆盖动力学 Jacobian、所有代价函数的梯度/Hessian、以及全部约束(PolygonCollisionConstraint 除外)的 Jacobian。用户可通过 UI 界面实时切换数值差分与解析求导模式,便于对比验证。
性能提升

| 指标 | 数值差分(旧) | 解析求导(新) | 提升倍数 |
|---|
| 单次规划耗时 | ~150 ms | ~9.6 ms | 15.6× |
一、为什么快了这么多?
1.1 旧方案的瓶颈:中心差分的 O(n2) 调用量
旧版对每个时间步的每个求导项都使用中心差分,以 n=4(状态维度)、m=2(控制维度)计算:
| 求导项 | 每步差分调用次数 |
|---|
| A=∂f/∂x | 2n=8 次 NextState |
| B=∂f/∂u | 2m=4 次 NextState |
| ℓxx(Hessian) | 4n2=64 次 StageCost |
| ℓuu | 4m2=16 次 StageCost |
| ℓux(交叉项) | 4nm=32 次 StageCost |
| ℓx,ℓu(梯度) | 2(n+m)=12 次 StageCost |
每步合计:12 次动力学 + 124 次代价函数(每次代价函数内部还会遍历所有约束的 Evaluate)。80 步时域下,每次 iLQR 迭代约需 10,000+ 次函数调用。
1.2 新方案:零差分调用
解析求导直接通过闭式公式计算所有导数,无循环差分、无重复函数调用。特别是:
- 代价 Hessian:从 4n2=64 次函数调用 → 1 次矩阵外积运算
- 约束 AL 项:从隐式标量差分 → 显式 J⊤diag(μ)J Gauss-Newton 近似
- 动力学 Jacobian:从 12 次
NextState → 1 次三角函数计算

二、架构设计:可切换的求导模式

2.1 DerivativeMode 枚举
enum class DerivativeMode {
kFiniteDifference, // 保留原有中心差分(兜底/对照)
kAnalytical, // 解析求导(新增)
};
在 ILQROptions 中新增 derivative_mode 字段,默认为 kFiniteDifference(向后兼容)。
2.2 三层可选接口
在 DynamicsModel、CostFunction、ConstraintFunction 三个基类中统一新增可选的解析求导虚方法:
动力学模型 — DynamicsModel:
virtual bool HasAnalyticalJacobian() const { return false; }
virtual Matrix JacobianState(const Vector& state, const Vector& control, double dt) const;
virtual Matrix JacobianControl(const Vector& state, const Vector& control, double dt) const;
代价函数 — CostFunction:
virtual bool HasAnalyticalDerivatives() const { return false; }
virtual CostExpansion AnalyticalStageCostExpansion(const Vector& state, const Vector& control) const;
virtual std::pair<Vector, Matrix> AnalyticalTerminalCostExpansion(const Vector& state) const;
约束函数 — ConstraintFunction:
virtual bool HasAnalyticalJacobian() const { return false; }
virtual Matrix JacobianState(const Vector& state, const Vector& control) const;
virtual Matrix JacobianControl(const Vector& state, const Vector& control) const;
2.3 ILQRSolver 自动分派
ILQRSolver 在计算导数时检查 derivative_mode 和对应组件的 HasAnalytical*() 标志:
- 若模式为
kAnalytical 且 组件支持解析求导 → 调用解析方法
- 否则 → 回退到中心差分
这意味着即使某个约束(如 PolygonCollisionConstraint)没有实现解析 Jacobian,系统仍能正常工作——对该约束对应的 AL 代价项仍使用差分。
2.4 AL 罚项解析展开
AugmentedLagrangianKnotCost 直接利用约束的解析 Jacobian 组装 AL 项的梯度和 Hessian,避免了对标量 AL 代价的全维度差分:
不等式约束展开(Gauss-Newton 近似):
∂x∂φ=Jx⊤max(0,λ+μ⊙c)
∂x2∂2φ≈Jx⊤diag(Iactive⊙μ)Jx
2.5 UI 实时切换
在 ImGui 前端的 Planning Config 面板中新增 Derivative Mode 下拉框,用户可实时在 Finite Difference 和 Analytical 之间切换,立即对比求解耗时和轨迹质量。

三、已实现解析求导的组件清单
| 组件 | 解析求导 | 说明 |
|---|
| KinematicBicycleModel | A, B | sin/cos/tan 闭式 |
| QuadraticCost | 全部 | 二次型闭式 |
| LaneTrackingCost | 全部 | 外积分解 |
| GuidanceTrackingCost | 全部 | 含纵向投影终端 |
| ControlRateCost | 全部 | 仅控制量项 |
| ControlBoxConstraint | Jacobian | 常数矩阵 |
| SpeedLimitConstraint | Jacobian | 一个非零元素 |
| RoadBoundaryConstraint | Jacobian | 参考线航向 |
| CircularObstacleConstraint | Jacobian | 距离对位置的偏导 |
| MultiCircleRoadBoundary | Jacobian | 刚体变换链式法则 |
| MultiCircleVehicleObs | Jacobian | 刚体变换链式法则 |
| LSEPolygonObstacle | Jacobian | softmax 梯度 |
| TerminalGoalConstraint | Jacobian | 单位矩阵 |
| PolygonCollisionConstraint | 回退差分 | GJK 距离不可微 |
3.1 动力学模型
| 组件 | 解析公式 | 说明 |
|---|
KinematicBicycleModel | A (4×4), B (4×2) | 前向欧拉离散化后的 Jacobian,含 sin/cos/tan |
3.2 代价函数
| 组件 | 解析项 | 说明 |
|---|
QuadraticCost | lx, lu, lxx, luu, lux | 二次型闭式解 |
LaneTrackingCost | lx, lu, lxx, luu, lux + 终端 | 横向/航向/速度误差的外积分解 |
GuidanceTrackingCost | lx, lxx + 终端 | 含纵向投影终端模式 |
ControlRateCost | lu, luu | 仅控制量差分项 |
CompositeCostFunction | 聚合子项 | 自动聚合所有子代价的解析展开 |
3.3 约束函数
| 组件 | Jacobian 维度 | 说明 |
|---|
ControlBoxConstraint | (4×4), (4×2) | 常数矩阵 ±I |
SpeedLimitConstraint | (2×4), (2×2) | 仅 v 分量非零 |
TerminalGoalConstraint | (n×n) | 单位矩阵 |
RoadBoundaryConstraint | (2×4), (2×2) | 依赖参考线航向 h |
CircularObstacleConstraint | (1×4), (1×2) | -2[dx, dy, 0, 0] |
MultiCircleRoadBoundaryConstraint | (2k×4), (2k×2) | 含刚体变换 Jacobian |
MultiCircleVehicleObstacleConstraint | (k×4), (k×2) | 距离对圆心 + 刚体变换链式法则 |
LSEPolygonObstacleConstraint | (k×4), (k×2) | LSE softmax 梯度 + 刚体变换 |
3.4 未实现解析求导的组件
| 组件 | 原因 |
|---|
PolygonCollisionConstraint | 基于 GJK 的凸多边形精确距离在顶点/边切换处不可微 |
该约束在 kAnalytical 模式下会自动回退到中心差分。
四、代码变更文件清单
新增文件
| 文件 | 用途 |
|---|
src/dynamics/dynamics_model.cpp | 基类默认实现(抛异常兜底) |
src/cost/cost_function.cpp | 基类默认实现 |
guide/derivative_architecture.md | 求导架构分析与公式推导文档 |
修改文件
接口层(新增虚方法):
include/dynamics/dynamics_model.hpp
include/cost/cost_function.hpp — 含新增 CostExpansion 结构体
include/constraints/constraint_function.hpp
include/ilqr/ilqr_solver.hpp — 新增 DerivativeMode 枚举
动力学解析 Jacobian:
include/dynamics/kinematic_bicycle_model.hpp
src/dynamics/kinematic_bicycle_model.cpp
代价函数解析求导:
include/cost/quadratic_cost.hpp / src/cost/quadratic_cost.cpp
include/cost/composite_cost_function.hpp / src/cost/composite_cost_function.cpp
include/autodrive/lane_tracking_cost.hpp / src/autodrive/lane_tracking_cost.cpp
include/autodrive/guidance_tracking_cost.hpp / src/autodrive/guidance_tracking_cost.cpp
include/autodrive/control_rate_cost.hpp / src/autodrive/control_rate_cost.cpp
约束解析 Jacobian:
include/constraints/control_box_constraint.hpp / src/constraints/control_box_constraint.cpp
include/constraints/terminal_goal_constraint.hpp / src/constraints/terminal_goal_constraint.cpp
include/autodrive/speed_limit_constraint.hpp / src/autodrive/speed_limit_constraint.cpp
include/autodrive/road_boundary_constraint.hpp / src/autodrive/road_boundary_constraint.cpp
include/autodrive/circular_obstacle_constraint.hpp / src/autodrive/circular_obstacle_constraint.cpp
include/autodrive/multi_circle_road_boundary_constraint.hpp / src/autodrive/multi_circle_road_boundary_constraint.cpp
include/autodrive/multi_circle_vehicle_obstacle_constraint.hpp / src/autodrive/multi_circle_vehicle_obstacle_constraint.cpp
include/autodrive/lse_polygon_obstacle_constraint.hpp / src/autodrive/lse_polygon_obstacle_constraint.cpp
include/autodrive/convex_polygon.hpp / src/autodrive/convex_polygon.cpp — 新增 LogSumExpGradient
AL 层解析展开:
include/al/augmented_lagrangian_cost.hpp / src/al/augmented_lagrangian_cost.cpp
求解器分派逻辑:
场景配置与 UI:
include/autodrive/demo_scenario.hpp — StaticObstacleScenarioConfig 新增 derivative_mode
src/autodrive/demo_scenario.cpp — 传递到 solver_options
apps/rerun_imgui_frontend.cpp — Planning Config 面板新增 Derivative Mode 下拉框
构建系统:
CMakeLists.txt — 新增 dynamics_model.cpp、cost_function.cpp
五、解析求导公式推导
以下对除 PolygonCollisionConstraint 外的所有组件给出解析导数公式。
状态定义 x=[px,py,θ,v]⊤,控制定义 u=[a,δ]⊤(加速度、前轮转角)。
参考线航向 h、原点 (ox,oy)、轮距 L。
5.1 KinematicBicycleModel — Jacobian A, B
动力学方程(前向欧拉):
f0f1f2f3=px+Δt⋅vcosθ=py+Δt⋅vsinθ=θ+Δt⋅Lvtanδ=v+Δt⋅a
A=∂x∂f(4×4):
A=10000100−ΔtvsinθΔtvcosθ10ΔtcosθΔtsinθLΔttanδ1
B=∂u∂f(4×2):
B=000Δt00Lcos2δΔtv0
5.2 QuadraticCost
Stage cost:
ℓ=21(x−xr)⊤Q(x−xr)+21(u−ur)⊤R(u−ur)
ℓx=Q(x−xr),ℓu=R(u−ur),ℓxx=Q,ℓuu=R,ℓux=0
Terminal cost:
ℓf=21(x−xr)⊤Qf(x−xr)
ℓx=Qf(x−xr),ℓxx=Qf
5.3 LaneTrackingCost
定义中间变量:
elatehdgespd=−sinh⋅(px−ox)+cosh⋅(py−oy)=θ−h(归一化到[−π,π])=v−vtarget
对状态的 Jacobian:
∂x∂elat=[−sinhcosh00],∂x∂ehdg=[0010],∂x∂espd=[0001]
Stage cost:
ℓ=21wlelat2+21whehdg2+21wsespd2+21waa2+21wδδ2
ℓx=wlelat∂x∂elat+whehdg∂x∂ehdg+wsespd∂x∂espd
ℓu=[waawδδ]
ℓxx=wl(∂x∂elat)⊤∂x∂elat+wh(∂x∂ehdg)⊤∂x∂ehdg+ws(∂x∂espd)⊤∂x∂espd
ℓuu=diag(wa,wδ),ℓux=0
即 ℓxx 为三个秩1矩阵之和(每个是外积加权)。
Terminal cost: 增加纵向偏差项:
elon=cosh⋅(px−ox)+sinh⋅(py−oy)−starget,∂x∂elon=[coshsinh00]
ℓx=wltelon∂x∂elon+wlattelat∂x∂elat+whtehdg∂x∂ehdg+wstespd∂x∂espd
ℓxx=wlt(∂x∂elon)⊤∂x∂elon+wlatt(∂x∂elat)⊤∂x∂elat+wht(∂x∂ehdg)⊤∂x∂ehdg+wst(∂x∂espd)⊤∂x∂espd
5.4 GuidanceTrackingCost
Stage cost(非 terminal_mode):
ℓ=21wp(Δx2+Δy2)+21whehdg2+21wsespd2
其中 Δx=px−rx,Δy=py−ry,ehdg=NormalizeAngle(θ−ryaw),espd=v−rspeed。
ℓx=wpΔxwpΔywhehdgwsespd,ℓu=0,ℓxx=diag(wp,wp,wh,ws),ℓuu=0,ℓux=0
Terminal cost(terminal_longitudinal_only 模式):
elon=cosh⋅(px−rx)+sinh⋅(py−ry),∂x∂elon=[coshsinh00]
ℓx=wpelon∂x∂elon,ℓxx=wp(∂x∂elon)⊤∂x∂elon
5.5 ControlRateCost
ℓ=21wj(a−aprev)2+21wsr(δ−δprev)2
ℓx=0,ℓu=[wj(a−aprev)wsr(δ−δprev)],ℓxx=0,ℓuu=diag(wj,wsr),ℓux=0
5.6 ControlBoxConstraint — Jacobian
c=[umin−uu−umax]∈R2m
∂x∂c=02m×n,∂u∂c=[−ImIm]
5.7 SpeedLimitConstraint — Jacobian
c=[vmin−vv−vmax]∈R2
∂x∂c=[000000−11],∂u∂c=02×2
5.8 TerminalGoalConstraint — Jacobian
c=x−xtarget∈Rn
∂x∂c=In
∂c/∂u 不适用(终端无控制)。
5.9 RoadBoundaryConstraint — Jacobian
elat=−sinh⋅(px−ox)+cosh⋅(py−oy)
c=[dlb−elatelat−dub],∂x∂elat=[−sinhcosh00]
∂x∂c=[sinh−sinh−coshcosh0000],∂u∂c=02×2
5.10 CircularObstacleConstraint — Jacobian
Δx=px−cx,Δy=py−cy,c=r2−(Δx2+Δy2)
∂x∂c=[−2Δx−2Δy00],∂u∂c=01×2
5.11 MultiCircleRoadBoundaryConstraint — Jacobian
车身覆盖圆 j 的体坐标偏移 (bxj,0)(by=0,圆心在纵轴上)。
刚体变换及其 Jacobian(公共子式):
pj=[px+cosθ⋅bxjpy+sinθ⋅bxj]
∂x∂pj,x=[10−sinθ⋅bxj0],∂x∂pj,y=[01cosθ⋅bxj0]
横向偏差(参考线坐标系下):
latj=−sinh⋅(pj,x−ox)+cosh⋅(pj,y−oy)
∂x∂latj=−sinh⋅∂x∂pj,x+cosh⋅∂x∂pj,y=[−sinhcoshbxjcos(θ−h)0]
约束输出:
c2j=(dlb+rj)−latj,c2j+1=latj−(dub−rj)
∂x∂c2j=−∂x∂latj=[sinh−cosh−bxjcos(θ−h)0]
∂x∂c2j+1=∂x∂latj,∂u∂c=0
5.12 MultiCircleVehicleObstacleConstraint — Jacobian
pj=[px+cosθ⋅bxjpy+sinθ⋅bxj],Δxj=pj,x−ocx,Δyj=pj,y−ocy
cj=(robs+rj)2−(Δxj2+Δyj2)
∂x∂cj=[−2Δxj−2Δyj2bxj(Δxjsinθ−Δyjcosθ)0],∂u∂cj=0
5.13 LSEPolygonObstacleConstraint — Jacobian
LSE 函数对点 p 的梯度:
LSE(p)=hmax+α1lni∑exp(α(hi−hmax))
其中 hi=ni⊤p−bi,hmax=maxihi。
softmax 权重:
wi=∑kexp(α(hk−hmax))exp(α(hi−hmax))
∂p∂LSE=i∑wini(法向量的加权平均)
约束输出:
cj=rj−LSE(pj)
∂p∂cj=−∂p∂LSE=−i∑wini
∂x∂cj=(∂p∂cj)⊤∂x∂pj(1×4)
其中:
∂x∂pj=[1001−sinθ⋅bxjcosθ⋅bxj00],∂u∂cj=0
5.14 增广拉格朗日(AL)罚项展开公式
给定约束 c(x,u)∈Rp,其 Jacobian 为 Jx=∂x∂c∈Rp×n,Ju=∂u∂c∈Rp×m。
等式约束 AL 项:
φ=j∑[λjcj+2μjcj2]
∂x∂φ=Jx⊤(λ+μ⊙c),∂u∂φ=Ju⊤(λ+μ⊙c)
∂x2∂2φ≈Jx⊤diag(μ)Jx,∂u2∂2φ≈Ju⊤diag(μ)Ju,∂u∂x∂2φ≈Ju⊤diag(μ)Jx
以上 Hessian 使用 Gauss-Newton 近似,忽略二阶约束项 ∑j(λj+μjcj)∇2cj 。
不等式约束 AL 项:
φ=j∑2μj[max(0,λj+μjcj)]2−λj2
定义活跃指示 Ij=1[λj+μjcj>0],投影值 p^j=max(0,λj+μjcj)。
∂x∂φ=Jx⊤(I⊙p^),∂u∂φ=Ju⊤(I⊙p^)
∂x2∂2φ≈Jx⊤diag(I⊙μ)Jx,∂u2∂2φ≈Ju⊤diag(I⊙μ)Ju,∂u∂x∂2φ≈Ju⊤diag(I⊙μ)Jx
总的 AL 代价展开:
总展开=基础代价展开+i∑第i个约束 AL 项展开
六、验证方法

- UI 对比:在 Derivative Mode 下拉框中切换
Finite Difference ↔ Analytical,观察:
- 规划耗时变化(Solver 面板)
- 轨迹是否一致(场景视图叠加对比)
- 收敛行为是否一致(违约度、代价历史)
- 数值一致性:在相同场景下,两种模式应产生相同或极接近的轨迹(解析模式精度更高,微小差异源于差分截断误差)。
- 回退安全性:当使用
PolygonCollisionConstraint(kPolygonExact 模式)时,即使选择 Analytical,该约束会自动回退到差分,不影响求解正确性。
评论
加入讨论
登录或注册后即可发表评论,与其他学习者交流
0 条评论
加载评论中...