#engine #internal #fuel #system #json-file #combustion

bin+lib lmb_engine_simulator

The lmb_engine_simulator library provides an easy way to simulate internal combustion engines

1 unstable release

0.1.0 Jan 20, 2021

#317 in Simulation

MIT/Apache and LGPL-3.0

170KB
3.5K SLoC

Engine-Simulator

Libary developed by the Laboratory of Biofuels Engine (LMB) at University of Campinas (UNICAMP)

Developer: Felipe Augusto Ferreira Gomes, email: f.augustofgomes@gmail.com


lib.rs:

lmb_engine_simulator

The lmb_engine_simulator crate provides an easy way to simulate internal combustion engines.

This library employed the Builder Pattern so the user feels as she/he is acctually building an engine system. To construct (build) the system, the struct SystemBuilder is used to add the desired components. After finishing building, the method build_system() can be used to return an object System which is used to solve the components numerically.

Current stage

The library allows you to build Gas, Zero Dimensional and Connector objects. The basic logic of the program is to use the SystemBuilder to build all the objects and then indicate how the objects are connected with each other. Basicly, all of the dimensional objects require a Gas to be created and a Gas object is created from a .json file. Currently, the only available one is air.json. However, they were made in a way to be easily contructed. Once all dimensional objects and connections were added, the SystemBuilder object can use the method build_system() to create an object of type System, which will carry all the Zero Dimensional and Connector objects. The System object is responsible to manage the interaction between the objects, the simulation process, the storable variables.

In order to simulate, two methods can be used: advance(dt) which advance the state of the objects by dt and advance_to_steady_state() which advances until the system reaches steady state. OBS: So far, steady state conditions are not checked. The method runs long enough that almost every system will have reached steady state by then. For engine simulation, most commonly, it is used advance_to_steady_state(). After the simulation is finished, all stored variables can only be accessed by writing them into a file via system method write_to_file()

Example

A simple system with a Reservoir and Environment connected by an Orifice is created and simulated until steady state. After, the stored data is written into two files.

use lmb::Gas;
use lmb_engine_simulator as lmb;

fn main() {
    let mut gas_ambient = Gas::new("air.json");
    gas_ambient.TPX(293.0, 2.0*101325.0, "O2:0.21, N2:0.79");
    let mut gas_chamber = Gas::new("air.json");
    gas_chamber.TPX(293.0, 101325.0, "O2:0.21, N2:0.79");
    let mut builder = lmb::SystemBuilder::new();
    builder
        .add_environment("ambient", &gas_ambient)
        .add_reservoir("chamber", 500.0, &gas_chamber)
        .add_orifice("orifice", 50.0, 0.9, vec!["ambient", "chamber"]);

    let mut system = builder.build_system();
   
    // Calculating
    system.advance_to_steady_state();
   
    // Writting data
    system.write_to_file("chamber.txt", "chamber", None);
    system.write_to_file("orifice.txt", "orifice", None);
}

Simulating engines

To add an engine to the system, the method add_engine("engine_file.json", "gas") of SystemBuilder must be used. The engine_file.json is read into the struct json_engine. This file must have at least the following attributes:

  • "speed" in RPM,
  • "eccentricity" in mm,
  • "conrod" in mm,
  • "displacement" in cm³,
  • "bore" in mm,
  • "firing_order" as a string - i.e "1-3-2",
  • "cylinders" as a vector of structs json_cylinder

All possible attributes of the engine_file.json file can be found at the full documentation at Json Reader. Attention when entering the variables in crank-angle degree! The reference, where crank-angle is zero, is at top-dead-center (TDC) of compression phase and it only accepts positive numbers. Therefore, the full cycle starts in 0 CA-deg and finishes at 720 CA-deg.

Example

Let's simulate a simple engine system with intake and exhaust manifolds as environments connected to a single cylinder through only two valves (intake and exhaust). The engine.json file will be

{
    "speed": 3000.0,
    "eccentricity": 0.0,
    "conrod": 145.6,
    "displacement": 400.0,
    "bore": 80.0,
    "firing_order": "1",
    "combustion": {
        "model": "Two-zone model",        
        "comb_ini": 690.0,
        "wiebe": {
            "m": 2.0,
            "a": 6.908,
            "comb_duration": 40.0
        }
    },
    "injector": {
        "inj_type": "port",
        "air_fuel_ratio": 1.0,
        "fuel": {
            "name": "C2H5OH",
            "state": "liquid",
            "lhv": 25.858e06,
            "heat_vap": 900.0e3
        }
    },
    "cylinders": [
        {
            "name": "cyl_1",
            "compression_ratio": 12.50,
            "wall_temperature": 520.0,
            "store_species": true,
            "intake_valves": [
                {
                    "name": "valve_int",
                    "opening_angle": 340.0,
                    "closing_angle": 570.0,
                    "diameter": 30.93,
                    "max_lift": 9.30
                }
            ],
            "exhaust_valves": [
                {
                    "name": "valve_exh",
                    "opening_angle": 130.0,
                    "closing_angle": 375.0,
                    "diameter": 28.27,
                    "max_lift": 8.48
                }
            ]
        }
    ]
}

In this example, we added an injector, with relative air fuel ratio equal 1.0 and ethanol (C2H5OH) as fuel, and a combustion model. If they are not added, the engine will run as a motoring. Right now, the only combustion model implemented is the "Two-zone model". Notice that the cylinder requires both intake and exhaust valves connected to it. In the main.rs, we will need to connect these valves to their ports with connect_from_to("valve_name", "object_name") method.

The main.rs can be written as:

use lmb::Gas;
use lmb_engine_simulator as lmb;

fn main() {
    let gas_intake = Gas::new("air.json");
    let mut gas_exhaust = Gas::new("air.json");
    gas_exhaust.TPX(500.0, 101325.0, "N2:0.662586, H2O:0.202449, CO2:0.134965");
    let mut builder = lmb::SystemBuilder::new();
    builder
        .add_engine("engine.json", &gas_intake)
        .add_environment("intake_port", &gas_intake)
        .add_environment("exhaust_port", &gas_exhaust)
        .connect_from_to("valve_int", "intake_port")
        .connect_from_to("valve_exh", "exhaust_port");

    let mut system = builder.build_system();
   
    // Calculating
    system.advance_to_steady_state();
   
    // Writting data
    system.write_to_file("cylinder.txt", "cyl_1", None);
    system.write_to_file("intake_valve.txt", "valve_int", None);
    system.write_to_file("exhaust_valve.txt", "valve_exh", None);
}

For a real-life engine simulation, see Engine Examples

Dependencies

~2.4–3.5MB
~68K SLoC