2024-05-03 14:07:57 +02:00
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
2024-05-06 19:24:11 +02:00
self . day_generated = [ ]
self . generated = 0
self . stored = 0
self . hour_stored = [ ]
self . hour_stored_2 = [ ]
self . afford = True
2024-05-07 10:27:45 +02:00
self . cost = self . ess . get_cost ( ) + self . pv . get_cost ( )
2024-05-06 19:24:11 +02:00
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 = [ ]
2024-05-15 15:06:43 +02:00
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
2024-05-06 19:24:11 +02:00
self . granularity = 4
self . season_step = self . granularity * 24 * 7 * 12
2024-05-07 10:27:45 +02:00
self . season_start = self . granularity * 24 * 7 * 2
2024-05-06 19:24:11 +02:00
self . week_length = self . granularity * 24 * 7
2024-05-07 10:27:45 +02:00
self . unmet = [ ]
2024-05-06 19:24:11 +02:00
2024-05-07 10:27:45 +02:00
def get_cost ( self ) :
return self . ess . get_cost ( ) + self . pv . get_cost ( )
2024-05-03 14:07:57 +02:00
2024-05-03 15:36:02 +02:00
def simulate ( self , data , time_interval ) :
2024-05-17 10:48:07 +02:00
"""
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 .
"""
2024-05-03 14:07:57 +02:00
total_benefit = 0
2024-05-10 23:57:58 +02:00
total_netto_benefit = 0
total_gen = 0
2024-05-15 15:06:43 +02:00
net_grid = 0.
2024-05-03 14:07:57 +02:00
for index , row in data . iterrows ( ) :
time = row [ ' time ' ]
2024-05-15 15:06:43 +02:00
self . time . append ( time )
2024-05-13 16:48:16 +02:00
# sunlight_intensity = row['sunlight']
pv_yield = row [ ' PV yield[kW/kWp] ' ]
2024-05-03 14:07:57 +02:00
factory_demand = row [ ' demand ' ]
2024-05-10 17:29:08 +02:00
electricity_price = row [ ' buy ' ]
sell_price = row [ ' sell ' ]
2024-05-06 19:24:11 +02:00
# electricity_price = self.grid.get_price_for_time(time)
2024-05-17 10:48:07 +02:00
# 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
2024-05-15 15:06:43 +02:00
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 )
2024-05-06 19:24:11 +02:00
self . generated + = generated_pv_energy
2024-05-17 10:48:07 +02:00
# generated_pv_energy is larger than factory_demand energy
2024-05-03 14:07:57 +02:00
if generated_pv_energy > = factory_demand * time_interval :
2024-05-17 10:48:07 +02:00
"""
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 .
"""
2024-05-03 14:07:57 +02:00
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 )
2024-05-03 15:12:52 +02:00
self . ess . storage + = charge_to_ess
2024-05-03 14:07:57 +02:00
surplus_after_ess = surplus_energy - charge_to_ess
2024-05-17 10:48:07 +02:00
"""
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 .
"""
2024-05-03 14:07:57 +02:00
if surplus_after_ess > 0 and generated_pv_power > self . ess . charge_power + factory_demand :
sold_to_grid = surplus_after_ess
2024-05-10 17:29:08 +02:00
sell_income = sold_to_grid * sell_price
2024-05-03 14:07:57 +02:00
total_benefit + = sell_income
2024-05-17 10:48:07 +02:00
"""
Saved energy is the energy that is saved by using the PV to power the factory .
"""
2024-05-06 19:24:11 +02:00
saved_energy = factory_demand * time_interval
2024-05-15 15:06:43 +02:00
self . grid_need_power_kW . append ( 0 )
2024-05-03 14:07:57 +02:00
else :
2024-05-17 10:48:07 +02:00
"""
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
"""
2024-05-03 14:07:57 +02:00
needed_from_ess = factory_demand * time_interval - generated_pv_energy
2024-05-17 10:48:07 +02:00
"""
If the ESS has enough stored energy to power the factory , the energy will be taken from the ESS .
"""
2024-05-06 19:24:11 +02:00
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
2024-05-03 14:07:57 +02:00
self . ess . storage - = discharging_power
2024-05-17 10:48:07 +02:00
"""
In this case , the energy that is needed from the grid is 0.
"""
2024-05-06 19:24:11 +02:00
saved_energy = generated_pv_energy + discharging_power * self . ess . loss
2024-05-15 15:06:43 +02:00
self . grid_need_power_kW . append ( 0 )
2024-05-03 14:07:57 +02:00
else :
2024-05-17 10:48:07 +02:00
"""
If the ESS does not have enough stored energy to power the factory , the energy will be taken from the grid .
"""
2024-05-06 19:24:11 +02:00
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
2024-05-07 10:27:45 +02:00
self . unmet . append ( ( index , time , factory_demand , generated_pv_power ) )
2024-05-06 19:24:11 +02:00
saved_energy = generated_pv_energy + self . ess . storage * self . ess . loss
2024-05-03 14:07:57 +02:00
self . ess . storage = 0
2024-05-06 19:24:11 +02:00
needed_from_grid = factory_demand * time_interval - saved_energy
net_grid = min ( self . grid . capacity * time_interval , needed_from_grid ) * self . grid . loss
2024-05-15 15:06:43 +02:00
self . grid_need_power_kW . append ( needed_from_grid * 4 )
2024-05-10 23:57:58 +02:00
total_gen + = saved_energy
2024-05-06 19:24:11 +02:00
benefit = ( saved_energy ) * electricity_price
cost = net_grid * electricity_price
2024-05-10 23:57:58 +02:00
total_netto_benefit + = benefit
2024-05-06 19:24:11 +02:00
total_benefit + = benefit - cost
2024-05-17 10:48:07 +02:00
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 )
2024-05-03 14:07:57 +02:00
2024-05-10 23:57:58 +02:00
return ( total_benefit , total_netto_benefit , total_gen )