首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Pyomo电池优化。中频条件

Pyomo电池优化。中频条件
EN

Stack Overflow用户
提问于 2022-09-05 13:32:32
回答 1查看 101关注 0票数 0

我目前正在建立一个简单的优化工具的电池存储。在t中,电池由Q_charget加载,即从电网Q_elt提取的电能乘以效率因子eta_charge

  1. Q_elt*eta_charge=Q_charget

放电功率Q_discharget乘以效率因子eta_discharge,给出了需求Q_demandt。需求概况在一年中的每一个小时都是众所周知的。

  1. Q_discharget*eta_discharge=Q_demandt

电池SOC(t)定义为前一时间的充电状态+功率输入-功率输出。未考虑任何损失。

  1. SOC(t)=SOC(t-1)+Q_charget-Q_demandt

在t=0的电荷状态应该等于所考虑的周期的最后一个小时。

  1. SOC(t=0)=SOC(t=end)

充放电不能同时发生。

  1. Charget+Discharget <= 1

充放电有最小和最大限值。

知道一年中每小时的电价,目标函数将决定何时收费,从而使购买成本降到最低。需求是内部使用的,不卖电。

Demandt是已知的(从导入)。Pricet是已知的(从导入)。

这是密码。

代码语言:javascript
复制
model = pyo.ConcreteModel()

##Parameters

tot_time=8760 #Hours in a year
model.T=pyo.Set(initialize=[t for t in range(0,tot_time)])
model.EtaCharge=pyo.Param(initialize=1.0, mutable=True) #-    
model.PMinCharge=0 #MW
model.PMaxCharge=2 #MW
model.EtaDischarge=pyo.Param(initialize=1.0, mutable=True) #-
model.PMinDischarge=2 #MW
model.PMaxDischarge=4 #MW
model.S0=pyo.Param(initialize=0.0, mutable=True) #MWh SOC at t=0

##Variables

model.QEl = pyo.Var(model.T, within=NonNegativeReals, initialize=0)
model.QCharge= pyo.Var(model.T, within=NonNegativeReals)
model.QDischarge= pyo.Var(model.T, within=NonNegativeReals)
model.Charge=pyo.Var(model.T, within = pyo.Binary)
model.Discharge=pyo.Var(model.T, within = pyo.Binary)
model.SOC=pyo.Var(model.T, bounds=(0,100)) #Size of the battery limited to 100 MWh

##Constraints

model.C1 = pyo.ConstraintList()
model.C2 = pyo.ConstraintList()
model.C3 = pyo.ConstraintList()
model.C4 = pyo.ConstraintList()
model.C5 = pyo.ConstraintList()
model.C6 = pyo.ConstraintList()
model.C7 = pyo.ConstraintList()

for t in model.T:
    
    model.C1.add(model.QEl[t] * model.EtaCharge ==  model.QCharge[t])   

    model.C2.add(model.QDischarge[t] * model.EtaDischarge ==  Demand[t])   
          
    model.C3.add(model.Charge[t] + model.Discharge[t] <= 1)
    
    model.C4.add(model.QCharge[t] >= model.PMinCharge*model.Charge[t])
                 
    model.C5.add(model.QCharge[t] <= model.PMaxCharge*model.Charge[t])
    
    model.C6.add(model.QDischarge[t] >= model.PMinDischarge*model.Discharge[t])
    
    model.C7.add(model.QDischarge[t] <= model.PMaxDischarge*model.Discharge[t])  


def SOC_storage(model,t):

    if t == 0:
        return (model.SOC[t] == model.S0+ model.QCharge[t]-model.QDischarge[t]) 
    else:
        return (model.SOC[t] == model.SOC[t-1] + model.QCharge[t] - model.QDischarge[t])

model.C8 = pyo.Constraint(model.T,rule = SOC_storage)

model.C9 = pyo.Constraint(expr = model.S0 == model.SOC[len(tot_time)-1])

##Objective

model.objective = pyo.Objective(expr = sum(model.QEl[t]*Price[t] for t in model.T), sense = pyo.minimize)

opt=SolverFactory('glpk')
results = opt.solve(model, tee = True)
model.write("myfile_lp.lp", io_options={'symbolic_solver_labels':True})
results.solver.status
results.solver.termination_condition
model.pprint()
value(model.objective)

