Improve physical geometry, fluid solvers, audio, and profiling
This commit is contained in:
1 parent
bf8621ad39
commit
eb2b6366c2
130 files changed
+14649
-862
No files matched your search
+167
-6
@@ -10,13 +10,16 @@ Start by copying a similar engine, such as `single-450.toml`, `five.toml`,
|
||||
calibration values, including the previous carb and idle tunes.
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "my-single"
|
||||
name = "My four-stroke single"
|
||||
category = "Singles / four-stroke"
|
||||
description = "My calibration"
|
||||
order = 100
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
```
|
||||
|
||||
`id`, `name`, `category`, `cycle` and `schema_version` are required. IDs use
|
||||
@@ -25,6 +28,74 @@ ID. Duplicate IDs, unknown keys, unsupported versions, incorrect types and
|
||||
invalid physical values stop loading with a diagnostic identifying the file
|
||||
and field. TOML syntax errors also report their location.
|
||||
|
||||
Version 2 requires explicit physical geometry. Version 1 remains readable and
|
||||
receives a generated layout for compatibility. All bundled scenarios use version 2.
|
||||
|
||||
## Physical geometry
|
||||
|
||||
Pipe centerlines and storage boxes are shared by simulation, rendering, mouth
|
||||
positions, and junction directions. Coordinates use millimetres, with Y up.
|
||||
Pipe indices follow the expanded pipe-group ordering below.
|
||||
|
||||
```toml
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [[-200.0, 300.0, 0.0], [-100.0, 300.0, 0.0], [-100.0, 200.0, 0.0]]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
size_mm = [200.0, 100.0, 50.0]
|
||||
center_mm = [0.0, 200.0, 0.0]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [0.0, 0.0, 0.0] # crank axis origin
|
||||
tilt_deg = 0.0 # rotation about X
|
||||
```
|
||||
|
||||
That pipe is 200 mm long: its length is the sum of the two straight segments.
|
||||
There is no independent pipe-length field in version 2 definitions. Mesh cells
|
||||
are distributed along the measured centerline; hard corners remain hard corners
|
||||
in both views. The 3D tube uses bounded miter joins rather than a spline.
|
||||
Paths require 2..64 finite points without consecutive duplicates.
|
||||
|
||||
The box above is 1 litre. Storage volumes support either `size_mm` with optional
|
||||
`center_mm` (the center defaults to the origin), or two opposite corners:
|
||||
|
||||
```toml
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
corners_mm = [[-100.0, 150.0, -25.0], [100.0, 250.0, 25.0]]
|
||||
```
|
||||
|
||||
Use one form per box. Corner order can be reversed. Zero or negative sizes,
|
||||
duplicate IDs, missing required volumes, or mismatched pipe/cylinder counts
|
||||
are rejected. Four-stroke storage IDs are `intake_plenum`, `exhaust_collector`
|
||||
for a volume collector, and `junction_0`, `junction_1`, etc. in topology order.
|
||||
Two-strokes use `intake_plenum` and `crankcase`; the latter defines crankcase
|
||||
clearance volume, and the renderer adds the live piston displacement to its box.
|
||||
Only active fluid storage components are drawn as pressure-colored boxes.
|
||||
|
||||
Cylinder gas volume comes from bore, stroke, rod length, compression, and piston
|
||||
position; cylinder placement supplies the crank origin and bank tilt. The 3D
|
||||
cutaway uses these dimensions for sleeves, pistons, rods, heads, and valves.
|
||||
All 32 bundled layouts have explicit cylinder placements and routed plumbing.
|
||||
The four-stroke headers use direct swept bends and realistic collector placement,
|
||||
with new lengths measured from their geometry rather than folded detours to
|
||||
retain the old numerical lengths. This intentionally changes exhaust tuning.
|
||||
See [header length changes](../verification/geometry-header-lengths.csv).
|
||||
Intake, tailpipe, crossover and two-stroke profile lengths retain their existing
|
||||
dimensions. Smooth manufactured bends are explicitly sampled centerlines;
|
||||
authored hard corners still use miter joins.
|
||||
|
||||
Profiled two-stroke exhaust and silencers retain their sectional dimensions.
|
||||
Their axial section proportions are mapped onto the measured centerline, so
|
||||
changing the overall route scales section lengths while preserving diameters.
|
||||
Silencer `diameter_mm` and `length_mm` define its cylindrical casing size;
|
||||
straight-through gas uses the separate core diameter. Rendering shows the gas
|
||||
profile and a cutaway casing. Bends do not add a new distributed bend-loss model.
|
||||
The existing named engine topologies still define connections; arbitrary graph
|
||||
editing is a future layer over this shared geometry.
|
||||
|
||||
## File discovery and distribution
|
||||
|
||||
The first available directory is used:
|
||||
@@ -59,8 +130,11 @@ Four-stroke definitions use these sections:
|
||||
|
||||
| Section | Contents |
|
||||
| --- | --- |
|
||||
| `[engine]` | Cylinder count, layout, bank angle, phases, intake volumes, throttle, startup, load, and exhaust topology |
|
||||
| `[cylinder]` | Bore/stroke/rod, compression, valve geometry and timing, combustion and heat transfer |
|
||||
| `[engine]` | Cylinder count, layout, bank angle, phases, throttle, startup, load, and exhaust topology |
|
||||
| `[cylinder]` | Bore/stroke/rod, compression, valve diameters/counts, combustion and heat transfer |
|
||||
| `[cam.intake]`, `[cam.exhaust]` | Cam lift curves as `[angle_deg, lift_mm]` points over a 720 degree cycle |
|
||||
| `[valves.intake]`, `[valves.exhaust]` | Valve mass, spring, damping, seat preload, travel and contact restitution |
|
||||
| `[valve_sound]` | Contact resonance and radiating area for four-stroke valve impacts |
|
||||
| `[crankshaft]` | Inertia and mechanical friction |
|
||||
| `[ecu]` | Idle, actuator response, ignition curve, limiter and overrun thresholds |
|
||||
| `[vehicle]` | Vehicle mass, gears, clutch, wheel geometry and road resistance |
|
||||
@@ -68,12 +142,22 @@ Four-stroke definitions use these sections:
|
||||
| `[junctions]` | Fitting volume and H crossover selection |
|
||||
| `[silencers]` | Connecting pipes, resonator and muffler profiles, when used |
|
||||
| `[[pipes]]` | Ordered pipe groups for the selected exhaust topology |
|
||||
| `[[geometry.pipes]]`, `[[geometry.volumes]]`, `[[geometry.cylinders]]` | Physical routes, storage sizes and component placements |
|
||||
|
||||
`engine.phase_degrees` contains one phase per cylinder in cylinder index order,
|
||||
within `[0,720)`. It records the actual crank offsets rather than a firing-order
|
||||
label. `ecu.ignition_map` is an array of `[RPM, degrees BTDC]` pairs with strictly
|
||||
increasing RPM. Negative advance means ignition after TDC.
|
||||
|
||||
Four-stroke valve lift is driven by the cam profile and a one dimensional
|
||||
mass-spring model. Cam points must cover 0 through 720 degrees, have strictly
|
||||
increasing angles, and start and end at zero lift. A valve can separate from
|
||||
the cam at high RPM, producing valve float; seat, cam and travel-stop impacts
|
||||
excite a damped contact mode spatialized from the engine through the existing
|
||||
stereo, ear-distance and travel-delay paths. These profiles and dynamics apply
|
||||
only to four-stroke cylinders. Valve masses are per valve; the model scales
|
||||
effective mass, spring force and contact impulse by the configured valve count.
|
||||
|
||||
For a carbureted four-stroke, use `ecu.idle_control = "fixed"` and set
|
||||
`ecu.idle_base_opening`. Its limiter and overrun control cut ignition while the
|
||||
carburetor continues supplying fuel. Jet diameters in `[fuel]` are effective
|
||||
@@ -90,6 +174,34 @@ Required cylinder geometry must be explicit. Optional calibration fields use
|
||||
the typed config defaults; a misspelled field is always an error. Existing files
|
||||
include explicit values so their behavior does not depend on future defaults.
|
||||
|
||||
## Scenario mesh resolution
|
||||
|
||||
Every bundled scenario defines a shared pipe density, for example:
|
||||
|
||||
```toml
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
```
|
||||
|
||||
This applies to all intake, runner, header, tailpipe, silencer and two-stroke
|
||||
profile sections. Uniform pipes use `max(1, ceil(length_m * cells_per_meter))`;
|
||||
profiled pipes subdivide each geometry section at that maximum cell length.
|
||||
Geometry and integrated pipe volumes are preserved. Tiny floating-point rounding
|
||||
at exact integer counts is ignored. Legacy per-pipe `cells` and exhaust cell
|
||||
length fields remain readable for older definitions without a global density;
|
||||
when density is present it controls the mesh.
|
||||
|
||||
Valid density is 1..500 cells/m, with existing per-pipe and network cell caps
|
||||
also enforced. Higher resolution reduces numerical diffusion and costs more CPU.
|
||||
In the desktop sidebar, **Cells/m - / +** changes density in steps of five.
|
||||
The mesh builds in the background and the engine restarts at its configured RPM;
|
||||
solver, scene, listener and driving-control inputs are retained. Each scenario's
|
||||
selection is remembered for the current app session. These controls do not write
|
||||
TOML; edit `cells_per_meter` in the scenario file for a permanent default.
|
||||
|
||||
The desktop cam/valve, fuel and geometry editor has been removed. Engine
|
||||
calibration remains available through TOML. Escape returns directly to the menu.
|
||||
|
||||
## Pipe groups and exhaust topologies
|
||||
|
||||
These definitions configure the existing topology builders. They do not yet
|
||||
@@ -101,10 +213,11 @@ unique; `count` repeats its dimensions across adjacent pipes.
|
||||
id = "primaries"
|
||||
count = 8
|
||||
diameter_mm = 38.0
|
||||
length_mm = 750.0
|
||||
cells = 15
|
||||
```
|
||||
|
||||
Each expanded pipe gets its own `geometry.pipes` centerline. A group's diameter
|
||||
remains the cross-section geometry; its length is derived from that centerline.
|
||||
|
||||
The order is significant because the topology builder connects the expanded
|
||||
groups to fixed cylinder and junction ports:
|
||||
|
||||
@@ -123,4 +236,52 @@ A collector outlet can instead use `profile = "silenced"`. Its dimensions and
|
||||
mesh then come from `[silencers]`, `[silencers.resonator]` and
|
||||
`[silencers.muffler]`; omit the group's uniform pipe dimensions. The loader
|
||||
checks expanded pipe counts and mesh limits before construction. Pipe positions
|
||||
continue to use the shared scene routes for rendering and sound sources.
|
||||
and sound-source locations come from the explicit centerlines.
|
||||
|
||||
## Characteristic exhaust junctions
|
||||
|
||||
Existing files default to the finite-volume model. To opt into nonlinear,
|
||||
zero-storage exhaust junctions, add:
|
||||
|
||||
```toml
|
||||
[junctions]
|
||||
model = "characteristic" # "volume" (default), "characteristic", or "legacy"
|
||||
turning_loss = 0.5 # dimensionless, 0..10; 0 gives ideal angle-independent coupling
|
||||
```
|
||||
|
||||
This applies to exhaust header fittings, staged collectors, and H-pipe nodes.
|
||||
For `collector` topology it replaces the exhaust collector storage volume with
|
||||
a zero-storage node, including the two-port single-cylinder transition. That
|
||||
changes the physical model and removes collector compliance. Intake plenums,
|
||||
cylinders, silencers, and intentional pipe volumes remain unchanged. The
|
||||
storage dimensions come from the corresponding geometry boxes in version 2.
|
||||
`junction_volume_cc` is retained only for legacy version 1 layout generation.
|
||||
|
||||
Branch directions point **outward from the node into the pipe**. By default they
|
||||
come from the first/last segment of the physical pipe centerline. Optional
|
||||
direction overrides remain available for measured fitting axes. For example:
|
||||
|
||||
```toml
|
||||
[[junctions.branches]]
|
||||
pipe = 2
|
||||
left = false
|
||||
direction = [-1.0, 0.0, 0.0]
|
||||
|
||||
[[junctions.branches]]
|
||||
pipe = 3
|
||||
left = true
|
||||
direction = [1.0, 0.0, 0.0]
|
||||
```
|
||||
|
||||
Directions are normalized, must be finite and nonzero, and must identify active
|
||||
node endpoints in characteristic/legacy mode. Pipe indices follow expanded
|
||||
scenario ordering, not TOML pipe-group indices. `left` is the endpoint at pipe
|
||||
coordinate zero; it does not prescribe flow direction. Reversal is automatic.
|
||||
Opposing outward axes describe straight-through flow; perpendicular axes describe
|
||||
a 90-degree turn. A common world rotation leaves the solution unchanged.
|
||||
|
||||
For listening without editing TOML, desktop and capture accept
|
||||
`--junctions characteristic --junction-loss 0.5`; use `--junctions volume` for
|
||||
the original fittings. Restart the scenario between models. These switches
|
||||
apply to four-stroke scenarios; two-stroke exhaust is currently a profiled pipe.
|
||||
See [junction solver details and validation](JUNCTION_SOLVER.md).
|
||||
Reference in new issue
Block a user