How to estimate theta value in FOPDT equation using gekko? - python

I'm trying to use GEKKO to fit to a certain dataset, using the FOPDT Optimization Method to estimate k, tau and theta.
I saw the example using odeint on https://apmonitor.com/pdc/index.php/Main/FirstOrderOptimization and tried to do the same thing with GEKKO, but I can't use the value of theta in the equation.
I saw this question where should the delay call be placed inside a gekko code? and the docs https://apmonitor.com/wiki/index.php/Apps/TimeDelay, but in this case I wanted to estimate the value of theta and not use the initial guess value. I tried to use gekko's delay, but I get an error that it only works if the delay is an int value (and not a gekko FV).
I also tried to use time directly in the equation, but I can't figure out how to place x(t-theta) in there, since I can't do that syntax with gekko variables.
import pandas as pd
import numpy as np
from gekko import GEKKO
import plotly.express as px
data = pd.read_csv('data.csv',sep=',',header=0,index_col=0)
xm1 = data['x']
ym1 = data['y']
xm = xm1.to_numpy()
ym = ym1.to_numpy()
xm_r = len(xm)
tm = np.linspace(0,xm_r-1,xm_r)
m = GEKKO()
m.options.IMODE=5
m.time = tm
k = m.FV()
k.STATUS=1
tau = m.FV()
tau.STATUS=1
theta = m.FV()
theta.STATUS=1
x = m.Param(value=xm)
y = m.CV()
y.FSTATUS = 1
yObj = m.Param(value=ym)
xtheta = m.Var()
m.delay(x,xtheta,theta)
m.Equation(y.dt()==(-y + k * xtheta)/tau)
m.Minimize((y-yObj)**2)
m.options.EV_TYPE=2
m.solve(disp=True)

Here are some strategies for implementing variable time-delay in a model such as when an optimizer adjusts the time delay in a First Order Plus Dead Time (FOPDT) model.
Create a cubic spline (continuous approximation) of the relationship between time t and the input u. This allows a fractional time delay that is not restricted to an integer multiple of the sample interval.
Create time as a variable with derivative equal to 1.
Define tc with an equation tc==time-theta to get the time shifted value. This will lookup the spline uc value that corresponds to this tc value.
You can also fit the FOPDT model to data with Excel or other tools.
from gekko import GEKKO
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# load data
url = 'http://apmonitor.com/do/uploads/Main/tclab_siso_data.txt'
data = pd.read_csv(url)
t = data['time'].values
u = data['voltage'].values
y = data['temperature'].values
m = GEKKO(remote=False)
m.time = t; time = m.Var(0); m.Equation(time.dt()==1)
K = m.FV(lb=0,ub=1); K.STATUS=1
tau = m.FV(lb=1,ub=300); tau.STATUS=1
theta = m.FV(lb=2,ub=30); theta.STATUS=1
# create cubic spline with t versus u
uc = m.Var(u); tc = m.Var(t); m.Equation(tc==time-theta)
m.cspline(tc,uc,t,u,bound_x=False)
ym = m.Param(y)
yp = m.Var(y); m.Equation(tau*yp.dt()+(yp-y[0])==K*(uc-u[0]))
m.Minimize((yp-ym)**2)
m.options.IMODE=5
m.solve()
print('K: ', K.value[0])
print('tau: ', tau.value[0])
print('theta: ', theta.value[0])
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,u)
plt.legend([r'$V_1$ (mV)'])
plt.ylabel('MV Voltage (mV)')
plt.subplot(2,1,2)
plt.plot(t,y)
plt.plot(t,yp)
plt.legend([r'$T_{1meas}$',r'$T_{1pred}$'])
plt.ylabel('CV Temp (degF)')
plt.xlabel('Time')
plt.savefig('sysid.png')
plt.show()
K: 0.25489655932
tau: 229.06377617
theta: 2.0
Another way to approach this is to estimate a higher-order ARX model and then determine the statistical significance of the beta terms. Here is an example of using the Gekko sysid function.
from gekko import GEKKO
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# load data and parse into columns
url = 'http://apmonitor.com/do/uploads/Main/tclab_siso_data.txt'
data = pd.read_csv(url)
t = data['time']
u = data['voltage']
y = data['temperature']
# generate time-series model
m = GEKKO()
# system identification
na = 5 # output coefficients
nb = 5 # input coefficients
yp,p,K = m.sysid(t,u,y,na,nb,pred='meas')
print('alpha: ', p['a'])
print('beta: ', p['b'])
print('gamma: ', p['c'])
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,u)
plt.legend([r'$V_1$ (mV)'])
plt.ylabel('MV Voltage (mV)')
plt.subplot(2,1,2)
plt.plot(t,y)
plt.plot(t,yp)
plt.legend([r'$T_{1meas}$',r'$T_{1pred}$'])
plt.ylabel('CV Temp (degF)')
plt.xlabel('Time')
plt.savefig('sysid.png')
plt.show()
With results:
alpha: [[0.525143 ]
[0.19284469]
[0.08177381]
[0.06152181]
[0.12918898]]
beta: [[[-8.51804876e-05]
[ 5.88425202e-04]
[ 1.99205676e-03]
[-2.81456773e-03]
[ 2.38110003e-03]]]
gamma: [0.75189199]
The first two beta terms are nearly zero but they can also be left in the model for a higher-order representation of the system.

