Nonlinear Model Predictive Control

Main.NonlinearControl History

Hide minor edits - Show changes to output

February 10, 2023, at 06:10 PM by 10.35.117.248 -
Changed line 277 from:
m = GEKKO(remote=True) # remote=True for MacOS
to:
m = GEKKO(remote=True)
November 17, 2021, at 12:58 AM by 10.35.117.248 -
Changed line 127 from:
plt.plot(t,u,'b--',linewidth=3)
to:
plt.plot(t,u,'b--',lw=3)
Changed line 132 from:
plt.plot(t,Ca,'r-',linewidth=3)
to:
plt.plot(t,Ca,'r-',lw=3)
Changed line 137 from:
plt.plot(t,T,'k.-',linewidth=3)
to:
plt.plot(t,T,'k.-',lw=3)
Changed line 232 from:
plt.plot(t,Tc,'b--',linewidth=3)
to:
plt.plot(t,Tc,'b--',lw=3)
Changed line 237 from:
plt.plot(t,Ca,'r-',linewidth=3)
to:
plt.plot(t,Ca,'r-',lw=3)
Changed line 242 from:
plt.plot(t,T,'k.-',linewidth=3)
to:
plt.plot(t,T,'k.-',lw=3)
Changed line 493 from:
   plt.plot(t[0:i],u[0:i],'b--',linewidth=3)
to:
   plt.plot(t[0:i],u[0:i],'b--',lw=3)
Changed line 498 from:
   plt.plot(t[0:i],Ca[0:i],'r-',linewidth=3)
to:
   plt.plot(t[0:i],Ca[0:i],'r-',lw=3)
