间断捕获与网格加密

简介

Pockit 通过分段线性多项式拟合函数。Radau 节点在网格点(子区间边界)处容许间断;Lobatto 节点的近似函数总是在区间内连续。为了较为精确地拟合函数,需要从间断处和连续部分两方面进行考虑

  • 对于所有间断点,要存在网格点与其尽可能接近
  • 对于连续部分,网格要足够密、插值节点数足够多以使得其近似误差在容许范围

Pockit 可以分别估计间断部分和连续部分的误差,并根据当前计算结果自动对网格点和插值点个数进行调整。

间断捕获

Lobatto 节点无法精确近似间断函数,本节中的方法仅适用于 Radau 节点。

对于 Radau 节点,Pockit 通过如下方法检测间断点估计是否准确:对于在 Phase.set_phase_constraint() 中设置为 bang-bang 控制的阶段约束,检测其是否在每个子区间内都同时接近下界或同时接近上界。其中相对误差为 tolerance_discontinuous 由用户给定,默认为 \(10^{-3}\)。 通过调用 System.check_discontinuous() 方法检验当前计算结果是否满足上述条件

# 系统有 n_p 个 Phase,对应的 Variable 分别为 v_0, ..., v_{n_p - 1}
# 系统变量取值对应的列表或 np.array 为 v_sp
S.check_discontinuous(
    [v_0, ..., v_{n_p - 1}, v_sp], # 若只有一个阶段且无系统变量,也可以直接传入 v
    tolerance_discontinuous,
    tolerance_mesh, # 长度小于 tolerance_mesh 的子区间跳过检测
)

若检测不通过,Pockit 可以自动估计函数间断点位置,并增加或移动网格点使得网格点尽可能接近间断点。 通过调用 System.refine_discontinuous() 方法实现

# 系统有 n_p 个 Phase,对应的 Variable 分别为 v_0, ..., v_{n_p - 1}
# 系统变量取值对应的列表或 np.array 为 v_sp
[v2_0, ..., v2_{n_p - 1}, v2_sp] = S.refine_discontinuous(
    [v_0, ..., v_{n_p - 1}, v_sp], # 若只有一个阶段且无系统变量,也可以直接传入 v
    tolerance_discontinuous,
    num_point_min, # 子区间最低插值点个数
    num_point_max, # 子区间最高插值点个数
    mesh_length_min, # 子区间最短长度(假设总长为 1)
    mesh_length_max # 子区间最长长度(假设总长为 1)
)
# 返回的 v2_* 为 v_* 在新插值点上的插值,可直接用作下一轮优化输入

注:Pockit 目前无法估计有 singular arc 的最优控制问题间断点。

网格加密

对于连续部分,pockit 采用 ph 方法估计误差和加密网格。方法参考:

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

通过调用 System.check_continuous() 方法检验当前计算结果是否满足容许误差

# 系统有 n_p 个 Phase,对应的 Variable 分别为 v_0, ..., v_{n_p - 1}
# 系统变量取值对应的列表或 np.array 为 v_sp
S.check_continuous(
    [v_0, ..., v_{n_p - 1}, v_sp], # 若只有一个阶段且无系统变量,也可以直接传入 v
    atol,
    rtol,
    tolerance_mesh, # 长度小于 tolerance_mesh 的子区间跳过检测
)

若检测不通过,Pockit 可以自动估计函数误差并增加网格点或插值点数量。 通过调用 System.refine_continuous() 方法实现自适应网格加密

# 系统有 n_p 个 Phase,对应的 Variable 分别为 v_0, ..., v_{n_p - 1}
# 系统变量取值对应的列表或 np.array 为 v_sp
[v2_0, ..., v2_{n_p - 1}, v2_sp] = S.refine_discontinuous(
    [v_0, ..., v_{n_p - 1}, v_sp], # 若只有一个阶段且无系统变量,也可以直接传入 v
    atol,
    rtol,
    num_point_min, # 子区间最低插值点个数
    num_point_max, # 子区间最高插值点个数
    mesh_length_min, # 子区间最短长度(假设总长为 1)
    mesh_length_max # 子区间最长长度(假设总长为 1)
)
# 返回的 v2_* 为 v_* 在新插值点上的插值,可直接用作下一轮优化输入

同时处理间断和连续部分

Pockit 还提供 System.check()System.refine() 方法,同时处理间断和连续部分。

该方法会同时检测间断点和连续部分的误差。 若间断点误差不满足容许范围,会调用 System.refine_discontinuous() 方法,并跳过连续部分的网格加密。 在间断点误差满足容许范围的情况下,若连续部分误差不满足容许范围,会调用 System.refine_continuous() 方法。 由于 ph 网格加密不会减少网格点,因此连续加密不会导致网格点远离函数间断点。