Spaces:
Sleeping
Sleeping
Daniel Varga
commited on
Commit
•
0c694ac
1
Parent(s):
5ef652c
before big rewrite
Browse files- v2/architecture.py +131 -3
v2/architecture.py
CHANGED
@@ -8,7 +8,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 =
|
12 |
|
13 |
|
14 |
# mock model
|
@@ -68,7 +68,7 @@ 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
|
72 |
|
73 |
# prod_cons_pred is a dataframe starting at now, containing
|
74 |
# fields Production and Consumption.
|
@@ -95,6 +95,134 @@ def simulator(battery_model, supplier, prod_cons, decider):
|
|
95 |
return None
|
96 |
|
97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
def main():
|
99 |
battery_model = BatteryModel(capacity=200, efficiency=0.95)
|
100 |
|
@@ -109,7 +237,7 @@ def main():
|
|
109 |
|
110 |
decider = Decider()
|
111 |
|
112 |
-
results = simulator(battery_model, supplier, all_2021_data, decider)
|
113 |
|
114 |
|
115 |
if __name__ == '__main__':
|
|
|
8 |
from data_processing import read_datasets, add_production_field, interpolate_and_join, Parameters
|
9 |
|
10 |
|
11 |
+
STEPS_PER_HOUR = 12
|
12 |
|
13 |
|
14 |
# mock model
|
|
|
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 decisions for the next hour
|
72 |
|
73 |
# prod_cons_pred is a dataframe starting at now, containing
|
74 |
# fields Production and Consumption.
|
|
|
95 |
return None
|
96 |
|
97 |
|
98 |
+
# TODO even in a first mockup version, parameters should come from a single
|
99 |
+
# place, not some from the parameters dataclass and some from the battery_model.
|
100 |
+
def simulator(battery_model, supplier, prod_cons, decider, parameters):
|
101 |
+
battery_model = copy.copy(battery_model)
|
102 |
+
|
103 |
+
demand_np = prod_cons['Consumption'].to_numpy()
|
104 |
+
production_np = prod_cons['Production'].to_numpy()
|
105 |
+
assert len(demand_np) == len(production_np)
|
106 |
+
step_in_minutes = prod_cons.index.freq.n
|
107 |
+
print(step_in_minutes)
|
108 |
+
assert step_in_minutes == 5
|
109 |
+
|
110 |
+
print("Simulating for", len(demand_np), "time steps. Each step is", step_in_minutes, "minutes.")
|
111 |
+
soc_series = []
|
112 |
+
# by convention, we only call end user demand, demand,
|
113 |
+
# and we only call end user consumption, consumption.
|
114 |
+
# in our simple model, demand is always satisfied, hence demand=consumption.
|
115 |
+
# BESS demand is called charge.
|
116 |
+
consumption_from_solar_series = [] # demand satisfied by solar production
|
117 |
+
consumption_from_network_series = [] # demand satisfied by network
|
118 |
+
consumption_from_bess_series = [] # demand satisfied by BESS
|
119 |
+
# the previous three must sum to demand_series.
|
120 |
+
|
121 |
+
# power taken from solar by BESS.
|
122 |
+
# note: in inital mock version power is never taken from network by BESS.
|
123 |
+
charge_of_bess_series = []
|
124 |
+
discarded_production_series = [] # solar power thrown away
|
125 |
+
|
126 |
+
# 1 is not nominal but targeted (healthy) maximum charge.
|
127 |
+
# we start with an empty battery, but not emptier than what's healthy for the batteries.
|
128 |
+
|
129 |
+
# For the sake of simplicity 0 <= soc <=1
|
130 |
+
# soc=0 means battery is emptied till it's 20% and soc=1 means battery is charged till 80% of its capacity
|
131 |
+
# soc = 1 - maximal_depth_of_discharge
|
132 |
+
# and will use only maximal_depth_of_discharge percent of the real battery capacity
|
133 |
+
|
134 |
+
max_cap_of_battery = parameters.bess_capacity * parameters.maximal_depth_of_discharge
|
135 |
+
cap_of_battery = soc * max_cap_of_battery
|
136 |
+
|
137 |
+
time_interval = step_in_minutes / 60 # amount of time step in hours
|
138 |
+
for i, (demand, production) in enumerate(zip(demand_np, production_np)):
|
139 |
+
|
140 |
+
# these five are modified on the appropriate codepaths:
|
141 |
+
consumption_from_solar = 0
|
142 |
+
consumption_from_bess = 0
|
143 |
+
consumption_from_network = 0
|
144 |
+
discarded_production = 0
|
145 |
+
|
146 |
+
unsatisfied_demand = demand
|
147 |
+
remaining_production = production
|
148 |
+
|
149 |
+
if parameters.bess_present:
|
150 |
+
is_battery_charged_enough = battery_model.soc > 0
|
151 |
+
is_battery_chargeable = battery_model.soc < 1.0
|
152 |
+
else:
|
153 |
+
is_battery_charged_enough = battery_model.soc <= 0
|
154 |
+
is_battery_chargeable = battery_model.soc >= 1.0
|
155 |
+
|
156 |
+
if unsatisfied_demand >= remaining_production:
|
157 |
+
# all goes to demand
|
158 |
+
consumption_from_solar = remaining_production
|
159 |
+
unsatisfied_demand -= consumption_from_solar
|
160 |
+
remaining_production = 0
|
161 |
+
# we try to cover the rest from BESS
|
162 |
+
if (unsatisfied_demand > 0 ) and parameters.bess_present:
|
163 |
+
if is_battery_charged_enough:
|
164 |
+
# battery capacity is limited!
|
165 |
+
if cap_of_battery >= unsatisfied_demand * time_interval :
|
166 |
+
consumption_from_bess = unsatisfied_demand
|
167 |
+
unsatisfied_demand = 0
|
168 |
+
cap_of_battery -= consumption_from_bess * time_interval
|
169 |
+
soc = cap_of_battery / max_cap_of_battery
|
170 |
+
else:
|
171 |
+
discharge_of_bess = cap_of_battery / time_interval
|
172 |
+
discharge = min(parameters.bess_discharge, discharge_of_bess)
|
173 |
+
consumption_from_bess = discharge
|
174 |
+
unsatisfied_demand -= consumption_from_bess
|
175 |
+
cap_of_battery -= consumption_from_bess * time_interval
|
176 |
+
soc = cap_of_battery / max_cap_of_battery
|
177 |
+
consumption_from_network = unsatisfied_demand
|
178 |
+
unsatisfied_demand = 0
|
179 |
+
else:
|
180 |
+
# we cover the rest from network
|
181 |
+
consumption_from_network = unsatisfied_demand
|
182 |
+
unsatisfied_demand = 0
|
183 |
+
else:
|
184 |
+
# demand fully satisfied by production
|
185 |
+
consumption_from_solar = unsatisfied_demand
|
186 |
+
remaining_production -= unsatisfied_demand
|
187 |
+
unsatisfied_demand = 0
|
188 |
+
if (remaining_production > 0) and parameters.bess_present:
|
189 |
+
# exploitable production still remains:
|
190 |
+
if is_battery_chargeable:
|
191 |
+
# we try to specify the BESS modell
|
192 |
+
if parameters.bess_charge <= remaining_production :
|
193 |
+
energy = parameters.bess_charge * time_interval
|
194 |
+
remaining_production = remaining_production - parameters.bess_charge
|
195 |
+
else :
|
196 |
+
energy = remaining_production * time_interval
|
197 |
+
remaining_production = 0
|
198 |
+
cap_of_battery += energy
|
199 |
+
soc = cap_of_battery / max_cap_of_battery
|
200 |
+
|
201 |
+
discarded_production = remaining_production
|
202 |
+
|
203 |
+
soc_series.append(battery_model.soc)
|
204 |
+
consumption_from_solar_series.append(consumption_from_solar)
|
205 |
+
consumption_from_network_series.append(consumption_from_network)
|
206 |
+
consumption_from_bess_series.append(consumption_from_bess)
|
207 |
+
discarded_production_series.append(discarded_production)
|
208 |
+
|
209 |
+
soc_series = np.array(soc_series)
|
210 |
+
consumption_from_solar_series = np.array(consumption_from_solar_series)
|
211 |
+
consumption_from_network_series = np.array(consumption_from_network_series)
|
212 |
+
consumption_from_bess_series = np.array(consumption_from_bess_series)
|
213 |
+
discarded_production_series = np.array(discarded_production_series)
|
214 |
+
|
215 |
+
results = pd.DataFrame({'soc_series': soc_series, 'consumption_from_solar': consumption_from_solar_series,
|
216 |
+
'consumption_from_network': consumption_from_network_series,
|
217 |
+
'consumption_from_bess': consumption_from_bess_series,
|
218 |
+
'discarded_production': discarded_production_series,
|
219 |
+
'Consumption': all_data['Consumption'],
|
220 |
+
'Production': all_data['Production']
|
221 |
+
})
|
222 |
+
results = results.set_index(all_data.index)
|
223 |
+
return results
|
224 |
+
|
225 |
+
|
226 |
def main():
|
227 |
battery_model = BatteryModel(capacity=200, efficiency=0.95)
|
228 |
|
|
|
237 |
|
238 |
decider = Decider()
|
239 |
|
240 |
+
results = simulator(battery_model, supplier, all_2021_data, decider, parameters)
|
241 |
|
242 |
|
243 |
if __name__ == '__main__':
|