Changed lines 503-504 from:
   plt.plot(t[0:i],Tsp[0:i],'k-',linewidth=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',linewidth=3,label=r'$T_{meas}$')
to:
   plt.plot(t[0:i],Tsp[0:i],'k-',lw=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',lw=3,label=r'$T_{meas}$')
Changed line 646 from:
   plt.plot(t[0:i],Tc[0:i],'b--',linewidth=3)
to:
   plt.plot(t[0:i],Tc[0:i],'b--',lw=3)
Changed line 651 from:
   plt.plot(t[0:i],Ca[0:i],'r-',linewidth=3)
to:
   plt.plot(t[0:i],Ca[0:i],'r-',lw=3)
Changed lines 656-657 from:
   plt.plot(t[0:i],Tsp[0:i],'k-',linewidth=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',linewidth=3,label=r'$T_{meas}$')
to:
   plt.plot(t[0:i],Tsp[0:i],'k-',lw=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',lw=3,label=r'$T_{meas}$')
Changed line 854 from:
   plt.plot(t[0:i],u[0:i],'b--',linewidth=3)
to:
   plt.plot(t[0:i],u[0:i],'b--',lw=3)
Changed lines 859-860 from:
   plt.plot(t[0:i],Ca[0:i],'b.-',linewidth=3,label=r'$C_A$')
    plt.plot([0,t[i-1]],[0.2,0.2],'r--',linewidth=2,label='limit')
to:
   plt.plot(t[0:i],Ca[0:i],'b.-',lw=3,label=r'$C_A$')
    plt.plot([0,t[i-1]],[0.2,0.2],'r--',lw=2,label='limit')
Changed lines 865-867 from:
   plt.plot(t[0:i],Tsp[0:i],'k-',linewidth=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',linewidth=3,label=r'$T_{meas}$')
    plt.plot([0,t[i-1]],[400,400],'r--',linewidth=2,label='limit')
to:
   plt.plot(t[0:i],Tsp[0:i],'k-',lw=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',lw=3,label=r'$T_{meas}$')
    plt.plot([0,t[i-1]],[400,400],'r--',lw=2,label='limit')
March 08, 2019, at 04:38 AM by 10.37.149.103 -
Changed lines 571-572 from:
m.time = np.linspace(0,5,51)
to:
m.time = np.linspace(0,2,21)
Changed line 587 from:
m.T.TAU = 0.5
to:
m.T.TAU = 1.2
Changed lines 604-605 from:
t = np.linspace(0,10,101)
to:
t = np.linspace(0,20,201)
Changed lines 614-618 from:
Tsp[0:20] = 330.0
Tsp[20:40] = 350.0
Tsp[40:60] = 370.0
Tsp[60:] = 390.0
to:
Tsp[0:40] = 330.0
Tsp[40:80] = 350.0
Tsp[80:120] = 370.0
Tsp[120:] = 390.0
Changed line 660 from:
   plt.legend(['Reactor Temperature'],loc='best')
to:
   plt.legend(['Temperature SP','Reactor Temperature'],loc='best')
March 08, 2019, at 04:32 AM by 10.37.149.103 -
Changed line 339 from:
(:toggle hide gekko_mpc button show="Show GEKKO Linear MPC Code":)
to:
(:toggle hide gekko_mpc button show="Show GEKKO Linear First-Order MPC Code":)
Added lines 494-646:
   plt.ylabel('Cooling T (K)')
    plt.legend(['Jacket Temperature'],loc='best')

    plt.subplot(3,1,2)
    plt.plot(t[0:i],Ca[0:i],'r-',linewidth=3)
    plt.ylabel('Ca (mol/L)')
    plt.legend(['Reactor Concentration'],loc='best')

    plt.subplot(3,1,3)
    plt.plot(t[0:i],Tsp[0:i],'k-',linewidth=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',linewidth=3,label=r'$T_{meas}$')
    plt.ylabel('T (K)')
    plt.xlabel('Time (min)')
    plt.legend(['Reactor Temperature'],loc='best')
    plt.draw()
    plt.pause(0.01)
(:sourceend:)
(:divend:)

(:toggle hide gekko_arx_mpc button show="Show GEKKO ARX MPC Code":)
(:div id=gekko_arx_mpc:)

'''Linear ARX MPC: Reactor Runaway and Upper Limit Temperature Violation (>400K)'''

%width=550px%Attach:cstr_arx_mpc.png

(:source lang=python:)
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import pandas as pd
from gekko import GEKKO

# load data and parse into columns
url = 'http://apmonitor.com/do/uploads/Main/cstr_step_tests.txt'
data = pd.read_csv(url)
print(data.head())

# generate time-series model
t = data['Time']
u = data['Tc']
y = data['T']
m = GEKKO(remote=True)

# system identification
na = 2 # output coefficients
nb = 2 # input coefficients
yp,p,K = m.sysid(t,u,y,na,nb,shift='init',scale=True,objf=100,diaglevel=1)

# plot results of fitting
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,u)
plt.legend([r'$T_c$'])
plt.ylabel('MV')
plt.subplot(2,1,2)
plt.plot(t,y)
plt.plot(t,yp)
plt.legend([r'$T_{meas}$',r'$T_{pred}$'])
plt.ylabel('CV')
plt.xlabel('Time')
plt.savefig('sysid.png')
plt.show()

# step test model
yc,uc = m.arx(p)

# rename MV and CV
m.Tc = uc[0]
m.T = yc[0]

# steady state initialization
m.options.IMODE = 1
m.Tc.value = 280
m.solve(disp=True)

# GEKKO linear MPC
m.time = np.linspace(0,5,51)

# MV tuning
m.Tc.STATUS = 1
m.Tc.FSTATUS = 0
m.Tc.DMAX = 100
m.Tc.DCOST = 0.1
m.Tc.DMAXHI = 5  # constrain movement up
m.Tc.DMAXLO = -100 # quick action down
m.Tc.UPPER = 350
m.Tc.LOWER = 250
# CV tuning
m.T.STATUS = 1
m.T.FSTATUS = 1
m.T.SP = 330
m.T.TR_INIT = 1
m.T.TAU = 0.5
m.options.CV_TYPE = 2
m.options.IMODE = 6
m.options.SOLVER = 3

# define CSTR (plant)
def cstr(x,t,Tc):
    Ca,T = x
    Tf = 350; Caf = 1.0; q = 100; V = 100
    rho = 1000; Cp = 0.239; mdelH = 5e4
    EoverR = 8750; k0 = 7.2e10; UA = 5e4
    rA = k0*np.exp(-EoverR/T)*Ca
    dCadt = q/V*(Caf - Ca) - rA
    dTdt = q/V*(Tf - T) + mdelH/(rho*Cp)*rA + UA/V/rho/Cp*(Tc-T)
    return [dCadt,dTdt]

# Time Interval (min)
t = np.linspace(0,10,101)

# Store results for plotting
Ca_ss = 1; T_ss = 304; Tc_ss = 280
Ca = np.ones(len(t)) * Ca_ss
T = np.ones(len(t)) * T_ss
Tsp = np.ones(len(t)) * T_ss
Tc = np.ones(len(t)) * Tc_ss

# Set point steps
Tsp[0:20] = 330.0
Tsp[20:40] = 350.0
Tsp[40:60] = 370.0
Tsp[60:] = 390.0

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

# Simulate CSTR
x0 = [Ca_ss,T_ss]
for i in range(len(t)-1):
    y = odeint(cstr,x0,[0,0.05],args=(Tc[i],))
    # retrieve measurements
    Ca[i+1] = y[-1][0]
    T[i+1] = y[-1][1]
    # insert measurement
    m.T.MEAS = T[i+1]
    # update setpoint
    m.T.SP = Tsp[i+1]
    # solve MPC
    m.solve(disp=True)
    # retrieve new Tc value
    Tc[i+1] = m.Tc.NEWVAL
    # update initial conditions
    x0[0] = Ca[i+1]
    x0[1] = T[i+1]

    #%% Plot the results
    plt.clf()
    plt.subplot(3,1,1)
    plt.plot(t[0:i],Tc[0:i],'b--',linewidth=3)
March 08, 2019, at 03:49 AM by 10.37.149.103 -
Changed lines 255-331 from:
to:
%width=550px%Attach:cstr_arx_fit.png

(:toggle hide arx_fit button show="Show Python ARX System ID":)
(:div id=arx_fit:)

%width=550px%Attach:cstr_arx_step.png

(:source lang=python:)
from gekko import GEKKO
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# load data and parse into columns
url = 'http://apmonitor.com/do/uploads/Main/cstr_step_tests.txt'
data = pd.read_csv(url)
print(data.head())

# generate time-series model
t = data['Time']
u = data['Tc']
y = data['T']
m = GEKKO(remote=True) # remote=True for MacOS

# system identification
na = 2 # output coefficients
nb = 2 # input coefficients
yp,p,K = m.sysid(t,u,y,na,nb,shift='init',scale=True,objf=100,diaglevel=1)

# plot results of fitting
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,u)
plt.legend([r'$T_c$'])
plt.ylabel('MV')
plt.subplot(2,1,2)
plt.plot(t,y)
plt.plot(t,yp)
plt.legend([r'$T_{meas}$',r'$T_{pred}$'])
plt.ylabel('CV')
plt.xlabel('Time')
plt.savefig('sysid.png')

# step test model
yc,uc = m.arx(p)

# rename MV and CV
Tc = uc[0]
T = yc[0]

# steady state initialization
m.options.IMODE = 1
Tc.value = 300
m.solve(disp=False)

# dynamic simulation (step test validation)
m.time = np.linspace(0,2,21)
m.options.IMODE = 4
Tc.value = np.ones(21)*300
Tc.value[5:] = 305
m.solve(disp=False)

plt.figure()
plt.subplot(2,1,1)
plt.title('Step Test')
plt.plot(m.time,Tc.value,'b-',label='Cooling Jacket')
plt.ylabel(r'$T_c (K)$')
plt.legend()
plt.subplot(2,1,2)
plt.plot(m.time,T.value,'r-',label='Reactor')
plt.ylabel('T (K)')
plt.xlabel('Time (min)')
plt.legend()

plt.show()
(:sourceend:)
(:divend:)
March 08, 2019, at 12:56 AM by 10.37.149.103 -
Changed line 647 from:
See additional information on this application on the [[https://apmonitor.com/che436/index.php/Main/CaseStudyCSTR|Process Control Class Web-page]].
to:
See additional information on this application with [[https://apmonitor.com/che436/index.php/Main/CaseStudyCSTR|CSTR PID Control with MATLAB]] and [[https://apmonitor.com/pdc/index.php/Main/StirredReactor|CSTR PID Control with Python]].
March 08, 2019, at 12:53 AM by 10.37.149.103 -
Added lines 266-267:
'''Linear MPC: Reactor Runaway and Upper Limit Temperature Violation (>400K)'''
Added lines 440-441:

'''Nonlinear MPC: Acceptable Temperature (<400K) and Concentration (<0.2) Control'''
March 08, 2019, at 12:40 AM by 10.37.149.103 -
Added lines 250-257:

!!!! Model Identification

There are many methods to develop a controller model. For a PID controller, an [[https://apmonitor.com/pdc/index.php/Main/FirstOrderOptimization|FOPDT model]] is one method to obtain [[https://apmonitor.com/pdc/index.php/Main/ProportionalIntegralDerivative|IMC tuning parameters]]. For linear MPC, there are many options to obtain a controller model through [[Main/ModelIdentification|identification methods]]. For nonlinear MPC, the nonlinear simulator equations can be used to develop the controller. This section demonstrates how to obtain a linear model for the MPC application using the step test data generated in the prior section.



!!!! Predictive Control
March 07, 2019, at 11:58 PM by 10.37.149.103 -
Deleted lines 147-148:
[[Attach:cstr_step_tests.txt|CSTR Step Test Data]]
Added lines 152-153:

[[Attach:cstr_step_tests.txt|CSTR Step Test Data (cstr_step_tests.txt)]]
March 07, 2019, at 11:57 PM by 10.37.149.103 -
Changed line 148 from:
[[Attach:cstr_step_tests.txt|CSTR Step Tests Data]]
to:
[[Attach:cstr_step_tests.txt|CSTR Step Test Data]]
March 07, 2019, at 11:57 PM by 10.37.149.103 -
Changed lines 17-20 from:
!!!! Step Test (Doublet)

A step test is required to obtain a process model for the PID controller and the linear model predictive
controller. It is a first step in developing a controller. The following code implements a doublet test. A doublet test starts with the system at steady state. Three moves of Manipulated Variable (MV) are made with sufficient time to nearly reach steady state conditions at two other operating points. The steps are above and below the nominal operating conditions. In this case, the cooling jacket temperature is raised, lowered, and brought back to 300 K (nominal operating condition.
to:
!!!! Step Testing

Step testing is required to obtain a process model for the PID controller and the linear model predictive
controller. It is a first step in developing a controller. The following code implements either a doublet test or multiple steps to different levels. A doublet test starts with the system at steady state. Three moves of Manipulated Variable (MV) are made with sufficient time to nearly reach steady state conditions at two other operating points. The steps are above and below the nominal operating conditions. In this case, the cooling jacket temperature is raised, lowered, and brought back to 300 K (nominal operating condition.
Changed lines 121-122 from:
np.savetxt('data_doublet.txt',data,delimiter=',')
to:
np.savetxt('data_doublet.txt',data,delimiter=',',\
          header='Time,Tc,T',comments='
')
Changed lines 146-148 from:
(:toggle hide step_tests button show="Show Python Step Test Generator":)
(:div id=
step_tests:)
to:
Additional steps are preferred for systems that show a high degree a nonlinearity or when there is little additional expense to obtain the data. The following code generates data at multiple input levels and with varying different step time intervals. The cooling jacket temperature is not raised above 305 K to avoid reactor instability in open loop.
Added lines 152-154:
(:toggle hide step_tests button show="Show Python Step Test Generator":)
(:div id=step_tests:)

Changed line 226 from:
np.savetxt('data_doublet.txt',data,delimiter=',',\
to:
np.savetxt('cstr_step_tests.txt',data,delimiter=',',\
March 07, 2019, at 11:50 PM by 10.37.149.103 -
Changed lines 23-24 from:
(:toggle hide python button show="Show Python Simulation Code":)
(:div id=python:)
to:
(:toggle hide doublet button show="Show Python Simulation Code":)
(:div id=doublet:)
Added lines 127-229:
plt.ylabel('Cooling T (K)')
plt.legend(['Jacket Temperature'],loc='best')

plt.subplot(3,1,2)
plt.plot(t,Ca,'r-',linewidth=3)
plt.ylabel('Ca (mol/L)')
plt.legend(['Reactor Concentration'],loc='best')

plt.subplot(3,1,3)
plt.plot(t,T,'k.-',linewidth=3)
plt.ylabel('T (K)')
plt.xlabel('Time (min)')
plt.legend(['Reactor Temperature'],loc='best')

plt.show()
(:sourceend:)
(:divend:)

(:toggle hide step_tests button show="Show Python Step Test Generator":)
(:div id=step_tests:)

[[Attach:cstr_step_tests.txt|CSTR Step Tests Data]]

%width=550px%Attach:cstr_step_tests.png

(:source lang=python:)
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# define CSTR model
def cstr(x,t,Tc):
    Ca = x[0]
    T = x[1]
    Tf = 350
    Caf = 1.0
    q = 100
    V = 100
    rho = 1000
    Cp = 0.239
    mdelH = 5e4
    EoverR = 8750
    k0 = 7.2e10
    UA = 5e4
    rA = k0*np.exp(-EoverR/T)*Ca
    dCadt = q/V*(Caf - Ca) - rA
    dTdt = q/V*(Tf - T) \
            + mdelH/(rho*Cp)*rA \
            + UA/V/rho/Cp*(Tc-T)
    xdot = np.zeros(2)
    xdot[0] = dCadt
    xdot[1] = dTdt
    return xdot

# Steady State Initial Conditions for the States
Ca_ss = 0.87725294608097
T_ss = 324.475443431599
x0 = np.empty(2)
x0[0] = Ca_ss
x0[1] = T_ss

# Steady State Initial Condition
Tc_ss = 300.0

# Time Interval (min)
t = np.linspace(0,50,501)

# Store results for plotting
Ca = np.ones(len(t)) * Ca_ss
T = np.ones(len(t)) * T_ss
Tc = np.ones(len(t)) * Tc_ss

# Step cooling temperature
Tc[10:100]  = 303.0
Tc[100:200] = 297.0
Tc[200:300] = 300.0
Tc[300:350] = 290.0
Tc[350:400] = 302.0
Tc[400:450] = 302.0
Tc[450:]    = 299.0

# Simulate CSTR
for i in range(len(t)-1):
    ts = [t[i],t[i+1]]
    y = odeint(cstr,x0,ts,args=(Tc[i+1],))
    Ca[i+1] = y[-1][0]
    T[i+1] = y[-1][1]
    x0[0] = Ca[i+1]
    x0[1] = T[i+1]

# Construct results and save data file
# Column 1 = time
# Column 2 = cooling temperature
# Column 3 = reactor temperature
data = np.vstack((t,Tc,T)) # vertical stack
data = data.T              # transpose data
np.savetxt('data_doublet.txt',data,delimiter=',',\
          header='Time,Tc,T',comments='')

# Plot the results
plt.figure()
plt.subplot(3,1,1)
plt.plot(t,Tc,'b--',linewidth=3)
March 07, 2019, at 09:35 PM by 10.37.149.103 -
Changed line 152 from:
%width=550px%cstr_linear_mpc.png
to:
%width=550px%Attach:cstr_linear_mpc.png
March 07, 2019, at 09:34 PM by 10.37.149.103 -
Added lines 151-153:

%width=550px%cstr_linear_mpc.png

Changed lines 158-159 from:
from gekko import gekko
to:
from gekko import GEKKO
Changed line 175 from:
m = gekko()
to:
m = GEKKO(remote=True)
Changed line 289 from:
   m.solve(disp=True,remote=True) # remote=False for local solve
to:
   m.solve(disp=True)
Changed line 322 from:
(:toggle hide gekko_nmpc button show="Show GEKKO Non-Linear MPC Code":)
to:
(:toggle hide gekko_nmpc button show="Show GEKKO Nonlinear MPC Code":)
Added lines 324-326:

%width=550px%Attach:cstr_nonlinear_mpc.png

Changed lines 331-333 from:
from gekko import gekko

to:
from gekko import GEKKO
Changed line 348 from:
m = gekko()
to:
m = GEKKO(remote=True)
Changed line 493 from:
   m.solve(disp=True,remote=True) # remote=False for local solve
to:
   m.solve(disp=True)
April 03, 2018, at 01:08 AM by 174.148.130.212 -
Deleted line 172:
#m.server = 'https://127.0.0.1'
Deleted line 343:
m.server='https://127.0.0.1'
March 26, 2018, at 03:59 PM by 10.4.53.207 -
Added lines 314-520:
   plt.draw()
    plt.pause(0.01)
(:sourceend:)
(:divend:)


(:toggle hide gekko_nmpc button show="Show GEKKO Non-Linear MPC Code":)
(:div id=gekko_nmpc:)
(:source lang=python:)
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from gekko import gekko


# Steady State Initial Condition
u_ss = 280.0
# Feed Temperature (K)
Tf = 350
# Feed Concentration (mol/m^3)
Caf = 1

# Steady State Initial Conditions for the States
Ca_ss = 1
T_ss = 304
x0 = np.empty(2)
x0[0] = Ca_ss
x0[1] = T_ss

#%% GEKKO nonlinear MPC
m = gekko()
m.server='https://127.0.0.1'
m.time = [0,0.02,0.04,0.06,0.08,0.1,0.12,0.15,0.2]

# Volumetric Flowrate (m^3/sec)
q = 100
# Volume of CSTR (m^3)
V = 100
# Density of A-B Mixture (kg/m^3)
rho = 1000
# Heat capacity of A-B Mixture (J/kg-K)
Cp = 0.239
# Heat of reaction for A->B (J/mol)
mdelH = 5e4
# E - Activation energy in the Arrhenius Equation (J/mol)
# R - Universal Gas Constant = 8.31451 J/mol-K
EoverR = 8750
# Pre-exponential factor (1/sec)
k0 = 7.2e10
# U - Overall Heat Transfer Coefficient (W/m^2-K)
# A - Area - this value is specific for the U calculation (m^2)
UA = 5e4

# initial conditions
Tc0 = 280
T0 = 304
Ca0 = 1.0

tau = m.Const(value=0.5)
Kp = m.Const(value=1)

m.Tc = m.MV(value=Tc0,lb=250,ub=350)
m.T = m.CV(value=T_ss)
m.rA = m.Var(value=0)
m.Ca = m.CV(value=Ca_ss)

m.Equation(m.rA == k0*m.exp(-EoverR/m.T)*m.Ca)

m.Equation(m.T.dt() == q/V*(Tf - m.T) \
            + mdelH/(rho*Cp)*m.rA \
            + UA/V/rho/Cp*(m.Tc-m.T))

m.Equation(m.Ca.dt() == q/V*(Caf - m.Ca) - m.rA)

#MV tuning
m.Tc.STATUS = 1
m.Tc.FSTATUS = 0
m.Tc.DMAX = 100
m.Tc.DMAXHI = 20  # constrain movement up
m.Tc.DMAXLO = -100 # quick action down

#CV tuning
m.T.STATUS = 1
m.T.FSTATUS = 1
m.T.TR_INIT = 1
m.T.TAU = 1.0
DT = 0.5 # deadband

m.Ca.STATUS = 0
m.Ca.FSTATUS = 0 # no measurement
m.Ca.TR_INIT = 0

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

#%% define CSTR model
def cstr(x,t,u,Tf,Caf):
    # Inputs (3):
    # Temperature of cooling jacket (K)
    Tc = u
    # Tf = Feed Temperature (K)
    # Caf = Feed Concentration (mol/m^3)

    # States (2):
    # Concentration of A in CSTR (mol/m^3)
    Ca = x[0]
    # Temperature in CSTR (K)
    T = x[1]

    # Parameters:
    # Volumetric Flowrate (m^3/sec)
    q = 100
    # Volume of CSTR (m^3)
    V = 100
    # Density of A-B Mixture (kg/m^3)
    rho = 1000
    # Heat capacity of A-B Mixture (J/kg-K)
    Cp = 0.239
    # Heat of reaction for A->B (J/mol)
    mdelH = 5e4
    # E - Activation energy in the Arrhenius Equation (J/mol)
    # R - Universal Gas Constant = 8.31451 J/mol-K
    EoverR = 8750
    # Pre-exponential factor (1/sec)
    k0 = 7.2e10
    # U - Overall Heat Transfer Coefficient (W/m^2-K)
    # A - Area - this value is specific for the U calculation (m^2)
    UA = 5e4
    # reaction rate
    rA = k0*np.exp(-EoverR/T)*Ca

    # Calculate concentration derivative
    dCadt = q/V*(Caf - Ca) - rA
    # Calculate temperature derivative
    dTdt = q/V*(Tf - T) \
            + mdelH/(rho*Cp)*rA \
            + UA/V/rho/Cp*(Tc-T)

    # Return xdot:
    xdot = np.zeros(2)
    xdot[0] = dCadt
    xdot[1] = dTdt
    return xdot

# Time Interval (min)
t = np.linspace(0,8,401)

# Store results for plotting
Ca = np.ones(len(t)) * Ca_ss
T = np.ones(len(t)) * T_ss
Tsp = np.ones(len(t)) * T_ss
u = np.ones(len(t)) * u_ss

# Set point steps
Tsp[0:100] = 330.0
Tsp[100:200] = 350.0
Tsp[200:300] = 370.0
Tsp[300:] = 390.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=(u[i],Tf,Caf))
    # retrieve measurements
    Ca[i+1] = y[-1][0]
    T[i+1] = y[-1][1]
    # insert measurement
    m.T.MEAS = T[i+1]
    # solve MPC
    m.solve(disp=True,remote=True) # remote=False for local solve

    m.T.SPHI = Tsp[i+1] + DT
    m.T.SPLO = Tsp[i+1] - DT

    # retrieve new Tc value
    u[i+1] = m.Tc.NEWVAL
    # update initial conditions
    x0[0] = Ca[i+1]
    x0[1] = T[i+1]

    #%% Plot the results
    plt.clf()
    plt.subplot(3,1,1)
    plt.plot(t[0:i],u[0:i],'b--',linewidth=3)
    plt.ylabel('Cooling T (K)')
    plt.legend(['Jacket Temperature'],loc='best')

    plt.subplot(3,1,2)
    plt.plot(t[0:i],Ca[0:i],'b.-',linewidth=3,label=r'$C_A$')
    plt.plot([0,t[i-1]],[0.2,0.2],'r--',linewidth=2,label='limit')
    plt.ylabel(r'$C_A$ (mol/L)')
    plt.legend(loc='best')

    plt.subplot(3,1,3)
    plt.plot(t[0:i],Tsp[0:i],'k-',linewidth=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',linewidth=3,label=r'$T_{meas}$')
    plt.plot([0,t[i-1]],[400,400],'r--',linewidth=2,label='limit')
    plt.ylabel('T (K)')
    plt.xlabel('Time (min)')
    plt.legend(loc='best')
March 08, 2018, at 03:48 PM by 45.56.3.173 -
Changed lines 149-151 from:

(:toggle hide python button show="Show Python Simulation Code":)
(:div id=python:)
to:
(:toggle hide gekko_mpc button show="Show GEKKO Linear MPC Code":)
(:div id=gekko_mpc:)
March 08, 2018, at 03:47 PM by 45.56.3.173 -
Added lines 142-316:
(:sourceend:)
(:divend:)

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/ZvvQ0_PdMPk" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
(:htmlend:)


(:toggle hide python button show="Show Python Simulation Code":)
(:div id=python:)
(:source lang=python:)
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from gekko import gekko

# Steady State Initial Condition
u_ss = 280.0
# Feed Temperature (K)
Tf = 350
# Feed Concentration (mol/m^3)
Caf = 1

# Steady State Initial Conditions for the States
Ca_ss = 1
T_ss = 304
x0 = np.empty(2)
x0[0] = Ca_ss
x0[1] = T_ss

#%% GEKKO linear MPC
m = gekko()
#m.server = 'https://127.0.0.1'
m.time = [0,0.02,0.04,0.06,0.08,0.1,0.15,0.2,0.3,0.4,0.5]

# initial conditions
Tc0 = 280
T0 = 304
Ca0 = 1.0

tau = m.Const(value = 0.5)
Kp = m.Const(value = 1)

m.Tc = m.MV(value = Tc0,lb=250,ub=350)
m.T = m.CV(value = T_ss)

m.Equation(tau * m.T.dt() == -(m.T - T0) + Kp * (m.Tc - Tc0))

#MV tuning
m.Tc.STATUS = 1
m.Tc.FSTATUS = 0
m.Tc.DMAX = 100
m.Tc.DMAXHI = 5  # constrain movement up
m.Tc.DMAXLO = -100 # quick action down
#CV tuning
m.T.STATUS = 1
m.T.FSTATUS = 1
m.T.SP = 330
m.T.TR_INIT = 2
m.T.TAU = 1.0
m.options.CV_TYPE = 2
m.options.IMODE = 6
m.options.SOLVER = 3

#%% define CSTR model
def cstr(x,t,u,Tf,Caf):
    # Inputs (3):
    # Temperature of cooling jacket (K)
    Tc = u
    # Tf = Feed Temperature (K)
    # Caf = Feed Concentration (mol/m^3)

    # States (2):
    # Concentration of A in CSTR (mol/m^3)
    Ca = x[0]
    # Temperature in CSTR (K)
    T = x[1]

    # Parameters:
    # Volumetric Flowrate (m^3/sec)
    q = 100
    # Volume of CSTR (m^3)
    V = 100
    # Density of A-B Mixture (kg/m^3)
    rho = 1000
    # Heat capacity of A-B Mixture (J/kg-K)
    Cp = 0.239
    # Heat of reaction for A->B (J/mol)
    mdelH = 5e4
    # E - Activation energy in the Arrhenius Equation (J/mol)
    # R - Universal Gas Constant = 8.31451 J/mol-K
    EoverR = 8750
    # Pre-exponential factor (1/sec)
    k0 = 7.2e10
    # U - Overall Heat Transfer Coefficient (W/m^2-K)
    # A - Area - this value is specific for the U calculation (m^2)
    UA = 5e4
    # reaction rate
    rA = k0*np.exp(-EoverR/T)*Ca

    # Calculate concentration derivative
    dCadt = q/V*(Caf - Ca) - rA
    # Calculate temperature derivative
    dTdt = q/V*(Tf - T) \
            + mdelH/(rho*Cp)*rA \
            + UA/V/rho/Cp*(Tc-T)

    # Return xdot:
    xdot = np.zeros(2)
    xdot[0] = dCadt
    xdot[1] = dTdt
    return xdot

# Time Interval (min)
t = np.linspace(0,10,501)

# Store results for plotting
Ca = np.ones(len(t)) * Ca_ss
T = np.ones(len(t)) * T_ss
Tsp = np.ones(len(t)) * T_ss
u = np.ones(len(t)) * u_ss

# Set point steps
Tsp[0:100] = 330.0
Tsp[100:200] = 350.0
Tsp[200:300] = 370.0
Tsp[300:] = 390.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=(u[i],Tf,Caf))
    # retrieve measurements
    Ca[i+1] = y[-1][0]
    T[i+1] = y[-1][1]
    # insert measurement
    m.T.MEAS = T[i+1]
    # update setpoint
    m.T.SP = Tsp[i+1]
    # solve MPC
    m.solve(disp=True,remote=True) # remote=False for local solve
    # change to a fixed starting point for trajectory
    m.T.TR_INIT = 2
    # retrieve new Tc value
    u[i+1] = m.Tc.NEWVAL
    # update initial conditions
    x0[0] = Ca[i+1]
    x0[1] = T[i+1]

    #%% Plot the results
    plt.clf()
    plt.subplot(3,1,1)
    plt.plot(t[0:i],u[0:i],'b--',linewidth=3)
    plt.ylabel('Cooling T (K)')
    plt.legend(['Jacket Temperature'],loc='best')

    plt.subplot(3,1,2)
    plt.plot(t[0:i],Ca[0:i],'r-',linewidth=3)
    plt.ylabel('Ca (mol/L)')
    plt.legend(['Reactor Concentration'],loc='best')

    plt.subplot(3,1,3)
    plt.plot(t[0:i],Tsp[0:i],'k-',linewidth=3,label=r'$T_{sp}$')
    plt.plot(t[0:i],T[0:i],'b.-',linewidth=3,label=r'$T_{meas}$')
    plt.ylabel('T (K)')
    plt.xlabel('Time (min)')
    plt.legend(['Reactor Temperature'],loc='best')
    plt.draw()
    plt.pause(0.01)
March 08, 2018, at 01:44 PM by 45.56.3.173 -
Changed lines 149-154 from:
Attach:zip.png [[Attach:cstr_pid_solution_Python.zip|ODEINT Python Solution for CSTR Control (PID)]] - [[https://youtu.be/tSOMSxGLzQo|Solution Video]]

Attach:zip.png [[Attach:cstr_mpc2_solution_Python.zip|APM Python Solution for CSTR Control (Linear MPC)]] - [[https://youtu.be/nqv6jFeVUYA|Solution Video]]

Attach:zip.png [[Attach:cstr_nmpc_solution_Python.zip|APM Python Solution for CSTR Control (Nonlinear MPC)]] - [[https://youtu.be/Jxpk4-daDLI|Solution Video]]
to:
Attach:download.png [[Attach:cstr_pid_solution_Python.zip|PID for CSTR Control (Python)]] - [[https://youtu.be/tSOMSxGLzQo|Solution Video]]

Attach:download.png [[Attach:cstr_mpc2_solution_Python.zip|Linear MPC for CSTR Control (APM Python)]] - [[https://youtu.be/nqv6jFeVUYA|Solution Video]]

Attach:download.png [[Attach:cstr_nmpc_solution_Python.zip|Nonlinear MPC for CSTR Control (APM Python)]] - [[https://youtu.be/Jxpk4-daDLI|Solution Video]]
Changed lines 157-161 from:
Attach:download.png [[Attach:cstr_control_solution_PID.zip|Solution 1: PID CSTR Control]] - [[https://youtu.be/sfhHcSF2i90|Solution Video]]

Attach:download.png [[Attach:cstr_control_solution_Linear_MPC.zip|Solution 2: Linear MPC CSTR Control]] - [[https://youtu.be/lBx10LvT8uA|Solution Video]]

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|Solution 3: Nonlinear MPC CSTR Control]] - [[https://youtu.be/PyrLMlht-PU|Solution Video]]
to:
Attach:download.png [[Attach:cstr_control_solution_PID.zip|PID for CSTR Control (Simulink)]] - [[https://youtu.be/sfhHcSF2i90|Solution Video]]

Attach:download.png [[Attach:cstr_control_solution_Linear_MPC.zip|Linear MPC for CSTR Control (Simulink)]] - [[https://youtu.be/lBx10LvT8uA|Solution Video]]

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|Nonlinear MPC for CSTR Control (Simulink)]] - [[https://youtu.be/PyrLMlht-PU|Solution Video]]
March 08, 2018, at 01:40 PM by 45.56.3.173 -
Changed lines 149-166 from:
Attach:zip.png [[Attach:cstr_pid_solution_Python.zip|ODEINT Python Solution for CSTR Control (PID)]]

(:html:)
<iframe width="560" height="315" src="
https://www.youtube.com/embed/tSOMSxGLzQo" frameborder="0" allowfullscreen></iframe>
(
:htmlend:)

Attach:zip
.png [[Attach:cstr_mpc2_solution_Python.zip|APM Python Solution for CSTR Control (Linear MPC)]]

(:html:)
<iframe width="560" height="315" src="
https://www.youtube.com/embed/nqv6jFeVUYA" frameborder="0" allowfullscreen></iframe>
(
:htmlend:)

Attach:zip
.png [[Attach:cstr_nmpc_solution_Python.zip|APM Python Solution for CSTR Control (Nonlinear MPC)]]

(:html:)
<iframe width="560" height="315" src="
https://www.youtube.com/embed/Jxpk4-daDLI" frameborder="0" allowfullscreen></iframe>
(:htmlend:)

to:
Attach:zip.png [[Attach:cstr_pid_solution_Python.zip|ODEINT Python Solution for CSTR Control (PID)]] - [[https://youtu.be/tSOMSxGLzQo|Solution Video]]

Attach:zip.png [[Attach
:cstr_mpc2_solution_Python.zip|APM Python Solution for CSTR Control (Linear MPC)]] - [[https://youtu.be/nqv6jFeVUYA|Solution Video]]

Attach:zip.png [[Attach
:cstr_nmpc_solution_Python.zip|APM Python Solution for CSTR Control (Nonlinear MPC)]] - [[https://youtu.be/Jxpk4-daDLI|Solution Video]]
Changed lines 157-173 from:
Attach:download.png [[Attach:cstr_control_solution_PID.zip|Solution 1: PID CSTR Control]]

(:html:)
<iframe width="560" height="315" src="
https://www.youtube.com/embed/sfhHcSF2i90" frameborder="0" allowfullscreen></iframe>
(
:htmlend:)

Attach:download.png [[Attach:cstr_control_solution_
Linear_MPC.zip|Solution 2: Linear MPC CSTR Control]]

(:html:)
<iframe width="560" height="315" src="
https://www.youtube.com/embed/lBx10LvT8uA" frameborder="0" allowfullscreen></iframe>
(
:htmlend:)

Attach:download.png [[Attach:cstr_control_solution_
Nonlinear_MPC.zip|Solution 3: Nonlinear MPC CSTR Control]]

(:html:)
<iframe width="560" height="315" src="
https://www.youtube.com/embed/PyrLMlht-PU" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
to:
Attach:download.png [[Attach:cstr_control_solution_PID.zip|Solution 1: PID CSTR Control]] - [[https://youtu.be/sfhHcSF2i90|Solution Video]]

Attach:download.png [[Attach
:cstr_control_solution_Linear_MPC.zip|Solution 2: Linear MPC CSTR Control]] - [[https://youtu.be/lBx10LvT8uA|Solution Video]]

Attach:download.png [[Attach
:cstr_control_solution_Nonlinear_MPC.zip|Solution 3: Nonlinear MPC CSTR Control]] - [[https://youtu.be/PyrLMlht-PU|Solution Video]]
Added lines 23-24:
(:toggle hide python button show="Show Python Simulation Code":)
(:div id=python:)
Added line 143:
(:divend:)
June 21, 2017, at 09:40 PM by 10.5.113.130 -
Changed lines 11-13 from:
[[Attach:cstr_control.pdf|Problem Information]]

Attach:download.png [[Attach:cstr_control.zip|CSTR Source Files]]
to:
Attach:download.png [[Attach:cstr_control.zip|CSTR Source Files]] | [[Attach:cstr_control.pdf|Problem Information]]
June 21, 2017, at 09:39 PM by 10.5.113.130 -
Changed line 15 from:
Attach:cstr.png
to:
%width=300px%Attach:cstr.png
March 13, 2017, at 10:42 AM by 82.217.12.178 -
Added lines 161-164:

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/Jxpk4-daDLI" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
March 11, 2017, at 07:31 AM by 45.56.3.173 -
Added lines 155-158:

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/nqv6jFeVUYA" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
March 11, 2017, at 06:33 AM by 45.56.3.173 -
Added lines 149-152:

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/tSOMSxGLzQo" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
March 11, 2017, at 06:06 AM by 45.56.3.173 -
Deleted lines 150-151:

Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and MPC compared)]]
March 11, 2017, at 05:09 AM by 45.56.3.173 -
Changed line 152 from:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and MPC - 2nd approach)]]
to:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and MPC compared)]]
March 11, 2017, at 05:09 AM by 45.56.3.173 -
Changed line 152 from:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and Linear MPC Solution 2)]]
to:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and MPC - 2nd approach)]]
Changed lines 150-152 from:
Attach:zip.png [[Attach:cstr_pid_solution_Python.zip|APM Python Solution for CSTR Control (Linear MPC)]]

Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and Linear MPC)]]
to:
Attach:zip.png [[Attach:cstr_mpc2_solution_Python.zip|APM Python Solution for CSTR Control (Linear MPC)]]

Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and Linear MPC Solution 2)]]
Added lines 149-150:

Attach:zip.png [[Attach:cstr_pid_solution_Python.zip|APM Python Solution for CSTR Control (Linear MPC)]]
March 10, 2017, at 04:13 PM by 10.5.113.121 -
Added lines 20-21:

A step test is required to obtain a process model for the PID controller and the linear model predictive controller. It is a first step in developing a controller. The following code implements a doublet test. A doublet test starts with the system at steady state. Three moves of Manipulated Variable (MV) are made with sufficient time to nearly reach steady state conditions at two other operating points. The steps are above and below the nominal operating conditions. In this case, the cooling jacket temperature is raised, lowered, and brought back to 300 K (nominal operating condition.
March 10, 2017, at 04:09 PM by 10.5.113.121 -
Added lines 18-140:

!!!! Step Test (Doublet)

%width=550px%Attach:cstr_doublet.png

(:source lang=python:)
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# define CSTR model
def cstr(x,t,u,Tf,Caf):
    # Inputs (3):
    # Temperature of cooling jacket (K)
    Tc = u
    # Tf = Feed Temperature (K)
    # Caf = Feed Concentration (mol/m^3)

    # States (2):
    # Concentration of A in CSTR (mol/m^3)
    Ca = x[0]
    # Temperature in CSTR (K)
    T = x[1]

    # Parameters:
    # Volumetric Flowrate (m^3/sec)
    q = 100
    # Volume of CSTR (m^3)
    V = 100
    # Density of A-B Mixture (kg/m^3)
    rho = 1000
    # Heat capacity of A-B Mixture (J/kg-K)
    Cp = 0.239
    # Heat of reaction for A->B (J/mol)
    mdelH = 5e4
    # E - Activation energy in the Arrhenius Equation (J/mol)
    # R - Universal Gas Constant = 8.31451 J/mol-K
    EoverR = 8750
    # Pre-exponential factor (1/sec)
    k0 = 7.2e10
    # U - Overall Heat Transfer Coefficient (W/m^2-K)
    # A - Area - this value is specific for the U calculation (m^2)
    UA = 5e4
    # reaction rate
    rA = k0*np.exp(-EoverR/T)*Ca

    # Calculate concentration derivative
    dCadt = q/V*(Caf - Ca) - rA
    # Calculate temperature derivative
    dTdt = q/V*(Tf - T) \
            + mdelH/(rho*Cp)*rA \
            + UA/V/rho/Cp*(Tc-T)
   
    # Return xdot:
    xdot = np.zeros(2)
    xdot[0] = dCadt
    xdot[1] = dTdt
    return xdot

# Steady State Initial Conditions for the States
Ca_ss = 0.87725294608097
T_ss = 324.475443431599
x0 = np.empty(2)
x0[0] = Ca_ss
x0[1] = T_ss

# Steady State Initial Condition
u_ss = 300.0
# Feed Temperature (K)
Tf = 350
# Feed Concentration (mol/m^3)
Caf = 1

# Time Interval (min)
t = np.linspace(0,25,251)

# Store results for plotting
Ca = np.ones(len(t)) * Ca_ss
T = np.ones(len(t)) * T_ss
u = np.ones(len(t)) * u_ss

# Step cooling temperature to 295
u[10:100] = 303.0
u[100:190] = 297.0
u[190:] = 300.0

# Simulate CSTR
for i in range(len(t)-1):
    ts = [t[i],t[i+1]]
    y = odeint(cstr,x0,ts,args=(u[i+1],Tf,Caf))
    Ca[i+1] = y[-1][0]
    T[i+1] = y[-1][1]
    x0[0] = Ca[i+1]
    x0[1] = T[i+1]

# Construct results and save data file
# Column 1 = time
# Column 2 = cooling temperature
# Column 3 = reactor temperature
data = np.vstack((t,u,T)) # vertical stack
data = data.T            # transpose data
np.savetxt('data_doublet.txt',data,delimiter=',')
   
# Plot the results
plt.figure()
plt.subplot(3,1,1)
plt.plot(t,u,'b--',linewidth=3)
plt.ylabel('Cooling T (K)')
plt.legend(['Jacket Temperature'],loc='best')

plt.subplot(3,1,2)
plt.plot(t,Ca,'r-',linewidth=3)
plt.ylabel('Ca (mol/L)')
plt.legend(['Reactor Concentration'],loc='best')

plt.subplot(3,1,3)
plt.plot(t,T,'k.-',linewidth=3)
plt.ylabel('T (K)')
plt.xlabel('Time (min)')
plt.legend(['Reactor Temperature'],loc='best')

plt.show()
(:sourceend:)
March 10, 2017, at 04:05 PM by 10.5.113.121 -
Changed line 1 from:
(:title Model Predictive Control:)
to:
(:title Nonlinear Model Predictive Control:)
March 10, 2017, at 04:04 PM by 10.5.113.121 -
Changed lines 1-2 from:
(:title Nonlinear Model Predictive Control:)
(:keywords Nonlinear, Model Predictive Control, real-time, tutorial:)
to:
(:title Model Predictive Control:)
(:keywords Nonlinear, PID, Model Predictive Control, real-time, tutorial:)
March 10, 2017, at 04:02 PM by 10.5.113.121 -
Changed lines 23-25 from:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|Python Solution for CSTR Control (PID and Linear MPC)]]

Attach:zip.png [[Attach:cstr_nmpc_solution_Python.zip|Python Solution for CSTR Control (Nonlinear MPC)]]
to:
Attach:zip.png [[Attach:cstr_pid_solution_Python.zip|ODEINT Python Solution for CSTR Control (PID)]]

Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|APM Python Solution for CSTR Control (PID and Linear MPC)]]

Attach:zip.png [[Attach:cstr_nmpc_solution_Python.zip|APM
Python Solution for CSTR Control (Nonlinear MPC)]]
March 09, 2016, at 01:40 AM by 10.5.113.128 -
Changed lines 23-25 from:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|Python Solution for CSTR Control]]
to:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|Python Solution for CSTR Control (PID and Linear MPC)]]

Attach:zip.png [[Attach:cstr_nmpc_solution_Python.zip|Python Solution for CSTR Control (Nonlinear MPC)
]]
March 05, 2016, at 05:21 PM by 45.56.3.173 -
Changed line 23 from:
Attach:download.png [[Attach:cstr_mpc_solution_Python.zip|Python Solution for CSTR Control]]
to:
Attach:zip.png [[Attach:cstr_mpc_solution_Python.zip|Python Solution for CSTR Control]]
March 04, 2016, at 06:20 PM by 10.4.53.157 -
Changed lines 21-25 from:
!!!! Solution
to:
!!!! Solution in Python

Attach:download.png [[Attach:cstr_mpc_solution_Python.zip|Python Solution for CSTR Control]]

!!!! Solution in Simulink
Deleted lines 5-8:

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/qH55ym1g-NM" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
May 25, 2015, at 01:46 AM by 184.203.121.185 -
Added lines 41-43:
(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/PyrLMlht-PU" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
May 25, 2015, at 01:05 AM by 184.203.121.185 -
Added lines 34-37:

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/lBx10LvT8uA" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
May 24, 2015, at 10:34 PM by 12.217.225.253 -
Added lines 27-28:
Attach:download.png [[Attach:cstr_control_solution_PID.zip|Solution 1: PID CSTR Control]]
Changed lines 33-35 from:
Attach:download.png [[Attach:cstr_control_solution_Linear_MPC.zip|Linear MPC CSTR Control]]

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|Nonlinear MPC CSTR Control]]
to:
Attach:download.png [[Attach:cstr_control_solution_Linear_MPC.zip|Solution 2: Linear MPC CSTR Control]]

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|Solution 3: Nonlinear MPC CSTR Control]]
May 24, 2015, at 10:33 PM by 12.217.225.253 -
Deleted lines 25-28:

Attach:download.png [[Attach:cstr_control_solution.zip|All CSTR Control Solution Files]]

Attach:download.png [[Attach:cstr_control_solution_PID.zip|PID CSTR Control]]
May 23, 2015, at 08:26 PM by 174.148.103.31 -
Added lines 22-23:

See additional information on this application on the [[https://apmonitor.com/che436/index.php/Main/CaseStudyCSTR|Process Control Class Web-page]].
May 23, 2015, at 08:24 PM by 174.148.103.31 -
Added lines 34-35:

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|Nonlinear MPC CSTR Control]]
May 23, 2015, at 08:08 PM by 45.56.3.184 -
Added line 33:
Attach:download.png [[Attach:cstr_control_solution_Linear_MPC.zip|Linear MPC CSTR Control]]
May 23, 2015, at 03:10 PM by 45.56.3.184 -
Changed lines 25-33 from:
Attach:download.png [[Attach:cstr_control_solution.zip|CSTR Control Solution Files]]
to:
Attach:download.png [[Attach:cstr_control_solution.zip|All CSTR Control Solution Files]]

Attach:download.png [[Attach:cstr_control_solution_PID.zip|PID CSTR Control]]

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/sfhHcSF2i90" frameborder="0" allowfullscreen></iframe>
(:htmlend:)

May 23, 2015, at 03:03 PM by 45.56.3.184 -
Changed line 21 from:
A reactor is used to convert a hazardous chemical '''A''' to an acceptable chemical '''B''' in waste stream before entering a nearby lake. This particular reactor is dynamically modeled as a Continuously Stirred Tank Reactor (CSTR) with a simplified kinetic mechanism that describes the conversion of reactant '''A''' to product '''B''' with an irreversible and exothermic reaction. It is desired to maintain the temperature at a constant setpoint that maximizes the destruction of A (highest possible temperature).
to:
A reactor is used to convert a hazardous chemical '''A''' to an acceptable chemical '''B''' in waste stream before entering a nearby lake. This particular reactor is dynamically modeled as a Continuously Stirred Tank Reactor (CSTR) with a simplified kinetic mechanism that describes the conversion of reactant '''A''' to product '''B''' with an irreversible and exothermic reaction. It is desired to maintain the temperature at a constant setpoint that maximizes the destruction of A (highest possible temperature). Adjust the jacket temperature (''T'_c_''') to maintain a desired  reactor temperature and minimize the concentration of '''A'''. The reactor temperature should never exceed 400 K. The cooling jacket temperature can be adjusted between 250 K and 350 K.
May 22, 2015, at 06:36 PM by 10.5.113.160 -
Added lines 24-25:

Attach:download.png [[Attach:cstr_control_solution.zip|CSTR Control Solution Files]]
May 22, 2015, at 06:32 PM by 10.5.113.160 -
Changed line 15 from:
[[Attach:cstr_control.pdf|Problem Statement]]
to:
[[Attach:cstr_control.pdf|Problem Information]]
May 18, 2015, at 04:03 PM by 45.56.3.184 -
Changed line 13 from:
'''Objective:''' Design a controller to maintain temperature of a chemical reactor. Develop 3 separate controllers (PID, Linear MPC, Nonlinear MPC) in Python or MATLAB/Simulink. Demonstrate controller performance with steps in the set point and disturbance changes. ''Estimated time: 3 hours.''
to:
'''Objective:''' Design a controller to maintain temperature of a chemical reactor. Develop 3 separate controllers (PID, Linear MPC, Nonlinear MPC) in Python, MATLAB, or Simulink. Demonstrate controller performance with steps in the set point and disturbance changes. ''Estimated time: 3 hours.''
May 18, 2015, at 03:26 PM by 45.56.3.184 -
Deleted lines 5-8:

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/YHAA-uXhI0E?rel=0" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
May 18, 2015, at 03:23 PM by 45.56.3.184 -
Changed lines 17-18 from:
'''Objective:''' Design a model predictive controller to maintain temperature of a chemical reactor. Develop a linear, first-order model of the reactor and implement the controller in Python or MATLAB/Simulink. Demonstrate controller performance with steps in the set point and disturbance changes. ''Estimated time: 3 hours.''
to:
'''Objective:''' Design a controller to maintain temperature of a chemical reactor. Develop 3 separate controllers (PID, Linear MPC, Nonlinear MPC) in Python or MATLAB/Simulink. Demonstrate controller performance with steps in the set point and disturbance changes. ''Estimated time: 3 hours.''
Deleted line 27:
May 13, 2015, at 06:05 PM by 10.5.113.160 -
Changed lines 13-28 from:
(:htmlend:)
to:
(:htmlend:)

!!!! Exercise

'''Objective:''' Design a model predictive controller to maintain temperature of a chemical reactor. Develop a linear, first-order model of the reactor and implement the controller in Python or MATLAB/Simulink. Demonstrate controller performance with steps in the set point and disturbance changes. ''Estimated time: 3 hours.''

[[Attach:cstr_control.pdf|Problem Statement]]

Attach:download.png [[Attach:cstr_control.zip|CSTR Source Files]]

Attach:cstr.png

A reactor is used to convert a hazardous chemical '''A''' to an acceptable chemical '''B''' in waste stream before entering a nearby lake. This particular reactor is dynamically modeled as a Continuously Stirred Tank Reactor (CSTR) with a simplified kinetic mechanism that describes the conversion of reactant '''A''' to product '''B''' with an irreversible and exothermic reaction. It is desired to maintain the temperature at a constant setpoint that maximizes the destruction of A (highest possible temperature).

!!!! Solution

Added lines 9-12:
(:htmlend:)

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/qH55ym1g-NM" frameborder="0" allowfullscreen></iframe>
Changed lines 5-9 from:
Dynamic control is also known as Nonlinear Model Predictive Control (NMPC) or simply as Nonlinear Control (NLC). NLC with predictive models is a dynamic optimization approach that seeks to follow a trajectory or drive certain values to maximum or minimum levels.
to:
Dynamic control is also known as Nonlinear Model Predictive Control (NMPC) or simply as Nonlinear Control (NLC). NLC with predictive models is a dynamic optimization approach that seeks to follow a trajectory or drive certain values to maximum or minimum levels.

(:html:)
<iframe width="560" height="315" src="https://www.youtube.com/embed/YHAA-uXhI0E?rel=0" frameborder="0" allowfullscreen></iframe>
(:htmlend:)
Added lines 1-5:
(:title Nonlinear Model Predictive Control:)
(:keywords Nonlinear, Model Predictive Control, real-time, tutorial:)
(:description Nonlinear Control (NLC) with predictive models is a dynamic optimization approach that seeks to follow a trajectory or drive certain values to maximum or minimum levels:)

Dynamic control is also known as Nonlinear Model Predictive Control (NMPC) or simply as Nonlinear Control (NLC). NLC with predictive models is a dynamic optimization approach that seeks to follow a trajectory or drive certain values to maximum or minimum levels.