where should the delay call be placed inside a gekko code?

生来就可爱ヽ(ⅴ<●) 提交于 2021-01-27 13:40:32

问题


I am trying to use GEKKO MPC to control the level of a tank while manipulating the inlet flow. I want to model the GEKKO controller as a FOPDT. I got all the parameters I need, but I want to account for the time delay using the delay function. I am not sure of the exact position of this function since it is giving me an error when I put it in the code. When I remove it (i.e. no time delay) the code works fine but I want to be more realistic and put a time delay. Here is code attached:

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from gekko import GEKKO

# Steady State Initial Condition
u2_ss=10.0

h_ss=50.0

x0 = np.empty(1)
x0[0]= h_ss

#%% GEKKO nonlinear MPC
m = GEKKO(remote=False)
m.time = [0,0.02,0.04,0.06,0.08,0.1,0.12,0.15,0.2]

Ac=30.0
# initial conditions

h0=50.0
q0=10.0
Kp=93.48425357240352
taup=1010.8757590561246
thetap= 3
m.q=m.MV(value=q0,lb=0,ub=100)
m.h= m.CV(value=h0)

m.delay(m.q,m.h,thetap)

m.Equation(taup * m.h.dt()==m.q*Kp -m.h)


#MV tuning
m.q.STATUS = 1
m.q.FSTATUS = 0
m.q.DMAX = 100


#CV tuning

m.h.STATUS = 1
m.h.FSTATUS = 1
m.h.TR_INIT = 2
m.h.TAU = 1.0
m.h.SP = 55.0

m.options.CV_TYPE = 2
m.options.IMODE = 6
m.options.SOLVER = 3

#%% define CSTR model
def cstr(x,t,u2,Ac):

    q=u2
    Ac=30.0


    # States (2):
    # the height of the tank (m)

    h=x[0]

    # Parameters:


    # Calculate height derivative

    dhdt=(q-5)/Ac

    # Return xdot:
    xdot = np.zeros(1)
    xdot[0]= dhdt
    return xdot


# Time Interval (min)
t = np.linspace(0,20,400)

# Store results for plotting


hsp=np.ones(len(t))*h_ss
h=np.ones(len(t))*h_ss

u2 = np.ones(len(t)) * u2_ss


# Set point steps

hsp[0:100] = 55.0
hsp[100:]=70.0


# Create plot
plt.figure(figsize=(10,7))
plt.ion()
plt.show()

# Simulate CSTR
for i in range(len(t)-1):
    # simulate one time period (0.05 sec each loop)
    ts = [t[i],t[i+1]]
    y = odeint(cstr,x0,ts,args=(u2[i],Ac))

    # retrieve measurements

    h[i+1]= y[-1][0]

    # insert measurement

    m.h.MEAS=h[i+1]

    m.h.SP=hsp[i+1]


    # solve MPC
    m.solve(disp=True)


    # retrieve new q value

    u2[i+1] = m.q.NEWVAL
    # update initial conditions
    x0[0]= h[i+1]

    #%% Plot the results

    plt.clf()
    plt.subplot(2,1,1)
    plt.plot(t[0:i],u2[0:i],'b--',linewidth=3)
    plt.ylabel('inlet flow')

    plt.subplot(2,1,2)

    plt.plot(t[0:i],hsp[0:i],'g--',linewidth=3,label=r'$h_{sp}$')
    plt.plot(t[0:i],h[0:i],'k.-',linewidth=3,label=r'$h_{meas}$')
    plt.xlabel('time')
    plt.ylabel('tank level')
    plt.legend(loc='best')


    plt.draw()
    plt.pause(0.01)


回答1:


The problem with your model is that the differential equation and the delay model are trying to solve the value of m.h based on the value of m.q. Both equations cannot be satisfied at the same time. The delay object requires that m.h is delayed version of m.q from 3 cycles ago. The differential equation requires the solution of the linear differential equation. They do not produce the same answer for m.h so this leads to an infeasible solution as the solver correctly reports.

m.delay(m.q,m.h,thetap)
m.Equation(taup * m.h.dt()==m.q*Kp -m.h)

Instead, you should create a new variable such as m.qd as a delayed version of m.q. The m.dq is then the input to the differential equation.

m.qd=m.Var()
m.delay(m.q,m.qd,thetap)
m.Equation(taup * m.h.dt()==m.qd*Kp -m.h)

Other Issues, Not Related to the Question

