Internal Combustion Engine Combined Heat & Power

Note

An internal combustion Engine consists of an element and a controller. The element defines it’s physical parameters, while the controller governs the operational logic.

The create_controlled function creates both and connects them.

Create Controlled Function

pandaprosumer.create_controlled_ice_chp(prosumer, size, fuel, altitude, name=None, index=None, in_service=True, level=0, order=0, period=0, **kwargs)[source]

Creates an ICE CHP element in prosumer[“ice_chp”] and an ICE CHP controller

INPUT:

prosumer - The prosumer within this ice_chp should be created

size (float) - ICE CHP rating [kW]

fuel (string) - Type of the fuel used in the calculation

altitude (float) - Altitude above sea level of the ICE CHP installation site [m]

OPTIONAL:

name (string, default None) - The name of the ICE CHP instance

index (int, default None) - Force a specified ID if it is available. If None, the index one higher than the highest already existing index is selected.

in_service (boolean, default True) - True for in_service or False for out of service

level (int, default 0) - The level of the controller

order (int, default 0) - The order of the controller

period (int, default 0) - Index of the period, default is 0

OUTPUT:

index (int) - The unique ID of the created ICE CHP

EXAMPLE:

create_controlled_ice_chp(prosumer, 350, “ng”, 0, “example_ice_chp”)

Controller

ice chp logic

Input Static Data

Parameter

Description

Unit

size

Size of the system

fuel

Type of fuel used

N/A

altitude

Altitude in meters

m

in_service

Indicates if the system is in service

N/A

name

Custom name for the instance

N/A

Input Time Series

Parameter

Description

Unit

cycle

Cycle number of the process

N/A

t_intake_k

Intake temperature in Kelvin

K

Output Time Series

Parameter

Description

Unit

load

Load on the system

N/A

p_in_kw

Input power in kilowatts

kW

p_el_out_kw

Electrical output power in kilowatts

kW

p_th_out_kw

Thermal output power in kilowatts

kW

p_rad_out_kw

Radiative output power in kilowatts

kW

ice_chp_efficiency

ICE CHP efficiency

%

mdot_fuel_in_kg_per_s

Mass flow rate of fuel input

kg/s

acc_m_fuel_in_kg

Accumulated fuel input mass

kg

acc_co2_equiv_kg

Accumulated CO2 equivalent emissions

kg

acc_co2_inst_kg

Instantaneous CO2 emissions

kg

acc_nox_mg

Accumulated NOx emissions

mg

acc_time_ice_chp_oper_s

Accumulated operational time of ICE CHP

s

Mapping

The Internal Combustion Engine model uses Generic Mapping Scheme.

Model

class pandaprosumer.controller.models.ice_chp.IceChpController(prosumer, chp_object, order=0, level=0, in_service=True, index=None, **kwargs)[source]
calculate_air_density(temperature_k: float, altitude_m: float, pressure_ref_pa=101325, m_molar_air_kg_per_mol=0.0289652, g_m_per_s2=9.81, gas_const_universal_j_per_molk=8.314) float[source]

Calculates air density according to the ideal gas law.

param temperature_k:

air temperature in K

param altitude_m:

the altitude of the CHP location in m

param pressure_ref_pa:

reference pressure in Pa

param m_molar_air_kg_per_mol:

air molar mass in kg/mol

param g_m_per_s2:

gravitational acceleration in m/s2

param gas_const_universal_j_per_molk:

universal gas constant in J/molK

return density:

air density in kg/m3

calculate_co2_equiv_mass_flow(p_in_kw: float, fuel_type: str, map_fuel: dict) float[source]

Calculates equivalent CO2 emissions.

param p_in_kw:

input energy flow in kW

param fuel_type:

selected fuel type (options: ng, sng1, sng2, sng3, sng4, sng5, sng6)

param map_fuel:

data for the chosen CHP size from the map in the JSON file

return mdot_co2_inst_kg_per_s:

mass flow of CO2 emissions at the location of the ICE CHP in kg/s

calculate_co2_instant_mass_flow(mdot_fuel_kg_per_s: float, fuel_type: str, map_fuel: dict) float[source]

Calculates CO2 emissions at the location of the ICE CHP (instantaneous emissions).

param mdot_fuel_kg_per_s:

fuel mass flow in kg/s

param r_oxidised_c:

fraction of fully oxidised carbon

param fuel_type:

selected fuel type (options: ng, sng1, sng2, sng3, sng4, sng5, sng6)

param map_fuel:

data for the chosen CHP size from the map in the JSON file

return mdot_co2_inst_kg_per_s:

mass flow of CO2 emissions at the location of the ICE CHP in kg/s

calculate_density_ratio(temperature_act_k: float, altitude_act_m: float, map_chp: dict) float[source]

Calculates the ratio between the reference density for which the CHP maps were designed and the actual density of the air at intake.

param temperature_act_k:

actual air temperature at CHP intake in K

param altitude_act_m:

the actual altitude of the CHP location in m

param map_engine:

data for the chosen CHP size

return ratio:

ratio between map reference density and actual density

calculate_efficiency(p_in_kw: float, p_loss_kw: float) float[source]

Calculates the efficiency of the entire ICE CHP.

param p_in_kw:

input energy flow in kW

param p_loss_kw:

lost energy flow in kW

return efficiency:

efficiency of the ICE CHP in %

calculate_electrical_power_out(load: float, map_chp: dict) float[source]

Calculates the generated electrical power.

param load:

CHP load in %

param map_chp:

data for the chosen CHP size from the map in the JSON file

return p_el_out_kw:

output electrical power on the generator in kW

calculate_energy_flow_loss(p_in_kw: float, p_out_kw: float, p_el_kw: float) float[source]

Calculates the amount of energy flow that is lost —> wasted heat.

param p_in_kw:

input energy flow in kW

param p_out_kw:

total recovered energy flow on the output side in kW

param p_el_kw:

generated electrical power in kW

return p_loss_kw:

wasted heat flow from the ICE CHP in kW

calculate_fuel_input_mass_flow(p_in_kw: float, fuel_type: str, map_fuel: dict) float[source]

Determines the required fuel mass flow.

param p_in_kw:

required energy flow into the CHP in kW

param fuel_type:

selected fuel type (options: ng, sng1, sng2, sng3, sng4, sng5, sng6)

param map_fuel:

data for the fuels in the fuels JSON file

return mdot_fuel_in_kg_per_s:

required fuel mass flow in kg/s

calculate_input_energy_flow(load: float, map_chp: dict) float[source]

Determines the input energy flow into the engine.

param load_calc:

CHP load in %

param map_engine:

data for the chosen CHP size

return p_in_kw:

required energy flow for the defined load/output power in kW

calculate_load(cycle: int, demand_kw: float, temperature_k: float, altitude_m: float, map_chp: dict, time) float[source]

Calculates the engine load based on the desired output.

param cycle:

defines output priority (electrical power = 1, heat = 2)

param demand_kw:

current demand value in kW

param temperature_k:

current air temperature at intake in K

param altitude_m:

the altitude of the CHP location in m

param map_chp:

data for the chosen CHP size

param time:

the current step’s simulation time

returns:
  • load - CHP load under reference conditions in %

  • load_actual - CHP load under actual conditions in %

calculate_nox_mass_flow(load: float, map_chp: dict) float[source]

Determines the amount of NOx emissions.

param load:

CHP load in %

param map_chp:

data for the chosen CHP size from the map in the JSON file

return mdot_nox_mg_per_s:

mass flow of NOx emissions at the location of the ICE CHP in mg/s

calculate_radiation(load: float, map_chp: dict) float[source]

Determines the amount of radiation from the ICE CHP unit into the sorounding space.

param load:

CHP load in %