Related

Gekko model with variable delay

I have a system with a non-constant delay. Does gekko support this type of problem and can it be handled in the MHE and MPC formulation?
Reading the docs I can see how to implement the delay, but I am not sure how the state estimation part of the MPC/MHE will handle this or if it is even capable to deal with such problems.
There is no problem to include variable time delay in estimation or control problems. There is a reformulation of the problem to allow for continuous 1st and 2nd derivatives that are needed for a gradient-based optimizer. I recommend that you use a cubic spline to create a continuous approximation of the discontinuous delay function. This way, the delay can be fractional such as theta=2.3. If the delay must be integer steps then set integer=True for the theta decision variable.
theta_ub = 30 # upper bound to dead-time
theta = m.FV(0,lb=0,ub=theta_ub); theta.STATUS=1
# add extrapolation points
td = np.concatenate((np.linspace(-theta_ub,min(t)-1e-5,5),t))
ud = np.concatenate((u[0]*np.ones(5),u))
# create cubic spline with t versus u
uc = m.Var(u); tc = m.Var(t); m.Equation(tc==time-theta)
m.cspline(tc,uc,td,ud,bound_x=False)
Here is an example of one cycle of Moving Horizon Estimation with a first-order plus dead-time (FOPDT) model with variable time delay. This example is from the Process Dynamics and Control online course.
import numpy as np
import pandas as pd
from gekko import GEKKO
import matplotlib.pyplot as plt
# Import CSV data file
# Column 1 = time (t)
# Column 2 = input (u)
# Column 3 = output (yp)
url = 'http://apmonitor.com/pdc/uploads/Main/data_fopdt.txt'
data = pd.read_csv(url)
t = data['time'].values - data['time'].values[0]
u = data['u'].values
y = data['y'].values
m = GEKKO(remote=False)
m.time = t; time = m.Var(0); m.Equation(time.dt()==1)
K = m.FV(2,lb=0,ub=10); K.STATUS=1
tau = m.FV(3,lb=1,ub=200); tau.STATUS=1
theta_ub = 30 # upper bound to dead-time
theta = m.FV(0,lb=0,ub=theta_ub); theta.STATUS=1
# add extrapolation points
td = np.concatenate((np.linspace(-theta_ub,min(t)-1e-5,5),t))
ud = np.concatenate((u[0]*np.ones(5),u))
# create cubic spline with t versus u
uc = m.Var(u); tc = m.Var(t); m.Equation(tc==time-theta)
m.cspline(tc,uc,td,ud,bound_x=False)
ym = m.Param(y); yp = m.Var(y)
m.Equation(tau*yp.dt()+(yp-y[0])==K*(uc-u[0]))
m.Minimize((yp-ym)**2)
m.options.IMODE=5
m.solve()
print('Kp: ', K.value[0])
print('taup: ', tau.value[0])
print('thetap: ', theta.value[0])
# plot results
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,y,'k.-',lw=2,label='Process Data')
plt.plot(t,yp.value,'r--',lw=2,label='Optimized FOPDT')
plt.ylabel('Output')
plt.legend()
plt.subplot(2,1,2)
plt.plot(t,u,'b.-',lw=2,label='u')
plt.legend()
plt.ylabel('Input')
plt.xlabel('Time')
plt.show()

