跟进问题在 Python 中使用 PuLP 优化 EV 充电站选择
当前设置
from pulp import *
from matplotlib import pyplot as plt
BC = 100 # battery capacity
SOC_in = 1.0 # (%) initial state of charge
SOC_max = 1.0 #(%) maximum SOC
# energy consumed in each trip segment
e_c = [23.5, 4.6, 4.4, 33.8, 89.5, 0. , 24.5, 4.7, 21.5, 0. , 0. ,
16.2, 4.8, 20.1, 0. , 62.8, 0.6, 40.8, 41.1, 5.1, 16.7, 0. ,
39.6, 9.6, 9.8, 23.7, 0. , 0. , 23.4, 5.3, 8.6, 23.7, 18.6,
5.8, 9.1, 0.1, 0. , 0.1, 0. , 0.3, 19.8, 0. , 4.9, 23.4,
7.7, 9.6, 8. , 1. , 0. , 0. , 0. , 0. , 28.1, 5.5, 9.3,
0. , 0.1, 27.9, 41.3, 2.8, 20.8, 6.4, 5.7, 28.4, 7.7, 35.2,
2.8, 21. , 11.8, 0.1, 21.6, 7.4, 13.5, 8.6, 7.5, 0. , 12.8,
10.5, 0.4, 0. , 0. , 0.5, 37.2, 5.8, 19. , 10.7, 21.7, 17.1,
0.9, 0. , 17.1, 12. , 7.9, 2.4, 0.2, 20.6, 4.9, 21.1]
# energy recharged in each trip segment
e_r = [30.7, 64.8, 31.2, 181.2, 2.2, 66.5, 30.3, 52.8, 43.8,
54.1, 151.1, 33.9, 22.2, 68.3, 66.4, 70.2, 170.5, 260.2,
32.7, 72.6, 89.1, 138.1, 54.6, 70.2, 24.3, 42.2, 44.4,
38. , 38.8, 30.1, 28.7, 179.4, 48.6, 96.6, 0.2, 38.5,
44.5, 0.4, 0.4, 28.8, 13.5, 25.5, 44.9, 196.8, 269.8,
215.7, 81.1, 166.6, 0.4, 0.4, 0.1, 22.3, 111.9, 36.9,
43.3, 38. , 712.2, 9.7, 25.2, 242.3, 24.5, 49.4, 31.6,
231.6, 0.4, 27.5, 228.6, 31.7, 685.1, 812.4, 84.5, 36.7,
28.4, 214.7, 0.5, 46. , 61.3, 0.4, 0.4, 22.4, 0.4,
0.5, 47.5, 27. , 43.8, 182.3, 24.2, 76.3, 54. , 748.8,
72. , 46. , 31.3, 113.2, 0.4, 22.7, 70.6, 78.9]
candidate_nodes = range(len(e_c))
n = len(candidate_nodes)
# Define optimization problem
model = LpProblem("EV charging optimization modellem", LpMinimize)
### Decision variables
X = LpVariable.dicts("UseLocation", candidate_nodes, cat=LpBinary)
E = LpVariable.dicts("energy", candidate_nodes, lowBound=0, upBound = 100, cat = LpContinuous)
### Objective function
model += lpSum(X[i] for i in candidate_nodes)
### Constraints
# Initial energy level
model += E[0] == SOC_in * BC # typo fixed
for i in range(n-1):
# Energy at next stop (only add charge if charging station is built there)
model += E[i+1] <= E[i] - e_c[i] + (e_r[i] * X[i]) # less than or equal => prevent over-charge
# Energy does not exceed battery capacity
model += E[i+1] <= BC * SOC_max
# Has enough energy to reach the next stop without going below minimum battery level
model += E[i] >= e_c[i]
# Solve
status = model.solve()
# print the "build plan":
build_plan = [i for i in candidate_nodes if X[i].varValue > 0]
print('build at nodes: ')
print(build_plan)
plt.plot(candidate_nodes, [E[i].varValue for i in candidate_nodes], color='r', label='no bonus')
plt.scatter(build_plan, [0 for t in build_plan], s=10, alpha=0.6, color='orange', label='no-bonus charge')
# replace the objective function with this
model += lpSum(X[i] for i in candidate_nodes) - 1/(100*100)*lpSum(E[i] for i in candidate_nodes)
status2 = model.solve()
# QA the build plan has the same NUMBER of build points
build_plan_2 = [i for i in candidate_nodes if X[i].varValue > 0]
assert len(build_plan) == len(build_plan_2)
print('build at nodes: ', build_plan_2)
plt.plot(candidate_nodes, [E[i].varValue for i in candidate_nodes], color='b', label='bonus')
plt.scatter(build_plan_2, [0 for t in build_plan_2], s=10, alpha=0.6, color='g', label='charge')
plt.legend(loc='upper right')
plt.show()
以上作品。 BUT e_r 处的每个节点代表车辆停止充电的点,不一定是唯一的充电站。以下数组 'station_labels ' 实际上包含车辆停在哪个充电站。
station_labels = [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 2, 1, 0, 0, 1, 1,
0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 3, 4, 4, 1, 0, 0, 0, 4, 4, 4,
1, 0, 1, 1, 0, 0, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 0, 0, 4, 4, 5, 4,
4, 4, 4, 4, 4, 1, 1, 0, 0, 3]
所以车辆在充电站 0 停了三次,然后去充电站 1,然后又是 0,等等。从这个数组可以看出,车辆完成充电可能需要 0、1 和 4 站它的行程而 2、3 和 5 可能不是因为车辆几乎没有访问它们。 (事实上 ,当您运行优化时,第 5 站未被使用,但 2 和 3 可能不需要)
目标: 将断点映射到它们在优化问题中代表的实际站点
到目前为止尝试过:
我尝试将决策变量 X 更改为 station_labels 中的唯一值,然后通过更改“下一站能量”约束将 X 映射到约束中的站点标签。
所以
X = LpVariable.dicts("UseLocation", candidate_nodes, cat=LpBinary)
改为
X = LpVariable.dicts("UseLocation", range(len(np.unique(station_labels))), lowBound=0, upBound=1, cat=LpBinary)
和
model += E[i+1] <= E[i] - e_c[i] + (e_r[i] * X[i])
改为
model += E[i+1] <= E[i] - e_c[i] + (e_r[i] * X[station_labels[i]])
但是这使得优化说“问题不可行”并给出了一些像这样的无意义输出:
有什么想法吗?