Daniel Varga commited on
Commit
5ef652c
·
1 Parent(s): a0c2244
Files changed (3) hide show
  1. v2/architecture.py +116 -0
  2. v2/data_processing.py +1 -0
  3. v2/supplier.py +1 -0
v2/architecture.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pandas as pd
3
+ import copy
4
+ from enum import IntEnum
5
+
6
+ # it's really just a network pricing model
7
+ from supplier import Supplier
8
+ from data_processing import read_datasets, add_production_field, interpolate_and_join, Parameters
9
+
10
+
11
+ STEPS_PER_HOUR = 4
12
+
13
+
14
+ # mock model
15
+ class BatteryModel:
16
+ def __init__(self, capacity, efficiency=0.95):
17
+ self.soc = 0
18
+ self.capacity = capacity # kWh
19
+ self.efficiency = efficiency
20
+
21
+ def discharge(self, target):
22
+ assert 0 <= self.soc <= 1
23
+ if self.soc >= target:
24
+ self.soc -= target
25
+ amount = target
26
+ else:
27
+ amount = self.soc
28
+ self.soc = 0
29
+ assert 0 <= self.soc <= 1
30
+ return amount
31
+
32
+ # not very refined, whatevs.
33
+ def charge(self, target):
34
+ assert 0 <= self.soc <= 1
35
+ target_to_add = target * self.efficiency
36
+ if self.soc <= 1 - target_to_add:
37
+ self.soc += target_to_add
38
+ could_take = target
39
+ else:
40
+ could_take = (1 - self.soc) / self.efficiency
41
+ self.soc = 1
42
+ assert 0 <= self.soc <= 1
43
+ return could_take
44
+
45
+
46
+ class Decision(IntEnum):
47
+ # use solar to satisfy consumption,
48
+ # and if it is not enough, use network.
49
+ # BESS is not discharged in this mode,
50
+ # but might be charged if solar has surplus.
51
+ PASSIVE = 0
52
+
53
+ # use the battery if possible and necessary.
54
+ # the possible part means that there's charge in it,
55
+ # and the necessary part means that the consumption
56
+ # is not already covered by solar.
57
+ DISCHARGE = 1
58
+
59
+ # use the network to charge the battery
60
+ # this is similar to PASSIVE, but forces the
61
+ # BESS to be charged, even if solar does not cover
62
+ # the whole of consumption plus BESS.
63
+ NETWORK_CHARGE = 2
64
+
65
+
66
+ # mock class as usual
67
+ class Decider:
68
+ def __init__(self):
69
+ self.parameters = None
70
+ self.input_window_size = STEPS_PER_HOUR * 24 # day long window.
71
+ self.output_window_size = STEPS_PER_HOUR # only output 4 decisions for the next hour
72
+
73
+ # prod_cons_pred is a dataframe starting at now, containing
74
+ # fields Production and Consumption.
75
+ # this function does not mutate its inputs.
76
+ # battery_model is just queried for capacity and current soc.
77
+ # the method returns a pd.Series of Decisions as integers.
78
+ def decide(self, prod_cons_pred, battery_model):
79
+ assert len(prod_cons_pred) == self.input_window_size
80
+ # dummy decider always says DISCHARGE:
81
+ return pd.Series([Decision.DISCHARGE] * STEPS_PER_HOUR, dtype=int)
82
+
83
+
84
+ # this function does not mutate its inputs.
85
+ # it makes a clone of battery_model and modifies that.
86
+ # it returns
87
+ def simulator(battery_model, supplier, prod_cons, decider):
88
+ battery_model = copy.copy(battery_model)
89
+ for indx, date in enumerate(prod_cons.index):
90
+ if indx + decider.input_window_size > len(prod_cons):
91
+ break
92
+ # not really a prediction obviously
93
+ prod_cons_pred = prod_cons.iloc[indx: indx + decider.input_window_size]
94
+ decisions = decider.decide(prod_cons_pred, battery_model)
95
+ return None
96
+
97
+
98
+ def main():
99
+ battery_model = BatteryModel(capacity=200, efficiency=0.95)
100
+
101
+ supplier = Supplier(price=100) # Ft/kWh
102
+ supplier.set_price_for_interval(9, 17, 150) # nine-to-five increased price.
103
+
104
+ parameters = Parameters()
105
+
106
+ met_2021_data, cons_2021_data = read_datasets()
107
+ add_production_field(met_2021_data, parameters)
108
+ all_2021_data = interpolate_and_join(met_2021_data, cons_2021_data)
109
+
110
+ decider = Decider()
111
+
112
+ results = simulator(battery_model, supplier, all_2021_data, decider)
113
+
114
+
115
+ if __name__ == '__main__':
116
+ main()
v2/data_processing.py ADDED
@@ -0,0 +1 @@
 
 
1
+ ../data_processing.py
v2/supplier.py ADDED
@@ -0,0 +1 @@
 
 
1
+ ../supplier.py