如何通过使用 Gekko 调整参数来解决超调?

问题描述

GEKKO 是混合整数和微分代数方程的优化软件。它与 large-scale solverslinear,quadratic,nonlinear 和混合整数规划 (LP,QP,NLP,MILP,MINLP) 结合使用。 我用gekko来控制我的TCLab Arduino,但是当我发出干扰时,无论我如何调整参数,都会出现过冲温度。我该如何解决这个问题?

这是我的代码

import tclab
import numpy as np
import time
import matplotlib.pyplot as plt
from gekko import GEKKO

# Connect to Arduino
a = tclab.TCLab()

# Get Version
print(a.version)

# Turn LED on
print('LED On')
a.LED(100)

# Run time in minutes
run_time = 60.0

# Number of cycles
loops = int(60.0*run_time)
tm = np.zeros(loops)

# Temperature (K)
T1 = np.ones(loops) * a.T1 # temperature (degC)
Tsp1 = np.ones(loops) * 35.0 # set point (degC)

# heater values
Q1s = np.ones(loops) * 0.0

#########################################################
# Initialize Model
#########################################################
# use remote=True for MacOS
m = GEKKO(name='tclab-mpc',remote=False)

# 100 second time horizon
m.time = np.linspace(0,100,101)

# Parameters
Q1_ss = m.Param(value=0)
TC1_ss = m.Param(value=a.T1)
Kp = m.Param(value=0.8)
tau = m.Param(value=160.0)

# Manipulated variable
Q1 = m.MV(value=0)
Q1.STATUS = 1  # use to control temperature
Q1.FSTATUS = 0 # no Feedback measurement
Q1.LOWER = 0.0
Q1.UPPER = 100.0
Q1.DMAX = 50.0
# Q1.COST = 0.0
Q1.dcosT = 0.2

# Controlled variable
TC1 = m.CV(value=TC1_ss.value)
TC1.STATUS = 1     # minimize error with setpoint range
TC1.FSTATUS = 1    # receive measurement
TC1.TR_INIT = 2    # reference trajectory
TC1.TR_OPEN = 2    # reference trajectory
TC1.TAU = 35       # time constant for response

m.Equation(tau * TC1.dt() + (TC1-TC1_ss) == Kp * (Q1-Q1_ss))

# Global Options
m.options.IMODE   = 6 # MPC
m.options.CV_TYPE = 1 # Objective type
m.options.NODES   = 2 # collocation nodes
m.options.soLVER  = 1 # 1=APOPT,3=IPOPT
##################################################################

# Create plot
plt.figure()
plt.ion()
plt.show()

filter_tc1 = []
def movefilter(predata,new,n):
    if len(predata) < n:
        predata.append(new)
    else:
        predata.pop(0)
        predata.append(new)
    return np.average(predata)

# Main Loop
start_time = time.time()
prev_time = start_time
try:
    for i in range(1,loops):
        # Sleep time
        sleep_max = 1.0
        sleep = sleep_max - (time.time() - prev_time)
        if sleep>=0.01:
            time.sleep(sleep)
        else:
            time.sleep(0.01)

        # Record time and change in time
        t = time.time()
        dt = t - prev_time
        prev_time = t
        tm[i] = t - start_time

        # Read temperatures in Kelvin
        curr_T1 = a.T1
        last_T1 = curr_T1
        avg_T1 = movefilter(filter_tc1,last_T1,3)
        T1[i] = curr_T1

        ###############################
        ### MPC CONTROLLER          ###
        ###############################
        TC1.MEAS = avg_T1
        # input setpoint with deadband +/- DT
        DT = 0.1
        TC1.SPHI = Tsp1[i] + DT
        TC1.SPLO = Tsp1[i] - DT
        # solve MPC
        m.solve(disp=False)
        # test for successful solution
        if (m.options.APPSTATUS==1):
            # retrieve the first Q value
            Q1s[i] = Q1.NEWVAL
        else:
            # not successful,set heater to zero
            Q1s[i] = 0

        # Write output (0-100)
        a.Q1(Q1s[i])

        # Plot
        plt.clf()
        ax=plt.subplot(2,1,1)
        ax.grid()
        plt.plot(tm[0:i],T1[0:i],'ro',MarkerSize=3,label=r'$T_1$')
        plt.plot(tm[0:i],Tsp1[0:i],'b-',label=r'$T_1 Setpoint$')
        plt.ylabel('Temperature (degC)')
        plt.legend(loc='best')
        ax=plt.subplot(2,2)
        ax.grid()
        plt.plot(tm[0:i],Q1s[0:i],'r-',linewidth=3,label=r'$Q_1$')
        plt.ylabel('Heaters')
        plt.xlabel('Time (sec)')
        plt.legend(loc='best')
        plt.draw()
        plt.pause(0.05)

    # Turn off heaters
    a.Q1(0)
    a.Q2(0)
    print('Shutting down')
    a.close()

# Allow user to end loop with Ctrl-C
except KeyboardInterrupt:
    # disconnect from Arduino
    a.Q1(0)
    a.Q2(0)
    print('Shutting down')
    a.close()

# Make sure serial connection still closes when there's an error
except:
    # disconnect from Arduino
    a.Q1(0)
    a.Q2(0)
    print('Error: Shutting down')
    a.close()
    raise

有测试结果图片

Image

解决方法

当您添加干扰(例如打开另一个加热器)时,系统增益会增加,因为温度上升得比控制器预期的要高。这意味着您开始在失配图上向左走(导致最差的控制性能)。

MPC Objective

这是 Hedengren,JD,Eaton,AN,Overview of Estimation Methods for Industrial Dynamic Systems,Optimization and Engineering,Springer,Vol 18 (1),2017,pp. 155-178,DOI: 10.1007/s11081-015-中的图 14- 9295-9。

超调的原因之一是模型不匹配。这里有几种方法可以解决这个问题:

  1. 增加您的模型增益 K(可能为 1)或减少您的模型 tau(可能为 120),以便控制器变得不那么激进。您可能还想重新识别您的模型,以便更好地反映您的 TCLab 系统动态。这是有关获取 first ordersecond order 模型的教程。更高阶的 ARX 模型也适用于 TCLab。
  2. 使用 TC.TAU=50include the reference trajectory on the plot 将参考轨迹更改为不那么激进,以便您可以观察控制器的计划。我还喜欢在图中包含无偏模型,以展示模型的表现。
  3. 查看此 Control Tuning 页面以获取有关其他 MV 和 CV 调整选项的帮助。 Jupyter 笔记本小部件可以帮助您直观地了解这些选项。

MPC Tuning