我试图使用线性优化,以最小化太阳能光伏和电池的规模,为离网的财产。我有太阳辐照度数据和家庭能源消耗数据--我创建了以下数据中的一年值(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 (电荷)的大小。
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()发布于 2022-03-16 17:33:49
你好,欢迎来到这个网站。有趣的问题。
您的问题似乎设置正确。你得到了“大规模排放”,因为你是人为的(?)限制电池在半夜在time=0的最大电量(通过观察你的太阳能的周期性来评估)。这会导致电池人为地太大,因为它不需要在那个特定的时间达到最大容量。最优的情况是,当需求大于光伏发电时,它应该处于峰值充电,对吗?
所以,它是一个巨大的倾倒在半夜,以摆脱这一指控,这(在你的模型)是免费的。从数据截断到5个句点,请参见下面的图:

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

代码(您的代码经过一些调整/注释):
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()https://stackoverflow.com/questions/71494297
复制相似问题