2026-10-23 03:00:20 +02:00
2026-10-23 03:00:20 +02:00
2026-10-23 03:00:20 +02:00
2026-10-23 03:00:20 +02:00
2026-10-23 03:00:20 +02:00
2026-10-23 03:00:20 +02:00
2026-10-23 03:00:20 +02:00
2026-10-23 03:00:20 +02:00

FluidSimCpp

Solver performance measurements and reproducible SIMD/threading experiments are documented in the optimization audit. Current scenarios use serial pipe execution because per-substep threading costs more than it saves at their graph sizes. Portable compiler SIMD remains enabled by default.

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:

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:

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:

.\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:

.\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:

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 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:

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 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:

./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. The optimized 7,000-RPM workload takes about 0.65 wall seconds per simulated second on the audit machine; actual playback headroom depends on the computer. See turbo verification for assumptions and results.

Saab B205 / 9-5 wagon baseline

The Saab menu entry now includes an estimated GT17 turbo and ECU wastegate boost control (up to 0.45 bar gauge). Launch with --scenario b205 --turbo gt17, or use --turbo none for the naturally aspirated baseline. See GT17 verification for controller behavior, assumptions and tests. Charge heating and backpressure are simulated; an intercooler is not yet included.

Select Saab B205 / 9-5 wagon from the desktop menu, or launch directly:

./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. The original atmospheric-breathing geometry baseline remains available with --turbo none. Pipe/cam dimensions, friction, idle/ignition maps, clutch, drag and loaded tire radius are estimates. Turbo calibration and acoustics are approximate; factory power is not validated. See B205 verification 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 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.

Description
No description provided
Readme 1.5 MiB
Languages
C++ 96.1%
Python 1.7%
CMake 1.3%
PowerShell 0.5%
C# 0.4%