Gekko Optimization doesn't give me a unique answer although there is a unique answer for my model

my optimization model works but with different initial values for the main variable (Pre), it gives a different answer! not the optimal one! but this should have one answer.
I do not understand why!
try:
from pip import main as pipmain
except:
from pip._internal import main as pipmain
pipmain(['install','gekko'])
from gekko import GEKKO
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#Initialize Model
m = GEKKO(remote=False)
#define parameter
df=pd.read_excel (r'C:\Users\....')
Pw=pd.DataFrame(df).values
eta = m.Const(value=0.6)
Pre=m.Var(lb=20, ub=30)
Pre.value=23
def f(Pw,Pre):
Dplus=m.Var(value=0)
Dminus=m.Var(value=0)
for i in range(744):
D=float(Pw[i])-Pre.value
if D>=0:
Dplus.value=Dplus.value+D*eta.value
elif D<0:
Dminus.value=Dminus.value+D
return Dplus+Dminus
#constraint:
m.Equation(f(Pw,Pre)>=0)
#Objective:
m.Minimize(f(Pw,Pre))
#Set global options:
m.options.IMODE = 2 #steady state optimization
#Solve simulation:
m.solve()
You shouldn't use .value to build model equations because it only references the initial guess value, not the variable value. Use the m.if3() (preferred) or m.if2() functions to use conditional statements in the model. Here is an example of m.if3():
import numpy as np
import matplotlib.pyplot as plt
from gekko import GEKKO
m = GEKKO(remote=False)
p = m.Param()
y = m.if3(p-4,p**2,p+1)
# solve with condition<0
p.value = 3
m.solve(disp=False)
print(y.value)
# solve with condition>=0
p.value = 5
m.solve(disp=False)
print(y.value)
An even better way to incorporate conditional statements is to use slack variables. It appears that your application is for energy storage where there is inefficiency in the storage process given by eta. Here is a simple energy storage problem (see problem 4) where the loss from storage and retrieval is embedded in the optimization.
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
m = GEKKO(remote=False)
m.time = np.linspace(0,1,101)
g = m.FV(); g.STATUS = 1 # production
s = m.Var(1e-2, lb=0) # storage inventory
store = m.Var() # store energy rate
s_in = m.Var(lb=0) # store slack variable
recover = m.Var() # recover energy rate
s_out = m.Var(lb=0) # recover slack variable
eta = 0.7
d = m.Param(-2*np.sin(2*np.pi*m.time)+10)
m.periodic(s)
m.Equations([g + recover/eta - store >= d,
g - d == s_out - s_in,
store == g - d + s_in,
recover == d - g + s_out,
s.dt() == store - recover/eta,
store * recover <= 0])
m.Minimize(g)
m.options.SOLVER = 1
m.options.IMODE = 6
m.options.NODES = 3
m.solve()
plt.figure(figsize=(6,3))
plt.subplot(2,1,1)
plt.plot(m.time,d,'r-',label='Demand')
plt.plot(m.time,g,'b:',label='Prod')
plt.legend(); plt.grid(); plt.xlim([0,1])
plt.subplot(2,1,2)
plt.plot(m.time,s,'k-',label='Storage')
plt.plot(m.time,store,'g--', label='Store Rate')
plt.plot(m.time,recover,'b:', label='Recover Rate')
plt.legend(); plt.grid(); plt.xlim([0,1])
plt.show()

Improving the quality of non-linear regression in Python gekko

