首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >离网光伏和电池系统的Python PulP线性优化

离网光伏和电池系统的Python PulP线性优化
EN

Stack Overflow用户
提问于 2022-03-16 09:08:00
回答 1查看 514关注 0票数 0

我试图使用线性优化,以最小化太阳能光伏和电池的规模,为离网的财产。我有太阳辐照度数据和家庭能源消耗数据--我创建了以下数据中的一年值(8760个数据点)。

我认为这个问题可以用线性的方式解决,但是,我看到了一些奇怪的行为,PulP没有以最优的方式运行。也许它可以更好的表述。

太阳能光伏发电的数量与光伏系统(PV_size)的大小成正比(我假设了20%的效率)。太阳能光伏输出(PV_gen)和电池放电(P放电)必须始终满足家庭的需求(负荷)。当PV大于家用负载时,多余的PV可以用来充电电池(充电)。当多余的PV大于电池中可用的空间时,我们可以假设电池完全充电,然后光伏就会减少。交付的最大费用由Pcharge_a描述。

放电量(放电)必须小于电池的可用空间。电池在任何时间的充电状态由Bstatet定义,电池的最大充电量为Bmax。我们可以假设电池有100%的放电深度,因此可以放电到0。

目标函数是最小化系统的成本,我已经定义为PV (PV_size)的大小乘以PV系统的成本(假设每m2 500 ),加上电池的成本(让我们使用每kWh的电池容量1500 )。因此,目标职能是尽量减少:

PV_size * 500 + Bmax * 1500

我正在与python一起使用PulP包,到目前为止,这是我的代码。它将返回一个最优的解决方案,然而,从下面数据的第3行可以看到,它创造了一个巨大的放电和电荷,这是完全没有必要的。我认为这是因为我并没有限制放电(放电)的负面程度,同样的,我也没有限制过多余的PV (电荷)的大小。

前几个小时的数据

代码语言:javascript
复制
    load = np.array([0.580416667,0.539066667,0.390116667,0.232033333,
0.204533333,0.194716667,0.194633333,0.209233333,
0.247266668,0.407916668,0.537349998,0.576983332,
0.580216667,0.520566667,0.485200003,0.4197,
0.424300002,0.448333332,0.546983333,0.840733333,
1.320233332,0.856422014,0.921716667,0.720283335]*365)

solar_irrad = np.array([0,0,0,0,
0.846573268,6.670823882,22.34096457,48.40323145,
95.10129002,161.7686087,236.9894473,293.9150696,
305.3854497,294.6843366,251.7269744,182.2991627,
123.210826,73.11869927,33.55642336,9.910144956,
1.621109317,0.008980831,0,0]*365)

T = len(load)

# Decision variables
Bmax = LpVariable('Bmax', 0, None) # battery max energy (kWh)
PV_size = LpVariable('PV_size', 0, None) # PV size

# Optimisation problem
prb = LpProblem('Battery_Operation', LpMinimize)

# Objective function
prb += (PV_size*500) + (Bmax*1500)  # cost of battery

# Auxilliary variables
PV_gen = [LpVariable('PV_gen_{}'.format(i), 0, None) for i in range(T)]

# Load difference
Pflow = [LpVariable('Pflow_{}'.format(i), None, None) for i in range(T)]
# Excess PV
Pcharge = [LpVariable('Pcharge_{}'.format(i), lowBound=0, upBound=None) for i in range(T)]
# Discharge required
Pdischarge = [LpVariable('Pdischarge_{}'.format(i), lowBound=None, upBound=0) for i in range(T)]
# Charge delivered
Pcharge_a = [LpVariable('Pcharge_a{}'.format(i), 0, None) for i in range(T)]

# Battery
Bstate = [LpVariable('E_{}'.format(i), 0, None) for i in range(T)]

# Battery Constraints
prb += Bstate[0] == Bmax + Pdischarge[0] + Pcharge_a[0]
for t in range(1, T):
    prb += Bstate[t] == Bstate[t-1] + Pdischarge[t] + Pcharge_a[t] 

# Power flow Constraints
for t in range(0, T):
    
    # PV generation
    prb += PV_gen[t] == PV_size*0.2*solar_rad[t]/1000
    
    # Pflow is the energy flow reuired to meet the load
    # Negative if load greater than PV, positive if PV greater than load
    prb += Pflow[t] == PV_gen[t] - load[t]
    
    # Given the below, it will push Pflow available for charge to zero or to to or greater than excess PV
    prb += Pcharge[t] >= 0
    prb += Pcharge[t] >= Pflow[t]

    # If Pflow is negative (discharge), then it will at least ePflowual discharge rePflowuired
    # If Pflow is positive (charge), then Pdischarge (discharge rePflowuired will ePflowual 0)
    prb += Pdischarge[t] <= 0
    prb += Pdischarge[t] <= Pflow[t]
    # Discharge cannot exceed available charge in battery
    # Discharge is negative
    prb += Pdischarge[t] >= (-1)*Bstate[t-1]
    
    # Ensures that energy flow rePflowuired is satisifed by charge and discharge flows
    prb += Pflow[t] == Pcharge[t] + Pdischarge[t] 
    
    # Limit amount charge delivered by the available space in the battery
    prb += Pcharge_a[t] >= 0
    prb += Pcharge_a[t] <= Pcharge[t]
    prb += Pcharge_a[t] <= Bmax - Bstate[t-1]
    
    prb += Bstate[t] >= 0
    prb += Bstate[t] <= Bmax
    
    # Solve problem
    prb.solve()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-16 17:33:49

你好,欢迎来到这个网站。有趣的问题。

