Mohamad Ibrahim
Mohamad Ibrahim

Reputation: 315

How can i use gekko python to control the level of a tank of a cstr by manipulating the inlet flow to the tank?- Part 2

I am trying to use GEKKO on PYTHON to control the level of a CSTR tank while manipulating the inlet flow q. I tried the same problem using a pid controller and it worked. However, on GEKKO the height is not tracking its setpoint. Once I did the doublet test: at a flow rate of 200, the height reached 800 and as I decreased the flowrate to 2, the height was about 0. However, when im putting the height setpoint in GEKKO as 700 or 800, the flowrate is not stopping at 200, it is continuously increasing indefinitely. in addition, I tried putting qout=5.0, Ac=30 and h0=50, it also didn't work.

Below is my 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 = [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

m.q=m.MV(value=q0,lb=0,ub=100)
m.h= m.CV(value=h0)
m.qout=m.Param(value=5)

m.Equation(m.h.dt()==(m.q- m.qout)/Ac)


#MV tuning
m.q.STATUS = 1
m.q.FSTATUS = 0
m.q.DMAX = 100
m.q.DMAXHI = 5  
m.q.DMAXLO = -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.0)/Ac

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


# Time Interval (min)
t = np.linspace(0,6,100)

# 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:50] = 55.0
hsp[100:150]=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+1],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)

Upvotes: 2

Views: 352

Answers (1)

John Hedengren
John Hedengren

Reputation: 14346

The problem is with your input to the simulator y = odeint(cstr,x0,ts,args=(u2[i+1],Ac)). It should be using the value from the prior loop: y = odeint(cstr,x0,ts,args=(u2[i],Ac)). Here is an updated script.

Simulation results

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

m.q=m.MV(value=q0,lb=0,ub=100)
m.h= m.CV(value=h0)
m.qout=m.Param(value=5)

m.Equation(Ac * m.h.dt()==m.q- m.qout)


#MV tuning
m.q.STATUS = 1
m.q.FSTATUS = 0
m.q.DMAX = 100
m.q.DMAXHI = 5  
m.q.DMAXLO = -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,6,100)

# 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:50] = 55.0
hsp[100:150]=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=False)


    # retrieve new q value

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

    #%% Plot the results
    if i%10==0:
        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)

Upvotes: 2

Related Questions