首页 > 解决方案 > 让 Optimizer 根据容量和净负载切换电力存储

问题描述

我试图让优化器使用两个电力存储来进行循环发电和消耗循环。目标是让它在达到满容量时关闭一次能量存储(在这种情况下是电池存储),然后先放电直到它耗尽。二次存储是在一次存储之后充电,在一次存储之后放电。我希望优化器根据系统进行解决。我曾尝试使用一系列开关,但效果不佳。我知道使用 if 语句对于基于梯度的求解器来说很棘手,所以如果有任何帮助将非常感谢!

Capacity = 76.2
EStored = m.SV(value=0,lb=0,ub=Capacity)
batteryeff = .95
batteff = m.if3((Enuc - Cons),1/batteryeff,batteryeff)

#Energy Balance 
Cost = m.Var()
eneed = m.sign2(Enuc-Cons)  #gives sign of energy need for energy storage or removal from storage
eswitch = m.if3(eneed,0, 1) #Turns eneed into a binary switch
switch = m.if3(eswitch*(Capacity-EStored)+(1-eswitch)*(EStored),0,1) #supposed to charge battery until at capacity and then discharge until EStored is 0. Then use thermal energy second


m.Equation(EStored.dt() == (switch)*batteff*(Enuc - Cons))  #Energy balance for Battery
m.Equation(T.dt() == (1-switch)*thermeff*(Enuc - Cons)/(mass*Cp)) #Energy balance for Thermal Storage
m.Equation(Cost == Enuc*1000 )
m.Obj(Cost)

m.options.IMODE = 5
m.options.SOLVER = 3
m.solve()

这是我正在使用的代码部分,但是如果需要更多细节,这里是总代码的简化版本。

from gekko import GEKKO
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.integrate import quad

#Set up basic power consumption data
n = 24
t = np.linspace(0,n,n)
def load(t):
    return  -10*np.sin(2*np.pi*t/24)+40
Load = load(t)
Gen = np.ones(n)*40
def need(t):
    return 10*np.sin(2*np.pi*t/24)+10

#Set up Model
m = GEKKO()
m.time = t

Cons = m.Param(value=Load)
Enuc = m.FV(value=45, lb=0) #nuclear power
Enuc.STATUS = 1

#Thermal Energy Storage
T = m.SV(value=300,ub=500,lb=300)
mass = m.FV(value=.0746,lb=0)
mass.STATUS=0
Cp = m.Param(value=5)
thermaleff = .8   #80%efficient
thermeff = m.if3((Enuc - Cons)/(mass*Cp),1/thermaleff,thermaleff)

#Battery Electrical storage
Capacity = 76.2
EStored = m.SV(value=0,lb=0,ub=Capacity)
batteryeff = .95
batteff = m.if3((Enuc - Cons),1/batteryeff,batteryeff)

#Energy Balance 
Cost = m.Var()
eneed = m.sign2(Enuc-Cons)  #gives sign of energy need for energy storage or removal from storage
eswitch = m.if3(eneed,0, 1) #Turns eneed into a binary switch
switch = m.if3(eswitch*(Capacity-EStored)+(1-eswitch)*(EStored),0,1) #supposed to charge battery until at capacity and then discharge until EStored is 0. Then use thermal energy second


m.Equation(EStored.dt() == (switch)*batteff*(Enuc - Cons))  #Energy balance for Battery
m.Equation(T.dt() == (1-switch)*thermeff*(Enuc - Cons)/(mass*Cp)) #Energy balance for Thermal Storage
m.Equation(Cost == Enuc*1000 )
m.Obj(Cost)

m.options.IMODE = 5
m.options.SOLVER = 3
m.solve()

#plot
plt.subplot(3,1,1)
plt.plot(t,Load)
plt.plot(t,Enuc.value, label=f'Enuc = {Enuc.value[-1]}')
plt.ylabel("Energy")
plt.legend()

plt.subplot(3,1,2)
plt.plot(t,EStored.value, label=f'Capacity = {np.max(EStored.value):.03}')
plt.title("Battery Storage")
plt.ylabel("Energy")
plt.legend()

plt.subplot(3,1,3)
plt.plot(t,T.value,label=f'mass = {mass.value[-1]:.03}')
plt.title("Thermal Storage")
plt.ylabel("Temperature(K)")
plt.legend()
plt.show()```

标签: pythongekko

解决方案


您可以使用松弛变量而不是切换条件。这是一个简单的问题,有两个水箱,总入口流量为100. 入口流量可以在两个罐之间分流,但罐的最大体积分别为3001000。Tank 2 的使用成本更高(例如您的热能系统)。

罐灌装

import numpy as np
from gekko import GEKKO
m = GEKKO(remote=False)
m.time = np.linspace(0,10,100)
t = m.Var(0); m.Equation(t.dt()==1) # define time
flow = 100

V1 = m.Var(0,lb=0,ub=300) # tank 1
inlet1 = m.MV(0,lb=0); inlet1.STATUS = 1; inlet1.DCOST = 1e-4
m.Minimize(inlet1)

V2 = m.Var(0,lb=0,ub=1000) # tank 2
inlet2 = m.MV(0,lb=0); inlet2.STATUS = 1; inlet2.DCOST = 1e-4
m.Minimize(10*inlet2) # more expensive
                      # use tank 2 if tank 1 is projected to be filled

# only one in use, could also use inlet1*inlet2==0 to
#  enforce the complementarity condition
m.Minimize(inlet1*inlet2)

# mass balance
m.Equation(flow==inlet1+inlet2)
m.Equations([V1.dt()==inlet1,V2.dt()==inlet2])

m.options.IMODE = 6
m.solve(disp=False)

import matplotlib.pyplot as plt
plt.plot(m.time,inlet1.value,'r--',label='Inlet 1')
plt.plot(m.time,V1.value,'r-',label='Volume 1')
plt.plot(m.time,inlet2.value,'b--',label='Inlet 2')
plt.plot(m.time,V2.value,'b-',label='Volume 2')
plt.grid()
plt.legend()
plt.show()

如果优化器知道电能和热能存储都将被填满,那么它们何时存储并不一定重要。如果您确实需要逻辑条件来强制执行,那么m.if3()语句可能会更好,但也可能更难解决。如果您可以同时充电电能和热能,m.Minimize(inlet1*inlet2)则也不需要互补执行器,并提供不同但仍然是最佳解决方案。

连续灌装

在这两种情况下,水箱 1 都是更便宜的选择,因此它会达到容量并最大限度地减少水箱 2 的填充。这可能是您的情况的更好解决方案,因为这样您就不需要可能导致问题的切换条件。电池存储将完全充满,但如果预测电池将在需要存储电力的夜间充满时,它可能会在填充热能的同时完成。


推荐阅读