To simulate the dead-time in the FOPDT model using the GEKKO package, I used the Gekko 'cspline' function to make the time-shifting operation smoother.
It works well when the input changes after the length of dead-time. (eg. The input changes at t=15 when dead-time=10)
However, when the input changes before the length of dead-time (eg. The input changes at t=5 when dead-time=10), it looks like the cspline function overly extrapolates the input value. Please give some suggestions to avoid this problem.
from gekko import GEKKO
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
tf = 50
npt = 51
t = np.linspace(0,tf,npt)
u1 = np.zeros(npt)
u1[5:] = 5
m = GEKKO(remote=True)
m.time = t
time = m.Var(0)
m.Equation(time.dt()==1)
K1 = m.FV(1,lb=0,ub=1); K1.STATUS=1
tau1 = m.FV(5, lb=1,ub=300); tau1.STATUS=1
theta1 = m.FV(10, lb=2,ub=30); theta1.STATUS=1
uc1 = m.Var(u1)
tc1 = m.Var(t)
m.Equation(tc1==time-theta1)
m.cspline(tc1,uc1,t,u1,bound_x=False)
yp1 = m.Var()
m.Equation(yp1.dt() == -yp1/tau1 + K1*uc1/tau1)
m.options.IMODE=4
m.solve()
print('K1: ', K1.value[0])
print('tau1: ', tau1.value[0])
print('theta1: ', theta1.value[0])
print('')
plt.figure()
plt.subplot(2,1,1)
plt.plot(t,u1)
plt.legend([r'u1'])
plt.ylabel('Input')
plt.subplot(2,1,2)
plt.plot(t,yp1)
plt.legend([r'y1'])
plt.ylabel('Output')
plt.xlabel('Time')
plt.savefig('sysid.png')
plt.show()
The cspline object is given data for the range t=0
to t=50
but it accesses values for t=-10
to t=40
. The error is because of extrapolation from the cubic spline. You can generate spline data in the range t=-theta_ub
to t=50
to avoid extrapolation problems.
from gekko import GEKKO
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
theta_ub = 30
tf = 50
m = GEKKO(remote=True)
m.time = np.linspace(0,tf,tf+1)
time = m.Param(m.time)
K1 = m.FV(1,lb=0,ub=1)
tau1 = m.FV(5,lb=1,ub=300)
theta1 = m.FV(10,lb=2,ub=theta_ub)
u_step = [0 if ti<=5 else 5 for ti in m.time]
uc1 = m.Var()
tc1 = m.Var()
m.Equation(tc1==time-theta1)
# for cspline
t1 = np.linspace(-theta_ub,tf,500)
u1 = [0 if ti<=5 else 5 for ti in t1]
m.cspline(tc1,uc1,t1,u1,bound_x=False)
yp1 = m.Var()
m.Equation(tau1*yp1.dt()+yp1==K1*uc1)
m.options.IMODE=4
m.solve()
print('K1: ', K1.value[0])
print('tau1: ', tau1.value[0])
print('theta1: ', theta1.value[0])
print('')
plt.figure()
plt.subplot(2,1,1)
plt.plot(t1,u1,label='Unshifted Input')
plt.plot(m.time,uc1,label='Shifted Spline')
plt.xlim([0,tf])
plt.legend()
plt.ylabel('Input')
plt.subplot(2,1,2)
plt.plot(m.time,yp1)
plt.legend([r'y1'])
plt.ylabel('Output')
plt.xlabel('Time')
plt.savefig('sysid.png')
plt.show()