Spaces:
Sleeping
Sleeping
File size: 7,316 Bytes
07e817b 376d985 07e817b 376d985 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
import pandas as pd
import numpy as np
from data_processing import add_production_field, interpolate_and_join, monthly_analysis
def simulator_with_solar(all_data, parameters):
demand_np = all_data['Consumption'].to_numpy()
production_np = all_data['Production'].to_numpy()
assert len(demand_np) == len(production_np)
step_in_minutes = all_data.index.freq.n
# print("Simulating for", len(demand_np), "time steps. Each step is", step_in_minutes, "minutes.")
soc_series = [] # soc = state_of_charge.
# by convention, we only call end user demand, demand,
# and we only call end user consumption, consumption.
# in our simple model, demand is always satisfied, hence demand=consumption.
# BESS demand is called charge.
consumption_from_solar_series = [] # demand satisfied by solar production
consumption_from_network_series = [] # demand satisfied by network
consumption_from_bess_series = [] # demand satisfied by BESS
# the previous three must sum to demand_series.
charge_of_bess_series = [] # power taken from solar by BESS. note: power never taken from network by BESS.
discarded_production_series = [] # solar power thrown away
# 1 is not nominal but targeted (healthy) maximum charge.
# we start with an empty battery, but not emptier than what's healthy for the batteries.
# For the sake of simplicity 0 <= soc <=1
# soc=0 means battery is emptied till it's 20% and soc=1 means battery is charged till 80% of its capacity
# soc = 1 - maximal_depth_of_discharge
# and will use only maximal_depth_of_discharge percent of the real battery capacity
soc = 0
max_cap_of_battery = parameters.bess_capacity * parameters.maximal_depth_of_discharge
cap_of_battery = soc * max_cap_of_battery
time_interval = step_in_minutes / 60 # amount of time step in hours
for i, (demand, production) in enumerate(zip(demand_np, production_np)):
# these five are modified on the appropriate codepaths:
consumption_from_solar = 0
consumption_from_bess = 0
consumption_from_network = 0
discarded_production = 0
unsatisfied_demand = demand
remaining_production = production
# crucially, we never charge the BESS from the network.
# if demand >= production:
# all goes to demand
# we try to cover the rest from BESS
# we cover the rest from network
# else:
# demand fully satisfied by production
# if exploitable production still remains:
# if is_battery_chargeable:
# charge_battery
# else:
# log discarded production
#battery_charged_enough = (soc > 1- maximal_depth_of_discharge)
if parameters.bess_present:
is_battery_charged_enough = soc > 0
is_battery_chargeable = soc < 1.0
else:
is_battery_charged_enough = soc <= 0
is_battery_chargeable = soc >= 1.0
if unsatisfied_demand >= remaining_production:
# all goes to demand
consumption_from_solar = remaining_production
unsatisfied_demand -= consumption_from_solar
remaining_production = 0
# we try to cover the rest from BESS
if (unsatisfied_demand > 0 ) and parameters.bess_present:
if is_battery_charged_enough:
# battery capacity is limited!
if cap_of_battery >= unsatisfied_demand * time_interval :
consumption_from_bess = unsatisfied_demand
unsatisfied_demand = 0
cap_of_battery -= consumption_from_bess * time_interval
soc = cap_of_battery / max_cap_of_battery
else:
discharge_of_bess = cap_of_battery / time_interval
discharge = min(parameters.bess_discharge, discharge_of_bess)
consumption_from_bess = discharge
unsatisfied_demand -= consumption_from_bess
cap_of_battery -= consumption_from_bess * time_interval
soc = cap_of_battery / max_cap_of_battery
consumption_from_network = unsatisfied_demand
unsatisfied_demand = 0
else:
# we cover the rest from network
consumption_from_network = unsatisfied_demand
unsatisfied_demand = 0
else:
# demand fully satisfied by production
consumption_from_solar = unsatisfied_demand
remaining_production -= unsatisfied_demand
unsatisfied_demand = 0
if (remaining_production > 0) and parameters.bess_present:
# exploitable production still remains:
if is_battery_chargeable:
# we try to specify the BESS modell
if parameters.bess_charge <= remaining_production :
energy = parameters.bess_charge * time_interval
remaining_production = remaining_production - parameters.bess_charge
else :
energy = remaining_production * time_interval
remaining_production = 0
cap_of_battery += energy
soc = cap_of_battery / max_cap_of_battery
discarded_production = remaining_production
soc_series.append(soc)
consumption_from_solar_series.append(consumption_from_solar)
consumption_from_network_series.append(consumption_from_network)
consumption_from_bess_series.append(consumption_from_bess)
charge_of_bess_series.append(soc)
discarded_production_series.append(discarded_production)
soc_series = np.array(soc_series)
consumption_from_solar_series = np.array(consumption_from_solar_series)
consumption_from_network_series = np.array(consumption_from_network_series)
consumption_from_bess_series = np.array(consumption_from_bess_series)
charge_of_bess_series = np.array(charge_of_bess_series)
discarded_production_series = np.array(discarded_production_series)
results = pd.DataFrame({'soc_series': soc_series, 'consumption_from_solar': consumption_from_solar_series,
'consumption_from_network': consumption_from_network_series,
'consumption_from_bess': consumption_from_bess_series,
'charge_of_bess': charge_of_bess_series,
'discarded_production': discarded_production_series,
'Consumption': all_data['Consumption'],
'Production': all_data['Production']
})
results = results.set_index(all_data.index)
return results
def evaluate_parameters(parameters, met_2021_data, cons_2021_data):
add_production_field(met_2021_data, parameters)
all_2021_data = interpolate_and_join(met_2021_data, cons_2021_data)
results = simulator_with_solar(all_2021_data, parameters)
consumptions_in_mwh = monthly_analysis(results)
return consumptions_in_mwh.sum(axis=0)
|