添加约束以将电池循环限制为每 24 小时 1 次充电和 1 次放电
Posted
技术标签:
【中文标题】添加约束以将电池循环限制为每 24 小时 1 次充电和 1 次放电【英文标题】:Adding constraint to limit battery cycling to 1 charge and 1 discharge every 24 hours 【发布时间】:2022-01-22 07:26:05 【问题描述】:此查询是对以下问题的扩展:'@Error: Solution not found' being returned when using gekko for optimization。 “ind_1”和“ind_2”是长度为 8760 的列表,包含 0s/1s。一年中的某些时间可能会获得额外的收入,因此这些指标列表用于区分这些时间(进一步用于最大化功能 我试图通过将电池循环限制为每 24 小时最多 1 次充电和放电来构建此模型。作为最初的简单方法,我试图总结每个 24 小时段的电池命令信号,并将其限制为最多 8000 kWh。您可以在下面找到我的方法:
m = Gekko(remote=False)
#variables
e_battery = m.Var(lb=0, ub=4000, value=2000) #energy in battery at time t, battery size 4 MWh, initial value is 2MWh
command = m.Var(lb=-1000, ub=1000) #command power -1 to 1 (in MW)
e_price = m.Param(value = price) #price is a list of 8760 values
ind_1 = m.Param(value = ind_1)
ind_2 = m.Param(value = ind_2)
peak_list = m.Param(value = peak_load_list) #list of the monthly peaks (an array of length 8760)
load_list = m.Param(value = load) #hourly electric load
m.time = np.linspace(0,8759, 8760)
m.Equation(e_battery.dt() == command)
#The next 2 constraints are to ensure that the new load (original load + battery operation) is greater than 0, but less than the peak load for that month
m.Equation(load_list + command >= 0)
m.Equation(load_list + command <= peak_list)
#Here is the code to limit the cycling. "abs(command)" is used since "command" can be negative (discharge) or positive (charge), and a full charge and full discharge will equate to 8000 kWh.
daily_sum=0
for i in range(8760):
daily_sum += abs(command)
if i%24==0 and i!=0: #when i=0, it's the beginning of the first day so we can skip it
m.Equation(daily_sum <= 8000)
daily_sum = 0 #reset to 0 in preparation for the first hour of the next day
m.Maximize((-command)*(e_price + ind_1*ind1_price + ind_2*ind2_price))
m.options.IMODE = 6
m.solve()
添加循环约束时,返回如下输出:
--------- APM Model Size ------------
Each time step contains
Objects : 0
Constants : 0
Variables : 373
Intermediates: 0
Connections : 0
Equations : 368
Residuals : 368
Error: At line 1545 of file apm.f90
Traceback: not available, compile with -ftrace=frame or -ftrace=full
Fortran runtime error: Out of memory
这个特定的实现是否使用 gekko 的框架工作?我是否必须为“命令”初始化不同类型的变量?此外,我还没有找到许多将 for 循环用于方程式的相关示例,因此我非常清楚我的实现可能会很顺利。很想听听任何人的想法和/或建议,谢谢。
【问题讨论】:
请重新格式化您的输入,使代码看起来像代码。我发现最简单的方法是将所有代码粘贴为文本,选择它,然后按 ctrl-K 一次缩进所有代码。abs()
可能是个问题。我认为 Gekko 有一些替代方案。
谢谢 Erwin.. 我做了这个修改,但现在程序卡住了,没有返回任何东西。我尝试限制“max_iter”和“max_cpu_time”,但程序仍然卡住。
这有点离题了,但是有没有考虑将这个模型分解成更容易理解的部分?每当您在优化模型中查看约 10K 时间步时,我认为您遇到了麻烦(从不解决,内存过多等)您是否有理由无法运行几个月然后得出结论剩下的几个月? 1-3 个月如何影响 9-12 的模型决策?你能把它分成独立的块或改变你的时间表,比如 6 小时的块,等等......可能需要一些创造性/批判性思维。
感谢您的回复。除了添加上述循环约束之外,该模型在所有约束下都运行良好(约 50 秒计算时间),因此它让我认为我的实现可能有问题而不是问题大小。我将继续尝试挖掘一些相关信息,以查看我的实现如何/是否关闭。否则,我将研究如何以更易于理解的块更好地表示问题。
【参考方案1】:
二进制变量指示何时到达目的地(e_battery>3999 或 e_battery
以下是两个具有软约束和硬约束的示例。用于测试的时间点数量从 8760 个减少到 120 个(5 天)。
from gekko import Gekko
import numpy as np
m = Gekko(remote=False)
n = 120 # hours
price=np.ones(n)
e_battery = m.Var(lb=0, ub=4000, value=2000) #energy in battery at time t
# battery size 4 MWh, initial value is 2MWh
command = m.Var(lb=-1000, ub=1000) #command power -1 to 1 (in MW)
e_price = m.Param(value = price) #price is a list of 8760 values
ind_1=1; ind_2=1
ind1_price=1; ind2_price=1
ind_1 = m.Param(value = ind_1)
ind_2 = m.Param(value = ind_2)
m.time = np.linspace(0,n-1,n)
m.Equation(e_battery.dt() == command)
day = 24
discharge = m.Intermediate(m.integral(m.if3(e_battery+1,1,0)))
charge = m.Intermediate(m.integral(m.if3(e_battery-3999,0,1)))
x = np.ones_like(m.time)
for i in range(1,n):
if i%day==0:
x[i] = x[i-1] + 1
else:
x[i] = x[i-1]
limit = m.Param(x)
soft_constraints = True
if soft_constraints:
derr = m.CV(value=0)
m.Equation(derr==limit-discharge)
derr.STATUS = 1
derr.SPHI = 1; derr.WSPHI = 1000
derr.SPLO = 0; derr.WSPLO = 1000
cerr = m.CV(value=0)
m.Equation(cerr==limit-charge)
cerr.STATUS = 1
cerr.SPHI = 1; cerr.WSPHI = 1000
cerr.SPLO = 0; cerr.WSPLO = 1000
else:
# Hard Constraints
m.Equation(charge<=limit)
m.Equation(charge>=limit-1)
m.Equation(discharge<=limit)
m.Equation(discharge>=limit-1)
m.Minimize(command*(e_price + ind_1*ind1_price + ind_2*ind2_price))
m.options.IMODE = 6
m.solve()
import matplotlib.pyplot as plt
plt.figure(figsize=(10,6))
plt.subplot(3,1,1)
plt.plot(m.time,limit.value,'g-.',label='Limit')
plt.plot(m.time,discharge.value,'b:',label='Discharge')
plt.plot(m.time,charge.value,'r--',label='Charge')
plt.legend(); plt.xlabel('Time'); plt.ylabel('Cycles'); plt.grid()
plt.subplot(3,1,2)
plt.plot(m.time,command.value,'k-',label='command')
plt.legend(); plt.xlabel('Time'); plt.ylabel('Command'); plt.grid()
plt.subplot(3,1,3)
plt.plot(m.time,e_battery.value,'g-.',label='Battery Charge')
plt.legend(); plt.xlabel('Time'); plt.ylabel('Battery'); plt.grid()
plt.show()
原始问题中的应用程序内存不足,因为 8760 个方程分别在 8760 个时间步上同时积分。尝试提出写过一次但在整个框架内有效的方程。当前的目标函数是最小化用电量。您可能需要包含约束或目标函数以满足需求。否则,解决方案是永远不要使用电力,因为它被最小化(例如最大化(-command))。这里有类似的Grid Energy Benchmark problems,可能会有所帮助。
【讨论】:
以上是关于添加约束以将电池循环限制为每 24 小时 1 次充电和 1 次放电的主要内容,如果未能解决你的问题,请参考以下文章