间断捕获与网格加密
简介
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 网格加密不会减少网格点,因此连续加密不会导致网格点远离函数间断点。