from config import pv_config, ess_config, grid_config import pandas as pd class EnergySystem: def __init__(self, pv_type: pv_config, ess_type: ess_config, grid_type: grid_config): self.pv = pv_type self.ess = ess_type self.grid = grid_type self.day_generated = [] self.generated = 0 self.stored = 0 self.hour_stored = [] self.hour_stored_2 = [] self.afford = True self.cost = self.ess.get_cost() + self.pv.get_cost() self.overload_cnt = 0 self.spring_week_gen = [] self.summer_week_gen = [] self.autumn_week_gen = [] self.winter_week_gen = [] self.spring_week_soc = [] self.summer_week_soc = [] self.autumn_week_soc = [] self.winter_week_soc = [] self.factory_demand = [] self.buy_price_kWh = [] self.sell_price_kWh = [] self.pv_generated_kWh = [] self.grid_need_power_kW = [] self.time = [] self.ess_rest = 0 self.granularity = 4 self.season_step = self.granularity * 24 * 7 * 12 self.season_start= self.granularity * 24 * 7 * 2 self.week_length = self.granularity * 24 * 7 self.unmet = [] def get_cost(self): return self.ess.get_cost()+self.pv.get_cost() def simulate(self, data, time_interval): """ The program will use the PV to supply the factory first. If the PV output can meet the factory's demand, it will be directly powered, and the excess electrical energy will be used to charge the ESS. Program will use the PV to supply the Ess. When the PV is insufficient, the ESS is used to supplement. If the PV output is not enough to meet the factory's demand, the required power is first obtained from the ESS. If the ESS is also insufficient to meet the demand, it will be obtained from the grid. When the stored power in the ESS is also insufficient to supplement, the remaining required power will be purchased from the grid. Args: data: pandas.DataFrame The data that contains the factory's demand, PV output, and electricity price. time_interval: float The time interval of the data in hours. Returns: tuple The total benefit, total netto benefit, and total generated energy. """ total_benefit = 0 total_netto_benefit = 0 total_gen = 0 net_grid = 0. for index, row in data.iterrows(): time = row['time'] self.time.append(time) # sunlight_intensity = row['sunlight'] pv_yield = row['PV yield[kW/kWp]'] factory_demand = row['demand'] electricity_price = row['buy'] sell_price = row['sell'] # electricity_price = self.grid.get_price_for_time(time) # if time == '00:00': # self.day_generated.append(self.generated) # self.generated = 0 # if time.endswith('14:00'): # soc = self.ess.storage / self.ess.capacity # self.hour_stored.append(soc) # if time.endswith('08:00'): # soc = self.ess.storage / self.ess.capacity # self.hour_stored_2.append(soc) # `generated_pv_power`: the power generated by the PV in kW # `generated_pv_energy`: the energy generated by the PV in kWh generated_pv_power = self.pv.capacity * pv_yield generated_pv_energy = generated_pv_power * time_interval * self.pv.loss self.pv_generated_kWh.append(generated_pv_energy) self.factory_demand.append(factory_demand) self.buy_price_kWh.append(electricity_price) self.sell_price_kWh.append(sell_price) self.generated += generated_pv_energy # generated_pv_energy is larger than factory_demand energy if generated_pv_energy >= factory_demand * time_interval: """ That means the generated energy is enough to power the factory. The surplus energy will be used to charge the ESS. surplus_energy: The energy that is left after powering the factory. formula: generated_pv_energy - factory_demand * time_interval charge_to_ess: The energy that will be charged to the ESS. formula: min(surplus_energy, ess.charge_power * time_interval, ess.capacity - ess.storage) surplus_after_ess: The energy that is left after charging the ESS. """ surplus_energy = generated_pv_energy - factory_demand * time_interval charge_to_ess = min(surplus_energy, self.ess.charge_power * time_interval, self.ess.capacity - self.ess.storage) self.ess.storage += charge_to_ess surplus_after_ess = surplus_energy - charge_to_ess """ If there is still surplus energy after charging the ESS, and the generated PV power is greater than the sum of the ESS's charge power and the factory's demand power, the surplus energy will be sold to the grid. """ if surplus_after_ess > 0 and generated_pv_power > self.ess.charge_power + factory_demand: sold_to_grid = surplus_after_ess sell_income = sold_to_grid * sell_price total_benefit += sell_income """ Saved energy is the energy that is saved by using the PV to power the factory. """ saved_energy = factory_demand * time_interval self.grid_need_power_kW.append(0) else: """ If the generated energy is not enough to power the factory, the ESS will be used to supplement the energy. needed_from_ess: The energy that is needed from the ESS to power the factory. formula: factory_demand * time_interval - generated_pv_energy """ needed_from_ess = factory_demand * time_interval - generated_pv_energy """ If the ESS has enough stored energy to power the factory, the energy will be taken from the ESS. """ if self.ess.storage * self.ess.loss >= needed_from_ess: if self.ess.discharge_power * time_interval * self.ess.loss < needed_from_ess: discharging_power = self.ess.discharge_power * time_interval else: discharging_power = needed_from_ess / self.ess.loss self.ess.storage -= discharging_power """ In this case, the energy that is needed from the grid is 0. """ saved_energy = generated_pv_energy + discharging_power * self.ess.loss self.grid_need_power_kW.append(0) else: """ If the ESS does not have enough stored energy to power the factory, the energy will be taken from the grid. """ if self.grid.capacity * time_interval + generated_pv_energy + self.ess.storage * self.ess.loss < factory_demand * time_interval: self.afford = False self.overload_cnt+=1 self.unmet.append((index,time,factory_demand,generated_pv_power)) saved_energy = generated_pv_energy + self.ess.storage * self.ess.loss self.ess.storage = 0 needed_from_grid = factory_demand * time_interval - saved_energy net_grid = min(self.grid.capacity * time_interval, needed_from_grid) * self.grid.loss self.grid_need_power_kW.append(needed_from_grid * 4) total_gen += saved_energy benefit = (saved_energy) * electricity_price cost = net_grid * electricity_price total_netto_benefit += benefit total_benefit += benefit - cost print_season_flag = False if print_season_flag == True: week_start = self.season_start week_end = self.week_length + week_start if index in range(week_start, week_end): self.spring_week_gen.append(generated_pv_power) self.spring_week_soc.append(self.ess.storage / self.ess.capacity) self.ess_rest = self.ess.storage # summer week_start += self.season_step week_end += self.season_step if index in range(week_start, week_end): self.summer_week_gen.append(generated_pv_power) self.summer_week_soc.append(self.ess.storage / self.ess.capacity) # # autumn week_start += self.season_step week_end += self.season_step if index in range(week_start, week_end): self.autumn_week_gen.append(generated_pv_power) self.autumn_week_soc.append(self.ess.storage / self.ess.capacity) week_start += self.season_step week_end += self.season_step if index in range(week_start, week_end): self.winter_week_gen.append(generated_pv_power) self.winter_week_soc.append(self.ess.storage / self.ess.capacity) return (total_benefit, total_netto_benefit, total_gen)