I am trying to use the python GEKKO non-linear regression tools to perform system identification of a second order over-damped system using the step response.
My code is as follows:
m = GEKKO()
m_input = m.Param(value=input)
m_time=m.Param(value=time)
m_T1 = m.FV(value=initT1, lb=T1bounds[0], ub=T1bounds[1])
m_T1.STATUS = 1
m_k = m.FV(value=initk,lb=100)
m_k.STATUS = 1
m_T2 = m.FV(value=initT2, lb=T2bounds[0], ub=T2bounds[1])
m_T2.STATUS = 1
m_output = m.CV(value=output)
m_output.FSTATUS=1
m.Equation(m_output==(m_k/(m_T1+m_T2))*(1+((m_T1/(m_T2-m_T1))*m.exp(-m_time/m_T2))-((m_T2/(m_T2-m_T1))*m.exp(-m_time/m_T1)))*m_input)
m.options.IMODE = 2
m.options.MAX_ITER = 10000
m.options.OTOL = 1e-8
m.options.RTOL = 1e-8
m.solve(disp=True)
The results have not been promising. It seems that the optimizer seems to get stuck in local minimas of the objective function leaving the objective function too high
The output of the solver is:
The final value of the objective function is 160453.282142838
---------------------------------------------------
Solver : IPOPT (v3.12)
Solution time : 7.60390000000189 sec
Objective : 160453.282605857
Successful solution
---------------------------------------------------
What can I do to improve the quality of the fit? Can I place limits on the objective function value?
Try using the equation for an underdamped 2nd order system instead of an overdamped 2nd order system. There is more information on the explicit solution to 2nd order systems on the Process Dynamics and Control website. An even better approach is to not use the explicit solution where it must be pre-determined if it is underdamped, critically damped, or overdamped. If the original 2nd order differential equation is used then the solver can decide if it is underdamped (overshoot with oscillations) or overdamped. Here is example code for fitting a 2nd order system.
import numpy as np
import pandas as pd
from gekko import GEKKO
import matplotlib.pyplot as plt
# Import CSV data file
# Column 1 = time (t)
# Column 2 = input (u)
# Column 3 = output (y)
url = 'http://apmonitor.com/pdc/uploads/Main/data_sopdt.txt'
data = pd.read_csv(url)
t = data['time'].values - data['time'].values[0]
u = data['u'].values
y = data['y'].values
m = GEKKO(remote=False)
m.time = t; time = m.Var(0); m.Equation(time.dt()==1)
K = m.FV(2,lb=0,ub=10); K.STATUS=1
tau = m.FV(3,lb=1,ub=200); tau.STATUS=1
theta_ub = 30 # upper bound to dead-time
theta = m.FV(0,lb=0,ub=theta_ub); theta.STATUS=1
zeta = m.FV(1,lb=0.1,ub=3); zeta.STATUS=1
# add extrapolation points
td = np.concatenate((np.linspace(-theta_ub,min(t)-1e-5,5),t))
ud = np.concatenate((u[0]*np.ones(5),u))
# create cubic spline with t versus u
uc = m.Var(u); tc = m.Var(t); m.Equation(tc==time-theta)
m.cspline(tc,uc,td,ud,bound_x=False)
ym = m.Param(y); yp = m.Var(y); xp = m.Var(y)
m.Equation(xp==yp.dt())
m.Equation((tau**2)*xp.dt()+2*zeta*tau*yp.dt()+yp==K*(uc-u[0]))
m.Minimize((yp-ym)**2)
m.options.IMODE=5
m.solve(disp=False)
print('Kp: ', K.value[0])
print('taup: ', tau.value[0])
print('thetap: ', theta.value[0])
print('zetap: ', zeta.value[0])
# plot results
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,y,'k.-',lw=2,label='Process Data')
plt.plot(t,yp.value,'r--',lw=2,label='Optimized SOPDT')
plt.ylabel('Output')
plt.legend()
plt.subplot(2,1,2)
plt.plot(t,u,'b.-',lw=2,label='u')
plt.legend()
plt.ylabel('Input')
plt.show()
Please try this with your data to see if it gives a better solution.

ARX models is Gekko

