Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
3,271 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
|
||
from ortools.linear_solver import pywraplp | ||
|
||
class BatteryContoller(object): | ||
step = 960 | ||
def propose_state_of_charge(self, | ||
site_id, | ||
timestamp, | ||
battery, | ||
actual_previous_load, | ||
actual_previous_pv_production, | ||
price_buy, | ||
price_sell, | ||
load_forecast, | ||
pv_forecast): | ||
|
||
|
||
self.step -= 1 | ||
if (self.step == 1): return 0 | ||
if (self.step > 1): number_step = min(96, self.step) | ||
# | ||
price_buy = price_buy.tolist() | ||
price_sell = price_sell.tolist() | ||
load_forecast = load_forecast.tolist() | ||
pv_forecast = pv_forecast.tolist() | ||
# | ||
energy = [None] * number_step | ||
|
||
for i in range(number_step): | ||
if (pv_forecast[i] >=50): energy[i] = load_forecast[i] - pv_forecast[i] | ||
else: energy[i] = load_forecast[i] | ||
#battery | ||
capacity = battery.capacity | ||
charging_efficiency = battery.charging_efficiency | ||
discharging_efficiency = 1. / battery.discharging_efficiency | ||
current = capacity * battery.current_charge | ||
limit = battery.charging_power_limit | ||
dis_limit = battery.discharging_power_limit | ||
limit /= 4. | ||
dis_limit /= 4. | ||
|
||
# Ortools | ||
solver = pywraplp.Solver("B", pywraplp.Solver.GLOP_LINEAR_PROGRAMMING) | ||
|
||
#Variables: all are continous | ||
charge = [solver.NumVar(0.0, limit, "c"+str(i)) for i in range(number_step)] | ||
dis_charge = [solver.NumVar( dis_limit, 0.0, "d"+str(i)) for i in range(number_step)] | ||
battery_power = [solver.NumVar(0.0, capacity, "b"+str(i)) for i in range(number_step+1)] | ||
grid = [solver.NumVar(0.0, solver.infinity(), "g"+str(i)) for i in range(number_step)] | ||
|
||
#Objective function | ||
objective = solver.Objective() | ||
for i in range(number_step): | ||
objective.SetCoefficient(grid[i], price_buy[i] - price_sell[i]) | ||
objective.SetCoefficient(charge[i], price_sell[i] + price_buy[i] / 1000.) | ||
objective.SetCoefficient(dis_charge[i], price_sell[i]) | ||
objective.SetMinimization() | ||
|
||
# 3 Constraints | ||
c_grid = [None] * number_step | ||
c_power = [None] * (number_step+1) | ||
|
||
# first constraint | ||
c_power[0] = solver.Constraint(current, current) | ||
c_power[0].SetCoefficient(battery_power[0], 1) | ||
|
||
for i in range(0, number_step): | ||
# second constraint | ||
c_grid[i] = solver.Constraint(energy[i], solver.infinity()) | ||
c_grid[i].SetCoefficient(grid[i], 1) | ||
c_grid[i].SetCoefficient(charge[i], -1) | ||
c_grid[i].SetCoefficient(dis_charge[i], -1) | ||
# third constraint | ||
c_power[i+1] = solver.Constraint( 0, 0) | ||
c_power[i+1].SetCoefficient(charge[i], charging_efficiency) | ||
c_power[i+1].SetCoefficient(dis_charge[i], discharging_efficiency) | ||
c_power[i+1].SetCoefficient(battery_power[i], 1) | ||
c_power[i+1].SetCoefficient(battery_power[i+1], -1) | ||
|
||
#solve the model | ||
solver.Solve() | ||
|
||
if ((energy[0] < 0) & (dis_charge[0].solution_value() >= 0)): | ||
n = 0 | ||
first = -limit | ||
mid = 0 | ||
|
||
sum_charge = charge[0].solution_value() | ||
last = energy[0] | ||
for n in range(1, number_step): | ||
if((energy[n] > 0) | (dis_charge[n].solution_value() < 0) | (price_sell[n] != price_sell[n-1])): | ||
break | ||
last = min(last, energy[n]) | ||
sum_charge += charge[n].solution_value() | ||
if (sum_charge <= 0.): | ||
return battery_power[1].solution_value() / capacity | ||
def tinh(X): | ||
res = 0 | ||
for i in range(n): | ||
res += min(limit, max(-X - energy[i], 0.)) | ||
if (res >= sum_charge): return True | ||
return False | ||
last = 2 - last | ||
# binary search | ||
while (last - first > 1): | ||
mid = (first + last) / 2 | ||
if (tinh(mid)): first = mid | ||
else: last = mid | ||
return (current + min(limit, max(-first - energy[0] , 0)) * charging_efficiency) / capacity | ||
|
||
if ((energy[0] > 0) & (charge[0].solution_value() <=0)): | ||
n = 0 | ||
first = dis_limit | ||
mid = 0 | ||
sum_discharge = dis_charge[0].solution_value() | ||
last = energy[0] | ||
for n in range(1, number_step): | ||
if ((energy[n] < 0) | (charge[n].solution_value() > 0) | (price_sell[n] != price_sell[n-1]) | (price_buy[n] != price_buy[n-1])): | ||
break | ||
last = max(last, energy[n]) | ||
sum_discharge += dis_charge[n].solution_value() | ||
if (sum_discharge >= 0.): | ||
return battery_power[1].solution_value() / capacity | ||
|
||
def tinh2(X): | ||
res = 0 | ||
for i in range(n): | ||
res += max(dis_limit, min(X - energy[i], 0)) | ||
if (res <= sum_discharge): return True | ||
return False | ||
last += 2 | ||
|
||
# binary search | ||
while (last - first > 1): | ||
mid = (first + last) / 2 | ||
if (tinh2(mid)): first = mid | ||
else: last = mid | ||
return (current + max(dis_limit, min(first - energy[0], 0)) * discharging_efficiency) / capacity | ||
return battery_power[1].solution_value() / capacity |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
1. To run the code, please install Ortools - version 6.7.4957 | ||
|
||
2. The linear programming model is as follows: | ||
|
||
Variables: | ||
charge[i]: charged energy of battery at step i (charge[i] >=0) | ||
dis_charge[i]: discharged energy of battery at step i (dis_charge[i] <=0) | ||
battery_power[i]: power of battery at step i (0 <= battery_power[i] <= capacity) | ||
grid[i]: energy bought from grid at step i (grid[i] > 0) | ||
|
||
Objective | ||
Minimize Z =∑_(i=0)^95 (grid[i]*(price_buy[i] - price_sell[i])+ charge[i]*(price_sell[i] + price_buy[i]/1000.)+dis_charge[i] * price_sell[i]) | ||
|
||
Constraints | ||
(1) Initialize the power of battery | ||
battery_power[0] = capacity * battery.current_charge | ||
|
||
(2) The demand of building must be satisfied | ||
grid[i] – (charge[i] + dis_charge[i]) >= load_forecast[i] - pv_forecast[i] | ||
|
||
(3) Relationship of battery power between two consecutive steps | ||
battery_power[i] + charge[i] * charging_efficiency + dis_charge[i]/discharging_efficiency = battery_power[i+1] | ||
|
||
(4) Charged energy must less than charging power limit | ||
charge[i] <= charging_power_limit * (1/4.) | ||
|
||
(5) Discharged energy must be less than discharging power limit | ||
dis_charge[i] >= discharging_power_limit* (1/4.) | ||
|
||
|
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Final solution for Power Laws: Optimizing Demand-side Strategies | ||
https://www.drivendata.org/competitions/53/optimize-photovoltaic-battery/ | ||
|
||
## Files | ||
battery_controller.py | ||
This is the script used on the simulation. | ||
assets/coefs.json | ||
This coeficients are used by the battery_controller to improve the accuracy | ||
of the forecasts. | ||
forecast_accuracy_optimization.ipynb | ||
This notebook shows how the coeficients are computed using keras and the training data. | ||
requirements.txt | ||
A list with the libraries needed to run the scripts. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"1": {"2014-08-28 18:15:00": [0.9381, 0.0214, 0.0407], "2015-05-02 18:15:00": [0.9065, 0.0885, 0.0051], "2015-08-25 18:15:00": [0.9283, 0.054, 0.018], "2015-10-24 18:15:00": [0.9346, 0.0466, 0.019], "2016-02-18 18:15:00": [0.8491, 0.2042, -0.0533], "2016-04-18 18:15:00": [0.9359, 0.0538, 0.01], "2017-01-31 18:15:00": [0.8547, 0.1986, -0.0536], "2017-04-01 18:15:00": [0.8857, 0.1422, -0.0276], "2017-05-31 18:15:00": [0.8517, 0.2163, -0.068]}, "10": {"2013-02-21 00:45:00": [0.8904, 0.1622, -0.0529], "2013-04-22 00:45:00": [0.8763, 0.183, -0.0594], "2013-06-21 00:45:00": [0.8848, 0.1923, -0.0773], "2013-08-20 00:45:00": [0.8938, 0.1603, -0.054], "2013-10-19 00:45:00": [0.8906, 0.1602, -0.051], "2013-12-18 00:45:00": [0.8906, 0.1578, -0.0484], "2014-02-16 00:45:00": [0.8735, 0.188, -0.0615], "2014-04-17 00:45:00": [0.8679, 0.1936, -0.0611], "2014-06-16 00:45:00": [0.8963, 0.1503, -0.0467]}, "11": {"2015-07-22 01:45:00": [0.783, 0.2983, -0.0732], "2015-09-24 01:45:00": [0.8083, 0.274, -0.0795], "2016-01-20 01:45:00": [0.7746, 0.3171, -0.0925], "2016-03-20 01:45:00": [0.7362, 0.3798, -0.1221], "2016-05-19 01:45:00": [0.764, 0.3311, -0.1014], "2016-09-25 01:45:00": [0.6083, 0.5763, -0.1913], "2016-11-24 01:45:00": [0.7374, 0.3597, -0.1045]}, "12": {"2014-08-21 13:00:00": [0.675, 0.4098, -0.0897], "2014-10-20 13:00:00": [0.7597, 0.3138, -0.0765], "2014-12-19 13:00:00": [0.6879, 0.3834, -0.0806], "2015-02-17 13:00:00": [0.6935, 0.3718, -0.0745], "2015-04-18 13:00:00": [0.7009, 0.3527, -0.0627], "2015-06-17 13:00:00": [0.7205, 0.3374, -0.0677], "2015-08-19 13:00:00": [0.6952, 0.3752, -0.0803], "2015-10-18 13:00:00": [0.6895, 0.3785, -0.0782], "2016-01-17 13:00:00": [0.7134, 0.35, -0.0733], "2016-03-17 13:00:00": [0.7141, 0.3504, -0.0743], "2016-05-16 13:00:00": [0.729, 0.3321, -0.0713], "2016-07-15 13:00:00": [0.6097, 0.4807, -0.1016], "2016-09-13 13:00:00": [0.718, 0.3427, -0.0714], "2017-01-03 13:00:00": [0.9443, -0.0313, 0.069]}, "2": {"2014-12-17 16:30:00": [0.7644, 0.2905, -0.0548], "2015-02-15 16:30:00": [0.7429, 0.3615, -0.1047], "2015-07-19 16:30:00": [0.7733, 0.3272, -0.102], "2015-10-30 16:30:00": [0.8375, 0.2293, -0.0675], "2016-01-10 16:30:00": [0.8681, 0.1689, -0.038]}, "29": {"2013-02-20 23:45:00": [0.88, 0.1842, -0.0639], "2013-04-21 23:45:00": [0.8695, 0.189, -0.0569], "2013-06-20 23:45:00": [0.9052, 0.0647, 0.0338], "2013-08-19 23:45:00": [0.8606, 0.1644, -0.0235], "2013-10-28 23:45:00": [0.8489, 0.1597, -0.0053], "2014-02-23 23:45:00": [0.8466, 0.1455, 0.0095], "2014-04-24 23:45:00": [0.9173, 0.0533, 0.0327], "2014-06-23 23:45:00": [0.8612, 0.1221, 0.0187], "2014-08-22 23:45:00": [0.8708, 0.1086, 0.0235], "2014-12-17 23:45:00": [0.8809, 0.1026, 0.0207], "2015-02-15 23:45:00": [0.9139, 0.0586, 0.0325], "2015-06-13 23:45:00": [0.888, 0.098, 0.0182], "2015-08-12 23:45:00": [0.8961, 0.0858, 0.0227], "2015-10-11 23:45:00": [0.9055, 0.0662, 0.0323], "2015-12-10 23:45:00": [0.8622, 0.1334, 0.0077], "2016-04-29 23:45:00": [0.8706, 0.0949, 0.0384], "2016-11-13 23:45:00": [0.8678, 0.125, 0.0119], "2017-01-15 23:45:00": [0.8028, 0.2112, -0.0082]}, "3": {"2015-03-12 15:15:00": [0.8655, 0.1445, -0.0117], "2015-06-09 15:15:00": [0.9118, 0.1005, -0.0121], "2015-08-08 15:15:00": [0.8902, 0.129, -0.0209], "2015-10-07 15:15:00": [0.8874, 0.1368, -0.0261], "2016-01-10 15:15:00": [0.8996, 0.1126, -0.0144], "2016-03-10 15:15:00": [0.8828, 0.1456, -0.0308], "2016-05-09 15:15:00": [0.8962, 0.1199, -0.0174], "2016-07-08 15:15:00": [0.9023, 0.1175, -0.0223], "2017-01-31 15:15:00": [0.8877, 0.1393, -0.0291], "2017-04-01 15:15:00": [0.894, 0.1268, -0.0226], "2017-05-31 15:15:00": [0.8778, 0.1561, -0.0365], "2017-07-30 15:15:00": [0.8661, 0.1799, -0.0473], "2017-09-28 15:15:00": [0.8193, 0.175, 0.0037]}, "31": {"2015-05-03 00:45:00": [0.7651, 0.2928, -0.0606], "2015-08-26 00:45:00": [0.7591, 0.2843, -0.0461], "2015-10-25 00:45:00": [0.798, 0.2327, -0.0336], "2016-02-19 00:45:00": [0.7852, 0.2639, -0.0519], "2016-04-19 00:45:00": [0.798, 0.2511, -0.0512], "2017-02-01 00:45:00": [0.7925, 0.2645, -0.0595], "2017-04-02 00:45:00": [0.7898, 0.2659, -0.0566], "2017-06-01 00:45:00": [0.8257, 0.2047, -0.033], "2017-07-31 00:45:00": [0.8051, 0.2422, -0.0503]}, "32": {"2015-02-11 14:15:00": [0.9355, 0.0984, -0.0287], "2015-05-27 14:15:00": [0.875, 0.1634, -0.0324], "2015-07-26 14:15:00": [0.859, 0.1677, -0.0218], "2015-10-31 14:15:00": [0.9429, 0.0592, 0.0035]}, "4": {"2015-03-06 12:15:00": [0.8722, 0.0546, 0.0725], "2015-05-05 12:15:00": [0.9083, 0.0428, 0.0492], "2015-07-04 12:15:00": [0.8915, 0.0724, 0.0352], "2015-09-02 12:15:00": [0.8907, 0.0776, 0.0297], "2015-11-01 12:15:00": [0.8888, 0.0767, 0.0328], "2016-01-10 12:15:00": [0.8847, 0.0705, 0.0422], "2016-03-10 12:15:00": [0.8869, 0.0658, 0.0445], "2016-07-05 12:15:00": [0.8914, 0.0739, 0.0318], "2017-01-31 12:15:00": [0.8865, 0.0758, 0.0355], "2017-04-16 12:15:00": [0.8921, 0.0657, 0.0422], "2017-06-15 12:15:00": [0.8889, 0.0453, 0.0662], "2017-08-14 12:15:00": [0.89, 0.0751, 0.0389]}, "7": {"2015-06-20 16:15:00": [0.7893, 0.2725, -0.0613], "2015-08-19 16:15:00": [0.7939, 0.2637, -0.0573], "2015-10-18 16:15:00": [0.789, 0.2689, -0.0577], "2015-12-17 16:15:00": [0.8158, 0.2297, -0.0432], "2016-02-15 16:15:00": [0.8156, 0.2277, -0.0426], "2016-04-15 16:15:00": [0.7751, 0.2884, -0.0616], "2016-06-14 16:15:00": [0.8339, 0.2103, -0.0411], "2016-08-13 16:15:00": [0.8117, 0.2424, -0.0518], "2016-10-12 16:15:00": [0.8781, 0.1451, -0.0204]}} |
Oops, something went wrong.