This question is related to this my previous question how to formulate the problem of finding the optimal PID paramters in gekko?
I have successfully estimated the optimal PID parameters by minimizing the IAE based on the answer to the above question. However, I would like to add a constraint of MV overshoot in the objective function. Below is the pseudo code to add the constraint that the MV overshoot should be less than 10 % .
MV_Overshoot= Max_MV - SteadyState_MV
MV_Overshoot < 0.1*Steady_State MV # constraint
However, I am stuck with the 2 questions below
or is there any better way to calculate the MV overshoot ?
Solve a first step with a steady state calculation to determine the OP (MV) and PV values.
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
# Process model
Kp = 0.5 # process gain
tauP = 10.0 # process time constant
# pre-solve for steady state values
m = GEKKO()
OP = m.Var(value=0.0) # controller output (MV)
PV = m.Var(value=0.0) # process variable
SP = m.Param(value=5.0) # final set point
m.Equation(SP==PV) # assume PV reaches set point
m.Equation(tauP*PV.dt() + PV == Kp*OP)
m.options.IMODE = 1
m.solve(disp=False)
print('Steady state target values')
print('OP: ' + str(OP.value[0]))
print('PV: ' + str(PV.value[0]))
print('SP: ' + str(SP.value[0]))
PV_ss = PV.value[0]
OP_ss = OP.value[0]
Solve a second step to optimize the tuning parameters to stay under the requested overshoot targets. Overshoot is typically defined in terms of the distance above the setpoint, not the amount over the MV target. Both are included in the example.
# dynamic optimization of controller tuning
m = GEKKO()
tf = 40
m.time = np.linspace(0,tf,2*tf+1)
step = np.zeros(2*tf+1)
step[3:40] = 0.0
step[40:] = 5.0
# Controller model
Kc = m.FV(15.0,lb=0,ub=100) # controller gain
tauI = m.FV(100.0,lb=0.01,ub=100) # controller reset time
tauD = m.FV(0.0,lb=0,ub=100) # derivative constant
Kc.STATUS = 1; tauI.STATUS = 1; tauD.STATUS = 1
OP_0 = m.Const(value=0.0) # OP bias
OP = m.Var(value=0.0,ub=OP_ss*1.1) # controller output
# with overshoot bound on OP (MV)
PV = m.Var(value=0.0,ub=PV_ss*1.1) # process variable
# with overshoot bound on PV
SP = m.Param(value=step) # set point
Intgl = m.Var(value=0.0) # integral of the error
err = m.Intermediate(SP-PV) # set point error
m.Equation(Intgl.dt()==err) # integral of the error
m.Equation(OP == OP_0 + Kc*err + (Kc/tauI)*Intgl - PV.dt())
m.Equation(tauP*PV.dt() + PV == Kp*OP)
m.Minimize((SP-PV)**2)
m.options.IMODE=6
m.solve(disp=False)
print('Tuning values')
print('Kc: ' + str(Kc.value[0]))
print('tauI: ' + str(tauI.value[0]))
print('tauD: ' + str(tauD.value[0]))
plt.figure()
plt.subplot(2,1,1)
plt.plot([0,max(m.time)],[1.1*OP_ss,1.1*OP_ss],\
'b-',label='Upper bound')
plt.plot(m.time,OP.value,'b:',label='OP')
plt.ylabel('Output')
plt.legend()
plt.subplot(2,1,2)
plt.plot(m.time,SP.value,'k-',label='SP')
plt.plot(m.time,PV.value,'r--',label='PV')
plt.plot([0,max(m.time)],[1.1*PV_ss,1.1*PV_ss],\
'b-',label='Upper bound')
plt.xlabel('Time (sec)')
plt.ylabel('Process')
plt.legend()
plt.show()