如何使用gekko估计FOPDT方程中的theta值?

How to estimate theta value in FOPDT equation using gekko?

我正在尝试使用 GEKKO 来拟合某个数据集,使用 FOPDT 优化方法来估计 k、tau 和 theta。

我在 https://apmonitor.com/pdc/index.php/Main/FirstOrderOptimization 上看到了使用 odeint 的例子,并尝试用 GEKKO 做同样的事情,但我不能在等式中使用 theta 的值。

我看到了这个问题 and the docs https://apmonitor.com/wiki/index.php/Apps/TimeDelay,但是在这种情况下我想估计theta的值而不是使用初始猜测值。我尝试使用 gekko 的延迟,但我得到一个错误,它只有在延迟是一个 int 值(而不是 gekko FV)时才有效。 我也尝试在等式中直接使用时间,但我无法弄清楚如何将 x(t-theta) 放在那里,因为我不能用 gekko 变量执行该语法。

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)

以下是在模型中实现变量 time-delay 的一些策略,例如当优化器调整一阶加死时间 (FOPDT) 模型中的时间延迟时。

  • 创建时间 t 和输入 u 之间关系的三次样条(连续逼近)。这允许小数时间延迟不限于采样间隔的整数倍。
  • 创建time作为导数等于1的变量。
  • 用等式tc==time-theta定义tc得到时移值。这将查找对应于此 tc 值的样条 uc 值。

您还可以使用 Excel 或其他工具 fit the FOPDT model 获取数据。

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

另一种方法是估计 higher-order ARX model,然后确定 beta 项的统计显着性。这是使用 Gekko sysid 函数的示例。

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

结果:

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]

前两个 beta 项几乎为零,但它们也可以保留在模型中以 higher-order 表示系统。