You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GEKKO仅支持零向量终态求解,其他终态提示不可行求助

线性MPC求解局部不可行问题排查与解决

问题背景

在GEKKO中实现线性时不变系统的模型预测控制(MPC),终端状态x_f单独定义,权重矩阵Q为6×6零矩阵,R为3×3的10倍单位矩阵。当设置x_f为零向量时求解可正常收敛,但设置非零终端状态(如[0.04, 0.00, 0.00, 0.00, 0.00, 0.00])时,求解器提示局部不可行,且该问题在多组初始状态x_0与终端状态x_f组合下均出现,怀疑并非真实不可行场景,需排查原因并寻找解决办法。

GEKKO实现代码

m = GEKKO(remote = solverParams["remote"])
m.time = timeSeq
x = [m.Var(value = x_0[i], fixed_initial =  True) for i in range(len(x_0))]
u = [m.Var(value = u_0[i], fixed_initial = False) for i in range(len(u_0))]
w = m.Param(value = w)

for i in range(len(x)):
  m.fix_final(x[i], val = x_f[i])
  if stateBounds[i]["lower"] != "-Inf":
    x[i].lower = stateBounds[i]["lower"]
  if stateBounds[i]["upper"] != "+Inf":
    x[i].upper = stateBounds[i]["upper"]
for i in range(len(u)):
  if forceBounds[i]["lower"] != "-Inf":
    u[i].lower = forceBounds[i]["lower"]
  if forceBounds[i]["upper"] != "+Inf":
    u[i].upper = forceBounds[i]["upper"]
  
eqs = [x[i].dt() == np.matmul(A[i], x) + np.matmul(np.atleast_1d(B[i]), u)
        for i in range(len(x))]
eqs = m.Equations(eqs)

startTime = time.time()
m.Minimize(np.add(np.matmul(np.subtract(x, x_f), np.atleast_1d(np.matmul(np.atleast_1d(Q), np.subtract(x, x_f)))),
                  np.matmul(            u,       np.atleast_1d(np.matmul(np.atleast_1d(R),             u))))
          *w)
m.options.IMODE  = 6
m.options.SOLVER = 3
m.solve(disp = solverParams["disp"])
stopTime = time.time()

x_p = [x[i].value for i in range(len(x))]
u_p = [u[i].value for i in range(len(u))]
x_p = np.transpose(x_p)
u_p = np.transpose(u_p)

测试用例

  • 初始状态:
x_0 = np.array([50.00, -25.00, 80.00, 0.00, 0.00, 0.00])
  • 可行终端状态(零向量):
x_f = np.array([0.00, 0.00, 0.00, 0.00, 0.00, 0.00])
  • 不可行终端状态示例:
x_f = np.array([0.04, 0.00, 0.00, 0.00, 0.00, 0.00])

问题原因分析

  1. 硬终端约束过于严格:代码中使用m.fix_final(x[i], val=x_f[i])强制终端状态完全等于x_f,属于硬约束。若系统在给定时间序列长度、状态/控制约束下无法精确到达x_f,求解器会直接判定不可行。尤其当Q=0时,目标函数仅最小化控制输入代价,没有终端状态跟踪的软惩罚,求解器没有妥协空间。

  2. 初始猜测不合理:控制输入u的初始值u_0若离可行解过远,IPOPT(SOLVER=3)作为梯度求解器,可能陷入局部不可行区域无法跳出。

  3. 求解器参数设置:默认的IPOPT迭代次数、收敛容差可能不足以让求解器找到可行解;部分求解器对硬约束的处理策略也会影响结果。

  4. 系统可达性验证不足:虽然系统是线性时不变,但需确认在给定约束(状态上下限、控制上下限)和时间范围内,x_f是否真的可达。若存在约束限制了路径,即使理论可控,实际也无法到达。

解决办法

1. 替换硬终端约束为软约束

去掉m.fix_final硬约束,在目标函数中加入终端状态跟踪的惩罚项,给求解器妥协空间。例如:

# 移除原有硬约束
# for i in range(len(x)):
#   m.fix_final(x[i], val = x_f[i])

# 增加终端状态软惩罚(权重可根据需求调整,比如1e6)
m.Minimize(1e6 * sum((x[i]-x_f[i])**2 for i in range(len(x))))

保留原有的控制输入代价最小化,求解器会在控制代价和终端跟踪误差之间做权衡,避免硬约束导致的不可行。

2. 优化初始猜测

  • 若已知稳态控制输入(使得系统稳态为x_f),将u的初始值设为该稳态值。
  • 先通过开环仿真计算一个粗略可行的控制序列,作为u的初始猜测。

3. 调整求解器参数

  • 更换求解器:尝试使用APOPT(m.options.SOLVER=1),它在处理不可行问题和离散优化时表现更灵活。
  • 增大迭代次数:m.options.MAX_ITER=1000(默认可能为500)。
  • 调整收敛容差:m.options.RTOL=1e-6,m.options.ATOL=1e-6,放宽容差帮助求解器收敛。

4. 验证系统可达性

  • 先做开环仿真:手动给定控制输入,看是否能让系统在时间序列内到达x_f,同时满足状态和控制约束。若开环都无法到达,说明x_f确实不可行,需调整x_f或约束。
  • 检查系统可控性:通过可控性矩阵验证系统是否完全可控,确认理论上x_f是否可达。

5. 调整时间序列长度

若时间序列过短,系统没有足够时间调整到x_f,可增加timeSeq的长度,给系统留出更多调整时间。


内容的提问来源于stack exchange,提问作者Aaron John Sabu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 12:25:14