Load engines from TOML and improve scenario audio and carb tuning

Migrate 32 engine definitions into validated startup-loaded TOML files and separate configuration and snapshots from scenario assembly. Add camera-based stereo propagation from shared pipe geometry, preserve exhaust character, tune carburetor mixtures and idle, use ignition cuts for carb engines, and support returning to the scenario menu.

Validation: full Windows build and all 14 CTest checks passed.
This commit is contained in:
max
2026-10-24 03:24:35 +02:00
parent 5607dcf2b5
commit bf8621ad39
82 changed files with 24084 additions and 648 deletions

107
README.md
View File

@@ -123,18 +123,27 @@ The primary source is a linear compact-monopole approximation,
`p(r,t) = rho_ambient * (d volume_flow/dt)/(4*pi*r)`. Mouth volume flow
comes from the boundary face velocity and area. Fluid conservation retains the
actual mass flux; hot/cold density changes are excluded from the acoustic source.
Intake and exhaust have separate static
positions, fractional-sample propagation delays, inverse-distance spreading,
and left/right ear paths. Playback calibration is 200 Pa per device full scale;
Intake and exhaust sources sit at the open ends of the same world routes used
to draw the pipes, including both outlets of dual exhausts. The desktop camera
is the listener: orbit, pan and zoom change its position and ear orientation.
Left and right ears are 18 cm apart, with separate fractional-sample travel
delays at 343 m/s and inverse-distance spreading. Camera updates smooth over
20 ms while retaining propagation history and reflection filter state.
Playback calibration is 200 Pa per device full scale;
this is not calibrated speaker SPL. A second-order 6 kHz monitoring filter
reduces sharp sample-to-sample transients without saturation or synthetic bangs.
A roughly 3.5 Hz device DC blocker and final PCM clipping protection remain.
Use 1x playback for acoustic evaluation.
Use 1x playback for acoustic evaluation. Toggle **G** off to hear the full
distance-related loudness change; automatic gain otherwise compensates for it.
The default environment is a nearby wall. Press **R** to cycle dry, field,
wall, woodland, and tunnel. Ground/wall image paths provide early reflections;
the live eight-line feedback-delay network supplies a scene-dependent late
tail. Woodland scatterers and the hard-surface tunnel images are approximate.
tail. Early reflections follow the listener geometry, with plane reflections
disabled when the listener crosses to the other side. The diffuse tail receives
a delayed centre signal rather than summing the ears, avoiding ear-delay comb
filtering in the reverb input. Woodland scatterers and the hard-surface tunnel
images are approximate.
These are listening profiles, not validated acoustics. Mechanical sounds are
not implemented.
Open pipe mouths now use a causal unflanged radiation boundary with frequency-
@@ -149,7 +158,9 @@ for capture commands, current renderer details and limitations.
Launching `fluidsim_desktop` without `--scenario` opens a small scenario menu.
Choose the twin, YZ125, Saab B205, or American V8 card, or select with Up/Down
and press Enter.
Escape closes the menu. Simulation and audio start after selection. Passing
Escape returns from a running scenario to the menu, stopping its simulation and
audio so another scenario can be selected. Escape closes the menu at the category
screen. Simulation and audio start after selection. Passing
`--scenario twin`, `--scenario two-stroke`, `--scenario b205`, or `--scenario v8`
bypasses the menu; `--scene` and `--exhaust` options also apply
when choosing through the menu.
@@ -353,11 +364,12 @@ catalyst, cold-start temperature model or injector electrical model. Idle
control can still stall under excessive load and does not impose crankshaft
speed or add artificial sustaining torque. Existing combustion/thermal models
remain approximations; ECU changes do not establish their physical accuracy.
The two-stroke uses a fixed mechanical carb slide stop instead of RPM-controlled
idle throttle or idle ignition trim. Each carb scenario config sets
`TwoStrokeConfig::idle_slide_opening` (normalized 0..1); the default is 0.045,
or 4.5% slide travel. Pedal demand above that stop opens the slide further.
The resulting idle RPM depends on the simulation and load. Its
The two-stroke uses a fixed mechanical carb slide stop. With the pedal released,
the ECU trims ignition timing around the configured idle RPM instead of moving
the carb stop. Each carb scenario config sets
`TwoStrokeConfig::idle_slide_opening` (normalized 0..1); the catalog 125 cc
scenarios now use a calibrated 3% stop. Pedal demand above that stop opens the
slide further. The resulting idle RPM depends on the simulation and load. Its
reed is a damped lumped cantilever model with finite opening time and seating
contacts. Cylinder and crankcase moving-volume work use adiabatic energy changes.
Jet dimensions are effective flow calibrations rather than measured Mikuni
@@ -492,7 +504,8 @@ equal 400 mm x 45 mm secondaries, then a 50 mm exhaust. Pairings are 1+2 / 3+4
and 5+7 / 6+8 with this simulation's bank numbering and firing order. Two T
junctions and a 780 mm x 38 mm tube form the H-pipe. Small configurable port-coupled junction volumes are used by the V8. The intake
plenum also remains a storage volume.
`V8ExhaustConfig` configures primary length/diameter and enables the H crossover;
The TOML `primaries` pipe group configures primary length/diameter, while
`[junctions] h_pipe` enables the H crossover;
pass it as the fourth `FourStrokeScenario` constructor argument. The renderer
routes the primary pairs into Y merges, then the final Y collectors and H-pipe,
using local pipe diameter and pressure colors without collector boxes.
@@ -505,16 +518,25 @@ The previous header optimization measurements applied to the earlier finite-volu
The startup browser now scrolls with the mouse wheel, Up/Down, Page Up/Down,
Home and End. It adapts to the window size and shows a scroll indicator. Click
an example or press Enter to start it. The examples are defined in
`ScenarioCatalog.hpp`, grouped into categories with selectable variants. These are configuration comparisons of
`engines/*.toml`, loaded at startup and grouped into categories with selectable variants. These are configuration comparisons of
the existing engine models, not measurements of additional production engines.
The V8 currently uses port-coupled finite-volume fittings, configured by
`V8ExhaustConfig::junction_volume` (default 50 cc per fitting). They use the
`JunctionConfig::junction_volume` (default 50 cc per fitting). They use the
existing conservative component/port exchange and have no volume boxes in the
renderer. The earlier zero-storage Rusanov junction remains available for
comparison through `BoundarySystem::add_junction`, but is not used by the V8.
The 4-2-1 piping and the H crossover geometry remain the same.
### TOML engine definitions
Every engine is defined in its own file under `engines/`. Copy an existing
`.toml` file, change its `id`, name and calibration, then restart to load it.
No rebuild is required when editing definitions in the active directory.
Unknown keys, invalid dimensions, malformed timing and duplicate IDs produce
a file-specific startup error. See [the engine configuration guide](docs/ENGINE_CONFIG.md)
for units, directory discovery, sections and pipe topology ordering.
### Engine families and inspired builds
The browser opens at engine categories; click a category to see variants, then
@@ -531,7 +553,7 @@ estimated calibrations and simplified common-plenum/exhaust networks: they are
not factory replicas, measured torque curves, or turbocharged configurations.
The 8.0 L big-block variant transports carburetor fuel through its intake into
the cylinders. Its fixed idle stop is configured with `EngineConfig::idle_opening`.
the cylinders. Its fixed idle stop is configured with `[ecu] idle_base_opening` in its TOML file.
It reuses the lumped carb model with scaled effective jets; multiple carb barrels,
floats and cylinder-specific fuel distribution are not resolved. Larger engine
geometry requires its own mixture and idle calibration.
@@ -544,5 +566,56 @@ chamber is a geometry experiment, not a guaranteed RPM or power improvement.
Launch a specific variant directly with `--example big-carb`, `--example flat6`,
`--example fifty` or another catalog ID. Carb jet scaling is configurable per
engine (`EngineConfig::carb_jet_scale`, `carb_pilot_scale`, or
`TwoStrokeConfig::jet_scale`).
engine: four-strokes use effective jet diameters in `[fuel]`; two-strokes
use jet multipliers in `[two_stroke]`.
### Pulse-preserving custom exhausts
The custom inline three, F20 four, inline five and inline six examples use
unequal-length primaries, 50 cc junction collectors and secondary pipes rather
than a single large mixing volume. Their pipe damping matches the undamped Saab
path. Inline fours/fives/sixes use physical firing orders so collector grouping
preserves pulse timing; combustion remains even-fire.
The custom big-block V8 uses the American V8's cross-plane 1-5-4-2-6-3-7-8 firing
order and 4-2-1 headers with an H crossover, retaining its own displacement and
carburetor. V10/V12 examples retain separate banks through junction collectors,
secondary pipes and two radiating outlets, including both outlets in the spatial
audio renderer. The existing Saab, American V8, single and twin presets retain
their exhaust paths.
Capture any catalog entry at controlled RPM for comparison:
```powershell
./out/build/windows-gcc/fluidsim_audio_capture.exe --example v12 --rpm 3000 --warmup 0.6 --seconds 2 --throttle 0.55 --scene dry --out out/audio/v12
```
See [custom exhaust verification](verification/CUSTOM_EXHAUST_CHARACTER.md) for
fixed-RPM comparison results.
### Carburetor calibration
All seven two-stroke catalog variants and both carbureted four-strokes have
separate pilot, main-jet and needle-taper calibrations. Progressive pilot metering
fills the 5% throttle transition after lowering the 125 idle stops. The smaller four-stroke
single (`single-450`) now uses a 40 mm carburetor, transported fuel and milder
355/565-degree intake and 145/370-degree exhaust timing. The 650 cc single keeps
EFI. The big-block idle opening is 7%; the straight-pipe 125 uses 3%. The racing
125 and its chamber variants use the calibrated 3% mechanical slide stop.
Needle annulus area is interpolated continuously across slide positions; liquid
fuel still comes from the simulated jet pressure drop and float bowl. There is
no AFR feedback or cylinder-side fuel correction. The displayed carb AFR is the
uncapped ratio of filtered air flow to delivered fuel flow.
`fluidsim_carb_calibration --check` tests every carbureted catalog scenario at
idle, 5%, 10%, 15%, 25%, 50%, 75% and full pedal on an imposed-speed dyno, then
releases the dyno for an idle run. It fails on AFR outside the calibration
bounds, stalling, nonfinite RPM/AFR, pipe positivity repairs, a changed racing
125 stop, or loss of transported carb fuel in the 450 single. Run it through
`ctest --preset windows -R carb_calibration --output-on-failure`.
The tool also prints CSV diagnostics: run without arguments for the four main
operating points, or use `--sweep single-450` for a denser sweep of one scenario.
See [carb calibration results](verification/CARB_CALIBRATION.md) for operating
conditions, AFR values and the distinction between carb and recirculated charge.