繁体   English   中英

使用 GEKKO 进行状态变化检测的问题(估计时变变量)

[英]Problem using GEKKO to do regime change detection (estimating time-varying variables)

使用 GEKKO Python,我们在尝试学习每天可能多次变化的参数时遇到了麻烦。 在某些学科中,这也称为“状态检测或状态变化检测”。 我们(我和我来自温德斯海姆应用科学大学的同事 Henri ter Hofte)构思了 3 种策略但都失败了(详见下文)。

我们的问题:

  • 我们做错了什么,我们的 GEKKO 代码中是否有明显的错误(更多细节见下文)?
  • 策略 I 注定要失败吗?我们应该转向策略 II 还是策略 II?
  • GEKKO Python 是否适合进行这种制度(变更)检测?

非常感谢您的帮助。

=== 问题:我们有关于以下方面的时间序列数据:(1) 二氧化碳浓度 (2) 通风率(或者更确切地说:阀门分数,当乘以已知的最大通风率时,它给出通风率)(3) 占用率(数量房间里的人)

对于研究问题 (A),我们想知道一天中每个小时对 (2) 的正确估计,给定有关 (1) 和 (3) 的时间序列数据。 对于研究问题 (B),我们想知道一天中每个小时对 (3) 的正确估计,给定关于 (1) 和 (2) 的时间序列数据。

我们专注于研究问题 A(但对 B 也有类似的问题)。

=== 三种策略:

我们考虑了 3 种不同的策略如何使用 GEKKO Python 来实现:策略 I. 在我们的 GEKKO model (m.MV) 中将变量 valve_frac 声明为操纵变量,因为 GEKKO 文档说这些变量可以“由优化器调整以最小化每个时间点的目标 function”。 和“操纵变量类似于 FV,但可以随每个数据行而变化,由优化器计算 (STATUS=1) 或由用户指定 (STATUS=0)。” 根据https://gekko.readthedocs.io/en/latest/imode.html#mv

战略二。 将时间分成几个较短的时间跨度(例如,每小时一个时间跨度),然后将 valve_frac 学习为 GEKKO 固定变量 (m.FV),每小时一个。

战略三。 将问题重新定义为 GEKKO,就好像它是一个控制问题:设定点达到特定的 CO2 浓度,GEKKO 可以使用 valve_frac 作为控制变量 (m.CV)

