from server.devices.producers import CogenerationUnit, PeakLoadBoiler
[docs]class SimulatedCogenerationUnit(CogenerationUnit):
"""The simulation of a cogeneration unit"""
def __init__(self, device_id, env):
super(SimulatedCogenerationUnit, self).__init__(device_id, env)
#: Saves the last powered off time to ensure minimal_off_time
self.off_time = self.env.now
#: Device can have fixed workload without internal control. Be aware of overheating!
self.overwrite_workload = None
"""Efficiency is reached only on maximum workload
at minumum workload the efficiency is decreased by 15 %"""
self.max_efficiency_loss = 0.15
[docs] def step(self):
"""Calculates new workload, produce and consume energy for the last time-step"""
if self.running:
presumable_workload = self.calculate_new_workload()
self.set_workload(presumable_workload)
self.consume_and_produce_energy()
self.power_meter.add_energy(self.get_electrical_energy_production())
self.heat_storage.add_energy(self.get_thermal_energy_production())
else:
self._workload = 0.0
[docs] def calculate_new_workload(self):
"""Selects right operating mode for workload calculation"""
if self.overwrite_workload is not None:
calculated_workload = float(self.overwrite_workload)
elif self.off_time > self.env.now:
calculated_workload = 0.0
elif self.thermal_driven:
calculated_workload = self.get_calculated_workload_thermal()
else:
calculated_workload = self.get_calculated_workload_electric()
return calculated_workload
[docs] def get_electrical_energy_production(self):
"""Returns produced electrical energy in kWh during current time-step"""
return self.current_electrical_production * (self.env.step_size / 3600.0)
[docs] def get_thermal_energy_production(self):
"""Returns produced thermal energy in kWh during current time-step"""
return self.current_thermal_production * (self.env.step_size / 3600.0)
[docs] def get_efficiency_loss_factor(self):
"""Computes efficiency loss on modulation and returns left efficiency in percent [0,1]"""
if self._workload == self.config['minimal_workload']:
return 1.0 - self.max_efficiency_loss
relative_workload = (self._workload - self.config['minimal_workload']) \
/ (1.0 - self.config['minimal_workload'])
return 1.0 - self.max_efficiency_loss * (1.0 - relative_workload)
[docs] def get_calculated_workload_thermal(self):
"""Returns workload for thermal driven mode"""
max_thermal_power = self.config['thermal_efficiency'] * self.config['max_gas_input']
min_thermal_power = max_thermal_power * self.config['minimal_workload'] \
* (1.0 - self.max_efficiency_loss)
demand = self.heat_storage.get_required_energy()
relative_demand = max(demand, min_thermal_power) / max_thermal_power
return min(relative_demand, 1.0)
[docs] def get_calculated_workload_electric(self):
"""Returns workload for electrical driven mode"""
if self.heat_storage.get_temperature() >= self.heat_storage.target_temperature:
return 0.0
max_electric_power = self.config['electrical_efficiency'] * self.config['max_gas_input']
min_electric_power = max_electric_power * self.config['minimal_workload'] \
* (1.0 - self.max_efficiency_loss)
demand = self.power_meter.current_power_consum
relative_demand = max(demand, min_electric_power) / max_electric_power
return min(relative_demand, 1.0)
[docs] def set_workload(self, calculated_workload):
"""Sets given workload, detects power-ons and tracks operating time
:param float calculated_workload: new workload for the next time-step
"""
old_workload = self._workload
# make sure that config['minimal_workload'] <= workload <= 99.0 or workload = 0
if calculated_workload >= self.config['minimal_workload']:
# detect if power has been turned on
if old_workload == 0:
self.power_on_count += 1
self.total_hours_of_operation += self.env.step_size / 3600.0
# check range because of external overwrite_workload
self._workload = max(min(calculated_workload, 1.0), 0.0)
else:
self._workload = 0.0
if self.off_time <= self.env.now:
self.off_time = self.env.now + self.config['minimal_off_time']
[docs] def consume_and_produce_energy(self):
"""Updates currently consumed and produced energy"""
self.current_gas_consumption = self._workload * self.config['max_gas_input']
self.current_electrical_production = self.current_gas_consumption * \
self.config['electrical_efficiency'] * self.get_efficiency_loss_factor()
self.current_thermal_production = self.current_gas_consumption * \
self.config['thermal_efficiency'] * self.get_efficiency_loss_factor()
self.total_gas_consumption += self.current_gas_consumption * \
(self.env.step_size / 3600.0)
self.total_thermal_production += self.current_thermal_production * \
(self.env.step_size / 3600.0)
self.total_electrical_production += self.current_electrical_production * \
(self.env.step_size / 3600.0)
[docs]class SimulatedPeakLoadBoiler(PeakLoadBoiler):
"""The simulation of a peak load boiler"""
def __init__(self, device_id, env):
super(SimulatedPeakLoadBoiler, self).__init__(device_id, env)
#: Saves the last power off time to ensure 3 min off-time
self.off_time = self.env.now
#: Device can have fixed workload without internal control. Be aware of overheating!
self.overwrite_workload = None
[docs] def step(self):
"""Calculates new workload, produce and consume energy for the last time-step"""
if self.running:
self.calculate_workload()
self.consume_and_produce_energy()
self.heat_storage.add_energy(self.get_thermal_energy_production())
else:
self._workload = 0.0
[docs] def calculate_workload(self):
"""Switches on when the heat storage is undersupplied and off if target temperature is reached.
Also detects power-ons and tracks operating time."""
if self.overwrite_workload is not None:
self._workload = float(self.overwrite_workload)
self.total_hours_of_operation += self.env.step_size / 3600.0
else:
# turn on if heat_storage is undersupplied
if self.heat_storage.undersupplied() and self.off_time <= self.env.now:
if self._workload == 0.0:
self.power_on_count += 1
self.total_hours_of_operation += self.env.step_size / 3600.0
self._workload = 1.0
# turn off if heat storage's target energy is reached
elif self.current_thermal_production >= self.heat_storage.get_required_energy():
self._workload = 0.0
if self.off_time <= self.env.now:
self.off_time = self.env.now + 3 * 60.0
[docs] def consume_and_produce_energy(self):
"""Updates currently consumed and produced energy"""
self.current_gas_consumption = self._workload * self.config['max_gas_input']
self.current_thermal_production = self.current_gas_consumption * \
self.config['thermal_efficiency']
self.total_gas_consumption += self.current_gas_consumption * \
(self.env.step_size / 3600.0)
self.total_thermal_production += self.current_thermal_production * \
(self.env.step_size / 3600.0)
[docs] def get_thermal_energy_production(self):
"""Returns produced thermal energy in kWh during current time-step"""
return self.current_thermal_production * (self.env.step_size / 3600.0)