So this is a follow-up question to this one: ARX Models in Gekko.
I think I didn't give enough details and my question was not very clear.
First of all, I am looking for the model of my system to use it in an MPC so the identification needs to be good in order to get good results from my MPC.
This is the code I used to the system Identification with GEKKO. I used data of about 5 hours where the fridge was only controlled by a thermostat. There was data coming from my sensor every 5 sec.
Identification with Sysid()
from gekko import GEKKO
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
#Load data
a_dataframe = pd.read_csv("State.txt")
a_dataframe.columns = ["State"]
u = a_dataframe["State"]
b_dataframe = pd.read_csv("Temp.txt")
b_dataframe.columns = ["Temp"]
T = b_dataframe["Temp"]
t = np.linspace(0,17180,3436)
#Identification
m = GEKKO()
na = 1 # output coefficients
nb = 1 # input coefficients
yp,p,K = m.sysid(t,u,T,na,nb,shift='calc',pred='meas')
#Plots
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,u)
plt.subplot(2,1,2)
plt.plot(t,T)
plt.plot(t,yp)
plt.xlabel('Time')
plt.show()
Plotted Results
The results I got with sysid() were not good. Despite these results,
I simulated the ARX model with the following code. Using the p dictionary that I got from sysid().
Simulation
from gekko import GEKKO
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
na = 1# Number of A coefficients
nb = 1 # Number of B coefficients
ny = 1 # Number of outputs
nu = 1 # Number of inputs
# A (na x ny)
# actual A,B,C values are from 5 h data
A = np.array([[1.00037807]])
# B (ny x (nb x nu))
B= np.array([[[-0.01318095]]])
C = np.array([-0.00162522])
# create parameter dictionary
# parameter dictionary p['a'], p['b'], p['c']
# a (coefficients for a polynomial, na x ny)
# b (coefficients for b polynomial, ny x (nb x nu))
# c (coefficients for output bias, ny)
p = {'a':A,'b':B,'c':C}
m = GEKKO(remote=True)
y,u = m.arx(p)
# load inputs
#tf = 719 # final time
u1 = np.append(np.ones(500),np.zeros(500),0)
u2 = np.append(u1, np.ones(500),0)
u3 = np.append(u2, np.zeros(500),0)
u4 = np.append(u3, np.ones(500),0)
u5 = np.append(u4, np.zeros(936),0)
u[0].value = u5
cv = y[0]
mv= u[0]
cv.value = 14.2
m.time = np.linspace(0,17180,3436)
m.options.imode = 4
m.options.nodes= 2
#m.options.SOLVER = 1
# simulate
m.solve()
The Simulation results:
The changes in temperature are not logical. At the end the fridge is off and the temperature keeps on decresing. And my fridge ist not powerful enough to attein -5 °C.
My questions are:
What am I potentially doing wrong here? did I use enough data for the identification?
Why do I get other coefficients for p when using linear regression than with sysid()? (Code from my last post)
Does sysid() proceed like linear regression?
Why do I get better fitting results with linear regression but the temperature does not change much when plotting the simulation? (See simulation plot of linear regression in my last post)
Thanks in advance :)

How to build process simulator in gekko knowing time constant and steady-state values

