Improve physical geometry, fluid solvers, audio, and profiling
This commit is contained in:
110
docs/ACOUSTIC_BENCHMARK.md
Normal file
110
docs/ACOUSTIC_BENCHMARK.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Acoustic pulse benchmark
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows --target fluidsim_acoustic_benchmark
|
||||
.\out\build\windows-gcc\fluidsim_acoustic_benchmark.exe out/acoustics
|
||||
ctest --preset windows -R 'acoustic_benchmark|fluid_validation' --output-on-failure
|
||||
```
|
||||
|
||||
`summary.csv` contains 408 cases. Each case also has a pressure/velocity probe
|
||||
trace in CSV. No engine configuration or production solver behavior is changed.
|
||||
|
||||
## Cases and measurement
|
||||
|
||||
- A continuous 4 m pipe and an equivalent pair of directly connected 2 m pipes.
|
||||
- Equal-area characteristic and legacy zero-storage three-way junctions, and an unequal-area characteristic junction (an idealized T/Y, without angles).
|
||||
- Two-port and three-port finite-volume fittings, with 50, 500, and 5000 cc storage
|
||||
and discharge coefficients 1.0 and 0.7. Opening area equals branch pipe area;
|
||||
discharge variation represents restriction, not resolved entry geometry.
|
||||
- Rusanov, HLLE, HLLC, and limited MUSCL-Hancock/HLLC; 40, 80, and 160 cells per 2 m; nominal Courant
|
||||
settings 0.4 and 0.8. Solver CFL protection remains active. The requested
|
||||
timestep uses reference sound speed plus a small wave-speed margin.
|
||||
|
||||
All pipes have area 0.001 m² and initially rest at 101325 Pa, 300 K. A 100 Pa
|
||||
Gaussian pressure pulse, centered 0.6 m from the inlet with width parameter
|
||||
0.12 m, is initialized as a right-going linear acoustic wave. Explicit pipe
|
||||
damping and thermal relaxation are disabled.
|
||||
|
||||
The upstream probe is near x=1.4 m, and downstream probes are near x=2.6 m
|
||||
(0.6 m into each outlet branch). Probe positions use containing cell centers.
|
||||
The 9 ms integration ends before far-end reflections return to the probes.
|
||||
For every probe, characteristics are `p± = (p' ± rho*c*u)/2`.
|
||||
Acoustic pulse energy is the integral of `area * p±² / (rho*c)` over time.
|
||||
Transmitted energy sums all outlet branches. Ratios divide by incident energy
|
||||
at the upstream probe, so incident-path attenuation before that probe is excluded.
|
||||
|
||||
`transmission_over_straight` and `reflection_over_straight` divide the measured
|
||||
ratios by transmission through the continuous pipe at matching mesh, scheme,
|
||||
and timestep. This approximately removes shared propagation attenuation. Junction
|
||||
filtering can change spectra, so this correction is not a complete de-embedding
|
||||
of frequency-dependent pipe loss.
|
||||
|
||||
The ideal equal-area lossless three-way junction has reflected energy 1/9 and
|
||||
total transmitted energy 8/9. Straight-pipe ideals are 0 and 1. Finite-volume
|
||||
fittings have no constant analytic coefficient in this benchmark: their storage
|
||||
and nozzle models introduce frequency and amplitude dependence.
|
||||
|
||||
`unaccounted_ratio` is acoustic energy missing from the measured outgoing pulse,
|
||||
not a total conserved-energy error. It includes numerical attenuation, interface
|
||||
loss, and any energy still stored or delayed beyond the measurement window.
|
||||
It must not automatically be interpreted as physical dissipation.
|
||||
|
||||
Mass and total-energy drift, limited fluxes, positivity repairs, and substeps are
|
||||
reported separately. Cases with limiting or outgoing acoustic energy above 1.05
|
||||
times incident are flagged; they are not accepted as physical loss measurements.
|
||||
The test fails for nonfinite results, positivity repairs, conservation drift
|
||||
above 100 ppm, straight-pipe reflection above 0.0001, split-pipe mismatch, or a
|
||||
failure of straight-pipe transmission to improve with mesh refinement at 0.4.
|
||||
Flagged volume cases are retained as diagnostics rather than silently discarded.
|
||||
|
||||
## Initial findings
|
||||
|
||||
For Rusanov at nominal Courant 0.4:
|
||||
|
||||
| Cells per 2 m | Straight transmission | Three-way transmission / straight |
|
||||
| --- | --- | --- |
|
||||
| 40 | 0.6783 | 0.2215 |
|
||||
| 80 | 0.7172 | 0.2219 |
|
||||
| 160 | 0.7707 | 0.2222 |
|
||||
|
||||
The split pipe matches the continuous pipe. Straight-pipe attenuation decreases
|
||||
with refinement, identifying spatial numerical diffusion as a contributor.
|
||||
The legacy zero-storage junction's corrected transmission remains near 2/9 instead of
|
||||
the ideal 8/9, indicating a separate interface problem that refinement does not
|
||||
remove. Total mass and energy conservation alone does not establish correct
|
||||
acoustic scattering.
|
||||
|
||||
The original three solvers flagged five coarse, high-timestep 50 cc three-port volume cases for flux
|
||||
limiting or acoustic amplification. These show sensitivity to component storage
|
||||
and explicit exchange timesteps; a pipe CFL limit alone does not validate that
|
||||
coupling. A component timestep study should precede acoustic calibration of those
|
||||
cases. Other cases passing robustness checks are not thereby physically validated.
|
||||
|
||||
These are small-signal, zero-mean-flow results for one pulse bandwidth. They do
|
||||
not establish the dominant loss at every engine operating point. The single-450
|
||||
and current V8 use storage volumes, so a zero-storage junction fix alone will not
|
||||
address their sound. The next production-model investigation should address
|
||||
pipe diffusion and finite-volume coupling stability; retain the zero-storage
|
||||
scattering result as a separate junction regression target. Frequency sweeps,
|
||||
phase comparison, mean-flow cases, and measured fitting data remain follow-up work.
|
||||
|
||||
## Production listening candidate
|
||||
|
||||
`muscl` is now a fourth selectable solver in the desktop, CLI, and capture tool.
|
||||
Its straight-pipe energy transmission at Courant 0.4 is 0.7834, 0.8637, and
|
||||
0.9446 for 40, 80, and 160 cells per 2 m, versus Rusanov's 0.6783, 0.7172,
|
||||
and 0.7707. The benchmark also checks at least 0.05 improvement over Rusanov at
|
||||
matching mesh/timestep. Split-pipe equivalence still passes without relaxed
|
||||
thresholds. Adding MUSCL and the new characteristic/unequal-area comparisons brings the sweep to 408 cases, with seven flagged
|
||||
small-volume cases; the component-coupling timestep issue is still open.
|
||||
|
||||
The new reconstruction applies to uniform pipe sections and matching direct
|
||||
connections. Fittings, component boundaries, and profile transitions retain
|
||||
first-order coupling. Production evaluation is opt-in (`--solver muscl` or F3);
|
||||
Rusanov remains the startup default. Auto gain defaults off for listening.
|
||||
|
||||
The new characteristic solver corrects the legacy scattering error. Its corrected
|
||||
transmission is about 8/9 for equal branches; unequal-area checks and transmitted
|
||||
500/1000 Hz gain/phase checks are now included. See [junction solver details](JUNCTION_SOLVER.md).
|
||||
@@ -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).
|
||||
|
||||
98
docs/JUNCTION_SOLVER.md
Normal file
98
docs/JUNCTION_SOLVER.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Direction-aware characteristic junctions
|
||||
|
||||
## Model and scope
|
||||
|
||||
The new `BoundarySystem` node solves a nonlinear common-pressure mass balance
|
||||
using each branch's outgoing Euler acoustic wave curve: an isentropic
|
||||
rarefaction or Rankine-Hugoniot shock curve. Branch area enters mass flow,
|
||||
and pipe-coordinate orientation is handled independently of physical direction.
|
||||
Incoming total enthalpy and species are mixed by incoming mass flux. Outgoing
|
||||
contact density follows the mixed total enthalpy and the local pressure/velocity.
|
||||
Outgoing fluxes share that enthalpy and composition, conserving total energy,
|
||||
air, and fuel at the zero-storage node. Fitting forces react momentum; axial
|
||||
momentum is not summed as a scalar across differently directed branches.
|
||||
|
||||
Pressure is found by a bracketed Newton iteration. Setup allocates scratch
|
||||
arrays; node updates allocate no memory. Outgoing mass is normalized to incoming
|
||||
mass to remove root roundoff. A shared donor budget scales advective fluxes when
|
||||
necessary, preserving node conservation, and reports `junction_limited_fluxes`.
|
||||
|
||||
This is a subsonic, common-pressure engineering closure. It has not been proven
|
||||
entropy stable for arbitrary mixtures, large thermal contrasts, and shocks.
|
||||
Endpoint Mach numbers at or above 0.95, predicted face Mach numbers at or above
|
||||
0.98, and unsuccessful pressure solves select the conservative legacy Rusanov
|
||||
fallback. `junction_fallbacks` reports these cases. It is not a choked/supersonic
|
||||
multi-port Riemann solver. Frequent fallback or limiting indicates a case needing
|
||||
further timestep/model investigation, not a validated acoustic measurement.
|
||||
|
||||
The broader research on entropy-preserving Euler junctions uses common total
|
||||
enthalpy and entropy-based coupling; the implemented common-pressure/mixed-enthalpy
|
||||
closure is a distinct engineering choice. See
|
||||
[Lang and Mindt, 2018](https://www.aimsciences.org/article/doi/10.3934/nhm.2018008)
|
||||
for the stronger mathematical coupling conditions and their subsonic assumptions.
|
||||
|
||||
## Direction and turning
|
||||
|
||||
Each endpoint can specify a unit axis pointing out of the node. For a receiving
|
||||
branch, the loss coefficient is the incoming-mass-weighted average of
|
||||
`turning_loss * (1 + dot(outward_receiver, outward_donor)) / 2`.
|
||||
Opposite axes have zero turning loss; perpendicular axes have half the configured
|
||||
loss. A local signed pressure-drop relation uses `K * rho * u² / 2`, with three
|
||||
outer updates of the donor-weighted direction coefficients. Donors are recomputed
|
||||
as flow reverses. This is a quasi-steady uncalibrated turning-loss approximation.
|
||||
It does not resolve vortices, bend radii, separation, or transverse acoustic modes.
|
||||
|
||||
At zero mean flow, ideal low-frequency compact-junction scattering depends on
|
||||
branch impedances, not a stereo direction or a branch-angle audio filter. Angles
|
||||
enter the mean-flow/turning model. Defaults use schematic route tangents, which
|
||||
can be overridden with actual branch axes in TOML. No 3D CFD is involved.
|
||||
|
||||
## Production selection
|
||||
|
||||
```powershell
|
||||
.\out\build\windows-gcc\fluidsim_desktop.exe --example v8-h --solver rusanov --junctions characteristic --junction-loss 0.5 --scene dry
|
||||
```
|
||||
|
||||
Use `--junctions volume` for the original finite-volume fittings or
|
||||
`--junctions legacy` for the old zero-storage numerical node. The volume model
|
||||
remains the default. Pipe solvers and junction models are independent. Restart
|
||||
for model comparisons; auto gain remains off by default.
|
||||
|
||||
The same options work in `fluidsim_audio_capture`. Captures report junction
|
||||
iterations, fallback, limiting, and pipe positivity repairs. On collector-topology
|
||||
engines, selecting characteristic/legacy explicitly replaces collector storage
|
||||
with a node. Changes there include removal of that physical compliance, so they
|
||||
cannot all be attributed to numerical accuracy. The V8 and staged exhaust paths
|
||||
also change from storage fittings to zero-storage nodes.
|
||||
|
||||
See [the configuration guide](ENGINE_CONFIG.md#characteristic-exhaust-junctions)
|
||||
for branch direction overrides and endpoint indexing.
|
||||
|
||||
## Validation
|
||||
|
||||
`fluidsim_junction_tests` checks mass, total energy, air/fuel conservation,
|
||||
unequal areas and thermal states, opposite donor configurations, all-pipe
|
||||
coordinate reversal, world rotation, straight-versus-turning flow preference,
|
||||
invalid direction rejection, and explicit supersonic fallback reporting.
|
||||
|
||||
The 408-case acoustic benchmark compares volume fittings, characteristic nodes,
|
||||
and legacy nodes across all four pipe schemes, meshes, and timesteps. Equal-area
|
||||
characteristic scattering approaches reflected energy 1/9 and transmitted energy
|
||||
8/9 after approximately removing common pipe attenuation. With outlet areas
|
||||
2A and 3A and inlet area A, the targets are 4/9 reflected and 5/9 transmitted.
|
||||
Characteristic pulse cases require no fallback. At the finest mesh, transmitted
|
||||
pressure gain and phase at 500 and 1000 Hz are compared against ideal equal-area
|
||||
gain 2/3 and zero extra phase, after straight-pipe de-embedding.
|
||||
|
||||
For Rusanov, 160 cells per 2 m, Courant 0.4, corrected transmission is about
|
||||
0.889 with the characteristic node versus 0.222 with the legacy node. Seven
|
||||
small-volume cases remain flagged in the separate volume model. Full measured
|
||||
junction spectra, geometry calibration, high-Mach coupling, and entropy
|
||||
admissibility remain follow-up work.
|
||||
|
||||
Listening captures are in `out/audio/junction-ab-single-{volume,characteristic}-rendered.wav`
|
||||
and `out/audio/junction-ab-v8-{volume,characteristic}-rendered.wav`. Their
|
||||
`-level-matched.wav` copies use RMS 0.08 with constant per-file gain. The single
|
||||
comparison is 3000 RPM / pedal 0.3; V8 is 3000 RPM / pedal 0.5 with turning-loss
|
||||
coefficient 0.5 in the characteristic case. Both use dry Rusanov rendering.
|
||||
These comparisons include the change in storage model described above.
|
||||
Reference in New Issue
Block a user