param map_chp:

data for the chosen CHP size from the map in the JSON file

return p_rad_out_kw:

radiation int in kW

calculate_recovered_heat_flow(load: float, map_chp: dict) float[source]

Calculates the recovered energy (heat) flow.

param load:

CHP load in %

param map_chp:

data for the chosen CHP size from the map in the JSON file

return p_th_out_kw:

useful heat flow extracted from the ICE CHP in kW

control_step(prosumer)[source]

Executes the control step for the controller.

Parameters:

prosumer – The prosumer object

is_converged(container)[source]

This method is calculated whether or not the controller converged. This is where any target values are being calculated and compared to the actual measurements. Returns convergence of the controller.

Parameters:

container (_type_) – _description_

q_requested_kw(prosumer)[source]

Calculates the heat to deliver in kW.

Parameters:

prosumer – The prosumer object

Returns:

Heat to deliver in kW

read_json_maps(map_filename: str) dict[source]

Opens a JSON file and reads data from it.

param map_filename:

name of the file with maps to import

return jason_data:

contains all data in the JSON file

select_chp_map(size_kw: int, json_data: dict) dict[source]

Selects a ICE CHP map from CHP JSON data.

param size_kw:

nominal CHP size (output: electrical power) in kW

param json_data:

all data in a JSON file

return chp_map_data:

contains data of the chosen CHP from the JSON file

time_step(prosumer, time)[source]

It is the first call in each time step, thus suited for things like reading profiles or prepare the controller for the next control step.

Note

This method is ONLY being called during time-series simulations!

Parameters:
  • prosumer

  • time

The ICE CHP module is map based. Its engine response is read from tabulated data contained in a map associated with the chosen size of the ICE CHP. Maps for three sizes are provided:

  • 350 kWe,

  • 700 kWe,

  • 1400 kWe.

They are stored in a dedicated JSON file in pandaprosumer/library/chp_maps/ice_chp_maps.json to make modifications to the maps easier if required. If maps are added or removed, their sizes must be added to or removed from the “chp_ice_size_kw” list. All sizes should be in kW. The file should not contain two or more maps of the same size. The minimum information in an ICE CHP map should include the following:

  • temperature_reference_k: the temperature at which values in the map were measured (in K)

  • altitude_reference_m: the altitude at which values in the map were measured (in m)

  • pressure_reference_pa: air intake pressure at which values in the map were measured (in Pa)

  • air_molar_mass_kg_per_mol: average molar mass of intake air at the location of measurement (in kg/mol)

  • gravitational_acc_m_per_s2: gravitational acceleration at the location of measurement (in m/s2)

  • universal_gas_const_j_per_molk: the value of the universal gas constant (in J/molK)

  • load_limits_percent: minimum and maximum limits below and above which the CHP should not operate (in % of maximum load)

  • engine_load_percent: a list of load values at which measurements were taken (in % of maximum load)

  • power_el_kw: a list of values for the power on the electrical generator at each load (in kW)

  • energy_flow_input_kw: required input energy flow for each load value (in kW)

  • heat_flow_radiation_kw: the amount of radiation emitted at each load (in kW)

  • heat_flow_recovered_kw: total recovered heat flow at each load (in kW); provided maps include contributions from the jacket water (cooling) and the exhaust recovered to 150°C

  • exhaust_flow_rate_m3n_per_h: the rate of the exhaust flow (in m3N/h)

  • emiss_rate_nox_mg_per_m3n: an average rate of NOx emissions (in mg/m3N)

Except for temperature_reference_k, if data for the parameters above is not available, a value of zero should be used. For temperature_reference_k a value of 293 is recommended instead of zero. Other information can be included for completeness, but will not be used by the program.

Similarly to the engine, properties of available fuels is stored in a dedicated JSON file in pandaprosumer/library/chp_maps/fuel_maps.json. Data for seven types of gaseous fuels is provided.

Fuel Types and Production Methods