There were a couple other issues with your application.

  1. The time synchronization between the simulator and controller are not correct. You should use the same cycle time for the simulator and controller. I changed the simulation time to t = np.linspace(0,20,201) for a 0.1 min cycle time.
  2. The delay model requires that the controller have uniform time spacing because it is a discrete model. I changed the controller time spacing to m.time = np.linspace(0,2,21) or 0.1 min for a cycle time.
  3. The simulator (solved with ODEINT) does not have input delay so there is model mismatch between the controller and simulator. This is still okay because it is a realistic scenario to have model mismatch but you'll need to realize that there will be some corrective control action based on feedback from the simulator. The controller is able to drive the level to the set point but there is chatter in the MV due to model mismatch and the squared error objective.

To improve the chatter, I switched to m.options.CV_TYPE=1, set a SPHI and SPLO dead-band, opened the initial trajectory with m.options.TR_OPEN=50, and added a move suppression with m.q.DCOST. These have the effect of achieving similar performance but without the valve chatter.

Here is the source code:

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from gekko import GEKKO

# Steady State Initial Condition
u2_ss=10.0
h_ss=50.0
x0 = np.empty(1)
x0[0]= h_ss

#%% GEKKO nonlinear MPC
m = GEKKO(remote=False)
m.time = np.linspace(0,2,21)
Ac=30.0
# initial conditions
h0=50.0
q0=10.0
Kp=93.48425357240352
taup=1010.8757590561246
thetap= 3
m.q=m.MV(value=q0,lb=0,ub=100)
m.qd=m.Var(value=q0)
m.h= m.CV(value=h0)
m.delay(m.q,m.qd,thetap)
m.Equation(taup * m.h.dt()==m.qd*Kp -m.h)

#MV tuning
m.q.STATUS = 1
m.q.FSTATUS = 0
m.q.DMAX = 100
m.q.DCOST = 1

#CV tuning
m.h.STATUS = 1
m.h.FSTATUS = 1
m.h.TR_INIT = 1
m.h.TR_OPEN = 50
m.h.TAU = 0.5

m.options.CV_TYPE = 1
m.options.IMODE = 6
m.options.SOLVER = 3

#%% define CSTR model
def cstr(x,t,u2,Ac):
    q=u2
    Ac=30.0

    # States (2):
    # the height of the tank (m)
    h=x[0]

    # Parameters:
    # Calculate height derivative
    dhdt=(q-5)/Ac

    # Return xdot:
    xdot = np.zeros(1)
    xdot[0]= dhdt
    return xdot

# Time Interval (min)
t = np.linspace(0,20,201)

# Store results for plotting
hsp=np.ones(len(t))*h_ss
h=np.ones(len(t))*h_ss
u2 = np.ones(len(t)) * u2_ss

# Set point steps
hsp[0:100] = 55.0
hsp[100:]  = 70.0

# Create plot
plt.figure(figsize=(10,7))
plt.ion()
plt.show()

# Simulate CSTR
for i in range(len(t)-1):
    # simulate one time period (0.05 sec each loop)
    ts = [t[i],t[i+1]]
    y = odeint(cstr,x0,ts,args=(u2[i],Ac))

    # retrieve measurements
    h[i+1]= y[-1][0]

    # insert measurement
    m.h.MEAS=h[i+1]
    # for CV_TYPE = 1
    m.h.SPHI=hsp[i+1]+0.05
    m.h.SPLO=hsp[i+1]-0.05
    # for CV_TYPE = 2
    m.h.SP=hsp[i+1]

    # solve MPC
    m.solve(disp=False)

    # retrieve new q value
    u2[i+1] = m.q.NEWVAL
    # update initial conditions
    x0[0]= h[i+1]

    #%% Plot the results
    plt.clf()
    plt.subplot(2,1,1)
    plt.plot(t[0:i],u2[0:i],'b--',linewidth=3)
    plt.ylabel('inlet flow')

    plt.subplot(2,1,2)
    plt.plot(t[0:i],hsp[0:i],'g--',linewidth=3,label=r'$h_{sp}$')
    plt.plot(t[0:i],h[0:i],'k.-',linewidth=3,label=r'$h_{meas}$')
    plt.xlabel('time')
    plt.ylabel('tank level')
    plt.legend(loc='best')

    plt.draw()
    plt.pause(0.01)


来源:https://stackoverflow.com/questions/58287318/where-should-the-delay-call-be-placed-inside-a-gekko-code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!