Internal Combustion Engine Combined Heat & Power

Note

An internal combustion engine (ICE) combined heat & power (CHP) element consists of one element and one controller. The element defines its 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 controller.

Input Static Data

Parameter

Description

Unit

name

Unique name or identifier for the ICE CHP element

N/A

size

ICE CHP rating (nominal max. electrical power)

kW

fuel

Fuel type used in the calculation

N/A

altitude

Altitude above sea level of the ICE CHP installation site

m

Input Time Series

Parameter

Description

Unit

cycle

Output preference: electricity or heat

N/A

temp_intake_k

Air intake temperature (e.g. ambient air temperature)

K

Output Time Series

Output

Description

Unit

load

Percentage of the ICE CHP max. output power

N/A

p_in_kw

Total input energy flow (from the fuel)

kW

p_el_out_kw

Electrical power on the generator

kW

p_th_out_kw

Recovered heat flow

kW

p_rad_out_kw

Radiated heat flow

kW

ice_chp_efficiency

ICE CHP’s total efficiency (electrical + thermal)

N/A

mdot_fuel_in_kg_per_s

Required fuel mass flow

kg/s

acc_m_fuel_in_kg

Total mass of fuel consumed

kg

acc_co2_equiv_kg

Total mass of CO2-equivalent emissions

kg

acc_co2_inst_kg

Total mass of CO2 emissions (emissions at ICE CHP location)

kg

acc_nox_mg

Total mass of NOx emissions

mg

acc_time_ice_chp_oper_s

Total time of ICE CHP operation

s

Mapping

The ICE CHP Controller can be mapped using the Generic Mapping Scheme.

  • No inputs are mapped as ICE CHP is an independent energy source

  • The following outputs can be mapped:

    • p_el_out_kw

    • p_th_out_kw

Note

Input file values and the mapping setup:

  • If the mapped output is electrical power (p_el_out_kw), the recommended value of the time-dependant input cycle is 1.

  • If the mapped output is thermal power, i.e. heat (p_th_out_kw), the recommended value of the time-dependant input cycle is 2.

In case the cycle and the mapped output don’t match, the ICE CHP will pair the demand to the mapped output, which may lead to inaccuracies.

Example: For the given heat demand q_demand_kw = 500 kW, the expected output of a (700 kW) ICE CHP is p_th_out_kw = 500 kW. However, if cycle = 1, but the mapped output is p_th_out_kw, the ICE CHP module will give the following output values:

  • p_el_out_kw = 500 kW

  • p_th_out_kw = 495 kW

Because the instruction to the ICE CHP module is that electrical power (p_el_out_kw) is preferred, it will try to match electrical power to the demand and the level of recovered heat will be lower than the demanded energy flow.

Particular care should be taken when the ICE CHP module is connected to more consumers (more than one demand), especially where one consumer demands heat and another demands electrical power.

Model

class pandaprosumer.controller.models.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 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 pandaprosumer2/library/chp_maps/ice_chp_maps.json to make modifications to the maps easier. If required, maps can be added or removed. However, in case of changes, 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)

If data for the parameters above is not available, a value of zero should be used, except for temperature_reference_k for which 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, information about available fuels is stored in a dedicated JSON file in pandaprosumer2/library/chp_maps/fuel_maps.json. Data for seven types of gaseous fuels is provided.

Fuel Types and Production Methods

Input key

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 least 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 chosen size. If the size is not in the chp_ice_size_kw list, the program will choose one size larger to guarantee that the chosen maximum power can be obtained. In the case where the chosen size is outside of the available range, the program will print a warning to the console and will shut down before starting calculations.

An example of reading map data.

An example of how the ICE CHP module reads the value of recovered heat flow from its map, which takes the (thermal) power requirement as basis for determining the load at each time step. (source: University of Ljubljana, Faculty of Mechanical Engineering)

At each time step the algorithm follows the procedure described below:

  1. Based on the current demand, the reference CHP load \(L_\text{ref}\) is determined from the map:

  • A check is performed to determine the preferred output - (1) electricity or (2) heat

  • For electricity, the demand is compared against values in power_el_kw, while for heat is compared against heat_flow_recovered_kw

  • If the demand exceeds the maximum values, the load is set to 100%

  • If the demand is not equal to any of the values in engine_load_percent, the algorithm performs a piece-wise linear interpolation

  1. The actual load \(L_\text{act}\), i.e. the load perceived by the engine, is calulated next:

