我正在尝试在 gekko 中实现实时 MPC。这意味着我需要这个模拟无限期地实时运行。类似于do-MPC的实时MPC。一般代码循环是在每个时间步调用求解器,根据当前状态重新评估问题,然后将 m.time 数组移动 1(即,如果它以 [0-20] 开始,则下一个时间步将是 [ 1-21]等)。
当我像这样定义 m.time 数组时,问题就出现了:
m.time = np.linspace(current_time, current_time+prediction_horizon, prediction_horizon+1) current_time += 1
应该会达到预期的效果。相反,求解器给了我这个警告消息:
Warning: shifting time horizon to start at zero Current starting time value: 18.
这意味着现在模拟窗口不会移动。这只是解算器的限制还是我可以改变?
我尝试动态延长时间范围,这有效:
m.time = np.linspace(0, current_time+prediction_horizon, prediction_horizon+1) current_time += 1
这意味着我需要向所有数组附加新值,以便所有求解参数的数组具有相同的长度。然而,这显着减慢了计算时间 60 秒。移动设定的范围可以克服这个问题,但我似乎无法实现它。
如有任何帮助,我们将不胜感激。谢谢。
MPC应用时间范围是相对于零开始时间而言的。时间通常不在模型中,因此不需要从非零值开始。 Gekko 自动对先前的解决方案进行时间平移,并接受对任何干扰、设定点、状态变量初始条件和测量反馈的更新,以创建新的 MPC 解决方案。下面是一个演示该方法的简单应用程序。
import numpy as np
from gekko import GEKKO
import matplotlib.pyplot as plt
from PIL import Image
# Initialize the GEKKO model
m = GEKKO(remote=False)
m.time = np.linspace(0, 20, 21) # Time grid
mass = 500
b = m.Param(value=50)
K = m.Param(value=0.8)
p = m.MV(value=0, lb=0, ub=100) # Manipulated Variable (gas pedal)
v = m.CV(value=0) # Controlled Variable (velocity)
# Define the dynamic equation
m.Equation(mass * v.dt() == -v * b + K * b * p)
# Set optimization mode for control
m.options.IMODE = 6 # Control mode
# Tuning parameters for MV (gas pedal)
p.STATUS = 1 # Allow optimizer to change
p.FSTATUS = 0
p.DCOST = 0.1 # Smooth out gas pedal movement
p.DMAX = 20 # Limit rate of change
# Tuning parameters for CV (velocity)
v.STATUS = 1 # Include set point in the objective
m.options.CV_TYPE = 2 # L2 norm
v.SP = 40 # Set point for velocity
v.TR_INIT = 1 # Enable set point trajectory
v.TAU = 5 # Time constant of trajectory
# List to store frames for GIF
frames = []
# Run the optimization in a loop and save plots
for i in range(25):
if i==15:
v.SP = 20
print(f'MPC cycle: {i} of 25')
m.solve(disp=False) # Solve the optimization problem
# Create a plot for each iteration
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(6, 8))
ax1.plot(m.time+i, p.value, 'b-', lw=2)
ax1.set_ylabel('Gas Pedal (%)')
ax1.set_title(f'MPC Cycle {i+1}')
ax1.set_ylim([0,100])
ax2.plot(m.time+i, v.value, 'r--', lw=2)
ax2.plot(m.time+i,np.ones_like(m.time)*v.SP,'k:',lw=2)
ax2.set_ylim([0,50])
ax2.set_ylabel('Velocity (m/s)')
ax2.set_xlabel('Time (s)')
fig.tight_layout()
# Save the plot as an image frame
fig.canvas.draw()
frame = np.frombuffer(fig.canvas.tostring_rgb(), dtype='uint8')
frame = frame.reshape(fig.canvas.get_width_height()[::-1] + (3,))
frames.append(Image.fromarray(frame))
plt.close(fig) # Close the figure to save memory
# Save the frames as a GIF
frames[0].save('control_simulation.gif', format='GIF',
append_images=frames[1:], save_all=True, duration=500, loop=0)
print("GIF saved as 'control_simulation.gif'")
我在图中添加了
m.time+i
以显示时间的进展。
ax2.plot(m.time+i, v.value, 'r--', lw=2)
Gekko 应用程序不需要相同的进程,可以在解决方案完成后添加到任何可视化中。