Daniel Varga commited on
Commit
4da0b0d
·
1 Parent(s): 9c39ff0

demand charge measured in kwh/15min

Browse files
Files changed (2) hide show
  1. v2/architecture.py +10 -2
  2. v2/supplier.py +14 -14
v2/architecture.py CHANGED
@@ -227,10 +227,16 @@ def simulator(battery_model, supplier, prod_cons, decider):
227
  consumption_from_bess_series = np.array(consumption_from_bess_series)
228
  discarded_production_series = np.array(discarded_production_series)
229
 
 
230
  total_charge, consumption_charge_series, demand_charges = supplier.fee(
231
- pd.Series(consumption_from_network_series, index=prod_cons.index),
232
  provide_detail=True)
233
  print(f"All in all we have paid {total_charge} to network.")
 
 
 
 
 
234
 
235
  results = pd.DataFrame({'soc_series': soc_series, 'consumption_from_solar': consumption_from_solar_series,
236
  'consumption_from_network': consumption_from_network_series,
@@ -248,6 +254,9 @@ def main():
248
 
249
  supplier = Supplier(price=100) # Ft/kWh
250
  supplier.set_price_for_interval(9, 17, 150) # nine-to-five increased price.
 
 
 
251
 
252
  parameters = SolarParameters()
253
 
@@ -267,7 +276,6 @@ def main():
267
  results = simulator(battery_model, supplier, all_data_with_predictions, decider)
268
  print("Simulation runtime", time.perf_counter() - t, "seconds.")
269
 
270
- return
271
  import matplotlib.pyplot as plt
272
  results['soc_series'].plot()
273
  plt.show()
 
227
  consumption_from_bess_series = np.array(consumption_from_bess_series)
228
  discarded_production_series = np.array(discarded_production_series)
229
 
230
+ consumption_from_network_pandas_series = pd.Series(consumption_from_network_series, index=prod_cons.index)
231
  total_charge, consumption_charge_series, demand_charges = supplier.fee(
232
+ consumption_from_network_pandas_series,
233
  provide_detail=True)
234
  print(f"All in all we have paid {total_charge} to network.")
235
+ fifteen_minute_peaks = consumption_from_network_pandas_series.resample('15T').sum()
236
+ demand_charges = pd.Series(demand_charges, index=fifteen_minute_peaks.index)
237
+ demand_charges.plot()
238
+ import matplotlib.pyplot as plt
239
+ plt.show()
240
 
241
  results = pd.DataFrame({'soc_series': soc_series, 'consumption_from_solar': consumption_from_solar_series,
242
  'consumption_from_network': consumption_from_network_series,
 
254
 
255
  supplier = Supplier(price=100) # Ft/kWh
256
  supplier.set_price_for_interval(9, 17, 150) # nine-to-five increased price.
257
+ # peak_demand dimension is kWh, but it's interpreted as the full consumption
258
+ # during a 15 minute timestep.
259
+ supplier.set_demand_charge(peak_demand=25, surcharge_per_kwh=200) # kWh in a 15 minutes interval, Ft/kWh
260
 
261
  parameters = SolarParameters()
262
 
 
276
  results = simulator(battery_model, supplier, all_data_with_predictions, decider)
277
  print("Simulation runtime", time.perf_counter() - t, "seconds.")
278
 
 
279
  import matplotlib.pyplot as plt
280
  results['soc_series'].plot()
281
  plt.show()
v2/supplier.py CHANGED
@@ -9,11 +9,11 @@ import unittest
9
  class Supplier:
10
  # price [HUF/kWh]
11
  # peak_demand kW
12
- # surcharge_per_kw [HUF/kW for each 15 minute timeframe]
13
  def __init__(self, price):
14
  self.hourly_prices = np.ones(168) * price
15
- self.peak_demand = np.inf # no demand_charge by default
16
- self.surcharge_per_kw = 0
17
 
18
  # start and end are indices of hours starting from Monday 00:00.
19
  def set_price_for_interval(self, start, end, price):
@@ -30,10 +30,10 @@ class Supplier:
30
  h = day * 24
31
  self.set_price_for_interval(h + start, h + end, price)
32
 
33
- def set_demand_charge(self, peak_demand, surcharge_per_kw):
34
- self.peak_demand = peak_demand # [kW]
35
  # the HUF charged per kW of demand exceeding peak_demand during a 15 minutes timeframe.
36
- self.surcharge_per_kw = surcharge_per_kw # [HUF/kW]
37
 
38
  @staticmethod
39
  def hour_of_date(date):
@@ -46,12 +46,12 @@ class Supplier:
46
  def price(self, date):
47
  return self.hourly_prices[self.hour_of_date(date)]
48
 
49
- # demand is the maximum demand in kW during a 15 minute interval
50
- def demand_charge(self, demand):
51
- if demand <= self.peak_demand:
52
  return 0.0
53
  else:
54
- return (demand - self.peak_demand) * self.surcharge_per_kw
55
 
56
  # demand_series is pandas series indexed by time.
57
  # during each time step demand [kW] is assumed to be constant.
@@ -70,8 +70,8 @@ class Supplier:
70
  assert 15 % demand_series.index.freq.n == 0
71
  time_steps_per_demand_charge_evaluation = 15 // demand_series.index.freq.n
72
  # fifteen_minute_peaks [kW] tells the maximum demand in a 15 minutes timeframe:
73
- fifteen_minute_peaks = demand_series.resample('15T').max()
74
- demand_charges = [self.demand_charge(demand) for demand in fifteen_minute_peaks]
75
  total_demand_charge = sum(demand_charges)
76
  total_charge = consumption_charge + total_demand_charge
77
  if provide_detail:
@@ -131,9 +131,9 @@ class TestSupplier(unittest.TestCase):
131
  expected_fee = (constant_demand * 23 + extreme_demand) * self.constant_price
132
  self.assertEqual(self.supplier.fee(demand_series), expected_fee)
133
 
134
- # now the (1000-500) kW above 500 kW is surcharged for (1000-500 kW) * 10 HUF/kW/15mins, for 1 hour,
135
  # that is 500*10*4=20000 demand_charge.
136
- self.supplier.set_demand_charge(peak_demand=500, surcharge_per_kw=10)
137
  expected_fee += 20000
138
  self.assertEqual(self.supplier.fee(demand_series), expected_fee)
139
 
 
9
  class Supplier:
10
  # price [HUF/kWh]
11
  # peak_demand kW
12
+ # surcharge_per_kwh [HUF/kWh for each 15 minute timeframe]
13
  def __init__(self, price):
14
  self.hourly_prices = np.ones(168) * price
15
+ self.peak_demand = np.inf # [kWh] (!) no demand_charge by default
16
+ self.surcharge_per_kwh = 0
17
 
18
  # start and end are indices of hours starting from Monday 00:00.
19
  def set_price_for_interval(self, start, end, price):
 
30
  h = day * 24
31
  self.set_price_for_interval(h + start, h + end, price)
32
 
33
+ def set_demand_charge(self, peak_demand, surcharge_per_kwh):
34
+ self.peak_demand = peak_demand # [kWh]
35
  # the HUF charged per kW of demand exceeding peak_demand during a 15 minutes timeframe.
36
+ self.surcharge_per_kwh = surcharge_per_kwh # [HUF/kWh]
37
 
38
  @staticmethod
39
  def hour_of_date(date):
 
46
  def price(self, date):
47
  return self.hourly_prices[self.hour_of_date(date)]
48
 
49
+ # demand is the maximum demand in kWh during a 15 minute interval
50
+ def demand_charge(self, demand_in_kwh):
51
+ if demand_in_kwh <= self.peak_demand:
52
  return 0.0
53
  else:
54
+ return (demand_in_kwh - self.peak_demand) * self.surcharge_per_kwh
55
 
56
  # demand_series is pandas series indexed by time.
57
  # during each time step demand [kW] is assumed to be constant.
 
70
  assert 15 % demand_series.index.freq.n == 0
71
  time_steps_per_demand_charge_evaluation = 15 // demand_series.index.freq.n
72
  # fifteen_minute_peaks [kW] tells the maximum demand in a 15 minutes timeframe:
73
+ fifteen_minute_demands_in_kwh = demand_series.resample('15T').sum() * step_in_hour
74
+ demand_charges = [self.demand_charge(demand_in_kwh) for demand_in_kwh in fifteen_minute_demands_in_kwh]
75
  total_demand_charge = sum(demand_charges)
76
  total_charge = consumption_charge + total_demand_charge
77
  if provide_detail:
 
131
  expected_fee = (constant_demand * 23 + extreme_demand) * self.constant_price
132
  self.assertEqual(self.supplier.fee(demand_series), expected_fee)
133
 
134
+ # now the (1000-500) kW above 500 kW is surcharged for (1000-500 kW) * 10 HUF/kWh/15mins, for 1 hour,
135
  # that is 500*10*4=20000 demand_charge.
136
+ self.supplier.set_demand_charge(peak_demand=500, surcharge_per_kwh=10)
137
  expected_fee += 20000
138
  self.assertEqual(self.supplier.fee(demand_series), expected_fee)
139