实际上,代码运行很顺利。然而,我如何能够插入条件,不购买电力(Charget=0)只有在特定的时间?假设电池不能每天8点到15点之间充电?我试过:

代码语言:javascript
复制
day_stop=np.arange(8,15,1) # Index of hours When we don't charge
week_stop= np.concatenate([day_stop+24*j for j in range(0,7)]) # Index of hours When we don't charge for the first week
year_stop = np.concatenate([week_stop+168*j for j in range(0,52)]) # Index of hours When we don't charge for the all year

def NoCharge(model,t):
    if t in year_stop :
        return model.Charge[t]==0
    else:
        return Constraint.Skip

model.C10 = pyo.Constraint(model.T,rule = NoCharge)

运行代码后的所有变量都等于零或零。我是否以错误的方式提出约束?

你知道如何更好地制定最新的约束条件吗?非常感谢你的帮助!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-05 16:17:37

您使用NoCharge函数的方法似乎是正确的。没有数据就很难排除故障。所以..。我编造了一些。

一些建议:

  • --很难排除带有8000+时间周期的模型,所以我强烈建议您将其分解成非常小的东西(就像我下面所做的那样),这样您就可以将模型分解为非常小的部分,这样您就可以查看模型正在发生什么,并检查它--检查模型是否清楚,这很好!
  • 您的模型很容易由于充放电限制和最终state==start状态的限制而变得不可行,所以要小心,而且必须E 210检查解决程序状态E 111之前的E 212评估您的模型。我敢打赌,当你在约束条件中加上这个模型是不可行的时,我赌5美元。因此,在解决

问题时,您可能需要放宽充放电限制。

编辑...我想起了另外几件事..。先让它起作用,然后考虑一下这些.

  • ,您可能可以消除一个充放电二进制变量,因为它们是相互排斥的(由约束强制执行)。所以charge = 1 - discharge是真的,允许电荷等于零,所以“空闲”包含在内。您只需在需要时包含两个二进制文件中的一个,并在需要时使用"1 -“结构。
  • 您可能想要添加另一个电源,并在需求>可以产生什么以及电池无法跟上的情况下对其进行成本计算。添加一个“开销”电源变量并将其添加到您的OBJ中是很容易的,只需付出一些小小的代价。这将使您的模型更具弹性,从而帮助您保持模型的可行性。
  • 如果您的模型执行速度变慢,您可能应该将您的时间步骤增加到2,4,……小时或直接将“夜间时间”放入一大块,以减小

的大小

无论如何,下面的工作和产生的结果。我使用了您的C10约束,您可以切换它和C11,看看它是否在输出中工作。C11与C10是冗余的,只显示了一个备用结构.你可以任意使用。

代码:

代码语言:javascript
复制
import pyomo.environ as pyo

model = pyo.ConcreteModel()

##Parameters

tot_time=10 #Hours in a year
Demand = [0, 2, 3, 0, 0, 3, 3, 0, 0, 3]
Price = [0.5 for t in range(tot_time)]

model.T=pyo.Set(initialize=[t for t in range(0,tot_time)])
model.EtaCharge=pyo.Param(initialize=1.0, mutable=True) #-    
model.PMinCharge=0 #MW
model.PMaxCharge=5 #MW
model.EtaDischarge=pyo.Param(initialize=1.0, mutable=True) #-
model.PMinDischarge=2 #MW
model.PMaxDischarge=4 #MW

model.S0=pyo.Param(initialize=10, mutable=True) #MWh SOC at t=0

##Variables

model.QEl = pyo.Var(model.T, within=pyo.NonNegativeReals, initialize=0)
model.QCharge= pyo.Var(model.T, within=pyo.NonNegativeReals)
model.QDischarge= pyo.Var(model.T, within=pyo.NonNegativeReals)
model.Charge=pyo.Var(model.T, within = pyo.Binary)
model.Discharge=pyo.Var(model.T, within = pyo.Binary)
model.SOC=pyo.Var(model.T, bounds=(0,100)) #Size of the battery limited to 100 MWh

##Constraints

