1 unstable release
0.1.0 | Jan 20, 2021 |
---|
#317 in Simulation
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