I have a very complicated non-linear dynamical system for which I know time constant and steady-state responses at each time instance from CFD (Computational Fluid Dynamics). How do I (1) build a process simulator using this information? and (2) how do I tune time-constant values if I know measured inputs and outputs and steady-state values?
Question 1: Build a Process Simulator
You may want to first try a linear time-series model and then go to nonlinear if this doesn't work. Below is a sample script to identify a linear time-series model.
from gekko import GEKKO
import pandas as pd
import matplotlib.pyplot as plt
# load data and parse into columns
url = 'http://apmonitor.com/do/uploads/Main/tclab_dyn_data2.txt'
data = pd.read_csv(url)
t = data['Time']
u = data[['H1','H2']]
y = data[['T1','T2']]
# generate time-series model
m = GEKKO(remote=False) # remote=True for MacOS
# system identification
na = 2 # output coefficients
nb = 2 # input coefficients
yp,p,K = m.sysid(t,u,y,na,nb,diaglevel=1)
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,u)
plt.legend([r'$u_0$',r'$u_1$'])
plt.ylabel('MVs')
plt.subplot(2,1,2)
plt.plot(t,y)
plt.plot(t,yp)
plt.legend([r'$y_0$',r'$y_1$',r'$z_0$',r'$z_1$'])
plt.ylabel('CVs')
plt.xlabel('Time')
plt.savefig('sysid.png')
plt.show()
Note that the data can be dynamic data, not necessarily separated into steady-state and dynamic parts. You need to call m.sysid with the correct inputs as detailed in the documentation. Once you have a good model, you can transform it into a simulator with m.arx(p) where p is the parameter output from the m.sysid function.
If linear identification doesn't work then you can try a nonlinear approach such as shown in TCLab B Exercise (See Python Gekko Neural Network). You can use Gekko's Deep Learning capabilities to simplify the coding. Once you have a steady-state relationship, add dynamics with a first-order or second-order relationship with a differential equation that relates the steady-state output to the dynamic output such as m.Equation(tau * x.dt() + x = x_ss) where tau is the time constant, x.dt() is the time derivative, x is the dynamic output, and x_ss is the steady state output. This is called a Hammerstein model because the steady state precedes the dynamic calculations. You can also put the dynamics on the inputs as a Wiener model. You'll be able to find more information on-line about Hammerstein-Wiener Models.
Question 2: Tuning the time constants
If you already have a steady-state relationship and you want to tune the time constants then regression is a powerful method because it can try many different combinations of your time constant to minimize the difference between model and measurements. There are a few examples of doing this with scipy.optimize.minimize and gekko.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from gekko import GEKKO
# Import or generate data
filename = 'tclab_dyn_data2.csv'
try:
data = pd.read_csv(filename)
except:
url = 'http://apmonitor.com/do/uploads/Main/tclab_dyn_data2.txt'
data = pd.read_csv(url)
# Create GEKKO Model
m = GEKKO()
m.time = data['Time'].values
# Parameters to Estimate
U = m.FV(value=10,lb=1,ub=20)
alpha1 = m.FV(value=0.01,lb=0.003,ub=0.03) # W / % heater
alpha2 = m.FV(value=0.005,lb=0.002,ub=0.02) # W / % heater
# STATUS=1 allows solver to adjust parameter
U.STATUS = 1
alpha1.STATUS = 1
alpha2.STATUS = 1
# Measured inputs
Q1 = m.MV(value=data['H1'].values)
Q2 = m.MV(value=data['H2'].values)
# State variables
TC1 = m.CV(value=data['T1'].values)
TC1.FSTATUS = 1 # minimize fstatus * (meas-pred)^2
TC2 = m.CV(value=data['T2'].values)
TC2.FSTATUS = 1 # minimize fstatus * (meas-pred)^2
Ta = m.Param(value=19.0+273.15) # K
mass = m.Param(value=4.0/1000.0) # kg
Cp = m.Param(value=0.5*1000.0) # J/kg-K
A = m.Param(value=10.0/100.0**2) # Area not between heaters in m^2
As = m.Param(value=2.0/100.0**2) # Area between heaters in m^2
eps = m.Param(value=0.9) # Emissivity
sigma = m.Const(5.67e-8) # Stefan-Boltzmann
# Heater temperatures in Kelvin
T1 = m.Intermediate(TC1+273.15)
T2 = m.Intermediate(TC2+273.15)
# Heat transfer between two heaters
Q_C12 = m.Intermediate(U*As*(T2-T1)) # Convective
Q_R12 = m.Intermediate(eps*sigma*As*(T2**4-T1**4)) # Radiative
# Semi-fundamental correlations (energy balances)
m.Equation(TC1.dt() == (1.0/(mass*Cp))*(U*A*(Ta-T1) \
+ eps * sigma * A * (Ta**4 - T1**4) \
+ Q_C12 + Q_R12 \
+ alpha1*Q1))
m.Equation(TC2.dt() == (1.0/(mass*Cp))*(U*A*(Ta-T2) \
+ eps * sigma * A * (Ta**4 - T2**4) \
- Q_C12 - Q_R12 \
+ alpha2*Q2))
# Options
m.options.IMODE = 5 # MHE
m.options.EV_TYPE = 2 # Objective type
m.options.NODES = 2 # Collocation nodes
m.options.SOLVER = 3 # IPOPT
# Solve
m.solve(disp=True)
# Parameter values
print('U : ' + str(U.value[0]))
print('alpha1: ' + str(alpha1.value[0]))
print('alpha2: ' + str(alpha2.value[0]))
# Create plot
plt.figure()
ax=plt.subplot(2,1,1)
ax.grid()
plt.plot(data['Time'],data['T1'],'ro',label=r'$T_1$ measured')
plt.plot(m.time,TC1.value,color='purple',linestyle='--',\
linewidth=3,label=r'$T_1$ predicted')
plt.plot(data['Time'],data['T2'],'bx',label=r'$T_2$ measured')
plt.plot(m.time,TC2.value,color='orange',linestyle='--',\
linewidth=3,label=r'$T_2$ predicted')
plt.ylabel('Temperature (degC)')
plt.legend(loc=2)
ax=plt.subplot(2,1,2)
ax.grid()
plt.plot(data['Time'],data['H1'],'r-',\
linewidth=3,label=r'$Q_1$')
plt.plot(data['Time'],data['H2'],'b:',\
linewidth=3,label=r'$Q_2$')
plt.ylabel('Heaters')
plt.xlabel('Time (sec)')
plt.legend(loc='best')
plt.show()

Categories