Чтобы смоделировать мертвое время в модели FOPDT с помощью пакета GEKKO, я использовал функцию Gekko «cspline», чтобы сделать операцию временного сдвига более плавной.
Это хорошо работает, когда вход изменяется после продолжительности мертвого времени. (например, ввод изменяется при t = 15, когда мертвое время = 10)
Однако, когда входные данные изменяются до истечения мертвого времени (например, входные данные изменяются в момент времени t=5, когда мертвое время=10), похоже, что функция cspline чрезмерно экстраполирует входное значение. Пожалуйста, дайте несколько советов, чтобы избежать этой проблемы.
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()
Объект cspline получает данные для диапазона от t=0
до t=50
, но он получает доступ к значениям от t=-10
до t=40
. Ошибка возникает из-за экстраполяции кубического сплайна. Вы можете генерировать данные сплайна в диапазоне от t=-theta_ub
до t=50
, чтобы избежать проблем с экстраполяцией.
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()
Если мертвое время является статическим, то вместо этого я рекомендую дискретную форму пространства состояний. Это реализовано как
m.delay()
в Gekko. Вот более подробная информация: apmonitor.com/wiki/index.php/Apps/TimeDelay и apmonitor.com/wiki/index.php/Apps/DiscreteStateSpace