Main

(:toggle hide ~~python~~ button show="Show ~~Python Simulation~~ Code":)

(:div id=~~python~~:)
~~[[~~Attach:~~cstr_control~~.~~pdf|Problem Information]]~~

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

(:html:)

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

(:htmlend:)

(:html:)

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

(:htmlend:)

(:html:)

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

(:htmlend:)

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

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

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.

!!!! 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:)

(:html:)

<iframe width="560" height="315" src="https://www.youtube.com/embed/qH55ym1g-NM" frameborder="0" allowfullscreen></iframe>

(:htmlend:)

(: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.zip|All CSTR Control Solution Files]]

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

See additional information on this application on the [[http://apmonitor.com/che436/index.php/Main/CaseStudyCSTR|Process Control Class Web-page]].

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|Nonlinear MPC CSTR Control]]

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

(:html:)

<iframe width="560" height="315" src="https://www.youtube.com/embed/YHAA-uXhI0E?rel=0" frameborder="0" allowfullscreen></iframe>

(:htmlend:)

## Nonlinear Model Predictive Control

## Main.NonlinearControl History

Hide minor edits - Show changes to output

Changed lines 149-151 from:

(:div id=

to:

(:toggle hide gekko_mpc button show="Show GEKKO Linear MPC Code":)

(:div id=gekko_mpc:)

(:div id=gekko_mpc:)

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 = 'http://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)

(: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 = 'http://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)

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]]

Attach:

Attach:

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]]

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]]

Attach:download.png [[Attach:cstr_control_solution_Linear_MPC.zip|

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|

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]]

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]]

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:)

(:html:)

<iframe width="560" height="315" src="

(

Attach:zip

(:html:)

<iframe width="560" height="315" src="

(

Attach:zip

(:html:)

<iframe width="560" height="315" src="

(: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]]

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:)

(:html:)

<iframe width="560" height="315" src="

(

Attach:download.png [[Attach:cstr_control_solution_

(:html:)

<iframe width="560" height="315" src="

(

Attach:download.png [[Attach:cstr_control_solution_

(:html:)

<iframe width="560" height="315" src="

(: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]]

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:)

(:div id=python:)

Added line 143:

(:divend:)

Changed lines 11-13 from:

Attach:

to:

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

Changed line 15 from:

Attach:cstr.png

to:

%width=300px%Attach:cstr.png

Added lines 161-164:

(:html:)

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

(:htmlend:)

Added lines 155-158:

(:html:)

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

(:htmlend:)

Added lines 149-152:

(:html:)

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

(:htmlend:)

Deleted lines 150-151:

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

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)]]

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)]]

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)]]

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)]]

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.

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:)

Changed line 1 from:

(:title Model Predictive Control:)

to:

(:title Nonlinear Model Predictive Control:)

Changed lines 1-2 from:

(:title ~~Nonlinear ~~Model Predictive Control:)

(:keywords Nonlinear, Model Predictive Control, real-time, tutorial:)

(:keywords Nonlinear, Model Predictive Control, real-time, tutorial:)

to:

(:title Model Predictive Control:)

(:keywords Nonlinear, PID, Model Predictive Control, real-time, tutorial:)

(:keywords Nonlinear, PID, Model Predictive Control, real-time, tutorial:)

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)]]

Attach:zip.png [[Attach:cstr_

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)]]

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)]]

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)]]

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

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]]

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

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:)

Added lines 41-43:

(:html:)

<iframe width="560" height="315" src="https://www.youtube.com/embed/PyrLMlht-PU" frameborder="0" allowfullscreen></iframe>

(:htmlend:)

<iframe width="560" height="315" src="https://www.youtube.com/embed/PyrLMlht-PU" frameborder="0" allowfullscreen></iframe>

(:htmlend:)

Added lines 34-37:

(:html:)

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

(:htmlend:)

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]]

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]]

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

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]]

Added lines 22-23:

See additional information on this application on the [[http://apmonitor.com/che436/index.php/Main/CaseStudyCSTR|Process Control Class Web-page]].

Added lines 34-35:

Attach:download.png [[Attach:cstr_control_solution_Nonlinear_MPC.zip|Nonlinear MPC CSTR Control]]

Added line 33:

Attach:download.png [[Attach:cstr_control_solution_Linear_MPC.zip|Linear MPC CSTR Control]]

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:)

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:)

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.

Added lines 24-25:

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

Changed line 15 from:

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

to:

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

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.''

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:)

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:

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

!!!! 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>

(: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:)

(: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.

(: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.