Code

Fuel type

Production method

Ref.

ng

Natural gas

[GFM+21]

sng1

Sythetic natural gas 1

Biogas catalytic methanation with 38% renewable electricity mix

[GFM+21]

sng2

Sythetic natural gas 2

Biogas catalytic methanation with 100% renewable electricity mix

[GFM+21]

sng3

Sythetic natural gas 3

Catalytic methanation from green H2 and CO2 sourced from iron/steel processing

[LSE+24]

sng4

Sythetic natural gas 4

Catalytic methanation from green H2 and CO2 sourced from direct air capture

[LSE+24]

sng5

Sythetic natural gas 5

Catalytic methanation from green H2 and CO2 sourced from ethanol production

[LSE+24]

sng6

Sythetic natural gas 6

Catalytic methanation from green H2 and CO2 sourced from ammonia production

[LSE+24]

Data in the fuel map can also be modified if required. It should include at leat the following:

  • fuel_types: a list of available fuel types

  • lower_heating_value_kwh_per_kg: a list of lower heating value parameters associated with each type of fuel (in kWh/kg)

  • carbon_fraction: the percentage of carbon weight to total molecule weight for each type of fuel

  • co2eq_kg_per_kwh: CO2 equivalent emissions for each fuel type (in kg/kWh)

An instance of the ICE CHP is defined by its size, fuel type, and altitude. A CHP map is selected based on the size.

An example of reading data from an ICE CHP map.

An example of reading data from an ICE CHP map. (source: Faculty of Mechanical Engineering, University of Ljubljana)

The evaporator of the heat pump should get heat from a District Heating Network or from the ambient air.

The condenser should be connected to downstream elements in the prosumer or to a District Heating Network.

Schematic representation of a thermal-based heat pump

Schematic representation of a thermal-based heat pump considered by EIFER during modeling (source: own creation)

To understand the thermal-based heat pump model developed by EIFER, it is first necessary to have an overview of the technologies and parameters involved in the modelling of a heat pump. Figure 4 offers a schematic representation of a thermal-based heat pump considered by EIFER during modelling.

The thermal-based heat pump modelled includes a compressor, a condenser, an expansion valve, and an evaporator. In general terms, a heat pump requires a certain amount of power \(P_\text{comp}\), it transfers a certain amount of heat \(Q_\text{cond}\) to the heat sink, and it absorbs a certain amount of heat \(Q_\text{evap}\) from the heat source.

The thermal-based heat pump model developed by EIFER calculates the required heat pump mass flow on the evaporator (\(\dot{m}_\text{evap}\)) to produce enough heat (Qcond) to meet the requirements of the network in terms of temperature increase (\(T_{\text{out}_\text{cond}} - T_{\text{in}_\text{cond}}\)) with a given mass flow (\(\dot{m}_\text{cond}\)).

To do so, a series of parameters are required as a given input from the model developed:

  • \(T_{\text{out}_\text{cond}}\): target temperature need from the network.

  • \(T_{\text{in}_\text{cond}}\): return temperature from the network to the considered HP.

  • \(\dot{m}_\text{cond}\): mass flow in the network, which for simplicity is considered water.

  • \(T_{\text{in}_\text{evap}}\): temperature of the heat source at the inlet of the evaporator.

  • \(\Delta T_\text{evap}\): it is the temperature difference between the inlet and outlet of the evaporator on the heat source side.

  • \(Pinch\): it is a small temperature difference, usually in between 5-10 K, to account for temperature difference between the heat pump side and the heat source (or heat sink) side.

  • \(\eta_\text{C}\): Carnot efficiency, usually between 0.4-0.6, used to simplify the calculation of the heat pump COP

  • \(T_{\text{out}_{\text{cond}_\text{max}}}\): it is the maximum temperature that can be achieved at the outlet of the condenser on the heat sink side, it is usually given from the HP manufacturer and it depends on the refrigerant chosen.