您的问题似乎设置正确。你得到了“大规模排放”,因为你是人为的(?)限制电池在半夜在time=0的最大电量(通过观察你的太阳能的周期性来评估)。这会导致电池人为地太大,因为它不需要在那个特定的时间达到最大容量。最优的情况是,当需求大于光伏发电时,它应该处于峰值充电,对吗?

所以,它是一个巨大的倾倒在半夜,以摆脱这一指控,这(在你的模型)是免费的。从数据截断到5个句点,请参见下面的图:

那么,我们能做些什么呢?首先,在t=0不限制你的电池.这将使模型能够选择最优的初始电荷。您可能仍然会看到异常行为,因为模型仍然可以保持高于必要的电荷和放电,因为该场景具有相同的客观分数。因此,您可以选择在累积放电上设置一个微小的惩罚来影响模型。意识到这是人为地增加电池使用的成本非常轻微,所以明智地检查这一点,使放电罚款在我的代码下面巨大,并看到不同之处。或者你可以忽略这一点,把第一个周期截断为“热身”,等等.

这是没有启动限制的电池和微小的放电惩罚的结果.

代码(您的代码经过一些调整/注释):

代码语言:javascript
复制
from pulp import *
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

load = np.array([0.580416667,0.539066667,0.390116667,0.232033333,
0.204533333,0.194716667,0.194633333,0.209233333,
0.247266668,0.407916668,0.537349998,0.576983332,
0.580216667,0.520566667,0.485200003,0.4197,
0.424300002,0.448333332,0.546983333,0.840733333,
1.320233332,0.856422014,0.921716667,0.720283335]*5)

solar_rad = np.array([0,0,0,0,
0.846573268,6.670823882,22.34096457,48.40323145,
95.10129002,161.7686087,236.9894473,293.9150696,
305.3854497,294.6843366,251.7269744,182.2991627,
123.210826,73.11869927,33.55642336,9.910144956,
1.621109317,0.008980831,0,0]*5)

T = len(load)

# Decision variables
Bmax = LpVariable('Bmax', 0, None) # battery max energy (kWh)
PV_size = LpVariable('PV_size', 0, None) # PV size

# Optimisation problem
prb = LpProblem('Battery_Operation', LpMinimize)

# Auxilliary variables
PV_gen = [LpVariable('PV_gen_{}'.format(i), 0, None) for i in range(T)]

# Load difference
Pflow = [LpVariable('Pflow_{}'.format(i), None, None) for i in range(T)]
# Excess PV
Pcharge = [LpVariable('Pcharge_{}'.format(i), lowBound=0, upBound=None) for i in range(T)]
# Discharge required
Pdischarge = [LpVariable('Pdischarge_{}'.format(i), lowBound=None, upBound=0) for i in range(T)]
# Charge delivered
Pcharge_a = [LpVariable('Pcharge_a{}'.format(i), 0, None) for i in range(T)]

###  Moved this down as it needs to include Pdischarge
# Objective function
# cost + some small penalty for cumulative discharge, just to shape behavior
prb += (PV_size*500) + (Bmax*1500)  - 0.01 * lpSum(Pdischarge[t] for t in range(T)) 

# Battery
Bstate = [LpVariable('E_{}'.format(i), 0, None) for i in range(T)]

# Battery Constraints
### NOTE this is killed to allow initial state to "float"
#prb += Bstate[0] == Bmax + Pdischarge[0] + Pcharge_a[0]
for t in range(1, T):
    prb += Bstate[t] == Bstate[t-1] + Pdischarge[t] + Pcharge_a[t] 

# Power flow Constraints
for t in range(0, T):
    
    # PV generation
    prb += PV_gen[t] == PV_size*0.2*solar_rad[t]/1000
    
    # Pflow is the energy flow reuired *from the battery* to meet the load
    # Negative if load greater than PV, positive if PV greater than load
    prb += Pflow[t] == PV_gen[t] - load[t]
    
    # Given the below, it will push Pflow available for charge to zero or to to or greater than excess PV
    prb += Pcharge[t] >= 0
    prb += Pcharge[t] >= Pflow[t]

    # If Pflow is negative (discharge), then it will at least ePflowual discharge rePflowuired
    # If Pflow is positive (charge), then Pdischarge (discharge rePflowuired will ePflowual 0)
    prb += Pdischarge[t] <= 0
    prb += Pdischarge[t] <= Pflow[t]
    # Discharge cannot exceed available charge in battery
    # Discharge is negative
    prb += Pdischarge[t] >= (-1)*Bstate[t-1]
    
    # Ensures that energy flow rePflowuired is satisifed by charge and discharge flows
    prb += Pflow[t] == Pcharge[t] + Pdischarge[t] 
    
    # Limit amount charge delivered by the available space in the battery
    prb += Pcharge_a[t] >= 0
    prb += Pcharge_a[t] <= Pcharge[t]
    prb += Pcharge_a[t] <= Bmax - Bstate[t-1]
    
    prb += Bstate[t] >= 0
    prb += Bstate[t] <= Bmax
    
# Solve problem
prb.solve()

# make some records to prep for dataframe (what a pain in pulp!!)
res = []
for t in range(T):
    record = {  'period': t,
                'Load': load[t],
                'PV_gen': PV_gen[t].varValue,
                'Pflow' : Pflow[t].varValue,
                'Pcharge': Pcharge[t].varValue,
                'Pcharge_a': Pcharge_a[t].varValue,
                'Pdischarge': Pdischarge[t].varValue,
                'Bstate': Bstate[t].varValue}
    res.append(record)

df = pd.DataFrame.from_records(res)
df.set_index('period', inplace=True)
df = df.round(2)
print(df.to_string())

print(f'PV size: {PV_size.varValue : 0.1f}, Batt size: {Bmax.varValue : 0.1f}')

df.plot()
plt.show()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71494297

复制
相关文章

相似问题

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