283 lines
15 KiB
Markdown
283 lines
15 KiB
Markdown
# FluidSimCpp
|
|
|
|
FluidSimCpp aims to reproduce sound from a physically accurate simulation of
|
|
compressible flow in pipes and connected volumes, sampled at 44,100 Hz. Each
|
|
audio sample advances physical time by 1/44100 second; adaptive internal
|
|
substeps resolve the fluid dynamics. Every subsystem must ultimately follow
|
|
physical laws with explicit units, assumptions and validation. Matching the
|
|
C# reference is a regression aid, not proof of physical accuracy.
|
|
|
|
This is a work in progress. Physical correctness is the acceptance goal, not
|
|
a claim about all current models. Validation must include conservation of
|
|
mass, momentum and energy, analytic acoustic modes, boundary reflection and
|
|
radiation, thermodynamics and convergence under time/space refinement.
|
|
|
|
## Build (Windows / Visual Studio)
|
|
|
|
Open a Visual Studio Developer PowerShell (or initialize the MSVC environment
|
|
with `VsDevCmd.bat`), then run from this directory:
|
|
|
|
```powershell
|
|
cmake -S . -B build -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release
|
|
cmake --build build
|
|
ctest --test-dir build --output-on-failure
|
|
```
|
|
|
|
## Build (Linux / Windows presets)
|
|
|
|
The repository includes CMake presets and VS Code tasks for the desktop app.
|
|
Install CMake 3.28 or newer, a C++20 compiler, and Make on Linux. On Windows,
|
|
install Visual Studio 2022 with the C++ desktop workload and CMake. Configure
|
|
and build from the project root with:
|
|
|
|
```sh
|
|
cmake --preset linux
|
|
cmake --build --preset linux --target fluidsim_desktop
|
|
```
|
|
|
|
On Windows, use the `windows` preset in place of `linux`. CMake fetches SFML
|
|
3.0.2 if it is not installed, so the first desktop configure needs network
|
|
access. In VS Code, choose **FluidSim desktop** in Run and Debug; the
|
|
same configuration selects the Windows executable on Windows. The `.vscode`
|
|
build task configures and builds the desktop target before launching it.
|
|
|
|
The UI uses the optional Fira Code Nerd Font file from `../fonts` when present.
|
|
Without it, the simulation still runs but text labels are hidden. To bundle a
|
|
font from another location, configure with `-DFLUIDSIM_FONT_FILE=/path/to/font.ttf`.
|
|
|
|
The first configure fetches SFML 3.0.2 with CMake FetchContent for the desktop
|
|
window and audio stream. `-DFLUIDSIM_BUILD_DESKTOP=OFF` builds only the headless
|
|
runner and physics tests.
|
|
|
|
Run the interactive simulator with:
|
|
|
|
```powershell
|
|
.\build\fluidsim_desktop.exe
|
|
```
|
|
|
|
Controls: hold `W` for throttle, `C` for clutch, `A` / `D` to shift, `Z` for
|
|
neutral, up/down to adjust throttle target, left/right to adjust engine load,
|
|
`M` toggles mechanical engine noise, mouse wheel changes simulation playback
|
|
speed, and Space toggles real time.
|
|
|
|
The command-line runner is useful for repeatable checks:
|
|
|
|
```powershell
|
|
.\build\fluidsim_cpp.exe --seconds 1 --throttle 0.35
|
|
.\build\fluidsim_cpp.exe --scenario two-stroke --seconds 1 --throttle 0.3
|
|
.\build\fluidsim_cpp.exe --scenario helmholtz --seconds 1
|
|
.\build\fluidsim_cpp.exe --scenario pulse --seconds 1
|
|
```
|
|
|
|
To compare deterministic checkpoints from the active C# twin scenario against
|
|
the C++ port (energy variation is disabled for repeatability), build the C++
|
|
trace runner and execute the PowerShell comparison script:
|
|
|
|
```powershell
|
|
cmake --build build-msvc --target fluidsim_parity_trace
|
|
.\verification\Compare-ScenarioTrace.ps1
|
|
```
|
|
|
|
## Audio fidelity and playback
|
|
|
|
Desktop playback starts at real time: one solver output frame per 44.1 kHz
|
|
stereo device frame. A simulation worker fills a bounded 8192-frame queue in
|
|
512-frame batches with a 4096-frame startup reserve (about 93 ms). The device
|
|
callback only reads samples, removes DC, converts to PCM and handles underruns;
|
|
it performs no simulation, allocation or waiting. An underrun fades out and
|
|
recovery crossfades over 64 samples rather than stepping abruptly to silence.
|
|
The callback never advances physical time to conceal missing samples.
|
|
|
|
The source is a linear compact-monopole approximation,
|
|
`p(r,t) = (d mass_flow/dt)/(4*pi*r)`. 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;
|
|
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.
|
|
|
|
The default environment is a nearby wall. Press **R** to cycle dry, field,
|
|
wall and woodland. Ground/wall image paths provide early reflections; the
|
|
woodland scatterers and decaying feedback-delay tail are approximate effects,
|
|
not validated outdoor acoustics. Synthetic mechanical noise remains optional.
|
|
The compact source does not implement pipe-end radiation impedance, validated
|
|
directivity, or exhaust afterfire chemistry. Filtering cannot recover aliased
|
|
source information. See [audio verification](verification/AUDIO_RENDERING.md)
|
|
for tests, capture commands, limitations and measured transient reductions.
|
|
|
|
Launching `fluidsim_desktop` without `--scenario` opens a small scenario menu.
|
|
Click the twin, YZ125 or Saab B205 card to start, or select with Up/Down and press Enter.
|
|
Escape closes the menu. Simulation and audio start after selection. Passing
|
|
`--scenario twin`, `--scenario two-stroke` or `--scenario b205` bypasses the menu; `--scene` and
|
|
`--exhaust` options also apply when choosing through the menu.
|
|
|
|
To test the two desktop engines from the repository root:
|
|
|
|
```sh
|
|
cmake --build build-desktop --target fluidsim_desktop -j 4
|
|
./build-desktop/fluidsim_desktop --scenario two-stroke --scene wall
|
|
# Or:
|
|
./build-desktop/fluidsim_desktop --scenario twin --scene field
|
|
```
|
|
|
|
Hold **W** for throttle, use **Up/Down** to adjust the persistent pedal request,
|
|
**Space** to restore real-time playback and **R** to change environment. The two-stroke desktop uses
|
|
the existing 125 cc configuration; its dimensions and calibrations must be
|
|
adapted before it represents a particular engine. Both scenarios use the same
|
|
motorcycle test model, dashboard and rolling peak dyno graph (kW and Nm versus
|
|
RPM). Start in neutral, hold **C** to disengage the clutch, press **D** for first
|
|
gear, apply throttle and release **C** to pull away. **D/A** shift up/down;
|
|
**Z** selects neutral. Left/right adjust an external engine load, not a wheel
|
|
brake. The graph records simulated crank power/torque, not measured wheel power.
|
|
|
|
The two-stroke now uses a YZ125 baseline: published 2022 primary, gearbox and
|
|
final reductions, 54 x 54.5 mm geometry, and an estimated racing expansion
|
|
chamber. Ports use piston-uncovered window areas. The pipe display follows
|
|
physical cell diameter and length. Compare exhausts with `--exhaust racing`
|
|
(default) or `--exhaust straight`; the desktop, CLI and WAV capture tool accept
|
|
this option. See [YZ125 verification](verification/YZ125_BASELINE.md) for the
|
|
geometry, assumptions, speed sweep and remaining unloaded-RPM limitation.
|
|
|
|
## Twin with a VZ21-size turbo
|
|
|
|
Choose **600 cc twin + VZ21-size turbo** in the startup menu, or bypass it:
|
|
|
|
```sh
|
|
./build-desktop/fluidsim_desktop --scenario twin --turbo vz21 --scene field
|
|
./build-audit/fluidsim_cpp --scenario twin --turbo vz21 --seconds 5 --throttle 0.7
|
|
```
|
|
|
|
`Turbocharger` connects to four existing pipe ends and couples turbine and
|
|
compressor work through a rigid rotor. Small housing volumes preserve unsteady
|
|
exhaust pressure. Backpressure, charge temperature and spool speed emerge from
|
|
flow restrictions and energy exchange. A pressure-can/spring wastegate opens a
|
|
bypass; no boost pressure is imposed. HUD pressures are absolute. The default
|
|
unboosted twin is unchanged unless `--turbo vz21` is selected.
|
|
|
|
This is an estimated VZ21-size model, not a measured turbo map. Engine exhaust
|
|
pulses are implemented; blade-passing whistle/wakes are still pending. The
|
|
seven-second twin transient and all nine CTest suites passed. Sustained high-load
|
|
performance is close to, or slower than, real time in the current benchmark;
|
|
watch the underrun counter during testing. See
|
|
[turbo verification](verification/TURBO_VZ21.md) for assumptions and results.
|
|
|
|
## Saab B205 / 9-5 wagon baseline
|
|
|
|
Select **Saab B205 / 9-5 wagon** from the desktop menu, or launch directly:
|
|
|
|
```sh
|
|
./build-desktop/fluidsim_desktop --scenario b205 --scene field
|
|
./build-audit/fluidsim_cpp --scenario b205 --seconds 4 --throttle 0.5
|
|
```
|
|
|
|
The shared four-stroke scenario now supports two or four cylinders. The B205
|
|
uses 90 x 78 mm geometry, 8.8:1 compression, two intake/two exhaust valves per
|
|
cylinder and 1-3-4-2 firing order. Four intake runners and four exhaust headers
|
|
connect shared plenums and a tailpipe. The vehicle approximates a 9-5 wagon:
|
|
1675 kg with driver, five-speed manual, FM55 B05 overall ratios
|
|
13.70 / 7.12 / 4.77 / 3.62 / 2.67, and 4.05 final drive. No sixth gear is offered.
|
|
Controls and dyno match the other scenarios. There is no turbo system yet;
|
|
this is an atmospheric-breathing B205 geometry baseline. Pipe/cam dimensions,
|
|
friction, idle/ignition maps, clutch, drag and loaded tire radius are estimates.
|
|
It does not reproduce factory turbo power or turbo/exhaust acoustics.
|
|
See [B205 verification](verification/B205_BASELINE.md) for sources and checks.
|
|
|
|
## Current port status
|
|
|
|
The C++ core now includes the shared `EngineCylinder` model with four-stroke and
|
|
two-stroke cycle implementations, crankshaft, crankcase, atmosphere and
|
|
configurable 0-D volume components (including thermal relaxation and moving
|
|
volume work), profiled compressible 1-D pipes and boundaries, adaptive solver
|
|
stepping, the impulse-clutch motorcycle/road-load model, and the active 600 cc
|
|
twin topology. Audio includes the flow-derivative source, spatialized
|
|
intake/exhaust radiation, outdoor feedback-delay reverb, optional mechanical
|
|
noise, a lock-free simulation audio buffer, a `SoundEngine` lifecycle wrapper,
|
|
and an SFML desktop frontend. The shared 50-RPM-bin dyno history and graph are
|
|
also ported. A crankcase-scavenged 125 cc two-stroke scenario is available in
|
|
the core and desktop, with an ECU, finite-response throttle and dynamic reed.
|
|
|
|
This is still an in-progress port, not a claimed complete replacement. All four
|
|
current C# scenarios (600 cc twin, 125 cc two-stroke, Helmholtz resonator, and
|
|
pressure pulse) have headless C++ counterparts and can be selected by the CLI.
|
|
Remaining parity work includes completing the C# drawing/diagnostic controls in
|
|
the desktop UI and resolving numerical differences reported by the comparison
|
|
harness. Earlier Windows builds passed CTest, but the current audio and two-stroke
|
|
changes still need Windows runtime verification. The Linux desktop builds and
|
|
runs; installed-font fallbacks provide labels when no bundled font is present.
|
|
|
|
The one-second twin trace remains substantially outside its 1% tolerance. The
|
|
latest comparison's largest relative difference is 40.6745 for cylinder 1
|
|
pressure at checkpoint 33075 (69.8 kPa in C# versus 2.91 MPa in C++). A dense
|
|
intake trace matches closely at first, then the C# plenum pressure begins
|
|
rising at checkpoint 63 while C++ remains near ambient. This divergence needs
|
|
to be resolved before claiming numerical parity. CTest covers cylinder
|
|
geometry and valve timing, dyno-bin interpolation, configurable 0-D volume
|
|
thermodynamics, crankcase and atmosphere state, profiled-pipe geometry,
|
|
inertive and closed boundaries, gearing and clutch momentum transfer, finite
|
|
runs for every scenario, and finite audio/reverb output.
|
|
|
|
## ECU and throttle control
|
|
|
|
Both desktop engines use `Ecu` (`include/FluidSim/Ecu.hpp`). The desktop and
|
|
CLI throttle values are pedal requests; the actual throttle is advanced every
|
|
simulation sample, independently of rendering. Opening and closing use an
|
|
80 ms first-order actuator response and a maximum travel rate of two full
|
|
travels per second. An ideal butterfly's projected opening determines orifice
|
|
area continuously; shaft obstruction and edge leakage are not modeled.
|
|
|
|
The ECU uses ideal sensors and direct access to trapped fresh-air mass at
|
|
intake-valve closure to calculate each cylinder's fuel dose. This explicitly
|
|
permitted idealization replaces injector flow/duty-cycle and fuel-film models.
|
|
The nominal AFR is 14.7, enriched progressively toward 12.8 above 70% throttle.
|
|
A PI idle controller targets 1800 RPM with filtered RPM feedback, bounded idle
|
|
authority and anti-windup. Overrun fuel cut engages above 3500 RPM on a closed
|
|
pedal and restores fuel below 2400 RPM to catch idle. The twin's rev limiter cuts fuel
|
|
and spark at 10000 RPM, recovering below 9750 RPM. The two-stroke has no rev
|
|
limiter; its idle, overrun and sensor-fault controls remain active. Invalid sensor readings
|
|
inhibit fuel. A simple RPM-based ignition advance map is provided. An already
|
|
burning charge completes combustion when a cut begins.
|
|
|
|
All ECU parameters are accessible calibrations, not measured engine maps.
|
|
There is no starter motor, automatic restart, knock sensor, lambda sensor,
|
|
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 doses fuel after the last scavenging port closes, targets
|
|
3000 RPM idle, and uses idle ignition trim in addition to throttle control. 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.
|
|
Reed material, combustion and controller parameters still require calibration.
|
|
C# trace parity is intentionally changed by these control and physics changes.
|
|
|
|
VS Code's default build task builds the desktop through CMake. Use
|
|
Ctrl+Shift+B to build, or choose **FluidSim desktop** in Run and Debug and
|
|
press F5 to build and run. The single-file C/C++ editor Run shortcut is disabled
|
|
because this project requires multiple sources and SFML; IntelliSense gets
|
|
include paths from CMake Tools. Open the repository root as the VS Code folder.
|
|
|
|
## Fluid physics verification and performance
|
|
|
|
See [the fluid physics audit](verification/FLUID_PHYSICS_AUDIT.md) for corrected
|
|
conservation/boundary equations, analytic tests, measured performance and
|
|
remaining model limits. The validation executable exercises 29 cases covering
|
|
walls, pressure outlets, nozzles, inertance, pipe joints, volumes, species,
|
|
acoustic modes, shocks and invalid states. The default coupled solver updates
|
|
components on every substep, uses area-weighted shared fluxes and matches
|
|
orifice discharge to duct characteristics. These changes intentionally alter
|
|
older C# trace comparisons.
|
|
|
|
Build headless with CMake, then run `ctest --test-dir build-audit
|
|
--output-on-failure`. `fluidsim_physics_benchmark` and
|
|
`fluidsim_thread_benchmark` reproduce the performance experiments.
|
|
`FLUIDSIM_ENABLE_SIMD=OFF` provides a scalar comparison; fast-math is not used.
|
|
Production fluid solving remains serial because threading was slower for the
|
|
current small pipe graph. SIMD and scalar Linux checks are covered; Windows
|
|
execution is still unverified.
|
|
|
|
The twin intake is supplied by an explicit 300 K atmospheric reservoir rather
|
|
than a pressure-only boundary with extrapolated entropy. The repeated-blip
|
|
`fluidsim_intake_regression` checks fresh-air supply and pressure/idle recovery.
|
|
Manifold vacuum at closed throttle remains part of the simulated pumping cycle.
|