Then, the calculation steps modelled follow the equations presented below:

  1. The first step is to calculate the condenser thermal demand \(Q_\text{cond}\), meaning the thermal need from the network

\begin{align*} Q_\text{cond} &= \dot{m}_\text{cond} * Cp_\text{cond} * (T_{\text{out}_\text{cond}} - T_{\text{in}_\text{cond}}) \\ \end{align*}

Where \(Cp_\text{cond}\) is the specific heat capacity at constant pressure of the fluid used in the heat network, which is usually water

  1. Then the temperature at the outlet of the evaporator is calculated (\(T_{\text{out}_\text{evap}}\))

\begin{align*} T_{\text{out}_\text{evap}} &= T_{\text{in}_\text{evap}} + \Delta T_\text{evap} \\ \end{align*}
  1. Thanks to step n°2 it is possible to calculate the Carnot COP (\(COP_\text{C}\))

\begin{align*} COP_\text{C} &= \frac{T_{\text{out}_\text{cond}} + T_\text{pinch} + 273.15\text{K}}{T_{\text{out}_\text{cond}} - T_{\text{in}_\text{evap}}} \\ \end{align*}
  1. Which allows a simplified calculation of the heat pump COP (\(COP_\text{HP}\))

\begin{align*} COP_\text{HP} &= \eta_\text{C} * COP_\text{C} \\ \end{align*}
  1. The required electrical power \(P_\text{comp}\) to provide \(Q_\text{cond}\) is also calculated

\begin{align*} P_\text{comp} &= \frac{Q_\text{comp}}{COP_\text{HP}} \\ \end{align*}
  1. From which it is possible to derive the heat required from the heat source \(Q_\text{evap}\)

\begin{align*} Q_\text{evap} &= Q_\text{cond} - P_\text{comp} \\ \end{align*}
  1. And finally the mass flow \(\dot{m}_\text{evap}\) needed at the evaporator for the HP to provide the required \(Q_\text{cond}\) Where \(Cp_\text{evap}\) is the specific heat capacity at constant pressure of the fluid used in the heat sink

\begin{align*} \dot{m}_\text{evap} &= \frac{Q_\text{evap}}{Cp_\text{evap} * \Delta T_\text{evap}} \\ \end{align*}
  1. It is important to check that the temperature at the outlet of the condenser is not above the maximum temperature achievable from the considered HP with the given refrigerant, otherwise that means that the maximum heat that can be provided to the network is lower than the requirement

\begin{align*} \text{if}\ T_{\text{out}_\text{cond}} > T_{\text{out}_{\text{cond}_\text{max}}}\ \text{then}\ Q_\text{cond} &= \dot{m}_\text{cond} * Cp_\text{cond} * (T_{\text{out}_{\text{cond}_\text{max}}} - T_{\text{in}_\text{cond}}) \\ \end{align*} The COP and power consumption are then recalculated based on the new :math:`Q_\text{cond}`.
  1. If the COP is higher than the maximum COP of the HP, the power consumption is set to the maximum power, \(T_{\text{out}_\text{cond}}\) is also recalculated based on the maximum COP.

  2. If the power consumption is higher than the maximum power of the HP, \(\dot{m}_\text{cond}\) is recalculated so that the power consumption is set to the maximum power.

\begin{align*} \text{if}\ P_\text{comp} > P_{\text{comp}_\text{max}}\ \text{then}\ \dot{m}_\text{cond} &= \frac{P_{\text{comp}_\text{max}} * COP_\text{HP}}{Cp_\text{cond} * (T_{\text{out}_\text{cond}} - T_{\text{in}_\text{cond}})} \\ \end{align*}
  1. If the power consumption is lower than the minimum power of the HP, the heat pump is considered off and the power consumption is set to zero,

Note

Limitations of the model:

  • Assume a constant \(\Delta T_\text{evap}\)

  • Assume a constant \(\eta_\text{C}\)