model.C1 = pyo.ConstraintList()
model.C2 = pyo.ConstraintList()
model.C3 = pyo.ConstraintList()
model.C4 = pyo.ConstraintList()
model.C5 = pyo.ConstraintList()
model.C6 = pyo.ConstraintList()
model.C7 = pyo.ConstraintList()

for t in model.T:
    
    model.C1.add(model.QEl[t] * model.EtaCharge == model.QCharge[t])   

    model.C2.add(model.QDischarge[t] * model.EtaDischarge == Demand[t])   
          
    model.C3.add(model.Charge[t] + model.Discharge[t] <= 1)
    
    model.C4.add(model.QCharge[t] >= model.PMinCharge*model.Charge[t])
                 
    model.C5.add(model.QCharge[t] <= model.PMaxCharge*model.Charge[t])
    
    model.C6.add(model.QDischarge[t] >= model.PMinDischarge*model.Discharge[t])
    
    model.C7.add(model.QDischarge[t] <= model.PMaxDischarge*model.Discharge[t])  


def SOC_storage(model,t):

    if t == 0:
        return (model.SOC[t] == model.S0 + model.QCharge[t] - model.QDischarge[t]) 
    else:
        return (model.SOC[t] == model.SOC[t-1] + model.QCharge[t] - model.QDischarge[t])

model.C8 = pyo.Constraint(model.T,rule = SOC_storage)

model.C9 = pyo.Constraint(expr = model.S0 == model.SOC[tot_time-1])

def NoCharge(model,t):
    if t in no_charge_zone :
        return model.Charge[t]==0
    else:
        return pyo.Constraint.Skip

no_charge_zone = [7, 8]
model.C10 = pyo.Constraint(model.T,rule = NoCharge)

# The below C11 is redundant with C10...  It just shows a different approach.
# I think this is cleaner....  Just make a subset from your "prohibited" time periods
# and pass that in...
def NoCharge2(model, t):
    return model.Charge[t] == 0

model.C11 = pyo.Constraint(no_charge_zone, rule=NoCharge2)

##Objective

model.objective = pyo.Objective(expr = sum(model.QEl[t]*Price[t] for t in model.T), sense = pyo.minimize)

opt=pyo.SolverFactory('glpk')
results = opt.solve(model, tee = True)
#model.write("myfile_lp.lp", io_options={'symbolic_solver_labels':True})
results.solver.status
results.solver.termination_condition
#model.pprint()
model.Charge.display()
model.SOC.display()
#print(pyo.value(model.objective))

输出:

代码语言:javascript
复制
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (87515 bytes)
Writing MIP solution to '/var/folders/rt/5gc2md7s7y5bw8ddt74tz5vw0000gp/T/tmpi82nq7rg.glpk.raw'...
154 lines were written
Charge : Size=10, Index=T
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      0 :     0 :   1.0 :     1 : False : False : Binary
      1 :     0 :   0.0 :     1 : False : False : Binary
      2 :     0 :   0.0 :     1 : False : False : Binary
      3 :     0 :   1.0 :     1 : False : False : Binary
      4 :     0 :   1.0 :     1 : False : False : Binary
      5 :     0 :   0.0 :     1 : False : False : Binary
      6 :     0 :   0.0 :     1 : False : False : Binary
      7 :     0 :   0.0 :     1 : False : False : Binary
      8 :     0 :   0.0 :     1 : False : False : Binary
      9 :     0 :   0.0 :     1 : False : False : Binary
SOC : Size=10, Index=T
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      0 :     0 :  14.0 :   100 : False : False :  Reals
      1 :     0 :  12.0 :   100 : False : False :  Reals
      2 :     0 :   9.0 :   100 : False : False :  Reals
      3 :     0 :  14.0 :   100 : False : False :  Reals
      4 :     0 :  19.0 :   100 : False : False :  Reals
      5 :     0 :  16.0 :   100 : False : False :  Reals
      6 :     0 :  13.0 :   100 : False : False :  Reals
      7 :     0 :  13.0 :   100 : False : False :  Reals
      8 :     0 :  13.0 :   100 : False : False :  Reals
      9 :     0 :  10.0 :   100 : False : False :  Reals
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73610201

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档