\begin{align*} L_\text{act} &= L_\text{ref} \, r_\text{air} \\ \end{align*}
  • A ratio \(r_\text{air}\) betwen the reference and actual intak air density is calculated to take into account the effects of different ambient temperatures and altitudes. The perfect gas law is used to calculate air densities since air is assumed to be dry and homogeneously mixed.

  • For consistency, if \(r_\text{air} > 1\), then \(r_\text{air} = 1\)

  1. Obtained load limits are compared against the values in load_limits_percent:

  • If \(L_\text{act}\) is below the lower limit, the ICE CHP is considered to be switched off and \(L_\text{act} = 0\)

  • If \(L_\text{act}\) is bigger than the upper limit, \(L_\text{act}\) is set to the upper limit

  1. Parameter values associated with the calculated load are read or interpolated from the map:

  • Input: required input energy \(P_\text{in}\) (in kW) - from energy_flow_input_kw

  • Output: electrical energy on the generator \(P_\text{el}\) (in kW) - from power_el_kw

  • Output: recovered thermal energy \(P_\text{th}\) (in kW) - from heat_flow_recovered_kw

  • Output: radiated thermal energy \(P_\text{rad}\) (in kW) - from heat_flow_radiation_kw

  1. Fuel consumption is calculated in two ways:

  • Fuel mass flow \(P_\text{el}\) (in kg/s):

\begin{align*} \dot{m}_\text{fuel} &= \frac{P_\text{in}}{LHV} \\ \end{align*}

where \(LHV\) (in kWh/kg) is the lower heating value obtained from the fuel map (lower_heating_value_kwh_per_kg) for the selected type of fuel

  • Total mass of fuel consumed (in kg) from the start of the calculation to the current time step :

\begin{align*} m_\text{fuel} &= \sum\dot{m}_\text{fuel} \, \Delta t \\ \end{align*}

where \(\Delta t\) is the duration of the time step (in s)

  1. Three typical emissions are calculated in the following way:

  • CO2 mass flow (in kg/s) at the location of the ICE CHP:

\begin{align*} \dot{m}_{\text{CO}_2} &= \dot{m}_\text{fuel} \, r_\text{C} \, \left(\frac{M_{\text{CO}_2}}{M_\text{C}}\right) \\ \end{align*}

where \(r_\text{C}\) is the carbon fraction for the chosen fuel obtained from the fuel map (carbon_fraction). \(M_{\text{CO}_2}\) and \(M_\text{C}\) represent molar masses of CO2 and C (in kg/mol), respectively.

  • CO2-equivalent mass flow (in kg/s):

\begin{align*} \dot{m}_{\text{CO}_{2}eq} &= P_\text{in} \, r_\text{eq} \, \left(\frac{1}{3600}\right) \\ \end{align*}

where \(r_\text{eq}\) (kg/kWh) is the rate of CO2-equivalent emissions specified in the fuel map (co2eq_kg_per_kwh).

  • NOx mass flow (in mg/s):

\begin{align*} \dot{m}_{\text{NO}_{x}} &= \dot{V}_\text{exh} \, q_{\text{NO}_x} \, \left(\frac{1}{3600}\right)\\ \end{align*}

where \(\dot{V}_\text{exh}\) is the volumetric flow of exhaust gases (in m3N/h) and \(q_{\text{NO}_x}\) is the rate of NOx emissions (in mg/m3N). Both are properties of the ICE CHP and their values are specified in the CHP map, exhaust_flow_rate_m3n_per_h and emiss_rate_nox_mg_per_m3n, respectively

Note

  • Results for CO2 and CO2-equivalent emissions are given in kg/s

  • Results for NOx emissions are given in mg/s

  1. Information about the ICE CHP efficiency and total time of operation is also provided:

  • The total time is a sum of time steps during which the CHP load is not zero, i.e. it is considered to be operating

  • The total efficiency is calculated with the formula shown below:

\begin{align*} \eta_\text{tot} &= \left(\frac{P_\text{th} + P_\text{el}}{P_\text{in}}\right) * 100 \\ \end{align*}