我们尝试实施策略 I(请参阅下面的更多信息和代码)但未能获得正确的结果。 考虑从物理学中导出的一些方程,我们打算找到一些特定变量的最佳值(下表中的 valve_frac__0 变量。有一个 dataframe (df_learn) 是这样的:

指数 约会时间 占用__p valve_frac__0 co2__ppm
1个 2022.12.01 – 00:00:00 0 0.51 546
2个 2022.12.01 – 00:15:00 4个 0.85 820
3个 2022.12.01 – 00:30:00 1个 0.21 595
4个 2022.12.01 – 00:45:00 2个 0.74 635
5个 2022.12.01 – 00:15:00 0 0.65 559
6个 2022.12.01 – 00:15:00 0 0.45 538
7 2022.12.01 – 00:15:00 2个 0.82 659
. . . . .
. . . . .
. . . . .
1920 2022.12.20 – 00:15:00 3个 0.73 749

我们正在尝试开发移动地平线估计 model (IMODE=5) 或控制 model (IMODE=6) 来预测 valve_frac__0 值。 以下是 Gekko 格式的代码:

===代码:

from gekko import GEKKO
# Gekko Model - Initialize
m = GEKKO(remote = False)
m.time = np.arange(0, duration__s, step__s)

# Conversion factors
s_min_1 = 60
min_h_1 = 60
s_h_1 = s_min_1 * min_h_1
mL_m_3 = 1e3 * 1e3
million = 1e6

# Constants
MET__mL_min_1_kg_1_p_1 = 3.5                                  
desk_work__MET = 1.5                                 
P_std__Pa = 101325                                            
R__m3_Pa_K_1_mol_1 = 8.3145                                   
T_room__degC = 20.0                                           
T_std__degC = 0.0                                             
T_zero__K = 273.15                                           
T_std__K = T_zero__K + T_std__degC                            
T_room__K = T_zero__K + T_room__degC
infilt__m2 = 0.001                          

# Approximations
room__mol_m_3 = P_std__Pa / (R__m3_Pa_K_1_mol_1 * T_room__K)  
std__mol_m_3 = P_std__Pa / (R__m3_Pa_K_1_mol_1 * T_std__K)    
co2_ext__ppm = 415                                            
        
# National averages
weight__kg = 77.5                                             
MET__m3_s_1_p_1 = MET__mL_min_1_kg_1_p_1 * weight__kg / (s_min_1 * mL_m_3)
MET_mol_s_1_p_1 = MET__m3_s_1_p_1 * std__mol_m_3           
co2_o2 = 0.894                                           
co2__mol0_p_1_s_1 = co2_o2 * desk_work__MET * MET_mol_s_1_p_1    

# Room averages
wind__m_s_1 = 3.0                                             

# GEKKO Manipulated Variables: measured values
occupancy__p = m.MV(value = df_learn.occupancy__p.values)
occupancy__p.STATUS = 0; occupancy__p.FSTATUS = 1

# Strategy I:
valve_frac__0 = m.MV(value = df_learn.valve_frac__0.values)
valve_frac__0.STATUS = 1; valve_frac__0.FSTATUS = 0

# Strategy II:
#valve_frac__0 = m.FV(value = df_learn.valve_frac__0.values)
#valve_frac__0.STATUS = 1; valve_frac__0.FSTATUS = 0

# GEKKO Control Varibale (predicted variable)
co2__ppm = m.CV(value = df_learn.co2__ppm.values) 
co2__ppm.STATUS = 1; co2__ppm.FSTATUS = 1

# GEKKO - Equations
co2_loss__ppm_s_1 = m.Intermediate((co2__ppm - co2_ext__ppm) * (vent_max__m3_s_1 * valve_frac__0 + wind__m_s_1 * infilt__m2) / room__m3)

co2_gain_mol0_s_1 = m.Intermediate(occupancy__p * co2__mol0_p_1_s_1 / (room__m3 * room__mol_m_3))

co2_gain__ppm_s_1 = m.Intermediate(co2_gain_mol0_s_1 * million)

m.Equation(co2__ppm.dt() == co2_gain__ppm_s_1 - co2_loss__ppm_s_1)

# GEKKO - Solver setting
m.options.IMODE = 5
m.options.EV_TYPE = 1
m.options.NODES = 2
m.solve(disp = False) 

我为每个场景得到的结果如下:

策略一:

模拟的“co2__ppm”没有 output,valve_frac__0 = 0 的值为 output

策略二:

valve_frac__0 = 0.166 的模拟和测量“co2__ppm”与 output 值之间存在很大差异(这是不合理的)

只要valve_frac__0是应该根据 CO2 PPM 数据估算的可调未知参数,代码看起来就应该可以工作。 这是已发布数据的较小子集的结果。

结果

如果阀门 position 的下限为零,则数据不完全吻合。

valve_frac__0 = m.MV(value = valve_frac__0,lb=0)

否则,可以调整阀门 position 以完美匹配 CO2 数据。

在此处输入图像描述

这是带有示例数据的完整脚本。

from gekko import GEKKO
import numpy as np
# Gekko Model - Initialize
m = GEKKO(remote = False)

# data
# 1 2022.12.01 – 00:00:00   0   0.51    546
# 2 2022.12.01 – 00:15:00   4   0.85    820
# 3 2022.12.01 – 00:30:00   1   0.21    595
# 4 2022.12.01 – 00:45:00   2   0.74    635
# 5 2022.12.01 – 00:15:00   0   0.65    559
# 6 2022.12.01 – 00:15:00   0   0.45    538
# 7 2022.12.01 – 00:15:00   2   0.82    659

occupancy__p = np.array([0,4,1,2,0,0,2])
valve_frac__0 = np.array([0.51,0.85,0.21,0.74,0.65,0.45,0.82])
co2__ppm_meas = np.array([546,820,595,635,559,538,659])

duration__s = len(co2__ppm_meas)
m.time = np.linspace(0,duration__s-1,duration__s)

vent_max__m3_s_1 = 1
room__m3 = 1

# Conversion factors
s_min_1 = 60
min_h_1 = 60
s_h_1 = s_min_1 * min_h_1
mL_m_3 = 1e3 * 1e3
million = 1e6

# Constants
MET__mL_min_1_kg_1_p_1 = 3.5                                  
desk_work__MET = 1.5                                 
P_std__Pa = 101325                                            
R__m3_Pa_K_1_mol_1 = 8.3145                                   
T_room__degC = 20.0                                           
T_std__degC = 0.0                                             
T_zero__K = 273.15                                           
T_std__K = T_zero__K + T_std__degC                            
T_room__K = T_zero__K + T_room__degC
infilt__m2 = 0.001                          

# Approximations
room__mol_m_3 = P_std__Pa / (R__m3_Pa_K_1_mol_1 * T_room__K)  
std__mol_m_3 = P_std__Pa / (R__m3_Pa_K_1_mol_1 * T_std__K)    
co2_ext__ppm = 415                                            
        
# National averages
weight__kg = 77.5                                             
MET__m3_s_1_p_1 = MET__mL_min_1_kg_1_p_1 \
                * weight__kg / (s_min_1 * mL_m_3)
MET_mol_s_1_p_1 = MET__m3_s_1_p_1 * std__mol_m_3           
co2_o2 = 0.894                                           
co2__mol0_p_1_s_1 = co2_o2 * desk_work__MET * MET_mol_s_1_p_1    

# Room averages
wind__m_s_1 = 3.0                                             

# GEKKO Manipulated Variables: measured values
occupancy__p = m.MV(value = occupancy__p)
occupancy__p.STATUS = 0; occupancy__p.FSTATUS = 1

# Strategy I:
valve_frac__0 = m.MV(value = valve_frac__0,lb=0)
valve_frac__0.STATUS = 1; valve_frac__0.FSTATUS = 0

# Strategy II:
#valve_frac__0 = m.FV(value = df_learn.valve_frac__0.values)
#valve_frac__0.STATUS = 1; valve_frac__0.FSTATUS = 0

# GEKKO Control Varibale (predicted variable)
co2__ppm = m.CV(value = co2__ppm_meas) 
co2__ppm.STATUS = 1; co2__ppm.FSTATUS = 1

# GEKKO - Equations
co2_loss__ppm_s_1 = m.Intermediate((co2__ppm - co2_ext__ppm) \
                      * (vent_max__m3_s_1 * valve_frac__0 \
                      + wind__m_s_1 * infilt__m2) / room__m3)

co2_gain_mol0_s_1 = m.Intermediate(occupancy__p \
            * co2__mol0_p_1_s_1 / (room__m3 * room__mol_m_3))

co2_gain__ppm_s_1 = m.Intermediate(co2_gain_mol0_s_1 * million)

m.Equation(co2__ppm.dt() == co2_gain__ppm_s_1 - co2_loss__ppm_s_1)

# GEKKO - Solver setting
m.options.IMODE = 5
m.options.EV_TYPE = 1
m.options.NODES = 2
m.options.SOLVER = 1
m.solve(disp = True) 


import matplotlib.pyplot as plt

plt.subplot(2,1,1)
plt.plot(m.time,valve_frac__0.value,'r-',label='Valve Frac')
plt.legend(); plt.grid(); plt.ylabel('Valve Frac')
plt.subplot(2,1,2)
plt.plot(m.time,co2__ppm_meas,'ko',label='Measured')
plt.plot(m.time,co2__ppm.value,'k--',label='Predicted')
plt.legend(); plt.grid()
plt.xlabel('Time'); plt.ylabel('CO2')
plt.savefig('results.png',dpi=300)
plt.show()

B题,调整代码,使阀门position固定在实测值和优化器确定的占用率。

occupancy__p = m.MV(value = occupancy__p)
occupancy__p.STATUS = 1; occupancy__p.FSTATUS = 0

# Strategy I:
valve_frac__0 = m.MV(value = valve_frac__0,lb=0)
valve_frac__0.STATUS = 0; valve_frac__0.FSTATUS = 1

使用occupancy__p.MV_STEP_HOR = 2或更高降低优化参数可以更改的频率(例如每 2 小时)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM