Implemented baseline policy
This commit is contained in:
@@ -4,7 +4,7 @@ Eerst literatuur bekijken ofdat probleem al voorkomt
|
||||
|
||||
- [x] compare reconstructed prices with real imbalance prices (on figure and metrics on whole test set)
|
||||
|
||||
- [ ] Baseline policy (Eche imbalanceprijzen):
|
||||
- [x] Baseline policy (Eche imbalanceprijzen):
|
||||
- Batterij:
|
||||
- 2 MWh
|
||||
- 1 MW power (charging / discharging)
|
||||
@@ -13,9 +13,7 @@ Eerst literatuur bekijken ofdat probleem al voorkomt
|
||||
|
||||
- 1000 generaties voor 1 dag -> 1000 prijzen reconstrueren -> tresholds bepalen (logische tresholds) -> 2 tresholds voor 1 dag en toepassen op volledige test set
|
||||
|
||||
-> resultaten: # charge cycle
|
||||
|
||||
- [ ] Learning rate non autoregressive
|
||||
- [x] Learning rate non autoregressive
|
||||
|
||||
- [x] !!! Historgram quantile plot volledige dag
|
||||
- [x] CRPS en MAE, over 96 wanneer wordt het slecht
|
||||
@@ -199,4 +197,4 @@ Estimated Total Size (MB): 219.17
|
||||
| Model | Experiment | test_L1Loss | test_CRPSLoss |
|
||||
|---|---|---| ---|
|
||||
| Linear Model | [Link](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/8f00fa7713f94d2ca376ce0eabc2742f/info-output/metrics/scalar?columns=selected&columns=type&columns=name&columns=tags&columns=status&columns=project.name&columns=users&columns=started&columns=last_update&columns=last_iteration&columns=parent.name&columns=m.1a899a19b54957e02a21c3a1d82577ad.0970ca62a85af2722008c5220e9d8a9e.value.Summary%2Ftest_CRPSLoss.lastreported&columns=m.293da6b015ca6a65992dcf7a53fa0237.098f6bcd4621d373cade4e832627b4f6.min_value.PinballLoss.test&order=-last_update&filter=) | 104.89022124436754 | 69.04472427024562 |
|
||||
| Non Linear Model | [Link](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/f2ed5c3b54cd4d859d72bc55e53ff646/info-output/metrics/scalar?columns=selected&columns=type&columns=name&columns=tags&columns=status&columns=project.name&columns=users&columns=started&columns=last_update&columns=last_iteration&columns=parent.name&columns=m.1a899a19b54957e02a21c3a1d82577ad.0970ca62a85af2722008c5220e9d8a9e.value.Summary%2Ftest_CRPSLoss.lastreported&columns=m.293da6b015ca6a65992dcf7a53fa0237.098f6bcd4621d373cade4e832627b4f6.min_value.PinballLoss.test&order=-last_update&filter=) | 103.250159162178 | 74.21675055952228 |
|
||||
| Non Linear Model | [Link](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/d19c767120a24f97b3231f0e8ac9f2b5/info-output/metrics/scalar?columns=selected&columns=type&columns=name&columns=tags&columns=status&columns=project.name&columns=users&columns=started&columns=last_update&columns=last_iteration&columns=parent.name&columns=m.1a899a19b54957e02a21c3a1d82577ad.0970ca62a85af2722008c5220e9d8a9e.value.Summary%2Ftest_CRPSLoss.lastreported&columns=m.293da6b015ca6a65992dcf7a53fa0237.098f6bcd4621d373cade4e832627b4f6.min_value.PinballLoss.test&order=-last_update&filter=) | 103.3332725941881 | 69.50204645931149 |
|
||||
|
||||
85
Result-Reports/Policies.md
Normal file
85
Result-Reports/Policies.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Policies for battery charging
|
||||
## Battery
|
||||
Capacity: 2MWh \
|
||||
Charging Power: 1MW \
|
||||
Discharging Power: 1MW
|
||||
|
||||
## Baseline policy
|
||||
Determining 2 thresholds for battery charging and discharging. Charging when the imbalance price is below the lower threshold and discharging when the imbalance price is above the upper threshold.
|
||||
|
||||
Training data: 01-01-2020 - 31-12-2022
|
||||
Test data: 01-01-2023 - 12-12-2023
|
||||
|
||||
| Charging threshold (€/MWh) | Discharge threshold (€/MWh) | Profit (€) | Charge Cycles |
|
||||
------------------:|---------------------:|---------------:|----------------:|
|
||||
| 150 | 100 | 366406 | 2658 |
|
||||
| 150 | 50 | 366406 | 2658 |
|
||||
| 150 | 0 | 366406 | 2658 |
|
||||
| 150 | 150 | 365999 | 2639 |
|
||||
| 100 | 150 | 364905 | 2306 |
|
||||
| 100 | 100 | 364483 | 2886 |
|
||||
| 100 | 0 | 364376 | 2896 |
|
||||
| 100 | 50 | 364376 | 2896 |
|
||||
| 200 | 150 | 352953 | 2416 |
|
||||
| 200 | 100 | 352953 | 2416 |
|
||||
| 200 | 50 | 352953 | 2416 |
|
||||
| 200 | 0 | 352953 | 2416 |
|
||||
| 200 | 200 | 352811 | 2413 |
|
||||
| 150 | 200 | 350975 | 2243 |
|
||||
| 100 | 200 | 345855 | 1929 |
|
||||
| 50 | 50 | 341569 | 3864 |
|
||||
| 50 | 100 | 341421 | 2357 |
|
||||
| 50 | 0 | 341202 | 3865 |
|
||||
| 200 | 250 | 337567 | 1996 |
|
||||
| 50 | 150 | 330189 | 1815 |
|
||||
| 150 | 250 | 329684 | 1835 |
|
||||
| 200 | 300 | 329343 | 1610 |
|
||||
| 250 | 250 | 323456 | 2089 |
|
||||
| 250 | 0 | 322692 | 2103 |
|
||||
| 250 | 150 | 322692 | 2103 |
|
||||
| 250 | 50 | 322692 | 2103 |
|
||||
| 250 | 100 | 322692 | 2103 |
|
||||
| 250 | 200 | 322692 | 2103 |
|
||||
| 250 | 300 | 321378 | 1685 |
|
||||
| 100 | 250 | 319651 | 1554 |
|
||||
| 150 | 300 | 319089 | 1462 |
|
||||
| 300 | 250 | 314776 | 1752 |
|
||||
| 300 | 50 | 314776 | 1752 |
|
||||
| 300 | 100 | 314776 | 1752 |
|
||||
| 300 | 150 | 314776 | 1752 |
|
||||
| 300 | 200 | 314776 | 1752 |
|
||||
| 300 | 0 | 314776 | 1752 |
|
||||
| 50 | 200 | 313685 | 1476 |
|
||||
| 300 | 300 | 313469 | 1749 |
|
||||
| 100 | 300 | 309773 | 1236 |
|
||||
| 200 | 350 | 306832 | 1341 |
|
||||
| 250 | 350 | 302349 | 1411 |
|
||||
| 150 | 350 | 295917 | 1202 |
|
||||
| 300 | 350 | 290570 | 1466 |
|
||||
| 50 | 250 | 290097 | 1195 |
|
||||
| 350 | 300 | 284856 | 1507 |
|
||||
| 350 | 250 | 284856 | 1507 |
|
||||
| 350 | 150 | 284856 | 1507 |
|
||||
| 350 | 100 | 284856 | 1507 |
|
||||
| 350 | 50 | 284856 | 1507 |
|
||||
| 350 | 0 | 284856 | 1507 |
|
||||
| 350 | 200 | 284856 | 1507 |
|
||||
| 100 | 350 | 284323 | 996 |
|
||||
| 50 | 300 | 280922 | 954 |
|
||||
| 350 | 350 | 279834 | 1496 |
|
||||
| 0 | 150 | 277863 | 1243 |
|
||||
| 0 | 100 | 276435 | 1477 |
|
||||
| 0 | 200 | 270056 | 1080 |
|
||||
| 0 | 50 | 269265 | 1914 |
|
||||
| 50 | 350 | 259569 | 787 |
|
||||
| 0 | 250 | 258282 | 908 |
|
||||
| 0 | 300 | 250679 | 741 |
|
||||
| 0 | 0 | 248357 | 2065 |
|
||||
| 0 | 350 | 233775 | 624 |
|
||||
|
||||
## Optimal policy
|
||||
Charge threshold: 150 €/MWh \
|
||||
Discharge threshold: 100 €/MWh
|
||||
|
||||
Profit on test data: € 169846.84 \
|
||||
Charge cycles: 1403
|
||||
@@ -11,3 +11,4 @@ clearml
|
||||
properscoring
|
||||
nbconvert
|
||||
torchinfo
|
||||
tabulate
|
||||
139
src/policies/simple_baseline.py
Normal file
139
src/policies/simple_baseline.py
Normal file
@@ -0,0 +1,139 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import itertools
|
||||
from tqdm import tqdm
|
||||
|
||||
imbalance_prices = "data/imbalance_prices.csv"
|
||||
|
||||
class Battery:
|
||||
def __init__(self, capacity: float, power: float):
|
||||
"""
|
||||
:param capacity: Battery capacity in MWh
|
||||
:param current_charge: Current charge in MWh
|
||||
:param power: Power in MW
|
||||
"""
|
||||
self.capacity = capacity
|
||||
self.current_charge = 0
|
||||
self.power = power
|
||||
self.charge_cycles = 0
|
||||
|
||||
self.charging = False
|
||||
self.discharging = False
|
||||
|
||||
def simulate(self):
|
||||
"""
|
||||
Simulate the battery for one time step (one quarter of an hour)
|
||||
"""
|
||||
if self.charging:
|
||||
return self.charge()
|
||||
elif self.discharging:
|
||||
return self.discharge()
|
||||
return 0
|
||||
|
||||
def discharge(self):
|
||||
"""
|
||||
Discharge the battery by one time step (one quarter of an hour)
|
||||
"""
|
||||
if self.current_charge == 0:
|
||||
return 0
|
||||
self.discharging = True
|
||||
self.current_charge -= self.power / 4
|
||||
|
||||
if self.current_charge <= 0:
|
||||
self.current_charge = 0
|
||||
self.discharging = False
|
||||
self.charge_cycles += 1
|
||||
|
||||
return self.power / 4
|
||||
|
||||
def charge(self):
|
||||
"""
|
||||
Charge the battery by one time step (one quarter of an hour)
|
||||
"""
|
||||
if self.current_charge == self.capacity:
|
||||
return 0
|
||||
self.charging = True
|
||||
self.current_charge += self.power / 4
|
||||
|
||||
if self.current_charge >= self.capacity:
|
||||
self.current_charge = self.capacity
|
||||
self.charging = False
|
||||
|
||||
return self.power / 4
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the battery to its initial state
|
||||
"""
|
||||
self.current_charge = 0
|
||||
self.charging = False
|
||||
self.discharging = False
|
||||
self.charge_cycles = 0
|
||||
|
||||
class BaselinePolicy():
|
||||
def __init__(self, battery: Battery):
|
||||
self.battery = battery
|
||||
self.train_data = self.load_imbalance_prices(train=True)
|
||||
self.test_data = self.load_imbalance_prices(train=False)
|
||||
|
||||
# print first datetime of train and test data
|
||||
print(f"Training range: {self.train_data.iloc[0]['DateTime'].strftime('%d-%m-%Y')} - {self.train_data.iloc[-1]['DateTime'].strftime('%d-%m-%Y')}")
|
||||
print(f"Test range: {self.test_data.iloc[0]['DateTime'].strftime('%d-%m-%Y')} - {self.test_data.iloc[-1]['DateTime'].strftime('%d-%m-%Y')}")
|
||||
|
||||
def load_imbalance_prices(self, train: bool = True):
|
||||
imbalance_prices = pd.read_csv('data/imbalance_prices.csv', parse_dates=True, sep=";")
|
||||
imbalance_prices = imbalance_prices[['DateTime', 'Positive imbalance price']]
|
||||
imbalance_prices['DateTime'] = pd.to_datetime(imbalance_prices['DateTime'], utc=True)
|
||||
if train:
|
||||
imbalance_prices = imbalance_prices.loc[imbalance_prices['DateTime'].dt.year < 2023]
|
||||
imbalance_prices = imbalance_prices.loc[imbalance_prices['DateTime'].dt.year >= 2020]
|
||||
else:
|
||||
imbalance_prices = imbalance_prices.loc[imbalance_prices['DateTime'].dt.year == 2023]
|
||||
imbalance_prices = imbalance_prices.sort_values(by=['DateTime'])
|
||||
return imbalance_prices
|
||||
|
||||
def get_train_score(self, charge_treshold, discharge_treshold):
|
||||
return self.get_score(self.train_data, charge_treshold, discharge_treshold)
|
||||
|
||||
def get_test_score(self, charge_treshold, discharge_treshold):
|
||||
return self.get_score(self.test_data, charge_treshold, discharge_treshold)
|
||||
|
||||
# if price is below treshold -> charge battery: total_profit -= charge * price
|
||||
# if price is above treshold -> discharge battery: total_profit += discharge * price
|
||||
def get_score(self, df, charge_treshold, discharge_treshold):
|
||||
self.battery.reset()
|
||||
total_profit = 0
|
||||
|
||||
for index, row in df.iterrows():
|
||||
if self.battery.charging:
|
||||
total_profit -= self.battery.simulate() * row['Positive imbalance price']
|
||||
elif self.battery.discharging:
|
||||
total_profit += self.battery.simulate() * row['Positive imbalance price']
|
||||
else:
|
||||
if row['Positive imbalance price'] < charge_treshold:
|
||||
total_profit -= self.battery.charge() * row['Positive imbalance price']
|
||||
elif row['Positive imbalance price'] > discharge_treshold:
|
||||
total_profit += self.battery.discharge() * row['Positive imbalance price']
|
||||
|
||||
return total_profit, self.battery.charge_cycles
|
||||
|
||||
def treshold_scores(self, charge_tresholds, discharge_tresholds):
|
||||
df = pd.DataFrame(columns=["Charge treshold", "Discharge treshold", "Total Profit", "Charge cycles"])
|
||||
|
||||
for charge_treshold, discharge_treshold in tqdm(itertools.product(charge_tresholds, discharge_tresholds)):
|
||||
total_profit, charge_cycles = self.get_train_score(charge_treshold, discharge_treshold)
|
||||
df = pd.concat([df, pd.DataFrame([[charge_treshold, discharge_treshold, total_profit, charge_cycles]], columns=["Charge treshold", "Discharge treshold", "Total Profit", "Charge cycles"])])
|
||||
|
||||
df = df.sort_values(by=['Total Profit'], ascending=False)
|
||||
return df
|
||||
|
||||
|
||||
battery = Battery(2, 1)
|
||||
policy = BaselinePolicy(battery)
|
||||
|
||||
# charge_tresholds = [0, 50, 100, 150, 200, 250, 300, 350]
|
||||
# discharge_tresholds = [0, 50, 100, 150, 200, 250, 300, 350]
|
||||
# df = policy.treshold_scores(charge_tresholds, discharge_tresholds)
|
||||
# print(df.to_markdown())
|
||||
|
||||
print(policy.get_test_score(150, 100))
|
||||
Reference in New Issue
Block a user