跳转至

误差检查与网格调整

为什么需要检查配点解?

Pockit 使用分段插值多项式表示状态和控制。非线性规划解即使在配点处满足 方程,仍可能存在过大的插值误差或节点之间的约束违反。网格检查用于估计当前 多项式表示是否具有足够分辨率,但不能替代物理验证。

两类误差需要分别处理:

  • 真实跳变应与 Radau 网格边界重合。相比在跳变两侧盲目提高多项式次数, 移动或增加边界通常更有效。
  • 连续但分辨率不足的函数需要更多区间、更高的逐区间点数,或同时调整两者。

检查间断控制

Lobatto 插值在公共网格节点处连续,因此 Pockit 的间断处理流程只适用于 Radau 阶段。求解前,应在 Phase.set_phase_constraint() 中把相应有界 表达式标记为 bang-bang。对于没有静态参数的单阶段成功解,检查方式为:

discontinuous_ok = system.check_discontinuous(
    solution,
    tolerance_discontinuous=1.0e-3,
    tolerance_mesh=1.0e-4,
)

检查器会在每个区间内把标记表达式缩放到 ([0,1])。若表达式在整个区间内 始终位于某一边界的 tolerance_discontinuous 范围内,则该区间通过检查; 长度小于 tolerance_mesh 的区间会被跳过。

检查失败时,先更新网格,再把插值后的结果作为下一轮初值:

from pockit.optimizer import ipopt

solution = system.refine_discontinuous(
    solution,
    tolerance_discontinuous=1.0e-3,
    num_point_min=6,
    num_point_max=12,
    mesh_length_min=1.0e-3,
    mesh_length_max=1.0,
)
solution, info = ipopt.solve(system, solution)

对于包含多个阶段和静态参数的系统,应依次传入各阶段结果,最后传入静态参数值; 返回列表保持相同布局:

values = [solution_0, solution_1, static_values]
values = system.refine_discontinuous(values)

这个简短布局示例中的名称表示多阶段求解器已经返回的结果。

奇异弧限制

该检查假设每个标记表达式都会接近上界或下界。真正的奇异控制可以严格位于 两个边界之间,因此 check_discontinuous()refine_discontinuous() 不能识别、求解或验证奇异弧。详见奇异弧:识别方法与当前限制

检查连续近似

对于连续区域,Pockit 采用 Patterson、Hager 与 Rao 提出的 ph 网格调整方法:

Patterson, M. A., W. W. Hager, and A. V. Rao (2015). "A mesh refinement method for optimal control." Optimal Control Applications and Methods, 36(4), 398-421.

使用明确的绝对、相对容差检查单阶段结果:

continuous_ok = system.check_continuous(
    solution,
    absolute_tolerance_continuous=1.0e-8,
    relative_tolerance_continuous=1.0e-8,
    tolerance_mesh=1.0e-4,
)

若分辨率仍然不足,则调整网格并重新求解:

solution = system.refine_continuous(
    solution,
    absolute_tolerance_continuous=1.0e-8,
    relative_tolerance_continuous=1.0e-8,
    num_point_min=6,
    num_point_max=12,
    mesh_length_min=1.0e-3,
    mesh_length_max=1.0,
)
solution, info = ipopt.solve(system, solution)

num_point_minnum_point_max 限制每个区间的点数; mesh_length_minmesh_length_max 限制归一化区间长度。该方法不会 减少已有网格点数量。

同时处理两类误差

System.check()System.refine() 将两个流程组合起来。每次调用最多 执行一种调整:尚未解析的间断具有更高优先级;否则由连续误差估计决定更新方式。

if not system.check(
    solution,
    absolute_tolerance_continuous=1.0e-8,
    relative_tolerance_continuous=1.0e-8,
    tolerance_discontinuous=1.0e-3,
):
    solution = system.refine(
        solution,
        absolute_tolerance_continuous=1.0e-8,
        relative_tolerance_continuous=1.0e-8,
        tolerance_discontinuous=1.0e-3,
        num_point_min=6,
        num_point_max=12,
        mesh_length_min=1.0e-3,
        mesh_length_max=1.0,
    )
    solution, info = ipopt.solve(system, solution)

每一轮都应先确认求解器状态,并设置明确的最大调整次数。 超敏感问题展示了用于狭窄端点边界层的完整自适应循环。

调整后仍需验证

通过网格检查只说明插值误差受到控制,并不能证明全局最优性或物理可行性。应在 密集物理时间网格上重构状态、控制和路径约束,分别检查跳变左右极限,并至少比较 两套离散下的目标函数和工程诊断量。条件允许时,还应独立积分原始动力学。