From 9ab5aea40207d3097b8d8f9220634d79ee691cda Mon Sep 17 00:00:00 2001 From: ChristofBernsteiner <144016397+ChristofBernsteiner@users.noreply.github.com> Date: Tue, 26 Mar 2024 09:45:10 +0100 Subject: [PATCH] Implementation of Standby Modus of fuel cell and electrolyzer --- examples/Cell4LifeSzenario2a.py | 18 +++++- hisim/components/C4L_electrolyzer.py | 26 +++++--- ...er_predicitve_C4L_electrolyzer_fuelcell.py | 61 +++++++++---------- hisim/components/generic_CHP.py | 17 ++++-- 4 files changed, 75 insertions(+), 47 deletions(-) diff --git a/examples/Cell4LifeSzenario2a.py b/examples/Cell4LifeSzenario2a.py index c7ee8ee2d..42986f539 100644 --- a/examples/Cell4LifeSzenario2a.py +++ b/examples/Cell4LifeSzenario2a.py @@ -224,7 +224,7 @@ def Cell4Life( electrolyzer_config = C4L_electrolyzer.C4LElectrolyzerConfig.get_default_config() electrolyzer_config.source_weight = input_variablen["electrolyzer_source_weight"]["value"] electrolyzer_config.p_el = input_variablen["p_el_elektrolyzer"]["value"] - + electrolyzer_config.p_el_percentage_standby_electrolyzer = input_variablen["p_el_percentage_standby_electrolyzer"]["value"] my_electrolyzer = C4L_electrolyzer.C4LElectrolyzer( my_simulation_parameters=my_simulation_parameters, config=electrolyzer_config ) @@ -234,7 +234,7 @@ def Cell4Life( chp_config = generic_CHP.CHPConfig.get_default_config_fuelcell_p_el_based(fuel_cell_power=input_variablen["fuel_cell_power"]["value"]) chp_config.source_weight = input_variablen["init_source_weight_chp"]["value"] chp_config.h_fuel = input_variablen["h_fuel"]["value"] - + chp_config.p_el_percentage_standby_fuelcell = input_variablen["p_el_percentage_standby_fuelcell"]["value"] my_chp = generic_CHP.SimpleCHP( my_simulation_parameters=my_simulation_parameters, config=chp_config, @@ -403,6 +403,8 @@ def InputParameter(): fuel_cell_power = FuelCellPowerW #Electricity Power of Fuel Cell Power in Watt fuel_cell_powerUnit = FuelCellPowerWUnit + p_el_percentage_standby_fuelcell = 10 #If fuel cell is running in standby, it needs so much electricity power in % of its electricitiy production power if it is running + p_el_percentage_standby_fuelcellUnit = "%" del BatteryCapkWh, FuelCellPowerW, BatteryCapkWhUnit, FuelCellPowerWUnit @@ -432,6 +434,9 @@ def InputParameter(): p_el_elektrolyzer = fuel_cell_power*2.1 #Electrical Operating Power in Watt p_el_elektrolyzerUnit = "W" + + p_el_percentage_standby_electrolyzer = 10 #if electrolyzer runs in standby, than it needs "p_el_percentage_standby_electrolyzer" (%) electricity power of the operating power + p_el_percentage_standby_electrolyzerUnit = "%" electrolyzer_source_weight = 999 electrolyzer_source_weightUnit = "-" @@ -713,6 +718,15 @@ def InputParameter(): "unit": Usebale_electrical_amount_of_fuelcell_related_to_fuelcell_output_in_minimum_standby_time_in_percentageUnit, }, + "p_el_percentage_standby_electrolyzer": { + "value": p_el_percentage_standby_electrolyzer, + "unit": p_el_percentage_standby_electrolyzerUnit, + }, + + "p_el_percentage_standby_fuelcell": { + "value": p_el_percentage_standby_fuelcell, + "unit": p_el_percentage_standby_fuelcellUnit, + }, } diff --git a/hisim/components/C4L_electrolyzer.py b/hisim/components/C4L_electrolyzer.py index 1a0cc8f50..900c84697 100644 --- a/hisim/components/C4L_electrolyzer.py +++ b/hisim/components/C4L_electrolyzer.py @@ -56,9 +56,9 @@ class C4LElectrolyzerConfig(cp.ConfigBase): name: str loadtype: loadtypes.LoadTypes unit: loadtypes.Units - p_el: float #Electricity consumption of Electrolyzer in Watt + p_el: float #Electricity consumption of Electrolyzer if electrolyzer is in operating, in Watt output_description: str - + p_el_percentage_standby_electrolyzer: int #if electrolyzer runs in standby, than it needs "p_el_percentage_standby_electrolyzer" (%) electricity power of the electrolyzer operating power @staticmethod def get_default_config() -> "C4LElectrolyzerConfig": @@ -69,6 +69,7 @@ def get_default_config() -> "C4LElectrolyzerConfig": loadtype=loadtypes.LoadTypes.HEATING, unit=loadtypes.Units.WATT, output_description = "Electrolyzer E-Consumption", + p_el_percentage_standby_electrolyzer = 0, ) return config @@ -270,13 +271,20 @@ def i_simulate( else: """Simulates the component.""" - - hydrogen_production = self.config.p_el / (3600*40000) #umrechnung von Watt [=Joule/Sekunde, Leistung) p_el in kg/s H2 - stsv.set_output_value(self.hydrogen_output_channel, self.state.state * hydrogen_production) - stsv.set_output_value(self.output_needed_electricity, self.state.state * self.config.p_el) - self.processed_state = self.state.clone() #Neu - - + #Electrolyzer is running, is turned off, or is in standby: + + if self.state.state == 0 or self.state.state == 1: + #Running or turned off + hydrogen_production = self.config.p_el / (3600*40000) #umrechnung von Watt [=Joule/Sekunde, Leistung) p_el in kg/s H2 + stsv.set_output_value(self.hydrogen_output_channel, self.state.state * hydrogen_production) + stsv.set_output_value(self.output_needed_electricity, self.state.state * self.config.p_el) + self.processed_state = self.state.clone() #Neu + elif self.state.state == 99: #Standby Electrolyzer + #Running in standby, so electrolyzer is NOT producing hydrogen + hydrogen_production = 0 + stsv.set_output_value(self.hydrogen_output_channel, hydrogen_production) + stsv.set_output_value(self.output_needed_electricity, self.config.p_el*self.config.p_el_percentage_standby_electrolyzer/100) + self.processed_state = self.state.clone() #Neu # write values to state diff --git a/hisim/components/controller_predicitve_C4L_electrolyzer_fuelcell.py b/hisim/components/controller_predicitve_C4L_electrolyzer_fuelcell.py index da3f457f4..2fcd92ac9 100644 --- a/hisim/components/controller_predicitve_C4L_electrolyzer_fuelcell.py +++ b/hisim/components/controller_predicitve_C4L_electrolyzer_fuelcell.py @@ -79,7 +79,7 @@ class C4LelectrolyzerfuelcellpredictiveControllerConfig(ConfigBase): def get_default_config_electrolyzerfuelcell() -> "C4LelectrolyzerfuelcellpredictiveControllerConfig": """Returns default configuration for the CHP controller.""" config = C4LelectrolyzerfuelcellpredictiveControllerConfig( - name="Electrolyzer FuelCell Controller", source_weight=1, use=LoadTypes.GAS, h2_soc_upper_threshold_electrolyzer=0,h2_soc_lower_threshold_fuelcell = 0 , on_off_SOEC = 0, off_on_SOEC = 0, p_el_elektrolyzer = 0, fuel_cell_power = 0,minstandbytime_electrolyzer=0, minruntime_electrolyzer = 0,minstandbytime_fuelcell = 0,minruntime_fuelcell = 0,minbatterystateofcharge_electrolyzer_turnon=0, maxbatterystateofcharge_fuelcell_turnon = 0, Electrical_power_surplus_related_to_electrolzyer_percentage = 0, Surplus_electrical_amount_related_to_electrolzyer_in_prediction_horizon_in_percentage = 0, usebale_electrical_amount_of_fuelcell_related_to_fuelcell_output_in_prediction_horizon_in_percentage= 0,minbatterystateofcharge_let_electrolyzer_staysturnedon = 0, maxbatterystateofcharge_let_fuelcell_staysturnedon = 0, Surplus_electrical_amount_related_to_electrolzyer_in_minimum_standby_time_in_percentage = 0, Electrical_power_demand_related_to_fuelcell_percentage = 0, Usebale_electrical_amount_of_fuelcell_related_to_fuelcell_output_in_minimum_standby_time_in_percentage = 0) + name="Electrolyzer FuelCell Controller", source_weight=1, use=LoadTypes.GAS, h2_soc_upper_threshold_electrolyzer=0,h2_soc_lower_threshold_fuelcell = 0 , on_off_SOEC = 0, off_on_SOEC = 0, p_el_elektrolyzer = 0, fuel_cell_power = 0,minstandbytime_electrolyzer=0, minruntime_electrolyzer = 0,minstandbytime_fuelcell = 0,minruntime_fuelcell = 0,minbatterystateofcharge_electrolyzer_turnon=0, maxbatterystateofcharge_fuelcell_turnon = 0, Electrical_power_surplus_related_to_electrolzyer_percentage = 0, Surplus_electrical_amount_related_to_electrolzyer_in_prediction_horizon_in_percentage = 0, Usebale_electrical_amount_of_fuelcell_related_to_fuelcell_output_in_prediction_horizon_in_percentage= 0,minbatterystateofcharge_let_electrolyzer_staysturnedon = 0, maxbatterystateofcharge_let_fuelcell_staysturnedon = 0, Surplus_electrical_amount_related_to_electrolzyer_in_minimum_standby_time_in_percentage = 0, Electrical_power_demand_related_to_fuelcell_percentage = 0, Usebale_electrical_amount_of_fuelcell_related_to_fuelcell_output_in_minimum_standby_time_in_percentage = 0) return config @@ -408,9 +408,9 @@ def turn_off_procedure_electrolyzer(self, timestep, pv_prediction_watt, el_consu if hydrogen_soc > self.config.h2_soc_upper_threshold_electrolyzer: #Is the hydrogen storage tank already filled above the upper limit? '''Hydrogen tank is already filled up!''' - self.state.RunElectrolyzer = 0 #electrolyzer is not running"off" because, there is not enough fuel cell in the tank + self.state.RunElectrolyzer = 99 #electrolyzer is not running"off" because, there is not enough fuel cell in the tank print('Hydrogen tank is already full') - self.state.RunElectrolyzer = 0 + self.state.RunElectrolyzer = 99 self.state.deactivation_timestep_electrolyzer = timestep sys.exit() @@ -422,15 +422,15 @@ def turn_off_procedure_electrolyzer(self, timestep, pv_prediction_watt, el_consu else: - #Elektrolyseur wird abgeschalten + #Elektrolyseur wird in den Standby geschalten ''' - There is NOT enoug useable electricity amount in the prediction horizon, which is min stand by time in this case, - to run the electrolyzer, so turn on if there is not to much hydrogen in the tank + There is NOT enoug useable electricity amount in the prediction horizon/minimum stand by time in this case, + to run the electrolyzer - So turn off Electrolyzer and save deactivation timestep! + So turn Electrolyzer in standby mode and save deactivation timestep! ''' self.state.deactivation_timestep_electrolyzer = timestep - self.state.RunElectrolyzer = 0 + self.state.RunElectrolyzer = 99 else: @@ -529,7 +529,7 @@ def turn_on_procedure_electrolyzer(self, timestep, pv_prediction_watt, el_consum if hydrogen_soc > self.config.h2_soc_upper_threshold_electrolyzer: #Is the hydrogen storage tank already filled above the upper limit? '''Hydrogen tank is already filled up!''' - self.state.RunElectrolyzer = 0 #electrolyzer is not running"off" because, there is not enough fuel cell in the tank + self.state.RunElectrolyzer = 0 #electrolyzer is not running"off" because, there is enough fuel cell in the tank print('Hydrogen tank is already full') self.state.RunElectrolyzer = 0 sys.exit() @@ -546,22 +546,22 @@ def turn_on_procedure_electrolyzer(self, timestep, pv_prediction_watt, el_consum else: #Elektrolyseur läuft weiterhin auf Standby - self.state.RunElectrolyzer = 0 + self.state.RunElectrolyzer = 99 else: #Elektrolyseur läuft weiterhin auf Standby - self.state.RunElectrolyzer = 0 + self.state.RunElectrolyzer = 99 else: #Elektrolyseur läuft weiterhin auf Standby - self.state.RunElectrolyzer = 0 + self.state.RunElectrolyzer = 99 else: #Elektrolyseur läuft weiterhin auf Standby - self.state.RunElectrolyzer = 0 + self.state.RunElectrolyzer = 99 def turn_off_procedure_fuelcell(self, timestep, pv_prediction_watt, el_consumption_pred_onlyhouse_watt, BatteryStateOfCharge, General_PhotovoltaicDelivery, General_ElectricityConsumptiom, hydrogen_soc): ''' Turn off procedure started because Fuel Cell is already running @@ -578,7 +578,7 @@ def turn_off_procedure_fuelcell(self, timestep, pv_prediction_watt, el_consumpti Is the Minimum state of charge of battery already reached to turn off Electrolyzer? ''' - if BatteryStateOfCharge*100 < self.config.maxbatterystateofcharge_let_fuelcell_staysturnedon: + if BatteryStateOfCharge*100 < self.config.maxbatterystateofcharge_let_fuelcell_staysturnedon: # [ ] ''' Fuel Cell stays turned on because battery state of charge threshold to turn off fuel cell is not reached ''' @@ -666,7 +666,7 @@ def turn_off_procedure_fuelcell(self, timestep, pv_prediction_watt, el_consumpti else: - #Fuel Cell wird abgeschalten + #Fuel Cell wird in Standby geschalten ''' There is NOT enough electricity demand amount in the minimum standby time of fuel cell, which means, that the fuel cell will be turned off @@ -674,7 +674,7 @@ def turn_off_procedure_fuelcell(self, timestep, pv_prediction_watt, el_consumpti ''' self.state.deactivation_timestep_fuelcell = timestep - self.state.RunFuelCell = 0 + self.state.RunFuelCell = 99 self.state.mode = 0 #Needs the fuel cell: then the global thermal power is calculated; 0 means that global thermal power fuel cell is NOT calculated, 2 means, that the global thermal power is calculated @@ -769,7 +769,7 @@ def turn_on_procedure_fuelcell(self, timestep, pv_prediction_watt, el_consumptio ratio_inpercentage_useableenergyfromfuelcell = 0 ratio_inpercentage_useableenergyfromfuelcell = total_useable_fuelcell_energy_amount_in_prediction_horizon_wh/total_fuelcell_energy_output_amount_in_prediction_horizon_Wh *100 - if ratio_inpercentage_useableenergyfromfuelcell >= self.config.usebale_electrical_amount_of_fuelcell_related_to_fuelcell_output_in_prediction_horizon_in_percentage: + if ratio_inpercentage_useableenergyfromfuelcell >= self.config.Usebale_electrical_amount_of_fuelcell_related_to_fuelcell_output_in_prediction_horizon_in_percentage: '''There is enough electricity demand amount in the prediction horizon, to run the fuel cell, so turn fuel cell on Start Fuel Cell and save the timestep when Fuel cell is started! @@ -783,26 +783,26 @@ def turn_on_procedure_fuelcell(self, timestep, pv_prediction_watt, el_consumptio else: #Fuel Cell läuft weiterhin auf Standby - self.state.RunFuelCell = 0 + self.state.RunFuelCell = 99 self.state.mode = 0 #Needs the fuel cell: then the global thermal power is calculated; 0 means that global thermal power fuel cell is NOT calculated, 2 means, that the global thermal power is calculated else: #Fuel Cell läuft weiterhin auf Standby - self.state.RunFuelCell = 0 + self.state.RunFuelCell = 99 self.state.mode = 0 #Needs the fuel cell: then the global thermal power is calculated; 0 means that global thermal power fuel cell is NOT calculated, 2 means, that the global thermal power is calculated else: #Fuel Cell läuft weiterhin auf Standby - self.state.RunFuelCell = 0 + self.state.RunFuelCell = 99 self.state.mode = 0 #Needs the fuel cell: then the global thermal power is calculated; 0 means that global thermal power fuel cell is NOT calculated, 2 means, that the global thermal power is calculated else: #Fuel Cell läuft weiterhin auf Standby - self.state.RunFuelCell = 0 + self.state.RunFuelCell = 99 self.state.mode = 0 #Needs the fuel cell: then the global thermal power is calculated; 0 means that global thermal power fuel cell is NOT calculated, 2 means, that the global thermal power is calculated @@ -861,10 +861,9 @@ def i_simulate( #electrolyzer_or_fuelcell_mode = False --> Electrolyzer Season #electrolyzer_or_fuelcell_mode = True --> Fuel Cell Season - prediction_timesteps = [6] if electrolyzer_or_fuelcell_mode == False: #ELECTROLYZER SEASON!!! - self.state.RunFuelCell = 0 + self.state.RunFuelCell = 0 #Fuel Cell is completely turned off if self.state.RunElectrolyzer == 1: @@ -875,7 +874,7 @@ def i_simulate( - elif self.state.RunElectrolyzer == 0: + elif self.state.RunElectrolyzer == 0 or self.state.RunElectrolyzer == 99: ##Turn On Procedure ''' The following turn_off_procedure function manipulates the @@ -893,28 +892,26 @@ def i_simulate( else: #FUEL CELL SEASON!!! - self.state.RunElectrolyzer = 0 #electrolyzer is not running"off" because, it is not the season, where the electrolyzer is allowed to run or there is not enough fuel cell in the tank + self.state.RunElectrolyzer = 0 # Electrolyzer is completely turned off which means, it is NOT running in standby ''' Predictive Controll Fuel Cell: - # [ ] Fuel Cell --> implementation of prediciton is not done until now + # [x] Fuel Cell --> implementation of prediciton is not done until now ''' #Forecast needed if hydrogen_soc > self.config.h2_soc_lower_threshold_fuelcell: if self.state.RunFuelCell == 1: self.turn_off_procedure_electrolyzer(timestep, pv_prediction_watt, el_consumption_pred_onlyhouse_watt, BatteryStateOfCharge, General_PhotovoltaicDelivery, General_ElectricityConsumptiom, hydrogen_soc) - self.state.RunFuelCell = 1 #turn on - self.state.mode = 2 #Needs the fuel cell: then the global thermal power is calculated - stsv.set_output_value(self.chp_heatingmode_signal_channel, self.state.mode) - elif self.state.RunFuellCell == 0: - self.turn_on_procedure_fuelcell(self, timestep, pv_prediction_watt, el_consumption_pred_onlyhouse_watt, BatteryStateOfCharge, General_PhotovoltaicDelivery, General_ElectricityConsumptiom, hydrogen_soc): + + elif self.state.RunFuelCell == 0 or self.state.RunFuelCell == 99: + self.turn_on_procedure_fuelcell(timestep, pv_prediction_watt, el_consumption_pred_onlyhouse_watt, BatteryStateOfCharge, General_PhotovoltaicDelivery, General_ElectricityConsumptiom, hydrogen_soc) else: #There is not enough Hydrogen available in storage - self.state.RunFuelCell = 0 + self.state.RunFuelCell = 0 #Fuel Cell wird abgeschalten! self.state.mode = 0 #Needs the fuel cell: then the global thermal power is calculated diff --git a/hisim/components/generic_CHP.py b/hisim/components/generic_CHP.py index 5ed9e6dfe..c15123877 100644 --- a/hisim/components/generic_CHP.py +++ b/hisim/components/generic_CHP.py @@ -44,7 +44,8 @@ class CHPConfig(cp.ConfigBase): p_fuel: float #: demanded lower or upper heat vaule "Brennwert/Heizwert" of fuel input in kWh / kg h_fuel: float - + #: if fuel cell runs in standby, than it needs "p_el_percentage_standby_fuelcell" (%) electricity power of the fuelcell production power in % + p_el_percentage_standby_fuelcell: int @staticmethod @@ -68,7 +69,7 @@ def get_default_config_fuelcell_p_el_based(fuel_cell_power: float) -> "CHPConfig config = CHPConfig( # name="CHP", source_weight=1, use=lt.LoadTypes.HYDROGEN, p_el = fuel_cell_power, p_th = fuel_cell_power * (0.43 / 0.48), p_fuel=(1 / 0.43) * (fuel_cell_power * (0.43 / 0.48)), - name="CHP", source_weight=1, use=lt.LoadTypes.HYDROGEN, p_el = fuel_cell_power, p_th = fuel_cell_power * 0.5, p_fuel= (fuel_cell_power* (1 / 0.58)), h_fuel = 0.0, + name="CHP", source_weight=1, use=lt.LoadTypes.HYDROGEN, p_el = fuel_cell_power, p_th = fuel_cell_power * 0.5, p_fuel= (fuel_cell_power* (1 / 0.58)), h_fuel = 0.0, p_el_percentage_standby_fuelcell = 0 ) return config @@ -242,8 +243,16 @@ def i_simulate( elif mode == 2: # Gives the global Thermal Power of the Fuel Cell back, if fuel cell is turned on stsv.set_output_value(self.thermal_power_output_channel, self.state.state * self.config.p_th) - stsv.set_output_value(self.electricity_output_channel, self.state.state * self.config.p_el) - stsv.set_output_value(self.fuel_consumption_channel, self.state.state * self.p_fuel) + + #fuel cell is turned off, is running, or is in standby: Decision, in which mode fuel cell is running: + if self.state.state == 99: #Fuel Cell is on standby, fuel cell is NOT heating in standby! + + stsv.set_output_value(self.electricity_output_channel, self.config.p_el*self.config.p_el_percentage_standby_fuelcell/100) + stsv.set_output_value(self.fuel_consumption_channel, 0) + + else: # Fuel Cell is running OR is turned off! if running, fuel cell is ALSO heating + stsv.set_output_value(self.electricity_output_channel, self.state.state * self.config.p_el) + stsv.set_output_value(self.fuel_consumption_channel, self.state.state * self.p_fuel) def get_default_connections_from_chp_controller(self,) -> List[cp.ComponentConnection]: """Sets default connections of the controller in the Fuel Cell / CHP."""