Improve physical geometry, fluid solvers, audio, and profiling
This commit is contained in:
22
.gitignore
vendored
22
.gitignore
vendored
@@ -1,6 +1,28 @@
|
||||
/build/
|
||||
/build-*/
|
||||
/out/
|
||||
*.wav
|
||||
*.mp3
|
||||
*.ogg
|
||||
*.flac
|
||||
*.aiff
|
||||
*.aif
|
||||
|
||||
# Local editor and operating system artifacts
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.swp
|
||||
*.swo
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
# Generated profiling and benchmark output
|
||||
*.prof
|
||||
*.profraw
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
*.log
|
||||
/.vs/
|
||||
CMakeUserPresets.json
|
||||
/verification/bin/
|
||||
|
||||
27
.vscode/tasks.json
vendored
27
.vscode/tasks.json
vendored
@@ -48,9 +48,32 @@
|
||||
"dependsOn": "FluidSim: configure desktop",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
"isDefault": false
|
||||
},
|
||||
"problemMatcher": "$gcc"
|
||||
},
|
||||
{
|
||||
"type": "cppbuild",
|
||||
"label": "C/C++: cl.exe build active file",
|
||||
"command": "cl.exe",
|
||||
"args": [
|
||||
"/Zi",
|
||||
"/EHsc",
|
||||
"/nologo",
|
||||
"/Fe${fileDirname}\\${fileBasenameNoExtension}.exe",
|
||||
"${file}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${fileDirname}"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$msCompile"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "Task generated by Debugger."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ add_library(fluidsim_core
|
||||
src/scenario.cpp
|
||||
src/scenario_snapshot.cpp
|
||||
src/scenario_geometry.cpp
|
||||
src/physical_geometry.cpp
|
||||
src/solver.cpp
|
||||
src/vehicle.cpp
|
||||
src/simulation_ring_buffer.cpp
|
||||
@@ -46,6 +47,8 @@ target_link_libraries(fluidsim_cpp PRIVATE fluidsim_core)
|
||||
|
||||
add_executable(fluidsim_parity_trace tools/parity_trace.cpp)
|
||||
target_link_libraries(fluidsim_parity_trace PRIVATE fluidsim_core)
|
||||
add_executable(fluidsim_migrate_geometry tools/migrate_geometry.cpp)
|
||||
target_link_libraries(fluidsim_migrate_geometry PRIVATE fluidsim_core)
|
||||
|
||||
if(FLUIDSIM_BUILD_DESKTOP)
|
||||
find_package(SFML 3.0.2 COMPONENTS Graphics Audio QUIET)
|
||||
@@ -114,6 +117,19 @@ endif()
|
||||
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
add_executable(fluidsim_physical_geometry_tests tests/physical_geometry_tests.cpp)
|
||||
target_link_libraries(fluidsim_physical_geometry_tests PRIVATE fluidsim_core)
|
||||
target_include_directories(fluidsim_physical_geometry_tests SYSTEM PRIVATE third_party/tomlplusplus)
|
||||
add_test(NAME fluidsim_physical_geometry_tests COMMAND fluidsim_physical_geometry_tests)
|
||||
add_executable(fluidsim_mesh_resolution_tests tests/mesh_resolution_tests.cpp)
|
||||
target_link_libraries(fluidsim_mesh_resolution_tests PRIVATE fluidsim_core)
|
||||
add_test(NAME fluidsim_mesh_resolution_tests COMMAND fluidsim_mesh_resolution_tests)
|
||||
add_executable(fluidsim_junction_tests tests/junction_tests.cpp)
|
||||
target_link_libraries(fluidsim_junction_tests PRIVATE fluidsim_core)
|
||||
add_test(NAME fluidsim_junction_tests COMMAND fluidsim_junction_tests)
|
||||
add_executable(fluidsim_live_tuning_tests tests/live_tuning_tests.cpp)
|
||||
target_link_libraries(fluidsim_live_tuning_tests PRIVATE fluidsim_core)
|
||||
add_test(NAME fluidsim_live_tuning_tests COMMAND fluidsim_live_tuning_tests)
|
||||
add_executable(fluidsim_engine_config_tests tests/engine_config_tests.cpp)
|
||||
target_link_libraries(fluidsim_engine_config_tests PRIVATE fluidsim_core)
|
||||
add_test(NAME fluidsim_engine_config_tests COMMAND fluidsim_engine_config_tests)
|
||||
@@ -136,6 +152,8 @@ add_executable(fluidsim_physics_benchmark tools/physics_benchmark.cpp)
|
||||
target_link_libraries(fluidsim_physics_benchmark PRIVATE fluidsim_core)
|
||||
add_executable(fluidsim_scenario_benchmark tools/scenario_benchmark.cpp)
|
||||
target_link_libraries(fluidsim_scenario_benchmark PRIVATE fluidsim_core)
|
||||
add_executable(fluidsim_scenario_profile tools/scenario_profile.cpp)
|
||||
target_link_libraries(fluidsim_scenario_profile PRIVATE fluidsim_core)
|
||||
if(BUILD_TESTING)
|
||||
add_test(NAME fluidsim_v8_exhaust_regression COMMAND fluidsim_scenario_benchmark 8 coast v8)
|
||||
endif()
|
||||
@@ -145,6 +163,7 @@ if(BUILD_TESTING)
|
||||
add_test(NAME fluidsim_fluid_validation COMMAND fluidsim_fluid_validation)
|
||||
add_test(NAME fluidsim_fluid_validation_hlle COMMAND fluidsim_fluid_validation hlle)
|
||||
add_test(NAME fluidsim_fluid_validation_hllc COMMAND fluidsim_fluid_validation hllc)
|
||||
add_test(NAME fluidsim_fluid_validation_muscl COMMAND fluidsim_fluid_validation muscl)
|
||||
endif()
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(fluidsim_core PUBLIC Threads::Threads)
|
||||
@@ -156,6 +175,11 @@ if(BUILD_TESTING)
|
||||
add_test(NAME fluidsim_intake_regression COMMAND fluidsim_intake_regression)
|
||||
endif()
|
||||
|
||||
add_executable(fluidsim_acoustic_benchmark tools/acoustic_benchmark.cpp)
|
||||
target_link_libraries(fluidsim_acoustic_benchmark PRIVATE fluidsim_core)
|
||||
if(BUILD_TESTING)
|
||||
add_test(NAME fluidsim_acoustic_benchmark COMMAND fluidsim_acoustic_benchmark "${CMAKE_CURRENT_BINARY_DIR}/acoustic-validation")
|
||||
endif()
|
||||
add_executable(fluidsim_audio_capture tools/audio_capture.cpp)
|
||||
target_link_libraries(fluidsim_audio_capture PRIVATE fluidsim_core)
|
||||
add_executable(fluidsim_two_stroke_benchmark tools/two_stroke_benchmark.cpp)
|
||||
|
||||
137
README.md
137
README.md
@@ -87,7 +87,9 @@ Controls: W/S raise/lower the pedal over 0.5 seconds, C disengages the clutch,
|
||||
V applies starter torque while held,
|
||||
A/D shift, Z selects neutral, and left/right adjust engine load. The on-screen
|
||||
pedal is direct and springs back on release; zero pedal retains ECU idle control.
|
||||
Page Up/Down change playback speed; Space toggles real time.
|
||||
Space toggles real-time and manual playback. In manual mode, Shift+scroll or
|
||||
Page Up/Down changes speed; ordinary scrolling zooms the view. Rendering uses
|
||||
display VSync independently of simulation speed, including 0.01x slow motion.
|
||||
|
||||
The command-line runner is useful for repeatable checks:
|
||||
|
||||
@@ -113,7 +115,8 @@ cmake --build build-msvc --target fluidsim_parity_trace
|
||||
|
||||
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
|
||||
up to 128-frame batches with a 4096-frame startup reserve (about 93 ms). Batches
|
||||
shrink with playback speed so 0.01x does not advance in large bursts. 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.
|
||||
@@ -155,10 +158,18 @@ or exhaust afterfire chemistry. Filtering cannot recover aliased
|
||||
source information. See [audio verification](verification/AUDIO_RENDERING.md)
|
||||
for capture commands, current renderer details and limitations.
|
||||
|
||||
Use the **Cells/m - / +** control in the sidebar to change the active scenario's
|
||||
pipe resolution. Changes rebuild the mesh in the background and restart the
|
||||
engine, retaining solver, listener, scene and driving-control inputs. Values are
|
||||
remembered separately per scenario until the app closes. Set persistent defaults
|
||||
in each engine TOML's `[simulation] cells_per_meter`. The desktop engine editor
|
||||
has been removed; edit engine calibration in TOML.
|
||||
|
||||
|
||||
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 returns from a running scenario to the menu, stopping its simulation and
|
||||
Escape returns from the 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`
|
||||
@@ -176,7 +187,9 @@ cmake --build build-desktop --target fluidsim_desktop -j 4
|
||||
|
||||
Hold **W** to raise the pedal and **S** to lower it. Releasing the keyboard
|
||||
returns the pedal over 0.5 seconds. The UI lever is direct and springs back. Use
|
||||
**Space** to restore real-time playback and **R** to change environment. The two-stroke desktop uses
|
||||
**Space** to toggle real-time/manual playback and **R** to change environment.
|
||||
In manual mode use **Shift+scroll** or **Page Up/Down** to adjust speed;
|
||||
ordinary scrolling continues to zoom the view. 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
|
||||
@@ -310,7 +323,7 @@ runs for every scenario, and finite audio/reverb output.
|
||||
|
||||
## Fuel and throttle control
|
||||
|
||||
Desktop playback has automatic gain enabled by default for every scenario.
|
||||
Desktop playback has automatic gain disabled by default for every scenario.
|
||||
Press **G** to toggle it; the dashboard shows its state. It tracks stereo RMS
|
||||
and peaks after DC removal, lifting quiet idle audio gradually (1.5-second
|
||||
gain-rise time constant) and reducing gain faster for loud revs (30 ms).
|
||||
@@ -410,8 +423,8 @@ Manifold vacuum at closed throttle remains part of the simulated pumping cycle.
|
||||
|
||||
## Pipe solver comparisons
|
||||
|
||||
The desktop accepts `--solver rusanov|hlle|hllc`. Press **F3** during playback to
|
||||
cycle Rusanov, HLLE and HLLC; the dashboard shows the current solver. All pipes
|
||||
The desktop accepts `--solver rusanov|hlle|hllc|muscl`. Press **F3** during playback to
|
||||
cycle Rusanov, HLLE, HLLC and MUSCL; the dashboard shows the current solver. All pipes
|
||||
switch together between simulation samples. Rusanov remains the startup default.
|
||||
Changing solver affects the ongoing engine state; allow several cycles and the
|
||||
audio queue to settle before judging it. Use the same scene and auto-gain setting.
|
||||
@@ -499,16 +512,20 @@ geometry-resolving junction model. Momentum changes
|
||||
are reacted by the fitting. Branch angle losses are not modeled. The separate
|
||||
`Junction` class remains available for explicit finite-volume chambers.
|
||||
|
||||
Each V8 bank now has a 4-2-1 header: four equal 750 mm x 38 mm primaries feed two
|
||||
equal 400 mm x 45 mm secondaries, then a 50 mm exhaust. Pairings are 1+2 / 3+4
|
||||
Each V8 bank has a 4-2-1 header: four primaries feed two 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.
|
||||
The TOML `primaries` pipe group configures primary length/diameter, while
|
||||
The TOML `primaries` pipe group configures diameter; measured
|
||||
`geometry.pipes` centerlines configure length and position. Headers now use
|
||||
direct swept bends with revised lengths, and the short/long variants have
|
||||
distinct physical layouts. See [geometry definitions](docs/ENGINE_CONFIG.md).
|
||||
The
|
||||
`[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.
|
||||
uses the same centerlines, cross-sections and active storage-volume dimensions
|
||||
as the fluid system, with local pressure colors and mitered hard corners.
|
||||
|
||||
The previous header optimization measurements applied to the earlier finite-volume
|
||||
4-1 layout and do not establish an optimum for this new 4-2-1 network.
|
||||
@@ -619,3 +636,99 @@ 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.
|
||||
|
||||
### Source-separated audio diagnostics
|
||||
|
||||
The capture tool writes `-intake.wav`, `-exhaust.wav`, `-exhaust-2.wav`, and
|
||||
`-valve-contact.wav` alongside the existing rendered, dry, and unfiltered mixes.
|
||||
Source stems contain direct sound and early reflections, before the shared diffuse
|
||||
reverb; `-tail.wav` contains that shared tail. With all sources enabled, the four
|
||||
stems plus the tail reconstruct the rendered mix before WAV quantization/clipping.
|
||||
Absent sources produce silent files. Peak, RMS, maximum sample delta, and clipping
|
||||
counts are reported for every stem, in device full-scale units, without normalization.
|
||||
|
||||
Use `--solo intake`, `--solo exhaust`, `--solo exhaust-2`, or
|
||||
`--solo valve-contact` to select a source in the output mix (default: `--solo all`).
|
||||
All diagnostic stems remain active during soloing. These controls affect audio only;
|
||||
they do not change the fluid simulation. Source controls are simulation-thread APIs.
|
||||
|
||||
```powershell
|
||||
.\out\build\windows-gcc\fluidsim_audio_capture.exe --example single-450 --rpm 3000 --throttle .3 --warmup 1 --seconds 2 --scene dry --out out/audio/single-450-baseline
|
||||
```
|
||||
|
||||
For intake-only listening, repeat with `--solo intake` and a different output prefix.
|
||||
The shared tail can retain decay when controls change during playback.
|
||||
|
||||
Captures use 32-bit IEEE float WAV to preserve very quiet sources without clipping.
|
||||
For audible, individually peak-normalized PCM16 listening copies, run:
|
||||
|
||||
```powershell
|
||||
py tools/audio_preview.py out/audio/single-450-baseline
|
||||
```
|
||||
|
||||
Previews appear in `out/audio/previews/`, with gain reported for each file.
|
||||
Silent sources are skipped. Preview loudness does not represent relative source
|
||||
strength; use the original captures and metrics for calibration.
|
||||
|
||||
### Acoustic pulse diagnostics
|
||||
|
||||
The `fluidsim_acoustic_benchmark` target compares straight connections, idealized
|
||||
three-way junctions, and finite-volume fittings across meshes, timesteps, and
|
||||
all three flux solvers. It exports pressure/velocity traces and acoustic energy
|
||||
ratios, with conservation and numerical-repair diagnostics. See
|
||||
[the benchmark guide and initial findings](docs/ACOUSTIC_BENCHMARK.md).
|
||||
|
||||
### Listening comparison: limited second-order pipes
|
||||
|
||||
Desktop auto gain now starts **off**. Press **G** to enable it if desired.
|
||||
For a direct comparison on the current engine, keep throttle and master volume
|
||||
fixed and press **F3** to cycle `rusanov ? hlle ? hllc ? muscl`.
|
||||
The dashboard shows the selected solver. Rusanov remains the startup default.
|
||||
To start directly in the new mode:
|
||||
|
||||
```powershell
|
||||
.\out\build\windows-gcc\fluidsim_desktop.exe --example single-450 --solver muscl --scene dry
|
||||
```
|
||||
|
||||
`muscl` uses minmod-limited primitive MUSCL-Hancock reconstruction with HLLC
|
||||
fluxes on uniform pipe sections. Matching direct connections share reconstruction
|
||||
stencils. Component boundaries and area/profile transitions retain first-order
|
||||
coupling; nonphysical predicted edges fall back to cell averages, and HLLC keeps
|
||||
its existing HLLE fallback. Reconstruction buffers are allocated at construction.
|
||||
This is a listening candidate, not a calibrated real-engine sound model.
|
||||
|
||||
At 3000 RPM / 0.3 pedal, four-second dry captures are in
|
||||
`out/audio/pipe-ab-rusanov-rendered.wav` and `out/audio/pipe-ab-muscl-rendered.wav`.
|
||||
They preserve the actual level difference. New wave resolution can also change
|
||||
cylinder filling, combustion, and torque. Restart in each solver for clean
|
||||
comparisons; live switching retains the engine's current state.
|
||||
|
||||
For a comparison at equal RMS loudness, use
|
||||
`out/audio/pipe-ab-rusanov-level-matched.wav` and
|
||||
`out/audio/pipe-ab-muscl-level-matched.wav`. Both are PCM16 listening copies;
|
||||
original float captures keep their physical output scale. Equal RMS does not
|
||||
imply identical perceived loudness or identical engine state.
|
||||
|
||||
In one local loaded V8 check, MUSCL took 1.23 wall seconds per simulated second,
|
||||
versus 0.78 for Rusanov. Large engines may underrun in real-time playback;
|
||||
use the single-450 for the first listening comparison.
|
||||
|
||||
### Direction-aware characteristic junctions
|
||||
|
||||
A nonlinear zero-storage exhaust junction solver is now available separately
|
||||
from the pipe solver. Start with Rusanov pipes to isolate the junction change:
|
||||
|
||||
```powershell
|
||||
.\out\build\windows-gcc\fluidsim_desktop.exe --example v8-h --solver rusanov --junctions characteristic --junction-loss 0.5 --scene dry
|
||||
```
|
||||
|
||||
Use `--junctions volume` to compare against the original volume fittings.
|
||||
`--junctions legacy` selects the old dissipative zero-storage Rusanov node.
|
||||
Default engine behavior still uses volume fittings. Direction losses use local
|
||||
route tangents, with explicit TOML branch direction overrides supported. The
|
||||
loss coefficient is an uncalibrated engineering parameter; zero disables angle
|
||||
losses. Auto gain still defaults off.
|
||||
|
||||
The single-450 also supports these switches, but its two-port collector cannot
|
||||
exercise multi-branch turning. Selecting a zero-storage node there removes its
|
||||
collector-volume resonance. See [junction details](docs/JUNCTION_SOLVER.md).
|
||||
|
||||
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.
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "big-carb"
|
||||
name = "8.0 litre / carbureted big-block"
|
||||
category = "V8 / big-block"
|
||||
@@ -7,9 +7,11 @@ description = "Cross-plane firing / American 4-2-1 + H / carb fuel transport"
|
||||
order = 29
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 90.0
|
||||
collector_volume_litres = 2.0
|
||||
cylinders = 8
|
||||
initial_rpm = 1120.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0, 270.0, 540.0, 630.0, 360.0, 180.0, 89.99998]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 8.0
|
||||
starter_torque_nm = 201.1122
|
||||
throttle_diameter_mm = 85.0
|
||||
topology = "american_v8"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 65.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 9.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 370.0
|
||||
exhaust_open_deg = 140.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 36.576
|
||||
exhaust_valve_lift_mm = 10.287
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 570.0
|
||||
intake_open_deg = 350.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 43.434
|
||||
intake_valve_lift_mm = 11.43
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 176.4
|
||||
stroke_mm = 98.0
|
||||
@@ -113,51 +108,619 @@ bowl_refill_kg_per_s = 0.1
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 3
|
||||
diameter_mm = 70.0
|
||||
length_mm = 180.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 8
|
||||
cells = 2
|
||||
diameter_mm = 38.0
|
||||
length_mm = 120.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 8
|
||||
cells = 15
|
||||
diameter_mm = 38.0
|
||||
length_mm = 750.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondaries"
|
||||
count = 4
|
||||
cells = 8
|
||||
diameter_mm = 45.0
|
||||
length_mm = 400.0
|
||||
|
||||
[[pipes]]
|
||||
id = "bank_collectors"
|
||||
count = 2
|
||||
cells = 11
|
||||
diameter_mm = 50.0
|
||||
length_mm = 550.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipes"
|
||||
count = 2
|
||||
cells = 25
|
||||
diameter_mm = 50.0
|
||||
length_mm = 1250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "crossover"
|
||||
cells = 16
|
||||
diameter_mm = 38.0
|
||||
length_mm = 780.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[350.000, 0.000000],
|
||||
[355.000, 0.266213],
|
||||
[360.000, 0.996153],
|
||||
[365.000, 2.086769],
|
||||
[370.000, 3.435011],
|
||||
[375.000, 4.937829],
|
||||
[380.000, 6.492171],
|
||||
[385.000, 7.994989],
|
||||
[390.000, 9.343231],
|
||||
[395.000, 10.433847],
|
||||
[400.000, 11.163787],
|
||||
[405.000, 11.430000],
|
||||
[515.000, 11.430000],
|
||||
[520.000, 11.163787],
|
||||
[525.000, 10.433847],
|
||||
[530.000, 9.343231],
|
||||
[535.000, 7.994989],
|
||||
[540.000, 6.492171],
|
||||
[545.000, 4.937829],
|
||||
[550.000, 3.435011],
|
||||
[555.000, 2.086769],
|
||||
[560.000, 0.996153],
|
||||
[565.000, 0.266213],
|
||||
[570.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[140.000, 0.000000],
|
||||
[145.000, 0.219826],
|
||||
[150.000, 0.825192],
|
||||
[155.000, 1.734933],
|
||||
[160.000, 2.867881],
|
||||
[165.000, 4.142870],
|
||||
[170.000, 5.478734],
|
||||
[175.000, 6.794307],
|
||||
[180.000, 8.008421],
|
||||
[185.000, 9.039912],
|
||||
[190.000, 9.807611],
|
||||
[195.000, 10.230353],
|
||||
[197.500, 10.287000],
|
||||
[312.500, 10.287000],
|
||||
[317.500, 10.067174],
|
||||
[322.500, 9.461808],
|
||||
[327.500, 8.552067],
|
||||
[332.500, 7.419119],
|
||||
[337.500, 6.144130],
|
||||
[342.500, 4.808266],
|
||||
[347.500, 3.492693],
|
||||
[352.500, 2.278579],
|
||||
[357.500, 1.247088],
|
||||
[362.500, 0.479389],
|
||||
[367.500, 0.056647],
|
||||
[370.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -198.45, 0, 0 ]
|
||||
tilt_deg = -45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -66.15, 0, 0 ]
|
||||
tilt_deg = -45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 66.15, 0, 0 ]
|
||||
tilt_deg = -45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 198.45, 0, 0 ]
|
||||
tilt_deg = -45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -198.45, 0, 0 ]
|
||||
tilt_deg = 45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -66.15, 0, 0 ]
|
||||
tilt_deg = 45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 66.15, 0, 0 ]
|
||||
tilt_deg = 45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 198.45, 0, 0 ]
|
||||
tilt_deg = 45.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -444.6, 334.9036, 0 ],
|
||||
[ -264.6, 334.9036, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -198.45, 314.716, -130.0582 ],
|
||||
[ -198.45, 194.716, -130.0582 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -66.15, 314.716, -130.0582 ],
|
||||
[ -66.15, 194.716, -130.0582 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 66.15, 314.716, -130.0582 ],
|
||||
[ 66.15, 194.716, -130.0582 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 198.45, 314.716, -130.0582 ],
|
||||
[ 198.45, 194.716, -130.0582 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -198.45, 314.716, 130.0582 ],
|
||||
[ -198.45, 194.716, 130.0582 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -66.15, 314.716, 130.0582 ],
|
||||
[ -66.15, 194.716, 130.0582 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 66.15, 314.716, 130.0582 ],
|
||||
[ 66.15, 194.716, 130.0582 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 198.45, 314.716, 130.0582 ],
|
||||
[ 198.45, 194.716, 130.0582 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -198.45, 121.9759, -202.7982 ],
|
||||
[ -197.0012, 111.4774, -210.8704 ],
|
||||
[ -192.907, 102.0521, -218.6645 ],
|
||||
[ -186.5452, 93.5225, -226.147 ],
|
||||
[ -178.2937, 85.7113, -233.2843 ],
|
||||
[ -168.5305, 78.441, -240.0431 ],
|
||||
[ -157.6335, 71.5342, -246.3898 ],
|
||||
[ -145.9807, 64.8134, -252.291 ],
|
||||
[ -133.9499, 58.1011, -257.7131 ],
|
||||
[ -121.9191, 51.2201, -262.6227 ],
|
||||
[ -110.2663, 43.9927, -266.9864 ],
|
||||
[ -99.3693, 36.2416, -270.7706 ],
|
||||
[ -89.6061, 27.7894, -273.9418 ],
|
||||
[ -81.3546, 18.4586, -276.4666 ],
|
||||
[ -74.9928, 8.0717, -278.3115 ],
|
||||
[ -70.8985, -3.5486, -279.443 ],
|
||||
[ -69.4498, -16.5798, -279.8276 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -66.15, 121.9759, -202.7982 ],
|
||||
[ -66.0127, 113.4631, -209.2701 ],
|
||||
[ -65.6247, 105.1542, -215.8763 ],
|
||||
[ -65.0218, 97.0014, -222.5408 ],
|
||||
[ -64.2399, 88.9567, -229.1874 ],
|
||||
[ -63.3147, 80.9722, -235.7399 ],
|
||||
[ -62.282, 73.0001, -242.1222 ],
|
||||
[ -61.1777, 64.9925, -248.2581 ],
|
||||
[ -60.0376, 56.9014, -254.0714 ],
|
||||
[ -58.8975, 48.6789, -259.486 ],
|
||||
[ -57.7932, 40.2772, -264.4258 ],
|
||||
[ -56.7605, 31.6483, -268.8146 ],
|
||||
[ -55.8353, 22.7444, -272.5762 ],
|
||||
[ -55.0534, 13.5175, -275.6344 ],
|
||||
[ -54.4505, 3.9198, -277.9132 ],
|
||||
[ -54.0625, -6.0967, -279.3363 ],
|
||||
[ -53.9252, -16.5798, -279.8276 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 66.15, 121.9759, -202.7982 ],
|
||||
[ 67.5987, 111.4774, -210.8704 ],
|
||||
[ 71.693, 102.0521, -218.6645 ],
|
||||
[ 78.0548, 93.5225, -226.147 ],
|
||||
[ 86.3063, 85.7113, -233.2843 ],
|
||||
[ 96.0695, 78.441, -240.0431 ],
|
||||
[ 106.9665, 71.5342, -246.3898 ],
|
||||
[ 118.6193, 64.8134, -252.291 ],
|
||||
[ 130.6501, 58.1011, -257.7131 ],
|
||||
[ 142.6809, 51.2201, -262.6227 ],
|
||||
[ 154.3337, 43.9927, -266.9864 ],
|
||||
[ 165.2307, 36.2416, -270.7706 ],
|
||||
[ 174.9939, 27.7894, -273.9418 ],
|
||||
[ 183.2454, 18.4586, -276.4666 ],
|
||||
[ 189.6072, 8.0717, -278.3115 ],
|
||||
[ 193.7014, -3.5486, -279.443 ],
|
||||
[ 195.1502, -16.5798, -279.8276 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 198.45, 121.9759, -202.7982 ],
|
||||
[ 198.5873, 113.4631, -209.2701 ],
|
||||
[ 198.9753, 105.1542, -215.8763 ],
|
||||
[ 199.5782, 97.0014, -222.5408 ],
|
||||
[ 200.3601, 88.9567, -229.1874 ],
|
||||
[ 201.2853, 80.9722, -235.7399 ],
|
||||
[ 202.318, 73.0001, -242.1222 ],
|
||||
[ 203.4223, 64.9925, -248.2581 ],
|
||||
[ 204.5624, 56.9014, -254.0714 ],
|
||||
[ 205.7025, 48.6789, -259.486 ],
|
||||
[ 206.8068, 40.2772, -264.4258 ],
|
||||
[ 207.8394, 31.6483, -268.8146 ],
|
||||
[ 208.7647, 22.7444, -272.5762 ],
|
||||
[ 209.5466, 13.5175, -275.6344 ],
|
||||
[ 210.1495, 3.9198, -277.9132 ],
|
||||
[ 210.5375, -6.0967, -279.3363 ],
|
||||
[ 210.6748, -16.5798, -279.8276 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ -198.45, 121.9759, 202.7982 ],
|
||||
[ -197.277, 108.2502, 212.6484 ],
|
||||
[ -193.869, 94.7077, 221.8246 ],
|
||||
[ -188.3921, 81.4455, 230.332 ],
|
||||
[ -181.0126, 68.5602, 238.1762 ],
|
||||
[ -171.8968, 56.1489, 245.3622 ],
|
||||
[ -161.2109, 44.3085, 251.8955 ],
|
||||
[ -149.1211, 33.1359, 257.7814 ],
|
||||
[ -135.7937, 22.7279, 263.0251 ],
|
||||
[ -121.395, 13.1814, 267.632 ],
|
||||
[ -106.0911, 4.5935, 271.6075 ],
|
||||
[ -90.0483, -2.9391, 274.9567 ],
|
||||
[ -73.433, -9.3194, 277.6851 ],
|
||||
[ -56.4112, -14.4506, 279.7979 ],
|
||||
[ -39.1493, -18.2357, 281.3005 ],
|
||||
[ -21.8136, -20.5778, 282.1981 ],
|
||||
[ -4.5702, -21.38, 282.4962 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -66.15, 121.9759, 202.7982 ],
|
||||
[ -64.977, 108.2502, 212.6484 ],
|
||||
[ -61.569, 94.7077, 221.8246 ],
|
||||
[ -56.0921, 81.4455, 230.332 ],
|
||||
[ -48.7126, 68.5602, 238.1762 ],
|
||||
[ -39.5968, 56.1489, 245.3622 ],
|
||||
[ -28.9109, 44.3085, 251.8955 ],
|
||||
[ -16.8211, 33.1359, 257.7814 ],
|
||||
[ -3.4937, 22.7279, 263.0251 ],
|
||||
[ 10.905, 13.1814, 267.632 ],
|
||||
[ 26.2089, 4.5935, 271.6075 ],
|
||||
[ 42.2516, -2.9391, 274.9567 ],
|
||||
[ 58.867, -9.3194, 277.6851 ],
|
||||
[ 75.8888, -14.4506, 279.7979 ],
|
||||
[ 93.1506, -18.2357, 281.3005 ],
|
||||
[ 110.4864, -20.5778, 282.1981 ],
|
||||
[ 127.7298, -21.38, 282.4962 ]
|
||||
]
|
||||
|
||||
# primaries 7
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 66.15, 121.9759, 202.7982 ],
|
||||
[ 65.6316, 113.1956, 209.4857 ],
|
||||
[ 64.1664, 104.7363, 216.2519 ],
|
||||
[ 61.8898, 96.5327, 223.0266 ],
|
||||
[ 58.937, 88.5195, 229.7393 ],
|
||||
[ 55.4433, 80.6312, 236.3196 ],
|
||||
[ 51.5438, 72.8027, 242.6971 ],
|
||||
[ 47.3738, 64.9684, 248.8014 ],
|
||||
[ 43.0685, 57.063, 254.562 ],
|
||||
[ 38.7633, 49.0212, 259.9086 ],
|
||||
[ 34.5933, 40.7777, 264.7708 ],
|
||||
[ 30.6938, 32.2671, 269.0781 ],
|
||||
[ 27.2, 23.424, 272.7602 ],
|
||||
[ 24.2472, 14.1831, 275.7465 ],
|
||||
[ 21.9706, 4.4791, 277.9668 ],
|
||||
[ 20.5055, -5.7534, 279.3506 ],
|
||||
[ 19.9871, -16.5798, 279.8276 ]
|
||||
]
|
||||
|
||||
# primaries 8
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ 198.45, 121.9759, 202.7982 ],
|
||||
[ 197.9315, 113.1956, 209.4857 ],
|
||||
[ 196.4664, 104.7363, 216.2519 ],
|
||||
[ 194.1898, 96.5327, 223.0266 ],
|
||||
[ 191.237, 88.5195, 229.7393 ],
|
||||
[ 187.7432, 80.6312, 236.3196 ],
|
||||
[ 183.8437, 72.8027, 242.6971 ],
|
||||
[ 179.6738, 64.9684, 248.8014 ],
|
||||
[ 175.3685, 57.063, 254.562 ],
|
||||
[ 171.0633, 49.0212, 259.9086 ],
|
||||
[ 166.8933, 40.7777, 264.7708 ],
|
||||
[ 162.9938, 32.2671, 269.0781 ],
|
||||
[ 159.5, 23.424, 272.7602 ],
|
||||
[ 156.5472, 14.1831, 275.7465 ],
|
||||
[ 154.2706, 4.4791, 277.9668 ],
|
||||
[ 152.8055, -5.7534, 279.3506 ],
|
||||
[ 152.2871, -16.5798, 279.8276 ]
|
||||
]
|
||||
|
||||
# secondaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ -33.8798, -36.9883, -290.0681 ],
|
||||
[ -8.445, -37.449, -290.0681 ],
|
||||
[ 16.3173, -38.751, -290.0681 ],
|
||||
[ 40.5034, -40.7741, -290.0681 ],
|
||||
[ 64.209, -43.3982, -290.0681 ],
|
||||
[ 87.5305, -46.503, -290.0681 ],
|
||||
[ 110.5638, -49.9683, -290.0681 ],
|
||||
[ 133.4049, -53.6741, -290.0681 ],
|
||||
[ 156.15, -57.5, -290.0681 ],
|
||||
[ 178.8951, -61.3259, -290.0681 ],
|
||||
[ 201.7362, -65.0317, -290.0681 ],
|
||||
[ 224.7695, -68.497, -290.0681 ],
|
||||
[ 248.0909, -71.6018, -290.0681 ],
|
||||
[ 271.7966, -74.2259, -290.0681 ],
|
||||
[ 295.9826, -76.249, -290.0681 ],
|
||||
[ 320.745, -77.551, -290.0681 ],
|
||||
[ 346.1798, -78.0117, -290.0681 ]
|
||||
]
|
||||
|
||||
# secondaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 230.7201, -40.4426, -290.0681 ],
|
||||
[ 238.6832, -40.8257, -290.0681 ],
|
||||
[ 246.3475, -41.9085, -290.0681 ],
|
||||
[ 253.7557, -43.5909, -290.0681 ],
|
||||
[ 260.9506, -45.773, -290.0681 ],
|
||||
[ 267.9748, -48.355, -290.0681 ],
|
||||
[ 274.871, -51.2367, -290.0681 ],
|
||||
[ 281.6818, -54.3184, -290.0681 ],
|
||||
[ 288.45, -57.5, -290.0681 ],
|
||||
[ 295.2181, -60.6816, -290.0681 ],
|
||||
[ 302.029, -63.7633, -290.0681 ],
|
||||
[ 308.9251, -66.645, -290.0681 ],
|
||||
[ 315.9494, -69.227, -290.0681 ],
|
||||
[ 323.1442, -71.4091, -290.0681 ],
|
||||
[ 330.5525, -73.0915, -290.0681 ],
|
||||
[ 338.2168, -74.1743, -290.0681 ],
|
||||
[ 346.1798, -74.5574, -290.0681 ]
|
||||
]
|
||||
|
||||
# secondaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ 32.2702, -37.3632, 290.0681 ],
|
||||
[ 53.3195, -37.8155, 290.0681 ],
|
||||
[ 73.7968, -39.0937, 290.0681 ],
|
||||
[ 93.7839, -41.0799, 290.0681 ],
|
||||
[ 113.3624, -43.656, 290.0681 ],
|
||||
[ 132.614, -46.704, 290.0681 ],
|
||||
[ 151.6206, -50.106, 290.0681 ],
|
||||
[ 170.4636, -53.744, 290.0681 ],
|
||||
[ 189.225, -57.5, 290.0681 ],
|
||||
[ 207.9864, -61.256, 290.0681 ],
|
||||
[ 226.8294, -64.894, 290.0681 ],
|
||||
[ 245.8359, -68.296, 290.0681 ],
|
||||
[ 265.0875, -71.344, 290.0681 ],
|
||||
[ 284.6661, -73.9201, 290.0681 ],
|
||||
[ 304.6531, -75.9063, 290.0681 ],
|
||||
[ 325.1305, -77.1845, 290.0681 ],
|
||||
[ 346.1798, -77.6368, 290.0681 ]
|
||||
]
|
||||
|
||||
# secondaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ 164.5702, -38.7945, 290.0681 ],
|
||||
[ 176.8768, -39.2146, 290.0681 ],
|
||||
[ 188.801, -40.402, 290.0681 ],
|
||||
[ 200.3974, -42.247, 290.0681 ],
|
||||
[ 211.7207, -44.64, 290.0681 ],
|
||||
[ 222.8255, -47.4714, 290.0681 ],
|
||||
[ 233.7664, -50.6316, 290.0681 ],
|
||||
[ 244.598, -54.011, 290.0681 ],
|
||||
[ 255.375, -57.5, 290.0681 ],
|
||||
[ 266.152, -60.989, 290.0681 ],
|
||||
[ 276.9836, -64.3684, 290.0681 ],
|
||||
[ 287.9245, -67.5286, 290.0681 ],
|
||||
[ 299.0292, -70.36, 290.0681 ],
|
||||
[ 310.3525, -72.753, 290.0681 ],
|
||||
[ 321.9489, -74.598, 290.0681 ],
|
||||
[ 333.8732, -75.7854, 290.0681 ],
|
||||
[ 346.1798, -76.2055, 290.0681 ]
|
||||
]
|
||||
|
||||
# bank_collectors 1
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ 383.0201, -80, -294.0319 ],
|
||||
[ 417.8478, -80, -295.272 ],
|
||||
[ 451.5734, -80, -298.7767 ],
|
||||
[ 484.3543, -80, -304.2224 ],
|
||||
[ 516.3481, -80, -311.2857 ],
|
||||
[ 547.7121, -80, -319.643 ],
|
||||
[ 578.6038, -80, -328.9709 ],
|
||||
[ 609.1806, -80, -338.9457 ],
|
||||
[ 639.6, -80, -349.2441 ],
|
||||
[ 670.0194, -80, -359.5425 ],
|
||||
[ 700.5962, -80, -369.5174 ],
|
||||
[ 731.4879, -80, -378.8453 ],
|
||||
[ 762.852, -80, -387.2026 ],
|
||||
[ 794.8456, -80, -394.2659 ],
|
||||
[ 827.6266, -80, -399.7116 ],
|
||||
[ 861.3521, -80, -403.2163 ],
|
||||
[ 896.1799, -80, -404.4564 ]
|
||||
]
|
||||
|
||||
# bank_collectors 2
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 383.0201, -80, 294.0319 ],
|
||||
[ 417.8478, -80, 295.272 ],
|
||||
[ 451.5734, -80, 298.7767 ],
|
||||
[ 484.3543, -80, 304.2224 ],
|
||||
[ 516.3481, -80, 311.2857 ],
|
||||
[ 547.7121, -80, 319.643 ],
|
||||
[ 578.6038, -80, 328.9709 ],
|
||||
[ 609.1806, -80, 338.9457 ],
|
||||
[ 639.6, -80, 349.2441 ],
|
||||
[ 670.0194, -80, 359.5425 ],
|
||||
[ 700.5962, -80, 369.5174 ],
|
||||
[ 731.4879, -80, 378.8453 ],
|
||||
[ 762.852, -80, 387.2026 ],
|
||||
[ 794.8456, -80, 394.2659 ],
|
||||
[ 827.6266, -80, 399.7116 ],
|
||||
[ 861.3521, -80, 403.2163 ],
|
||||
[ 896.1799, -80, 404.4564 ]
|
||||
]
|
||||
|
||||
# tailpipes 1
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 933.0202, -80, -408.4201 ],
|
||||
[ 2183.0201, -80, -408.4201 ]
|
||||
]
|
||||
|
||||
# tailpipes 2
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 933.0202, -80, 408.4201 ],
|
||||
[ 2183.0201, -80, 408.4201 ]
|
||||
]
|
||||
|
||||
# crossover
|
||||
[[geometry.pipes]]
|
||||
index = 25
|
||||
points_mm = [
|
||||
[ 914.6, -80, -390 ],
|
||||
[ 914.6, -80, 390 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 334.9036, 0 ]
|
||||
size_mm = [ 529.2, 40.3753, 374.4163 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -52.3, -35, -290.0681 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 212.3, -35, -290.0681 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 13.85, -35, 290.0681 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 146.15, -35, 290.0681 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_4"
|
||||
center_mm = [ 364.6, -80, -290.0681 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_5"
|
||||
center_mm = [ 364.6, -80, 290.0681 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_6"
|
||||
center_mm = [ 914.6, -80, -408.4201 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_7"
|
||||
center_mm = [ 914.6, -80, 408.4201 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "busso"
|
||||
name = "Busso-inspired / 3.0 V6"
|
||||
category = "V6"
|
||||
@@ -7,9 +7,11 @@ description = "Estimated concept calibration / EFI"
|
||||
order = 26
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 6
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 600.0, 480.0, 360.0, 240.0, 120.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 6.0
|
||||
starter_torque_nm = 73.97478
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 29.76
|
||||
exhaust_valve_lift_mm = 8.370001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 35.34
|
||||
intake_valve_lift_mm = 9.3
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 130.68
|
||||
stroke_mm = 72.6
|
||||
@@ -101,26 +96,348 @@ system = "injection"
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 6
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 6
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.169037],
|
||||
[350.000, 0.638054],
|
||||
[355.000, 1.349914],
|
||||
[360.000, 2.247475],
|
||||
[365.000, 3.273600],
|
||||
[370.000, 4.371149],
|
||||
[375.000, 5.482982],
|
||||
[380.000, 6.551962],
|
||||
[385.000, 7.520947],
|
||||
[390.000, 8.332800],
|
||||
[395.000, 8.930381],
|
||||
[400.000, 9.256550],
|
||||
[402.500, 9.300000],
|
||||
[527.500, 9.300000],
|
||||
[532.500, 9.130963],
|
||||
[537.500, 8.661946],
|
||||
[542.500, 7.950086],
|
||||
[547.500, 7.052525],
|
||||
[552.500, 6.026400],
|
||||
[557.500, 4.928851],
|
||||
[562.500, 3.817018],
|
||||
[567.500, 2.748038],
|
||||
[572.500, 1.779053],
|
||||
[577.500, 0.967200],
|
||||
[582.500, 0.369619],
|
||||
[587.500, 0.043450],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.140960],
|
||||
[140.000, 0.533364],
|
||||
[145.000, 1.131493],
|
||||
[150.000, 1.889632],
|
||||
[155.000, 2.762062],
|
||||
[160.000, 3.703068],
|
||||
[165.000, 4.666933],
|
||||
[170.000, 5.607939],
|
||||
[175.000, 6.480369],
|
||||
[180.000, 7.238508],
|
||||
[185.000, 7.836637],
|
||||
[190.000, 8.229041],
|
||||
[195.000, 8.370001],
|
||||
[325.000, 8.370001],
|
||||
[330.000, 8.229041],
|
||||
[335.000, 7.836637],
|
||||
[340.000, 7.238508],
|
||||
[345.000, 6.480369],
|
||||
[350.000, 5.607939],
|
||||
[355.000, 4.666933],
|
||||
[360.000, 3.703068],
|
||||
[365.000, 2.762062],
|
||||
[370.000, 1.889632],
|
||||
[375.000, 1.131493],
|
||||
[380.000, 0.533364],
|
||||
[385.000, 0.140960],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -111, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 111, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -111, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 111, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -366.5, 459.3216, 0 ],
|
||||
[ -166.5, 459.3216, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -111, 413.2667, -51.3072 ],
|
||||
[ -111, 163.2667, -51.3072 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 0, 413.2667, -51.3072 ],
|
||||
[ 0, 163.2667, -51.3072 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 111, 413.2667, -51.3072 ],
|
||||
[ 111, 163.2667, -51.3072 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ -111, 413.2667, 51.3072 ],
|
||||
[ -111, 163.2667, 51.3072 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 0, 413.2667, 51.3072 ],
|
||||
[ 0, 163.2667, 51.3072 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ 111, 413.2667, 51.3072 ],
|
||||
[ 111, 163.2667, 51.3072 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -111, 121.4167, -123.7935 ],
|
||||
[ -109.1317, 108.6131, -136.7179 ],
|
||||
[ -103.8516, 95.8547, -143.7139 ],
|
||||
[ -95.6472, 83.2494, -145.3017 ],
|
||||
[ -85.0059, 70.9048, -142.0016 ],
|
||||
[ -72.415, 58.9287, -134.3337 ],
|
||||
[ -58.3619, 47.4287, -122.818 ],
|
||||
[ -43.334, 36.5127, -107.9749 ],
|
||||
[ -27.8188, 26.2884, -90.3245 ],
|
||||
[ -12.3035, 16.8635, -70.387 ],
|
||||
[ 2.7243, 8.3456, -48.6825 ],
|
||||
[ 16.7774, 0.8427, -25.7311 ],
|
||||
[ 29.3683, -5.5377, -2.0532 ],
|
||||
[ 40.0096, -10.6877, 21.8312 ],
|
||||
[ 48.214, -14.4997, 45.4019 ],
|
||||
[ 53.4941, -16.8659, 68.1387 ],
|
||||
[ 55.3624, -17.6786, 89.5215 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 0, 121.4167, -123.7935 ],
|
||||
[ 0.8855, 110.0026, -134.8242 ],
|
||||
[ 3.3879, 98.2756, -140.1187 ],
|
||||
[ 7.2762, 86.3804, -140.21 ],
|
||||
[ 12.3195, 74.4619, -135.6312 ],
|
||||
[ 18.2867, 62.6649, -126.9155 ],
|
||||
[ 24.947, 51.1341, -114.596 ],
|
||||
[ 32.0692, 40.0143, -99.2058 ],
|
||||
[ 39.4224, 29.4503, -81.2781 ],
|
||||
[ 46.7756, 19.5869, -61.3459 ],
|
||||
[ 53.8978, 10.5688, -39.9424 ],
|
||||
[ 60.558, 2.5409, -17.6007 ],
|
||||
[ 66.5253, -4.352, 5.1461 ],
|
||||
[ 71.5685, -9.9652, 27.7648 ],
|
||||
[ 75.4569, -14.1539, 49.7224 ],
|
||||
[ 77.9593, -16.7733, 70.4856 ],
|
||||
[ 78.8447, -17.6786, 89.5215 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 111, 121.4167, -123.7935 ],
|
||||
[ 110.9026, 110.4379, -134.231 ],
|
||||
[ 110.6273, 99.0339, -138.9924 ],
|
||||
[ 110.1996, 87.3613, -138.6148 ],
|
||||
[ 109.6449, 75.5763, -133.6355 ],
|
||||
[ 108.9885, 63.8354, -124.5916 ],
|
||||
[ 108.2558, 52.2949, -112.0203 ],
|
||||
[ 107.4724, 41.1112, -96.4587 ],
|
||||
[ 106.6635, 30.4408, -78.4441 ],
|
||||
[ 105.8547, 20.4401, -58.5136 ],
|
||||
[ 105.0712, 11.2653, -37.2044 ],
|
||||
[ 104.3386, 3.073, -15.0537 ],
|
||||
[ 103.6822, -3.9805, 7.4014 ],
|
||||
[ 103.1275, -9.7389, 29.6236 ],
|
||||
[ 102.6997, -14.0456, 51.0758 ],
|
||||
[ 102.4245, -16.7443, 71.2209 ],
|
||||
[ 102.3271, -17.6786, 89.5215 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -111, 121.4167, 123.7935 ],
|
||||
[ -110.0686, 112.54, 133.3156 ],
|
||||
[ -107.3627, 102.9428, 140.7747 ],
|
||||
[ -103.0145, 92.8035, 146.3708 ],
|
||||
[ -97.1563, 82.3007, 150.3036 ],
|
||||
[ -89.9205, 71.6126, 152.7732 ],
|
||||
[ -81.4393, 60.9178, 153.9794 ],
|
||||
[ -71.845, 50.3947, 154.1221 ],
|
||||
[ -61.2699, 40.2217, 153.4011 ],
|
||||
[ -49.8463, 30.5773, 152.0164 ],
|
||||
[ -37.7065, 21.6399, 150.1678 ],
|
||||
[ -24.9827, 13.5879, 148.0551 ],
|
||||
[ -11.8074, 6.5997, 145.8784 ],
|
||||
[ 1.6873, 0.8539, 143.8375 ],
|
||||
[ 15.369, -3.4712, 142.1322 ],
|
||||
[ 29.1054, -6.1971, 140.9624 ],
|
||||
[ 42.7643, -7.1453, 140.5281 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 0, 121.4167, 123.7935 ],
|
||||
[ 0.7587, 115.5283, 130.3663 ],
|
||||
[ 2.9028, 109.4543, 135.6078 ],
|
||||
[ 6.2345, 103.19, 139.6432 ],
|
||||
[ 10.5557, 96.7306, 142.5977 ],
|
||||
[ 15.6686, 90.0711, 144.5966 ],
|
||||
[ 21.3753, 83.2068, 145.7648 ],
|
||||
[ 27.4778, 76.1328, 146.2277 ],
|
||||
[ 33.7783, 68.8444, 146.1105 ],
|
||||
[ 40.0787, 61.3366, 145.5382 ],
|
||||
[ 46.1812, 53.6047, 144.6361 ],
|
||||
[ 51.8879, 45.6438, 143.5293 ],
|
||||
[ 57.0008, 37.4491, 142.3431 ],
|
||||
[ 61.3221, 29.0157, 141.2026 ],
|
||||
[ 64.6537, 20.339, 140.2329 ],
|
||||
[ 66.7978, 11.4139, 139.5593 ],
|
||||
[ 67.5565, 2.2357, 139.307 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 111, 121.4167, 123.7935 ],
|
||||
[ 110.9165, 116.1043, 129.5562 ],
|
||||
[ 110.6807, 110.3205, 134.1964 ],
|
||||
[ 110.3142, 104.1052, 137.8177 ],
|
||||
[ 109.8389, 97.4984, 140.5239 ],
|
||||
[ 109.2765, 90.54, 142.4182 ],
|
||||
[ 108.6487, 83.2702, 143.6045 ],
|
||||
[ 107.9774, 75.7288, 144.1863 ],
|
||||
[ 107.2844, 67.9558, 144.267 ],
|
||||
[ 106.5913, 59.9913, 143.9504 ],
|
||||
[ 105.9201, 51.8753, 143.3399 ],
|
||||
[ 105.2923, 43.6476, 142.5392 ],
|
||||
[ 104.7299, 35.3484, 141.6518 ],
|
||||
[ 104.2546, 27.0177, 140.7813 ],
|
||||
[ 103.8881, 18.6953, 140.0313 ],
|
||||
[ 103.6522, 10.4213, 139.5053 ],
|
||||
[ 103.5688, 2.2357, 139.307 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ 157.2357, -55, 146.7572 ],
|
||||
[ 1657.2357, -55, 146.7572 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 459.3216, 0 ]
|
||||
size_mm = [ 333, 92.1099, 195.6144 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 146.7572 ]
|
||||
size_mm = [ 114.4714, 114.4714, 114.4714 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "ej20"
|
||||
name = "EJ20-inspired / 2.0 flat four NA"
|
||||
category = "Boxer / flat four"
|
||||
@@ -7,9 +7,11 @@ description = "Estimated concept calibration / EFI"
|
||||
order = 27
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 180.0
|
||||
collector_volume_litres = 1.0
|
||||
cylinders = 4
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 540.0, 360.0, 180.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 4.0
|
||||
starter_torque_nm = 49.85708
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 29.44
|
||||
exhaust_valve_lift_mm = 8.280001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 34.96
|
||||
intake_valve_lift_mm = 9.2
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 135.0
|
||||
stroke_mm = 75.0
|
||||
@@ -101,26 +96,278 @@ system = "injection"
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 4
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 4
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.167219],
|
||||
[350.000, 0.631194],
|
||||
[355.000, 1.335398],
|
||||
[360.000, 2.223309],
|
||||
[365.000, 3.238400],
|
||||
[370.000, 4.324147],
|
||||
[375.000, 5.424026],
|
||||
[380.000, 6.481510],
|
||||
[385.000, 7.440077],
|
||||
[390.000, 8.243200],
|
||||
[395.000, 8.834355],
|
||||
[400.000, 9.157018],
|
||||
[402.500, 9.200000],
|
||||
[527.500, 9.200000],
|
||||
[532.500, 9.032781],
|
||||
[537.500, 8.568806],
|
||||
[542.500, 7.864602],
|
||||
[547.500, 6.976691],
|
||||
[552.500, 5.961600],
|
||||
[557.500, 4.875853],
|
||||
[562.500, 3.775974],
|
||||
[567.500, 2.718490],
|
||||
[572.500, 1.759923],
|
||||
[577.500, 0.956800],
|
||||
[582.500, 0.365645],
|
||||
[587.500, 0.042982],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.139445],
|
||||
[140.000, 0.527629],
|
||||
[145.000, 1.119326],
|
||||
[150.000, 1.869313],
|
||||
[155.000, 2.732363],
|
||||
[160.000, 3.663250],
|
||||
[165.000, 4.616751],
|
||||
[170.000, 5.547638],
|
||||
[175.000, 6.410688],
|
||||
[180.000, 7.160675],
|
||||
[185.000, 7.752372],
|
||||
[190.000, 8.140556],
|
||||
[195.000, 8.280001],
|
||||
[325.000, 8.280001],
|
||||
[330.000, 8.140556],
|
||||
[335.000, 7.752372],
|
||||
[340.000, 7.160675],
|
||||
[345.000, 6.410688],
|
||||
[350.000, 5.547638],
|
||||
[355.000, 4.616751],
|
||||
[360.000, 3.663250],
|
||||
[365.000, 2.732363],
|
||||
[370.000, 1.869313],
|
||||
[375.000, 1.119326],
|
||||
[380.000, 0.527629],
|
||||
[385.000, 0.139445],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -55, 0, 0 ]
|
||||
tilt_deg = -90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 55, 0, 0 ]
|
||||
tilt_deg = -90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -55, 0, 0 ]
|
||||
tilt_deg = 90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 55, 0, 0 ]
|
||||
tilt_deg = 90.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -310, 307.5713, 0 ],
|
||||
[ -110, 307.5713, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -55, 286.8, -172.8334 ],
|
||||
[ -55, 36.8, -172.8334 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 55, 286.8, -172.8334 ],
|
||||
[ 55, 36.8, -172.8334 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ -55, 286.8, 172.8334 ],
|
||||
[ -55, 36.8, 172.8334 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 55, 286.8, 172.8334 ],
|
||||
[ 55, 36.8, 172.8334 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -55, -46, -172.8334 ],
|
||||
[ -53.4569, -70.3798, -166.4422 ],
|
||||
[ -49.0959, -88.6617, -155.8208 ],
|
||||
[ -42.3196, -101.4701, -141.3612 ],
|
||||
[ -33.5305, -109.4294, -123.455 ],
|
||||
[ -23.1312, -113.164, -102.4941 ],
|
||||
[ -11.5242, -113.2982, -78.8702 ],
|
||||
[ 0.8879, -110.4563, -52.9752 ],
|
||||
[ 13.7025, -105.2628, -25.2009 ],
|
||||
[ 26.5171, -98.342, 4.0609 ],
|
||||
[ 38.9292, -90.3182, 34.4185 ],
|
||||
[ 50.5362, -81.8159, 65.48 ],
|
||||
[ 60.9355, -73.4593, 96.8536 ],
|
||||
[ 69.7246, -65.873, 128.1476 ],
|
||||
[ 76.5009, -59.6811, 158.97 ],
|
||||
[ 80.8619, -55.5081, 188.9292 ],
|
||||
[ 82.405, -53.9784, 217.6334 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ 55, -46, -172.8334 ],
|
||||
[ 55.448, -69.1222, -166.546 ],
|
||||
[ 56.7141, -86.4707, -155.833 ],
|
||||
[ 58.6814, -98.6364, -141.125 ],
|
||||
[ 61.2331, -106.2101, -122.8528 ],
|
||||
[ 64.2522, -109.7826, -101.4471 ],
|
||||
[ 67.622, -109.9447, -77.3387 ],
|
||||
[ 71.2255, -107.2873, -50.9582 ],
|
||||
[ 74.9459, -102.4012, -22.7365 ],
|
||||
[ 78.6663, -95.8772, 6.8957 ],
|
||||
[ 82.2698, -88.3061, 37.5077 ],
|
||||
[ 85.6395, -80.2789, 68.6687 ],
|
||||
[ 88.6587, -72.3862, 99.948 ],
|
||||
[ 91.2104, -65.219, 130.9149 ],
|
||||
[ 93.1777, -59.3681, 161.1385 ],
|
||||
[ 94.4438, -55.4243, 190.1883 ],
|
||||
[ 94.8918, -53.9784, 217.6334 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -55, -46, 172.8334 ],
|
||||
[ -54.3082, -53.2985, 172.4701 ],
|
||||
[ -52.3079, -58.8583, 173.7033 ],
|
||||
[ -49.1117, -62.8543, 176.3161 ],
|
||||
[ -44.8324, -65.4615, 180.0913 ],
|
||||
[ -39.5825, -66.8548, 184.8119 ],
|
||||
[ -33.4748, -67.2092, 190.2608 ],
|
||||
[ -26.6219, -66.6995, 196.2209 ],
|
||||
[ -19.1364, -65.5008, 202.4752 ],
|
||||
[ -11.1311, -63.7879, 208.8066 ],
|
||||
[ -2.7185, -61.7358, 214.9981 ],
|
||||
[ 5.9887, -59.5194, 220.8326 ],
|
||||
[ 14.8778, -57.3138, 226.093 ],
|
||||
[ 23.8361, -55.2938, 230.5623 ],
|
||||
[ 32.751, -53.6343, 234.0234 ],
|
||||
[ 41.5099, -52.5103, 236.2592 ],
|
||||
[ 50, -52.0968, 237.0527 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 55, -46, 172.8334 ],
|
||||
[ 55.2388, -48.968, 172.7016 ],
|
||||
[ 55.9138, -51.2704, 173.2603 ],
|
||||
[ 56.9625, -52.9727, 174.4452 ],
|
||||
[ 58.3228, -54.1402, 176.1922 ],
|
||||
[ 59.9323, -54.8385, 178.4371 ],
|
||||
[ 61.7286, -55.1329, 181.1157 ],
|
||||
[ 63.6496, -55.0888, 184.1638 ],
|
||||
[ 65.6329, -54.7716, 187.5172 ],
|
||||
[ 67.6162, -54.2468, 191.1118 ],
|
||||
[ 69.5372, -53.5797, 194.8832 ],
|
||||
[ 71.3336, -52.8358, 198.7675 ],
|
||||
[ 72.943, -52.0805, 202.7003 ],
|
||||
[ 74.3033, -51.3792, 206.6174 ],
|
||||
[ 75.3521, -50.7972, 210.4548 ],
|
||||
[ 76.027, -50.4001, 214.1482 ],
|
||||
[ 76.2658, -50.2532, 217.6334 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 150, -55, 267.6333 ],
|
||||
[ 1649.9999, -55, 267.6333 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 307.5713, 0 ]
|
||||
size_mm = [ 220, 41.5426, 437.6667 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 267.6333 ]
|
||||
size_mm = [ 100, 100, 100 ]
|
||||
|
||||
348
engines/f20.toml
348
engines/f20.toml
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "f20"
|
||||
name = "F20C-inspired / 2.0 high-rev four"
|
||||
category = "Inline four / specials"
|
||||
@@ -7,9 +7,11 @@ description = "Unequal primaries / small junctions / staged collectors / EFI"
|
||||
order = 22
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 1.0
|
||||
cylinders = 4
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 180.0, 540.0, 360.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 4.0
|
||||
starter_torque_nm = 49.9353
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "staged"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 27.84
|
||||
exhaust_valve_lift_mm = 7.83
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 33.06
|
||||
intake_valve_lift_mm = 8.7
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 151.2
|
||||
stroke_mm = 84.0
|
||||
@@ -101,59 +96,356 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 4
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_1"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_2"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_3"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_4"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_9"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_10"
|
||||
cells = 9
|
||||
diameter_mm = 48.0
|
||||
length_mm = 420.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_11"
|
||||
cells = 11
|
||||
diameter_mm = 48.0
|
||||
length_mm = 540.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.158131],
|
||||
[350.000, 0.596890],
|
||||
[355.000, 1.262822],
|
||||
[360.000, 2.102477],
|
||||
[365.000, 3.062400],
|
||||
[370.000, 4.089139],
|
||||
[375.000, 5.129242],
|
||||
[380.000, 6.129254],
|
||||
[385.000, 7.035725],
|
||||
[390.000, 7.795200],
|
||||
[395.000, 8.354227],
|
||||
[400.000, 8.659354],
|
||||
[402.500, 8.700000],
|
||||
[527.500, 8.700000],
|
||||
[532.500, 8.541869],
|
||||
[537.500, 8.103110],
|
||||
[542.500, 7.437178],
|
||||
[547.500, 6.597523],
|
||||
[552.500, 5.637600],
|
||||
[557.500, 4.610861],
|
||||
[562.500, 3.570758],
|
||||
[567.500, 2.570746],
|
||||
[572.500, 1.664275],
|
||||
[577.500, 0.904800],
|
||||
[582.500, 0.345773],
|
||||
[587.500, 0.040646],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.131866],
|
||||
[140.000, 0.498953],
|
||||
[145.000, 1.058493],
|
||||
[150.000, 1.767720],
|
||||
[155.000, 2.583864],
|
||||
[160.000, 3.464160],
|
||||
[165.000, 4.365840],
|
||||
[170.000, 5.246136],
|
||||
[175.000, 6.062280],
|
||||
[180.000, 6.771507],
|
||||
[185.000, 7.331047],
|
||||
[190.000, 7.698134],
|
||||
[195.000, 7.830000],
|
||||
[325.000, 7.830000],
|
||||
[330.000, 7.698134],
|
||||
[335.000, 7.331047],
|
||||
[340.000, 6.771507],
|
||||
[345.000, 6.062280],
|
||||
[350.000, 5.246136],
|
||||
[355.000, 4.365840],
|
||||
[360.000, 3.464160],
|
||||
[365.000, 2.583864],
|
||||
[370.000, 1.767720],
|
||||
[375.000, 1.058493],
|
||||
[380.000, 0.498953],
|
||||
[385.000, 0.131866],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -157.5, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -52.5, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 52.5, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 157.5, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -410, 194.5333, -363.1 ],
|
||||
[ -210, 194.5333, -363.1 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -157.5, 194.5333, -284.8 ],
|
||||
[ -157.5, 194.5333, -34.8 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -52.5, 194.5333, -284.8 ],
|
||||
[ -52.5, 194.5333, -34.8 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 52.5, 194.5333, -284.8 ],
|
||||
[ 52.5, 194.5333, -34.8 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 157.5, 194.5333, -284.8 ],
|
||||
[ 157.5, 194.5333, -34.8 ]
|
||||
]
|
||||
|
||||
# primary_1
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -157.5, 194.5333, 43.5 ],
|
||||
[ -156.9599, 191.2299, 56.8381 ],
|
||||
[ -155.4334, 185.7695, 68.1689 ],
|
||||
[ -153.0615, 178.3497, 77.6508 ],
|
||||
[ -149.9852, 169.1678, 85.4419 ],
|
||||
[ -146.3452, 158.4214, 91.7006 ],
|
||||
[ -142.2825, 146.3079, 96.5849 ],
|
||||
[ -137.9379, 133.0247, 100.2531 ],
|
||||
[ -133.4525, 118.7693, 102.8634 ],
|
||||
[ -128.9671, 103.7391, 104.5741 ],
|
||||
[ -124.6226, 88.1316, 105.5434 ],
|
||||
[ -120.5599, 72.1442, 105.9294 ],
|
||||
[ -116.9199, 55.9744, 105.8905 ],
|
||||
[ -113.8435, 39.8197, 105.5848 ],
|
||||
[ -111.4716, 23.8774, 105.1705 ],
|
||||
[ -109.9452, 8.3451, 104.806 ],
|
||||
[ -109.4051, -6.5798, 104.6493 ]
|
||||
]
|
||||
|
||||
# primary_2
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -52.5, 194.5333, 43.5 ],
|
||||
[ -53.0401, 191.2299, 56.8381 ],
|
||||
[ -54.5666, 185.7695, 68.1689 ],
|
||||
[ -56.9385, 178.3497, 77.6508 ],
|
||||
[ -60.0148, 169.1678, 85.4419 ],
|
||||
[ -63.6548, 158.4214, 91.7006 ],
|
||||
[ -67.7175, 146.3079, 96.5849 ],
|
||||
[ -72.062, 133.0247, 100.2531 ],
|
||||
[ -76.5475, 118.7693, 102.8634 ],
|
||||
[ -81.0329, 103.7391, 104.5741 ],
|
||||
[ -85.3774, 88.1316, 105.5434 ],
|
||||
[ -89.4401, 72.1442, 105.9294 ],
|
||||
[ -93.0801, 55.9744, 105.8905 ],
|
||||
[ -96.1565, 39.8197, 105.5848 ],
|
||||
[ -98.5284, 23.8774, 105.1705 ],
|
||||
[ -100.0548, 8.3451, 104.806 ],
|
||||
[ -100.5949, -6.5798, 104.6493 ]
|
||||
]
|
||||
|
||||
# primary_3
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 52.5, 194.5333, 43.5 ],
|
||||
[ 53.0401, 191.1567, 58.187 ],
|
||||
[ 54.5666, 185.761, 71.4839 ],
|
||||
[ 56.9385, 178.5161, 83.4517 ],
|
||||
[ 60.0148, 169.5922, 94.1515 ],
|
||||
[ 63.6548, 159.1591, 103.6443 ],
|
||||
[ 67.7175, 147.387, 111.9912 ],
|
||||
[ 72.062, 134.4458, 119.2533 ],
|
||||
[ 76.5475, 120.5056, 125.4917 ],
|
||||
[ 81.0329, 105.7364, 130.7675 ],
|
||||
[ 85.3774, 90.3081, 135.1416 ],
|
||||
[ 89.4401, 74.3909, 138.6753 ],
|
||||
[ 93.0801, 58.1546, 141.4295 ],
|
||||
[ 96.1565, 41.7694, 143.4654 ],
|
||||
[ 98.5284, 25.4053, 144.8439 ],
|
||||
[ 100.0548, 9.2322, 145.6263 ],
|
||||
[ 100.5949, -6.5798, 145.8735 ]
|
||||
]
|
||||
|
||||
# primary_4
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 157.5, 194.5333, 43.5 ],
|
||||
[ 156.9599, 191.1567, 58.187 ],
|
||||
[ 155.4334, 185.761, 71.4839 ],
|
||||
[ 153.0615, 178.5161, 83.4517 ],
|
||||
[ 149.9852, 169.5922, 94.1515 ],
|
||||
[ 146.3452, 159.1591, 103.6443 ],
|
||||
[ 142.2825, 147.387, 111.9912 ],
|
||||
[ 137.9379, 134.4458, 119.2533 ],
|
||||
[ 133.4525, 120.5056, 125.4917 ],
|
||||
[ 128.9671, 105.7364, 130.7675 ],
|
||||
[ 124.6226, 90.3081, 135.1416 ],
|
||||
[ 120.5599, 74.3909, 138.6753 ],
|
||||
[ 116.9199, 58.1546, 141.4295 ],
|
||||
[ 113.8435, 41.7694, 143.4654 ],
|
||||
[ 111.4716, 25.4053, 144.8439 ],
|
||||
[ 109.9452, 9.2322, 145.6263 ],
|
||||
[ 109.4051, -6.5798, 145.8735 ]
|
||||
]
|
||||
|
||||
# tailpipe_9
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 218.4202, -70, 170.25 ],
|
||||
[ 1718.4201, -70, 170.25 ]
|
||||
]
|
||||
|
||||
# secondary_10
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -86.5798, -27.7177, 113.8736 ],
|
||||
[ -68.2776, -28.1621, 114.4661 ],
|
||||
[ -50.5923, -29.4178, 116.1404 ],
|
||||
[ -33.4358, -31.3689, 118.7419 ],
|
||||
[ -16.7199, -33.8997, 122.1162 ],
|
||||
[ -0.3565, -36.8941, 126.1088 ],
|
||||
[ 15.7426, -40.2362, 130.5649 ],
|
||||
[ 31.6653, -43.8101, 135.3302 ],
|
||||
[ 47.5, -47.5, 140.25 ],
|
||||
[ 63.3347, -51.1899, 145.1698 ],
|
||||
[ 79.2574, -54.7638, 149.9351 ],
|
||||
[ 95.3565, -58.1059, 154.3912 ],
|
||||
[ 111.7199, -61.1003, 158.3838 ],
|
||||
[ 128.4358, -63.6311, 161.7581 ],
|
||||
[ 145.5923, -65.5822, 164.3596 ],
|
||||
[ 163.2777, -66.838, 166.0339 ],
|
||||
[ 181.5798, -67.2823, 166.6264 ]
|
||||
]
|
||||
|
||||
# secondary_11
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 123.4202, -33.7253, 158.1585 ],
|
||||
[ 127.6728, -34.0347, 158.2616 ],
|
||||
[ 131.6784, -34.9091, 158.553 ],
|
||||
[ 135.4722, -36.2677, 159.0059 ],
|
||||
[ 139.0895, -38.0299, 159.5933 ],
|
||||
[ 142.5657, -40.115, 160.2883 ],
|
||||
[ 145.9359, -42.4421, 161.064 ],
|
||||
[ 149.2356, -44.9307, 161.8936 ],
|
||||
[ 152.5, -47.5, 162.75 ],
|
||||
[ 155.7644, -50.0693, 163.6064 ],
|
||||
[ 159.0641, -52.5579, 164.436 ],
|
||||
[ 162.4343, -54.8851, 165.2117 ],
|
||||
[ 165.9105, -56.9701, 165.9067 ],
|
||||
[ 169.5278, -58.7323, 166.4941 ],
|
||||
[ 173.3216, -60.0909, 166.947 ],
|
||||
[ 177.3272, -60.9653, 167.2384 ],
|
||||
[ 181.5798, -61.2747, 167.3415 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 194.5333, -363.1 ]
|
||||
size_mm = [ 420, 60.8162, 156.6 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -105, -25, 110.25 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 105, -25, 155.25 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 200, -70, 170.25 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "fifty"
|
||||
name = "50 cc / little screamer"
|
||||
category = "Two-stroke / 50 cc"
|
||||
@@ -7,16 +7,19 @@ description = "Concept single / transported carb fuel"
|
||||
order = 15
|
||||
cycle = "two_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 100.0
|
||||
|
||||
[two_stroke]
|
||||
reed_pipe_diameter_mm = 40
|
||||
transfer_pipe_diameter_mm = 32
|
||||
initial_rpm = 3000.0
|
||||
starter_torque_nm = 8.0
|
||||
maximum_load_torque_nm = 10.0
|
||||
crankshaft_inertia_kg_m2 = 0.004006997
|
||||
bore_mm = 40.0
|
||||
carburetor_diameter_mm = 19.0
|
||||
crankcase_clearance_cc = 60.10495
|
||||
exhaust = "racing"
|
||||
exhaust_cell_length_mm = 15.0
|
||||
exhaust_duration_deg = 190.0
|
||||
exhaust_width_mm = 26.54048
|
||||
friction_bar = 0.4
|
||||
@@ -66,3 +69,69 @@ final_drive_ratio = 3.769231
|
||||
mass_kg = 170
|
||||
wheel_radius_mm = 331.3
|
||||
gear_ratios = [2.384615, 1.933333, 1.588235, 1.352941, 1.176471, 1.055556]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -228.9558, 1.6102, 0 ],
|
||||
[ -128.9558, 1.6102, 0 ]
|
||||
]
|
||||
|
||||
# reed passage
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -49.5857, 1.6102, 0 ],
|
||||
[ -19.5857, 1.6102, 0 ]
|
||||
]
|
||||
|
||||
# transfer passage
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 19.5857, 21.1959, 0 ],
|
||||
[ 23.8339, 23.9696, 0 ],
|
||||
[ 27.519, 26.7484, 0 ],
|
||||
[ 30.6412, 29.5324, 0 ],
|
||||
[ 33.2004, 32.3215, 0 ],
|
||||
[ 35.1967, 35.1159, 0 ],
|
||||
[ 36.63, 37.9155, 0 ],
|
||||
[ 37.5003, 40.7202, 0 ],
|
||||
[ 37.8077, 43.5301, 0 ],
|
||||
[ 37.5521, 46.3452, 0 ],
|
||||
[ 36.7336, 49.1655, 0 ],
|
||||
[ 35.352, 51.9909, 0 ],
|
||||
[ 33.4076, 54.8215, 0 ],
|
||||
[ 30.9001, 57.6574, 0 ],
|
||||
[ 27.8297, 60.4984, 0 ],
|
||||
[ 24.1963, 63.3446, 0 ],
|
||||
[ 20, 66.1959, 0 ]
|
||||
]
|
||||
|
||||
# exhaust chamber
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 20, 75.9959, 0 ],
|
||||
[ 130.844, 35.652, 0 ],
|
||||
[ 186.9265, -84.6172, 0 ],
|
||||
[ 106.5828, -199.3597, 0 ],
|
||||
[ 10.7422, -199.3597, 0 ],
|
||||
[ -134.7406, -146.4083, 0 ],
|
||||
[ -311.6772, -146.4083, 0 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ -89.2708, 1.6102, 0 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "crankcase"
|
||||
center_mm = [ 0, 1.6102, 0 ]
|
||||
size_mm = [ 39.1715, 39.1715, 39.1715 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "five"
|
||||
name = "Audi-inspired / 2.2 inline five"
|
||||
category = "Inline five"
|
||||
@@ -7,9 +7,11 @@ description = "Unequal primaries / small junctions / staged collectors / EFI"
|
||||
order = 23
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 1.25
|
||||
cylinders = 5
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 576.0, 144.0, 432.0, 288.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 5.0
|
||||
starter_torque_nm = 55.65237
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "staged"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 25.92
|
||||
exhaust_valve_lift_mm = 7.29
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 30.78
|
||||
intake_valve_lift_mm = 8.1
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 155.52
|
||||
stroke_mm = 86.4
|
||||
@@ -101,65 +96,395 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 5
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_1"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_2"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_3"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_4"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_5"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_11"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_12"
|
||||
cells = 9
|
||||
diameter_mm = 48.0
|
||||
length_mm = 420.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_13"
|
||||
cells = 11
|
||||
diameter_mm = 48.0
|
||||
length_mm = 540.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.147226],
|
||||
[350.000, 0.555725],
|
||||
[355.000, 1.175731],
|
||||
[360.000, 1.957478],
|
||||
[365.000, 2.851200],
|
||||
[370.000, 3.807130],
|
||||
[375.000, 4.775501],
|
||||
[380.000, 5.706547],
|
||||
[385.000, 6.550502],
|
||||
[390.000, 7.257600],
|
||||
[395.000, 7.778074],
|
||||
[400.000, 8.062157],
|
||||
[402.500, 8.100000],
|
||||
[527.500, 8.100000],
|
||||
[532.500, 7.952774],
|
||||
[537.500, 7.544275],
|
||||
[542.500, 6.924269],
|
||||
[547.500, 6.142522],
|
||||
[552.500, 5.248800],
|
||||
[557.500, 4.292870],
|
||||
[562.500, 3.324499],
|
||||
[567.500, 2.393453],
|
||||
[572.500, 1.549498],
|
||||
[577.500, 0.842400],
|
||||
[582.500, 0.321926],
|
||||
[587.500, 0.037843],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.122772],
|
||||
[140.000, 0.464543],
|
||||
[145.000, 0.985494],
|
||||
[150.000, 1.645808],
|
||||
[155.000, 2.405667],
|
||||
[160.000, 3.225253],
|
||||
[165.000, 4.064747],
|
||||
[170.000, 4.884333],
|
||||
[175.000, 5.644192],
|
||||
[180.000, 6.304506],
|
||||
[185.000, 6.825457],
|
||||
[190.000, 7.167228],
|
||||
[195.000, 7.290000],
|
||||
[325.000, 7.290000],
|
||||
[330.000, 7.167228],
|
||||
[335.000, 6.825457],
|
||||
[340.000, 6.304506],
|
||||
[345.000, 5.644192],
|
||||
[350.000, 4.884333],
|
||||
[355.000, 4.064747],
|
||||
[360.000, 3.225253],
|
||||
[365.000, 2.405667],
|
||||
[370.000, 1.645808],
|
||||
[375.000, 0.985494],
|
||||
[380.000, 0.464543],
|
||||
[385.000, 0.122772],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -198, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -99, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 99, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 198, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -447.5, 200.32, -355.3 ],
|
||||
[ -247.5, 200.32, -355.3 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -198, 200.32, -282.4 ],
|
||||
[ -198, 200.32, -32.4 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -99, 200.32, -282.4 ],
|
||||
[ -99, 200.32, -32.4 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 0, 200.32, -282.4 ],
|
||||
[ 0, 200.32, -32.4 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 99, 200.32, -282.4 ],
|
||||
[ 99, 200.32, -32.4 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 198, 200.32, -282.4 ],
|
||||
[ 198, 200.32, -32.4 ]
|
||||
]
|
||||
|
||||
# primary_1
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -198, 200.32, 40.5 ],
|
||||
[ -196.9791, 196.8636, 54.8898 ],
|
||||
[ -194.0939, 191.2973, 66.9724 ],
|
||||
[ -189.6107, 183.8025, 76.938 ],
|
||||
[ -183.7958, 174.5606, 84.977 ],
|
||||
[ -176.9157, 163.7531, 91.2796 ],
|
||||
[ -169.2366, 151.5614, 96.0361 ],
|
||||
[ -161.0248, 138.1668, 99.4366 ],
|
||||
[ -152.5467, 123.7508, 101.6714 ],
|
||||
[ -144.0686, 108.4947, 102.9308 ],
|
||||
[ -135.8568, 92.5801, 103.405 ],
|
||||
[ -128.1777, 76.1882, 103.2843 ],
|
||||
[ -121.2975, 59.5006, 102.759 ],
|
||||
[ -115.4827, 42.6985, 102.0192 ],
|
||||
[ -110.9995, 25.9635, 101.2552 ],
|
||||
[ -108.1143, 9.4769, 100.6573 ],
|
||||
[ -107.0934, -6.5798, 100.4157 ]
|
||||
]
|
||||
|
||||
# primary_2
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -99, 200.32, 40.5 ],
|
||||
[ -99, 196.9527, 53.8104 ],
|
||||
[ -99, 191.3077, 65.0919 ],
|
||||
[ -99, 183.5998, 74.5059 ],
|
||||
[ -99, 174.0438, 82.2139 ],
|
||||
[ -99, 162.8545, 88.3773 ],
|
||||
[ -99, 150.2468, 93.1578 ],
|
||||
[ -99, 136.4356, 96.7166 ],
|
||||
[ -99, 121.6356, 99.2152 ],
|
||||
[ -99, 106.0616, 100.8153 ],
|
||||
[ -99, 89.9286, 101.678 ],
|
||||
[ -99, 73.4513, 101.9651 ],
|
||||
[ -99, 56.8446, 101.8379 ],
|
||||
[ -99, 40.3233, 101.4579 ],
|
||||
[ -99, 24.1023, 100.9866 ],
|
||||
[ -99, 8.3963, 100.5854 ],
|
||||
[ -99, -6.5798, 100.4157 ]
|
||||
]
|
||||
|
||||
# primary_3
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 0, 200.32, 40.5 ],
|
||||
[ -1.0209, 196.8636, 54.8898 ],
|
||||
[ -3.9061, 191.2973, 66.9724 ],
|
||||
[ -8.3893, 183.8025, 76.938 ],
|
||||
[ -14.2042, 174.5606, 84.977 ],
|
||||
[ -21.0843, 163.7531, 91.2796 ],
|
||||
[ -28.7634, 151.5614, 96.0361 ],
|
||||
[ -36.9752, 138.1668, 99.4366 ],
|
||||
[ -45.4533, 123.7508, 101.6714 ],
|
||||
[ -53.9314, 108.4947, 102.9308 ],
|
||||
[ -62.1432, 92.5801, 103.405 ],
|
||||
[ -69.8223, 76.1882, 103.2843 ],
|
||||
[ -76.7025, 59.5006, 102.759 ],
|
||||
[ -82.5173, 42.6985, 102.0192 ],
|
||||
[ -87.0005, 25.9635, 101.2552 ],
|
||||
[ -89.8857, 9.4769, 100.6573 ],
|
||||
[ -90.9066, -6.5798, 100.4157 ]
|
||||
]
|
||||
|
||||
# primary_4
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 99, 200.32, 40.5 ],
|
||||
[ 99.5105, 196.8588, 55.4115 ],
|
||||
[ 100.9531, 191.2967, 68.8484 ],
|
||||
[ 103.1947, 183.8133, 80.8814 ],
|
||||
[ 106.1021, 174.5883, 91.5813 ],
|
||||
[ 109.5421, 163.8012, 101.0186 ],
|
||||
[ 113.3817, 151.6317, 109.2643 ],
|
||||
[ 117.4876, 138.2594, 116.3889 ],
|
||||
[ 121.7267, 123.8639, 122.4633 ],
|
||||
[ 125.9657, 108.6248, 127.5582 ],
|
||||
[ 130.0716, 92.7219, 131.7443 ],
|
||||
[ 133.9112, 76.3346, 135.0923 ],
|
||||
[ 137.3512, 59.6426, 137.673 ],
|
||||
[ 140.2586, 42.8255, 139.5571 ],
|
||||
[ 142.5003, 26.063, 140.8153 ],
|
||||
[ 143.9429, 9.5347, 141.5183 ],
|
||||
[ 144.4533, -6.5798, 141.737 ]
|
||||
]
|
||||
|
||||
# primary_5
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ 198, 200.32, 40.5 ],
|
||||
[ 197.4895, 196.8588, 55.4115 ],
|
||||
[ 196.0469, 191.2967, 68.8484 ],
|
||||
[ 193.8053, 183.8133, 80.8814 ],
|
||||
[ 190.8979, 174.5883, 91.5813 ],
|
||||
[ 187.4578, 163.8012, 101.0186 ],
|
||||
[ 183.6183, 151.6317, 109.2643 ],
|
||||
[ 179.5124, 138.2594, 116.3889 ],
|
||||
[ 175.2733, 123.8639, 122.4633 ],
|
||||
[ 171.0343, 108.6248, 127.5582 ],
|
||||
[ 166.9284, 92.7219, 131.7443 ],
|
||||
[ 163.0888, 76.3346, 135.0923 ],
|
||||
[ 159.6487, 59.6426, 137.673 ],
|
||||
[ 156.7414, 42.8255, 139.5571 ],
|
||||
[ 154.4998, 26.063, 140.8153 ],
|
||||
[ 153.0571, 9.5347, 141.5183 ],
|
||||
[ 152.5467, -6.5798, 141.737 ]
|
||||
]
|
||||
|
||||
# tailpipe_11
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 218.4202, -70, 165.75 ],
|
||||
[ 1718.4201, -70, 165.75 ]
|
||||
]
|
||||
|
||||
# secondary_12
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ -80.5798, -27.7723, 109.4464 ],
|
||||
[ -62.6699, -28.2154, 110.0372 ],
|
||||
[ -45.3699, -29.4676, 111.7068 ],
|
||||
[ -28.5928, -31.4134, 114.3012 ],
|
||||
[ -12.2514, -33.9372, 117.6662 ],
|
||||
[ 3.7414, -36.9233, 121.6478 ],
|
||||
[ 19.4729, -40.2562, 126.0916 ],
|
||||
[ 35.03, -43.8203, 130.8438 ],
|
||||
[ 50.5, -47.5, 135.75 ],
|
||||
[ 65.97, -51.1797, 140.6562 ],
|
||||
[ 81.5271, -54.7438, 145.4084 ],
|
||||
[ 97.2586, -58.0767, 149.8522 ],
|
||||
[ 113.2514, -61.0628, 153.8337 ],
|
||||
[ 129.5928, -63.5866, 157.1988 ],
|
||||
[ 146.3699, -65.5324, 159.7932 ],
|
||||
[ 163.6699, -66.7846, 161.4628 ],
|
||||
[ 181.5798, -67.2277, 162.0536 ]
|
||||
]
|
||||
|
||||
# secondary_13
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ 166.9202, -41.0953, 156.1151 ],
|
||||
[ 168.1884, -41.2391, 156.1631 ],
|
||||
[ 169.3158, -41.6457, 156.2986 ],
|
||||
[ 170.3225, -42.2774, 156.5091 ],
|
||||
[ 171.2287, -43.0968, 156.7823 ],
|
||||
[ 172.0544, -44.0662, 157.1054 ],
|
||||
[ 172.8198, -45.1483, 157.4661 ],
|
||||
[ 173.5449, -46.3054, 157.8518 ],
|
||||
[ 174.25, -47.5, 158.25 ],
|
||||
[ 174.955, -48.6946, 158.6482 ],
|
||||
[ 175.6802, -49.8517, 159.0339 ],
|
||||
[ 176.4456, -50.9338, 159.3946 ],
|
||||
[ 177.2713, -51.9032, 159.7177 ],
|
||||
[ 178.1775, -52.7226, 159.9909 ],
|
||||
[ 179.1842, -53.3543, 160.2014 ],
|
||||
[ 180.3117, -53.7609, 160.337 ],
|
||||
[ 181.5798, -53.9047, 160.3849 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 200.32, -355.3 ]
|
||||
size_mm = [ 495, 69.2799, 145.8 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -99, -25, 105.75 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 148.5, -25, 150.75 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 200, -70, 165.75 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "fivehundred"
|
||||
name = "500 cc / big single"
|
||||
category = "Two-stroke / 500 cc"
|
||||
@@ -7,16 +7,19 @@ description = "Concept single / transported carb fuel"
|
||||
order = 16
|
||||
cycle = "two_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 100.0
|
||||
|
||||
[two_stroke]
|
||||
reed_pipe_diameter_mm = 40
|
||||
transfer_pipe_diameter_mm = 32
|
||||
initial_rpm = 3000.0
|
||||
starter_torque_nm = 8.0
|
||||
maximum_load_torque_nm = 10.0
|
||||
crankshaft_inertia_kg_m2 = 0.04002316
|
||||
bore_mm = 86.0
|
||||
carburetor_diameter_mm = 41.0
|
||||
crankcase_clearance_cc = 600.3475
|
||||
exhaust = "racing"
|
||||
exhaust_cell_length_mm = 15.0
|
||||
exhaust_duration_deg = 190.0
|
||||
exhaust_width_mm = 57.15746
|
||||
friction_bar = 0.4
|
||||
@@ -66,3 +69,69 @@ final_drive_ratio = 3.769231
|
||||
mass_kg = 170
|
||||
wheel_radius_mm = 331.3
|
||||
gear_ratios = [2.384615, 1.933333, 1.588235, 1.352941, 1.176471, 1.055556]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -251.5498, 49.468, 0 ],
|
||||
[ -151.5498, 49.468, 0 ]
|
||||
]
|
||||
|
||||
# reed passage
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -72.1797, 49.468, 0 ],
|
||||
[ -42.1797, 49.468, 0 ]
|
||||
]
|
||||
|
||||
# transfer passage
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 42.1797, 91.6478, 0 ],
|
||||
[ 46.452, 94.3834, 0 ],
|
||||
[ 50.1614, 97.1292, 0 ],
|
||||
[ 53.3081, 99.8853, 0 ],
|
||||
[ 55.8919, 102.6516, 0 ],
|
||||
[ 57.913, 105.4282, 0 ],
|
||||
[ 59.3712, 108.215, 0 ],
|
||||
[ 60.2667, 111.0122, 0 ],
|
||||
[ 60.5993, 113.8195, 0 ],
|
||||
[ 60.3692, 116.6372, 0 ],
|
||||
[ 59.5763, 119.465, 0 ],
|
||||
[ 58.2206, 122.3032, 0 ],
|
||||
[ 56.302, 125.1516, 0 ],
|
||||
[ 53.8207, 128.0103, 0 ],
|
||||
[ 50.7766, 130.8792, 0 ],
|
||||
[ 47.1697, 133.7584, 0 ],
|
||||
[ 43, 136.6478, 0 ]
|
||||
]
|
||||
|
||||
# exhaust chamber
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 43, 192.6478, 0 ],
|
||||
[ 281.7131, 105.7633, 0 ],
|
||||
[ 402.492, -153.248, 0 ],
|
||||
[ 229.4644, -400.3569, 0 ],
|
||||
[ 23.0624, -400.3569, 0 ],
|
||||
[ -290.2485, -286.3211, 0 ],
|
||||
[ -671.2983, -286.321, 0 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ -111.8648, 49.468, 0 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "crankcase"
|
||||
center_mm = [ 0, 49.468, 0 ]
|
||||
size_mm = [ 84.3595, 84.3595, 84.3595 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "flat6"
|
||||
name = "911-inspired / 3.0 flat six"
|
||||
category = "Boxer / flat six"
|
||||
@@ -7,9 +7,11 @@ description = "Estimated concept calibration / EFI"
|
||||
order = 28
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 180.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 6
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 600.0, 480.0, 360.0, 240.0, 120.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 6.0
|
||||
starter_torque_nm = 74.85159
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 30.4
|
||||
exhaust_valve_lift_mm = 8.55
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 36.1
|
||||
intake_valve_lift_mm = 9.5
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 126.72
|
||||
stroke_mm = 70.4
|
||||
@@ -101,26 +96,348 @@ system = "injection"
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 6
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 6
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.172672],
|
||||
[350.000, 0.651776],
|
||||
[355.000, 1.378944],
|
||||
[360.000, 2.295808],
|
||||
[365.000, 3.344000],
|
||||
[370.000, 4.465152],
|
||||
[375.000, 5.600896],
|
||||
[380.000, 6.692864],
|
||||
[385.000, 7.682688],
|
||||
[390.000, 8.512000],
|
||||
[395.000, 9.122432],
|
||||
[400.000, 9.455616],
|
||||
[402.500, 9.500000],
|
||||
[527.500, 9.500000],
|
||||
[532.500, 9.327328],
|
||||
[537.500, 8.848224],
|
||||
[542.500, 8.121056],
|
||||
[547.500, 7.204192],
|
||||
[552.500, 6.156000],
|
||||
[557.500, 5.034848],
|
||||
[562.500, 3.899104],
|
||||
[567.500, 2.807136],
|
||||
[572.500, 1.817312],
|
||||
[577.500, 0.988000],
|
||||
[582.500, 0.377568],
|
||||
[587.500, 0.044384],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.143992],
|
||||
[140.000, 0.544834],
|
||||
[145.000, 1.155826],
|
||||
[150.000, 1.930269],
|
||||
[155.000, 2.821461],
|
||||
[160.000, 3.782704],
|
||||
[165.000, 4.767296],
|
||||
[170.000, 5.728539],
|
||||
[175.000, 6.619731],
|
||||
[180.000, 7.394174],
|
||||
[185.000, 8.005166],
|
||||
[190.000, 8.406008],
|
||||
[195.000, 8.550000],
|
||||
[325.000, 8.550000],
|
||||
[330.000, 8.406008],
|
||||
[335.000, 8.005166],
|
||||
[340.000, 7.394174],
|
||||
[345.000, 6.619731],
|
||||
[350.000, 5.728539],
|
||||
[355.000, 4.767296],
|
||||
[360.000, 3.782704],
|
||||
[365.000, 2.821461],
|
||||
[370.000, 1.930269],
|
||||
[375.000, 1.155826],
|
||||
[380.000, 0.544834],
|
||||
[385.000, 0.143992],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -113, 0, 0 ]
|
||||
tilt_deg = -90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = -90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 113, 0, 0 ]
|
||||
tilt_deg = -90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -113, 0, 0 ]
|
||||
tilt_deg = 90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 90.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 113, 0, 0 ]
|
||||
tilt_deg = 90.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -369.5, 309.1467, 0 ],
|
||||
[ -169.5, 309.1467, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -113, 288, -161.7422 ],
|
||||
[ -113, 38, -161.7422 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 0, 288, -161.7422 ],
|
||||
[ 0, 38, -161.7422 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 113, 288, -161.7422 ],
|
||||
[ 113, 38, -161.7422 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ -113, 288, 161.7422 ],
|
||||
[ -113, 38, 161.7422 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 0, 288, 161.7422 ],
|
||||
[ 0, 38, 161.7422 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ 113, 288, 161.7422 ],
|
||||
[ 113, 38, 161.7422 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -113, -47.5, -161.7422 ],
|
||||
[ -110.9337, -71.4523, -155.6934 ],
|
||||
[ -105.0942, -89.3819, -145.9139 ],
|
||||
[ -96.0205, -101.9065, -132.7278 ],
|
||||
[ -84.2516, -109.644, -116.4591 ],
|
||||
[ -70.3266, -113.2121, -97.4318 ],
|
||||
[ -54.7846, -113.2287, -75.9701 ],
|
||||
[ -38.1644, -110.3116, -52.3978 ],
|
||||
[ -21.0052, -105.0785, -27.0392 ],
|
||||
[ -3.8461, -98.1474, -0.2181 ],
|
||||
[ 12.7741, -90.136, 27.7413 ],
|
||||
[ 28.3162, -81.6621, 56.515 ],
|
||||
[ 42.2412, -73.3435, 85.779 ],
|
||||
[ 54.01, -65.798, 115.2091 ],
|
||||
[ 63.0837, -59.6435, 144.4815 ],
|
||||
[ 68.9232, -55.4977, 173.2719 ],
|
||||
[ 70.9895, -53.9785, 201.2565 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 0, -47.5, -161.7422 ],
|
||||
[ 0.9701, -69.4678, -155.8573 ],
|
||||
[ 3.7116, -85.9244, -145.9331 ],
|
||||
[ 7.9716, -97.4347, -132.3551 ],
|
||||
[ 13.4969, -104.5636, -115.5088 ],
|
||||
[ 20.0344, -107.8759, -95.7796 ],
|
||||
[ 27.3312, -107.9366, -73.5531 ],
|
||||
[ 35.1341, -105.3106, -49.2148 ],
|
||||
[ 43.19, -100.5627, -23.1501 ],
|
||||
[ 51.246, -94.2577, 4.2554 ],
|
||||
[ 59.0489, -86.9607, 32.6163 ],
|
||||
[ 66.3456, -79.2365, 61.547 ],
|
||||
[ 72.8832, -71.65, 90.6621 ],
|
||||
[ 78.4085, -64.7661, 119.5761 ],
|
||||
[ 82.6684, -59.1496, 147.9035 ],
|
||||
[ 85.41, -55.3654, 175.2588 ],
|
||||
[ 86.3801, -53.9785, 201.2565 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 113, -47.5, -161.7422 ],
|
||||
[ 112.8739, -68.8834, -155.9056 ],
|
||||
[ 112.5175, -84.9063, -145.9387 ],
|
||||
[ 111.9637, -96.1179, -132.2453 ],
|
||||
[ 111.2454, -103.0675, -115.2289 ],
|
||||
[ 110.3955, -106.3045, -95.2931 ],
|
||||
[ 109.4469, -106.3782, -72.8414 ],
|
||||
[ 108.4326, -103.8379, -48.2775 ],
|
||||
[ 107.3853, -99.2328, -22.0049 ],
|
||||
[ 106.338, -93.1123, 5.5727 ],
|
||||
[ 105.3236, -86.0257, 34.0518 ],
|
||||
[ 104.3751, -78.5223, 63.0288 ],
|
||||
[ 103.5252, -71.1513, 92.1001 ],
|
||||
[ 102.8069, -64.4622, 120.8621 ],
|
||||
[ 102.2531, -59.0041, 148.9112 ],
|
||||
[ 101.8967, -55.3265, 175.8439 ],
|
||||
[ 101.7706, -53.9785, 201.2565 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -113, -47.5, 161.7422 ],
|
||||
[ -111.9277, -57.604, 161.0304 ],
|
||||
[ -108.8344, -65.2317, 162.1579 ],
|
||||
[ -103.9057, -70.635, 164.8772 ],
|
||||
[ -97.3272, -74.0655, 168.941 ],
|
||||
[ -89.2844, -75.775, 174.1016 ],
|
||||
[ -79.9628, -76.0151, 180.1117 ],
|
||||
[ -69.548, -75.0376, 186.7238 ],
|
||||
[ -58.2255, -73.0943, 193.6904 ],
|
||||
[ -46.1809, -70.4369, 200.7643 ],
|
||||
[ -33.5998, -67.3171, 207.6977 ],
|
||||
[ -20.6676, -63.9866, 214.2434 ],
|
||||
[ -7.57, -60.6972, 220.1539 ],
|
||||
[ 5.5076, -57.7006, 225.1816 ],
|
||||
[ 18.3795, -55.2484, 229.0793 ],
|
||||
[ 30.8603, -53.5926, 231.5993 ],
|
||||
[ 42.7643, -52.9847, 232.4943 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 0, -47.5, 161.7422 ],
|
||||
[ 0.2446, -51.0321, 161.6825 ],
|
||||
[ 0.9577, -53.7288, 162.6064 ],
|
||||
[ 2.1082, -55.6739, 164.3788 ],
|
||||
[ 3.6652, -56.9512, 166.8645 ],
|
||||
[ 5.5977, -57.6445, 169.9283 ],
|
||||
[ 7.8745, -57.8378, 173.4349 ],
|
||||
[ 10.4648, -57.6147, 177.2493 ],
|
||||
[ 13.3376, -57.0593, 181.2361 ],
|
||||
[ 16.4617, -56.2552, 185.2602 ],
|
||||
[ 19.8062, -55.2863, 189.1865 ],
|
||||
[ 23.34, -54.2365, 192.8796 ],
|
||||
[ 27.0322, -53.1895, 196.2044 ],
|
||||
[ 30.8518, -52.2293, 199.0257 ],
|
||||
[ 34.7676, -51.4397, 201.2084 ],
|
||||
[ 38.7488, -50.9044, 202.617 ],
|
||||
[ 42.7643, -50.7073, 203.1167 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 113, -47.5, 161.7422 ],
|
||||
[ 112.9404, -49.8804, 161.6759 ],
|
||||
[ 112.7719, -51.7189, 162.2366 ],
|
||||
[ 112.51, -53.0691, 163.3623 ],
|
||||
[ 112.1704, -53.9844, 164.9911 ],
|
||||
[ 111.7686, -54.5186, 167.0612 ],
|
||||
[ 111.3201, -54.7253, 169.5108 ],
|
||||
[ 110.8405, -54.6579, 172.2777 ],
|
||||
[ 110.3453, -54.3701, 175.3004 ],
|
||||
[ 109.8501, -53.9154, 178.5167 ],
|
||||
[ 109.3705, -53.3476, 181.8648 ],
|
||||
[ 108.922, -52.72, 185.2829 ],
|
||||
[ 108.5202, -52.0865, 188.7091 ],
|
||||
[ 108.1806, -51.5004, 192.0814 ],
|
||||
[ 107.9187, -51.0154, 195.338 ],
|
||||
[ 107.7502, -50.6851, 198.417 ],
|
||||
[ 107.6906, -50.5631, 201.2565 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ 157.2357, -55, 258.4922 ],
|
||||
[ 1657.2357, -55, 258.4922 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 309.1467, 0 ]
|
||||
size_mm = [ 339, 42.2934, 418.4844 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 258.4922 ]
|
||||
size_mm = [ 114.4714, 114.4714, 114.4714 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "ltwin"
|
||||
name = "916-inspired / 90-degree V twin"
|
||||
category = "Twins / V"
|
||||
@@ -7,9 +7,11 @@ description = "Estimated concept calibration / EFI"
|
||||
order = 20
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 90.0
|
||||
collector_volume_litres = 0.5
|
||||
cylinders = 2
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 2.0
|
||||
starter_torque_nm = 22.90127
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 30.08
|
||||
exhaust_valve_lift_mm = 8.46
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 35.72
|
||||
intake_valve_lift_mm = 9.4
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 118.8
|
||||
stroke_mm = 66.0
|
||||
@@ -101,26 +96,208 @@ system = "injection"
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 2
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 2
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.170854],
|
||||
[350.000, 0.644915],
|
||||
[355.000, 1.364429],
|
||||
[360.000, 2.271642],
|
||||
[365.000, 3.308800],
|
||||
[370.000, 4.418150],
|
||||
[375.000, 5.541939],
|
||||
[380.000, 6.622413],
|
||||
[385.000, 7.601818],
|
||||
[390.000, 8.422400],
|
||||
[395.000, 9.026406],
|
||||
[400.000, 9.356083],
|
||||
[402.500, 9.400000],
|
||||
[527.500, 9.400000],
|
||||
[532.500, 9.229146],
|
||||
[537.500, 8.755085],
|
||||
[542.500, 8.035571],
|
||||
[547.500, 7.128358],
|
||||
[552.500, 6.091200],
|
||||
[557.500, 4.981850],
|
||||
[562.500, 3.858061],
|
||||
[567.500, 2.777587],
|
||||
[572.500, 1.798182],
|
||||
[577.500, 0.977600],
|
||||
[582.500, 0.373594],
|
||||
[587.500, 0.043917],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.142476],
|
||||
[140.000, 0.539099],
|
||||
[145.000, 1.143660],
|
||||
[150.000, 1.909950],
|
||||
[155.000, 2.791761],
|
||||
[160.000, 3.742886],
|
||||
[165.000, 4.717114],
|
||||
[170.000, 5.668239],
|
||||
[175.000, 6.550050],
|
||||
[180.000, 7.316340],
|
||||
[185.000, 7.920901],
|
||||
[190.000, 8.317524],
|
||||
[195.000, 8.460000],
|
||||
[325.000, 8.460000],
|
||||
[330.000, 8.317524],
|
||||
[335.000, 7.920901],
|
||||
[340.000, 7.316340],
|
||||
[345.000, 6.550050],
|
||||
[350.000, 5.668239],
|
||||
[355.000, 4.717114],
|
||||
[360.000, 3.742886],
|
||||
[365.000, 2.791761],
|
||||
[370.000, 1.909950],
|
||||
[375.000, 1.143660],
|
||||
[380.000, 0.539099],
|
||||
[385.000, 0.142476],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = -45.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 45.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -256, 418.5291, 0 ],
|
||||
[ -56, 418.5291, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ 0, 383.4546, -80.2802 ],
|
||||
[ 0, 133.4546, -80.2802 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 0, 383.4546, 80.2802 ],
|
||||
[ 0, 133.4546, 80.2802 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 0, 73.6334, -140.1014 ],
|
||||
[ 0.9822, 57.5171, -149.2024 ],
|
||||
[ 3.7581, 42.9223, -151.9312 ],
|
||||
[ 8.0713, 29.7825, -148.899 ],
|
||||
[ 13.6657, 18.0314, -140.717 ],
|
||||
[ 20.285, 7.6023, -127.9962 ],
|
||||
[ 27.6731, -1.5711, -111.348 ],
|
||||
[ 35.5736, -9.5553, -91.3833 ],
|
||||
[ 43.7303, -16.4169, -68.7134 ],
|
||||
[ 51.887, -22.2222, -43.9495 ],
|
||||
[ 59.7875, -27.0379, -17.7026 ],
|
||||
[ 67.1755, -30.9303, 9.416 ],
|
||||
[ 73.7948, -33.9659, 36.7953 ],
|
||||
[ 79.3892, -36.2112, 63.8239 ],
|
||||
[ 83.7025, -37.7327, 89.8909 ],
|
||||
[ 86.4783, -38.5968, 114.385 ],
|
||||
[ 87.4606, -38.8701, 136.6951 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 0, 73.6334, 140.1014 ],
|
||||
[ 0.7766, 67.5842, 144.4533 ],
|
||||
[ 2.9712, 61.9218, 148.2705 ],
|
||||
[ 6.3814, 56.5771, 151.588 ],
|
||||
[ 10.8045, 51.4813, 154.4409 ],
|
||||
[ 16.0379, 46.5657, 156.8641 ],
|
||||
[ 21.8791, 41.7612, 158.8927 ],
|
||||
[ 28.1254, 36.9992, 160.5619 ],
|
||||
[ 34.5744, 32.2106, 161.9065 ],
|
||||
[ 41.0233, 27.3267, 162.9617 ],
|
||||
[ 47.2696, 22.2785, 163.7626 ],
|
||||
[ 53.1108, 16.9973, 164.344 ],
|
||||
[ 58.3442, 11.4142, 164.7412 ],
|
||||
[ 62.7673, 5.4602, 164.9891 ],
|
||||
[ 66.1775, -0.9334, 165.1228 ],
|
||||
[ 68.3721, -7.8355, 165.1773 ],
|
||||
[ 69.1487, -15.315, 165.1877 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 139.685, -55, 176.3802 ],
|
||||
[ 1639.685, -55, 176.3802 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 418.5291, 0 ]
|
||||
size_mm = [ 112, 70.1489, 254.5604 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 176.3802 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "rb26"
|
||||
name = "RB26-inspired / 2.6 inline six NA"
|
||||
category = "Inline six"
|
||||
@@ -7,9 +7,11 @@ description = "Unequal primaries / small junctions / staged collectors / EFI"
|
||||
order = 24
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 6
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 240.0, 480.0, 120.0, 600.0, 360.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 6.0
|
||||
starter_torque_nm = 64.21635
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "staged"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 27.52
|
||||
exhaust_valve_lift_mm = 7.740001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 32.68
|
||||
intake_valve_lift_mm = 8.6
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 132.66
|
||||
stroke_mm = 73.7
|
||||
@@ -101,71 +96,434 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 6
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_1"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_2"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_3"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_4"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_5"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_6"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_13"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_14"
|
||||
cells = 9
|
||||
diameter_mm = 48.0
|
||||
length_mm = 420.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_15"
|
||||
cells = 11
|
||||
diameter_mm = 48.0
|
||||
length_mm = 540.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.156314],
|
||||
[350.000, 0.590029],
|
||||
[355.000, 1.248307],
|
||||
[360.000, 2.078310],
|
||||
[365.000, 3.027200],
|
||||
[370.000, 4.042138],
|
||||
[375.000, 5.070285],
|
||||
[380.000, 6.058803],
|
||||
[385.000, 6.954854],
|
||||
[390.000, 7.705600],
|
||||
[395.000, 8.258202],
|
||||
[400.000, 8.559821],
|
||||
[402.500, 8.600000],
|
||||
[527.500, 8.600000],
|
||||
[532.500, 8.443686],
|
||||
[537.500, 8.009971],
|
||||
[542.500, 7.351693],
|
||||
[547.500, 6.521690],
|
||||
[552.500, 5.572800],
|
||||
[557.500, 4.557862],
|
||||
[562.500, 3.529715],
|
||||
[567.500, 2.541197],
|
||||
[572.500, 1.645146],
|
||||
[577.500, 0.894400],
|
||||
[582.500, 0.341798],
|
||||
[587.500, 0.040179],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.130350],
|
||||
[140.000, 0.493218],
|
||||
[145.000, 1.046327],
|
||||
[150.000, 1.747401],
|
||||
[155.000, 2.554165],
|
||||
[160.000, 3.424343],
|
||||
[165.000, 4.315658],
|
||||
[170.000, 5.185836],
|
||||
[175.000, 5.992600],
|
||||
[180.000, 6.693674],
|
||||
[185.000, 7.246783],
|
||||
[190.000, 7.609651],
|
||||
[195.000, 7.740001],
|
||||
[325.000, 7.740001],
|
||||
[330.000, 7.609651],
|
||||
[335.000, 7.246783],
|
||||
[340.000, 6.693674],
|
||||
[345.000, 5.992600],
|
||||
[350.000, 5.185836],
|
||||
[355.000, 4.315658],
|
||||
[360.000, 3.424343],
|
||||
[365.000, 2.554165],
|
||||
[370.000, 1.747401],
|
||||
[375.000, 1.046327],
|
||||
[380.000, 0.493218],
|
||||
[385.000, 0.130350],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -260, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -156, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -52, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 52, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 156, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 260, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -512, 169.6989, -361.8 ],
|
||||
[ -312, 169.6989, -361.8 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -260, 169.6989, -284.4 ],
|
||||
[ -260, 169.6989, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -156, 169.6989, -284.4 ],
|
||||
[ -156, 169.6989, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ -52, 169.6989, -284.4 ],
|
||||
[ -52, 169.6989, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 52, 169.6989, -284.4 ],
|
||||
[ 52, 169.6989, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 156, 169.6989, -284.4 ],
|
||||
[ 156, 169.6989, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ 260, 169.6989, -284.4 ],
|
||||
[ 260, 169.6989, -34.4 ]
|
||||
]
|
||||
|
||||
# primary_1
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -260, 169.6989, 43 ],
|
||||
[ -258.9425, 166.7079, 55.9219 ],
|
||||
[ -255.954, 162.0061, 66.9219 ],
|
||||
[ -251.3103, 155.731, 76.1501 ],
|
||||
[ -245.2874, 148.0196, 83.7568 ],
|
||||
[ -238.161, 139.0093, 89.8919 ],
|
||||
[ -230.207, 128.8373, 94.7057 ],
|
||||
[ -221.7012, 117.6409, 98.3485 ],
|
||||
[ -212.9196, 105.5573, 100.9702 ],
|
||||
[ -204.138, 92.7238, 102.7211 ],
|
||||
[ -195.6323, 79.2776, 103.7514 ],
|
||||
[ -187.6783, 65.3559, 104.2112 ],
|
||||
[ -180.5519, 51.0961, 104.2507 ],
|
||||
[ -174.5289, 36.6354, 104.02 ],
|
||||
[ -169.8852, 22.111, 103.6693 ],
|
||||
[ -166.8968, 7.6602, 103.3488 ],
|
||||
[ -165.8393, -6.5798, 103.2085 ]
|
||||
]
|
||||
|
||||
# primary_2
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ -156, 169.6989, 43 ],
|
||||
[ -156, 166.8166, 54.605 ],
|
||||
[ -156, 162.0189, 64.6276 ],
|
||||
[ -156, 155.4836, 73.1827 ],
|
||||
[ -156, 147.389, 80.3855 ],
|
||||
[ -156, 137.9129, 86.3509 ],
|
||||
[ -156, 127.2335, 91.194 ],
|
||||
[ -156, 115.5287, 95.0298 ],
|
||||
[ -156, 102.9766, 97.9735 ],
|
||||
[ -156, 89.7552, 100.14 ],
|
||||
[ -156, 76.0426, 101.6444 ],
|
||||
[ -156, 62.0167, 102.6017 ],
|
||||
[ -156, 47.8557, 103.1269 ],
|
||||
[ -156, 33.7375, 103.3352 ],
|
||||
[ -156, 19.8401, 103.3415 ],
|
||||
[ -156, 6.3417, 103.261 ],
|
||||
[ -156, -6.5798, 103.2085 ]
|
||||
]
|
||||
|
||||
# primary_3
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -52, 169.6989, 43 ],
|
||||
[ -53.0575, 166.7079, 55.9219 ],
|
||||
[ -56.046, 162.0061, 66.9219 ],
|
||||
[ -60.6896, 155.731, 76.1501 ],
|
||||
[ -66.7126, 148.0196, 83.7568 ],
|
||||
[ -73.839, 139.0093, 89.8919 ],
|
||||
[ -81.793, 128.8373, 94.7057 ],
|
||||
[ -90.2988, 117.6409, 98.3485 ],
|
||||
[ -99.0804, 105.5573, 100.9702 ],
|
||||
[ -107.8619, 92.7238, 102.7211 ],
|
||||
[ -116.3677, 79.2776, 103.7514 ],
|
||||
[ -124.3217, 65.3559, 104.2112 ],
|
||||
[ -131.4481, 51.0961, 104.2507 ],
|
||||
[ -137.4711, 36.6354, 104.02 ],
|
||||
[ -142.1148, 22.111, 103.6693 ],
|
||||
[ -145.1033, 7.6602, 103.3488 ],
|
||||
[ -146.1607, -6.5798, 103.2085 ]
|
||||
]
|
||||
|
||||
# primary_4
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ 52, 169.6989, 43 ],
|
||||
[ 53.0575, 166.6343, 57.2699 ],
|
||||
[ 56.046, 161.9975, 70.224 ],
|
||||
[ 60.6896, 155.8982, 81.9166 ],
|
||||
[ 66.7126, 148.446, 92.4023 ],
|
||||
[ 73.839, 139.7507, 101.7358 ],
|
||||
[ 81.793, 129.9218, 109.9715 ],
|
||||
[ 90.2988, 119.0691, 117.164 ],
|
||||
[ 99.0804, 107.3023, 123.3678 ],
|
||||
[ 107.8619, 94.731, 128.6374 ],
|
||||
[ 116.3677, 81.465, 133.0275 ],
|
||||
[ 124.3217, 67.6138, 136.5926 ],
|
||||
[ 131.4481, 53.2872, 139.3871 ],
|
||||
[ 137.4711, 38.5949, 141.4657 ],
|
||||
[ 142.1148, 23.6465, 142.8829 ],
|
||||
[ 145.1033, 8.5517, 143.6932 ],
|
||||
[ 146.1607, -6.5798, 143.9512 ]
|
||||
]
|
||||
|
||||
# primary_5
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 156, 169.6989, 43 ],
|
||||
[ 156, 166.7349, 56.0518 ],
|
||||
[ 156, 162.0093, 68.1017 ],
|
||||
[ 156, 155.6694, 79.1718 ],
|
||||
[ 156, 147.8627, 89.284 ],
|
||||
[ 156, 138.7365, 98.4604 ],
|
||||
[ 156, 128.4383, 106.7232 ],
|
||||
[ 156, 117.1154, 114.0943 ],
|
||||
[ 156, 104.9152, 120.5959 ],
|
||||
[ 156, 91.9852, 126.25 ],
|
||||
[ 156, 78.4727, 131.0786 ],
|
||||
[ 156, 64.5251, 135.1038 ],
|
||||
[ 156, 50.2899, 138.3477 ],
|
||||
[ 156, 35.9144, 140.8323 ],
|
||||
[ 156, 21.546, 142.5797 ],
|
||||
[ 156, 7.3321, 143.612 ],
|
||||
[ 156, -6.5798, 143.9512 ]
|
||||
]
|
||||
|
||||
# primary_6
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 260, 169.6989, 43 ],
|
||||
[ 258.9425, 166.6343, 57.2699 ],
|
||||
[ 255.954, 161.9975, 70.224 ],
|
||||
[ 251.3103, 155.8982, 81.9166 ],
|
||||
[ 245.2874, 148.446, 92.4023 ],
|
||||
[ 238.161, 139.7507, 101.7358 ],
|
||||
[ 230.207, 129.9218, 109.9715 ],
|
||||
[ 221.7012, 119.0691, 117.164 ],
|
||||
[ 212.9196, 107.3023, 123.3678 ],
|
||||
[ 204.138, 94.731, 128.6374 ],
|
||||
[ 195.6323, 81.465, 133.0275 ],
|
||||
[ 187.6783, 67.6138, 136.5926 ],
|
||||
[ 180.5519, 53.2872, 139.3871 ],
|
||||
[ 174.5289, 38.5949, 141.4657 ],
|
||||
[ 169.8852, 23.6465, 142.8829 ],
|
||||
[ 166.8968, 8.5517, 143.6932 ],
|
||||
[ 165.8393, -6.5798, 143.9512 ]
|
||||
]
|
||||
|
||||
# tailpipe_13
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ 218.4202, -70, 169.5 ],
|
||||
[ 1718.4201, -70, 169.5 ]
|
||||
]
|
||||
|
||||
# secondary_14
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -137.5798, -27.3284, 112.6045 ],
|
||||
[ -115.9354, -27.7815, 113.2086 ],
|
||||
[ -94.9697, -29.0619, 114.9159 ],
|
||||
[ -74.5859, -31.0515, 117.5686 ],
|
||||
[ -54.6869, -33.632, 121.0094 ],
|
||||
[ -35.1758, -36.6853, 125.0805 ],
|
||||
[ -15.9556, -40.0932, 129.6243 ],
|
||||
[ 3.0707, -43.7375, 134.4834 ],
|
||||
[ 22, -47.5, 139.5 ],
|
||||
[ 40.9293, -51.2625, 144.5166 ],
|
||||
[ 59.9556, -54.9068, 149.3757 ],
|
||||
[ 79.1758, -58.3147, 153.9195 ],
|
||||
[ 98.6869, -61.368, 157.9906 ],
|
||||
[ 118.5859, -63.9485, 161.4314 ],
|
||||
[ 138.9697, -65.9381, 164.0842 ],
|
||||
[ 159.9354, -67.2185, 165.7914 ],
|
||||
[ 181.5798, -67.6716, 166.3955 ]
|
||||
]
|
||||
|
||||
# secondary_15
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 174.0108, -43.4202, 160.6401 ],
|
||||
[ 174.1004, -44.1614, 160.6706 ],
|
||||
[ 174.3536, -44.8101, 160.7569 ],
|
||||
[ 174.7471, -45.3796, 160.8911 ],
|
||||
[ 175.2574, -45.8829, 161.065 ],
|
||||
[ 175.8613, -46.3335, 161.2709 ],
|
||||
[ 176.5352, -46.7443, 161.5006 ],
|
||||
[ 177.2559, -47.1288, 161.7463 ],
|
||||
[ 178, -47.5, 162 ],
|
||||
[ 178.7441, -47.8712, 162.2536 ],
|
||||
[ 179.4648, -48.2557, 162.4994 ],
|
||||
[ 180.1387, -48.6665, 162.7291 ],
|
||||
[ 180.7426, -49.1171, 162.935 ],
|
||||
[ 181.2529, -49.6204, 163.1089 ],
|
||||
[ 181.6464, -50.1899, 163.2431 ],
|
||||
[ 181.8996, -50.8386, 163.3294 ],
|
||||
[ 181.9892, -51.5798, 163.3599 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 169.6989, -361.8 ]
|
||||
size_mm = [ 624, 62.1149, 154.8 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -156, -25, 109.5 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 156, -25, 154.5 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 200, -70, 169.5 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "saab-chambered"
|
||||
name = "Saab B205 / chambered"
|
||||
category = "Inline four / Saab"
|
||||
@@ -7,9 +7,11 @@ description = "Expansion resonator and two-chamber rear muffler"
|
||||
order = 4
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 40.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 0.6
|
||||
cylinders = 4
|
||||
initial_rpm = 1200.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 200.0
|
||||
minimum_substeps = 2
|
||||
phase_degrees = [0.0, 180.0, 540.0, 360.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 3.0
|
||||
starter_torque_nm = 65.0
|
||||
throttle_diameter_mm = 52.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 8.8
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 2
|
||||
exhaust_valve_diameter_mm = 28.0
|
||||
exhaust_valve_lift_mm = 8.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 2
|
||||
intake_valve_diameter_mm = 32.0
|
||||
intake_valve_lift_mm = 8.5
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 153.0
|
||||
stroke_mm = 78.0
|
||||
@@ -115,7 +110,7 @@ loss_coefficient = 0.1
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 2.0
|
||||
type = "expansion"
|
||||
volume_litres = 6.0
|
||||
diameter_mm = 138.1976604
|
||||
|
||||
[silencers.muffler]
|
||||
chambers = 2
|
||||
@@ -125,28 +120,282 @@ loss_coefficient = 0.35
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 4.0
|
||||
type = "chambered"
|
||||
volume_litres = 18.0
|
||||
diameter_mm = 187.7736449
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 8
|
||||
diameter_mm = 60.0
|
||||
length_mm = 150.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 32.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 34.0
|
||||
length_mm = 280.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
profile = "silenced"
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.154496],
|
||||
[350.000, 0.583168],
|
||||
[355.000, 1.233792],
|
||||
[360.000, 2.054144],
|
||||
[365.000, 2.992000],
|
||||
[370.000, 3.995136],
|
||||
[375.000, 5.011328],
|
||||
[380.000, 5.988352],
|
||||
[385.000, 6.873984],
|
||||
[390.000, 7.616000],
|
||||
[395.000, 8.162176],
|
||||
[400.000, 8.460288],
|
||||
[402.500, 8.500000],
|
||||
[527.500, 8.500000],
|
||||
[532.500, 8.345504],
|
||||
[537.500, 7.916832],
|
||||
[542.500, 7.266208],
|
||||
[547.500, 6.445856],
|
||||
[552.500, 5.508000],
|
||||
[557.500, 4.504864],
|
||||
[562.500, 3.488672],
|
||||
[567.500, 2.511648],
|
||||
[572.500, 1.626016],
|
||||
[577.500, 0.884000],
|
||||
[582.500, 0.337824],
|
||||
[587.500, 0.039712],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.134729],
|
||||
[140.000, 0.509786],
|
||||
[145.000, 1.081475],
|
||||
[150.000, 1.806099],
|
||||
[155.000, 2.639964],
|
||||
[160.000, 3.539372],
|
||||
[165.000, 4.460628],
|
||||
[170.000, 5.360036],
|
||||
[175.000, 6.193901],
|
||||
[180.000, 6.918525],
|
||||
[185.000, 7.490214],
|
||||
[190.000, 7.865271],
|
||||
[195.000, 8.000000],
|
||||
[325.000, 8.000000],
|
||||
[330.000, 7.865271],
|
||||
[335.000, 7.490214],
|
||||
[340.000, 6.918525],
|
||||
[345.000, 6.193901],
|
||||
[350.000, 5.360036],
|
||||
[355.000, 4.460628],
|
||||
[360.000, 3.539372],
|
||||
[365.000, 2.639964],
|
||||
[370.000, 1.806099],
|
||||
[375.000, 1.081475],
|
||||
[380.000, 0.509786],
|
||||
[385.000, 0.134729],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -366, 194, -367 ],
|
||||
[ -216, 194, -367 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -162, 194, -286 ],
|
||||
[ -162, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -54, 194, -286 ],
|
||||
[ -54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 54, 194, -286 ],
|
||||
[ 54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 162, 194, -286 ],
|
||||
[ 162, 194, -36 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -162, 194, 45 ],
|
||||
[ -160.763, 188.9129, 64.0687 ],
|
||||
[ -157.153, 180.2477, 79.8812 ],
|
||||
[ -151.3211, 168.5436, 92.717 ],
|
||||
[ -143.4188, 154.3395, 102.8556 ],
|
||||
[ -133.5973, 138.1743, 110.5766 ],
|
||||
[ -122.008, 120.5871, 116.1596 ],
|
||||
[ -108.8022, 102.1169, 119.884 ],
|
||||
[ -94.1311, 83.3026, 122.0296 ],
|
||||
[ -78.1462, 64.6831, 122.8757 ],
|
||||
[ -60.9986, 46.7976, 122.702 ],
|
||||
[ -42.8397, 30.185, 121.7881 ],
|
||||
[ -23.8208, 15.3842, 120.4134 ],
|
||||
[ -4.0933, 2.9342, 118.8576 ],
|
||||
[ 16.1917, -6.6259, 117.4002 ],
|
||||
[ 36.8826, -12.7573, 116.3208 ],
|
||||
[ 57.8284, -14.9208, 115.8988 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -54, 194, 45 ],
|
||||
[ -52.5634, 190.4508, 60.6385 ],
|
||||
[ -48.5035, 184.9694, 73.8883 ],
|
||||
[ -42.1951, 177.702, 84.9399 ],
|
||||
[ -34.0128, 168.7945, 93.9836 ],
|
||||
[ -24.3315, 158.3933, 101.2098 ],
|
||||
[ -13.526, 146.6443, 106.8088 ],
|
||||
[ -1.9709, 133.6937, 110.971 ],
|
||||
[ 9.959, 119.6875, 113.8869 ],
|
||||
[ 21.8888, 104.7719, 115.7468 ],
|
||||
[ 33.4439, 89.093, 116.741 ],
|
||||
[ 44.2495, 72.7969, 117.0599 ],
|
||||
[ 53.9308, 56.0297, 116.8939 ],
|
||||
[ 62.113, 38.9374, 116.4335 ],
|
||||
[ 68.4215, 21.6663, 115.8689 ],
|
||||
[ 72.4814, 4.3623, 115.3905 ],
|
||||
[ 73.9179, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 54, 194, 45 ],
|
||||
[ 54.4291, 190.6029, 58.7971 ],
|
||||
[ 55.6418, 184.9872, 70.6803 ],
|
||||
[ 57.5261, 177.3561, 80.7907 ],
|
||||
[ 59.9702, 167.9128, 89.2697 ],
|
||||
[ 62.862, 156.8603, 96.2586 ],
|
||||
[ 66.0897, 144.4017, 101.8985 ],
|
||||
[ 69.5412, 130.7403, 106.3308 ],
|
||||
[ 73.1046, 116.0791, 109.6968 ],
|
||||
[ 76.6681, 100.6212, 112.1377 ],
|
||||
[ 80.1196, 84.5698, 113.7948 ],
|
||||
[ 83.3472, 68.1279, 114.8094 ],
|
||||
[ 86.2391, 51.4988, 115.3227 ],
|
||||
[ 88.6831, 34.8854, 115.476 ],
|
||||
[ 90.5675, 18.4911, 115.4106 ],
|
||||
[ 91.7801, 2.5188, 115.2677 ],
|
||||
[ 92.2093, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 162, 194, 45 ],
|
||||
[ 161.4216, 190.5899, 58.9539 ],
|
||||
[ 159.7871, 184.9857, 70.9535 ],
|
||||
[ 157.2474, 177.3856, 81.144 ],
|
||||
[ 153.9532, 167.9879, 89.6711 ],
|
||||
[ 150.0555, 156.9908, 96.6801 ],
|
||||
[ 145.7053, 144.5927, 102.3166 ],
|
||||
[ 141.0532, 130.9918, 106.7259 ],
|
||||
[ 136.2503, 116.3863, 110.0536 ],
|
||||
[ 131.4474, 100.9746, 112.445 ],
|
||||
[ 126.7953, 84.9549, 114.0457 ],
|
||||
[ 122.445, 68.5255, 115.001 ],
|
||||
[ 118.5474, 51.8846, 115.4565 ],
|
||||
[ 115.2532, 35.2305, 115.5575 ],
|
||||
[ 112.7134, 18.7614, 115.4496 ],
|
||||
[ 111.0789, 2.6757, 115.2782 ],
|
||||
[ 110.5006, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 142.1717, -55, 129.5 ],
|
||||
[ 3742.1715, -55, 129.5 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 194, -367 ]
|
||||
size_mm = [ 432, 42.8669, 162 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 129.5 ]
|
||||
size_mm = [ 84.3433, 84.3433, 84.3433 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "saab-expansion"
|
||||
name = "Saab B205 / expansion silencers"
|
||||
category = "Inline four / Saab"
|
||||
@@ -7,9 +7,11 @@ description = "Two single expansion chambers, same body volumes"
|
||||
order = 5
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 40.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 0.6
|
||||
cylinders = 4
|
||||
initial_rpm = 1200.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 200.0
|
||||
minimum_substeps = 2
|
||||
phase_degrees = [0.0, 180.0, 540.0, 360.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 3.0
|
||||
starter_torque_nm = 65.0
|
||||
throttle_diameter_mm = 52.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 8.8
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 2
|
||||
exhaust_valve_diameter_mm = 28.0
|
||||
exhaust_valve_lift_mm = 8.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 2
|
||||
intake_valve_diameter_mm = 32.0
|
||||
intake_valve_lift_mm = 8.5
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 153.0
|
||||
stroke_mm = 78.0
|
||||
@@ -115,7 +110,7 @@ loss_coefficient = 0.1
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 2.0
|
||||
type = "expansion"
|
||||
volume_litres = 6.0
|
||||
diameter_mm = 138.1976604
|
||||
|
||||
[silencers.muffler]
|
||||
chambers = 1
|
||||
@@ -125,28 +120,282 @@ loss_coefficient = 0.35
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 4.0
|
||||
type = "expansion"
|
||||
volume_litres = 18.0
|
||||
diameter_mm = 187.7736449
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 8
|
||||
diameter_mm = 60.0
|
||||
length_mm = 150.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 32.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 34.0
|
||||
length_mm = 280.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
profile = "silenced"
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.154496],
|
||||
[350.000, 0.583168],
|
||||
[355.000, 1.233792],
|
||||
[360.000, 2.054144],
|
||||
[365.000, 2.992000],
|
||||
[370.000, 3.995136],
|
||||
[375.000, 5.011328],
|
||||
[380.000, 5.988352],
|
||||
[385.000, 6.873984],
|
||||
[390.000, 7.616000],
|
||||
[395.000, 8.162176],
|
||||
[400.000, 8.460288],
|
||||
[402.500, 8.500000],
|
||||
[527.500, 8.500000],
|
||||
[532.500, 8.345504],
|
||||
[537.500, 7.916832],
|
||||
[542.500, 7.266208],
|
||||
[547.500, 6.445856],
|
||||
[552.500, 5.508000],
|
||||
[557.500, 4.504864],
|
||||
[562.500, 3.488672],
|
||||
[567.500, 2.511648],
|
||||
[572.500, 1.626016],
|
||||
[577.500, 0.884000],
|
||||
[582.500, 0.337824],
|
||||
[587.500, 0.039712],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.134729],
|
||||
[140.000, 0.509786],
|
||||
[145.000, 1.081475],
|
||||
[150.000, 1.806099],
|
||||
[155.000, 2.639964],
|
||||
[160.000, 3.539372],
|
||||
[165.000, 4.460628],
|
||||
[170.000, 5.360036],
|
||||
[175.000, 6.193901],
|
||||
[180.000, 6.918525],
|
||||
[185.000, 7.490214],
|
||||
[190.000, 7.865271],
|
||||
[195.000, 8.000000],
|
||||
[325.000, 8.000000],
|
||||
[330.000, 7.865271],
|
||||
[335.000, 7.490214],
|
||||
[340.000, 6.918525],
|
||||
[345.000, 6.193901],
|
||||
[350.000, 5.360036],
|
||||
[355.000, 4.460628],
|
||||
[360.000, 3.539372],
|
||||
[365.000, 2.639964],
|
||||
[370.000, 1.806099],
|
||||
[375.000, 1.081475],
|
||||
[380.000, 0.509786],
|
||||
[385.000, 0.134729],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -366, 194, -367 ],
|
||||
[ -216, 194, -367 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -162, 194, -286 ],
|
||||
[ -162, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -54, 194, -286 ],
|
||||
[ -54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 54, 194, -286 ],
|
||||
[ 54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 162, 194, -286 ],
|
||||
[ 162, 194, -36 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -162, 194, 45 ],
|
||||
[ -160.763, 188.9129, 64.0687 ],
|
||||
[ -157.153, 180.2477, 79.8812 ],
|
||||
[ -151.3211, 168.5436, 92.717 ],
|
||||
[ -143.4188, 154.3395, 102.8556 ],
|
||||
[ -133.5973, 138.1743, 110.5766 ],
|
||||
[ -122.008, 120.5871, 116.1596 ],
|
||||
[ -108.8022, 102.1169, 119.884 ],
|
||||
[ -94.1311, 83.3026, 122.0296 ],
|
||||
[ -78.1462, 64.6831, 122.8757 ],
|
||||
[ -60.9986, 46.7976, 122.702 ],
|
||||
[ -42.8397, 30.185, 121.7881 ],
|
||||
[ -23.8208, 15.3842, 120.4134 ],
|
||||
[ -4.0933, 2.9342, 118.8576 ],
|
||||
[ 16.1917, -6.6259, 117.4002 ],
|
||||
[ 36.8826, -12.7573, 116.3208 ],
|
||||
[ 57.8284, -14.9208, 115.8988 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -54, 194, 45 ],
|
||||
[ -52.5634, 190.4508, 60.6385 ],
|
||||
[ -48.5035, 184.9694, 73.8883 ],
|
||||
[ -42.1951, 177.702, 84.9399 ],
|
||||
[ -34.0128, 168.7945, 93.9836 ],
|
||||
[ -24.3315, 158.3933, 101.2098 ],
|
||||
[ -13.526, 146.6443, 106.8088 ],
|
||||
[ -1.9709, 133.6937, 110.971 ],
|
||||
[ 9.959, 119.6875, 113.8869 ],
|
||||
[ 21.8888, 104.7719, 115.7468 ],
|
||||
[ 33.4439, 89.093, 116.741 ],
|
||||
[ 44.2495, 72.7969, 117.0599 ],
|
||||
[ 53.9308, 56.0297, 116.8939 ],
|
||||
[ 62.113, 38.9374, 116.4335 ],
|
||||
[ 68.4215, 21.6663, 115.8689 ],
|
||||
[ 72.4814, 4.3623, 115.3905 ],
|
||||
[ 73.9179, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 54, 194, 45 ],
|
||||
[ 54.4291, 190.6029, 58.7971 ],
|
||||
[ 55.6418, 184.9872, 70.6803 ],
|
||||
[ 57.5261, 177.3561, 80.7907 ],
|
||||
[ 59.9702, 167.9128, 89.2697 ],
|
||||
[ 62.862, 156.8603, 96.2586 ],
|
||||
[ 66.0897, 144.4017, 101.8985 ],
|
||||
[ 69.5412, 130.7403, 106.3308 ],
|
||||
[ 73.1046, 116.0791, 109.6968 ],
|
||||
[ 76.6681, 100.6212, 112.1377 ],
|
||||
[ 80.1196, 84.5698, 113.7948 ],
|
||||
[ 83.3472, 68.1279, 114.8094 ],
|
||||
[ 86.2391, 51.4988, 115.3227 ],
|
||||
[ 88.6831, 34.8854, 115.476 ],
|
||||
[ 90.5675, 18.4911, 115.4106 ],
|
||||
[ 91.7801, 2.5188, 115.2677 ],
|
||||
[ 92.2093, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 162, 194, 45 ],
|
||||
[ 161.4216, 190.5899, 58.9539 ],
|
||||
[ 159.7871, 184.9857, 70.9535 ],
|
||||
[ 157.2474, 177.3856, 81.144 ],
|
||||
[ 153.9532, 167.9879, 89.6711 ],
|
||||
[ 150.0555, 156.9908, 96.6801 ],
|
||||
[ 145.7053, 144.5927, 102.3166 ],
|
||||
[ 141.0532, 130.9918, 106.7259 ],
|
||||
[ 136.2503, 116.3863, 110.0536 ],
|
||||
[ 131.4474, 100.9746, 112.445 ],
|
||||
[ 126.7953, 84.9549, 114.0457 ],
|
||||
[ 122.445, 68.5255, 115.001 ],
|
||||
[ 118.5474, 51.8846, 115.4565 ],
|
||||
[ 115.2532, 35.2305, 115.5575 ],
|
||||
[ 112.7134, 18.7614, 115.4496 ],
|
||||
[ 111.0789, 2.6757, 115.2782 ],
|
||||
[ 110.5006, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 142.1717, -55, 129.5 ],
|
||||
[ 3742.1715, -55, 129.5 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 194, -367 ]
|
||||
size_mm = [ 432, 42.8669, 162 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 129.5 ]
|
||||
size_mm = [ 84.3433, 84.3433, 84.3433 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "saab-open"
|
||||
name = "Saab B205 / open exhaust"
|
||||
category = "Inline four / Saab"
|
||||
@@ -7,9 +7,11 @@ description = "Silencers bypassed; naturally aspirated baseline"
|
||||
order = 6
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 40.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 0.6
|
||||
cylinders = 4
|
||||
initial_rpm = 1200.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 200.0
|
||||
minimum_substeps = 2
|
||||
phase_degrees = [0.0, 180.0, 540.0, 360.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 3.0
|
||||
starter_torque_nm = 65.0
|
||||
throttle_diameter_mm = 52.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 8.8
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 2
|
||||
exhaust_valve_diameter_mm = 28.0
|
||||
exhaust_valve_lift_mm = 8.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 2
|
||||
intake_valve_diameter_mm = 32.0
|
||||
intake_valve_lift_mm = 8.5
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 153.0
|
||||
stroke_mm = 78.0
|
||||
@@ -115,7 +110,7 @@ loss_coefficient = 0.1
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 2.0
|
||||
type = "straight_through"
|
||||
volume_litres = 6.0
|
||||
diameter_mm = 138.1976604
|
||||
|
||||
[silencers.muffler]
|
||||
chambers = 1
|
||||
@@ -125,28 +120,282 @@ loss_coefficient = 0.35
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 4.0
|
||||
type = "straight_through"
|
||||
volume_litres = 18.0
|
||||
diameter_mm = 187.7736449
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 8
|
||||
diameter_mm = 60.0
|
||||
length_mm = 150.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 32.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 34.0
|
||||
length_mm = 280.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
profile = "silenced"
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.154496],
|
||||
[350.000, 0.583168],
|
||||
[355.000, 1.233792],
|
||||
[360.000, 2.054144],
|
||||
[365.000, 2.992000],
|
||||
[370.000, 3.995136],
|
||||
[375.000, 5.011328],
|
||||
[380.000, 5.988352],
|
||||
[385.000, 6.873984],
|
||||
[390.000, 7.616000],
|
||||
[395.000, 8.162176],
|
||||
[400.000, 8.460288],
|
||||
[402.500, 8.500000],
|
||||
[527.500, 8.500000],
|
||||
[532.500, 8.345504],
|
||||
[537.500, 7.916832],
|
||||
[542.500, 7.266208],
|
||||
[547.500, 6.445856],
|
||||
[552.500, 5.508000],
|
||||
[557.500, 4.504864],
|
||||
[562.500, 3.488672],
|
||||
[567.500, 2.511648],
|
||||
[572.500, 1.626016],
|
||||
[577.500, 0.884000],
|
||||
[582.500, 0.337824],
|
||||
[587.500, 0.039712],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.134729],
|
||||
[140.000, 0.509786],
|
||||
[145.000, 1.081475],
|
||||
[150.000, 1.806099],
|
||||
[155.000, 2.639964],
|
||||
[160.000, 3.539372],
|
||||
[165.000, 4.460628],
|
||||
[170.000, 5.360036],
|
||||
[175.000, 6.193901],
|
||||
[180.000, 6.918525],
|
||||
[185.000, 7.490214],
|
||||
[190.000, 7.865271],
|
||||
[195.000, 8.000000],
|
||||
[325.000, 8.000000],
|
||||
[330.000, 7.865271],
|
||||
[335.000, 7.490214],
|
||||
[340.000, 6.918525],
|
||||
[345.000, 6.193901],
|
||||
[350.000, 5.360036],
|
||||
[355.000, 4.460628],
|
||||
[360.000, 3.539372],
|
||||
[365.000, 2.639964],
|
||||
[370.000, 1.806099],
|
||||
[375.000, 1.081475],
|
||||
[380.000, 0.509786],
|
||||
[385.000, 0.134729],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -366, 194, -367 ],
|
||||
[ -216, 194, -367 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -162, 194, -286 ],
|
||||
[ -162, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -54, 194, -286 ],
|
||||
[ -54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 54, 194, -286 ],
|
||||
[ 54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 162, 194, -286 ],
|
||||
[ 162, 194, -36 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -162, 194, 45 ],
|
||||
[ -160.763, 188.9129, 64.0687 ],
|
||||
[ -157.153, 180.2477, 79.8812 ],
|
||||
[ -151.3211, 168.5436, 92.717 ],
|
||||
[ -143.4188, 154.3395, 102.8556 ],
|
||||
[ -133.5973, 138.1743, 110.5766 ],
|
||||
[ -122.008, 120.5871, 116.1596 ],
|
||||
[ -108.8022, 102.1169, 119.884 ],
|
||||
[ -94.1311, 83.3026, 122.0296 ],
|
||||
[ -78.1462, 64.6831, 122.8757 ],
|
||||
[ -60.9986, 46.7976, 122.702 ],
|
||||
[ -42.8397, 30.185, 121.7881 ],
|
||||
[ -23.8208, 15.3842, 120.4134 ],
|
||||
[ -4.0933, 2.9342, 118.8576 ],
|
||||
[ 16.1917, -6.6259, 117.4002 ],
|
||||
[ 36.8826, -12.7573, 116.3208 ],
|
||||
[ 57.8284, -14.9208, 115.8988 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -54, 194, 45 ],
|
||||
[ -52.5634, 190.4508, 60.6385 ],
|
||||
[ -48.5035, 184.9694, 73.8883 ],
|
||||
[ -42.1951, 177.702, 84.9399 ],
|
||||
[ -34.0128, 168.7945, 93.9836 ],
|
||||
[ -24.3315, 158.3933, 101.2098 ],
|
||||
[ -13.526, 146.6443, 106.8088 ],
|
||||
[ -1.9709, 133.6937, 110.971 ],
|
||||
[ 9.959, 119.6875, 113.8869 ],
|
||||
[ 21.8888, 104.7719, 115.7468 ],
|
||||
[ 33.4439, 89.093, 116.741 ],
|
||||
[ 44.2495, 72.7969, 117.0599 ],
|
||||
[ 53.9308, 56.0297, 116.8939 ],
|
||||
[ 62.113, 38.9374, 116.4335 ],
|
||||
[ 68.4215, 21.6663, 115.8689 ],
|
||||
[ 72.4814, 4.3623, 115.3905 ],
|
||||
[ 73.9179, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 54, 194, 45 ],
|
||||
[ 54.4291, 190.6029, 58.7971 ],
|
||||
[ 55.6418, 184.9872, 70.6803 ],
|
||||
[ 57.5261, 177.3561, 80.7907 ],
|
||||
[ 59.9702, 167.9128, 89.2697 ],
|
||||
[ 62.862, 156.8603, 96.2586 ],
|
||||
[ 66.0897, 144.4017, 101.8985 ],
|
||||
[ 69.5412, 130.7403, 106.3308 ],
|
||||
[ 73.1046, 116.0791, 109.6968 ],
|
||||
[ 76.6681, 100.6212, 112.1377 ],
|
||||
[ 80.1196, 84.5698, 113.7948 ],
|
||||
[ 83.3472, 68.1279, 114.8094 ],
|
||||
[ 86.2391, 51.4988, 115.3227 ],
|
||||
[ 88.6831, 34.8854, 115.476 ],
|
||||
[ 90.5675, 18.4911, 115.4106 ],
|
||||
[ 91.7801, 2.5188, 115.2677 ],
|
||||
[ 92.2093, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 162, 194, 45 ],
|
||||
[ 161.4216, 190.5899, 58.9539 ],
|
||||
[ 159.7871, 184.9857, 70.9535 ],
|
||||
[ 157.2474, 177.3856, 81.144 ],
|
||||
[ 153.9532, 167.9879, 89.6711 ],
|
||||
[ 150.0555, 156.9908, 96.6801 ],
|
||||
[ 145.7053, 144.5927, 102.3166 ],
|
||||
[ 141.0532, 130.9918, 106.7259 ],
|
||||
[ 136.2503, 116.3863, 110.0536 ],
|
||||
[ 131.4474, 100.9746, 112.445 ],
|
||||
[ 126.7953, 84.9549, 114.0457 ],
|
||||
[ 122.445, 68.5255, 115.001 ],
|
||||
[ 118.5474, 51.8846, 115.4565 ],
|
||||
[ 115.2532, 35.2305, 115.5575 ],
|
||||
[ 112.7134, 18.7614, 115.4496 ],
|
||||
[ 111.0789, 2.6757, 115.2782 ],
|
||||
[ 110.5006, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 142.1717, -55, 129.5 ],
|
||||
[ 1892.1716, -55, 129.5 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 194, -367 ]
|
||||
size_mm = [ 432, 42.8669, 162 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 129.5 ]
|
||||
size_mm = [ 84.3433, 84.3433, 84.3433 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "saab-straight"
|
||||
name = "Saab B205 / straight-through"
|
||||
category = "Inline four / Saab"
|
||||
@@ -7,9 +7,11 @@ description = "6 L resonator and 18 L straight-through rear muffler"
|
||||
order = 3
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 40.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 0.6
|
||||
cylinders = 4
|
||||
initial_rpm = 1200.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 200.0
|
||||
minimum_substeps = 2
|
||||
phase_degrees = [0.0, 180.0, 540.0, 360.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 3.0
|
||||
starter_torque_nm = 65.0
|
||||
throttle_diameter_mm = 52.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 8.8
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 2
|
||||
exhaust_valve_diameter_mm = 28.0
|
||||
exhaust_valve_lift_mm = 8.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 2
|
||||
intake_valve_diameter_mm = 32.0
|
||||
intake_valve_lift_mm = 8.5
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 153.0
|
||||
stroke_mm = 78.0
|
||||
@@ -115,7 +110,7 @@ loss_coefficient = 0.1
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 2.0
|
||||
type = "straight_through"
|
||||
volume_litres = 6.0
|
||||
diameter_mm = 138.1976604
|
||||
|
||||
[silencers.muffler]
|
||||
chambers = 1
|
||||
@@ -125,28 +120,282 @@ loss_coefficient = 0.35
|
||||
passage_diameter_mm = 60.0
|
||||
resistance = 4.0
|
||||
type = "straight_through"
|
||||
volume_litres = 18.0
|
||||
diameter_mm = 187.7736449
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 8
|
||||
diameter_mm = 60.0
|
||||
length_mm = 150.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 32.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 4
|
||||
cells = 10
|
||||
diameter_mm = 34.0
|
||||
length_mm = 280.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
profile = "silenced"
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.154496],
|
||||
[350.000, 0.583168],
|
||||
[355.000, 1.233792],
|
||||
[360.000, 2.054144],
|
||||
[365.000, 2.992000],
|
||||
[370.000, 3.995136],
|
||||
[375.000, 5.011328],
|
||||
[380.000, 5.988352],
|
||||
[385.000, 6.873984],
|
||||
[390.000, 7.616000],
|
||||
[395.000, 8.162176],
|
||||
[400.000, 8.460288],
|
||||
[402.500, 8.500000],
|
||||
[527.500, 8.500000],
|
||||
[532.500, 8.345504],
|
||||
[537.500, 7.916832],
|
||||
[542.500, 7.266208],
|
||||
[547.500, 6.445856],
|
||||
[552.500, 5.508000],
|
||||
[557.500, 4.504864],
|
||||
[562.500, 3.488672],
|
||||
[567.500, 2.511648],
|
||||
[572.500, 1.626016],
|
||||
[577.500, 0.884000],
|
||||
[582.500, 0.337824],
|
||||
[587.500, 0.039712],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.134729],
|
||||
[140.000, 0.509786],
|
||||
[145.000, 1.081475],
|
||||
[150.000, 1.806099],
|
||||
[155.000, 2.639964],
|
||||
[160.000, 3.539372],
|
||||
[165.000, 4.460628],
|
||||
[170.000, 5.360036],
|
||||
[175.000, 6.193901],
|
||||
[180.000, 6.918525],
|
||||
[185.000, 7.490214],
|
||||
[190.000, 7.865271],
|
||||
[195.000, 8.000000],
|
||||
[325.000, 8.000000],
|
||||
[330.000, 7.865271],
|
||||
[335.000, 7.490214],
|
||||
[340.000, 6.918525],
|
||||
[345.000, 6.193901],
|
||||
[350.000, 5.360036],
|
||||
[355.000, 4.460628],
|
||||
[360.000, 3.539372],
|
||||
[365.000, 2.639964],
|
||||
[370.000, 1.806099],
|
||||
[375.000, 1.081475],
|
||||
[380.000, 0.509786],
|
||||
[385.000, 0.134729],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 54, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 162, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -366, 194, -367 ],
|
||||
[ -216, 194, -367 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -162, 194, -286 ],
|
||||
[ -162, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -54, 194, -286 ],
|
||||
[ -54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 54, 194, -286 ],
|
||||
[ 54, 194, -36 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 162, 194, -286 ],
|
||||
[ 162, 194, -36 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -162, 194, 45 ],
|
||||
[ -160.763, 188.9129, 64.0687 ],
|
||||
[ -157.153, 180.2477, 79.8812 ],
|
||||
[ -151.3211, 168.5436, 92.717 ],
|
||||
[ -143.4188, 154.3395, 102.8556 ],
|
||||
[ -133.5973, 138.1743, 110.5766 ],
|
||||
[ -122.008, 120.5871, 116.1596 ],
|
||||
[ -108.8022, 102.1169, 119.884 ],
|
||||
[ -94.1311, 83.3026, 122.0296 ],
|
||||
[ -78.1462, 64.6831, 122.8757 ],
|
||||
[ -60.9986, 46.7976, 122.702 ],
|
||||
[ -42.8397, 30.185, 121.7881 ],
|
||||
[ -23.8208, 15.3842, 120.4134 ],
|
||||
[ -4.0933, 2.9342, 118.8576 ],
|
||||
[ 16.1917, -6.6259, 117.4002 ],
|
||||
[ 36.8826, -12.7573, 116.3208 ],
|
||||
[ 57.8284, -14.9208, 115.8988 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -54, 194, 45 ],
|
||||
[ -52.5634, 190.4508, 60.6385 ],
|
||||
[ -48.5035, 184.9694, 73.8883 ],
|
||||
[ -42.1951, 177.702, 84.9399 ],
|
||||
[ -34.0128, 168.7945, 93.9836 ],
|
||||
[ -24.3315, 158.3933, 101.2098 ],
|
||||
[ -13.526, 146.6443, 106.8088 ],
|
||||
[ -1.9709, 133.6937, 110.971 ],
|
||||
[ 9.959, 119.6875, 113.8869 ],
|
||||
[ 21.8888, 104.7719, 115.7468 ],
|
||||
[ 33.4439, 89.093, 116.741 ],
|
||||
[ 44.2495, 72.7969, 117.0599 ],
|
||||
[ 53.9308, 56.0297, 116.8939 ],
|
||||
[ 62.113, 38.9374, 116.4335 ],
|
||||
[ 68.4215, 21.6663, 115.8689 ],
|
||||
[ 72.4814, 4.3623, 115.3905 ],
|
||||
[ 73.9179, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 54, 194, 45 ],
|
||||
[ 54.4291, 190.6029, 58.7971 ],
|
||||
[ 55.6418, 184.9872, 70.6803 ],
|
||||
[ 57.5261, 177.3561, 80.7907 ],
|
||||
[ 59.9702, 167.9128, 89.2697 ],
|
||||
[ 62.862, 156.8603, 96.2586 ],
|
||||
[ 66.0897, 144.4017, 101.8985 ],
|
||||
[ 69.5412, 130.7403, 106.3308 ],
|
||||
[ 73.1046, 116.0791, 109.6968 ],
|
||||
[ 76.6681, 100.6212, 112.1377 ],
|
||||
[ 80.1196, 84.5698, 113.7948 ],
|
||||
[ 83.3472, 68.1279, 114.8094 ],
|
||||
[ 86.2391, 51.4988, 115.3227 ],
|
||||
[ 88.6831, 34.8854, 115.476 ],
|
||||
[ 90.5675, 18.4911, 115.4106 ],
|
||||
[ 91.7801, 2.5188, 115.2677 ],
|
||||
[ 92.2093, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 162, 194, 45 ],
|
||||
[ 161.4216, 190.5899, 58.9539 ],
|
||||
[ 159.7871, 184.9857, 70.9535 ],
|
||||
[ 157.2474, 177.3856, 81.144 ],
|
||||
[ 153.9532, 167.9879, 89.6711 ],
|
||||
[ 150.0555, 156.9908, 96.6801 ],
|
||||
[ 145.7053, 144.5927, 102.3166 ],
|
||||
[ 141.0532, 130.9918, 106.7259 ],
|
||||
[ 136.2503, 116.3863, 110.0536 ],
|
||||
[ 131.4474, 100.9746, 112.445 ],
|
||||
[ 126.7953, 84.9549, 114.0457 ],
|
||||
[ 122.445, 68.5255, 115.001 ],
|
||||
[ 118.5474, 51.8846, 115.4565 ],
|
||||
[ 115.2532, 35.2305, 115.5575 ],
|
||||
[ 112.7134, 18.7614, 115.4496 ],
|
||||
[ 111.0789, 2.6757, 115.2782 ],
|
||||
[ 110.5006, -12.8284, 115.1887 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 142.1717, -55, 129.5 ],
|
||||
[ 3742.1715, -55, 129.5 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 194, -367 ]
|
||||
size_mm = [ 432, 42.8669, 162 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 129.5 ]
|
||||
size_mm = [ 84.3433, 84.3433, 84.3433 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "single-450"
|
||||
name = "450 cc / carbureted four-stroke thumper"
|
||||
category = "Singles / four-stroke"
|
||||
@@ -7,9 +7,11 @@ description = "40 mm carb / mild valve timing / fixed idle stop"
|
||||
order = 17
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 0.25
|
||||
cylinders = 1
|
||||
initial_rpm = 1960.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 1.0
|
||||
starter_torque_nm = 11.21926
|
||||
throttle_diameter_mm = 40.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 370.0
|
||||
exhaust_open_deg = 145.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 30.72
|
||||
exhaust_valve_lift_mm = 8.640001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 565.0
|
||||
intake_open_deg = 355.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 36.48
|
||||
intake_valve_lift_mm = 9.6
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 111.6
|
||||
stroke_mm = 62.0
|
||||
@@ -73,8 +68,8 @@ overrun_resume_rpm = 2400.0
|
||||
power_afr = 12.8
|
||||
rev_limit_enabled = true
|
||||
rev_limit_fuel_cut_enabled = false
|
||||
rev_limit_rpm = 7000.0
|
||||
rev_resume_rpm = 6750.0
|
||||
rev_limit_rpm = 13000.0
|
||||
rev_resume_rpm = 12990.0
|
||||
stoichiometric_afr = 14.7
|
||||
throttle_closing_rate = 0.0
|
||||
throttle_closing_time_constant_s = 0.0
|
||||
@@ -113,24 +108,165 @@ bowl_refill_kg_per_s = 0.1
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[355.000, 0.000000],
|
||||
[360.000, 0.244639],
|
||||
[365.000, 0.912213],
|
||||
[370.000, 1.903207],
|
||||
[375.000, 3.118108],
|
||||
[380.000, 4.457402],
|
||||
[385.000, 5.821574],
|
||||
[390.000, 7.111111],
|
||||
[395.000, 8.226498],
|
||||
[400.000, 9.068222],
|
||||
[405.000, 9.536767],
|
||||
[407.500, 9.600000],
|
||||
[512.500, 9.600000],
|
||||
[517.500, 9.355361],
|
||||
[522.500, 8.687787],
|
||||
[527.500, 7.696793],
|
||||
[532.500, 6.481892],
|
||||
[537.500, 5.142598],
|
||||
[542.500, 3.778426],
|
||||
[547.500, 2.488889],
|
||||
[552.500, 1.373502],
|
||||
[557.500, 0.531778],
|
||||
[562.500, 0.063233],
|
||||
[565.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[145.000, 0.000000],
|
||||
[150.000, 0.192664],
|
||||
[155.000, 0.722110],
|
||||
[160.000, 1.515520],
|
||||
[165.000, 2.500077],
|
||||
[170.000, 3.602963],
|
||||
[175.000, 4.751361],
|
||||
[180.000, 5.872451],
|
||||
[185.000, 6.893417],
|
||||
[190.000, 7.741441],
|
||||
[195.000, 8.343705],
|
||||
[200.000, 8.627391],
|
||||
[201.250, 8.640001],
|
||||
[313.750, 8.640001],
|
||||
[318.750, 8.447337],
|
||||
[323.750, 7.917891],
|
||||
[328.750, 7.124481],
|
||||
[333.750, 6.139924],
|
||||
[338.750, 5.037038],
|
||||
[343.750, 3.888640],
|
||||
[348.750, 2.767550],
|
||||
[353.750, 1.746584],
|
||||
[358.750, 0.898560],
|
||||
[363.750, 0.296296],
|
||||
[368.750, 0.012610],
|
||||
[370.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -257, 141.4889, -374.8 ],
|
||||
[ -57, 141.4889, -374.8 ]
|
||||
]
|
||||
|
||||
# runners
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ 0, 141.4889, -288.4 ],
|
||||
[ 0, 141.4889, -38.4 ]
|
||||
]
|
||||
|
||||
# primaries
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 0, 141.4889, 48 ],
|
||||
[ 0.943, 138.6704, 60.5191 ],
|
||||
[ 3.6081, 134.2865, 71.5364 ],
|
||||
[ 7.7491, 128.4585, 81.1477 ],
|
||||
[ 13.1202, 121.3077, 89.4488 ],
|
||||
[ 19.4754, 112.9555, 96.5354 ],
|
||||
[ 26.5685, 103.5233, 102.5034 ],
|
||||
[ 34.1536, 93.1325, 107.4485 ],
|
||||
[ 41.9848, 81.9043, 111.4664 ],
|
||||
[ 49.8159, 69.9601, 114.6529 ],
|
||||
[ 57.4011, 57.4214, 117.1039 ],
|
||||
[ 64.4942, 44.4093, 118.915 ],
|
||||
[ 70.8493, 31.0454, 120.1821 ],
|
||||
[ 76.2204, 17.451, 121.0009 ],
|
||||
[ 80.3615, 3.7474, 121.4672 ],
|
||||
[ 83.0265, -9.944, 121.6767 ],
|
||||
[ 83.9696, -23.502, 121.7253 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 131.4981, -55, 135.8 ],
|
||||
[ 1631.4981, -55, 135.8 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 141.4889, -374.8 ]
|
||||
size_mm = [ 114, 50.7635, 172.8 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 135.8 ]
|
||||
size_mm = [ 62.9961, 62.9961, 62.9961 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "single-650"
|
||||
name = "650 cc / big thumper"
|
||||
category = "Singles / four-stroke"
|
||||
@@ -7,9 +7,11 @@ description = "Estimated concept calibration / EFI"
|
||||
order = 18
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 0.25
|
||||
cylinders = 1
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 1.0
|
||||
starter_torque_nm = 16.29701
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 32.0
|
||||
exhaust_valve_lift_mm = 9.000001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 38.0
|
||||
intake_valve_lift_mm = 10.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 149.4
|
||||
stroke_mm = 83.0
|
||||
@@ -101,24 +96,171 @@ system = "injection"
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.181760],
|
||||
[350.000, 0.686080],
|
||||
[355.000, 1.451520],
|
||||
[360.000, 2.416640],
|
||||
[365.000, 3.520000],
|
||||
[370.000, 4.700160],
|
||||
[375.000, 5.895680],
|
||||
[380.000, 7.045120],
|
||||
[385.000, 8.087040],
|
||||
[390.000, 8.960000],
|
||||
[395.000, 9.602560],
|
||||
[400.000, 9.953280],
|
||||
[402.500, 10.000000],
|
||||
[527.500, 10.000000],
|
||||
[532.500, 9.818240],
|
||||
[537.500, 9.313920],
|
||||
[542.500, 8.548480],
|
||||
[547.500, 7.583360],
|
||||
[552.500, 6.480000],
|
||||
[557.500, 5.299840],
|
||||
[562.500, 4.104320],
|
||||
[567.500, 2.954880],
|
||||
[572.500, 1.912960],
|
||||
[577.500, 1.040000],
|
||||
[582.500, 0.397440],
|
||||
[587.500, 0.046720],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.151570],
|
||||
[140.000, 0.573509],
|
||||
[145.000, 1.216659],
|
||||
[150.000, 2.031862],
|
||||
[155.000, 2.969959],
|
||||
[160.000, 3.981794],
|
||||
[165.000, 5.018207],
|
||||
[170.000, 6.030042],
|
||||
[175.000, 6.968139],
|
||||
[180.000, 7.783342],
|
||||
[185.000, 8.426492],
|
||||
[190.000, 8.848431],
|
||||
[195.000, 9.000001],
|
||||
[325.000, 9.000001],
|
||||
[330.000, 8.848431],
|
||||
[335.000, 8.426492],
|
||||
[340.000, 7.783342],
|
||||
[345.000, 6.968139],
|
||||
[350.000, 6.030042],
|
||||
[355.000, 5.018207],
|
||||
[360.000, 3.981794],
|
||||
[365.000, 2.969959],
|
||||
[370.000, 2.031862],
|
||||
[375.000, 1.216659],
|
||||
[380.000, 0.573509],
|
||||
[385.000, 0.151570],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -259, 192.1222, -380 ],
|
||||
[ -59, 192.1222, -380 ]
|
||||
]
|
||||
|
||||
# runners
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ 0, 192.1222, -290 ],
|
||||
[ 0, 192.1222, -40 ]
|
||||
]
|
||||
|
||||
# primaries
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 0, 192.1222, 50 ],
|
||||
[ 0.9799, 188.5111, 65.2858 ],
|
||||
[ 3.7492, 182.718, 78.469 ],
|
||||
[ 8.0523, 174.9286, 89.7037 ],
|
||||
[ 13.6334, 165.3287, 99.144 ],
|
||||
[ 20.2371, 154.1038, 106.9438 ],
|
||||
[ 27.6077, 141.4398, 113.2573 ],
|
||||
[ 35.4896, 127.5224, 118.2383 ],
|
||||
[ 43.627, 112.5371, 122.0411 ],
|
||||
[ 51.7645, 96.6697, 124.8196 ],
|
||||
[ 59.6463, 80.106, 126.7279 ],
|
||||
[ 67.0169, 63.0315, 127.9199 ],
|
||||
[ 73.6206, 45.632, 128.5498 ],
|
||||
[ 79.2018, 28.0933, 128.7716 ],
|
||||
[ 83.5049, 10.6009, 128.7393 ],
|
||||
[ 86.2742, -6.6594, 128.607 ],
|
||||
[ 87.2541, -23.502, 128.5287 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 131.4981, -55, 140 ],
|
||||
[ 1631.498, -55, 140 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 192.1222, -380 ]
|
||||
size_mm = [ 118, 47.081, 180 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 140 ]
|
||||
size_mm = [ 62.9961, 62.9961, 62.9961 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "six-long"
|
||||
name = "3.0 litre / long-stroke inline six"
|
||||
category = "Inline six"
|
||||
@@ -7,9 +7,11 @@ description = "Unequal primaries / small junctions / staged collectors / EFI"
|
||||
order = 25
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 6
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 240.0, 480.0, 120.0, 600.0, 360.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 6.0
|
||||
starter_torque_nm = 74.93359
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "staged"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 27.52
|
||||
exhaust_valve_lift_mm = 7.740001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 32.68
|
||||
intake_valve_lift_mm = 8.6
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 154.8
|
||||
stroke_mm = 86.0
|
||||
@@ -101,71 +96,434 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 6
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_1"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_2"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_3"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_4"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_5"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_6"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_13"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_14"
|
||||
cells = 9
|
||||
diameter_mm = 48.0
|
||||
length_mm = 420.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_15"
|
||||
cells = 11
|
||||
diameter_mm = 48.0
|
||||
length_mm = 540.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.156314],
|
||||
[350.000, 0.590029],
|
||||
[355.000, 1.248307],
|
||||
[360.000, 2.078310],
|
||||
[365.000, 3.027200],
|
||||
[370.000, 4.042138],
|
||||
[375.000, 5.070285],
|
||||
[380.000, 6.058803],
|
||||
[385.000, 6.954854],
|
||||
[390.000, 7.705600],
|
||||
[395.000, 8.258202],
|
||||
[400.000, 8.559821],
|
||||
[402.500, 8.600000],
|
||||
[527.500, 8.600000],
|
||||
[532.500, 8.443686],
|
||||
[537.500, 8.009971],
|
||||
[542.500, 7.351693],
|
||||
[547.500, 6.521690],
|
||||
[552.500, 5.572800],
|
||||
[557.500, 4.557862],
|
||||
[562.500, 3.529715],
|
||||
[567.500, 2.541197],
|
||||
[572.500, 1.645146],
|
||||
[577.500, 0.894400],
|
||||
[582.500, 0.341798],
|
||||
[587.500, 0.040179],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.130350],
|
||||
[140.000, 0.493218],
|
||||
[145.000, 1.046327],
|
||||
[150.000, 1.747401],
|
||||
[155.000, 2.554165],
|
||||
[160.000, 3.424343],
|
||||
[165.000, 4.315658],
|
||||
[170.000, 5.185836],
|
||||
[175.000, 5.992600],
|
||||
[180.000, 6.693674],
|
||||
[185.000, 7.246783],
|
||||
[190.000, 7.609651],
|
||||
[195.000, 7.740001],
|
||||
[325.000, 7.740001],
|
||||
[330.000, 7.609651],
|
||||
[335.000, 7.246783],
|
||||
[340.000, 6.693674],
|
||||
[345.000, 5.992600],
|
||||
[350.000, 5.185836],
|
||||
[355.000, 4.315658],
|
||||
[360.000, 3.424343],
|
||||
[365.000, 2.554165],
|
||||
[370.000, 1.747401],
|
||||
[375.000, 1.046327],
|
||||
[380.000, 0.493218],
|
||||
[385.000, 0.130350],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -260, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -156, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -52, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 52, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 156, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 260, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -512, 199.3556, -361.7999 ],
|
||||
[ -312, 199.3556, -361.7999 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -260, 199.3556, -284.3999 ],
|
||||
[ -260, 199.3556, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -156, 199.3556, -284.3999 ],
|
||||
[ -156, 199.3556, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ -52, 199.3556, -284.3999 ],
|
||||
[ -52, 199.3556, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 52, 199.3556, -284.3999 ],
|
||||
[ 52, 199.3556, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 156, 199.3556, -284.3999 ],
|
||||
[ 156, 199.3556, -34.4 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ 260, 199.3556, -284.3999 ],
|
||||
[ 260, 199.3556, -34.4 ]
|
||||
]
|
||||
|
||||
# primary_1
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -260, 199.3556, 43 ],
|
||||
[ -258.9279, 195.9039, 57.4758 ],
|
||||
[ -255.8981, 190.3736, 69.6486 ],
|
||||
[ -251.1903, 182.9408, 79.7072 ],
|
||||
[ -245.0842, 173.7821, 87.8407 ],
|
||||
[ -237.8593, 163.0735, 94.2378 ],
|
||||
[ -229.7954, 150.9915, 99.0876 ],
|
||||
[ -221.1722, 137.7124, 102.5789 ],
|
||||
[ -212.2693, 123.4124, 104.9007 ],
|
||||
[ -203.3664, 108.2679, 106.2418 ],
|
||||
[ -194.7432, 92.4553, 106.7912 ],
|
||||
[ -186.6793, 76.1507, 106.7377 ],
|
||||
[ -179.4545, 59.5305, 106.2704 ],
|
||||
[ -173.3483, 42.7711, 105.578 ],
|
||||
[ -168.6405, 26.0487, 104.8496 ],
|
||||
[ -165.6107, 9.5396, 104.274 ],
|
||||
[ -164.5387, -6.5798, 104.0402 ]
|
||||
]
|
||||
|
||||
# primary_2
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ -156, 199.3556, 43 ],
|
||||
[ -156, 196.0021, 56.2873 ],
|
||||
[ -156, 190.385, 67.5779 ],
|
||||
[ -156, 182.7176, 77.0291 ],
|
||||
[ -156, 173.2129, 84.798 ],
|
||||
[ -156, 162.084, 91.042 ],
|
||||
[ -156, 149.544, 95.9182 ],
|
||||
[ -156, 135.8061, 99.5838 ],
|
||||
[ -156, 121.0833, 102.1961 ],
|
||||
[ -156, 105.5888, 103.9123 ],
|
||||
[ -156, 89.5356, 104.8895 ],
|
||||
[ -156, 73.137, 105.2851 ],
|
||||
[ -156, 56.606, 105.2562 ],
|
||||
[ -156, 40.1556, 104.96 ],
|
||||
[ -156, 23.9992, 104.5538 ],
|
||||
[ -156, 8.3496, 104.1948 ],
|
||||
[ -156, -6.5798, 104.0402 ]
|
||||
]
|
||||
|
||||
# primary_3
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -52, 199.3556, 43 ],
|
||||
[ -53.0721, 195.9039, 57.4758 ],
|
||||
[ -56.1019, 190.3736, 69.6486 ],
|
||||
[ -60.8097, 182.9408, 79.7072 ],
|
||||
[ -66.9158, 173.7821, 87.8407 ],
|
||||
[ -74.1407, 163.0735, 94.2378 ],
|
||||
[ -82.2046, 150.9915, 99.0876 ],
|
||||
[ -90.8278, 137.7124, 102.5789 ],
|
||||
[ -99.7307, 123.4124, 104.9007 ],
|
||||
[ -108.6336, 108.2679, 106.2418 ],
|
||||
[ -117.2568, 92.4553, 106.7912 ],
|
||||
[ -125.3207, 76.1507, 106.7377 ],
|
||||
[ -132.5455, 59.5305, 106.2704 ],
|
||||
[ -138.6517, 42.7711, 105.578 ],
|
||||
[ -143.3595, 26.0487, 104.8496 ],
|
||||
[ -146.3893, 9.5396, 104.274 ],
|
||||
[ -147.4613, -6.5798, 104.0402 ]
|
||||
]
|
||||
|
||||
# primary_4
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ 52, 199.3556, 43 ],
|
||||
[ 53.0721, 195.8364, 58.7577 ],
|
||||
[ 56.1019, 190.3657, 72.8486 ],
|
||||
[ 60.8097, 183.0945, 85.3623 ],
|
||||
[ 66.9158, 174.1738, 96.3887 ],
|
||||
[ 74.1407, 163.7546, 106.0175 ],
|
||||
[ 82.2046, 151.9878, 114.3382 ],
|
||||
[ 90.8278, 139.0244, 121.4408 ],
|
||||
[ 99.7307, 125.0154, 127.4148 ],
|
||||
[ 108.6336, 110.1119, 132.35 ],
|
||||
[ 117.2568, 94.4647, 136.3361 ],
|
||||
[ 125.3207, 78.2248, 139.4628 ],
|
||||
[ 132.5455, 61.5433, 141.8198 ],
|
||||
[ 138.6517, 44.5711, 143.4969 ],
|
||||
[ 143.3595, 27.4592, 144.5837 ],
|
||||
[ 146.3893, 10.3586, 145.1701 ],
|
||||
[ 147.4613, -6.5798, 145.3456 ]
|
||||
]
|
||||
|
||||
# primary_5
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 156, 199.3556, 43 ],
|
||||
[ 156, 195.9285, 57.6414 ],
|
||||
[ 156, 190.3764, 70.9037 ],
|
||||
[ 156, 182.8848, 82.847 ],
|
||||
[ 156, 173.6392, 93.5311 ],
|
||||
[ 156, 162.8252, 103.0159 ],
|
||||
[ 156, 150.6282, 111.3615 ],
|
||||
[ 156, 137.234, 118.6277 ],
|
||||
[ 156, 122.8279, 124.8746 ],
|
||||
[ 156, 107.5956, 130.1621 ],
|
||||
[ 156, 91.7225, 134.55 ],
|
||||
[ 156, 75.3944, 138.0984 ],
|
||||
[ 156, 58.7966, 140.8673 ],
|
||||
[ 156, 42.1147, 142.9164 ],
|
||||
[ 156, 25.5343, 144.3059 ],
|
||||
[ 156, 9.2409, 145.0956 ],
|
||||
[ 156, -6.5798, 145.3456 ]
|
||||
]
|
||||
|
||||
# primary_6
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 260, 199.3556, 43 ],
|
||||
[ 258.9279, 195.8364, 58.7577 ],
|
||||
[ 255.8981, 190.3657, 72.8486 ],
|
||||
[ 251.1903, 183.0945, 85.3623 ],
|
||||
[ 245.0842, 174.1738, 96.3887 ],
|
||||
[ 237.8593, 163.7546, 106.0175 ],
|
||||
[ 229.7954, 151.9878, 114.3382 ],
|
||||
[ 221.1722, 139.0244, 121.4408 ],
|
||||
[ 212.2693, 125.0154, 127.4148 ],
|
||||
[ 203.3664, 110.1119, 132.35 ],
|
||||
[ 194.7432, 94.4647, 136.3361 ],
|
||||
[ 186.6793, 78.2248, 139.4628 ],
|
||||
[ 179.4545, 61.5433, 141.8198 ],
|
||||
[ 173.3483, 44.5711, 143.4969 ],
|
||||
[ 168.6405, 27.4592, 144.5837 ],
|
||||
[ 165.6107, 10.3586, 145.1701 ],
|
||||
[ 164.5387, -6.5798, 145.3456 ]
|
||||
]
|
||||
|
||||
# tailpipe_13
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ 218.4202, -70, 169.5 ],
|
||||
[ 1718.4201, -70, 169.5 ]
|
||||
]
|
||||
|
||||
# secondary_14
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -137.5798, -27.3284, 112.6045 ],
|
||||
[ -115.9354, -27.7815, 113.2086 ],
|
||||
[ -94.9697, -29.0619, 114.9159 ],
|
||||
[ -74.5859, -31.0515, 117.5686 ],
|
||||
[ -54.6869, -33.632, 121.0094 ],
|
||||
[ -35.1758, -36.6853, 125.0805 ],
|
||||
[ -15.9556, -40.0932, 129.6243 ],
|
||||
[ 3.0707, -43.7375, 134.4834 ],
|
||||
[ 22, -47.5, 139.5 ],
|
||||
[ 40.9293, -51.2625, 144.5166 ],
|
||||
[ 59.9556, -54.9068, 149.3757 ],
|
||||
[ 79.1758, -58.3147, 153.9195 ],
|
||||
[ 98.6869, -61.368, 157.9906 ],
|
||||
[ 118.5859, -63.9485, 161.4314 ],
|
||||
[ 138.9697, -65.9381, 164.0842 ],
|
||||
[ 159.9354, -67.2185, 165.7914 ],
|
||||
[ 181.5798, -67.6716, 166.3955 ]
|
||||
]
|
||||
|
||||
# secondary_15
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 174.0108, -43.4202, 160.6401 ],
|
||||
[ 174.1004, -44.1614, 160.6706 ],
|
||||
[ 174.3536, -44.8101, 160.7569 ],
|
||||
[ 174.7471, -45.3796, 160.8911 ],
|
||||
[ 175.2574, -45.8829, 161.065 ],
|
||||
[ 175.8613, -46.3335, 161.2709 ],
|
||||
[ 176.5352, -46.7443, 161.5006 ],
|
||||
[ 177.2559, -47.1288, 161.7463 ],
|
||||
[ 178, -47.5, 162 ],
|
||||
[ 178.7441, -47.8712, 162.2536 ],
|
||||
[ 179.4648, -48.2557, 162.4994 ],
|
||||
[ 180.1387, -48.6665, 162.7291 ],
|
||||
[ 180.7426, -49.1171, 162.935 ],
|
||||
[ 181.2529, -49.6204, 163.1089 ],
|
||||
[ 181.6464, -50.1899, 163.2431 ],
|
||||
[ 181.8996, -50.8386, 163.3294 ],
|
||||
[ 181.9892, -51.5798, 163.3599 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 199.3556, -361.7999 ]
|
||||
size_mm = [ 624, 62.1149, 154.8 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -156, -25, 109.5 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 156, -25, 154.5 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 200, -70, 169.5 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "triple"
|
||||
name = "1.0 litre / inline triple"
|
||||
category = "Inline three"
|
||||
@@ -7,9 +7,11 @@ description = "Unequal primaries / small junctions / staged collectors / EFI"
|
||||
order = 21
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 0.75
|
||||
cylinders = 3
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 480.0, 240.0]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 3.0
|
||||
starter_torque_nm = 24.99852
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "staged"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 25.28
|
||||
exhaust_valve_lift_mm = 7.110001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 30.02
|
||||
intake_valve_lift_mm = 7.900001
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 122.4
|
||||
stroke_mm = 68.0
|
||||
@@ -101,47 +96,285 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 3
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_1"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_2"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_3"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_7"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_8"
|
||||
cells = 9
|
||||
diameter_mm = 48.0
|
||||
length_mm = 420.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.143590],
|
||||
[350.000, 0.542003],
|
||||
[355.000, 1.146701],
|
||||
[360.000, 1.909146],
|
||||
[365.000, 2.780800],
|
||||
[370.000, 3.713127],
|
||||
[375.000, 4.657588],
|
||||
[380.000, 5.565646],
|
||||
[385.000, 6.388762],
|
||||
[390.000, 7.078401],
|
||||
[395.000, 7.586023],
|
||||
[400.000, 7.863092],
|
||||
[402.500, 7.900001],
|
||||
[527.500, 7.900001],
|
||||
[532.500, 7.756411],
|
||||
[537.500, 7.357998],
|
||||
[542.500, 6.753300],
|
||||
[547.500, 5.990855],
|
||||
[552.500, 5.119201],
|
||||
[557.500, 4.186874],
|
||||
[562.500, 3.242413],
|
||||
[567.500, 2.334355],
|
||||
[572.500, 1.511239],
|
||||
[577.500, 0.821600],
|
||||
[582.500, 0.313978],
|
||||
[587.500, 0.036909],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.119741],
|
||||
[140.000, 0.453072],
|
||||
[145.000, 0.961161],
|
||||
[150.000, 1.605171],
|
||||
[155.000, 2.346268],
|
||||
[160.000, 3.145617],
|
||||
[165.000, 3.964384],
|
||||
[170.000, 4.763733],
|
||||
[175.000, 5.504830],
|
||||
[180.000, 6.148840],
|
||||
[185.000, 6.656929],
|
||||
[190.000, 6.990260],
|
||||
[195.000, 7.110001],
|
||||
[325.000, 7.110001],
|
||||
[330.000, 6.990260],
|
||||
[335.000, 6.656929],
|
||||
[340.000, 6.148840],
|
||||
[345.000, 5.504830],
|
||||
[350.000, 4.763733],
|
||||
[355.000, 3.964384],
|
||||
[360.000, 3.145617],
|
||||
[365.000, 2.346268],
|
||||
[370.000, 1.605171],
|
||||
[375.000, 0.961161],
|
||||
[380.000, 0.453072],
|
||||
[385.000, 0.119741],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -97, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 97, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -345.5, 155.9556, -352.7 ],
|
||||
[ -145.5, 155.9556, -352.7 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -97, 155.9556, -281.6 ],
|
||||
[ -97, 155.9556, -31.6 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 0, 155.9556, -281.6 ],
|
||||
[ 0, 155.9556, -31.6 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 97, 155.9556, -281.6 ],
|
||||
[ 97, 155.9556, -31.6 ]
|
||||
]
|
||||
|
||||
# primary_1
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ -97, 155.9556, 39.5 ],
|
||||
[ -96.0215, 153.1933, 51.498 ],
|
||||
[ -93.2563, 148.862, 61.7643 ],
|
||||
[ -88.9596, 143.0867, 70.4309 ],
|
||||
[ -83.3866, 135.9922, 77.6302 ],
|
||||
[ -76.7926, 127.7034, 83.4941 ],
|
||||
[ -69.4328, 118.3452, 88.1548 ],
|
||||
[ -61.5625, 108.0425, 91.7445 ],
|
||||
[ -53.437, 96.9201, 94.3953 ],
|
||||
[ -45.3115, 85.103, 96.2394 ],
|
||||
[ -37.4412, 72.716, 97.4088 ],
|
||||
[ -30.0814, 59.884, 98.0358 ],
|
||||
[ -23.4874, 46.7319, 98.2525 ],
|
||||
[ -17.9144, 33.3846, 98.191 ],
|
||||
[ -13.6177, 19.9669, 97.9834 ],
|
||||
[ -10.8525, 6.6038, 97.762 ],
|
||||
[ -9.874, -6.5798, 97.6589 ]
|
||||
]
|
||||
|
||||
# primary_2
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 0, 155.9556, 39.5 ],
|
||||
[ 0, 153.2938, 50.2812 ],
|
||||
[ 0, 148.8738, 59.6443 ],
|
||||
[ 0, 142.8582, 67.689 ],
|
||||
[ 0, 135.4095, 74.515 ],
|
||||
[ 0, 126.6903, 80.2221 ],
|
||||
[ 0, 116.8632, 84.9099 ],
|
||||
[ 0, 106.0908, 88.678 ],
|
||||
[ 0, 94.5355, 91.6263 ],
|
||||
[ 0, 82.36, 93.8543 ],
|
||||
[ 0, 69.7268, 95.4619 ],
|
||||
[ 0, 56.7985, 96.5485 ],
|
||||
[ 0, 43.7377, 97.2141 ],
|
||||
[ 0, 30.7069, 97.5582 ],
|
||||
[ 0, 17.8686, 97.6806 ],
|
||||
[ 0, 5.3855, 97.6809 ],
|
||||
[ 0, -6.5798, 97.6589 ]
|
||||
]
|
||||
|
||||
# primary_3
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ 97, 155.9556, 39.5 ],
|
||||
[ 96.0215, 153.1933, 51.498 ],
|
||||
[ 93.2563, 148.862, 61.7643 ],
|
||||
[ 88.9596, 143.0867, 70.4309 ],
|
||||
[ 83.3866, 135.9922, 77.6302 ],
|
||||
[ 76.7926, 127.7034, 83.4941 ],
|
||||
[ 69.4328, 118.3452, 88.1548 ],
|
||||
[ 61.5625, 108.0425, 91.7445 ],
|
||||
[ 53.437, 96.9201, 94.3953 ],
|
||||
[ 45.3115, 85.103, 96.2394 ],
|
||||
[ 37.4412, 72.716, 97.4088 ],
|
||||
[ 30.0814, 59.884, 98.0358 ],
|
||||
[ 23.4874, 46.7319, 98.2525 ],
|
||||
[ 17.9144, 33.3846, 98.191 ],
|
||||
[ 13.6177, 19.9669, 97.9834 ],
|
||||
[ 10.8525, 6.6038, 97.762 ],
|
||||
[ 9.874, -6.5798, 97.6589 ]
|
||||
]
|
||||
|
||||
# tailpipe_7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 218.4202, -70, 164.25 ],
|
||||
[ 1718.4201, -70, 164.25 ]
|
||||
]
|
||||
|
||||
# secondary_8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 18.4202, -29.1445, 109.776 ],
|
||||
[ 29.9012, -29.5568, 110.3258 ],
|
||||
[ 40.8688, -30.722, 111.8793 ],
|
||||
[ 51.3963, -32.5324, 114.2932 ],
|
||||
[ 61.5571, -34.8806, 117.4242 ],
|
||||
[ 71.4246, -37.659, 121.1287 ],
|
||||
[ 81.072, -40.7601, 125.2635 ],
|
||||
[ 90.5727, -44.0763, 129.685 ],
|
||||
[ 100, -47.5, 134.25 ],
|
||||
[ 109.4274, -50.9237, 138.815 ],
|
||||
[ 118.9281, -54.2399, 143.2365 ],
|
||||
[ 128.5754, -57.341, 147.3713 ],
|
||||
[ 138.4429, -60.1194, 151.0758 ],
|
||||
[ 148.6037, -62.4676, 154.2068 ],
|
||||
[ 159.1312, -64.278, 156.6207 ],
|
||||
[ 170.0988, -65.4432, 158.1742 ],
|
||||
[ 181.5798, -65.8555, 158.724 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 155.9556, -352.7 ]
|
||||
size_mm = [ 291, 72.4984, 142.2 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ 0, -25, 104.25 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 200, -70, 164.25 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "twin-270"
|
||||
name = "700 cc / 270-degree parallel twin"
|
||||
category = "Twins / parallel"
|
||||
@@ -7,9 +7,11 @@ description = "Estimated concept calibration / EFI"
|
||||
order = 19
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 50.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 0.5
|
||||
cylinders = 2
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 2.0
|
||||
starter_torque_nm = 17.09026
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 25.6
|
||||
exhaust_valve_lift_mm = 7.2
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 30.4
|
||||
intake_valve_lift_mm = 8.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 122.4
|
||||
stroke_mm = 68.0
|
||||
@@ -101,26 +96,208 @@ system = "injection"
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 2
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 2
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.145408],
|
||||
[350.000, 0.548864],
|
||||
[355.000, 1.161216],
|
||||
[360.000, 1.933312],
|
||||
[365.000, 2.816000],
|
||||
[370.000, 3.760128],
|
||||
[375.000, 4.716544],
|
||||
[380.000, 5.636096],
|
||||
[385.000, 6.469632],
|
||||
[390.000, 7.168000],
|
||||
[395.000, 7.682048],
|
||||
[400.000, 7.962624],
|
||||
[402.500, 8.000000],
|
||||
[527.500, 8.000000],
|
||||
[532.500, 7.854592],
|
||||
[537.500, 7.451136],
|
||||
[542.500, 6.838784],
|
||||
[547.500, 6.066688],
|
||||
[552.500, 5.184000],
|
||||
[557.500, 4.239872],
|
||||
[562.500, 3.283456],
|
||||
[567.500, 2.363904],
|
||||
[572.500, 1.530368],
|
||||
[577.500, 0.832000],
|
||||
[582.500, 0.317952],
|
||||
[587.500, 0.037376],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.121256],
|
||||
[140.000, 0.458807],
|
||||
[145.000, 0.973327],
|
||||
[150.000, 1.625489],
|
||||
[155.000, 2.375967],
|
||||
[160.000, 3.185435],
|
||||
[165.000, 4.014565],
|
||||
[170.000, 4.824033],
|
||||
[175.000, 5.574511],
|
||||
[180.000, 6.226673],
|
||||
[185.000, 6.741193],
|
||||
[190.000, 7.078744],
|
||||
[195.000, 7.200000],
|
||||
[325.000, 7.200000],
|
||||
[330.000, 7.078744],
|
||||
[335.000, 6.741193],
|
||||
[340.000, 6.226673],
|
||||
[345.000, 5.574511],
|
||||
[350.000, 4.824033],
|
||||
[355.000, 4.014565],
|
||||
[360.000, 3.185435],
|
||||
[365.000, 2.375967],
|
||||
[370.000, 1.625489],
|
||||
[375.000, 0.973327],
|
||||
[380.000, 0.458807],
|
||||
[385.000, 0.121256],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -49, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 49, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -298, 155.9556, -354 ],
|
||||
[ -98, 155.9556, -354 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -49, 155.9556, -282 ],
|
||||
[ -49, 155.9556, -32 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 49, 155.9556, -282 ],
|
||||
[ 49, 155.9556, -32 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ -49, 155.9556, 40 ],
|
||||
[ -47.6414, 152.9696, 53.5851 ],
|
||||
[ -43.8021, 148.472, 65.1692 ],
|
||||
[ -37.8363, 142.566, 74.9076 ],
|
||||
[ -30.0984, 135.3552, 82.9554 ],
|
||||
[ -20.943, 126.9429, 89.4678 ],
|
||||
[ -10.7243, 117.4325, 94.5999 ],
|
||||
[ 0.2032, 106.9274, 98.5068 ],
|
||||
[ 11.485, 95.5311, 101.3437 ],
|
||||
[ 22.7669, 83.347, 103.2658 ],
|
||||
[ 33.6944, 70.4784, 104.4283 ],
|
||||
[ 43.913, 57.0288, 104.9862 ],
|
||||
[ 53.0685, 43.1016, 105.0948 ],
|
||||
[ 60.8063, 28.8002, 104.9091 ],
|
||||
[ 66.7721, 14.2281, 104.5844 ],
|
||||
[ 70.6115, -0.5115, 104.2758 ],
|
||||
[ 71.9701, -15.315, 104.1385 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 49, 155.9556, 40 ],
|
||||
[ 49.465, 153.1235, 51.7218 ],
|
||||
[ 50.7792, 148.49, 61.9229 ],
|
||||
[ 52.8211, 142.2161, 70.709 ],
|
||||
[ 55.4697, 134.4629, 78.1854 ],
|
||||
[ 58.6034, 125.3916, 84.4576 ],
|
||||
[ 62.1011, 115.1632, 89.631 ],
|
||||
[ 65.8413, 103.9388, 93.8112 ],
|
||||
[ 69.7029, 91.8796, 97.1037 ],
|
||||
[ 73.5645, 79.1467, 99.6138 ],
|
||||
[ 77.3048, 65.9012, 101.447 ],
|
||||
[ 80.8024, 52.3041, 102.7088 ],
|
||||
[ 83.9362, 38.5167, 103.5048 ],
|
||||
[ 86.5847, 24.6999, 103.9402 ],
|
||||
[ 88.6267, 11.015, 104.1207 ],
|
||||
[ 89.9409, -2.377, 104.1516 ],
|
||||
[ 90.4059, -15.315, 104.1385 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 139.685, -55, 119 ],
|
||||
[ 1639.685, -55, 119 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 155.9556, -354 ]
|
||||
size_mm = [ 196, 70.8617, 144 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 119 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "twin"
|
||||
name = "600 cc parallel twin"
|
||||
category = "Twins / parallel"
|
||||
@@ -7,9 +7,11 @@ description = "EFI motorcycle baseline"
|
||||
order = 0
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 50.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 0.15
|
||||
cylinders = 2
|
||||
initial_rpm = 2000.0
|
||||
initialize_phased_charge = false
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 180.0]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 1.0
|
||||
starter_torque_nm = 18.0
|
||||
throttle_diameter_mm = 26.0
|
||||
topology = "collector"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 11.5
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 26.0
|
||||
exhaust_valve_lift_mm = 7.5
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 30.0
|
||||
intake_valve_lift_mm = 8.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 112.0
|
||||
stroke_mm = 68.0
|
||||
@@ -101,26 +96,208 @@ system = "injection"
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 10
|
||||
diameter_mm = 27.5
|
||||
length_mm = 60.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 2
|
||||
cells = 10
|
||||
diameter_mm = 27.5
|
||||
length_mm = 120.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 2
|
||||
cells = 6
|
||||
diameter_mm = 28.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe"
|
||||
cells = 10
|
||||
diameter_mm = 28.0
|
||||
length_mm = 400.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.145408],
|
||||
[350.000, 0.548864],
|
||||
[355.000, 1.161216],
|
||||
[360.000, 1.933312],
|
||||
[365.000, 2.816000],
|
||||
[370.000, 3.760128],
|
||||
[375.000, 4.716544],
|
||||
[380.000, 5.636096],
|
||||
[385.000, 6.469632],
|
||||
[390.000, 7.168000],
|
||||
[395.000, 7.682048],
|
||||
[400.000, 7.962624],
|
||||
[402.500, 8.000000],
|
||||
[527.500, 8.000000],
|
||||
[532.500, 7.854592],
|
||||
[537.500, 7.451136],
|
||||
[542.500, 6.838784],
|
||||
[547.500, 6.066688],
|
||||
[552.500, 5.184000],
|
||||
[557.500, 4.239872],
|
||||
[562.500, 3.283456],
|
||||
[567.500, 2.363904],
|
||||
[572.500, 1.530368],
|
||||
[577.500, 0.832000],
|
||||
[582.500, 0.317952],
|
||||
[587.500, 0.037376],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.126309],
|
||||
[140.000, 0.477924],
|
||||
[145.000, 1.013883],
|
||||
[150.000, 1.693218],
|
||||
[155.000, 2.474966],
|
||||
[160.000, 3.318161],
|
||||
[165.000, 4.181839],
|
||||
[170.000, 5.025034],
|
||||
[175.000, 5.806782],
|
||||
[180.000, 6.486117],
|
||||
[185.000, 7.022076],
|
||||
[190.000, 7.373691],
|
||||
[195.000, 7.500000],
|
||||
[325.000, 7.500000],
|
||||
[330.000, 7.373691],
|
||||
[335.000, 7.022076],
|
||||
[340.000, 6.486117],
|
||||
[345.000, 5.806782],
|
||||
[350.000, 5.025034],
|
||||
[355.000, 4.181839],
|
||||
[360.000, 3.318161],
|
||||
[365.000, 2.474966],
|
||||
[370.000, 1.693218],
|
||||
[375.000, 1.013883],
|
||||
[380.000, 0.477924],
|
||||
[385.000, 0.126309],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -46.5, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 46.5, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -153, 144.4762, -217.5 ],
|
||||
[ -93, 144.4762, -217.5 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -46.5, 144.4762, -150 ],
|
||||
[ -46.5, 144.4762, -30 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 46.5, 144.4762, -150 ],
|
||||
[ 46.5, 144.4762, -30 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ -46.5, 144.4762, 37.5 ],
|
||||
[ -45.0739, 141.4466, 51.4126 ],
|
||||
[ -41.0434, 136.9192, 63.2857 ],
|
||||
[ -34.7808, 130.9928, 73.2768 ],
|
||||
[ -26.658, 123.7661, 81.5435 ],
|
||||
[ -17.047, 115.3378, 88.2433 ],
|
||||
[ -6.3199, 105.8067, 93.5338 ],
|
||||
[ 5.1513, 95.2715, 97.5727 ],
|
||||
[ 16.9945, 83.831, 100.5174 ],
|
||||
[ 28.8377, 71.584, 102.5255 ],
|
||||
[ 40.3089, 58.6292, 103.7547 ],
|
||||
[ 51.036, 45.0653, 104.3624 ],
|
||||
[ 60.6469, 30.9911, 104.5063 ],
|
||||
[ 68.7698, 16.5054, 104.344 ],
|
||||
[ 75.0324, 1.7069, 104.0329 ],
|
||||
[ 79.0628, -13.3057, 103.7307 ],
|
||||
[ 80.489, -28.4335, 103.5949 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 46.5, 144.4762, 37.5 ],
|
||||
[ 47.0208, 141.6097, 49.4384 ],
|
||||
[ 48.4927, 136.9383, 59.8461 ],
|
||||
[ 50.7797, 130.622, 68.8281 ],
|
||||
[ 53.7461, 122.8206, 76.4893 ],
|
||||
[ 57.2559, 113.6941, 82.9347 ],
|
||||
[ 61.1733, 103.4022, 88.2691 ],
|
||||
[ 65.3624, 92.1049, 92.5975 ],
|
||||
[ 69.6874, 79.9621, 96.0248 ],
|
||||
[ 74.0124, 67.1336, 98.6559 ],
|
||||
[ 78.2015, 53.7794, 100.5958 ],
|
||||
[ 82.1189, 40.0593, 101.9494 ],
|
||||
[ 85.6288, 26.1331, 102.8216 ],
|
||||
[ 88.5951, 12.1609, 103.3173 ],
|
||||
[ 90.8821, -1.6975, 103.5415 ],
|
||||
[ 92.354, -15.2823, 103.5991 ],
|
||||
[ 92.8748, -28.4335, 103.5949 ]
|
||||
]
|
||||
|
||||
# tailpipe
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 126.5665, -55, 113.75 ],
|
||||
[ 526.5663, -55, 113.75 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 144.4762, -217.5 ]
|
||||
size_mm = [ 186, 39.8248, 135 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "exhaust_collector"
|
||||
center_mm = [ 100, -55, 113.75 ]
|
||||
size_mm = [ 53.1329, 53.1329, 53.1329 ]
|
||||
|
||||
585
engines/v10.toml
585
engines/v10.toml
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "v10"
|
||||
name = "5.0 litre / even-fire V10"
|
||||
category = "V10"
|
||||
@@ -7,9 +7,11 @@ description = "Separate five-cylinder banks / junction collectors / dual outlets
|
||||
order = 30
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 72.0
|
||||
collector_volume_litres = 2.5
|
||||
cylinders = 10
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 576.0, 432.0, 288.0, 144.0, 648.0001, 504.0, 360.0, 216.0, 72.00003]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 10.0
|
||||
starter_torque_nm = 124.9751
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "staged"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 29.44
|
||||
exhaust_valve_lift_mm = 8.280001
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 34.96
|
||||
intake_valve_lift_mm = 9.2
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 135.36
|
||||
stroke_mm = 75.2
|
||||
@@ -101,101 +96,607 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 10
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_1"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_2"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_3"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_4"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_5"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_6"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_7"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_8"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_9"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_10"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_21"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_22"
|
||||
cells = 28
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1380.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_23"
|
||||
cells = 9
|
||||
diameter_mm = 48.0
|
||||
length_mm = 420.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_24"
|
||||
cells = 11
|
||||
diameter_mm = 48.0
|
||||
length_mm = 540.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.167219],
|
||||
[350.000, 0.631194],
|
||||
[355.000, 1.335398],
|
||||
[360.000, 2.223309],
|
||||
[365.000, 3.238400],
|
||||
[370.000, 4.324147],
|
||||
[375.000, 5.424026],
|
||||
[380.000, 6.481510],
|
||||
[385.000, 7.440077],
|
||||
[390.000, 8.243200],
|
||||
[395.000, 8.834355],
|
||||
[400.000, 9.157018],
|
||||
[402.500, 9.200000],
|
||||
[527.500, 9.200000],
|
||||
[532.500, 9.032781],
|
||||
[537.500, 8.568806],
|
||||
[542.500, 7.864602],
|
||||
[547.500, 6.976691],
|
||||
[552.500, 5.961600],
|
||||
[557.500, 4.875853],
|
||||
[562.500, 3.775974],
|
||||
[567.500, 2.718490],
|
||||
[572.500, 1.759923],
|
||||
[577.500, 0.956800],
|
||||
[582.500, 0.365645],
|
||||
[587.500, 0.042982],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.139445],
|
||||
[140.000, 0.527629],
|
||||
[145.000, 1.119326],
|
||||
[150.000, 1.869313],
|
||||
[155.000, 2.732363],
|
||||
[160.000, 3.663250],
|
||||
[165.000, 4.616751],
|
||||
[170.000, 5.547638],
|
||||
[175.000, 6.410688],
|
||||
[180.000, 7.160675],
|
||||
[185.000, 7.752372],
|
||||
[190.000, 8.140556],
|
||||
[195.000, 8.280001],
|
||||
[325.000, 8.280001],
|
||||
[330.000, 8.140556],
|
||||
[335.000, 7.752372],
|
||||
[340.000, 7.160675],
|
||||
[345.000, 6.410688],
|
||||
[350.000, 5.547638],
|
||||
[355.000, 4.616751],
|
||||
[360.000, 3.663250],
|
||||
[365.000, 2.732363],
|
||||
[370.000, 1.869313],
|
||||
[375.000, 1.119326],
|
||||
[380.000, 0.527629],
|
||||
[385.000, 0.139445],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -220, 0, 0 ]
|
||||
tilt_deg = -36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -110, 0, 0 ]
|
||||
tilt_deg = -36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = -36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 110, 0, 0 ]
|
||||
tilt_deg = -36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 220, 0, 0 ]
|
||||
tilt_deg = -36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -220, 0, 0 ]
|
||||
tilt_deg = 36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -110, 0, 0 ]
|
||||
tilt_deg = 36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 110, 0, 0 ]
|
||||
tilt_deg = 36.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 220, 0, 0 ]
|
||||
tilt_deg = 36.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -475, 450.3337, 0 ],
|
||||
[ -275, 450.3337, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -220, 411.8457, -72.1005 ],
|
||||
[ -220, 161.8457, -72.1005 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -110, 411.8457, -72.1005 ],
|
||||
[ -110, 161.8457, -72.1005 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 0, 411.8457, -72.1005 ],
|
||||
[ 0, 161.8457, -72.1005 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 110, 411.8457, -72.1005 ],
|
||||
[ 110, 161.8457, -72.1005 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 220, 411.8457, -72.1005 ],
|
||||
[ 220, 161.8457, -72.1005 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -220, 411.8457, 72.1005 ],
|
||||
[ -220, 161.8457, 72.1005 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -110, 411.8457, 72.1005 ],
|
||||
[ -110, 161.8457, 72.1005 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 0, 411.8457, 72.1005 ],
|
||||
[ 0, 161.8457, 72.1005 ]
|
||||
]
|
||||
|
||||
# runners 9
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ 110, 411.8457, 72.1005 ],
|
||||
[ 110, 161.8457, 72.1005 ]
|
||||
]
|
||||
|
||||
# runners 10
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ 220, 411.8457, 72.1005 ],
|
||||
[ 220, 161.8457, 72.1005 ]
|
||||
]
|
||||
|
||||
# primary_1
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ -220, 113.1771, -139.0871 ],
|
||||
[ -218.6901, 101.7204, -149.7241 ],
|
||||
[ -214.8997, 90.254, -158.5286 ],
|
||||
[ -208.8379, 78.8812, -165.6588 ],
|
||||
[ -200.7136, 67.7054, -171.2728 ],
|
||||
[ -190.7357, 56.8299, -175.5288 ],
|
||||
[ -179.1134, 46.358, -178.5849 ],
|
||||
[ -166.0556, 36.3931, -180.5993 ],
|
||||
[ -151.7712, 27.0384, -181.7302 ],
|
||||
[ -136.4693, 18.3972, -182.1357 ],
|
||||
[ -120.3588, 10.573, -181.974 ],
|
||||
[ -103.6488, 3.6691, -181.4032 ],
|
||||
[ -86.5482, -2.2113, -180.5816 ],
|
||||
[ -69.2661, -6.9648, -179.6672 ],
|
||||
[ -52.0114, -10.4881, -178.8183 ],
|
||||
[ -34.9931, -12.6778, -178.1929 ],
|
||||
[ -18.4202, -13.4307, -177.9493 ]
|
||||
]
|
||||
|
||||
# primary_2
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ -110, 113.1771, -139.0871 ],
|
||||
[ -108.9293, 105.9052, -146.1577 ],
|
||||
[ -105.9035, 98.9449, -152.2659 ],
|
||||
[ -101.2019, 92.2234, -157.4816 ],
|
||||
[ -95.1037, 85.6677, -161.8746 ],
|
||||
[ -87.8884, 79.2051, -165.5148 ],
|
||||
[ -79.8351, 72.7626, -168.472 ],
|
||||
[ -71.2232, 66.2675, -170.816 ],
|
||||
[ -62.332, 59.6468, -172.6168 ],
|
||||
[ -53.4407, 52.8278, -173.9442 ],
|
||||
[ -44.8288, 45.7375, -174.8679 ],
|
||||
[ -36.7756, 38.3031, -175.458 ],
|
||||
[ -29.5602, 30.4518, -175.7841 ],
|
||||
[ -23.462, 22.1107, -175.9161 ],
|
||||
[ -18.7604, 13.207, -175.924 ],
|
||||
[ -15.7346, 3.6677, -175.8775 ],
|
||||
[ -14.6639, -6.5798, -175.8465 ]
|
||||
]
|
||||
|
||||
# primary_3
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ 0, 113.1771, -139.0871 ],
|
||||
[ 0, 107.1157, -144.7979 ],
|
||||
[ 0, 100.8007, -149.8969 ],
|
||||
[ 0, 94.2457, -154.4176 ],
|
||||
[ 0, 87.4644, -158.3936 ],
|
||||
[ 0, 80.4706, -161.8586 ],
|
||||
[ 0, 73.2778, -164.846 ],
|
||||
[ 0, 65.8998, -167.3895 ],
|
||||
[ 0, 58.3503, -169.5227 ],
|
||||
[ 0, 50.6429, -171.2791 ],
|
||||
[ 0, 42.7913, -172.6924 ],
|
||||
[ 0, 34.8092, -173.7961 ],
|
||||
[ 0, 26.7103, -174.6238 ],
|
||||
[ 0, 18.5083, -175.2091 ],
|
||||
[ 0, 10.2168, -175.5856 ],
|
||||
[ 0, 1.8495, -175.7868 ],
|
||||
[ 0, -6.5798, -175.8465 ]
|
||||
]
|
||||
|
||||
# primary_4
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ 110, 113.1771, -139.0871 ],
|
||||
[ 108.9293, 105.9052, -146.1577 ],
|
||||
[ 105.9035, 98.9449, -152.2659 ],
|
||||
[ 101.2019, 92.2234, -157.4816 ],
|
||||
[ 95.1037, 85.6677, -161.8746 ],
|
||||
[ 87.8884, 79.2051, -165.5148 ],
|
||||
[ 79.8351, 72.7626, -168.472 ],
|
||||
[ 71.2232, 66.2675, -170.816 ],
|
||||
[ 62.332, 59.6468, -172.6168 ],
|
||||
[ 53.4407, 52.8278, -173.9442 ],
|
||||
[ 44.8288, 45.7375, -174.8679 ],
|
||||
[ 36.7756, 38.3031, -175.458 ],
|
||||
[ 29.5602, 30.4518, -175.7841 ],
|
||||
[ 23.462, 22.1107, -175.9161 ],
|
||||
[ 18.7604, 13.207, -175.924 ],
|
||||
[ 15.7346, 3.6677, -175.8775 ],
|
||||
[ 14.6639, -6.5798, -175.8465 ]
|
||||
]
|
||||
|
||||
# primary_5
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 220, 113.1771, -139.0871 ],
|
||||
[ 218.6901, 101.7204, -149.7241 ],
|
||||
[ 214.8997, 90.254, -158.5286 ],
|
||||
[ 208.8379, 78.8812, -165.6588 ],
|
||||
[ 200.7136, 67.7054, -171.2728 ],
|
||||
[ 190.7357, 56.8299, -175.5288 ],
|
||||
[ 179.1134, 46.358, -178.5849 ],
|
||||
[ 166.0556, 36.3931, -180.5993 ],
|
||||
[ 151.7712, 27.0384, -181.7302 ],
|
||||
[ 136.4693, 18.3972, -182.1357 ],
|
||||
[ 120.3588, 10.573, -181.974 ],
|
||||
[ 103.6488, 3.6691, -181.4032 ],
|
||||
[ 86.5483, -2.2113, -180.5816 ],
|
||||
[ 69.2661, -6.9648, -179.6672 ],
|
||||
[ 52.0114, -10.4881, -178.8183 ],
|
||||
[ 34.9931, -12.6778, -178.1929 ],
|
||||
[ 18.4202, -13.4307, -177.9493 ]
|
||||
]
|
||||
|
||||
# primary_6
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ -220, 113.1771, 139.0871 ],
|
||||
[ -218.6901, 101.7204, 149.7241 ],
|
||||
[ -214.8997, 90.254, 158.5286 ],
|
||||
[ -208.8379, 78.8812, 165.6588 ],
|
||||
[ -200.7136, 67.7054, 171.2728 ],
|
||||
[ -190.7357, 56.8299, 175.5288 ],
|
||||
[ -179.1134, 46.358, 178.5849 ],
|
||||
[ -166.0556, 36.3931, 180.5993 ],
|
||||
[ -151.7712, 27.0384, 181.7302 ],
|
||||
[ -136.4693, 18.3972, 182.1357 ],
|
||||
[ -120.3588, 10.573, 181.974 ],
|
||||
[ -103.6488, 3.6691, 181.4032 ],
|
||||
[ -86.5482, -2.2113, 180.5816 ],
|
||||
[ -69.2661, -6.9648, 179.6672 ],
|
||||
[ -52.0114, -10.4881, 178.8183 ],
|
||||
[ -34.9931, -12.6778, 178.1929 ],
|
||||
[ -18.4202, -13.4307, 177.9493 ]
|
||||
]
|
||||
|
||||
# primary_7
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ -110, 113.1771, 139.0871 ],
|
||||
[ -108.9293, 105.9052, 146.1577 ],
|
||||
[ -105.9035, 98.9449, 152.2659 ],
|
||||
[ -101.2019, 92.2234, 157.4816 ],
|
||||
[ -95.1037, 85.6677, 161.8746 ],
|
||||
[ -87.8884, 79.2051, 165.5148 ],
|
||||
[ -79.8351, 72.7626, 168.472 ],
|
||||
[ -71.2232, 66.2675, 170.816 ],
|
||||
[ -62.332, 59.6468, 172.6168 ],
|
||||
[ -53.4407, 52.8278, 173.9442 ],
|
||||
[ -44.8288, 45.7375, 174.8679 ],
|
||||
[ -36.7756, 38.3031, 175.458 ],
|
||||
[ -29.5602, 30.4518, 175.7841 ],
|
||||
[ -23.462, 22.1107, 175.9161 ],
|
||||
[ -18.7604, 13.207, 175.924 ],
|
||||
[ -15.7346, 3.6677, 175.8775 ],
|
||||
[ -14.6639, -6.5798, 175.8465 ]
|
||||
]
|
||||
|
||||
# primary_8
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 0, 113.1771, 139.0871 ],
|
||||
[ 0, 107.1157, 144.7979 ],
|
||||
[ 0, 100.8007, 149.8969 ],
|
||||
[ 0, 94.2457, 154.4176 ],
|
||||
[ 0, 87.4644, 158.3936 ],
|
||||
[ 0, 80.4706, 161.8586 ],
|
||||
[ 0, 73.2778, 164.846 ],
|
||||
[ 0, 65.8998, 167.3895 ],
|
||||
[ 0, 58.3503, 169.5227 ],
|
||||
[ 0, 50.6429, 171.2791 ],
|
||||
[ 0, 42.7913, 172.6924 ],
|
||||
[ 0, 34.8092, 173.7961 ],
|
||||
[ 0, 26.7103, 174.6238 ],
|
||||
[ 0, 18.5083, 175.2091 ],
|
||||
[ 0, 10.2168, 175.5856 ],
|
||||
[ 0, 1.8495, 175.7868 ],
|
||||
[ 0, -6.5798, 175.8465 ]
|
||||
]
|
||||
|
||||
# primary_9
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ 110, 113.1771, 139.0871 ],
|
||||
[ 108.9293, 105.9052, 146.1577 ],
|
||||
[ 105.9035, 98.9449, 152.2659 ],
|
||||
[ 101.2019, 92.2234, 157.4816 ],
|
||||
[ 95.1037, 85.6677, 161.8746 ],
|
||||
[ 87.8884, 79.2051, 165.5148 ],
|
||||
[ 79.8351, 72.7626, 168.472 ],
|
||||
[ 71.2232, 66.2675, 170.816 ],
|
||||
[ 62.332, 59.6468, 172.6168 ],
|
||||
[ 53.4407, 52.8278, 173.9442 ],
|
||||
[ 44.8288, 45.7375, 174.8679 ],
|
||||
[ 36.7756, 38.3031, 175.458 ],
|
||||
[ 29.5602, 30.4518, 175.7841 ],
|
||||
[ 23.462, 22.1107, 175.9161 ],
|
||||
[ 18.7604, 13.207, 175.924 ],
|
||||
[ 15.7346, 3.6677, 175.8775 ],
|
||||
[ 14.6639, -6.5798, 175.8465 ]
|
||||
]
|
||||
|
||||
# primary_10
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ 220, 113.1771, 139.0871 ],
|
||||
[ 218.6901, 101.7204, 149.7241 ],
|
||||
[ 214.8997, 90.254, 158.5286 ],
|
||||
[ 208.8379, 78.8812, 165.6588 ],
|
||||
[ 200.7136, 67.7054, 171.2728 ],
|
||||
[ 190.7357, 56.8299, 175.5288 ],
|
||||
[ 179.1134, 46.358, 178.5849 ],
|
||||
[ 166.0556, 36.3931, 180.5993 ],
|
||||
[ 151.7712, 27.0384, 181.7302 ],
|
||||
[ 136.4693, 18.3972, 182.1357 ],
|
||||
[ 120.3588, 10.573, 181.974 ],
|
||||
[ 103.6488, 3.6691, 181.4032 ],
|
||||
[ 86.5483, -2.2113, 180.5816 ],
|
||||
[ 69.2661, -6.9648, 179.6672 ],
|
||||
[ 52.0114, -10.4881, 178.8183 ],
|
||||
[ 34.9931, -12.6778, 178.1929 ],
|
||||
[ 18.4202, -13.4307, 177.9493 ]
|
||||
]
|
||||
|
||||
# tailpipe_21
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ 218.4202, -70, -181.5005 ],
|
||||
[ 1718.4201, -70, -181.5005 ]
|
||||
]
|
||||
|
||||
# tailpipe_22
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 218.4202, -70, 181.5005 ],
|
||||
[ 1598.4201, -70, 181.5005 ]
|
||||
]
|
||||
|
||||
# secondary_23
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 18.4202, -29.1445, -164.7842 ],
|
||||
[ 29.5589, -29.5568, -164.9719 ],
|
||||
[ 40.3211, -30.722, -165.5024 ],
|
||||
[ 50.7606, -32.5324, -166.3268 ],
|
||||
[ 60.9312, -34.8806, -167.3961 ],
|
||||
[ 70.8866, -37.659, -168.6613 ],
|
||||
[ 80.6807, -40.7601, -170.0733 ],
|
||||
[ 90.3673, -44.0763, -171.5833 ],
|
||||
[ 100, -47.5, -173.1423 ],
|
||||
[ 109.6328, -50.9237, -174.7013 ],
|
||||
[ 119.3193, -54.2399, -176.2114 ],
|
||||
[ 129.1134, -57.341, -177.6234 ],
|
||||
[ 139.0688, -60.1194, -178.8886 ],
|
||||
[ 149.2394, -62.4676, -179.9578 ],
|
||||
[ 159.6789, -64.278, -180.7822 ],
|
||||
[ 170.4412, -65.4432, -181.3128 ],
|
||||
[ 181.5798, -65.8555, -181.5005 ]
|
||||
]
|
||||
|
||||
# secondary_24
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 18.4202, -29.1445, 164.7842 ],
|
||||
[ 29.5589, -29.5568, 164.9719 ],
|
||||
[ 40.3211, -30.722, 165.5024 ],
|
||||
[ 50.7606, -32.5324, 166.3268 ],
|
||||
[ 60.9312, -34.8806, 167.3961 ],
|
||||
[ 70.8866, -37.659, 168.6613 ],
|
||||
[ 80.6807, -40.7601, 170.0733 ],
|
||||
[ 90.3673, -44.0763, 171.5833 ],
|
||||
[ 100, -47.5, 173.1423 ],
|
||||
[ 109.6328, -50.9237, 174.7013 ],
|
||||
[ 119.3193, -54.2399, 176.2114 ],
|
||||
[ 129.1134, -57.341, 177.6234 ],
|
||||
[ 139.0688, -60.1194, 178.8886 ],
|
||||
[ 149.2394, -62.4676, 179.9578 ],
|
||||
[ 159.6789, -64.278, 180.7822 ],
|
||||
[ 170.4412, -65.4432, 181.3128 ],
|
||||
[ 181.5798, -65.8555, 181.5005 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 450.3337, 0 ]
|
||||
size_mm = [ 550, 76.976, 236.201 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ 0, -25, -181.5005 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 0, -25, 181.5005 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 200, -70, -181.5005 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 200, -70, 181.5005 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
659
engines/v12.toml
659
engines/v12.toml
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "v12"
|
||||
name = "250-inspired / 3.0 V12"
|
||||
category = "V12"
|
||||
@@ -7,9 +7,11 @@ description = "Separate six-cylinder banks / junction collectors / dual outlets"
|
||||
order = 31
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 60.0
|
||||
collector_volume_litres = 3.0
|
||||
cylinders = 12
|
||||
initial_rpm = 1400.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 30.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 600.0, 480.0, 360.0, 240.0, 120.0, 660.0, 540.0, 420.0, 300.0, 180.0, 59.99998]
|
||||
pipe_damping = 0.0
|
||||
plenum_volume_litres = 12.0
|
||||
starter_torque_nm = 73.83022
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "staged"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 60.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 10.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 390.0
|
||||
exhaust_open_deg = 130.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 23.36
|
||||
exhaust_valve_lift_mm = 6.57
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 590.0
|
||||
intake_open_deg = 340.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 27.74
|
||||
intake_valve_lift_mm = 7.3
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 110.0
|
||||
stroke_mm = 58.8
|
||||
@@ -101,113 +96,685 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 4
|
||||
diameter_mm = 75.0
|
||||
length_mm = 200.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 12
|
||||
cells = 5
|
||||
diameter_mm = 35.0
|
||||
length_mm = 250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_1"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_2"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_3"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_4"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_5"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_6"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_7"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_8"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_9"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_10"
|
||||
cells = 11
|
||||
diameter_mm = 38.0
|
||||
length_mm = 520.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_11"
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 585.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primary_12"
|
||||
cells = 13
|
||||
diameter_mm = 38.0
|
||||
length_mm = 650.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_25"
|
||||
cells = 30
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1500.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipe_26"
|
||||
cells = 28
|
||||
diameter_mm = 60.0
|
||||
length_mm = 1380.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_27"
|
||||
cells = 9
|
||||
diameter_mm = 48.0
|
||||
length_mm = 420.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondary_28"
|
||||
cells = 11
|
||||
diameter_mm = 48.0
|
||||
length_mm = 540.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[340.000, 0.000000],
|
||||
[345.000, 0.132685],
|
||||
[350.000, 0.500838],
|
||||
[355.000, 1.059610],
|
||||
[360.000, 1.764147],
|
||||
[365.000, 2.569600],
|
||||
[370.000, 3.431117],
|
||||
[375.000, 4.303846],
|
||||
[380.000, 5.142938],
|
||||
[385.000, 5.903539],
|
||||
[390.000, 6.540800],
|
||||
[395.000, 7.009869],
|
||||
[400.000, 7.265894],
|
||||
[402.500, 7.300000],
|
||||
[527.500, 7.300000],
|
||||
[532.500, 7.167315],
|
||||
[537.500, 6.799162],
|
||||
[542.500, 6.240390],
|
||||
[547.500, 5.535853],
|
||||
[552.500, 4.730400],
|
||||
[557.500, 3.868883],
|
||||
[562.500, 2.996154],
|
||||
[567.500, 2.157062],
|
||||
[572.500, 1.396461],
|
||||
[577.500, 0.759200],
|
||||
[582.500, 0.290131],
|
||||
[587.500, 0.034106],
|
||||
[590.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[130.000, 0.000000],
|
||||
[135.000, 0.110646],
|
||||
[140.000, 0.418662],
|
||||
[145.000, 0.888161],
|
||||
[150.000, 1.483259],
|
||||
[155.000, 2.168070],
|
||||
[160.000, 2.906709],
|
||||
[165.000, 3.663291],
|
||||
[170.000, 4.401930],
|
||||
[175.000, 5.086741],
|
||||
[180.000, 5.681839],
|
||||
[185.000, 6.151338],
|
||||
[190.000, 6.459354],
|
||||
[195.000, 6.570000],
|
||||
[325.000, 6.570000],
|
||||
[330.000, 6.459354],
|
||||
[335.000, 6.151338],
|
||||
[340.000, 5.681839],
|
||||
[345.000, 5.086741],
|
||||
[350.000, 4.401930],
|
||||
[355.000, 3.663291],
|
||||
[360.000, 2.906709],
|
||||
[365.000, 2.168070],
|
||||
[370.000, 1.483259],
|
||||
[375.000, 0.888161],
|
||||
[380.000, 0.418662],
|
||||
[385.000, 0.110646],
|
||||
[390.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -227.5, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -136.5, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -45.5, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 45.5, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 136.5, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 227.5, 0, 0 ]
|
||||
tilt_deg = -30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -227.5, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -136.5, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -45.5, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 45.5, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 136.5, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 227.5, 0, 0 ]
|
||||
tilt_deg = 30.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -473, 452.582, 0 ],
|
||||
[ -273, 452.582, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -227.5, 384.0538, -43.6787 ],
|
||||
[ -227.5, 134.0538, -43.6787 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -136.5, 384.0538, -43.6787 ],
|
||||
[ -136.5, 134.0538, -43.6787 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ -45.5, 384.0538, -43.6787 ],
|
||||
[ -45.5, 134.0538, -43.6787 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 45.5, 384.0538, -43.6787 ],
|
||||
[ 45.5, 134.0538, -43.6787 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ 136.5, 384.0538, -43.6787 ],
|
||||
[ 136.5, 134.0538, -43.6787 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ 227.5, 384.0538, -43.6787 ],
|
||||
[ 227.5, 134.0538, -43.6787 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ -227.5, 384.0538, 43.6787 ],
|
||||
[ -227.5, 134.0538, 43.6787 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ -136.5, 384.0538, 43.6787 ],
|
||||
[ -136.5, 134.0538, 43.6787 ]
|
||||
]
|
||||
|
||||
# runners 9
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -45.5, 384.0538, 43.6787 ],
|
||||
[ -45.5, 134.0538, 43.6787 ]
|
||||
]
|
||||
|
||||
# runners 10
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ 45.5, 384.0538, 43.6787 ],
|
||||
[ 45.5, 134.0538, 43.6787 ]
|
||||
]
|
||||
|
||||
# runners 11
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 136.5, 384.0538, 43.6787 ],
|
||||
[ 136.5, 134.0538, 43.6787 ]
|
||||
]
|
||||
|
||||
# runners 12
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 227.5, 384.0538, 43.6787 ],
|
||||
[ 227.5, 134.0538, 43.6787 ]
|
||||
]
|
||||
|
||||
# primary_1
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ -227.5, 101.2038, -100.5766 ],
|
||||
[ -226.1083, 90.9653, -112.2028 ],
|
||||
[ -222.0863, 80.6518, -121.6751 ],
|
||||
[ -215.6643, 70.3646, -129.1873 ],
|
||||
[ -207.0722, 60.2053, -134.9332 ],
|
||||
[ -196.5399, 50.2753, -139.1062 ],
|
||||
[ -184.2975, 40.6763, -141.9002 ],
|
||||
[ -170.575, 31.5097, -143.5089 ],
|
||||
[ -155.6025, 22.877, -144.1259 ],
|
||||
[ -139.6098, 14.8798, -143.9449 ],
|
||||
[ -122.8271, 7.6195, -143.1596 ],
|
||||
[ -105.4844, 1.1977, -141.9638 ],
|
||||
[ -87.8116, -4.2841, -140.551 ],
|
||||
[ -70.0387, -8.7245, -139.115 ],
|
||||
[ -52.3959, -12.0219, -137.8495 ],
|
||||
[ -35.113, -14.0747, -136.9481 ],
|
||||
[ -18.4202, -14.7816, -136.6046 ]
|
||||
]
|
||||
|
||||
# primary_2
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -136.5, 101.2038, -100.5766 ],
|
||||
[ -135.8239, 93.9039, -108.5849 ],
|
||||
[ -133.853, 85.9308, -115.3225 ],
|
||||
[ -130.6732, 77.4423, -120.8934 ],
|
||||
[ -126.3704, 68.5964, -125.4017 ],
|
||||
[ -121.0305, 59.551, -128.9513 ],
|
||||
[ -114.7394, 50.4638, -131.6465 ],
|
||||
[ -107.5832, 41.4928, -133.5911 ],
|
||||
[ -99.6476, 32.7959, -134.8893 ],
|
||||
[ -91.0187, 24.5308, -135.6451 ],
|
||||
[ -81.7824, 16.8556, -135.9625 ],
|
||||
[ -72.0245, 9.928, -135.9457 ],
|
||||
[ -61.8311, 3.906, -135.6986 ],
|
||||
[ -51.288, -1.0526, -135.3253 ],
|
||||
[ -40.4812, -4.79, -134.9298 ],
|
||||
[ -29.4966, -7.1481, -134.6162 ],
|
||||
[ -18.4202, -7.9693, -134.4886 ]
|
||||
]
|
||||
|
||||
# primary_3
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ -45.5, 101.2038, -100.5766 ],
|
||||
[ -45.0636, 96.0541, -106.4923 ],
|
||||
[ -43.8303, 90.6495, -111.6666 ],
|
||||
[ -41.9139, 84.9992, -116.1491 ],
|
||||
[ -39.4283, 79.1125, -119.9895 ],
|
||||
[ -36.4873, 72.9988, -123.2374 ],
|
||||
[ -33.2048, 66.6673, -125.9425 ],
|
||||
[ -29.6945, 60.1273, -128.1544 ],
|
||||
[ -26.0705, 53.3882, -129.9227 ],
|
||||
[ -22.4464, 46.4591, -131.297 ],
|
||||
[ -18.9362, 39.3495, -132.3271 ],
|
||||
[ -15.6537, 32.0686, -133.0625 ],
|
||||
[ -12.7127, 24.6257, -133.5529 ],
|
||||
[ -10.2271, 17.0302, -133.8479 ],
|
||||
[ -8.3107, 9.2912, -133.9971 ],
|
||||
[ -7.0774, 1.4181, -134.0503 ],
|
||||
[ -6.641, -6.5798, -134.057 ]
|
||||
]
|
||||
|
||||
# primary_4
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ 45.5, 101.2038, -100.5766 ],
|
||||
[ 45.0636, 96.0541, -106.4923 ],
|
||||
[ 43.8303, 90.6495, -111.6666 ],
|
||||
[ 41.9139, 84.9992, -116.1491 ],
|
||||
[ 39.4283, 79.1125, -119.9895 ],
|
||||
[ 36.4873, 72.9988, -123.2374 ],
|
||||
[ 33.2048, 66.6673, -125.9425 ],
|
||||
[ 29.6945, 60.1273, -128.1544 ],
|
||||
[ 26.0705, 53.3882, -129.9227 ],
|
||||
[ 22.4464, 46.4591, -131.297 ],
|
||||
[ 18.9362, 39.3495, -132.3271 ],
|
||||
[ 15.6537, 32.0686, -133.0625 ],
|
||||
[ 12.7127, 24.6257, -133.5529 ],
|
||||
[ 10.2271, 17.0302, -133.8479 ],
|
||||
[ 8.3107, 9.2912, -133.9971 ],
|
||||
[ 7.0774, 1.4181, -134.0503 ],
|
||||
[ 6.641, -6.5798, -134.057 ]
|
||||
]
|
||||
|
||||
# primary_5
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ 136.5, 101.2038, -100.5766 ],
|
||||
[ 135.8239, 93.9039, -108.5849 ],
|
||||
[ 133.853, 85.9308, -115.3225 ],
|
||||
[ 130.6732, 77.4423, -120.8934 ],
|
||||
[ 126.3704, 68.5964, -125.4017 ],
|
||||
[ 121.0305, 59.551, -128.9513 ],
|
||||
[ 114.7394, 50.4638, -131.6465 ],
|
||||
[ 107.5832, 41.4928, -133.5911 ],
|
||||
[ 99.6476, 32.7959, -134.8893 ],
|
||||
[ 91.0187, 24.5308, -135.6451 ],
|
||||
[ 81.7824, 16.8556, -135.9625 ],
|
||||
[ 72.0245, 9.928, -135.9457 ],
|
||||
[ 61.8311, 3.906, -135.6986 ],
|
||||
[ 51.288, -1.0526, -135.3253 ],
|
||||
[ 40.4812, -4.79, -134.9298 ],
|
||||
[ 29.4966, -7.1481, -134.6162 ],
|
||||
[ 18.4202, -7.9693, -134.4886 ]
|
||||
]
|
||||
|
||||
# primary_6
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 227.5, 101.2038, -100.5766 ],
|
||||
[ 226.1083, 90.9653, -112.2028 ],
|
||||
[ 222.0863, 80.6518, -121.6751 ],
|
||||
[ 215.6643, 70.3646, -129.1873 ],
|
||||
[ 207.0722, 60.2053, -134.9332 ],
|
||||
[ 196.5399, 50.2753, -139.1062 ],
|
||||
[ 184.2975, 40.6763, -141.9002 ],
|
||||
[ 170.575, 31.5097, -143.5089 ],
|
||||
[ 155.6025, 22.877, -144.1259 ],
|
||||
[ 139.6098, 14.8798, -143.9449 ],
|
||||
[ 122.8271, 7.6195, -143.1596 ],
|
||||
[ 105.4844, 1.1977, -141.9638 ],
|
||||
[ 87.8116, -4.2841, -140.551 ],
|
||||
[ 70.0387, -8.7245, -139.115 ],
|
||||
[ 52.3959, -12.0219, -137.8495 ],
|
||||
[ 35.113, -14.0747, -136.9481 ],
|
||||
[ 18.4202, -14.7816, -136.6046 ]
|
||||
]
|
||||
|
||||
# primary_7
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ -227.5, 101.2038, 100.5766 ],
|
||||
[ -226.1083, 90.9653, 112.2028 ],
|
||||
[ -222.0863, 80.6518, 121.6751 ],
|
||||
[ -215.6643, 70.3646, 129.1873 ],
|
||||
[ -207.0722, 60.2053, 134.9332 ],
|
||||
[ -196.5399, 50.2753, 139.1062 ],
|
||||
[ -184.2975, 40.6763, 141.9002 ],
|
||||
[ -170.575, 31.5097, 143.5089 ],
|
||||
[ -155.6025, 22.877, 144.1259 ],
|
||||
[ -139.6098, 14.8798, 143.9449 ],
|
||||
[ -122.8271, 7.6195, 143.1596 ],
|
||||
[ -105.4844, 1.1977, 141.9638 ],
|
||||
[ -87.8116, -4.2841, 140.551 ],
|
||||
[ -70.0387, -8.7245, 139.115 ],
|
||||
[ -52.3959, -12.0219, 137.8495 ],
|
||||
[ -35.113, -14.0747, 136.9481 ],
|
||||
[ -18.4202, -14.7816, 136.6046 ]
|
||||
]
|
||||
|
||||
# primary_8
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ -136.5, 101.2038, 100.5766 ],
|
||||
[ -135.8239, 93.9039, 108.5849 ],
|
||||
[ -133.853, 85.9308, 115.3225 ],
|
||||
[ -130.6732, 77.4423, 120.8934 ],
|
||||
[ -126.3704, 68.5964, 125.4017 ],
|
||||
[ -121.0305, 59.551, 128.9513 ],
|
||||
[ -114.7394, 50.4638, 131.6465 ],
|
||||
[ -107.5832, 41.4928, 133.5911 ],
|
||||
[ -99.6476, 32.7959, 134.8893 ],
|
||||
[ -91.0187, 24.5308, 135.6451 ],
|
||||
[ -81.7824, 16.8556, 135.9625 ],
|
||||
[ -72.0245, 9.928, 135.9457 ],
|
||||
[ -61.8311, 3.906, 135.6986 ],
|
||||
[ -51.288, -1.0526, 135.3253 ],
|
||||
[ -40.4812, -4.79, 134.9298 ],
|
||||
[ -29.4966, -7.1481, 134.6162 ],
|
||||
[ -18.4202, -7.9693, 134.4886 ]
|
||||
]
|
||||
|
||||
# primary_9
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ -45.5, 101.2038, 100.5766 ],
|
||||
[ -45.0636, 96.0541, 106.4923 ],
|
||||
[ -43.8303, 90.6495, 111.6666 ],
|
||||
[ -41.9139, 84.9992, 116.1491 ],
|
||||
[ -39.4283, 79.1125, 119.9895 ],
|
||||
[ -36.4873, 72.9988, 123.2374 ],
|
||||
[ -33.2048, 66.6673, 125.9425 ],
|
||||
[ -29.6945, 60.1273, 128.1544 ],
|
||||
[ -26.0705, 53.3882, 129.9227 ],
|
||||
[ -22.4464, 46.4591, 131.297 ],
|
||||
[ -18.9362, 39.3495, 132.3271 ],
|
||||
[ -15.6537, 32.0686, 133.0625 ],
|
||||
[ -12.7127, 24.6257, 133.5529 ],
|
||||
[ -10.2271, 17.0302, 133.8479 ],
|
||||
[ -8.3107, 9.2912, 133.9971 ],
|
||||
[ -7.0774, 1.4181, 134.0503 ],
|
||||
[ -6.641, -6.5798, 134.057 ]
|
||||
]
|
||||
|
||||
# primary_10
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 45.5, 101.2038, 100.5766 ],
|
||||
[ 45.0636, 96.0541, 106.4923 ],
|
||||
[ 43.8303, 90.6495, 111.6666 ],
|
||||
[ 41.9139, 84.9992, 116.1491 ],
|
||||
[ 39.4283, 79.1125, 119.9895 ],
|
||||
[ 36.4873, 72.9988, 123.2374 ],
|
||||
[ 33.2048, 66.6673, 125.9425 ],
|
||||
[ 29.6945, 60.1273, 128.1544 ],
|
||||
[ 26.0705, 53.3882, 129.9227 ],
|
||||
[ 22.4464, 46.4591, 131.297 ],
|
||||
[ 18.9362, 39.3495, 132.3271 ],
|
||||
[ 15.6537, 32.0686, 133.0625 ],
|
||||
[ 12.7127, 24.6257, 133.5529 ],
|
||||
[ 10.2271, 17.0302, 133.8479 ],
|
||||
[ 8.3107, 9.2912, 133.9971 ],
|
||||
[ 7.0774, 1.4181, 134.0503 ],
|
||||
[ 6.641, -6.5798, 134.057 ]
|
||||
]
|
||||
|
||||
# primary_11
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 136.5, 101.2038, 100.5766 ],
|
||||
[ 135.8239, 93.9039, 108.5849 ],
|
||||
[ 133.853, 85.9308, 115.3225 ],
|
||||
[ 130.6732, 77.4423, 120.8934 ],
|
||||
[ 126.3704, 68.5964, 125.4017 ],
|
||||
[ 121.0305, 59.551, 128.9513 ],
|
||||
[ 114.7394, 50.4638, 131.6465 ],
|
||||
[ 107.5832, 41.4928, 133.5911 ],
|
||||
[ 99.6476, 32.7959, 134.8893 ],
|
||||
[ 91.0187, 24.5308, 135.6451 ],
|
||||
[ 81.7824, 16.8556, 135.9625 ],
|
||||
[ 72.0245, 9.928, 135.9457 ],
|
||||
[ 61.8311, 3.906, 135.6986 ],
|
||||
[ 51.288, -1.0526, 135.3253 ],
|
||||
[ 40.4812, -4.79, 134.9298 ],
|
||||
[ 29.4966, -7.1481, 134.6162 ],
|
||||
[ 18.4202, -7.9693, 134.4886 ]
|
||||
]
|
||||
|
||||
# primary_12
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 227.5, 101.2038, 100.5766 ],
|
||||
[ 226.1083, 90.9653, 112.2028 ],
|
||||
[ 222.0863, 80.6518, 121.6751 ],
|
||||
[ 215.6643, 70.3646, 129.1873 ],
|
||||
[ 207.0722, 60.2053, 134.9332 ],
|
||||
[ 196.5399, 50.2753, 139.1062 ],
|
||||
[ 184.2975, 40.6763, 141.9002 ],
|
||||
[ 170.575, 31.5097, 143.5089 ],
|
||||
[ 155.6025, 22.877, 144.1259 ],
|
||||
[ 139.6098, 14.8798, 143.9449 ],
|
||||
[ 122.8271, 7.6195, 143.1596 ],
|
||||
[ 105.4844, 1.1977, 141.9638 ],
|
||||
[ 87.8116, -4.2841, 140.551 ],
|
||||
[ 70.0387, -8.7245, 139.115 ],
|
||||
[ 52.3959, -12.0219, 137.8495 ],
|
||||
[ 35.113, -14.0747, 136.9481 ],
|
||||
[ 18.4202, -14.7816, 136.6046 ]
|
||||
]
|
||||
|
||||
# tailpipe_25
|
||||
[[geometry.pipes]]
|
||||
index = 25
|
||||
points_mm = [
|
||||
[ 218.4202, -70, -139.7787 ],
|
||||
[ 1718.4201, -70, -139.7787 ]
|
||||
]
|
||||
|
||||
# tailpipe_26
|
||||
[[geometry.pipes]]
|
||||
index = 26
|
||||
points_mm = [
|
||||
[ 218.4202, -70, 139.7787 ],
|
||||
[ 1598.4201, -70, 139.7787 ]
|
||||
]
|
||||
|
||||
# secondary_27
|
||||
[[geometry.pipes]]
|
||||
index = 27
|
||||
points_mm = [
|
||||
[ 18.4202, -29.1445, -126.905 ],
|
||||
[ 29.5401, -29.5568, -127.0496 ],
|
||||
[ 40.2911, -30.722, -127.4582 ],
|
||||
[ 50.7257, -32.5324, -128.0931 ],
|
||||
[ 60.8969, -34.8806, -128.9165 ],
|
||||
[ 70.8571, -37.659, -129.8909 ],
|
||||
[ 80.6593, -40.7601, -130.9783 ],
|
||||
[ 90.356, -44.0763, -132.1412 ],
|
||||
[ 100, -47.5, -133.3419 ],
|
||||
[ 109.644, -50.9237, -134.5425 ],
|
||||
[ 119.3407, -54.2399, -135.7054 ],
|
||||
[ 129.1429, -57.341, -136.7929 ],
|
||||
[ 139.1031, -60.1194, -137.7672 ],
|
||||
[ 149.2742, -62.4676, -138.5907 ],
|
||||
[ 159.7089, -64.278, -139.2256 ],
|
||||
[ 170.4599, -65.4432, -139.6342 ],
|
||||
[ 181.5798, -65.8555, -139.7787 ]
|
||||
]
|
||||
|
||||
# secondary_28
|
||||
[[geometry.pipes]]
|
||||
index = 28
|
||||
points_mm = [
|
||||
[ 18.4202, -29.1445, 126.905 ],
|
||||
[ 29.5401, -29.5568, 127.0496 ],
|
||||
[ 40.2911, -30.722, 127.4582 ],
|
||||
[ 50.7257, -32.5324, 128.0931 ],
|
||||
[ 60.8969, -34.8806, 128.9165 ],
|
||||
[ 70.8571, -37.659, 129.8909 ],
|
||||
[ 80.6593, -40.7601, 130.9783 ],
|
||||
[ 90.356, -44.0763, 132.1412 ],
|
||||
[ 100, -47.5, 133.3419 ],
|
||||
[ 109.644, -50.9237, 134.5425 ],
|
||||
[ 119.3407, -54.2399, 135.7054 ],
|
||||
[ 129.1429, -57.341, 136.7929 ],
|
||||
[ 139.1031, -60.1194, 137.7672 ],
|
||||
[ 149.2742, -62.4676, 138.5907 ],
|
||||
[ 159.7089, -64.278, 139.2256 ],
|
||||
[ 170.4599, -65.4432, 139.6342 ],
|
||||
[ 181.5798, -65.8555, 139.7787 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 452.582, 0 ]
|
||||
size_mm = [ 546, 137.0564, 160.3575 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ 0, -25, -139.7787 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 0, -25, 139.7787 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 200, -70, -139.7787 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 200, -70, 139.7787 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "v8-dual"
|
||||
name = "American 5.0 / independent banks"
|
||||
category = "V8 / American 5.0"
|
||||
description = "Same 4-2-1 headers with H crossover disconnected"
|
||||
description = "Swept primaries / independent dual outlets"
|
||||
order = 8
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 8
|
||||
initial_rpm = 1000.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 300.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0, 270.0, 540.0, 630.0, 360.0, 180.0, 89.99998]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 4.0
|
||||
starter_torque_nm = 180.0
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "american_v8"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 65.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 7.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 370.0
|
||||
exhaust_open_deg = 140.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 37.0
|
||||
exhaust_valve_lift_mm = 10.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 570.0
|
||||
intake_open_deg = 350.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 45.0
|
||||
intake_valve_lift_mm = 10.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 129.0
|
||||
stroke_mm = 76.2
|
||||
@@ -101,51 +96,609 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = false
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 3
|
||||
diameter_mm = 70.0
|
||||
length_mm = 180.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 8
|
||||
cells = 2
|
||||
diameter_mm = 38.0
|
||||
length_mm = 120.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 8
|
||||
cells = 15
|
||||
diameter_mm = 38.0
|
||||
length_mm = 750.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondaries"
|
||||
count = 4
|
||||
cells = 8
|
||||
diameter_mm = 45.0
|
||||
length_mm = 400.0
|
||||
|
||||
[[pipes]]
|
||||
id = "bank_collectors"
|
||||
count = 2
|
||||
cells = 11
|
||||
diameter_mm = 50.0
|
||||
length_mm = 550.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipes"
|
||||
count = 2
|
||||
cells = 25
|
||||
diameter_mm = 50.0
|
||||
length_mm = 1250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "crossover"
|
||||
cells = 16
|
||||
diameter_mm = 38.0
|
||||
length_mm = 780.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[350.000, 0.000000],
|
||||
[355.000, 0.232908],
|
||||
[360.000, 0.871525],
|
||||
[365.000, 1.825695],
|
||||
[370.000, 3.005259],
|
||||
[375.000, 4.320060],
|
||||
[380.000, 5.679940],
|
||||
[385.000, 6.994741],
|
||||
[390.000, 8.174305],
|
||||
[395.000, 9.128475],
|
||||
[400.000, 9.767092],
|
||||
[405.000, 10.000000],
|
||||
[515.000, 10.000000],
|
||||
[520.000, 9.767092],
|
||||
[525.000, 9.128475],
|
||||
[530.000, 8.174305],
|
||||
[535.000, 6.994741],
|
||||
[540.000, 5.679940],
|
||||
[545.000, 4.320060],
|
||||
[550.000, 3.005259],
|
||||
[555.000, 1.825695],
|
||||
[560.000, 0.871525],
|
||||
[565.000, 0.232908],
|
||||
[570.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[140.000, 0.000000],
|
||||
[145.000, 0.213693],
|
||||
[150.000, 0.802170],
|
||||
[155.000, 1.686529],
|
||||
[160.000, 2.787869],
|
||||
[165.000, 4.027287],
|
||||
[170.000, 5.325881],
|
||||
[175.000, 6.604751],
|
||||
[180.000, 7.784992],
|
||||
[185.000, 8.787704],
|
||||
[190.000, 9.533985],
|
||||
[195.000, 9.944933],
|
||||
[197.500, 10.000000],
|
||||
[312.500, 10.000000],
|
||||
[317.500, 9.786307],
|
||||
[322.500, 9.197830],
|
||||
[327.500, 8.313471],
|
||||
[332.500, 7.212131],
|
||||
[337.500, 5.972713],
|
||||
[342.500, 4.674119],
|
||||
[347.500, 3.395249],
|
||||
[352.500, 2.215008],
|
||||
[357.500, 1.212296],
|
||||
[362.500, 0.466015],
|
||||
[367.500, 0.055067],
|
||||
[370.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -419.2, 312.6411, 0 ],
|
||||
[ -239.2, 312.6411, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, -44.7722 ],
|
||||
[ -179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, -44.7722 ],
|
||||
[ -59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, -44.7722 ],
|
||||
[ 59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, -44.7722 ],
|
||||
[ 179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, 44.7722 ],
|
||||
[ -179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, 44.7722 ],
|
||||
[ -59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, 44.7722 ],
|
||||
[ 59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, 44.7722 ],
|
||||
[ 179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, -125.509 ],
|
||||
[ -178.0076, 119.9376, -135.7592 ],
|
||||
[ -174.0725, 112.269, -144.828 ],
|
||||
[ -167.9579, 104.7529, -152.7871 ],
|
||||
[ -160.0272, 97.307, -159.7084 ],
|
||||
[ -150.6434, 89.8488, -165.6635 ],
|
||||
[ -140.17, 82.2959, -170.7242 ],
|
||||
[ -128.9701, 74.5658, -174.9623 ],
|
||||
[ -117.4069, 66.5761, -178.4496 ],
|
||||
[ -105.8437, 58.2443, -181.2578 ],
|
||||
[ -94.6438, 49.4881, -183.4588 ],
|
||||
[ -84.1704, 40.225, -185.1243 ],
|
||||
[ -74.7866, 30.3725, -186.326 ],
|
||||
[ -66.8559, 19.8482, -187.1357 ],
|
||||
[ -60.7413, 8.5696, -187.6252 ],
|
||||
[ -56.8062, -3.5455, -187.8663 ],
|
||||
[ -55.4138, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, -125.509 ],
|
||||
[ -59.5988, 121.2536, -133.7587 ],
|
||||
[ -59.0302, 114.2313, -141.3427 ],
|
||||
[ -58.1467, 106.7977, -148.2793 ],
|
||||
[ -57.0008, 98.9764, -154.587 ],
|
||||
[ -55.6449, 90.7908, -160.2843 ],
|
||||
[ -54.1316, 82.2644, -165.3894 ],
|
||||
[ -52.5133, 73.4207, -169.921 ],
|
||||
[ -50.8425, 64.2831, -173.8973 ],
|
||||
[ -49.1717, 54.8751, -177.3368 ],
|
||||
[ -47.5534, 45.2202, -180.258 ],
|
||||
[ -46.0401, 35.3419, -182.6792 ],
|
||||
[ -44.6842, 25.2636, -184.6188 ],
|
||||
[ -43.5383, 15.0088, -186.0954 ],
|
||||
[ -42.6548, 4.601, -187.1273 ],
|
||||
[ -42.0862, -5.9364, -187.7329 ],
|
||||
[ -41.885, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, -125.509 ],
|
||||
[ 61.1924, 119.9376, -135.7592 ],
|
||||
[ 65.1275, 112.269, -144.828 ],
|
||||
[ 71.2421, 104.7529, -152.7871 ],
|
||||
[ 79.1728, 97.307, -159.7084 ],
|
||||
[ 88.5566, 89.8488, -165.6635 ],
|
||||
[ 99.03, 82.2959, -170.7242 ],
|
||||
[ 110.2299, 74.5658, -174.9623 ],
|
||||
[ 121.7931, 66.5761, -178.4496 ],
|
||||
[ 133.3563, 58.2443, -181.2578 ],
|
||||
[ 144.5562, 49.4881, -183.4588 ],
|
||||
[ 155.0296, 40.225, -185.1243 ],
|
||||
[ 164.4134, 30.3725, -186.326 ],
|
||||
[ 172.3441, 19.8482, -187.1357 ],
|
||||
[ 178.4587, 8.5696, -187.6252 ],
|
||||
[ 182.3938, -3.5455, -187.8663 ],
|
||||
[ 183.7862, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, -125.509 ],
|
||||
[ 179.6012, 121.2536, -133.7587 ],
|
||||
[ 180.1698, 114.2313, -141.3427 ],
|
||||
[ 181.0533, 106.7977, -148.2793 ],
|
||||
[ 182.1992, 98.9764, -154.587 ],
|
||||
[ 183.5551, 90.7908, -160.2843 ],
|
||||
[ 185.0684, 82.2644, -165.3894 ],
|
||||
[ 186.6867, 73.4207, -169.921 ],
|
||||
[ 188.3575, 64.2831, -173.8973 ],
|
||||
[ 190.0283, 54.8751, -177.3368 ],
|
||||
[ 191.6466, 45.2202, -180.258 ],
|
||||
[ 193.1599, 35.3419, -182.6792 ],
|
||||
[ 194.5158, 25.2636, -184.6188 ],
|
||||
[ 195.6617, 15.0088, -186.0954 ],
|
||||
[ 196.5452, 4.601, -187.1273 ],
|
||||
[ 197.1138, -5.9364, -187.7329 ],
|
||||
[ 197.315, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, 125.509 ],
|
||||
[ -178.324, 117.6211, 137.7817 ],
|
||||
[ -175.1941, 106.5763, 148.386 ],
|
||||
[ -170.1577, 94.9116, 157.4428 ],
|
||||
[ -163.362, 82.8316, 165.073 ],
|
||||
[ -154.9545, 70.5413, 171.3976 ],
|
||||
[ -145.0824, 58.2453, 176.5376 ],
|
||||
[ -133.893, 46.1485, 180.614 ],
|
||||
[ -121.5338, 34.4556, 183.7476 ],
|
||||
[ -108.1519, 23.3715, 186.0596 ],
|
||||
[ -93.8947, 13.1008, 187.6708 ],
|
||||
[ -78.9095, 3.8484, 188.7023 ],
|
||||
[ -63.3436, -4.1809, 189.2749 ],
|
||||
[ -47.3445, -10.7824, 189.5097 ],
|
||||
[ -31.0593, -15.7513, 189.5277 ],
|
||||
[ -14.6354, -18.8828, 189.4497 ],
|
||||
[ 1.7798, -19.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, 125.509 ],
|
||||
[ -58.724, 117.6211, 137.7817 ],
|
||||
[ -55.5941, 106.5763, 148.386 ],
|
||||
[ -50.5577, 94.9116, 157.4428 ],
|
||||
[ -43.762, 82.8316, 165.073 ],
|
||||
[ -35.3545, 70.5413, 171.3976 ],
|
||||
[ -25.4824, 58.2453, 176.5376 ],
|
||||
[ -14.293, 46.1485, 180.614 ],
|
||||
[ -1.9338, 34.4556, 183.7476 ],
|
||||
[ 11.4481, 23.3715, 186.0596 ],
|
||||
[ 25.7053, 13.1008, 187.6708 ],
|
||||
[ 40.6905, 3.8484, 188.7023 ],
|
||||
[ 56.2563, -4.1809, 189.2749 ],
|
||||
[ 72.2555, -10.7824, 189.5097 ],
|
||||
[ 88.5407, -15.7513, 189.5277 ],
|
||||
[ 104.9646, -18.8828, 189.4497 ],
|
||||
[ 121.3798, -19.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 7
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, 125.509 ],
|
||||
[ 59.4056, 121.1641, 133.8948 ],
|
||||
[ 58.2909, 114.0977, 141.5798 ],
|
||||
[ 56.5589, 106.6586, 148.586 ],
|
||||
[ 54.3124, 98.8628, 154.9355 ],
|
||||
[ 51.6544, 90.7267, 160.6503 ],
|
||||
[ 48.6876, 82.2665, 165.7524 ],
|
||||
[ 45.5151, 73.4986, 170.264 ],
|
||||
[ 42.2397, 64.4391, 174.2071 ],
|
||||
[ 38.9643, 55.1044, 177.6036 ],
|
||||
[ 35.7918, 45.5106, 180.4758 ],
|
||||
[ 32.8251, 35.6741, 182.8455 ],
|
||||
[ 30.167, 25.6112, 184.735 ],
|
||||
[ 27.9206, 15.3381, 186.1662 ],
|
||||
[ 26.1885, 4.871, 187.1611 ],
|
||||
[ 25.0739, -5.7737, 187.742 ],
|
||||
[ 24.6794, -16.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 8
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, 125.509 ],
|
||||
[ 179.0056, 121.164, 133.8948 ],
|
||||
[ 177.8909, 114.0977, 141.5798 ],
|
||||
[ 176.1589, 106.6586, 148.586 ],
|
||||
[ 173.9124, 98.8628, 154.9355 ],
|
||||
[ 171.2544, 90.7267, 160.6503 ],
|
||||
[ 168.2876, 82.2665, 165.7524 ],
|
||||
[ 165.1151, 73.4986, 170.264 ],
|
||||
[ 161.8397, 64.4391, 174.2071 ],
|
||||
[ 158.5643, 55.1044, 177.6036 ],
|
||||
[ 155.3918, 45.5106, 180.4758 ],
|
||||
[ 152.4251, 35.6741, 182.8455 ],
|
||||
[ 149.767, 25.6112, 184.735 ],
|
||||
[ 147.5205, 15.3381, 186.1662 ],
|
||||
[ 145.7885, 4.871, 187.1611 ],
|
||||
[ 144.6739, -5.7737, 187.742 ],
|
||||
[ 144.2794, -16.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# secondaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ -21.1798, -37.1882, -195.8922 ],
|
||||
[ 1.7283, -37.6445, -195.8922 ],
|
||||
[ 24.0223, -38.9338, -195.8922 ],
|
||||
[ 45.7896, -40.9372, -195.8922 ],
|
||||
[ 67.1182, -43.5357, -195.8922 ],
|
||||
[ 88.0958, -46.6102, -195.8922 ],
|
||||
[ 108.8101, -50.0418, -195.8922 ],
|
||||
[ 129.3489, -53.7114, -195.8922 ],
|
||||
[ 149.8, -57.5, -195.8922 ],
|
||||
[ 170.251, -61.2886, -195.8922 ],
|
||||
[ 190.7898, -64.9582, -195.8922 ],
|
||||
[ 211.5042, -68.3898, -195.8922 ],
|
||||
[ 232.4818, -71.4643, -195.8922 ],
|
||||
[ 253.8104, -74.0628, -195.8922 ],
|
||||
[ 275.5777, -76.0662, -195.8922 ],
|
||||
[ 297.8716, -77.3555, -195.8922 ],
|
||||
[ 320.7798, -77.8118, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 218.0202, -40.9377, -195.8922 ],
|
||||
[ 225.1524, -41.3097, -195.8922 ],
|
||||
[ 232.0008, -42.361, -195.8922 ],
|
||||
[ 238.6058, -43.9946, -195.8922 ],
|
||||
[ 245.008, -46.1134, -195.8922 ],
|
||||
[ 251.2479, -48.6204, -195.8922 ],
|
||||
[ 257.3662, -51.4185, -195.8922 ],
|
||||
[ 263.4034, -54.4107, -195.8922 ],
|
||||
[ 269.4, -57.5, -195.8922 ],
|
||||
[ 275.3966, -60.5892, -195.8922 ],
|
||||
[ 281.4338, -63.5815, -195.8922 ],
|
||||
[ 287.552, -66.3796, -195.8922 ],
|
||||
[ 293.792, -68.8866, -195.8922 ],
|
||||
[ 300.1942, -71.0054, -195.8922 ],
|
||||
[ 306.7992, -72.6389, -195.8922 ],
|
||||
[ 313.6476, -73.6903, -195.8922 ],
|
||||
[ 320.7798, -74.0623, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ 38.6202, -37.5985, 195.8922 ],
|
||||
[ 57.5671, -38.0455, 195.8922 ],
|
||||
[ 75.9893, -39.3087, 195.8922 ],
|
||||
[ 93.9616, -41.2717, 195.8922 ],
|
||||
[ 111.5591, -43.8177, 195.8922 ],
|
||||
[ 128.8567, -46.8301, 195.8922 ],
|
||||
[ 145.9294, -50.1924, 195.8922 ],
|
||||
[ 162.8522, -53.7879, 195.8922 ],
|
||||
[ 179.7, -57.5, 195.8922 ],
|
||||
[ 196.5478, -61.2121, 195.8922 ],
|
||||
[ 213.4705, -64.8076, 195.8922 ],
|
||||
[ 230.5433, -68.1699, 195.8922 ],
|
||||
[ 247.8409, -71.1823, 195.8922 ],
|
||||
[ 265.4383, -73.7283, 195.8922 ],
|
||||
[ 283.4107, -75.6913, 195.8922 ],
|
||||
[ 301.8329, -76.9545, 195.8922 ],
|
||||
[ 320.7798, -77.4015, 195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ 158.2202, -39.157, 195.8922 ],
|
||||
[ 169.2733, -39.569, 195.8922 ],
|
||||
[ 179.9691, -40.7334, 195.8922 ],
|
||||
[ 190.3587, -42.5426, 195.8922 ],
|
||||
[ 200.4932, -44.8892, 195.8922 ],
|
||||
[ 210.4235, -47.6657, 195.8922 ],
|
||||
[ 220.2007, -50.7647, 195.8922 ],
|
||||
[ 229.8759, -54.0786, 195.8922 ],
|
||||
[ 239.5, -57.5, 195.8922 ],
|
||||
[ 249.1241, -60.9214, 195.8922 ],
|
||||
[ 258.7993, -64.2353, 195.8922 ],
|
||||
[ 268.5765, -67.3343, 195.8922 ],
|
||||
[ 278.5068, -70.1108, 195.8922 ],
|
||||
[ 288.6412, -72.4574, 195.8922 ],
|
||||
[ 299.0309, -74.2666, 195.8922 ],
|
||||
[ 309.7267, -75.431, 195.8922 ],
|
||||
[ 320.7798, -75.843, 195.8922 ]
|
||||
]
|
||||
|
||||
# bank_collectors 1
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ 357.6201, -80, -203.01 ],
|
||||
[ 395.2968, -80, -204.5045 ],
|
||||
[ 431.5154, -80, -208.8033 ],
|
||||
[ 466.4613, -80, -215.6295 ],
|
||||
[ 500.3197, -80, -224.7065 ],
|
||||
[ 533.2757, -80, -235.7573 ],
|
||||
[ 565.5144, -80, -248.5051 ],
|
||||
[ 597.2213, -80, -262.6732 ],
|
||||
[ 628.5813, -80, -277.9846 ],
|
||||
[ 659.7797, -80, -294.1627 ],
|
||||
[ 691.0017, -80, -310.9305 ],
|
||||
[ 722.4326, -80, -328.0112 ],
|
||||
[ 754.2572, -80, -345.128 ],
|
||||
[ 786.6611, -80, -362.0041 ],
|
||||
[ 819.8294, -80, -378.3627 ],
|
||||
[ 853.9472, -80, -393.9269 ],
|
||||
[ 889.1997, -80, -408.42 ]
|
||||
]
|
||||
|
||||
# bank_collectors 2
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 357.6201, -80, 203.01 ],
|
||||
[ 395.2968, -80, 204.5045 ],
|
||||
[ 431.5154, -80, 208.8033 ],
|
||||
[ 466.4613, -80, 215.6295 ],
|
||||
[ 500.3197, -80, 224.7065 ],
|
||||
[ 533.2757, -80, 235.7573 ],
|
||||
[ 565.5144, -80, 248.5051 ],
|
||||
[ 597.2213, -80, 262.6732 ],
|
||||
[ 628.5813, -80, 277.9846 ],
|
||||
[ 659.7797, -80, 294.1627 ],
|
||||
[ 691.0017, -80, 310.9305 ],
|
||||
[ 722.4326, -80, 328.0112 ],
|
||||
[ 754.2572, -80, 345.128 ],
|
||||
[ 786.6611, -80, 362.0041 ],
|
||||
[ 819.8294, -80, 378.3627 ],
|
||||
[ 853.9472, -80, 393.9269 ],
|
||||
[ 889.1997, -80, 408.42 ]
|
||||
]
|
||||
|
||||
# tailpipes 1
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 889.1997, -80, -408.42 ],
|
||||
[ 2139.1997, -80, -408.42 ]
|
||||
]
|
||||
|
||||
# tailpipes 2
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 889.1997, -80, 408.42 ],
|
||||
[ 2139.1997, -80, 408.42 ]
|
||||
]
|
||||
|
||||
# crossover
|
||||
[[geometry.pipes]]
|
||||
index = 25
|
||||
points_mm = [
|
||||
[ 889.1997, -80, -408.42 ],
|
||||
[ 889.1997, -80, 408.42 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 312.6411, 0 ]
|
||||
size_mm = [ 478.4, 43.7429, 191.1445 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -39.6, -35, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 199.6, -35, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 20.2, -35, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 139.8, -35, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_4"
|
||||
center_mm = [ 339.2, -80, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_5"
|
||||
center_mm = [ 339.2, -80, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "v8-h"
|
||||
name = "American 5.0 / 4-2-1 + H"
|
||||
category = "V8 / American 5.0"
|
||||
description = "750 mm primaries, 50 cc junctions, H crossover"
|
||||
description = "Swept primaries / 50 cc junctions / H crossover"
|
||||
order = 7
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 8
|
||||
initial_rpm = 1000.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 300.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0, 270.0, 540.0, 630.0, 360.0, 180.0, 89.99998]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 4.0
|
||||
starter_torque_nm = 180.0
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "american_v8"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 65.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 7.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 370.0
|
||||
exhaust_open_deg = 140.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 37.0
|
||||
exhaust_valve_lift_mm = 10.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 570.0
|
||||
intake_open_deg = 350.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 45.0
|
||||
intake_valve_lift_mm = 10.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 129.0
|
||||
stroke_mm = 76.2
|
||||
@@ -101,51 +96,619 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 3
|
||||
diameter_mm = 70.0
|
||||
length_mm = 180.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 8
|
||||
cells = 2
|
||||
diameter_mm = 38.0
|
||||
length_mm = 120.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 8
|
||||
cells = 15
|
||||
diameter_mm = 38.0
|
||||
length_mm = 750.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondaries"
|
||||
count = 4
|
||||
cells = 8
|
||||
diameter_mm = 45.0
|
||||
length_mm = 400.0
|
||||
|
||||
[[pipes]]
|
||||
id = "bank_collectors"
|
||||
count = 2
|
||||
cells = 11
|
||||
diameter_mm = 50.0
|
||||
length_mm = 550.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipes"
|
||||
count = 2
|
||||
cells = 25
|
||||
diameter_mm = 50.0
|
||||
length_mm = 1250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "crossover"
|
||||
cells = 16
|
||||
diameter_mm = 38.0
|
||||
length_mm = 780.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[350.000, 0.000000],
|
||||
[355.000, 0.232908],
|
||||
[360.000, 0.871525],
|
||||
[365.000, 1.825695],
|
||||
[370.000, 3.005259],
|
||||
[375.000, 4.320060],
|
||||
[380.000, 5.679940],
|
||||
[385.000, 6.994741],
|
||||
[390.000, 8.174305],
|
||||
[395.000, 9.128475],
|
||||
[400.000, 9.767092],
|
||||
[405.000, 10.000000],
|
||||
[515.000, 10.000000],
|
||||
[520.000, 9.767092],
|
||||
[525.000, 9.128475],
|
||||
[530.000, 8.174305],
|
||||
[535.000, 6.994741],
|
||||
[540.000, 5.679940],
|
||||
[545.000, 4.320060],
|
||||
[550.000, 3.005259],
|
||||
[555.000, 1.825695],
|
||||
[560.000, 0.871525],
|
||||
[565.000, 0.232908],
|
||||
[570.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[140.000, 0.000000],
|
||||
[145.000, 0.213693],
|
||||
[150.000, 0.802170],
|
||||
[155.000, 1.686529],
|
||||
[160.000, 2.787869],
|
||||
[165.000, 4.027287],
|
||||
[170.000, 5.325881],
|
||||
[175.000, 6.604751],
|
||||
[180.000, 7.784992],
|
||||
[185.000, 8.787704],
|
||||
[190.000, 9.533985],
|
||||
[195.000, 9.944933],
|
||||
[197.500, 10.000000],
|
||||
[312.500, 10.000000],
|
||||
[317.500, 9.786307],
|
||||
[322.500, 9.197830],
|
||||
[327.500, 8.313471],
|
||||
[332.500, 7.212131],
|
||||
[337.500, 5.972713],
|
||||
[342.500, 4.674119],
|
||||
[347.500, 3.395249],
|
||||
[352.500, 2.215008],
|
||||
[357.500, 1.212296],
|
||||
[362.500, 0.466015],
|
||||
[367.500, 0.055067],
|
||||
[370.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -419.2, 312.6411, 0 ],
|
||||
[ -239.2, 312.6411, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, -44.7722 ],
|
||||
[ -179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, -44.7722 ],
|
||||
[ -59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, -44.7722 ],
|
||||
[ 59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, -44.7722 ],
|
||||
[ 179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, 44.7722 ],
|
||||
[ -179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, 44.7722 ],
|
||||
[ -59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, 44.7722 ],
|
||||
[ 59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, 44.7722 ],
|
||||
[ 179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, -125.509 ],
|
||||
[ -178.0076, 119.9376, -135.7592 ],
|
||||
[ -174.0725, 112.269, -144.828 ],
|
||||
[ -167.9579, 104.7529, -152.7871 ],
|
||||
[ -160.0272, 97.307, -159.7084 ],
|
||||
[ -150.6434, 89.8488, -165.6635 ],
|
||||
[ -140.17, 82.2959, -170.7242 ],
|
||||
[ -128.9701, 74.5658, -174.9623 ],
|
||||
[ -117.4069, 66.5761, -178.4496 ],
|
||||
[ -105.8437, 58.2443, -181.2578 ],
|
||||
[ -94.6438, 49.4881, -183.4588 ],
|
||||
[ -84.1704, 40.225, -185.1243 ],
|
||||
[ -74.7866, 30.3725, -186.326 ],
|
||||
[ -66.8559, 19.8482, -187.1357 ],
|
||||
[ -60.7413, 8.5696, -187.6252 ],
|
||||
[ -56.8062, -3.5455, -187.8663 ],
|
||||
[ -55.4138, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, -125.509 ],
|
||||
[ -59.5988, 121.2536, -133.7587 ],
|
||||
[ -59.0302, 114.2313, -141.3427 ],
|
||||
[ -58.1467, 106.7977, -148.2793 ],
|
||||
[ -57.0008, 98.9764, -154.587 ],
|
||||
[ -55.6449, 90.7908, -160.2843 ],
|
||||
[ -54.1316, 82.2644, -165.3894 ],
|
||||
[ -52.5133, 73.4207, -169.921 ],
|
||||
[ -50.8425, 64.2831, -173.8973 ],
|
||||
[ -49.1717, 54.8751, -177.3368 ],
|
||||
[ -47.5534, 45.2202, -180.258 ],
|
||||
[ -46.0401, 35.3419, -182.6792 ],
|
||||
[ -44.6842, 25.2636, -184.6188 ],
|
||||
[ -43.5383, 15.0088, -186.0954 ],
|
||||
[ -42.6548, 4.601, -187.1273 ],
|
||||
[ -42.0862, -5.9364, -187.7329 ],
|
||||
[ -41.885, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, -125.509 ],
|
||||
[ 61.1924, 119.9376, -135.7592 ],
|
||||
[ 65.1275, 112.269, -144.828 ],
|
||||
[ 71.2421, 104.7529, -152.7871 ],
|
||||
[ 79.1728, 97.307, -159.7084 ],
|
||||
[ 88.5566, 89.8488, -165.6635 ],
|
||||
[ 99.03, 82.2959, -170.7242 ],
|
||||
[ 110.2299, 74.5658, -174.9623 ],
|
||||
[ 121.7931, 66.5761, -178.4496 ],
|
||||
[ 133.3563, 58.2443, -181.2578 ],
|
||||
[ 144.5562, 49.4881, -183.4588 ],
|
||||
[ 155.0296, 40.225, -185.1243 ],
|
||||
[ 164.4134, 30.3725, -186.326 ],
|
||||
[ 172.3441, 19.8482, -187.1357 ],
|
||||
[ 178.4587, 8.5696, -187.6252 ],
|
||||
[ 182.3938, -3.5455, -187.8663 ],
|
||||
[ 183.7862, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, -125.509 ],
|
||||
[ 179.6012, 121.2536, -133.7587 ],
|
||||
[ 180.1698, 114.2313, -141.3427 ],
|
||||
[ 181.0533, 106.7977, -148.2793 ],
|
||||
[ 182.1992, 98.9764, -154.587 ],
|
||||
[ 183.5551, 90.7908, -160.2843 ],
|
||||
[ 185.0684, 82.2644, -165.3894 ],
|
||||
[ 186.6867, 73.4207, -169.921 ],
|
||||
[ 188.3575, 64.2831, -173.8973 ],
|
||||
[ 190.0283, 54.8751, -177.3368 ],
|
||||
[ 191.6466, 45.2202, -180.258 ],
|
||||
[ 193.1599, 35.3419, -182.6792 ],
|
||||
[ 194.5158, 25.2636, -184.6188 ],
|
||||
[ 195.6617, 15.0088, -186.0954 ],
|
||||
[ 196.5452, 4.601, -187.1273 ],
|
||||
[ 197.1138, -5.9364, -187.7329 ],
|
||||
[ 197.315, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, 125.509 ],
|
||||
[ -178.324, 117.6211, 137.7817 ],
|
||||
[ -175.1941, 106.5763, 148.386 ],
|
||||
[ -170.1577, 94.9116, 157.4428 ],
|
||||
[ -163.362, 82.8316, 165.073 ],
|
||||
[ -154.9545, 70.5413, 171.3976 ],
|
||||
[ -145.0824, 58.2453, 176.5376 ],
|
||||
[ -133.893, 46.1485, 180.614 ],
|
||||
[ -121.5338, 34.4556, 183.7476 ],
|
||||
[ -108.1519, 23.3715, 186.0596 ],
|
||||
[ -93.8947, 13.1008, 187.6708 ],
|
||||
[ -78.9095, 3.8484, 188.7023 ],
|
||||
[ -63.3436, -4.1809, 189.2749 ],
|
||||
[ -47.3445, -10.7824, 189.5097 ],
|
||||
[ -31.0593, -15.7513, 189.5277 ],
|
||||
[ -14.6354, -18.8828, 189.4497 ],
|
||||
[ 1.7798, -19.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, 125.509 ],
|
||||
[ -58.724, 117.6211, 137.7817 ],
|
||||
[ -55.5941, 106.5763, 148.386 ],
|
||||
[ -50.5577, 94.9116, 157.4428 ],
|
||||
[ -43.762, 82.8316, 165.073 ],
|
||||
[ -35.3545, 70.5413, 171.3976 ],
|
||||
[ -25.4824, 58.2453, 176.5376 ],
|
||||
[ -14.293, 46.1485, 180.614 ],
|
||||
[ -1.9338, 34.4556, 183.7476 ],
|
||||
[ 11.4481, 23.3715, 186.0596 ],
|
||||
[ 25.7053, 13.1008, 187.6708 ],
|
||||
[ 40.6905, 3.8484, 188.7023 ],
|
||||
[ 56.2563, -4.1809, 189.2749 ],
|
||||
[ 72.2555, -10.7824, 189.5097 ],
|
||||
[ 88.5407, -15.7513, 189.5277 ],
|
||||
[ 104.9646, -18.8828, 189.4497 ],
|
||||
[ 121.3798, -19.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 7
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, 125.509 ],
|
||||
[ 59.4056, 121.1641, 133.8948 ],
|
||||
[ 58.2909, 114.0977, 141.5798 ],
|
||||
[ 56.5589, 106.6586, 148.586 ],
|
||||
[ 54.3124, 98.8628, 154.9355 ],
|
||||
[ 51.6544, 90.7267, 160.6503 ],
|
||||
[ 48.6876, 82.2665, 165.7524 ],
|
||||
[ 45.5151, 73.4986, 170.264 ],
|
||||
[ 42.2397, 64.4391, 174.2071 ],
|
||||
[ 38.9643, 55.1044, 177.6036 ],
|
||||
[ 35.7918, 45.5106, 180.4758 ],
|
||||
[ 32.8251, 35.6741, 182.8455 ],
|
||||
[ 30.167, 25.6112, 184.735 ],
|
||||
[ 27.9206, 15.3381, 186.1662 ],
|
||||
[ 26.1885, 4.871, 187.1611 ],
|
||||
[ 25.0739, -5.7737, 187.742 ],
|
||||
[ 24.6794, -16.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 8
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, 125.509 ],
|
||||
[ 179.0056, 121.164, 133.8948 ],
|
||||
[ 177.8909, 114.0977, 141.5798 ],
|
||||
[ 176.1589, 106.6586, 148.586 ],
|
||||
[ 173.9124, 98.8628, 154.9355 ],
|
||||
[ 171.2544, 90.7267, 160.6503 ],
|
||||
[ 168.2876, 82.2665, 165.7524 ],
|
||||
[ 165.1151, 73.4986, 170.264 ],
|
||||
[ 161.8397, 64.4391, 174.2071 ],
|
||||
[ 158.5643, 55.1044, 177.6036 ],
|
||||
[ 155.3918, 45.5106, 180.4758 ],
|
||||
[ 152.4251, 35.6741, 182.8455 ],
|
||||
[ 149.767, 25.6112, 184.735 ],
|
||||
[ 147.5205, 15.3381, 186.1662 ],
|
||||
[ 145.7885, 4.871, 187.1611 ],
|
||||
[ 144.6739, -5.7737, 187.742 ],
|
||||
[ 144.2794, -16.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# secondaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ -21.1798, -37.1882, -195.8922 ],
|
||||
[ 1.7283, -37.6445, -195.8922 ],
|
||||
[ 24.0223, -38.9338, -195.8922 ],
|
||||
[ 45.7896, -40.9372, -195.8922 ],
|
||||
[ 67.1182, -43.5357, -195.8922 ],
|
||||
[ 88.0958, -46.6102, -195.8922 ],
|
||||
[ 108.8101, -50.0418, -195.8922 ],
|
||||
[ 129.3489, -53.7114, -195.8922 ],
|
||||
[ 149.8, -57.5, -195.8922 ],
|
||||
[ 170.251, -61.2886, -195.8922 ],
|
||||
[ 190.7898, -64.9582, -195.8922 ],
|
||||
[ 211.5042, -68.3898, -195.8922 ],
|
||||
[ 232.4818, -71.4643, -195.8922 ],
|
||||
[ 253.8104, -74.0628, -195.8922 ],
|
||||
[ 275.5777, -76.0662, -195.8922 ],
|
||||
[ 297.8716, -77.3555, -195.8922 ],
|
||||
[ 320.7798, -77.8118, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 218.0202, -40.9377, -195.8922 ],
|
||||
[ 225.1524, -41.3097, -195.8922 ],
|
||||
[ 232.0008, -42.361, -195.8922 ],
|
||||
[ 238.6058, -43.9946, -195.8922 ],
|
||||
[ 245.008, -46.1134, -195.8922 ],
|
||||
[ 251.2479, -48.6204, -195.8922 ],
|
||||
[ 257.3662, -51.4185, -195.8922 ],
|
||||
[ 263.4034, -54.4107, -195.8922 ],
|
||||
[ 269.4, -57.5, -195.8922 ],
|
||||
[ 275.3966, -60.5892, -195.8922 ],
|
||||
[ 281.4338, -63.5815, -195.8922 ],
|
||||
[ 287.552, -66.3796, -195.8922 ],
|
||||
[ 293.792, -68.8866, -195.8922 ],
|
||||
[ 300.1942, -71.0054, -195.8922 ],
|
||||
[ 306.7992, -72.6389, -195.8922 ],
|
||||
[ 313.6476, -73.6903, -195.8922 ],
|
||||
[ 320.7798, -74.0623, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ 38.6202, -37.5985, 195.8922 ],
|
||||
[ 57.5671, -38.0455, 195.8922 ],
|
||||
[ 75.9893, -39.3087, 195.8922 ],
|
||||
[ 93.9616, -41.2717, 195.8922 ],
|
||||
[ 111.5591, -43.8177, 195.8922 ],
|
||||
[ 128.8567, -46.8301, 195.8922 ],
|
||||
[ 145.9294, -50.1924, 195.8922 ],
|
||||
[ 162.8522, -53.7879, 195.8922 ],
|
||||
[ 179.7, -57.5, 195.8922 ],
|
||||
[ 196.5478, -61.2121, 195.8922 ],
|
||||
[ 213.4705, -64.8076, 195.8922 ],
|
||||
[ 230.5433, -68.1699, 195.8922 ],
|
||||
[ 247.8409, -71.1823, 195.8922 ],
|
||||
[ 265.4383, -73.7283, 195.8922 ],
|
||||
[ 283.4107, -75.6913, 195.8922 ],
|
||||
[ 301.8329, -76.9545, 195.8922 ],
|
||||
[ 320.7798, -77.4015, 195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ 158.2202, -39.157, 195.8922 ],
|
||||
[ 169.2733, -39.569, 195.8922 ],
|
||||
[ 179.9691, -40.7334, 195.8922 ],
|
||||
[ 190.3587, -42.5426, 195.8922 ],
|
||||
[ 200.4932, -44.8892, 195.8922 ],
|
||||
[ 210.4235, -47.6657, 195.8922 ],
|
||||
[ 220.2007, -50.7647, 195.8922 ],
|
||||
[ 229.8759, -54.0786, 195.8922 ],
|
||||
[ 239.5, -57.5, 195.8922 ],
|
||||
[ 249.1241, -60.9214, 195.8922 ],
|
||||
[ 258.7993, -64.2353, 195.8922 ],
|
||||
[ 268.5765, -67.3343, 195.8922 ],
|
||||
[ 278.5068, -70.1108, 195.8922 ],
|
||||
[ 288.6412, -72.4574, 195.8922 ],
|
||||
[ 299.0309, -74.2666, 195.8922 ],
|
||||
[ 309.7267, -75.431, 195.8922 ],
|
||||
[ 320.7798, -75.843, 195.8922 ]
|
||||
]
|
||||
|
||||
# bank_collectors 1
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ 357.6201, -80, -203.0101 ],
|
||||
[ 393.845, -80, -205.237 ],
|
||||
[ 428.4088, -80, -211.5304 ],
|
||||
[ 461.549, -80, -221.3095 ],
|
||||
[ 493.5029, -80, -233.9932 ],
|
||||
[ 524.5076, -80, -249.0007 ],
|
||||
[ 554.8005, -80, -265.751 ],
|
||||
[ 584.6189, -80, -283.6631 ],
|
||||
[ 614.2, -80, -302.1562 ],
|
||||
[ 643.781, -80, -320.6493 ],
|
||||
[ 673.5994, -80, -338.5614 ],
|
||||
[ 703.8922, -80, -355.3117 ],
|
||||
[ 734.897, -80, -370.3192 ],
|
||||
[ 766.8508, -80, -383.0029 ],
|
||||
[ 799.9911, -80, -392.782 ],
|
||||
[ 834.5549, -80, -399.0755 ],
|
||||
[ 870.7797, -80, -401.3024 ]
|
||||
]
|
||||
|
||||
# bank_collectors 2
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 357.6201, -80, 203.0101 ],
|
||||
[ 393.845, -80, 205.237 ],
|
||||
[ 428.4088, -80, 211.5304 ],
|
||||
[ 461.549, -80, 221.3095 ],
|
||||
[ 493.5029, -80, 233.9932 ],
|
||||
[ 524.5076, -80, 249.0007 ],
|
||||
[ 554.8005, -80, 265.751 ],
|
||||
[ 584.6189, -80, 283.6631 ],
|
||||
[ 614.2, -80, 302.1562 ],
|
||||
[ 643.781, -80, 320.6493 ],
|
||||
[ 673.5994, -80, 338.5614 ],
|
||||
[ 703.8922, -80, 355.3117 ],
|
||||
[ 734.897, -80, 370.3192 ],
|
||||
[ 766.8508, -80, 383.0029 ],
|
||||
[ 799.9911, -80, 392.782 ],
|
||||
[ 834.5549, -80, 399.0755 ],
|
||||
[ 870.7797, -80, 401.3024 ]
|
||||
]
|
||||
|
||||
# tailpipes 1
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 907.62, -80, -408.4202 ],
|
||||
[ 2157.62, -80, -408.4202 ]
|
||||
]
|
||||
|
||||
# tailpipes 2
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 907.62, -80, 408.4202 ],
|
||||
[ 2157.62, -80, 408.4202 ]
|
||||
]
|
||||
|
||||
# crossover
|
||||
[[geometry.pipes]]
|
||||
index = 25
|
||||
points_mm = [
|
||||
[ 889.1999, -80, -390 ],
|
||||
[ 889.1999, -80, 390 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 312.6411, 0 ]
|
||||
size_mm = [ 478.4, 43.7429, 191.1445 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -39.6, -35, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 199.6, -35, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 20.2, -35, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 139.8, -35, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_4"
|
||||
center_mm = [ 339.2, -80, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_5"
|
||||
center_mm = [ 339.2, -80, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_6"
|
||||
center_mm = [ 889.1999, -80, -408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_7"
|
||||
center_mm = [ 889.1999, -80, 408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "v8-large"
|
||||
name = "American 5.0 / larger primaries"
|
||||
category = "V8 / American 5.0"
|
||||
description = "42 mm x 750 mm primaries with H crossover"
|
||||
description = "42 mm swept primaries / H crossover"
|
||||
order = 11
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 8
|
||||
initial_rpm = 1000.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 300.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0, 270.0, 540.0, 630.0, 360.0, 180.0, 89.99998]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 4.0
|
||||
starter_torque_nm = 180.0
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "american_v8"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 65.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 7.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 370.0
|
||||
exhaust_open_deg = 140.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 37.0
|
||||
exhaust_valve_lift_mm = 10.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 570.0
|
||||
intake_open_deg = 350.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 45.0
|
||||
intake_valve_lift_mm = 10.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 129.0
|
||||
stroke_mm = 76.2
|
||||
@@ -101,51 +96,619 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 3
|
||||
diameter_mm = 70.0
|
||||
length_mm = 180.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 8
|
||||
cells = 2
|
||||
diameter_mm = 38.0
|
||||
length_mm = 120.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 8
|
||||
cells = 15
|
||||
diameter_mm = 42.0
|
||||
length_mm = 750.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondaries"
|
||||
count = 4
|
||||
cells = 8
|
||||
diameter_mm = 45.0
|
||||
length_mm = 400.0
|
||||
|
||||
[[pipes]]
|
||||
id = "bank_collectors"
|
||||
count = 2
|
||||
cells = 11
|
||||
diameter_mm = 50.0
|
||||
length_mm = 550.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipes"
|
||||
count = 2
|
||||
cells = 25
|
||||
diameter_mm = 50.0
|
||||
length_mm = 1250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "crossover"
|
||||
cells = 16
|
||||
diameter_mm = 38.0
|
||||
length_mm = 780.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[350.000, 0.000000],
|
||||
[355.000, 0.232908],
|
||||
[360.000, 0.871525],
|
||||
[365.000, 1.825695],
|
||||
[370.000, 3.005259],
|
||||
[375.000, 4.320060],
|
||||
[380.000, 5.679940],
|
||||
[385.000, 6.994741],
|
||||
[390.000, 8.174305],
|
||||
[395.000, 9.128475],
|
||||
[400.000, 9.767092],
|
||||
[405.000, 10.000000],
|
||||
[515.000, 10.000000],
|
||||
[520.000, 9.767092],
|
||||
[525.000, 9.128475],
|
||||
[530.000, 8.174305],
|
||||
[535.000, 6.994741],
|
||||
[540.000, 5.679940],
|
||||
[545.000, 4.320060],
|
||||
[550.000, 3.005259],
|
||||
[555.000, 1.825695],
|
||||
[560.000, 0.871525],
|
||||
[565.000, 0.232908],
|
||||
[570.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[140.000, 0.000000],
|
||||
[145.000, 0.213693],
|
||||
[150.000, 0.802170],
|
||||
[155.000, 1.686529],
|
||||
[160.000, 2.787869],
|
||||
[165.000, 4.027287],
|
||||
[170.000, 5.325881],
|
||||
[175.000, 6.604751],
|
||||
[180.000, 7.784992],
|
||||
[185.000, 8.787704],
|
||||
[190.000, 9.533985],
|
||||
[195.000, 9.944933],
|
||||
[197.500, 10.000000],
|
||||
[312.500, 10.000000],
|
||||
[317.500, 9.786307],
|
||||
[322.500, 9.197830],
|
||||
[327.500, 8.313471],
|
||||
[332.500, 7.212131],
|
||||
[337.500, 5.972713],
|
||||
[342.500, 4.674119],
|
||||
[347.500, 3.395249],
|
||||
[352.500, 2.215008],
|
||||
[357.500, 1.212296],
|
||||
[362.500, 0.466015],
|
||||
[367.500, 0.055067],
|
||||
[370.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -419.2, 312.6411, 0 ],
|
||||
[ -239.2, 312.6411, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, -44.7722 ],
|
||||
[ -179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, -44.7722 ],
|
||||
[ -59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, -44.7722 ],
|
||||
[ 59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, -44.7722 ],
|
||||
[ 179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, 44.7722 ],
|
||||
[ -179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, 44.7722 ],
|
||||
[ -59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, 44.7722 ],
|
||||
[ 59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, 44.7722 ],
|
||||
[ 179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, -125.509 ],
|
||||
[ -178.0076, 119.9376, -135.7592 ],
|
||||
[ -174.0725, 112.269, -144.828 ],
|
||||
[ -167.9579, 104.7529, -152.7871 ],
|
||||
[ -160.0272, 97.307, -159.7084 ],
|
||||
[ -150.6434, 89.8488, -165.6635 ],
|
||||
[ -140.17, 82.2959, -170.7242 ],
|
||||
[ -128.9701, 74.5658, -174.9623 ],
|
||||
[ -117.4069, 66.5761, -178.4496 ],
|
||||
[ -105.8437, 58.2443, -181.2578 ],
|
||||
[ -94.6438, 49.4881, -183.4588 ],
|
||||
[ -84.1704, 40.225, -185.1243 ],
|
||||
[ -74.7866, 30.3725, -186.326 ],
|
||||
[ -66.8559, 19.8482, -187.1357 ],
|
||||
[ -60.7413, 8.5696, -187.6252 ],
|
||||
[ -56.8062, -3.5455, -187.8663 ],
|
||||
[ -55.4138, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, -125.509 ],
|
||||
[ -59.5988, 121.2536, -133.7587 ],
|
||||
[ -59.0302, 114.2313, -141.3427 ],
|
||||
[ -58.1467, 106.7977, -148.2793 ],
|
||||
[ -57.0008, 98.9764, -154.587 ],
|
||||
[ -55.6449, 90.7908, -160.2843 ],
|
||||
[ -54.1316, 82.2644, -165.3894 ],
|
||||
[ -52.5133, 73.4207, -169.921 ],
|
||||
[ -50.8425, 64.2831, -173.8973 ],
|
||||
[ -49.1717, 54.8751, -177.3368 ],
|
||||
[ -47.5534, 45.2202, -180.258 ],
|
||||
[ -46.0401, 35.3419, -182.6792 ],
|
||||
[ -44.6842, 25.2636, -184.6188 ],
|
||||
[ -43.5383, 15.0088, -186.0954 ],
|
||||
[ -42.6548, 4.601, -187.1273 ],
|
||||
[ -42.0862, -5.9364, -187.7329 ],
|
||||
[ -41.885, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, -125.509 ],
|
||||
[ 61.1924, 119.9376, -135.7592 ],
|
||||
[ 65.1275, 112.269, -144.828 ],
|
||||
[ 71.2421, 104.7529, -152.7871 ],
|
||||
[ 79.1728, 97.307, -159.7084 ],
|
||||
[ 88.5566, 89.8488, -165.6635 ],
|
||||
[ 99.03, 82.2959, -170.7242 ],
|
||||
[ 110.2299, 74.5658, -174.9623 ],
|
||||
[ 121.7931, 66.5761, -178.4496 ],
|
||||
[ 133.3563, 58.2443, -181.2578 ],
|
||||
[ 144.5562, 49.4881, -183.4588 ],
|
||||
[ 155.0296, 40.225, -185.1243 ],
|
||||
[ 164.4134, 30.3725, -186.326 ],
|
||||
[ 172.3441, 19.8482, -187.1357 ],
|
||||
[ 178.4587, 8.5696, -187.6252 ],
|
||||
[ 182.3938, -3.5455, -187.8663 ],
|
||||
[ 183.7862, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, -125.509 ],
|
||||
[ 179.6012, 121.2536, -133.7587 ],
|
||||
[ 180.1698, 114.2313, -141.3427 ],
|
||||
[ 181.0533, 106.7977, -148.2793 ],
|
||||
[ 182.1992, 98.9764, -154.587 ],
|
||||
[ 183.5551, 90.7908, -160.2843 ],
|
||||
[ 185.0684, 82.2644, -165.3894 ],
|
||||
[ 186.6867, 73.4207, -169.921 ],
|
||||
[ 188.3575, 64.2831, -173.8973 ],
|
||||
[ 190.0283, 54.8751, -177.3368 ],
|
||||
[ 191.6466, 45.2202, -180.258 ],
|
||||
[ 193.1599, 35.3419, -182.6792 ],
|
||||
[ 194.5158, 25.2636, -184.6188 ],
|
||||
[ 195.6617, 15.0088, -186.0954 ],
|
||||
[ 196.5452, 4.601, -187.1273 ],
|
||||
[ 197.1138, -5.9364, -187.7329 ],
|
||||
[ 197.315, -16.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, 125.509 ],
|
||||
[ -178.324, 117.6211, 137.7817 ],
|
||||
[ -175.1941, 106.5763, 148.386 ],
|
||||
[ -170.1577, 94.9116, 157.4428 ],
|
||||
[ -163.362, 82.8316, 165.073 ],
|
||||
[ -154.9545, 70.5413, 171.3976 ],
|
||||
[ -145.0824, 58.2453, 176.5376 ],
|
||||
[ -133.893, 46.1485, 180.614 ],
|
||||
[ -121.5338, 34.4556, 183.7476 ],
|
||||
[ -108.1519, 23.3715, 186.0596 ],
|
||||
[ -93.8947, 13.1008, 187.6708 ],
|
||||
[ -78.9095, 3.8484, 188.7023 ],
|
||||
[ -63.3436, -4.1809, 189.2749 ],
|
||||
[ -47.3445, -10.7824, 189.5097 ],
|
||||
[ -31.0593, -15.7513, 189.5277 ],
|
||||
[ -14.6354, -18.8828, 189.4497 ],
|
||||
[ 1.7798, -19.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, 125.509 ],
|
||||
[ -58.724, 117.6211, 137.7817 ],
|
||||
[ -55.5941, 106.5763, 148.386 ],
|
||||
[ -50.5577, 94.9116, 157.4428 ],
|
||||
[ -43.762, 82.8316, 165.073 ],
|
||||
[ -35.3545, 70.5413, 171.3976 ],
|
||||
[ -25.4824, 58.2453, 176.5376 ],
|
||||
[ -14.293, 46.1485, 180.614 ],
|
||||
[ -1.9338, 34.4556, 183.7476 ],
|
||||
[ 11.4481, 23.3715, 186.0596 ],
|
||||
[ 25.7053, 13.1008, 187.6708 ],
|
||||
[ 40.6905, 3.8484, 188.7023 ],
|
||||
[ 56.2563, -4.1809, 189.2749 ],
|
||||
[ 72.2555, -10.7824, 189.5097 ],
|
||||
[ 88.5407, -15.7513, 189.5277 ],
|
||||
[ 104.9646, -18.8828, 189.4497 ],
|
||||
[ 121.3798, -19.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 7
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, 125.509 ],
|
||||
[ 59.4056, 121.1641, 133.8948 ],
|
||||
[ 58.2909, 114.0977, 141.5798 ],
|
||||
[ 56.5589, 106.6586, 148.586 ],
|
||||
[ 54.3124, 98.8628, 154.9355 ],
|
||||
[ 51.6544, 90.7267, 160.6503 ],
|
||||
[ 48.6876, 82.2665, 165.7524 ],
|
||||
[ 45.5151, 73.4986, 170.264 ],
|
||||
[ 42.2397, 64.4391, 174.2071 ],
|
||||
[ 38.9643, 55.1044, 177.6036 ],
|
||||
[ 35.7918, 45.5106, 180.4758 ],
|
||||
[ 32.8251, 35.6741, 182.8455 ],
|
||||
[ 30.167, 25.6112, 184.735 ],
|
||||
[ 27.9206, 15.3381, 186.1662 ],
|
||||
[ 26.1885, 4.871, 187.1611 ],
|
||||
[ 25.0739, -5.7737, 187.742 ],
|
||||
[ 24.6794, -16.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 8
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, 125.509 ],
|
||||
[ 179.0056, 121.164, 133.8948 ],
|
||||
[ 177.8909, 114.0977, 141.5798 ],
|
||||
[ 176.1589, 106.6586, 148.586 ],
|
||||
[ 173.9124, 98.8628, 154.9355 ],
|
||||
[ 171.2544, 90.7267, 160.6503 ],
|
||||
[ 168.2876, 82.2665, 165.7524 ],
|
||||
[ 165.1151, 73.4986, 170.264 ],
|
||||
[ 161.8397, 64.4391, 174.2071 ],
|
||||
[ 158.5643, 55.1044, 177.6036 ],
|
||||
[ 155.3918, 45.5106, 180.4758 ],
|
||||
[ 152.4251, 35.6741, 182.8455 ],
|
||||
[ 149.767, 25.6112, 184.735 ],
|
||||
[ 147.5205, 15.3381, 186.1662 ],
|
||||
[ 145.7885, 4.871, 187.1611 ],
|
||||
[ 144.6739, -5.7737, 187.742 ],
|
||||
[ 144.2794, -16.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# secondaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ -21.1798, -37.1882, -195.8922 ],
|
||||
[ 1.7283, -37.6445, -195.8922 ],
|
||||
[ 24.0223, -38.9338, -195.8922 ],
|
||||
[ 45.7896, -40.9372, -195.8922 ],
|
||||
[ 67.1182, -43.5357, -195.8922 ],
|
||||
[ 88.0958, -46.6102, -195.8922 ],
|
||||
[ 108.8101, -50.0418, -195.8922 ],
|
||||
[ 129.3489, -53.7114, -195.8922 ],
|
||||
[ 149.8, -57.5, -195.8922 ],
|
||||
[ 170.251, -61.2886, -195.8922 ],
|
||||
[ 190.7898, -64.9582, -195.8922 ],
|
||||
[ 211.5042, -68.3898, -195.8922 ],
|
||||
[ 232.4818, -71.4643, -195.8922 ],
|
||||
[ 253.8104, -74.0628, -195.8922 ],
|
||||
[ 275.5777, -76.0662, -195.8922 ],
|
||||
[ 297.8716, -77.3555, -195.8922 ],
|
||||
[ 320.7798, -77.8118, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 218.0202, -40.9377, -195.8922 ],
|
||||
[ 225.1524, -41.3097, -195.8922 ],
|
||||
[ 232.0008, -42.361, -195.8922 ],
|
||||
[ 238.6058, -43.9946, -195.8922 ],
|
||||
[ 245.008, -46.1134, -195.8922 ],
|
||||
[ 251.2479, -48.6204, -195.8922 ],
|
||||
[ 257.3662, -51.4185, -195.8922 ],
|
||||
[ 263.4034, -54.4107, -195.8922 ],
|
||||
[ 269.4, -57.5, -195.8922 ],
|
||||
[ 275.3966, -60.5892, -195.8922 ],
|
||||
[ 281.4338, -63.5815, -195.8922 ],
|
||||
[ 287.552, -66.3796, -195.8922 ],
|
||||
[ 293.792, -68.8866, -195.8922 ],
|
||||
[ 300.1942, -71.0054, -195.8922 ],
|
||||
[ 306.7992, -72.6389, -195.8922 ],
|
||||
[ 313.6476, -73.6903, -195.8922 ],
|
||||
[ 320.7798, -74.0623, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ 38.6202, -37.5985, 195.8922 ],
|
||||
[ 57.5671, -38.0455, 195.8922 ],
|
||||
[ 75.9893, -39.3087, 195.8922 ],
|
||||
[ 93.9616, -41.2717, 195.8922 ],
|
||||
[ 111.5591, -43.8177, 195.8922 ],
|
||||
[ 128.8567, -46.8301, 195.8922 ],
|
||||
[ 145.9294, -50.1924, 195.8922 ],
|
||||
[ 162.8522, -53.7879, 195.8922 ],
|
||||
[ 179.7, -57.5, 195.8922 ],
|
||||
[ 196.5478, -61.2121, 195.8922 ],
|
||||
[ 213.4705, -64.8076, 195.8922 ],
|
||||
[ 230.5433, -68.1699, 195.8922 ],
|
||||
[ 247.8409, -71.1823, 195.8922 ],
|
||||
[ 265.4383, -73.7283, 195.8922 ],
|
||||
[ 283.4107, -75.6913, 195.8922 ],
|
||||
[ 301.8329, -76.9545, 195.8922 ],
|
||||
[ 320.7798, -77.4015, 195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ 158.2202, -39.157, 195.8922 ],
|
||||
[ 169.2733, -39.569, 195.8922 ],
|
||||
[ 179.9691, -40.7334, 195.8922 ],
|
||||
[ 190.3587, -42.5426, 195.8922 ],
|
||||
[ 200.4932, -44.8892, 195.8922 ],
|
||||
[ 210.4235, -47.6657, 195.8922 ],
|
||||
[ 220.2007, -50.7647, 195.8922 ],
|
||||
[ 229.8759, -54.0786, 195.8922 ],
|
||||
[ 239.5, -57.5, 195.8922 ],
|
||||
[ 249.1241, -60.9214, 195.8922 ],
|
||||
[ 258.7993, -64.2353, 195.8922 ],
|
||||
[ 268.5765, -67.3343, 195.8922 ],
|
||||
[ 278.5068, -70.1108, 195.8922 ],
|
||||
[ 288.6412, -72.4574, 195.8922 ],
|
||||
[ 299.0309, -74.2666, 195.8922 ],
|
||||
[ 309.7267, -75.431, 195.8922 ],
|
||||
[ 320.7798, -75.843, 195.8922 ]
|
||||
]
|
||||
|
||||
# bank_collectors 1
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ 357.6201, -80, -203.0101 ],
|
||||
[ 393.845, -80, -205.237 ],
|
||||
[ 428.4088, -80, -211.5304 ],
|
||||
[ 461.549, -80, -221.3095 ],
|
||||
[ 493.5029, -80, -233.9932 ],
|
||||
[ 524.5076, -80, -249.0007 ],
|
||||
[ 554.8005, -80, -265.751 ],
|
||||
[ 584.6189, -80, -283.6631 ],
|
||||
[ 614.2, -80, -302.1562 ],
|
||||
[ 643.781, -80, -320.6493 ],
|
||||
[ 673.5994, -80, -338.5614 ],
|
||||
[ 703.8922, -80, -355.3117 ],
|
||||
[ 734.897, -80, -370.3192 ],
|
||||
[ 766.8508, -80, -383.0029 ],
|
||||
[ 799.9911, -80, -392.782 ],
|
||||
[ 834.5549, -80, -399.0755 ],
|
||||
[ 870.7797, -80, -401.3024 ]
|
||||
]
|
||||
|
||||
# bank_collectors 2
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 357.6201, -80, 203.0101 ],
|
||||
[ 393.845, -80, 205.237 ],
|
||||
[ 428.4088, -80, 211.5304 ],
|
||||
[ 461.549, -80, 221.3095 ],
|
||||
[ 493.5029, -80, 233.9932 ],
|
||||
[ 524.5076, -80, 249.0007 ],
|
||||
[ 554.8005, -80, 265.751 ],
|
||||
[ 584.6189, -80, 283.6631 ],
|
||||
[ 614.2, -80, 302.1562 ],
|
||||
[ 643.781, -80, 320.6493 ],
|
||||
[ 673.5994, -80, 338.5614 ],
|
||||
[ 703.8922, -80, 355.3117 ],
|
||||
[ 734.897, -80, 370.3192 ],
|
||||
[ 766.8508, -80, 383.0029 ],
|
||||
[ 799.9911, -80, 392.782 ],
|
||||
[ 834.5549, -80, 399.0755 ],
|
||||
[ 870.7797, -80, 401.3024 ]
|
||||
]
|
||||
|
||||
# tailpipes 1
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 907.62, -80, -408.4202 ],
|
||||
[ 2157.62, -80, -408.4202 ]
|
||||
]
|
||||
|
||||
# tailpipes 2
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 907.62, -80, 408.4202 ],
|
||||
[ 2157.62, -80, 408.4202 ]
|
||||
]
|
||||
|
||||
# crossover
|
||||
[[geometry.pipes]]
|
||||
index = 25
|
||||
points_mm = [
|
||||
[ 889.1999, -80, -390 ],
|
||||
[ 889.1999, -80, 390 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 312.6411, 0 ]
|
||||
size_mm = [ 478.4, 43.7429, 191.1445 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -39.6, -35, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 199.6, -35, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 20.2, -35, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 139.8, -35, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_4"
|
||||
center_mm = [ 339.2, -80, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_5"
|
||||
center_mm = [ 339.2, -80, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_6"
|
||||
center_mm = [ 889.1999, -80, -408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_7"
|
||||
center_mm = [ 889.1999, -80, 408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "v8-long"
|
||||
name = "American 5.0 / long headers"
|
||||
category = "V8 / American 5.0"
|
||||
description = "900 mm primaries with H crossover"
|
||||
description = "Extended swept headers / H crossover"
|
||||
order = 10
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 8
|
||||
initial_rpm = 1000.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 300.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0, 270.0, 540.0, 630.0, 360.0, 180.0, 89.99998]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 4.0
|
||||
starter_torque_nm = 180.0
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "american_v8"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 65.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 7.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 370.0
|
||||
exhaust_open_deg = 140.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 37.0
|
||||
exhaust_valve_lift_mm = 10.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 570.0
|
||||
intake_open_deg = 350.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 45.0
|
||||
intake_valve_lift_mm = 10.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 129.0
|
||||
stroke_mm = 76.2
|
||||
@@ -101,51 +96,619 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 3
|
||||
diameter_mm = 70.0
|
||||
length_mm = 180.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 8
|
||||
cells = 2
|
||||
diameter_mm = 38.0
|
||||
length_mm = 120.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 8
|
||||
cells = 18
|
||||
diameter_mm = 38.0
|
||||
length_mm = 900.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondaries"
|
||||
count = 4
|
||||
cells = 8
|
||||
diameter_mm = 45.0
|
||||
length_mm = 400.0
|
||||
|
||||
[[pipes]]
|
||||
id = "bank_collectors"
|
||||
count = 2
|
||||
cells = 11
|
||||
diameter_mm = 50.0
|
||||
length_mm = 550.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipes"
|
||||
count = 2
|
||||
cells = 25
|
||||
diameter_mm = 50.0
|
||||
length_mm = 1250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "crossover"
|
||||
cells = 16
|
||||
diameter_mm = 38.0
|
||||
length_mm = 780.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[350.000, 0.000000],
|
||||
[355.000, 0.232908],
|
||||
[360.000, 0.871525],
|
||||
[365.000, 1.825695],
|
||||
[370.000, 3.005259],
|
||||
[375.000, 4.320060],
|
||||
[380.000, 5.679940],
|
||||
[385.000, 6.994741],
|
||||
[390.000, 8.174305],
|
||||
[395.000, 9.128475],
|
||||
[400.000, 9.767092],
|
||||
[405.000, 10.000000],
|
||||
[515.000, 10.000000],
|
||||
[520.000, 9.767092],
|
||||
[525.000, 9.128475],
|
||||
[530.000, 8.174305],
|
||||
[535.000, 6.994741],
|
||||
[540.000, 5.679940],
|
||||
[545.000, 4.320060],
|
||||
[550.000, 3.005259],
|
||||
[555.000, 1.825695],
|
||||
[560.000, 0.871525],
|
||||
[565.000, 0.232908],
|
||||
[570.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[140.000, 0.000000],
|
||||
[145.000, 0.213693],
|
||||
[150.000, 0.802170],
|
||||
[155.000, 1.686529],
|
||||
[160.000, 2.787869],
|
||||
[165.000, 4.027287],
|
||||
[170.000, 5.325881],
|
||||
[175.000, 6.604751],
|
||||
[180.000, 7.784992],
|
||||
[185.000, 8.787704],
|
||||
[190.000, 9.533985],
|
||||
[195.000, 9.944933],
|
||||
[197.500, 10.000000],
|
||||
[312.500, 10.000000],
|
||||
[317.500, 9.786307],
|
||||
[322.500, 9.197830],
|
||||
[327.500, 8.313471],
|
||||
[332.500, 7.212131],
|
||||
[337.500, 5.972713],
|
||||
[342.500, 4.674119],
|
||||
[347.500, 3.395249],
|
||||
[352.500, 2.215008],
|
||||
[357.500, 1.212296],
|
||||
[362.500, 0.466015],
|
||||
[367.500, 0.055067],
|
||||
[370.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -419.2, 312.6411, 0 ],
|
||||
[ -239.2, 312.6411, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, -44.7722 ],
|
||||
[ -179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, -44.7722 ],
|
||||
[ -59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, -44.7722 ],
|
||||
[ 59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, -44.7722 ],
|
||||
[ 179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, 44.7722 ],
|
||||
[ -179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, 44.7722 ],
|
||||
[ -59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, 44.7722 ],
|
||||
[ 59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, 44.7722 ],
|
||||
[ 179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, -125.509 ],
|
||||
[ -173.96, 112.9085, -143.9462 ],
|
||||
[ -163.5939, 99.0794, -159.0769 ],
|
||||
[ -149.0058, 86.1075, -171.1943 ],
|
||||
[ -130.8994, 73.7466, -180.5915 ],
|
||||
[ -109.9786, 61.7504, -187.562 ],
|
||||
[ -86.9474, 49.8725, -192.3988 ],
|
||||
[ -62.5096, 37.8667, -195.3952 ],
|
||||
[ -37.369, 25.4867, -196.8445 ],
|
||||
[ -12.2297, 12.4862, -197.0399 ],
|
||||
[ 12.2045, -1.3811, -196.2746 ],
|
||||
[ 35.2299, -16.3615, -194.8419 ],
|
||||
[ 56.1423, -32.7012, -193.0351 ],
|
||||
[ 74.2381, -50.6466, -191.1473 ],
|
||||
[ 88.8132, -70.444, -189.4718 ],
|
||||
[ 99.1639, -92.3396, -188.3019 ],
|
||||
[ 104.5862, -116.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, -125.509 ],
|
||||
[ -57.476, 114.8912, -140.4956 ],
|
||||
[ -51.6334, 101.9895, -153.0346 ],
|
||||
[ -42.7747, 89.0591, -163.3339 ],
|
||||
[ -31.4028, 76.0233, -171.6011 ],
|
||||
[ -18.0202, 62.8053, -178.0441 ],
|
||||
[ -3.1297, 49.3284, -182.8705 ],
|
||||
[ 12.7659, 35.5157, -186.2882 ],
|
||||
[ 29.1641, 21.2904, -188.5048 ],
|
||||
[ 45.562, 6.5757, -189.7281 ],
|
||||
[ 61.4571, -8.7051, -190.166 ],
|
||||
[ 76.3465, -24.6288, -190.026 ],
|
||||
[ 89.7276, -41.2724, -189.516 ],
|
||||
[ 101.0977, -58.7124, -188.8437 ],
|
||||
[ 109.9541, -77.0258, -188.2169 ],
|
||||
[ 115.7941, -96.2893, -187.8433 ],
|
||||
[ 118.115, -116.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, -125.509 ],
|
||||
[ 65.24, 112.9085, -143.9462 ],
|
||||
[ 75.6061, 99.0794, -159.0769 ],
|
||||
[ 90.1942, 86.1075, -171.1943 ],
|
||||
[ 108.3006, 73.7466, -180.5915 ],
|
||||
[ 129.2214, 61.7504, -187.562 ],
|
||||
[ 152.2526, 49.8725, -192.3988 ],
|
||||
[ 176.6904, 37.8667, -195.3952 ],
|
||||
[ 201.831, 25.4867, -196.8445 ],
|
||||
[ 226.9703, 12.4862, -197.0399 ],
|
||||
[ 251.4045, -1.3811, -196.2746 ],
|
||||
[ 274.4299, -16.3615, -194.8419 ],
|
||||
[ 295.3423, -32.7012, -193.0351 ],
|
||||
[ 313.4381, -50.6466, -191.1473 ],
|
||||
[ 328.0132, -70.444, -189.4718 ],
|
||||
[ 338.3639, -92.3396, -188.3019 ],
|
||||
[ 343.7862, -116.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, -125.509 ],
|
||||
[ 181.724, 114.8912, -140.4956 ],
|
||||
[ 187.5666, 101.9895, -153.0346 ],
|
||||
[ 196.4253, 89.0591, -163.3339 ],
|
||||
[ 207.7972, 76.0233, -171.6011 ],
|
||||
[ 221.1798, 62.8053, -178.0441 ],
|
||||
[ 236.0703, 49.3284, -182.8705 ],
|
||||
[ 251.9659, 35.5157, -186.2882 ],
|
||||
[ 268.3641, 21.2904, -188.5048 ],
|
||||
[ 284.762, 6.5757, -189.7281 ],
|
||||
[ 300.6571, -8.7051, -190.166 ],
|
||||
[ 315.5465, -24.6288, -190.026 ],
|
||||
[ 328.9276, -41.2724, -189.516 ],
|
||||
[ 340.2977, -58.7124, -188.8437 ],
|
||||
[ 349.1541, -77.0258, -188.2169 ],
|
||||
[ 354.9941, -96.2893, -187.8433 ],
|
||||
[ 357.315, -116.5798, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, 125.509 ],
|
||||
[ -175.5507, 109.015, 145.6312 ],
|
||||
[ -168.0603, 89.4647, 162.0723 ],
|
||||
[ -157.2099, 69.4408, 175.1602 ],
|
||||
[ -143.2803, 49.1937, 185.223 ],
|
||||
[ -126.5526, 28.9742, 192.5886 ],
|
||||
[ -107.3076, 9.0326, 197.5849 ],
|
||||
[ -85.8263, -10.3803, 200.5401 ],
|
||||
[ -62.3898, -29.0142, 201.7819 ],
|
||||
[ -37.2788, -46.6185, 201.6385 ],
|
||||
[ -10.7745, -62.9425, 200.4378 ],
|
||||
[ 16.8423, -77.7358, 198.5078 ],
|
||||
[ 45.2906, -90.7478, 196.1764 ],
|
||||
[ 74.2894, -101.728, 193.7716 ],
|
||||
[ 103.5579, -110.4258, 191.6215 ],
|
||||
[ 132.815, -116.5907, 190.0539 ],
|
||||
[ 161.7798, -119.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, 125.509 ],
|
||||
[ -55.9507, 109.015, 145.6312 ],
|
||||
[ -48.4603, 89.4647, 162.0723 ],
|
||||
[ -37.6099, 69.4408, 175.1602 ],
|
||||
[ -23.6803, 49.1937, 185.223 ],
|
||||
[ -6.9526, 28.9742, 192.5886 ],
|
||||
[ 12.2924, 9.0326, 197.5849 ],
|
||||
[ 33.7737, -10.3803, 200.5401 ],
|
||||
[ 57.2102, -29.0142, 201.7819 ],
|
||||
[ 82.3212, -46.6185, 201.6385 ],
|
||||
[ 108.8255, -62.9425, 200.4378 ],
|
||||
[ 136.4423, -77.7358, 198.5078 ],
|
||||
[ 164.8906, -90.7478, 196.1764 ],
|
||||
[ 193.8894, -101.728, 193.7716 ],
|
||||
[ 223.1579, -110.4258, 191.6215 ],
|
||||
[ 252.415, -116.5907, 190.0539 ],
|
||||
[ 281.3798, -119.9721, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 7
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, 125.509 ],
|
||||
[ 60.6291, 115.8136, 139.2457 ],
|
||||
[ 64.2478, 103.3813, 150.8635 ],
|
||||
[ 70.2577, 90.538, 160.5356 ],
|
||||
[ 78.2604, 77.2777, 168.4348 ],
|
||||
[ 87.8572, 63.5944, 174.7343 ],
|
||||
[ 98.6499, 49.482, 179.607 ],
|
||||
[ 110.2399, 34.9344, 183.226 ],
|
||||
[ 122.2286, 19.9456, 185.7644 ],
|
||||
[ 134.2178, 4.5093, 187.3951 ],
|
||||
[ 145.8088, -11.3803, 188.2912 ],
|
||||
[ 156.6031, -27.7294, 188.6258 ],
|
||||
[ 166.2025, -44.5441, 188.5717 ],
|
||||
[ 174.2082, -61.8304, 188.3022 ],
|
||||
[ 180.2219, -79.5944, 187.9902 ],
|
||||
[ 183.8452, -97.8422, 187.8086 ],
|
||||
[ 184.6794, -116.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 8
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, 125.509 ],
|
||||
[ 180.2291, 115.8135, 139.2456 ],
|
||||
[ 183.8478, 103.3811, 150.8634 ],
|
||||
[ 189.8577, 90.5378, 160.5354 ],
|
||||
[ 197.8604, 77.2775, 168.4346 ],
|
||||
[ 207.4573, 63.5942, 174.7341 ],
|
||||
[ 218.2499, 49.4818, 179.6068 ],
|
||||
[ 229.8399, 34.9342, 183.2258 ],
|
||||
[ 241.8287, 19.9453, 185.7642 ],
|
||||
[ 253.8178, 4.5092, 187.395 ],
|
||||
[ 265.4088, -11.3804, 188.2911 ],
|
||||
[ 276.2032, -27.7295, 188.6257 ],
|
||||
[ 285.8025, -44.5441, 188.5717 ],
|
||||
[ 293.8082, -61.8304, 188.3022 ],
|
||||
[ 299.8219, -79.5944, 187.9901 ],
|
||||
[ 303.4452, -97.8422, 187.8086 ],
|
||||
[ 304.2794, -116.5798, 187.9307 ]
|
||||
]
|
||||
|
||||
# secondaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ 138.8202, -137.1882, -195.8922 ],
|
||||
[ 161.7283, -137.6445, -195.8922 ],
|
||||
[ 184.0223, -138.9338, -195.8922 ],
|
||||
[ 205.7896, -140.9372, -195.8922 ],
|
||||
[ 227.1182, -143.5357, -195.8922 ],
|
||||
[ 248.0958, -146.6102, -195.8922 ],
|
||||
[ 268.8101, -150.0418, -195.8922 ],
|
||||
[ 289.3489, -153.7114, -195.8922 ],
|
||||
[ 309.8, -157.5, -195.8922 ],
|
||||
[ 330.251, -161.2886, -195.8922 ],
|
||||
[ 350.7898, -164.9582, -195.8922 ],
|
||||
[ 371.5042, -168.3898, -195.8922 ],
|
||||
[ 392.4818, -171.4643, -195.8922 ],
|
||||
[ 413.8104, -174.0628, -195.8922 ],
|
||||
[ 435.5777, -176.0662, -195.8922 ],
|
||||
[ 457.8716, -177.3555, -195.8922 ],
|
||||
[ 480.7798, -177.8118, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 378.0202, -140.9377, -195.8922 ],
|
||||
[ 385.1524, -141.3097, -195.8922 ],
|
||||
[ 392.0008, -142.361, -195.8922 ],
|
||||
[ 398.6058, -143.9946, -195.8922 ],
|
||||
[ 405.008, -146.1134, -195.8922 ],
|
||||
[ 411.2479, -148.6204, -195.8922 ],
|
||||
[ 417.3662, -151.4185, -195.8922 ],
|
||||
[ 423.4034, -154.4107, -195.8922 ],
|
||||
[ 429.4, -157.5, -195.8922 ],
|
||||
[ 435.3966, -160.5892, -195.8922 ],
|
||||
[ 441.4338, -163.5815, -195.8922 ],
|
||||
[ 447.552, -166.3796, -195.8922 ],
|
||||
[ 453.792, -168.8866, -195.8922 ],
|
||||
[ 460.1942, -171.0054, -195.8922 ],
|
||||
[ 466.7992, -172.6389, -195.8922 ],
|
||||
[ 473.6476, -173.6903, -195.8922 ],
|
||||
[ 480.7798, -174.0623, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ 198.6202, -137.5985, 195.8922 ],
|
||||
[ 217.5671, -138.0455, 195.8922 ],
|
||||
[ 235.9893, -139.3087, 195.8922 ],
|
||||
[ 253.9616, -141.2717, 195.8922 ],
|
||||
[ 271.5591, -143.8177, 195.8922 ],
|
||||
[ 288.8567, -146.8301, 195.8922 ],
|
||||
[ 305.9294, -150.1924, 195.8922 ],
|
||||
[ 322.8522, -153.7879, 195.8922 ],
|
||||
[ 339.7, -157.5, 195.8922 ],
|
||||
[ 356.5478, -161.2121, 195.8922 ],
|
||||
[ 373.4705, -164.8076, 195.8922 ],
|
||||
[ 390.5433, -168.1699, 195.8922 ],
|
||||
[ 407.8409, -171.1823, 195.8922 ],
|
||||
[ 425.4383, -173.7283, 195.8922 ],
|
||||
[ 443.4107, -175.6913, 195.8922 ],
|
||||
[ 461.8329, -176.9545, 195.8922 ],
|
||||
[ 480.7798, -177.4015, 195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ 318.2202, -139.157, 195.8922 ],
|
||||
[ 329.2733, -139.569, 195.8922 ],
|
||||
[ 339.9691, -140.7334, 195.8922 ],
|
||||
[ 350.3587, -142.5426, 195.8922 ],
|
||||
[ 360.4932, -144.8892, 195.8922 ],
|
||||
[ 370.4235, -147.6657, 195.8922 ],
|
||||
[ 380.2007, -150.7647, 195.8922 ],
|
||||
[ 389.8759, -154.0786, 195.8922 ],
|
||||
[ 399.5, -157.5, 195.8922 ],
|
||||
[ 409.1241, -160.9214, 195.8922 ],
|
||||
[ 418.7993, -164.2353, 195.8922 ],
|
||||
[ 428.5765, -167.3343, 195.8922 ],
|
||||
[ 438.5068, -170.1108, 195.8922 ],
|
||||
[ 448.6412, -172.4574, 195.8922 ],
|
||||
[ 459.0309, -174.2666, 195.8922 ],
|
||||
[ 469.7267, -175.431, 195.8922 ],
|
||||
[ 480.7798, -175.843, 195.8922 ]
|
||||
]
|
||||
|
||||
# bank_collectors 1
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ 517.6201, -180, -203.0101 ],
|
||||
[ 553.845, -180, -205.237 ],
|
||||
[ 588.4088, -180, -211.5304 ],
|
||||
[ 621.549, -180, -221.3095 ],
|
||||
[ 653.5029, -180, -233.9932 ],
|
||||
[ 684.5076, -180, -249.0007 ],
|
||||
[ 714.8005, -180, -265.751 ],
|
||||
[ 744.6189, -180, -283.6631 ],
|
||||
[ 774.2, -180, -302.1562 ],
|
||||
[ 803.781, -180, -320.6493 ],
|
||||
[ 833.5994, -180, -338.5614 ],
|
||||
[ 863.8922, -180, -355.3117 ],
|
||||
[ 894.897, -180, -370.3192 ],
|
||||
[ 926.8508, -180, -383.0029 ],
|
||||
[ 959.9911, -180, -392.782 ],
|
||||
[ 994.5549, -180, -399.0755 ],
|
||||
[ 1030.7797, -180, -401.3024 ]
|
||||
]
|
||||
|
||||
# bank_collectors 2
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 517.6201, -180, 203.0101 ],
|
||||
[ 553.845, -180, 205.237 ],
|
||||
[ 588.4088, -180, 211.5304 ],
|
||||
[ 621.549, -180, 221.3095 ],
|
||||
[ 653.5029, -180, 233.9932 ],
|
||||
[ 684.5076, -180, 249.0007 ],
|
||||
[ 714.8005, -180, 265.751 ],
|
||||
[ 744.6189, -180, 283.6631 ],
|
||||
[ 774.2, -180, 302.1562 ],
|
||||
[ 803.781, -180, 320.6493 ],
|
||||
[ 833.5994, -180, 338.5614 ],
|
||||
[ 863.8922, -180, 355.3117 ],
|
||||
[ 894.897, -180, 370.3192 ],
|
||||
[ 926.8508, -180, 383.0029 ],
|
||||
[ 959.9911, -180, 392.782 ],
|
||||
[ 994.5549, -180, 399.0755 ],
|
||||
[ 1030.7797, -180, 401.3024 ]
|
||||
]
|
||||
|
||||
# tailpipes 1
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 1067.62, -180, -408.4202 ],
|
||||
[ 2317.62, -180, -408.4202 ]
|
||||
]
|
||||
|
||||
# tailpipes 2
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 1067.62, -180, 408.4202 ],
|
||||
[ 2317.62, -180, 408.4202 ]
|
||||
]
|
||||
|
||||
# crossover
|
||||
[[geometry.pipes]]
|
||||
index = 25
|
||||
points_mm = [
|
||||
[ 1049.1999, -180, -390 ],
|
||||
[ 1049.1999, -180, 390 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 312.6411, 0 ]
|
||||
size_mm = [ 478.4, 43.7429, 191.1445 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ 120.4, -135, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 359.6, -135, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ 180.2, -135, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 299.8, -135, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_4"
|
||||
center_mm = [ 499.2, -180, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_5"
|
||||
center_mm = [ 499.2, -180, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_6"
|
||||
center_mm = [ 1049.1999, -180, -408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_7"
|
||||
center_mm = [ 1049.1999, -180, 408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "v8-short"
|
||||
name = "American 5.0 / short headers"
|
||||
category = "V8 / American 5.0"
|
||||
description = "600 mm primaries with H crossover"
|
||||
description = "Compact swept headers / H crossover"
|
||||
order = 9
|
||||
cycle = "four_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 20.0
|
||||
|
||||
[engine]
|
||||
bank_angle_deg = 56.0
|
||||
collector_volume_litres = 1.5
|
||||
cylinders = 8
|
||||
initial_rpm = 1000.0
|
||||
initialize_phased_charge = true
|
||||
@@ -18,7 +20,6 @@ maximum_load_torque_nm = 300.0
|
||||
minimum_substeps = 1
|
||||
phase_degrees = [0.0, 450.0, 270.0, 540.0, 630.0, 360.0, 180.0, 89.99998]
|
||||
pipe_damping = 1.0
|
||||
plenum_volume_litres = 4.0
|
||||
starter_torque_nm = 180.0
|
||||
throttle_diameter_mm = 65.0
|
||||
topology = "american_v8"
|
||||
@@ -31,18 +32,12 @@ burn_duration_deg = 65.0
|
||||
burn_start_deg = 5.0
|
||||
compression = 7.0
|
||||
energy_variation = 0.05
|
||||
exhaust_close_deg = 370.0
|
||||
exhaust_open_deg = 140.0
|
||||
exhaust_valve_count = 1
|
||||
exhaust_valve_diameter_mm = 37.0
|
||||
exhaust_valve_lift_mm = 10.0
|
||||
fuel_lhv_j_per_kg = 4.4e+07
|
||||
heat_transfer = 100.0
|
||||
intake_close_deg = 570.0
|
||||
intake_open_deg = 350.0
|
||||
intake_valve_count = 1
|
||||
intake_valve_diameter_mm = 45.0
|
||||
intake_valve_lift_mm = 10.0
|
||||
misfire_probability = 0.0
|
||||
rod_mm = 129.0
|
||||
stroke_mm = 76.2
|
||||
@@ -101,51 +96,619 @@ system = "injection"
|
||||
|
||||
[junctions]
|
||||
h_pipe = true
|
||||
junction_volume_cc = 50.0
|
||||
|
||||
[[pipes]]
|
||||
id = "intake"
|
||||
cells = 3
|
||||
diameter_mm = 70.0
|
||||
length_mm = 180.0
|
||||
|
||||
[[pipes]]
|
||||
id = "runners"
|
||||
count = 8
|
||||
cells = 2
|
||||
diameter_mm = 38.0
|
||||
length_mm = 120.0
|
||||
|
||||
[[pipes]]
|
||||
id = "primaries"
|
||||
count = 8
|
||||
cells = 12
|
||||
diameter_mm = 38.0
|
||||
length_mm = 600.0
|
||||
|
||||
[[pipes]]
|
||||
id = "secondaries"
|
||||
count = 4
|
||||
cells = 8
|
||||
diameter_mm = 45.0
|
||||
length_mm = 400.0
|
||||
|
||||
[[pipes]]
|
||||
id = "bank_collectors"
|
||||
count = 2
|
||||
cells = 11
|
||||
diameter_mm = 50.0
|
||||
length_mm = 550.0
|
||||
|
||||
[[pipes]]
|
||||
id = "tailpipes"
|
||||
count = 2
|
||||
cells = 25
|
||||
diameter_mm = 50.0
|
||||
length_mm = 1250.0
|
||||
|
||||
[[pipes]]
|
||||
id = "crossover"
|
||||
cells = 16
|
||||
diameter_mm = 38.0
|
||||
length_mm = 780.0
|
||||
|
||||
[cam.intake]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[350.000, 0.000000],
|
||||
[355.000, 0.232908],
|
||||
[360.000, 0.871525],
|
||||
[365.000, 1.825695],
|
||||
[370.000, 3.005259],
|
||||
[375.000, 4.320060],
|
||||
[380.000, 5.679940],
|
||||
[385.000, 6.994741],
|
||||
[390.000, 8.174305],
|
||||
[395.000, 9.128475],
|
||||
[400.000, 9.767092],
|
||||
[405.000, 10.000000],
|
||||
[515.000, 10.000000],
|
||||
[520.000, 9.767092],
|
||||
[525.000, 9.128475],
|
||||
[530.000, 8.174305],
|
||||
[535.000, 6.994741],
|
||||
[540.000, 5.679940],
|
||||
[545.000, 4.320060],
|
||||
[550.000, 3.005259],
|
||||
[555.000, 1.825695],
|
||||
[560.000, 0.871525],
|
||||
[565.000, 0.232908],
|
||||
[570.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[cam.exhaust]
|
||||
points = [
|
||||
[0.000, 0.000000],
|
||||
[140.000, 0.000000],
|
||||
[145.000, 0.213693],
|
||||
[150.000, 0.802170],
|
||||
[155.000, 1.686529],
|
||||
[160.000, 2.787869],
|
||||
[165.000, 4.027287],
|
||||
[170.000, 5.325881],
|
||||
[175.000, 6.604751],
|
||||
[180.000, 7.784992],
|
||||
[185.000, 8.787704],
|
||||
[190.000, 9.533985],
|
||||
[195.000, 9.944933],
|
||||
[197.500, 10.000000],
|
||||
[312.500, 10.000000],
|
||||
[317.500, 9.786307],
|
||||
[322.500, 9.197830],
|
||||
[327.500, 8.313471],
|
||||
[332.500, 7.212131],
|
||||
[337.500, 5.972713],
|
||||
[342.500, 4.674119],
|
||||
[347.500, 3.395249],
|
||||
[352.500, 2.215008],
|
||||
[357.500, 1.212296],
|
||||
[362.500, 0.466015],
|
||||
[367.500, 0.055067],
|
||||
[370.000, 0.000000],
|
||||
[720.000, 0.000000]
|
||||
]
|
||||
|
||||
[valves.intake]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valves.exhaust]
|
||||
mass_g = 35.0
|
||||
spring_rate_n_per_mm = 38.0
|
||||
damping_n_s_per_m = 24.0
|
||||
seat_force_n = 75.0
|
||||
maximum_lift_mm = 15.0
|
||||
seat_restitution = 0.005
|
||||
cam_restitution = 0.01
|
||||
stop_restitution = 0.01
|
||||
|
||||
[valve_sound]
|
||||
mode_hz = 3600.0
|
||||
effective_mass_g = 180.0
|
||||
radiation_area_cm2 = 10.0
|
||||
damping_ratio = 0.9
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = -28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ -59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 59.8, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 179.4, 0, 0 ]
|
||||
tilt_deg = 28.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -419.2, 312.6411, 0 ],
|
||||
[ -239.2, 312.6411, 0 ]
|
||||
]
|
||||
|
||||
# runners 1
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, -44.7722 ],
|
||||
[ -179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 2
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, -44.7722 ],
|
||||
[ -59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 3
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, -44.7722 ],
|
||||
[ 59.8, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 4
|
||||
[[geometry.pipes]]
|
||||
index = 4
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, -44.7722 ],
|
||||
[ 179.4, 170.7697, -44.7722 ]
|
||||
]
|
||||
|
||||
# runners 5
|
||||
[[geometry.pipes]]
|
||||
index = 5
|
||||
points_mm = [
|
||||
[ -179.4, 290.7697, 44.7722 ],
|
||||
[ -179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 6
|
||||
[[geometry.pipes]]
|
||||
index = 6
|
||||
points_mm = [
|
||||
[ -59.8, 290.7697, 44.7722 ],
|
||||
[ -59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 7
|
||||
[[geometry.pipes]]
|
||||
index = 7
|
||||
points_mm = [
|
||||
[ 59.8, 290.7697, 44.7722 ],
|
||||
[ 59.8, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# runners 8
|
||||
[[geometry.pipes]]
|
||||
index = 8
|
||||
points_mm = [
|
||||
[ 179.4, 290.7697, 44.7722 ],
|
||||
[ 179.4, 170.7697, 44.7722 ]
|
||||
]
|
||||
|
||||
# primaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 9
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, -125.509 ],
|
||||
[ -177.371, 121.2287, -133.8812 ],
|
||||
[ -173.803, 114.8124, -141.5497 ],
|
||||
[ -168.9157, 108.526, -148.5375 ],
|
||||
[ -162.9293, 102.3031, -154.8678 ],
|
||||
[ -156.0637, 96.0772, -160.5636 ],
|
||||
[ -148.5387, 89.7821, -165.6479 ],
|
||||
[ -140.5743, 83.3514, -170.1438 ],
|
||||
[ -132.3905, 76.7187, -174.0743 ],
|
||||
[ -124.2073, 69.8176, -177.4624 ],
|
||||
[ -116.2444, 62.5817, -180.3313 ],
|
||||
[ -108.722, 54.9447, -182.704 ],
|
||||
[ -101.8599, 46.8403, -184.6035 ],
|
||||
[ -95.8781, 38.202, -186.0529 ],
|
||||
[ -90.9965, 28.9634, -187.0752 ],
|
||||
[ -87.4351, 19.0583, -187.6934 ],
|
||||
[ -85.4138, 8.4202, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 10
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, -125.509 ],
|
||||
[ -59.7929, 122.0275, -132.471 ],
|
||||
[ -60.0906, 115.9827, -139.0794 ],
|
||||
[ -60.6495, 109.7091, -145.3225 ],
|
||||
[ -61.4262, 103.2093, -151.1886 ],
|
||||
[ -62.3771, 96.4855, -156.6662 ],
|
||||
[ -63.4586, 89.54, -161.7434 ],
|
||||
[ -64.6273, 82.3754, -166.4087 ],
|
||||
[ -65.8396, 74.9939, -170.6503 ],
|
||||
[ -67.052, 67.3979, -174.4566 ],
|
||||
[ -68.221, 59.5899, -177.8159 ],
|
||||
[ -69.303, 51.5721, -180.7165 ],
|
||||
[ -70.2545, 43.3469, -183.1467 ],
|
||||
[ -71.032, 34.9168, -185.095 ],
|
||||
[ -71.5919, 26.284, -186.5495 ],
|
||||
[ -71.8908, 17.4511, -187.4986 ],
|
||||
[ -71.885, 8.4202, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 11
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, -125.509 ],
|
||||
[ 61.829, 121.2287, -133.8812 ],
|
||||
[ 65.397, 114.8124, -141.5497 ],
|
||||
[ 70.2843, 108.526, -148.5375 ],
|
||||
[ 76.2707, 102.3031, -154.8678 ],
|
||||
[ 83.1363, 96.0772, -160.5636 ],
|
||||
[ 90.6613, 89.7821, -165.6479 ],
|
||||
[ 98.6257, 83.3514, -170.1438 ],
|
||||
[ 106.8095, 76.7187, -174.0743 ],
|
||||
[ 114.9927, 69.8176, -177.4624 ],
|
||||
[ 122.9556, 62.5817, -180.3313 ],
|
||||
[ 130.478, 54.9447, -182.704 ],
|
||||
[ 137.3401, 46.8403, -184.6035 ],
|
||||
[ 143.3219, 38.202, -186.0529 ],
|
||||
[ 148.2035, 28.9634, -187.0752 ],
|
||||
[ 151.7649, 19.0583, -187.6934 ],
|
||||
[ 153.7862, 8.4202, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 12
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, -125.509 ],
|
||||
[ 179.4071, 122.0275, -132.471 ],
|
||||
[ 179.1094, 115.9827, -139.0794 ],
|
||||
[ 178.5505, 109.7091, -145.3225 ],
|
||||
[ 177.7738, 103.2093, -151.1886 ],
|
||||
[ 176.8229, 96.4855, -156.6662 ],
|
||||
[ 175.7414, 89.54, -161.7434 ],
|
||||
[ 174.5727, 82.3754, -166.4087 ],
|
||||
[ 173.3604, 74.9939, -170.6503 ],
|
||||
[ 172.148, 67.3979, -174.4566 ],
|
||||
[ 170.979, 59.5899, -177.8159 ],
|
||||
[ 169.897, 51.5721, -180.7165 ],
|
||||
[ 168.9455, 43.3469, -183.1467 ],
|
||||
[ 168.168, 34.9168, -185.095 ],
|
||||
[ 167.6081, 26.284, -186.5495 ],
|
||||
[ 167.3092, 17.4511, -187.4986 ],
|
||||
[ 167.315, 8.4202, -187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 5
|
||||
[[geometry.pipes]]
|
||||
index = 13
|
||||
points_mm = [
|
||||
[ -179.4, 127.8412, 125.509 ],
|
||||
[ -177.6937, 118.7511, 135.5531 ],
|
||||
[ -174.4999, 109.2369, 144.5084 ],
|
||||
[ -169.9162, 99.4299, 152.4353 ],
|
||||
[ -164.0401, 89.4615, 159.3942 ],
|
||||
[ -156.9692, 79.4628, 165.4457 ],
|
||||
[ -148.8009, 69.5652, 170.65 ],
|
||||
[ -139.6328, 59.8999, 175.0676 ],
|
||||
[ -129.5624, 50.5982, 178.759 ],
|
||||
[ -118.6873, 41.7914, 181.7846 ],
|
||||
[ -107.1049, 33.6108, 184.2048 ],
|
||||
[ -94.9128, 26.1876, 186.0801 ],
|
||||
[ -82.2085, 19.6531, 187.4708 ],
|
||||
[ -69.0896, 14.1386, 188.4374 ],
|
||||
[ -55.6536, 9.7754, 189.0404 ],
|
||||
[ -41.9979, 6.6947, 189.34 ],
|
||||
[ -28.2202, 5.0279, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 6
|
||||
[[geometry.pipes]]
|
||||
index = 14
|
||||
points_mm = [
|
||||
[ -59.8, 127.8412, 125.509 ],
|
||||
[ -58.0937, 118.7511, 135.5531 ],
|
||||
[ -54.8999, 109.2369, 144.5084 ],
|
||||
[ -50.3162, 99.4299, 152.4353 ],
|
||||
[ -44.4401, 89.4615, 159.3942 ],
|
||||
[ -37.3692, 79.4628, 165.4457 ],
|
||||
[ -29.2009, 69.5652, 170.65 ],
|
||||
[ -20.0328, 59.8999, 175.0676 ],
|
||||
[ -9.9624, 50.5982, 178.759 ],
|
||||
[ 0.9127, 41.7914, 181.7846 ],
|
||||
[ 12.4951, 33.6108, 184.2048 ],
|
||||
[ 24.6872, 26.1876, 186.0801 ],
|
||||
[ 37.3915, 19.6531, 187.4708 ],
|
||||
[ 50.5104, 14.1386, 188.4374 ],
|
||||
[ 63.9464, 9.7754, 189.0404 ],
|
||||
[ 77.6021, 6.6947, 189.34 ],
|
||||
[ 91.3798, 5.0279, 189.3969 ]
|
||||
]
|
||||
|
||||
# primaries 7
|
||||
[[geometry.pipes]]
|
||||
index = 15
|
||||
points_mm = [
|
||||
[ 59.8, 127.8412, 125.509 ],
|
||||
[ 58.7638, 121.5646, 133.1409 ],
|
||||
[ 56.5137, 115.2888, 140.2458 ],
|
||||
[ 53.2231, 108.9797, 146.83 ],
|
||||
[ 49.0655, 102.6033, 152.8998 ],
|
||||
[ 44.2144, 96.1253, 158.4616 ],
|
||||
[ 38.8431, 89.5118, 163.5217 ],
|
||||
[ 33.1251, 82.7287, 168.0866 ],
|
||||
[ 27.2338, 75.7417, 172.1625 ],
|
||||
[ 21.3427, 68.517, 175.7558 ],
|
||||
[ 15.6253, 61.0203, 178.8729 ],
|
||||
[ 10.2549, 53.2175, 181.5202 ],
|
||||
[ 5.405, 45.0747, 183.7039 ],
|
||||
[ 1.2491, 36.5576, 185.4305 ],
|
||||
[ -2.0394, 27.6322, 186.7062 ],
|
||||
[ -4.2872, 18.2645, 187.5375 ],
|
||||
[ -5.3206, 8.4202, 187.9307 ]
|
||||
]
|
||||
|
||||
# primaries 8
|
||||
[[geometry.pipes]]
|
||||
index = 16
|
||||
points_mm = [
|
||||
[ 179.4, 127.8412, 125.509 ],
|
||||
[ 178.3638, 121.5646, 133.1409 ],
|
||||
[ 176.1137, 115.2887, 140.2457 ],
|
||||
[ 172.8231, 108.9796, 146.8299 ],
|
||||
[ 168.6655, 102.6031, 152.8997 ],
|
||||
[ 163.8144, 96.1252, 158.4614 ],
|
||||
[ 158.4431, 89.5117, 163.5216 ],
|
||||
[ 152.7251, 82.7285, 168.0865 ],
|
||||
[ 146.8338, 75.7416, 172.1624 ],
|
||||
[ 140.9428, 68.5169, 175.7558 ],
|
||||
[ 135.2253, 61.0202, 178.8729 ],
|
||||
[ 129.8549, 53.2175, 181.5201 ],
|
||||
[ 125.005, 45.0747, 183.7039 ],
|
||||
[ 120.8491, 36.5576, 185.4304 ],
|
||||
[ 117.5606, 27.6322, 186.7062 ],
|
||||
[ 115.3128, 18.2645, 187.5375 ],
|
||||
[ 114.2794, 8.4202, 187.9307 ]
|
||||
]
|
||||
|
||||
# secondaries 1
|
||||
[[geometry.pipes]]
|
||||
index = 17
|
||||
points_mm = [
|
||||
[ -51.1798, -12.1882, -195.8922 ],
|
||||
[ -28.2717, -12.6445, -195.8922 ],
|
||||
[ -5.9777, -13.9338, -195.8922 ],
|
||||
[ 15.7896, -15.9372, -195.8922 ],
|
||||
[ 37.1182, -18.5357, -195.8922 ],
|
||||
[ 58.0958, -21.6102, -195.8922 ],
|
||||
[ 78.8101, -25.0418, -195.8922 ],
|
||||
[ 99.3489, -28.7114, -195.8922 ],
|
||||
[ 119.8, -32.5, -195.8922 ],
|
||||
[ 140.251, -36.2886, -195.8922 ],
|
||||
[ 160.7898, -39.9582, -195.8922 ],
|
||||
[ 181.5042, -43.3898, -195.8922 ],
|
||||
[ 202.4818, -46.4643, -195.8922 ],
|
||||
[ 223.8104, -49.0628, -195.8922 ],
|
||||
[ 245.5777, -51.0662, -195.8922 ],
|
||||
[ 267.8716, -52.3555, -195.8922 ],
|
||||
[ 290.7798, -52.8118, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 2
|
||||
[[geometry.pipes]]
|
||||
index = 18
|
||||
points_mm = [
|
||||
[ 188.0202, -15.9377, -195.8922 ],
|
||||
[ 195.1524, -16.3097, -195.8922 ],
|
||||
[ 202.0008, -17.361, -195.8922 ],
|
||||
[ 208.6058, -18.9946, -195.8922 ],
|
||||
[ 215.008, -21.1134, -195.8922 ],
|
||||
[ 221.2479, -23.6204, -195.8922 ],
|
||||
[ 227.3662, -26.4185, -195.8922 ],
|
||||
[ 233.4034, -29.4107, -195.8922 ],
|
||||
[ 239.4, -32.5, -195.8922 ],
|
||||
[ 245.3966, -35.5892, -195.8922 ],
|
||||
[ 251.4338, -38.5815, -195.8922 ],
|
||||
[ 257.552, -41.3796, -195.8922 ],
|
||||
[ 263.792, -43.8866, -195.8922 ],
|
||||
[ 270.1942, -46.0054, -195.8922 ],
|
||||
[ 276.7992, -47.6389, -195.8922 ],
|
||||
[ 283.6476, -48.6903, -195.8922 ],
|
||||
[ 290.7798, -49.0623, -195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 3
|
||||
[[geometry.pipes]]
|
||||
index = 19
|
||||
points_mm = [
|
||||
[ 8.6202, -12.5985, 195.8922 ],
|
||||
[ 27.5671, -13.0455, 195.8922 ],
|
||||
[ 45.9893, -14.3087, 195.8922 ],
|
||||
[ 63.9616, -16.2717, 195.8922 ],
|
||||
[ 81.5591, -18.8177, 195.8922 ],
|
||||
[ 98.8567, -21.8301, 195.8922 ],
|
||||
[ 115.9294, -25.1924, 195.8922 ],
|
||||
[ 132.8522, -28.7879, 195.8922 ],
|
||||
[ 149.7, -32.5, 195.8922 ],
|
||||
[ 166.5478, -36.2121, 195.8922 ],
|
||||
[ 183.4705, -39.8076, 195.8922 ],
|
||||
[ 200.5433, -43.1699, 195.8922 ],
|
||||
[ 217.8409, -46.1823, 195.8922 ],
|
||||
[ 235.4383, -48.7283, 195.8922 ],
|
||||
[ 253.4107, -50.6913, 195.8922 ],
|
||||
[ 271.8329, -51.9545, 195.8922 ],
|
||||
[ 290.7798, -52.4015, 195.8922 ]
|
||||
]
|
||||
|
||||
# secondaries 4
|
||||
[[geometry.pipes]]
|
||||
index = 20
|
||||
points_mm = [
|
||||
[ 128.2202, -14.157, 195.8922 ],
|
||||
[ 139.2733, -14.569, 195.8922 ],
|
||||
[ 149.9691, -15.7334, 195.8922 ],
|
||||
[ 160.3587, -17.5426, 195.8922 ],
|
||||
[ 170.4932, -19.8892, 195.8922 ],
|
||||
[ 180.4235, -22.6657, 195.8922 ],
|
||||
[ 190.2007, -25.7647, 195.8922 ],
|
||||
[ 199.8759, -29.0786, 195.8922 ],
|
||||
[ 209.5, -32.5, 195.8922 ],
|
||||
[ 219.1241, -35.9214, 195.8922 ],
|
||||
[ 228.7993, -39.2353, 195.8922 ],
|
||||
[ 238.5765, -42.3343, 195.8922 ],
|
||||
[ 248.5068, -45.1108, 195.8922 ],
|
||||
[ 258.6412, -47.4574, 195.8922 ],
|
||||
[ 269.0309, -49.2666, 195.8922 ],
|
||||
[ 279.7267, -50.431, 195.8922 ],
|
||||
[ 290.7798, -50.843, 195.8922 ]
|
||||
]
|
||||
|
||||
# bank_collectors 1
|
||||
[[geometry.pipes]]
|
||||
index = 21
|
||||
points_mm = [
|
||||
[ 327.6201, -55, -203.0101 ],
|
||||
[ 363.845, -55, -205.237 ],
|
||||
[ 398.4088, -55, -211.5304 ],
|
||||
[ 431.549, -55, -221.3095 ],
|
||||
[ 463.5029, -55, -233.9932 ],
|
||||
[ 494.5076, -55, -249.0007 ],
|
||||
[ 524.8005, -55, -265.751 ],
|
||||
[ 554.6189, -55, -283.6631 ],
|
||||
[ 584.2, -55, -302.1562 ],
|
||||
[ 613.781, -55, -320.6493 ],
|
||||
[ 643.5994, -55, -338.5614 ],
|
||||
[ 673.8922, -55, -355.3117 ],
|
||||
[ 704.897, -55, -370.3192 ],
|
||||
[ 736.8508, -55, -383.0029 ],
|
||||
[ 769.9911, -55, -392.782 ],
|
||||
[ 804.5549, -55, -399.0755 ],
|
||||
[ 840.7797, -55, -401.3024 ]
|
||||
]
|
||||
|
||||
# bank_collectors 2
|
||||
[[geometry.pipes]]
|
||||
index = 22
|
||||
points_mm = [
|
||||
[ 327.6201, -55, 203.0101 ],
|
||||
[ 363.845, -55, 205.237 ],
|
||||
[ 398.4088, -55, 211.5304 ],
|
||||
[ 431.549, -55, 221.3095 ],
|
||||
[ 463.5029, -55, 233.9932 ],
|
||||
[ 494.5076, -55, 249.0007 ],
|
||||
[ 524.8005, -55, 265.751 ],
|
||||
[ 554.6189, -55, 283.6631 ],
|
||||
[ 584.2, -55, 302.1562 ],
|
||||
[ 613.781, -55, 320.6493 ],
|
||||
[ 643.5994, -55, 338.5614 ],
|
||||
[ 673.8922, -55, 355.3117 ],
|
||||
[ 704.897, -55, 370.3192 ],
|
||||
[ 736.8508, -55, 383.0029 ],
|
||||
[ 769.9911, -55, 392.782 ],
|
||||
[ 804.5549, -55, 399.0755 ],
|
||||
[ 840.7797, -55, 401.3024 ]
|
||||
]
|
||||
|
||||
# tailpipes 1
|
||||
[[geometry.pipes]]
|
||||
index = 23
|
||||
points_mm = [
|
||||
[ 877.62, -55, -408.4202 ],
|
||||
[ 2127.62, -55, -408.4202 ]
|
||||
]
|
||||
|
||||
# tailpipes 2
|
||||
[[geometry.pipes]]
|
||||
index = 24
|
||||
points_mm = [
|
||||
[ 877.62, -55, 408.4202 ],
|
||||
[ 2127.62, -55, 408.4202 ]
|
||||
]
|
||||
|
||||
# crossover
|
||||
[[geometry.pipes]]
|
||||
index = 25
|
||||
points_mm = [
|
||||
[ 859.1999, -55, -390 ],
|
||||
[ 859.1999, -55, 390 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ 0, 312.6411, 0 ]
|
||||
size_mm = [ 478.4, 43.7429, 191.1445 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_0"
|
||||
center_mm = [ -69.6, -10, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_1"
|
||||
center_mm = [ 169.6, -10, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_2"
|
||||
center_mm = [ -9.8, -10, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_3"
|
||||
center_mm = [ 109.8, -10, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_4"
|
||||
center_mm = [ 309.2, -55, -195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_5"
|
||||
center_mm = [ 309.2, -55, 195.8922 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_6"
|
||||
center_mm = [ 859.1999, -55, -408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "junction_7"
|
||||
center_mm = [ 859.1999, -55, 408.4202 ]
|
||||
size_mm = [ 36.8403, 36.8403, 36.8403 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "yz-fat"
|
||||
name = "125 / wide belly chamber"
|
||||
category = "Two-stroke / 125 cc"
|
||||
@@ -7,16 +7,19 @@ description = "Estimated chamber geometry / same 125 cc engine"
|
||||
order = 14
|
||||
cycle = "two_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 100.0
|
||||
|
||||
[two_stroke]
|
||||
reed_pipe_diameter_mm = 40
|
||||
transfer_pipe_diameter_mm = 32
|
||||
initial_rpm = 3000.0
|
||||
starter_torque_nm = 8.0
|
||||
maximum_load_torque_nm = 10.0
|
||||
crankshaft_inertia_kg_m2 = 0.01
|
||||
bore_mm = 54.0
|
||||
carburetor_diameter_mm = 38.1
|
||||
crankcase_clearance_cc = 150.0
|
||||
exhaust = "racing"
|
||||
exhaust_cell_length_mm = 10.0
|
||||
exhaust_duration_deg = 190.0
|
||||
exhaust_width_mm = 36.0
|
||||
friction_bar = 0.4
|
||||
@@ -66,3 +69,69 @@ final_drive_ratio = 3.769231
|
||||
mass_kg = 170
|
||||
wheel_radius_mm = 331.3
|
||||
gear_ratios = [2.384615, 1.933333, 1.588235, 1.352941, 1.176471, 1.055556]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -235.9365, 16.1836, 0 ],
|
||||
[ -135.9365, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# reed passage
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -56.5664, 16.1836, 0 ],
|
||||
[ -26.5664, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# transfer passage
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 26.5664, 42.75, 0 ],
|
||||
[ 30.8157, 45.5218, 0 ],
|
||||
[ 34.5021, 48.2991, 0 ],
|
||||
[ 37.6254, 51.0817, 0 ],
|
||||
[ 40.1858, 53.8698, 0 ],
|
||||
[ 42.1833, 56.6633, 0 ],
|
||||
[ 43.6178, 59.4623, 0 ],
|
||||
[ 44.4893, 62.2667, 0 ],
|
||||
[ 44.7979, 65.0764, 0 ],
|
||||
[ 44.5435, 67.8916, 0 ],
|
||||
[ 43.7262, 70.7123, 0 ],
|
||||
[ 42.3459, 73.5383, 0 ],
|
||||
[ 40.4026, 76.3698, 0 ],
|
||||
[ 37.8964, 79.2067, 0 ],
|
||||
[ 34.8272, 82.0491, 0 ],
|
||||
[ 31.1951, 84.8968, 0 ],
|
||||
[ 27, 87.75, 0 ]
|
||||
]
|
||||
|
||||
# exhaust chamber
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 27, 112.25, 0 ],
|
||||
[ 177.3508, 57.5268, 0 ],
|
||||
[ 253.4221, -105.6086, 0 ],
|
||||
[ 144.4426, -261.2475, 0 ],
|
||||
[ 14.4426, -261.2475, 0 ],
|
||||
[ -182.8929, -189.4233, 0 ],
|
||||
[ -422.8929, -189.4233, 0 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ -96.2515, 16.1836, 0 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "crankcase"
|
||||
center_mm = [ 0, 16.1836, 0 ]
|
||||
size_mm = [ 53.1329, 53.1329, 53.1329 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "yz-racing"
|
||||
name = "YZ125 / expansion chamber"
|
||||
category = "Two-stroke / 125 cc"
|
||||
@@ -7,16 +7,19 @@ description = "Racing pipe / calibrated carb / 3% idle stop"
|
||||
order = 1
|
||||
cycle = "two_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 100.0
|
||||
|
||||
[two_stroke]
|
||||
reed_pipe_diameter_mm = 40
|
||||
transfer_pipe_diameter_mm = 32
|
||||
initial_rpm = 3000.0
|
||||
starter_torque_nm = 8.0
|
||||
maximum_load_torque_nm = 10.0
|
||||
crankshaft_inertia_kg_m2 = 0.01
|
||||
bore_mm = 54.0
|
||||
carburetor_diameter_mm = 38.1
|
||||
crankcase_clearance_cc = 150.0
|
||||
exhaust = "racing"
|
||||
exhaust_cell_length_mm = 10.0
|
||||
exhaust_duration_deg = 190.0
|
||||
exhaust_width_mm = 36.0
|
||||
friction_bar = 0.4
|
||||
@@ -66,3 +69,69 @@ final_drive_ratio = 3.769231
|
||||
mass_kg = 170
|
||||
wheel_radius_mm = 331.3
|
||||
gear_ratios = [2.384615, 1.933333, 1.588235, 1.352941, 1.176471, 1.055556]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -235.9365, 16.1836, 0 ],
|
||||
[ -135.9365, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# reed passage
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -56.5664, 16.1836, 0 ],
|
||||
[ -26.5664, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# transfer passage
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 26.5664, 42.75, 0 ],
|
||||
[ 30.8157, 45.5218, 0 ],
|
||||
[ 34.5021, 48.2991, 0 ],
|
||||
[ 37.6254, 51.0817, 0 ],
|
||||
[ 40.1858, 53.8698, 0 ],
|
||||
[ 42.1833, 56.6633, 0 ],
|
||||
[ 43.6178, 59.4623, 0 ],
|
||||
[ 44.4893, 62.2667, 0 ],
|
||||
[ 44.7979, 65.0764, 0 ],
|
||||
[ 44.5435, 67.8916, 0 ],
|
||||
[ 43.7262, 70.7123, 0 ],
|
||||
[ 42.3459, 73.5383, 0 ],
|
||||
[ 40.4026, 76.3698, 0 ],
|
||||
[ 37.8964, 79.2067, 0 ],
|
||||
[ 34.8272, 82.0491, 0 ],
|
||||
[ 31.1951, 84.8968, 0 ],
|
||||
[ 27, 87.75, 0 ]
|
||||
]
|
||||
|
||||
# exhaust chamber
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 27, 112.25, 0 ],
|
||||
[ 177.3508, 57.5268, 0 ],
|
||||
[ 253.4221, -105.6086, 0 ],
|
||||
[ 144.4426, -261.2475, 0 ],
|
||||
[ 14.4426, -261.2475, 0 ],
|
||||
[ -182.8929, -189.4233, 0 ],
|
||||
[ -422.8929, -189.4233, 0 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ -96.2515, 16.1836, 0 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "crankcase"
|
||||
center_mm = [ 0, 16.1836, 0 ]
|
||||
size_mm = [ 53.1329, 53.1329, 53.1329 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "yz-short"
|
||||
name = "125 / short high-RPM chamber"
|
||||
category = "Two-stroke / 125 cc"
|
||||
@@ -7,16 +7,19 @@ description = "Estimated chamber geometry / same 125 cc engine"
|
||||
order = 13
|
||||
cycle = "two_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 100.0
|
||||
|
||||
[two_stroke]
|
||||
reed_pipe_diameter_mm = 40
|
||||
transfer_pipe_diameter_mm = 32
|
||||
initial_rpm = 3000.0
|
||||
starter_torque_nm = 8.0
|
||||
maximum_load_torque_nm = 10.0
|
||||
crankshaft_inertia_kg_m2 = 0.01
|
||||
bore_mm = 54.0
|
||||
carburetor_diameter_mm = 38.1
|
||||
crankcase_clearance_cc = 150.0
|
||||
exhaust = "racing"
|
||||
exhaust_cell_length_mm = 10.0
|
||||
exhaust_duration_deg = 190.0
|
||||
exhaust_width_mm = 36.0
|
||||
friction_bar = 0.4
|
||||
@@ -66,3 +69,69 @@ final_drive_ratio = 3.769231
|
||||
mass_kg = 170
|
||||
wheel_radius_mm = 331.3
|
||||
gear_ratios = [2.384615, 1.933333, 1.588235, 1.352941, 1.176471, 1.055556]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -235.9365, 16.1836, 0 ],
|
||||
[ -135.9365, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# reed passage
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -56.5664, 16.1836, 0 ],
|
||||
[ -26.5664, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# transfer passage
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 26.5664, 42.75, 0 ],
|
||||
[ 30.8157, 45.5218, 0 ],
|
||||
[ 34.5021, 48.2991, 0 ],
|
||||
[ 37.6254, 51.0817, 0 ],
|
||||
[ 40.1858, 53.8698, 0 ],
|
||||
[ 42.1833, 56.6633, 0 ],
|
||||
[ 43.6178, 59.4623, 0 ],
|
||||
[ 44.4893, 62.2667, 0 ],
|
||||
[ 44.7979, 65.0764, 0 ],
|
||||
[ 44.5435, 67.8916, 0 ],
|
||||
[ 43.7262, 70.7123, 0 ],
|
||||
[ 42.3459, 73.5383, 0 ],
|
||||
[ 40.4026, 76.3698, 0 ],
|
||||
[ 37.8964, 79.2067, 0 ],
|
||||
[ 34.8272, 82.0491, 0 ],
|
||||
[ 31.1951, 84.8968, 0 ],
|
||||
[ 27, 87.75, 0 ]
|
||||
]
|
||||
|
||||
# exhaust chamber
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 27, 112.25, 0 ],
|
||||
[ 150.2877, 67.377, 0 ],
|
||||
[ 212.6661, -66.3941, 0 ],
|
||||
[ 123.3029, -194.018, 0 ],
|
||||
[ 16.7029, -194.018, 0 ],
|
||||
[ -145.1122, -135.1221, 0 ],
|
||||
[ -341.9122, -135.1221, 0 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ -96.2515, 16.1836, 0 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "crankcase"
|
||||
center_mm = [ 0, 16.1836, 0 ]
|
||||
size_mm = [ 53.1329, 53.1329, 53.1329 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "yz-straight"
|
||||
name = "YZ125 / straight exhaust"
|
||||
category = "Two-stroke / 125 cc"
|
||||
@@ -7,16 +7,19 @@ description = "Straight exhaust / calibrated pilot and needle / 3% idle stop"
|
||||
order = 2
|
||||
cycle = "two_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 100.0
|
||||
|
||||
[two_stroke]
|
||||
reed_pipe_diameter_mm = 40
|
||||
transfer_pipe_diameter_mm = 32
|
||||
initial_rpm = 3000.0
|
||||
starter_torque_nm = 8.0
|
||||
maximum_load_torque_nm = 10.0
|
||||
crankshaft_inertia_kg_m2 = 0.01
|
||||
bore_mm = 54.0
|
||||
carburetor_diameter_mm = 38.1
|
||||
crankcase_clearance_cc = 150.0
|
||||
exhaust = "straight"
|
||||
exhaust_cell_length_mm = 10.0
|
||||
exhaust_duration_deg = 190.0
|
||||
exhaust_width_mm = 36.0
|
||||
friction_bar = 0.4
|
||||
@@ -66,3 +69,64 @@ final_drive_ratio = 3.769231
|
||||
mass_kg = 170
|
||||
wheel_radius_mm = 331.3
|
||||
gear_ratios = [2.384615, 1.933333, 1.588235, 1.352941, 1.176471, 1.055556]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -235.9365, 16.1836, 0 ],
|
||||
[ -135.9365, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# reed passage
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -56.5664, 16.1836, 0 ],
|
||||
[ -26.5664, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# transfer passage
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 26.5664, 42.75, 0 ],
|
||||
[ 30.8157, 45.5218, 0 ],
|
||||
[ 34.5021, 48.2991, 0 ],
|
||||
[ 37.6254, 51.0817, 0 ],
|
||||
[ 40.1858, 53.8698, 0 ],
|
||||
[ 42.1833, 56.6633, 0 ],
|
||||
[ 43.6178, 59.4623, 0 ],
|
||||
[ 44.4893, 62.2667, 0 ],
|
||||
[ 44.7979, 65.0764, 0 ],
|
||||
[ 44.5435, 67.8916, 0 ],
|
||||
[ 43.7262, 70.7123, 0 ],
|
||||
[ 42.3459, 73.5383, 0 ],
|
||||
[ 40.4026, 76.3698, 0 ],
|
||||
[ 37.8964, 79.2067, 0 ],
|
||||
[ 34.8272, 82.0491, 0 ],
|
||||
[ 31.1951, 84.8968, 0 ],
|
||||
[ 27, 87.75, 0 ]
|
||||
]
|
||||
|
||||
# exhaust chamber
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 27, 112.25, 0 ],
|
||||
[ 1137, 112.25, 0 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ -96.2515, 16.1836, 0 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "crankcase"
|
||||
center_mm = [ 0, 16.1836, 0 ]
|
||||
size_mm = [ 53.1329, 53.1329, 53.1329 ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Engine definition. Dimensional keys state their units.
|
||||
schema_version = 1
|
||||
schema_version = 2
|
||||
id = "yz-torque"
|
||||
name = "125 / long torque chamber"
|
||||
category = "Two-stroke / 125 cc"
|
||||
@@ -7,16 +7,19 @@ description = "Estimated chamber geometry / same 125 cc engine"
|
||||
order = 12
|
||||
cycle = "two_stroke"
|
||||
|
||||
[simulation]
|
||||
cells_per_meter = 100.0
|
||||
|
||||
[two_stroke]
|
||||
reed_pipe_diameter_mm = 40
|
||||
transfer_pipe_diameter_mm = 32
|
||||
initial_rpm = 3000.0
|
||||
starter_torque_nm = 8.0
|
||||
maximum_load_torque_nm = 10.0
|
||||
crankshaft_inertia_kg_m2 = 0.01
|
||||
bore_mm = 54.0
|
||||
carburetor_diameter_mm = 38.1
|
||||
crankcase_clearance_cc = 150.0
|
||||
exhaust = "racing"
|
||||
exhaust_cell_length_mm = 10.0
|
||||
exhaust_duration_deg = 190.0
|
||||
exhaust_width_mm = 36.0
|
||||
friction_bar = 0.4
|
||||
@@ -66,3 +69,69 @@ final_drive_ratio = 3.769231
|
||||
mass_kg = 170
|
||||
wheel_radius_mm = 331.3
|
||||
gear_ratios = [2.384615, 1.933333, 1.588235, 1.352941, 1.176471, 1.055556]
|
||||
|
||||
[[geometry.cylinders]]
|
||||
origin_mm = [ 0, 0, 0 ]
|
||||
tilt_deg = 0.0
|
||||
|
||||
# intake
|
||||
[[geometry.pipes]]
|
||||
index = 0
|
||||
points_mm = [
|
||||
[ -235.9365, 16.1836, 0 ],
|
||||
[ -135.9365, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# reed passage
|
||||
[[geometry.pipes]]
|
||||
index = 1
|
||||
points_mm = [
|
||||
[ -56.5664, 16.1836, 0 ],
|
||||
[ -26.5664, 16.1836, 0 ]
|
||||
]
|
||||
|
||||
# transfer passage
|
||||
[[geometry.pipes]]
|
||||
index = 2
|
||||
points_mm = [
|
||||
[ 26.5664, 42.75, 0 ],
|
||||
[ 30.8157, 45.5218, 0 ],
|
||||
[ 34.5021, 48.2991, 0 ],
|
||||
[ 37.6254, 51.0817, 0 ],
|
||||
[ 40.1858, 53.8698, 0 ],
|
||||
[ 42.1833, 56.6633, 0 ],
|
||||
[ 43.6178, 59.4623, 0 ],
|
||||
[ 44.4893, 62.2667, 0 ],
|
||||
[ 44.7979, 65.0764, 0 ],
|
||||
[ 44.5435, 67.8916, 0 ],
|
||||
[ 43.7262, 70.7123, 0 ],
|
||||
[ 42.3459, 73.5383, 0 ],
|
||||
[ 40.4026, 76.3698, 0 ],
|
||||
[ 37.8964, 79.2067, 0 ],
|
||||
[ 34.8272, 82.0491, 0 ],
|
||||
[ 31.1951, 84.8968, 0 ],
|
||||
[ 27, 87.75, 0 ]
|
||||
]
|
||||
|
||||
# exhaust chamber
|
||||
[[geometry.pipes]]
|
||||
index = 3
|
||||
points_mm = [
|
||||
[ 27, 112.25, 0 ],
|
||||
[ 204.414, 47.6766, 0 ],
|
||||
[ 294.1781, -144.8232, 0 ],
|
||||
[ 165.5822, -328.4771, 0 ],
|
||||
[ 12.1822, -328.4771, 0 ],
|
||||
[ -220.6736, -243.7245, 0 ],
|
||||
[ -503.8736, -243.7245, 0 ]
|
||||
]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "intake_plenum"
|
||||
center_mm = [ -96.2515, 16.1836, 0 ]
|
||||
size_mm = [ 79.3701, 79.3701, 79.3701 ]
|
||||
|
||||
[[geometry.volumes]]
|
||||
id = "crankcase"
|
||||
center_mm = [ 0, 16.1836, 0 ]
|
||||
size_mm = [ 53.1329, 53.1329, 53.1329 ]
|
||||
|
||||
273
improvements.md
Normal file
273
improvements.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# Sound realism improvement plan
|
||||
|
||||
## Goal
|
||||
|
||||
Make engine sound emerge from the simulated engine and its surroundings. The 1D
|
||||
fluid model should provide the coherent pressure and flow behavior; separate
|
||||
acoustic source and propagation models should represent phenomena the 1D model
|
||||
cannot resolve. The real-time path should remain affordable, deterministic when
|
||||
requested, and diagnosable by source.
|
||||
|
||||
## Current sound path and limitations
|
||||
|
||||
The four-stroke and two-stroke scenarios currently pass intake and exhaust
|
||||
open-end volume flow to `OutdoorAudio`. It derives a compact monopole pressure
|
||||
signal from the time derivative of that flow, applies distance and ear delays,
|
||||
simple image-source reflections, and an approximate late reverb. The engine's
|
||||
3D scene supplies source/listener positions, but visible geometry does not yet
|
||||
control detailed acoustic propagation.
|
||||
|
||||
This captures coherent engine pulses, but has no direct model for turbulent
|
||||
noise at valves, throttle plates, sharp area changes, bends, collectors, or pipe
|
||||
exits. A nonzero flow or a large opening alone is not evidence that an audible
|
||||
turbulent source should be active. The 1D pipe state is cross-section averaged;
|
||||
it cannot resolve vortices, transverse velocity, or separated shear layers.
|
||||
The first-order pipe update also adds numerical damping, which can soften pulses
|
||||
before they reach the acoustic renderer.
|
||||
|
||||
## 1. Separate acoustic sources
|
||||
|
||||
Represent and capture each major sound contribution independently before
|
||||
mixing them:
|
||||
|
||||
- **Coherent intake and exhaust pulses:** derive from simulated pressure and
|
||||
volume-flow waves at ports and mouths.
|
||||
- **Intake aerodynamic noise:** generate at the throttle, valves, filter,
|
||||
bends, contractions, and other restrictions when their local operating
|
||||
conditions and geometry support turbulent flow or separation.
|
||||
- **Exhaust aerodynamic noise:** generate at exhaust valves, collectors, abrupt
|
||||
expansions/contractions, and outlets where jets or separated flow are
|
||||
expected.
|
||||
- **Combustion events:** retain cycle timing and add afterfire or misfire
|
||||
sounds only when the combustion/fuel model predicts those events.
|
||||
- **Mechanical sources:** add valve train, injector, gear, belt, and rotating
|
||||
imbalance sources as their physical models become available.
|
||||
|
||||
Each source should have an independent output/capture channel and enable
|
||||
control. This makes level and spectral calibration possible without masking
|
||||
errors by changing unrelated sources.
|
||||
|
||||
### Flow-noise source model
|
||||
|
||||
Use local flow and feature data to estimate source strength, rather than mapping
|
||||
area or mass flow directly to noise. Useful inputs include:
|
||||
|
||||
- mass or volume flow, density, local velocity, and flow direction;
|
||||
- upstream/downstream pressure and pressure drop;
|
||||
- effective opening area and area ratio;
|
||||
- hydraulic diameter, edge radius/sharpness, bend angle, and expansion ratio;
|
||||
- gas temperature and viscosity, for Reynolds-number estimates;
|
||||
- opening motion and rate of change for valves and throttle plates.
|
||||
|
||||
Use these inputs to estimate whether the feature creates a jet, separation, or
|
||||
vortex shedding, and how strongly it is excited. Reynolds number is a useful
|
||||
regime indicator, not an audible-noise switch. Mean flow alone should not force
|
||||
a noise source to be audible. A smooth, well-matched passage and an abrupt,
|
||||
partly closed restriction should produce different results at comparable flow.
|
||||
|
||||
For an initial real-time model, use a seeded, band-limited stochastic source
|
||||
with a smooth operating-point envelope and a short stateful correlation time.
|
||||
Shape its spectrum and level from local flow power/jet speed, pressure drop,
|
||||
feature geometry, and a calibrated source model. Avoid unfiltered white noise,
|
||||
hard on/off thresholds, and arbitrary random pops. Keep stochastic source
|
||||
generation out of the conserved pipe state in the first implementation; this
|
||||
avoids changing mass, momentum, or energy merely to create audio.
|
||||
|
||||
Treat unsteady separated flow as a modeled source, not a directly measured
|
||||
quantity in the current 1D cells. Proxies such as rapid changes in flow or
|
||||
pressure, reversals, and valve motion may modulate the source, but they do not
|
||||
resolve turbulent fluctuations. For higher-fidelity source data, use transient
|
||||
3D CFD/LES or measurements at selected features and reduce those results to a
|
||||
real-time source model.
|
||||
|
||||
## 2. Improve pipe and component acoustic coupling
|
||||
|
||||
### Diagnose wave loss before changing the model
|
||||
|
||||
Build small repeatable interface cases and record pressure on both sides of an
|
||||
interface:
|
||||
|
||||
1. Send a pressure pulse through an equal-area straight connection.
|
||||
2. Measure reflection and transmission at T/Y junctions.
|
||||
3. Connect a pipe to a known volume and vary the volume and opening geometry.
|
||||
4. Repeat at several cell sizes, CFL/time-step settings, and flux schemes.
|
||||
5. Track incident, reflected, and transmitted wave energy, mass/energy
|
||||
balance, `limited_fluxes`, and positivity repairs.
|
||||
|
||||
If pulse loss decreases with mesh refinement, spatial numerical diffusion is a
|
||||
major contributor. If loss is concentrated at an interface and does not
|
||||
converge with refinement, improve the boundary/junction model. Compare with
|
||||
analytic acoustic impedance/scattering results where applicable and with
|
||||
measured junction data for realistic geometries.
|
||||
|
||||
### Zero-volume pipe junctions
|
||||
|
||||
The current ideal N-way junction uses a zero-storage Rusanov star state. Improve
|
||||
this with a characteristic junction solve that enforces mass and energy
|
||||
conservation while accounting for each branch's area, orientation, flow
|
||||
direction, and pressure-wave impedance. Add calibrated geometry-dependent
|
||||
losses where the junction is not ideal. Validate frequency-dependent reflection
|
||||
and transmission, not just steady flow or conservation.
|
||||
|
||||
### Pipe-to-volume transitions
|
||||
|
||||
The current pipe-to-component connection uses an orifice/nozzle boundary and a
|
||||
shared component pressure/state. Represent the actual entry geometry where it
|
||||
matters: opening area, contraction/expansion, short profiled transitions, and
|
||||
calibrated discharge/loss coefficients. A shared volume pressure is appropriate
|
||||
for a well-mixed compact reservoir, but may be too simple for a collector or
|
||||
plenum with strong spatial pressure differences. Use resolved pipe sections or
|
||||
a richer multi-port model where those differences materially affect pulse
|
||||
transfer.
|
||||
|
||||
### Pipe wave resolution
|
||||
|
||||
Compare the current first-order Rusanov update with higher-order limited
|
||||
finite-volume schemes that preserve shocks without excessive damping. Measure
|
||||
waveform, phase, and spectrum convergence with mesh and timestep refinement.
|
||||
Retain robust positivity handling and conservation checks. Do not select a
|
||||
scheme on shock-tube error alone; validate acoustic pulse propagation and
|
||||
engine-relevant frequencies as well.
|
||||
|
||||
## 3. Add acoustic networks between flow ports and listener
|
||||
|
||||
Separate the simulated fluid flow network from the acoustic radiation network.
|
||||
For each source, represent how its sound travels through connected ducts,
|
||||
plenums, filters, resonators, and mufflers before it radiates. Options include:
|
||||
|
||||
- **Transfer matrices / frequency-domain network models:** efficient for
|
||||
linear acoustic behavior and useful for calibrating duct and chamber
|
||||
resonances.
|
||||
- **Digital waveguides / delay-line networks:** suitable for real-time,
|
||||
time-domain wave travel, reflections, and frequency-dependent losses.
|
||||
- **Reduced-order component models:** compact state-space filters derived from
|
||||
measured or higher-detail simulations for complex elements.
|
||||
|
||||
Model acoustic reflection, transmission, resonance, and attenuation at
|
||||
junctions and openings. Include frequency-dependent losses from wall friction,
|
||||
viscothermal effects, and porous/absorptive parts where data supports them.
|
||||
Use separate paths for intake and exhaust so changes to one system do not
|
||||
unintentionally alter the other.
|
||||
|
||||
## 4. Use the 3D environment for propagation and radiation
|
||||
|
||||
The engine's 3D placement can improve more than stereo panning, provided the
|
||||
scene contains usable acoustic geometry and materials. Give each source a
|
||||
position, orientation, size, and frequency-dependent directivity. Relevant
|
||||
sources include intake mouth, individual or grouped exhaust outlets, engine
|
||||
surfaces, valve train, and drivetrain.
|
||||
|
||||
Use scene geometry for:
|
||||
|
||||
- **Directivity:** tailpipe and intake radiation vary with direction and
|
||||
frequency; source orientation should affect the listener signal.
|
||||
- **Occlusion and diffraction:** engine parts, chassis, bodywork, and nearby
|
||||
obstacles can block or bend sound. A simple visibility test is useful only
|
||||
for the frequencies where geometric acoustics applies.
|
||||
- **Early reflections:** compute paths from actual ground, walls, vehicle body,
|
||||
and nearby surfaces, with material-dependent reflection and absorption.
|
||||
- **Late reverberation:** derive or tune the diffuse tail from the environment
|
||||
rather than relying only on fixed scene presets.
|
||||
- **Listener motion:** update source/listener distance, direction, delay, and
|
||||
Doppler shift consistently; smooth changes without breaking phase/history.
|
||||
|
||||
Use a **hybrid propagation model**. Ray tracing is relatively efficient for
|
||||
high-frequency reflections and occlusion. Low frequencies require wave or modal
|
||||
methods because they diffract and form strong cavity/vehicle resonances. A
|
||||
boundary-element, finite-element, or finite-difference time-domain (FDTD) solve
|
||||
can be run offline for representative geometry, then reduced to filters or
|
||||
modal data for real-time playback. The visible engine mesh alone is not enough:
|
||||
acoustic propagation also needs appropriate geometry detail and surface
|
||||
impedance/absorption data.
|
||||
|
||||
## 5. Calibration and validation
|
||||
|
||||
Record real intake and exhaust audio at fixed engine speed, load, throttle, and
|
||||
microphone position. Keep recordings unnormalized and disable automatic gain
|
||||
for comparisons. Add transient throttle sweeps and lift-off cases after the
|
||||
steady points.
|
||||
|
||||
Compare:
|
||||
|
||||
- engine-order peak frequencies, amplitudes, and phase/timing;
|
||||
- broadband noise level and spectral shape;
|
||||
- intake/exhaust level balance;
|
||||
- transient envelope and throttle response;
|
||||
- changes with listener position and direction;
|
||||
- reflection/decay behavior in each environment.
|
||||
|
||||
Use separate source captures and bypassable acoustic stages to identify where
|
||||
an error enters. Calibrate source strength first, then duct/network filtering,
|
||||
then 3D radiation and environment. Avoid compensating for a weak physical
|
||||
source by boosting reverb or global gain.
|
||||
|
||||
## Implementation status and scope
|
||||
|
||||
- Every scenario TOML now supplies `[simulation] cells_per_meter`. The desktop
|
||||
exposes a per-scenario resolution stepper with background mesh rebuild and
|
||||
engine restart, retaining each selection during the app session. The desktop
|
||||
calibration/geometry editor has been removed. Uniform and profiled pipe
|
||||
resolution is controlled by the shared density, preserving geometry/volume.
|
||||
|
||||
- Source-separated captures are implemented for intake, both exhaust emitters,
|
||||
and valve contact, with a separate shared diffuse-tail capture, per-source
|
||||
metrics, and capture-tool solo controls. Desktop UI controls remain future work.
|
||||
- Rusanov, HLLE, and HLLC are already selectable for comparison. The V8 uses
|
||||
finite-volume port-coupled fittings; zero-storage junctions remain a comparison path.
|
||||
- 3D CFD/LES work is out of scope. Use the 1D model, reduced acoustic source
|
||||
models, and measurements for this improvement effort.
|
||||
- Pulse benchmarks are implemented: 408 straight/split, zero-storage junction,
|
||||
and finite-volume fitting cases across meshes, timesteps, and flux solvers.
|
||||
See `docs/ACOUSTIC_BENCHMARK.md` for methodology, limitations, and findings.
|
||||
- Findings: straight-pipe numerical attenuation converges with refinement;
|
||||
zero-storage junction scattering has additional mesh-independent error;
|
||||
small finite-volume fittings can require tighter component timesteps.
|
||||
- A production-selectable `muscl` pipe solver now compares limited second-order
|
||||
MUSCL-Hancock/HLLC against the original solvers via F3 or `--solver muscl`.
|
||||
Automatic desktop gain defaults off. Pulse attenuation improves, with original
|
||||
conservation/robustness checks retained. The sweep now covers 408 cases.
|
||||
- A nonlinear characteristic zero-storage exhaust junction is available with
|
||||
`--junctions characteristic`, alongside volume and legacy comparison modes.
|
||||
It supports unequal areas, branch orientation, automatic flow reversal,
|
||||
enthalpy/species mixing, and configurable direction-dependent turning losses.
|
||||
Equal/unequal-area acoustic scattering and 500/1000 Hz phase/gain checks are
|
||||
included; see `docs/JUNCTION_SOLVER.md` for scope and limitations.
|
||||
- Next: listen at fixed operating points, check spectra and performance across
|
||||
engine families, and investigate component coupling timestep stability before
|
||||
changing acoustic source strength. The new mode remains opt-in for evaluation.
|
||||
|
||||
## Suggested implementation order
|
||||
|
||||
1. Add source-separated captures and per-source diagnostics.
|
||||
2. Build pulse reflection/transmission tests for straight connections,
|
||||
junctions, and pipe-volume boundaries.
|
||||
3. Determine whether junction loss or first-order pipe diffusion dominates;
|
||||
improve the responsible model and validate convergence.
|
||||
4. Add a flow/geometry-driven intake restriction-noise source with deterministic
|
||||
seeded, band-limited output and a separate capture channel.
|
||||
5. Add corresponding exhaust valve/collector/outlet sources; model afterfire
|
||||
only when supported by combustion state.
|
||||
6. Add an acoustic network (waveguide or reduced-order transfer model) for
|
||||
intake and exhaust ducts and volumes.
|
||||
7. Use 3D geometry for source directivity, occlusion, early reflections, and
|
||||
listener motion; add offline wave-based/acoustic calculations for important
|
||||
low-frequency resonances as needed.
|
||||
8. Calibrate against controlled microphone recordings and retain objective
|
||||
regression measurements alongside listening tests.
|
||||
|
||||
## References and further reading
|
||||
|
||||
- Li et al., *LES-FEM coupled analysis and experimental research on aerodynamic
|
||||
noise of the vehicle intake system* (2017):
|
||||
https://doi.org/10.1016/j.apacoust.2016.09.009
|
||||
- Ih et al., *Prediction of intake noise of an automotive engine in run-up
|
||||
condition* (2009): https://doi.org/10.1016/j.apacoust.2008.03.007
|
||||
- Morel et al., *Modeling of Engine Exhaust Acoustics* (1999):
|
||||
https://doi.org/10.4271/1999-01-1665
|
||||
- Parrondo et al., *Noise transmission through duct divisions in air circuits*
|
||||
(2006), experimental scattering coefficients for duct junctions:
|
||||
https://www.sciencedirect.com/science/article/abs/pii/S0022460X06002239
|
||||
- Lang and Mindt, *Entropy-Preserving Coupling Conditions for One-dimensional
|
||||
Euler Systems at Junctions* (2017): https://arxiv.org/abs/1704.04035
|
||||
- Hu, Morfey and Sandham, *Sound radiation in turbulent channel flows* (2003):
|
||||
https://doi.org/10.1017/S002211200200277X
|
||||
@@ -24,7 +24,7 @@ private:
|
||||
std::array<std::int16_t, block_size * 2> output_{};
|
||||
std::atomic<std::uint64_t> underrun_blocks_{};
|
||||
std::atomic<double> speed_{1.0};
|
||||
std::atomic<bool> auto_gain_enabled_{true};
|
||||
std::atomic<bool> auto_gain_enabled_{false};
|
||||
float rms_power_{}, peak_envelope_{}, automatic_gain_{1.f};
|
||||
float level_alpha_{}, peak_decay_{}, gain_rise_alpha_{}, gain_fall_alpha_{};
|
||||
float previous_input_left_{}, previous_output_left_{};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace fluidsim::port {
|
||||
|
||||
struct AudioFrame { float left{}, right{}; };
|
||||
struct Vec3 { float x{}, y{}, z{}; };
|
||||
struct Vec3 { float x{}, y{}, z{}; bool operator==(const Vec3&) const = default; };
|
||||
struct AudioListener { Vec3 position{}, right{1,0,0}; };
|
||||
|
||||
// Simple flow-derivative source used by the Helmholtz and pulse scenarios.
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "FluidSim/DynoCurve.hpp"
|
||||
#include "FluidSim/Desktop/PedalControl.hpp"
|
||||
#include "FluidSim/Desktop/EngineRenderer3D.hpp"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <SFML/Graphics.hpp>
|
||||
namespace fluidsim::port::desktop {
|
||||
struct PlaybackInfo {
|
||||
@@ -24,8 +26,17 @@ public:
|
||||
bool handle_event(const sf::Event&,sf::Vector2u);
|
||||
AudioListener listener(const ScenarioSnapshot&,sf::Vector2u);
|
||||
void draw(sf::RenderWindow&,const sf::Font*,const ScenarioSnapshot&,const PlaybackInfo&);
|
||||
void configure_resolution(float density) { resolution_=density; }
|
||||
std::optional<float> take_resolution_request() {auto value=resolution_request_;resolution_request_.reset();return value;}
|
||||
void resolution_started() {resolution_busy_=true;resolution_status_="Building mesh...";}
|
||||
void resolution_finished(float density,const std::string& message) {resolution_=density;resolution_busy_=false;resolution_status_=message;}
|
||||
static std::array<sf::FloatRect,2> resolution_buttons(sf::Vector2u size);
|
||||
private:
|
||||
DynoCurve dyno_;
|
||||
float resolution_{20};
|
||||
bool resolution_busy_{};
|
||||
std::optional<float> resolution_request_;
|
||||
std::string resolution_status_;
|
||||
EngineRenderer3D renderer_;
|
||||
OrbitCamera camera_;
|
||||
bool three_d_{true},camera_fitted_{},pan_drag_{},pedal_drag_{};
|
||||
@@ -34,5 +45,8 @@ private:
|
||||
sf::Vector2i previous_mouse_{};
|
||||
bool dragging_{};
|
||||
float zoom_{1};
|
||||
float camera_aspect_{};
|
||||
WorkspaceLayout workspace_layout(sf::Vector2u size) const;
|
||||
void fit_camera(float aspect,const ScenarioSnapshot&);
|
||||
};
|
||||
}
|
||||
|
||||
47
include/FluidSim/Desktop/EngineEditor.hpp
Normal file
47
include/FluidSim/Desktop/EngineEditor.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include "FluidSim/ScenarioCatalog.hpp"
|
||||
#include "FluidSim/ScenarioSnapshot.hpp"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <optional>
|
||||
|
||||
namespace fluidsim::port::desktop {
|
||||
// Owns an editable design only. Simulation state is exchanged through snapshots
|
||||
// and explicit actions; mouse handlers never touch running components.
|
||||
class EngineEditor {
|
||||
public:
|
||||
void configure(const ScenarioExample& definition);
|
||||
bool handle_event(const sf::Event& event,sf::Vector2u size);
|
||||
void draw(sf::RenderWindow& window,const sf::Font* font,const ScenarioSnapshot& state) const;
|
||||
bool close();
|
||||
bool visible() const { return visible_; }
|
||||
const EngineConfig& draft() const { return draft_; }
|
||||
std::optional<EngineConfig> take_live_update();
|
||||
std::optional<EngineConfig> take_rebuild_request();
|
||||
bool take_save_request();
|
||||
void finish_rebuild(bool success,const std::string& message);
|
||||
void set_status(std::string message) { status_=std::move(message); }
|
||||
static sf::FloatRect bounds(sf::Vector2u size);
|
||||
static sf::FloatRect toggle_bounds(sf::Vector2u size);
|
||||
private:
|
||||
enum class Tab { Valves, Fuel, Pipes };
|
||||
enum class Key { Mass,Spring,Damping,Preload,SoundArea,SoundDamping,Ignition,Idle,Pilot,Main,Needle,Stoich,Power,Length,Diameter };
|
||||
struct Field { Key key;std::string label,unit;float value,minimum,maximum;int precision; };
|
||||
bool supported_{},visible_{},exhaust_{},live_changed_{},rebuild_requested_{},save_requested_{},busy_{};
|
||||
Tab tab_{Tab::Valves};
|
||||
EngineConfig original_,draft_,rebuilding_;
|
||||
std::vector<PipeConfig> applied_pipes_;
|
||||
std::vector<EngineConfig> undo_,redo_;
|
||||
std::size_t pipe_{};
|
||||
int dragging_field_{-1},dragging_point_{-1};
|
||||
std::string status_{"Drag a cam point or slider. W/S controls the throttle."};
|
||||
std::vector<Field> fields() const;
|
||||
void set_field(const Field& field,float value);
|
||||
void begin_edit();
|
||||
void undo();
|
||||
void redo();
|
||||
void reset();
|
||||
void drag(sf::Vector2f position,sf::Vector2u size);
|
||||
sf::FloatRect graph_bounds(sf::Vector2u size) const;
|
||||
sf::FloatRect field_bounds(sf::Vector2u size,std::size_t index) const;
|
||||
};
|
||||
}
|
||||
@@ -7,8 +7,7 @@
|
||||
#include <utility>
|
||||
namespace fluidsim::port::desktop {
|
||||
struct PipeAnchor {float distance;Vec3 position;};
|
||||
// Knots are distances along the simulated pipe, in metres. Display positions
|
||||
// define its schematic route; changing them never changes fluid cell lengths.
|
||||
// Piecewise straight centerline; knot distances are measured from its geometry.
|
||||
class PipePath {
|
||||
public:
|
||||
explicit PipePath(std::vector<PipeAnchor> anchors):anchors_(std::move(anchors)) {
|
||||
@@ -24,10 +23,8 @@ public:
|
||||
auto it=std::upper_bound(anchors_.begin(),anchors_.end(),distance,[](float s,const PipeAnchor& a){return s<a.distance;});
|
||||
std::size_t i=std::clamp<std::size_t>(it-anchors_.begin(),1,anchors_.size()-1)-1;
|
||||
const auto& a=anchors_[i];const auto& b=anchors_[i+1];
|
||||
const float span=b.distance-a.distance,t=(distance-a.distance)/span,t2=t*t,t3=t2*t;
|
||||
const auto ma=tangent_at(i),mb=tangent_at(i+1);
|
||||
auto coordinate=[&](float pa,float pb,float ta,float tb){return (2*t3-3*t2+1)*pa+(t3-2*t2+t)*span*ta+(-2*t3+3*t2)*pb+(t3-t2)*span*tb;};
|
||||
return {coordinate(a.position.x,b.position.x,ma.x,mb.x),coordinate(a.position.y,b.position.y,ma.y,mb.y),coordinate(a.position.z,b.position.z,ma.z,mb.z)};
|
||||
const float t=(distance-a.distance)/(b.distance-a.distance);
|
||||
return {std::lerp(a.position.x,b.position.x,t),std::lerp(a.position.y,b.position.y,t),std::lerp(a.position.z,b.position.z,t)};
|
||||
}
|
||||
Vec3 tangent(float distance) const {
|
||||
const float epsilon=anchors_.back().distance*.0001f;
|
||||
@@ -35,12 +32,21 @@ public:
|
||||
const float x=b.x-a.x,y=b.y-a.y,z=b.z-a.z,n=std::sqrt(x*x+y*y+z*z);
|
||||
return n>1e-8f?Vec3{x/n,y/n,z/n}:Vec3{1,0,0};
|
||||
}
|
||||
private:
|
||||
Vec3 tangent_at(std::size_t i) const {
|
||||
const auto& a=anchors_[i?i-1:0];const auto& b=anchors_[std::min(i+1,anchors_.size()-1)];
|
||||
const float d=b.distance-a.distance;
|
||||
return {(b.position.x-a.position.x)/d,(b.position.y-a.position.y)/d,(b.position.z-a.position.z)/d};
|
||||
Vec3 miter_offset(float distance,Vec3 radial) const {
|
||||
const auto unit=[](Vec3 v){const float n=std::sqrt(v.x*v.x+v.y*v.y+v.z*v.z);return Vec3{v.x/n,v.y/n,v.z/n};};
|
||||
for(std::size_t i=1;i+1<anchors_.size();++i)if(std::abs(distance-anchors_[i].distance)<1e-6f) {
|
||||
const auto a=anchors_[i-1].position,b=anchors_[i].position,c=anchors_[i+1].position;
|
||||
const auto u=unit({b.x-a.x,b.y-a.y,b.z-a.z}),v=unit({c.x-b.x,c.y-b.y,c.z-b.z});
|
||||
const float cosine=std::clamp(u.x*v.x+u.y*v.y+u.z*v.z,-1.f,1.f);
|
||||
if(cosine>.99999f)return radial;
|
||||
const auto bend=unit({u.x-v.x,u.y-v.y,u.z-v.z});
|
||||
const float scale=std::min(3.f,1/std::sqrt(std::max(.0001f,(1+cosine)*.5f)));
|
||||
const float extension=(radial.x*bend.x+radial.y*bend.y+radial.z*bend.z)*(scale-1);
|
||||
return {radial.x+bend.x*extension,radial.y+bend.y*extension,radial.z+bend.z*extension};
|
||||
}
|
||||
return radial;
|
||||
}
|
||||
private:
|
||||
std::vector<PipeAnchor> anchors_;
|
||||
};
|
||||
}
|
||||
|
||||
24
include/FluidSim/Desktop/PlaybackControl.hpp
Normal file
24
include/FluidSim/Desktop/PlaybackControl.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <SFML/Window/Event.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
namespace fluidsim::port::desktop {
|
||||
class PlaybackControl {
|
||||
public:
|
||||
bool realtime() const {return realtime_;}
|
||||
double target_speed() const {return realtime_?1.0:manual_speed_;}
|
||||
bool handle_event(const sf::Event& event,bool shift=false) {
|
||||
if(const auto* key=event.getIf<sf::Event::KeyPressed>()) {
|
||||
if(key->code==sf::Keyboard::Key::Space){realtime_=!realtime_;return true;}
|
||||
if(!realtime_&&key->code==sf::Keyboard::Key::PageUp){adjust(1);return true;}
|
||||
if(!realtime_&&key->code==sf::Keyboard::Key::PageDown){adjust(-1);return true;}
|
||||
}
|
||||
if(const auto* wheel=event.getIf<sf::Event::MouseWheelScrolled>();wheel&&!realtime_&&shift) {adjust(wheel->delta);return true;}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
bool realtime_{true};
|
||||
double manual_speed_{1};
|
||||
void adjust(double steps){manual_speed_=std::clamp(manual_speed_*std::exp(steps*.12),.0001,1.0);}
|
||||
};
|
||||
}
|
||||
@@ -3,10 +3,29 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
namespace fluidsim::port::desktop {
|
||||
// Fixed absolute scale: vacuum blue, atmosphere green, >=1 MPa red.
|
||||
inline Vec3 pressure_tint(float pressure) {
|
||||
// Keep the established absolute vacuum palette. Above atmosphere, use a
|
||||
// narrower positive range so modest pulses stand out from the green baseline.
|
||||
inline Vec3 pressure_tint(float pressure, bool exhaust=false, float temperature=300.f) {
|
||||
if(pressure<=101325) {float t=std::clamp(pressure/101325,0.f,1.f);return {.05f,.15f+.70f*t,1-.95f*t};}
|
||||
float t=std::sqrt(std::clamp((pressure-101325)/(1000000-101325),0.f,1.f));
|
||||
return {.05f+.95f*t,.85f-.80f*t,.05f-.03f*t};
|
||||
const float temperature_boost=std::sqrt(std::clamp(temperature/300.f,.25f,9.f));
|
||||
const float pulse=(pressure-101325.f)*temperature_boost;
|
||||
// Exhaust reaches the warm colors sooner, while using the same continuous
|
||||
// ramp so the atmosphere boundary and pulse edges stay smooth.
|
||||
const float scale=exhaust?45000.f:150000.f;
|
||||
const float t=pulse/(pulse+scale);
|
||||
const auto mix=[](Vec3 a,Vec3 b,float u) {
|
||||
u=u*u*(3.f-2.f*u);
|
||||
return Vec3{a.x+(b.x-a.x)*u,a.y+(b.y-a.y)*u,a.z+(b.z-a.z)*u};
|
||||
};
|
||||
constexpr Vec3 green{.05f,.85f,.05f},yellow{1.f,1.f,.03f},orange{1.f,.52f,.02f},red{1.f,0.f,0.f};
|
||||
if(t<.35f)return mix(green,yellow,t/.35f);
|
||||
if(t<.68f)return mix(yellow,orange,(t-.35f)/.33f);
|
||||
return mix(orange,red,(t-.68f)/.32f);
|
||||
}
|
||||
inline float pressure_expansion(float pressure,float temperature=300.f) {
|
||||
if(pressure<=101325.f)return 0.f;
|
||||
const float temperature_boost=std::sqrt(std::clamp(temperature/300.f,.25f,9.f));
|
||||
const float pulse=(pressure-101325.f)*temperature_boost;
|
||||
return .10f*pulse/(pulse+80000.f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class DesktopScenario {
|
||||
public:
|
||||
explicit DesktopScenario(const ScenarioExample& e)
|
||||
: DesktopScenario(e.kind,e.two,e.exhaust,e.junctions,e.engine,e.title) {}
|
||||
explicit DesktopScenario(ScenarioKind kind, TwoStrokeConfig config = {}, ExhaustConfig exhaust = {}, JunctionConfig junctions = {}, EngineConfig engine = {}, std::string name = {}) : name_(std::move(name)) {
|
||||
explicit DesktopScenario(ScenarioKind kind, TwoStrokeConfig config = {}, ExhaustConfig exhaust = {}, JunctionConfig junctions = {}, EngineConfig engine = {}, std::string name = {}) : name_(std::move(name)),exhaust_(exhaust),junctions_(junctions) {
|
||||
if (kind == ScenarioKind::TwoStroke)
|
||||
two_ = std::make_unique<TwoStrokeScenario>(44100, config);
|
||||
else {
|
||||
@@ -21,33 +21,74 @@ public:
|
||||
}
|
||||
}
|
||||
AudioFrame process() {
|
||||
const std::lock_guard lock(mutex_);
|
||||
if (four_)
|
||||
return four_->process();
|
||||
const std::lock_guard lock(mutex_);
|
||||
return two_->process();
|
||||
}
|
||||
void set_controls(float pedal, float load, float clutch) {
|
||||
visit([&](auto& scenario) { scenario.set_controls(pedal, load, clutch); });
|
||||
visit([&](auto& scenario) { pedal_=pedal;load_=load;clutch_=clutch;scenario.set_controls(pedal, load, clutch); });
|
||||
}
|
||||
void set_starter(bool engaged) { visit([&](auto& scenario) { scenario.set_starter(engaged); }); }
|
||||
void set_starter(bool engaged) { visit([&](auto& scenario) { starter_=engaged;scenario.set_starter(engaged); }); }
|
||||
void shift_up() { visit([](auto& scenario) { scenario.shift_up(); }); }
|
||||
void shift_down() { visit([](auto& scenario) { scenario.shift_down(); }); }
|
||||
void set_neutral() { visit([](auto& scenario) { scenario.set_neutral(); }); }
|
||||
void set_pipe_solver(PipeSolver solver) { visit([&](auto& scenario) { scenario.set_pipe_solver(solver); }); }
|
||||
void set_pipe_solver(PipeSolver solver) { visit([&](auto& scenario) { solver_=solver;scenario.set_pipe_solver(solver); }); }
|
||||
void set_audio_scene(OutdoorScene scene) {
|
||||
visit([&](auto& scenario) { scenario.set_audio_scene(scene); });
|
||||
visit([&](auto& scenario) { scene_=scene;scenario.set_audio_scene(scene); });
|
||||
}
|
||||
void set_listener(AudioListener listener) {
|
||||
visit([&](auto& scenario) { scenario.set_listener(listener); });
|
||||
visit([&](auto& scenario) { listener_=listener;scenario.set_listener(listener); });
|
||||
}
|
||||
void set_tuning(const EngineConfig& tuning) {
|
||||
const std::lock_guard lock(mutex_);
|
||||
if(four_)four_->set_tuning(tuning);
|
||||
}
|
||||
// Build on a background thread. Publishing takes the same lock as process(),
|
||||
// so no solver/port pointers can be observed during the swap.
|
||||
void rebuild_engine(const EngineConfig& engine) {
|
||||
validate_engine_config(engine,"pipe rebuild");
|
||||
auto replacement=std::make_unique<FourStrokeScenario>(44100,engine,exhaust_,junctions_);
|
||||
{
|
||||
const std::lock_guard lock(mutex_);
|
||||
if(!four_)throw std::invalid_argument("Live editor requires a four-stroke engine");
|
||||
replacement->set_controls(pedal_,load_,clutch_);
|
||||
replacement->set_starter(starter_);replacement->set_pipe_solver(solver_);
|
||||
replacement->set_audio_scene(scene_);replacement->set_listener(listener_);
|
||||
four_.swap(replacement);
|
||||
}
|
||||
}
|
||||
void set_cells_per_meter(float density) {
|
||||
mesh_cell_count(.1f,density);
|
||||
EngineConfig engine;TwoStrokeConfig two_config;bool is_two;
|
||||
{
|
||||
const std::lock_guard lock(mutex_);
|
||||
is_two=bool(two_);
|
||||
if(is_two) two_config=two_->configuration; else engine=four_->engine_config;
|
||||
}
|
||||
std::unique_ptr<FourStrokeScenario> next_four;
|
||||
std::unique_ptr<TwoStrokeScenario> next_two;
|
||||
if(is_two) { two_config.cells_per_meter=density;two_config.exhaust_cell_length=1/density;next_two=std::make_unique<TwoStrokeScenario>(44100,two_config); }
|
||||
else { engine.cells_per_meter=density;next_four=std::make_unique<FourStrokeScenario>(44100,engine,exhaust_,junctions_); }
|
||||
{
|
||||
const std::lock_guard lock(mutex_);
|
||||
const auto restore=[&](auto& scenario) {
|
||||
scenario.set_controls(pedal_,load_,clutch_);scenario.set_starter(starter_);
|
||||
scenario.set_pipe_solver(solver_);scenario.set_audio_scene(scene_);scenario.set_listener(listener_);
|
||||
};
|
||||
if(is_two) {restore(*next_two);two_.swap(next_two);}
|
||||
else {restore(*next_four);four_.swap(next_four);}
|
||||
}
|
||||
}
|
||||
ScenarioSnapshot snapshot() const {
|
||||
if (four_) { auto s=four_->snapshot();s.example_name=name_;return s; }
|
||||
const std::lock_guard lock(mutex_);
|
||||
if (four_) { auto s=four_->snapshot();s.example_name=name_;s.cells_per_meter=four_->engine_config.cells_per_meter;return s; }
|
||||
const auto source = two_->snapshot();
|
||||
ScenarioSnapshot s;
|
||||
s.example_name=name_;
|
||||
s.pipe_solver=two_->pipes.front().solver;
|
||||
s.two_stroke = true;
|
||||
s.cells_per_meter=two_->configuration.cells_per_meter;
|
||||
s.cylinder_angles[0]=two_->crankshaft.angle;
|
||||
s.cylinder_count = 1;
|
||||
s.racing_exhaust = two_->configuration.exhaust == TwoStrokeExhaust::Racing;
|
||||
@@ -79,6 +120,7 @@ public:
|
||||
s.intake_flow = two_->intake_flow;
|
||||
s.exhaust_flow = two_->exhaust_flow;
|
||||
s.capture_pipes(two_->pipes);
|
||||
two_->capture_geometry(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -89,6 +131,13 @@ private:
|
||||
else function(*two_);
|
||||
}
|
||||
std::string name_;
|
||||
ExhaustConfig exhaust_;
|
||||
JunctionConfig junctions_;
|
||||
float pedal_{},load_{},clutch_{};
|
||||
bool starter_{};
|
||||
PipeSolver solver_{PipeSolver::Rusanov};
|
||||
OutdoorScene scene_{OutdoorScene::Wall};
|
||||
AudioListener listener_{};
|
||||
std::unique_ptr<FourStrokeScenario> four_;
|
||||
std::unique_ptr<TwoStrokeScenario> two_;
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
namespace fluidsim::port {
|
||||
|
||||
@@ -33,11 +34,9 @@ private:
|
||||
};
|
||||
|
||||
struct CylinderConfig {
|
||||
float intake_open{340}, intake_close{590}, exhaust_open{130}, exhaust_close{390};
|
||||
float bore{0.075f}, stroke{0.068f}, rod{0.112f}, compression{11.5f};
|
||||
float intake_valve_diameter{0.030f}, exhaust_valve_diameter{0.028f};
|
||||
int intake_valve_count{1}, exhaust_valve_count{1};
|
||||
float intake_valve_lift{0.005f}, exhaust_valve_lift{0.005f};
|
||||
float spark_advance{20.0f}, wiebe_a{5.0f}, wiebe_m{2.0f}, burn_duration{60.0f}, burn_start{5.0f};
|
||||
float afr{14.7f}, fuel_lhv{44.0e6f}, energy_variation{0.05f}, misfire_probability{};
|
||||
float wall_area{0.02f}, heat_transfer{100.0f}, ambient_temperature{300.0f};
|
||||
@@ -79,14 +78,44 @@ protected:
|
||||
static bool crossed_angle(float previous, float current, float event) {
|
||||
return current >= previous ? previous < event && current >= event : event > previous || event <= current;
|
||||
}
|
||||
static bool crossed_window_close(float previous, float current, float open, float close);
|
||||
void update_rev_limiter(float rpm, float dt);
|
||||
void sync_ports();
|
||||
};
|
||||
|
||||
class FourStrokeCylinder final : public EngineCylinder {
|
||||
public:
|
||||
struct CamPoint { float angle_degrees{}, lift_metres{}; };
|
||||
struct ValveDynamics {
|
||||
float mass_kg{0.035f};
|
||||
float spring_rate_n_per_m{30000.f};
|
||||
float damping_n_s_per_m{24.f};
|
||||
float seat_force_n{100.f};
|
||||
float maximum_lift_m{0.015f};
|
||||
float seat_restitution{0.005f}, cam_restitution{0.01f}, stop_restitution{0.01f};
|
||||
};
|
||||
struct CamProfile { std::vector<CamPoint> points; };
|
||||
|
||||
void set_valve_profiles(const CamProfile& intake_cam, const ValveDynamics& intake_valve,
|
||||
const CamProfile& exhaust_cam, const ValveDynamics& exhaust_valve);
|
||||
float valve_area(float cycle_degrees, bool inlet) const override;
|
||||
void pre_step(Crankshaft& crank, float dt, float throttle) override;
|
||||
float take_contact_impulse() { const float value=contact_impulse_;contact_impulse_=0;return value; }
|
||||
bool valve_floating() const { return intake_floating_ || exhaust_floating_; }
|
||||
float intake_lift() const { return intake_lift_; }
|
||||
float exhaust_lift() const { return exhaust_lift_; }
|
||||
static float cam_lift_at(const CamProfile& profile,float degrees) { return sample_cam(profile,degrees).lift_metres; }
|
||||
|
||||
private:
|
||||
struct ValveState { float lift{},velocity{};bool floating{}; };
|
||||
const CamProfile* intake_cam_{};
|
||||
const CamProfile* exhaust_cam_{};
|
||||
ValveDynamics intake_dynamics_{},exhaust_dynamics_{};
|
||||
ValveState intake_state_{},exhaust_state_{};
|
||||
float intake_lift_{},exhaust_lift_{},contact_impulse_{};
|
||||
bool intake_floating_{},exhaust_floating_{};
|
||||
|
||||
static CamPoint sample_cam(const CamProfile& profile,float degrees);
|
||||
float advance_valve(ValveState& state,const CamProfile& cam,const ValveDynamics& dynamics,
|
||||
bool inlet,const Crankshaft& crank,float dt);
|
||||
};
|
||||
} // namespace fluidsim::port
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#pragma once
|
||||
#include "FluidSim/MeshResolution.hpp"
|
||||
#include "FluidSim/Engine.hpp"
|
||||
#include "FluidSim/Ecu.hpp"
|
||||
#include "FluidSim/Vehicle.hpp"
|
||||
#include "FluidSim/Carburetor.hpp"
|
||||
#include "FluidSim/PhysicalGeometry.hpp"
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace fluidsim::port {
|
||||
@@ -17,11 +20,14 @@ struct PipeConfig {
|
||||
float diameter{}, length{}; // metres
|
||||
int cells{}, count{1};
|
||||
bool silenced{};
|
||||
bool operator==(const PipeConfig&) const = default;
|
||||
};
|
||||
|
||||
// Parsed calibration only. Runtime state belongs to the scenario components.
|
||||
// Dimensional fields use SI units after loading.
|
||||
struct EngineConfig {
|
||||
PhysicalGeometry geometry;
|
||||
float cells_per_meter{}; // Zero retains legacy programmatic meshes. TOML scenarios specify a density.
|
||||
int cylinders{};
|
||||
EngineLayout layout{EngineLayout::Inline};
|
||||
ExhaustTopology topology{ExhaustTopology::Collector};
|
||||
@@ -31,6 +37,9 @@ struct EngineConfig {
|
||||
EcuConfig ecu;
|
||||
VehicleConfig vehicle;
|
||||
CarburetorConfig fuel;
|
||||
FourStrokeCylinder::CamProfile intake_cam,exhaust_cam;
|
||||
FourStrokeCylinder::ValveDynamics intake_valve,exhaust_valve;
|
||||
struct ValveSound { float mode_hz{3600}, effective_mass_kg{0.18f}, radiation_area{0.001f}, damping_ratio{0.9f}; } valve_sound;
|
||||
bool carbureted{}, initialize_phased_charge{true};
|
||||
float initial_rpm{}, starter_torque{}, maximum_load_torque{};
|
||||
float plenum_volume{}, collector_volume{}, throttle_diameter{}, pipe_damping{};
|
||||
@@ -45,7 +54,14 @@ struct EngineConfig {
|
||||
int header_groups() const { return cylinders==3?1:2; }
|
||||
};
|
||||
|
||||
struct JunctionBranchConfig {
|
||||
int pipe{}; bool left{};
|
||||
std::array<float,3> direction{};
|
||||
};
|
||||
struct JunctionConfig {
|
||||
std::string model{"volume"}; // volume, characteristic, or legacy
|
||||
float turning_loss{0};
|
||||
std::vector<JunctionBranchConfig> branches;
|
||||
bool h_pipe{true};
|
||||
float junction_volume{50e-6f};
|
||||
};
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "FluidSim/OpenEndRadiation.hpp"
|
||||
#include "FluidSim/PipeSolver.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
#include <limits>
|
||||
@@ -181,12 +183,17 @@ public:
|
||||
std::vector<GasCell> cells;
|
||||
GasState left_ghost{}, right_ghost{};
|
||||
std::uint64_t positivity_repairs{};
|
||||
std::size_t scratch_bytes() const {
|
||||
return next_cells_.capacity()*sizeof(GasCell)+states_.capacity()*sizeof(GasState)+
|
||||
reconstructed_left_.capacity()*sizeof(GasState)+reconstructed_right_.capacity()*sizeof(GasState)+
|
||||
waves_.capacity()*sizeof(float)+faces_.capacity()*sizeof(Flux)+roe_states_.capacity()*sizeof(RoeState);
|
||||
}
|
||||
Pipe1D(float a, float length, int count)
|
||||
: Pipe1D(uniform(a, count), uniform(length / std::max(count, 1), count)) {}
|
||||
Pipe1D(std::vector<float> areas, std::vector<float> lengths)
|
||||
: area(areas.empty() ? 0 : areas.front()), dx(lengths.empty() ? 0 : lengths.front()),
|
||||
cell_areas(std::move(areas)), cell_lengths(std::move(lengths)), cells(cell_areas.size()),
|
||||
next_cells_(cells.size()), states_(cells.size()), waves_(cells.size()), faces_(cells.size() + 1), roe_states_(cells.size()) {
|
||||
next_cells_(cells.size()), states_(cells.size()), waves_(cells.size()), faces_(cells.size() + 1) {
|
||||
if (cells.empty() || cell_lengths.size() != cells.size())
|
||||
throw std::invalid_argument("pipe profiles must be nonempty and have equal length");
|
||||
for (std::size_t i = 0; i < cells.size(); ++i)
|
||||
@@ -212,6 +219,16 @@ public:
|
||||
// Solver preparation is valid until advance; boundary resolution changes
|
||||
// fluxes/ghosts, not cells. Standalone advance still prepares its own cache.
|
||||
float prepare_step(float cfl = 0.8f) {
|
||||
if(!scratch_solver_initialized_ || scratch_solver_!=solver) {
|
||||
if(solver==PipeSolver::Muscl) {
|
||||
if(reconstructed_left_.size()!=cells.size()) reconstructed_left_.resize(cells.size());
|
||||
if(reconstructed_right_.size()!=cells.size()) reconstructed_right_.resize(cells.size());
|
||||
} else if(solver==PipeSolver::Hlle || solver==PipeSolver::Hllc) {
|
||||
if(roe_states_.size()!=cells.size()) roe_states_.resize(cells.size());
|
||||
}
|
||||
scratch_solver_=solver;
|
||||
scratch_solver_initialized_=true;
|
||||
}
|
||||
float dt = std::numeric_limits<float>::max();
|
||||
for (std::size_t i = 0; i < cells.size(); ++i) {
|
||||
states_[i] = primitive(cells[i]);
|
||||
@@ -225,7 +242,7 @@ public:
|
||||
throw std::runtime_error("nonphysical pipe state in preparation");
|
||||
dt = std::min(dt, cfl * cell_lengths[i] / waves_[i]);
|
||||
}
|
||||
if (solver != PipeSolver::Rusanov)
|
||||
if (solver == PipeSolver::Hlle || solver == PipeSolver::Hllc)
|
||||
for (std::size_t i=0; i<cells.size(); ++i) {
|
||||
const auto& s=states_[i];
|
||||
const double energy=s.pressure*pipe_gm1_inverse+.5*double(s.rho)*s.velocity*s.velocity;
|
||||
@@ -327,6 +344,18 @@ public:
|
||||
static Flux numerical_flux(const GasState& a,const GasState& b,PipeSolver solver) {
|
||||
return numerical_flux(a,b,solver,std::sqrt(gamma*a.pressure/a.rho),std::sqrt(gamma*b.pressure/b.rho));
|
||||
}
|
||||
void set_acoustic_neighbor(bool left,GasState state) {
|
||||
if(left) { left_acoustic_neighbor_=state; has_left_acoustic_neighbor_=true; }
|
||||
else { right_acoustic_neighbor_=state; has_right_acoustic_neighbor_=true; }
|
||||
}
|
||||
void prepare_acoustic_reconstruction(float dt) {
|
||||
if(solver!=PipeSolver::Muscl) return;
|
||||
if(!prepared_) prepare_step();
|
||||
reconstruct(dt); reconstructed_prepared_=true;
|
||||
}
|
||||
GasState acoustic_edge(bool left) const {
|
||||
return left?reconstructed_left_.front():reconstructed_right_.back();
|
||||
}
|
||||
void advance(float dt) {
|
||||
if (dt <= 0)
|
||||
return;
|
||||
@@ -338,7 +367,18 @@ public:
|
||||
faces_[0] = left_override_ ? left_flux_ : scaled(numerical_flux(left_ghost, states_[0], solver), cell_areas[0]);
|
||||
faces_[n] =
|
||||
right_override_ ? right_flux_ : scaled(numerical_flux(states_[n - 1], right_ghost, solver), cell_areas[n - 1]);
|
||||
if (solver == PipeSolver::Rusanov) {
|
||||
if(solver==PipeSolver::Muscl) {
|
||||
if(!reconstructed_prepared_) reconstruct(dt);
|
||||
for(std::size_t i=1;i<n;++i) {
|
||||
bool fallback=false;
|
||||
const auto& a=reconstructed_right_[i-1];
|
||||
const auto& b=reconstructed_left_[i];
|
||||
faces_[i]=scaled(numerical_flux(a,b,PipeSolver::Hllc,
|
||||
std::sqrt(gamma*a.pressure/a.rho),std::sqrt(gamma*b.pressure/b.rho),&fallback),
|
||||
.5f*(cell_areas[i-1]+cell_areas[i]));
|
||||
hllc_fallbacks+=fallback;
|
||||
}
|
||||
} else if (solver == PipeSolver::Rusanov) {
|
||||
for (std::size_t i = 1; i < n; ++i)
|
||||
faces_[i] = scaled(riemann(states_[i-1], states_[i], std::max(waves_[i-1], waves_[i])),
|
||||
.5f*(cell_areas[i-1]+cell_areas[i]));
|
||||
@@ -400,6 +440,7 @@ public:
|
||||
}
|
||||
cells.swap(next_cells_);
|
||||
prepared_ = false;
|
||||
reconstructed_prepared_=has_left_acoustic_neighbor_=has_right_acoustic_neighbor_=false;
|
||||
left_override_ = right_override_ = false;
|
||||
}
|
||||
static Flux scaled(Flux f, float a) {
|
||||
@@ -409,11 +450,53 @@ public:
|
||||
private:
|
||||
std::vector<GasCell> next_cells_;
|
||||
std::vector<GasState> states_;
|
||||
std::vector<GasState> reconstructed_left_, reconstructed_right_;
|
||||
std::vector<float> waves_;
|
||||
std::vector<Flux> faces_;
|
||||
std::vector<RoeState> roe_states_;
|
||||
PipeSolver scratch_solver_{PipeSolver::Rusanov};
|
||||
bool scratch_solver_initialized_{};
|
||||
Flux left_flux_{}, right_flux_{};
|
||||
bool left_override_{}, right_override_{}, prepared_{};
|
||||
GasState left_acoustic_neighbor_{}, right_acoustic_neighbor_{};
|
||||
bool has_left_acoustic_neighbor_{}, has_right_acoustic_neighbor_{}, reconstructed_prepared_{};
|
||||
// Primitive minmod MUSCL-Hancock on uniform sections. Component interfaces
|
||||
// and area/profile transitions retain the existing first-order coupling.
|
||||
void reconstruct(float dt) {
|
||||
const auto minmod=[](float a,float b) {
|
||||
return a*b<=0 ? 0.f : std::copysign(std::min(std::abs(a),std::abs(b)),a);
|
||||
};
|
||||
for(std::size_t i=0;i<states_.size();++i) {
|
||||
const auto q=states_[i];
|
||||
reconstructed_left_[i]=reconstructed_right_[i]=q;
|
||||
if((i==0 && !has_left_acoustic_neighbor_) ||
|
||||
(i+1==states_.size() && !has_right_acoustic_neighbor_) ||
|
||||
(i>0 && (cell_areas[i-1]!=cell_areas[i] || cell_lengths[i-1]!=cell_lengths[i])) ||
|
||||
(i+1<states_.size() && (cell_areas[i+1]!=cell_areas[i] || cell_lengths[i+1]!=cell_lengths[i]))) continue;
|
||||
const auto a=i==0?left_acoustic_neighbor_:states_[i-1];
|
||||
const auto b=i+1==states_.size()?right_acoustic_neighbor_:states_[i+1];
|
||||
const float dr=minmod(q.rho-a.rho,b.rho-q.rho);
|
||||
const float du=minmod(q.velocity-a.velocity,b.velocity-q.velocity);
|
||||
const float dp=minmod(q.pressure-a.pressure,b.pressure-q.pressure);
|
||||
const float da=minmod(q.air-a.air,b.air-q.air);
|
||||
const float df=minmod(q.fuel-a.fuel,b.fuel-q.fuel);
|
||||
const float h=.5f*dt/cell_lengths[i];
|
||||
const GasState half{q.rho-h*(q.velocity*dr+q.rho*du),
|
||||
q.velocity-h*(q.velocity*du+dp/q.rho),
|
||||
q.pressure-h*(q.velocity*dp+gamma*q.pressure*du),
|
||||
q.air-h*q.velocity*da,q.fuel-h*q.velocity*df};
|
||||
const auto edge=[&](float sign) { return GasState{half.rho+sign*dr,
|
||||
half.velocity+sign*du,half.pressure+sign*dp,half.air+sign*da,half.fuel+sign*df}; };
|
||||
const auto left=edge(-.5f), right=edge(.5f);
|
||||
const auto physical=[](const GasState& v) {
|
||||
return v.rho>1e-12f && v.pressure>1e-6f && std::isfinite(v.pressure) &&
|
||||
std::isfinite(v.rho) && std::isfinite(v.velocity) && v.air>=0 && v.fuel>=0 && v.air+v.fuel<=1.000001f;
|
||||
};
|
||||
if(physical(left) && physical(right)) {
|
||||
reconstructed_left_[i]=left; reconstructed_right_[i]=right;
|
||||
}
|
||||
}
|
||||
}
|
||||
static std::vector<float> uniform(float v, int n) {
|
||||
if (n <= 0)
|
||||
throw std::invalid_argument("pipe count must be positive");
|
||||
@@ -514,25 +597,39 @@ public:
|
||||
claim(b, left_b);
|
||||
connections_.push_back({a, b, left_a, left_b});
|
||||
}
|
||||
struct JunctionFace { int pipe; bool left; };
|
||||
void add_junction(std::initializer_list<JunctionFace> ends) {
|
||||
if(ends.size()<2) throw std::invalid_argument("junction needs at least two faces");
|
||||
JunctionNode node;
|
||||
struct JunctionFace {
|
||||
int pipe; bool left;
|
||||
// Unit vector pointing OUT of the node into this branch, in world axes.
|
||||
std::array<float,3> direction{};
|
||||
};
|
||||
enum class JunctionMethod { Characteristic, LegacyRusanov };
|
||||
void add_junction(std::initializer_list<JunctionFace> ends,
|
||||
JunctionMethod method=JunctionMethod::Characteristic,float turning_loss=0) {
|
||||
add_junction(std::span(ends.begin(),ends.size()),method,turning_loss);
|
||||
}
|
||||
void add_junction(std::span<const JunctionFace> ends,
|
||||
JunctionMethod method=JunctionMethod::Characteristic,float turning_loss=0) {
|
||||
if(ends.size()<2 || !std::isfinite(turning_loss) || turning_loss<0 || turning_loss>10)
|
||||
throw std::invalid_argument("invalid junction size or turning loss");
|
||||
JunctionNode node; node.method=method; node.turning_loss=turning_loss;
|
||||
for(auto e:ends) {
|
||||
check_face(e.pipe,e.left);
|
||||
for(auto previous:node.ends) {
|
||||
for(auto previous:node.ends)
|
||||
if(previous.pipe==e.pipe && previous.left==e.left) throw std::invalid_argument("duplicate junction face");
|
||||
}
|
||||
double norm=0;
|
||||
for(float v:e.direction) { if(!std::isfinite(v)) throw std::invalid_argument("invalid junction direction"); norm+=double(v)*v; }
|
||||
if(norm>0) for(float& v:e.direction) v/=std::sqrt(norm);
|
||||
else if(turning_loss>0) throw std::invalid_argument("direction required for turning loss");
|
||||
node.ends.push_back(e);
|
||||
}
|
||||
for(auto e:ends) claim(e.pipe,e.left);
|
||||
node.states.resize(ends.size());
|
||||
node.states.resize(ends.size()); node.faces.resize(ends.size());
|
||||
nodes_.push_back(std::move(node));
|
||||
}
|
||||
float open_end_mass_flow(std::size_t i) const { return opens_.at(i).last_mass_flow; }
|
||||
float open_end_volume_flow(std::size_t i) const { return opens_.at(i).last_volume_flow; }
|
||||
float open_end_pressure(std::size_t i) const { return opens_.at(i).last_face_pressure; }
|
||||
std::uint64_t limited_fluxes{}, nonlinear_iterations{};
|
||||
std::uint64_t limited_fluxes{}, nonlinear_iterations{}, junction_fallbacks{}, junction_iterations{}, junction_limited_fluxes{};
|
||||
void validate_topology() const {
|
||||
if (claims_.size() != 2 * pipes_.size())
|
||||
throw std::runtime_error("every pipe endpoint needs an explicit boundary or connection");
|
||||
@@ -544,6 +641,20 @@ public:
|
||||
b.mass = .25f * (*b.air + (b.exhaust ? *b.exhaust : 0) + (b.fuel ? *b.fuel : 0));
|
||||
b.heat = b.energy ? .25f * (*b.energy) : std::numeric_limits<float>::max();
|
||||
}
|
||||
// Supply matching direct-pipe neighbors before reconstruction, preserving
|
||||
// the same stencil across artificial pipe splits and all orientations.
|
||||
for(const auto& o:connections_) {
|
||||
auto& a=pipes_[o.a]; auto& b=pipes_[o.b];
|
||||
const int ia=end(a,o.left_a), ib=end(b,o.left_b);
|
||||
if(a.solver==PipeSolver::Muscl && b.solver==PipeSolver::Muscl &&
|
||||
a.cell_area(ia)==b.cell_area(ib) && a.cell_length(ia)==b.cell_length(ib)) {
|
||||
auto sa=a.state(ia), sb=b.state(ib);
|
||||
const float sign=o.left_a==o.left_b?-1.f:1.f;
|
||||
sa.velocity*=sign; sb.velocity*=sign;
|
||||
a.set_acoustic_neighbor(o.left_a,sb); b.set_acoustic_neighbor(o.left_b,sa);
|
||||
}
|
||||
}
|
||||
for(auto& pipe:pipes_) pipe.prepare_acoustic_reconstruction(dt);
|
||||
for (auto &o : orifices_)
|
||||
resolve_orifice(o, dt);
|
||||
for (auto &o : opens_)
|
||||
@@ -557,12 +668,21 @@ private:
|
||||
struct JunctionNode {
|
||||
std::vector<JunctionFace> ends;
|
||||
std::vector<GasState> states;
|
||||
struct Face { double pressure{},rho{},velocity{},mass{},enthalpy{},air{},fuel{},loss{}; };
|
||||
std::vector<Face> faces;
|
||||
JunctionMethod method{JunctionMethod::Characteristic};
|
||||
double turning_loss{};
|
||||
};
|
||||
std::vector<JunctionNode> nodes_;
|
||||
// Zero-storage Rusanov star state. Integrated mass, total energy and
|
||||
// species fluxes sum to zero algebraically across every connected face.
|
||||
// The node has no conserved state, timestep or storage volume of its own.
|
||||
void resolve_junction(JunctionNode& node,float) {
|
||||
void resolve_junction(JunctionNode& node,float dt) {
|
||||
if(node.method==JunctionMethod::Characteristic && characteristic_junction(node,dt)) return;
|
||||
if(node.method==JunctionMethod::Characteristic) ++junction_fallbacks;
|
||||
legacy_junction(node);
|
||||
}
|
||||
void legacy_junction(JunctionNode& node) {
|
||||
double speed=0;
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
auto e=node.ends[k];auto& p=pipes_[e.pipe];auto s=p.state(end(p,e.left));
|
||||
@@ -593,6 +713,135 @@ private:
|
||||
p.set_boundary_flux(e.left,{float(orientation*m),float(momentum),float(orientation*heat),float(orientation*y),float(orientation*f)});
|
||||
}
|
||||
}
|
||||
// Nonlinear outgoing acoustic-wave curves (shock or rarefaction), with
|
||||
// common node pressure, conservative stagnation-enthalpy/species mixing,
|
||||
// and outgoing contact density set from the mixed enthalpy. This is a
|
||||
// compact subsonic engineering closure, not a resolved 3D junction.
|
||||
bool characteristic_junction(JunctionNode& node,float dt) {
|
||||
double low=std::numeric_limits<double>::max(), high=0;
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
const auto e=node.ends[k]; const auto& pipe=pipes_[e.pipe];
|
||||
auto state=pipe.state(end(pipe,e.left));
|
||||
state.velocity*=e.left?-1:1; // positive INTO the node
|
||||
const double c=std::sqrt(gamma*state.pressure/state.rho);
|
||||
if(std::abs(state.velocity)>=.95*c) return false;
|
||||
node.states[k]=state;
|
||||
low=std::min(low,double(state.pressure)); high=std::max(high,double(state.pressure));
|
||||
node.faces[k].loss=0;
|
||||
}
|
||||
const auto wave_curve=[](const GasState& q,double p) {
|
||||
if(p>q.pressure) {
|
||||
const double a=2/((gamma+1)*q.rho), b=(gamma-1)/(gamma+1)*q.pressure;
|
||||
return (p-q.pressure)*std::sqrt(a/(p+b));
|
||||
}
|
||||
const double c=std::sqrt(gamma*q.pressure/q.rho);
|
||||
return 2*c/(gamma-1)*(std::pow(p/q.pressure,(gamma-1)/(2*gamma))-1);
|
||||
};
|
||||
const auto density=[](const GasState& q,double p) {
|
||||
const double ratio=p/q.pressure, b=(gamma-1)/(gamma+1);
|
||||
return p>q.pressure ? q.rho*(ratio+b)/(b*ratio+1) : q.rho*std::pow(ratio,1/gamma);
|
||||
};
|
||||
// Each pressure evaluation writes scratch face states only, never pipes.
|
||||
const auto residual=[&](double pressure) {
|
||||
double incoming=0, heat=0, air=0, fuel=0;
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
const auto q=node.states[k]; auto& f=node.faces[k];
|
||||
double p=pressure;
|
||||
for(int iteration=0;iteration<(f.loss>0?8:1);++iteration) {
|
||||
const double u=q.velocity-wave_curve(q,p), rho=density(q,p);
|
||||
const double target=std::clamp(pressure+std::copysign(.5*f.loss*rho*u*u,u),pressure*.05,pressure*20);
|
||||
p=.5*(p+target);
|
||||
}
|
||||
f.pressure=p; f.rho=density(q,p); f.velocity=q.velocity-wave_curve(q,p);
|
||||
const auto e=node.ends[k]; const auto& pipe=pipes_[e.pipe];
|
||||
f.mass=pipe.cell_area(end(pipe,e.left))*f.rho*f.velocity;
|
||||
f.enthalpy=gamma/(gamma-1)*p/f.rho+.5*f.velocity*f.velocity;
|
||||
f.air=q.air; f.fuel=q.fuel;
|
||||
if(f.mass>0) { incoming+=f.mass; heat+=f.mass*f.enthalpy; air+=f.mass*q.air; fuel+=f.mass*q.fuel; }
|
||||
}
|
||||
double balance=0;
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
auto& f=node.faces[k];
|
||||
if(f.mass<0 && incoming>1e-20) {
|
||||
const double h=heat/incoming, thermal=h-.5*f.velocity*f.velocity;
|
||||
if(!(thermal>0)) return std::numeric_limits<double>::quiet_NaN();
|
||||
f.rho=gamma/(gamma-1)*f.pressure/thermal;
|
||||
const auto e=node.ends[k]; const auto& pipe=pipes_[e.pipe];
|
||||
f.mass=pipe.cell_area(end(pipe,e.left))*f.rho*f.velocity;
|
||||
f.enthalpy=h; f.air=air/incoming; f.fuel=fuel/incoming;
|
||||
}
|
||||
balance+=f.mass;
|
||||
}
|
||||
return balance;
|
||||
};
|
||||
// Iterate the donor-weighted direction coefficients separately from the
|
||||
// scalar pressure root; K=0 remains the ideal acoustic scattering case.
|
||||
double node_pressure=.5*(low+high);
|
||||
for(int geometry=0;geometry<(node.turning_loss>0?3:1);++geometry) {
|
||||
double lo=low*.01, hi=high*100;
|
||||
double fl=residual(lo), fh=residual(hi);
|
||||
if(!std::isfinite(fl) || !std::isfinite(fh) || fl<0 || fh>0) return false;
|
||||
node_pressure=std::clamp(node_pressure,lo,hi);
|
||||
bool converged=false;
|
||||
for(int iteration=0;iteration<40;++iteration) {
|
||||
const double value=residual(node_pressure); ++junction_iterations;
|
||||
if(!std::isfinite(value)) return false;
|
||||
double magnitude=0; for(const auto& face:node.faces) magnitude+=std::abs(face.mass);
|
||||
if(std::abs(value)<1e-14+1e-8*magnitude) { converged=true; break; }
|
||||
if(value>0) lo=node_pressure; else hi=node_pressure;
|
||||
const double delta=std::max(1e-3,node_pressure*1e-5);
|
||||
const double derivative=(residual(node_pressure+delta)-value)/delta;
|
||||
const double next=node_pressure-value/derivative;
|
||||
node_pressure=std::isfinite(next) && next>lo && next<hi ? next : .5*(lo+hi);
|
||||
}
|
||||
if(!converged) return false;
|
||||
residual(node_pressure);
|
||||
if(geometry+1<(node.turning_loss>0?3:1)) {
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
auto& f=node.faces[k]; double weight=0, loss=0;
|
||||
if(f.mass<0) for(std::size_t j=0;j<node.ends.size();++j) {
|
||||
const double m=std::max(0.,node.faces[j].mass); double dot=0;
|
||||
for(int axis=0;axis<3;++axis) dot+=node.ends[k].direction[axis]*node.ends[j].direction[axis];
|
||||
weight+=m; loss+=m*.5*(1+std::clamp(dot,-1.,1.));
|
||||
}
|
||||
f.loss=weight>0?node.turning_loss*loss/weight:0;
|
||||
}
|
||||
}
|
||||
}
|
||||
double incoming=0, outgoing=0, heat=0, air=0, fuel=0, scale=1;
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
const auto& f=node.faces[k];
|
||||
if(!std::isfinite(f.mass) || !std::isfinite(f.enthalpy)) return false;
|
||||
if(std::abs(f.velocity)>=.98*std::sqrt(gamma*f.pressure/f.rho)) return false;
|
||||
if(f.mass>0) { incoming+=f.mass;heat+=f.mass*f.enthalpy;air+=f.mass*f.air;fuel+=f.mass*f.fuel; }
|
||||
else outgoing-=f.mass;
|
||||
}
|
||||
if(incoming>1e-16 && outgoing<=1e-16) {
|
||||
if(incoming>1e-11) return false;
|
||||
// Residual tolerance at rest must not create a one-sided mass source.
|
||||
for(auto& face:node.faces) face.mass=0;
|
||||
incoming=heat=air=fuel=0;
|
||||
}
|
||||
// Remove root roundoff by scaling all outflows together. A shared donor
|
||||
// budget scales advective fluxes together, preserving node conservation.
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
auto& f=node.faces[k];
|
||||
if(f.mass<0) { f.mass*=outgoing>0?incoming/outgoing:0; f.enthalpy=incoming>0?heat/incoming:0; f.air=incoming>0?air/incoming:0; f.fuel=incoming>0?fuel/incoming:0; }
|
||||
if(f.mass>0) {
|
||||
const auto e=node.ends[k]; const auto& pipe=pipes_[e.pipe];const int i=end(pipe,e.left);
|
||||
scale=std::min(scale,.25*pipe.cell_mass(i)/(f.mass*dt));
|
||||
scale=std::min(scale,.25*double(pipe.cells[i].energy)*pipe.cell_area(i)*pipe.cell_length(i)/(f.mass*f.enthalpy*dt));
|
||||
}
|
||||
}
|
||||
if(scale<1) { ++limited_fluxes; ++junction_limited_fluxes; }
|
||||
for(std::size_t k=0;k<node.ends.size();++k) {
|
||||
const auto e=node.ends[k]; auto& pipe=pipes_[e.pipe]; const auto& f=node.faces[k];
|
||||
const double orientation=e.left?-1:1, m=f.mass*scale;
|
||||
const double momentum=m*f.velocity+f.pressure*pipe.cell_area(end(pipe,e.left));
|
||||
pipe.set_boundary_flux(e.left,{float(orientation*m),float(momentum),float(orientation*m*f.enthalpy),float(orientation*m*f.air),float(orientation*m*f.fuel)});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
struct Budget {
|
||||
float *air{}, *exhaust{}, *fuel{}, *energy{};
|
||||
float mass{}, heat{};
|
||||
@@ -864,6 +1113,9 @@ private:
|
||||
auto &b = pipes_[o.b];
|
||||
int ia = end(a, o.left_a), ib = end(b, o.left_b);
|
||||
auto sa = a.state(ia), sb = b.state(ib);
|
||||
if(a.solver==PipeSolver::Muscl && b.solver==PipeSolver::Muscl) {
|
||||
sa=a.acoustic_edge(o.left_a); sb=b.acoustic_edge(o.left_b);
|
||||
}
|
||||
const float da = o.left_a ? -1.f : 1.f, db = o.left_b ? 1.f : -1.f;
|
||||
sa.velocity *= da;
|
||||
sb.velocity *= db;
|
||||
|
||||
13
include/FluidSim/MeshResolution.hpp
Normal file
13
include/FluidSim/MeshResolution.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
namespace fluidsim::port {
|
||||
inline int mesh_cell_count(float length,float cells_per_meter) {
|
||||
if(!std::isfinite(cells_per_meter) || cells_per_meter<1 || cells_per_meter>500 || !std::isfinite(length) || length<=0)
|
||||
throw std::invalid_argument("cells_per_meter must be in 1..500 with positive pipe length");
|
||||
const double count=double(length)*cells_per_meter;
|
||||
if(count>4096.001) throw std::invalid_argument("pipe mesh exceeds 4096 cells");
|
||||
return std::max(1,int(std::ceil(count-1e-6*std::max(1.,count))));
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,9 @@ struct OutdoorAudioConfig {
|
||||
Vec3 intake_position{-0.2f, 0.7f, 0.0f};
|
||||
Vec3 exhaust_position{0.55f, 0.5f, 0.0f};
|
||||
Vec3 second_exhaust_position{-0.55f, 0.5f, 0.0f};
|
||||
Vec3 valve_position{0.08f,0.42f,0.0f};
|
||||
bool dual_exhaust{};
|
||||
bool valve_contact_enabled{};
|
||||
float ear_spacing{0.18f}, sound_speed{343.0f};
|
||||
float ground_y{0.0f}, wall_x{-1.5f};
|
||||
float ground_reflection{0.35f}, wall_reflection{0.65f};
|
||||
@@ -29,10 +31,15 @@ struct OutdoorAudioConfig {
|
||||
// approximate diffuse tail. No feedback into the fluid/combustion simulation.
|
||||
class OutdoorAudio {
|
||||
public:
|
||||
static constexpr std::array<const char*,4> source_names{"intake", "exhaust", "exhaust-2", "valve-contact"};
|
||||
struct SourceFrames { AudioFrame rendered{}, dry{}, unfiltered{}; };
|
||||
const auto& source_frames() const { return sources_; }
|
||||
AudioFrame tail_frame() const { return last_tail_; }
|
||||
void set_source_enabled(std::size_t index,bool enabled) { enabled_.at(index)=enabled; }
|
||||
explicit OutdoorAudio(int sample_rate = 44100, OutdoorAudioConfig config = {});
|
||||
// Acoustic source inputs are ambient-density times mouth volume flow, kg/s.
|
||||
// Fluid transport still uses actual donor-density mass flux independently.
|
||||
AudioFrame process(float intake_mass_flow, float exhaust_mass_flow, float second_exhaust_mass_flow = 0);
|
||||
AudioFrame process(float intake_mass_flow, float exhaust_mass_flow, float second_exhaust_mass_flow = 0, float valve_contact_mass_flow = 0);
|
||||
void set_scene(OutdoorScene scene) { requested_scene_.store(scene, std::memory_order_relaxed); }
|
||||
OutdoorScene scene() const { return requested_scene_.load(std::memory_order_relaxed); }
|
||||
// Call on the simulation thread or under the scenario's simulation lock.
|
||||
@@ -66,12 +73,14 @@ private:
|
||||
std::atomic<OutdoorScene> requested_scene_{OutdoorScene::Wall};
|
||||
OutdoorScene active_scene_{OutdoorScene::Wall};
|
||||
bool monitor_filter_{true};
|
||||
std::array<Emitter, 3> emitters_;
|
||||
std::array<Emitter, 4> emitters_;
|
||||
OutdoorExhaustReverb late_reverb_;
|
||||
std::array<float, 5> weights_{1, 0, 0, 0, 0};
|
||||
float scene_alpha_{}, tail_mix_{};
|
||||
float geometry_alpha_{}, reverb_input_{};
|
||||
AudioFrame last_dry_{}, last_raw_{};
|
||||
AudioFrame last_dry_{}, last_raw_{}, last_tail_{};
|
||||
std::array<SourceFrames,4> sources_{};
|
||||
std::array<bool,4> enabled_{true,true,true,true};
|
||||
void configure_emitter(Emitter &emitter, Vec3 position);
|
||||
void update_geometry();
|
||||
AudioFrame render(Emitter &emitter, float flow, AudioFrame &dry, AudioFrame &raw);
|
||||
|
||||
42
include/FluidSim/PhysicalGeometry.hpp
Normal file
42
include/FluidSim/PhysicalGeometry.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "FluidSim/AudioProcessing.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fluidsim::port {
|
||||
struct EngineConfig;
|
||||
struct ExhaustConfig;
|
||||
struct JunctionConfig;
|
||||
struct TwoStrokeConfig;
|
||||
struct GeometryPath {
|
||||
bool operator==(const GeometryPath&) const = default;
|
||||
std::vector<Vec3> points;
|
||||
float length() const;
|
||||
Vec3 position(float distance) const;
|
||||
};
|
||||
struct GeometryBox {
|
||||
bool operator==(const GeometryBox&) const = default;
|
||||
Vec3 center{},size{};
|
||||
float volume() const {return size.x*size.y*size.z;}
|
||||
Vec3 minimum() const {return {center.x-size.x*.5f,center.y-size.y*.5f,center.z-size.z*.5f};}
|
||||
Vec3 maximum() const {return {center.x+size.x*.5f,center.y+size.y*.5f,center.z+size.z*.5f};}
|
||||
};
|
||||
struct GeometryVolume {std::string id;GeometryBox box;bool operator==(const GeometryVolume&) const = default;};
|
||||
struct CylinderPlacement {Vec3 origin{};float tilt_degrees{};bool operator==(const CylinderPlacement&) const = default;};
|
||||
struct PhysicalGeometry {
|
||||
bool operator==(const PhysicalGeometry&) const = default;
|
||||
std::vector<GeometryPath> pipes;
|
||||
std::vector<GeometryVolume> volumes;
|
||||
std::vector<CylinderPlacement> cylinders;
|
||||
const GeometryBox* volume(const std::string& id) const;
|
||||
GeometryBox* volume(const std::string& id);
|
||||
bool empty() const {return pipes.empty();}
|
||||
};
|
||||
float geometry_distance(Vec3 a,Vec3 b);
|
||||
Vec3 cylinder_point(const CylinderPlacement& cylinder,Vec3 local);
|
||||
PhysicalGeometry default_geometry(const EngineConfig&,const ExhaustConfig&,const JunctionConfig&);
|
||||
PhysicalGeometry default_geometry(const TwoStrokeConfig&);
|
||||
EngineConfig resolve_engine_geometry(EngineConfig,const ExhaustConfig&,const JunctionConfig&);
|
||||
TwoStrokeConfig resolve_two_stroke_geometry(TwoStrokeConfig);
|
||||
void validate_geometry(const PhysicalGeometry&,std::size_t pipes,std::size_t cylinders);
|
||||
}
|
||||
@@ -6,6 +6,10 @@ namespace fluidsim::port {
|
||||
struct PipeSection {
|
||||
float length, inlet_diameter, outlet_diameter;
|
||||
};
|
||||
inline int profile_section_cells(float length,float maximum_cell_length) {
|
||||
const double count=double(length)/maximum_cell_length;
|
||||
return std::max(1,static_cast<int>(std::ceil(count-1e-6*std::max(1.,count))));
|
||||
}
|
||||
|
||||
// Linear diameter within each section. Cell area is the exact frustum-volume
|
||||
// average, so refining the mesh preserves the specified chamber volume.
|
||||
@@ -20,7 +24,7 @@ inline Pipe1D make_profiled_pipe(std::span<const PipeSection> sections, float ma
|
||||
section.inlet_diameter <= 0 || section.outlet_diameter <= 0 ||
|
||||
std::abs(section.inlet_diameter - previous_diameter) > 1e-6f)
|
||||
throw std::invalid_argument("invalid/discontinuous pipe profile");
|
||||
const int count = static_cast<int>(std::ceil(section.length / maximum_cell_length));
|
||||
const int count = profile_section_cells(section.length,maximum_cell_length);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const float d0 = std::lerp(section.inlet_diameter, section.outlet_diameter, float(i) / count);
|
||||
const float d1 = std::lerp(section.inlet_diameter, section.outlet_diameter, float(i + 1) / count);
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
namespace fluidsim::port {
|
||||
enum class PipeSolver { Rusanov, Hlle, Hllc };
|
||||
enum class PipeSolver { Rusanov, Hlle, Hllc, Muscl };
|
||||
inline const char* pipe_solver_name(PipeSolver solver) {
|
||||
switch(solver) {
|
||||
case PipeSolver::Rusanov: return "rusanov";
|
||||
case PipeSolver::Hlle: return "hlle";
|
||||
case PipeSolver::Hllc: return "hllc";
|
||||
case PipeSolver::Muscl: return "muscl";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
@@ -15,6 +16,7 @@ inline PipeSolver parse_pipe_solver(std::string_view name) {
|
||||
if(name=="rusanov") return PipeSolver::Rusanov;
|
||||
if(name=="hlle") return PipeSolver::Hlle;
|
||||
if(name=="hllc") return PipeSolver::Hllc;
|
||||
throw std::invalid_argument("choose rusanov, hlle or hllc pipe solver");
|
||||
if(name=="muscl") return PipeSolver::Muscl;
|
||||
throw std::invalid_argument("choose rusanov, hlle, hllc or muscl pipe solver");
|
||||
}
|
||||
} // namespace fluidsim::port
|
||||
|
||||
59
include/FluidSim/RuntimeProfiler.hpp
Normal file
59
include/FluidSim/RuntimeProfiler.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
namespace fluidsim::port {
|
||||
enum class ProfileStage : std::size_t { Total, Controls, Solver, Boundary, Pipe, Components, Audio, Count };
|
||||
inline constexpr std::array<std::string_view,7> profile_stage_names{
|
||||
"total", "controls", "solver", "boundary", "pipe", "components", "audio"};
|
||||
struct ProfileTotals {
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(ProfileStage::Count)> nanoseconds{};
|
||||
std::uint64_t sampled_steps{};
|
||||
std::array<std::uint64_t,512> frame_histogram{};
|
||||
};
|
||||
inline double profile_percentile_ms(const ProfileTotals& totals,double quantile) {
|
||||
if(!totals.sampled_steps) return 0;
|
||||
const auto target=static_cast<std::uint64_t>(quantile*(totals.sampled_steps-1));
|
||||
std::uint64_t count=0;
|
||||
for(std::size_t i=0;i<totals.frame_histogram.size();++i) {
|
||||
count+=totals.frame_histogram[i];
|
||||
if(count>target) return (i+.5)*.001;
|
||||
}
|
||||
return .512;
|
||||
}
|
||||
class RuntimeProfiler {
|
||||
public:
|
||||
void enable(bool value) { enabled_=value; frame_=0; totals_={}; }
|
||||
bool begin_step() { return enabled_ && (frame_++%2==0); }
|
||||
void add(ProfileStage stage,std::uint64_t ns) { totals_.nanoseconds[static_cast<std::size_t>(stage)]+=ns; }
|
||||
void finish_step(std::uint64_t elapsed_ns) {
|
||||
++totals_.sampled_steps;
|
||||
const auto bin=std::min<std::uint64_t>(elapsed_ns/1000,totals_.frame_histogram.size()-1);
|
||||
++totals_.frame_histogram[bin];
|
||||
}
|
||||
double frame_percentile_ms(double quantile) const {
|
||||
return profile_percentile_ms(totals_,quantile);
|
||||
}
|
||||
const ProfileTotals& totals() const { return totals_; }
|
||||
bool enabled() const { return enabled_; }
|
||||
private:
|
||||
bool enabled_{};
|
||||
std::uint64_t frame_{};
|
||||
ProfileTotals totals_{};
|
||||
};
|
||||
class ProfileScope {
|
||||
public:
|
||||
ProfileScope(RuntimeProfiler* profiler,bool active,ProfileStage stage)
|
||||
: profiler_(active?profiler:nullptr),stage_(stage),start_(profiler_?Clock::now():Clock::time_point{}) {}
|
||||
~ProfileScope() { if(profiler_) profiler_->add(stage_,std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now()-start_).count()); }
|
||||
std::uint64_t elapsed_ns() const {
|
||||
return profiler_?std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now()-start_).count():0;
|
||||
}
|
||||
private:
|
||||
using Clock=std::chrono::steady_clock;
|
||||
RuntimeProfiler* profiler_{}; ProfileStage stage_{}; Clock::time_point start_{};
|
||||
};
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "FluidSim/Fluid.hpp"
|
||||
#include "FluidSim/OutdoorAudio.hpp"
|
||||
#include "FluidSim/Solver.hpp"
|
||||
#include "FluidSim/RuntimeProfiler.hpp"
|
||||
#include "FluidSim/Vehicle.hpp"
|
||||
#include "FluidSim/MotorcycleTest.hpp"
|
||||
#include <memory>
|
||||
@@ -35,13 +36,22 @@ public:
|
||||
int cylinder_count() const { return engine_config.cylinders; }
|
||||
std::array<FourStrokeCylinder*, 12> cylinders() { return {&cylinder1, &cylinder2, &cylinder3, &cylinder4,
|
||||
&cylinder5, &cylinder6, &cylinder7, &cylinder8,&cylinder9,&cylinder10,&cylinder11,&cylinder12}; }
|
||||
std::array<const FourStrokeCylinder*, 12> cylinders() const { return {&cylinder1, &cylinder2, &cylinder3, &cylinder4,
|
||||
&cylinder5, &cylinder6, &cylinder7, &cylinder8,&cylinder9,&cylinder10,&cylinder11,&cylinder12}; }
|
||||
AudioFrame process();
|
||||
void enable_profiling(bool enabled) { profiler_.enable(enabled); }
|
||||
const ProfileTotals& profile_totals() const { return profiler_.totals(); }
|
||||
void set_controls(float throttle_value, float load_value, float clutch_value);
|
||||
void set_audio_scene(OutdoorScene scene);
|
||||
void set_listener(AudioListener listener);
|
||||
void set_pipe_solver(PipeSolver solver);
|
||||
void set_monitor_filter(bool enabled);
|
||||
void set_starter(bool engaged);
|
||||
// Replaces calibration at a simulation step boundary, preserving all state.
|
||||
void set_tuning(const EngineConfig& tuning);
|
||||
const auto& source_audio() const { return audio_.source_frames(); }
|
||||
AudioFrame tail_audio() const { return audio_.tail_frame(); }
|
||||
void set_audio_source_enabled(std::size_t index,bool enabled) { audio_.set_source_enabled(index,enabled); }
|
||||
AudioFrame dry_audio() const;
|
||||
AudioFrame unfiltered_audio() const;
|
||||
void shift_up();
|
||||
@@ -69,6 +79,12 @@ private:
|
||||
BoundarySystem boundaries_;
|
||||
Solver solver_;
|
||||
OutdoorAudio audio_;
|
||||
RuntimeProfiler profiler_;
|
||||
std::shared_ptr<const PhysicalGeometry> geometry_;
|
||||
std::shared_ptr<const EngineConfig> active_tuning_;
|
||||
std::array<float,181> intake_lift_trace_{},exhaust_lift_trace_{};
|
||||
float last_contact_impulse_{};
|
||||
float valve_sound_displacement_{},valve_sound_velocity_{};
|
||||
mutable std::mutex mutex_;
|
||||
std::vector<std::unique_ptr<Junction>> exhaust_junctions_;
|
||||
std::unique_ptr<Carburetor> carb_;
|
||||
|
||||
@@ -16,8 +16,13 @@ struct ScenarioExample {
|
||||
EngineConfig engine{};
|
||||
std::string category;
|
||||
int order{};
|
||||
std::filesystem::path source_path;
|
||||
};
|
||||
ScenarioExample load_engine_file(const std::filesystem::path& path);
|
||||
void migrate_engine_geometry(const std::filesystem::path& path,bool relayout=false);
|
||||
// Writes a distinct, validated engine file; never overwrites a preset.
|
||||
std::filesystem::path save_tuned_engine(const ScenarioExample& source,const EngineConfig& tuning,
|
||||
const std::filesystem::path& directory);
|
||||
std::vector<ScenarioExample> load_engine_directory(const std::filesystem::path& directory);
|
||||
// FLUIDSIM_ENGINE_DIR overrides discovery. Otherwise search the working directory,
|
||||
// beside the executable, then the source tree for developer tools.
|
||||
|
||||
@@ -7,10 +7,11 @@ struct ScenarioSnapshot;
|
||||
// Fractions refer to simulated pipe length; positions are world metres.
|
||||
// Both the pipe mesh and its acoustic mouths use these same routes.
|
||||
struct PipeRoute {
|
||||
std::array<Vec3, 5> points{};
|
||||
std::array<float, 5> fractions{};
|
||||
std::array<Vec3, 64> points{};
|
||||
std::array<float, 64> fractions{};
|
||||
unsigned count{};
|
||||
};
|
||||
std::array<PipeRoute, 32> scenario_pipe_routes(const ScenarioSnapshot& state);
|
||||
bool scenario_pipe_is_exhaust(const ScenarioSnapshot& state, std::size_t pipe_index);
|
||||
std::array<Vec3, 3> scenario_sound_sources(const ScenarioSnapshot& state);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,19 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace fluidsim::port {
|
||||
struct ScenarioSnapshot {
|
||||
struct StorageVolume {std::string id;GeometryBox box;float pressure{};};
|
||||
struct PipeHousing {std::size_t pipe{};float start{},length{},diameter{};};
|
||||
std::shared_ptr<const PhysicalGeometry> geometry;
|
||||
std::vector<StorageVolume> storage_volumes;
|
||||
std::vector<PipeHousing> pipe_housings;
|
||||
float cylinder_bore{},cylinder_stroke{},cylinder_rod{},cylinder_clearance{};
|
||||
float intake_valve_diameter{},exhaust_valve_diameter{};
|
||||
std::string example_name;
|
||||
float cells_per_meter{};
|
||||
EngineLayout layout{EngineLayout::Inline};
|
||||
float bank_angle{};
|
||||
bool v8_headers{};
|
||||
@@ -20,6 +29,8 @@ struct ScenarioSnapshot {
|
||||
float rev_limit_rpm{10000};
|
||||
std::array<float, 12> cylinder_angles{};
|
||||
std::array<float, 12> cylinder_pressures{}, piston_fractions{}, intake_areas{}, exhaust_areas{};
|
||||
std::array<float,12> intake_lifts{},exhaust_lifts{};
|
||||
std::uint64_t junction_fallbacks{}, junction_iterations{}, boundary_limited_fluxes{}, junction_limited_fluxes{};
|
||||
std::uint64_t solver_substeps{}, boundary_iterations{}, pipe_positivity_repairs{};
|
||||
float rpm{}, speed_kmh{}, kinetic_energy{}, average_power{}, average_torque{};
|
||||
float cylinder_pressure1{}, cylinder_pressure2{};
|
||||
@@ -30,6 +41,10 @@ struct ScenarioSnapshot {
|
||||
std::array<float,2> crossover_pressures{};
|
||||
float throttle{}, pedal{}, target_afr{}, clutch{}, intake_flow{}, exhaust_flow{};
|
||||
bool idle_control{}, fuel_cut{}, ignition_cut{}, two_stroke{}, reed_open{};
|
||||
bool valve_float{};
|
||||
// Cylinder 1 lift over the most recently sampled 720 degree cycle (4 degree bins, metres).
|
||||
std::array<float,181> intake_cam_lifts{},exhaust_cam_lifts{},intake_lift_trace{},exhaust_lift_trace{};
|
||||
float intake_lift{},exhaust_lift{},valve_contact_impulse{};
|
||||
bool racing_exhaust{};
|
||||
bool silencers{}, h_pipe{};
|
||||
ExhaustConfig exhaust_config{};
|
||||
|
||||
@@ -46,7 +46,7 @@ inline Pipe1D make_silenced_exhaust(const ExhaustConfig& c) {
|
||||
add(c.outlet_length,c.diameter,c.diameter);
|
||||
auto pipe=make_profiled_pipe(sections,c.cell_length);
|
||||
for(std::size_t i=0;i<sections.size();++i) {
|
||||
const int n=int(std::ceil(sections[i].length/c.cell_length));
|
||||
const int n=profile_section_cells(sections[i].length,c.cell_length);
|
||||
for(int j=0;j<n;++j) { pipe.linear_resistance.push_back(linear[i]);pipe.quadratic_resistance.push_back(quadratic[i]); }
|
||||
}
|
||||
return pipe;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "FluidSim/Component.hpp"
|
||||
#include "FluidSim/Fluid.hpp"
|
||||
#include "FluidSim/RuntimeProfiler.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
@@ -13,13 +14,15 @@ public:
|
||||
std::uint64_t substep_count() const { return substep_count_; }
|
||||
int minimum_substeps{4};
|
||||
void add_component(Component& component);
|
||||
void step(float dt);
|
||||
void set_profiler(RuntimeProfiler* profiler) { profiler_=profiler; }
|
||||
void step(float dt,bool profile_sample=false);
|
||||
std::uint64_t step_count() const { return step_count_; }
|
||||
private:
|
||||
std::vector<Pipe1D>& pipes_;
|
||||
BoundarySystem& boundaries_;
|
||||
std::vector<Component*> components_;
|
||||
std::uint64_t step_count_{}, substep_count_{};
|
||||
RuntimeProfiler* profiler_{};
|
||||
};
|
||||
|
||||
} // namespace fluidsim::port
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
#include "FluidSim/MeshResolution.hpp"
|
||||
#include "FluidSim/PipeProfile.hpp"
|
||||
#include "FluidSim/Ecu.hpp"
|
||||
#include "FluidSim/Vehicle.hpp"
|
||||
#include "FluidSim/PhysicalGeometry.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace fluidsim::port {
|
||||
@@ -10,6 +12,8 @@ enum class TwoStrokeExhaust { Racing, Straight };
|
||||
// YZ125-sized baseline. Port/chamber/combustion dimensions are explicit design
|
||||
// estimates, not a measured Yamaha cylinder or factory exhaust/ignition map.
|
||||
struct TwoStrokeConfig {
|
||||
PhysicalGeometry geometry;
|
||||
float cells_per_meter{}; // Zero retains legacy programmatic meshes. TOML scenarios specify a density.
|
||||
EcuConfig ecu=[] {
|
||||
EcuConfig e;
|
||||
e.idle_control=EcuConfig::IdleControl::FixedOpening;
|
||||
@@ -42,6 +46,7 @@ struct TwoStrokeConfig {
|
||||
float jet_scale{1.f}; // multiplier on effective jet diameters
|
||||
float crankcase_clearance{150e-6f};
|
||||
float carburetor_diameter{.0381f};
|
||||
float reed_pipe_diameter{.040f},transfer_pipe_diameter{.032f};
|
||||
float idle_spark_gain{.05f}; // spark degrees per RPM error at the fixed carb stop
|
||||
float idle_minimum_advance{-10.f};
|
||||
float idle_slide_opening{.045f}; // fixed mechanical stop, normalized 0..1 (4.5%)
|
||||
|
||||
@@ -23,6 +23,9 @@ public:
|
||||
void set_crankcase(Crankcase& crankcase) { crankcase_ = &crankcase; }
|
||||
void set_carburetor(Carburetor& carburetor) { carburetor_ = &carburetor; }
|
||||
float transfer_width{.050f}, exhaust_width{.036f};
|
||||
// Retained as two-stroke compatibility metadata; port areas come from the
|
||||
// transfer and exhaust geometry above rather than poppet valve motion.
|
||||
float intake_valve_lift{}, exhaust_valve_lift{};
|
||||
float minimum_burn_seconds{.0008f};
|
||||
std::uint64_t combustion_count() const { return combustion_count_; }
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "FluidSim/Carburetor.hpp"
|
||||
#include "FluidSim/Fluid.hpp"
|
||||
#include "FluidSim/OutdoorAudio.hpp"
|
||||
#include "FluidSim/RuntimeProfiler.hpp"
|
||||
#include "FluidSim/Ecu.hpp"
|
||||
#include "FluidSim/ReedValve.hpp"
|
||||
#include "FluidSim/MotorcycleTest.hpp"
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <vector>
|
||||
|
||||
namespace fluidsim::port {
|
||||
struct ScenarioSnapshot;
|
||||
|
||||
struct TwoStrokeSnapshot {
|
||||
float rpm{}, cylinder_pressure{}, crankcase_pressure{}, intake_pressure{};
|
||||
@@ -31,6 +33,8 @@ public:
|
||||
void set_listener(AudioListener listener) { audio_.set_listener(listener); }
|
||||
explicit TwoStrokeScenario(int sample_rate = 44100, TwoStrokeConfig config = {});
|
||||
AudioFrame process();
|
||||
void enable_profiling(bool enabled) { profiler_.enable(enabled); }
|
||||
const ProfileTotals& profile_totals() const { return profiler_.totals(); }
|
||||
void set_throttle(float value);
|
||||
void set_controls(float pedal, float load_value, float clutch_value);
|
||||
void shift_up() { vehicle.shift_up(); }
|
||||
@@ -39,9 +43,13 @@ public:
|
||||
void set_pipe_solver(PipeSolver solver) { for(auto& pipe : pipes) pipe.solver=solver; }
|
||||
void set_audio_scene(OutdoorScene scene) { audio_.set_scene(scene); }
|
||||
void set_monitor_filter(bool enabled) { audio_.set_monitor_filter(enabled); }
|
||||
const auto& source_audio() const { return audio_.source_frames(); }
|
||||
AudioFrame tail_audio() const { return audio_.tail_frame(); }
|
||||
void set_audio_source_enabled(std::size_t index,bool enabled) { audio_.set_source_enabled(index,enabled); }
|
||||
AudioFrame dry_audio() const { return audio_.dry_frame(); }
|
||||
AudioFrame unfiltered_audio() const { return audio_.unfiltered_frame(); }
|
||||
TwoStrokeSnapshot snapshot() const;
|
||||
void capture_geometry(ScenarioSnapshot&) const;
|
||||
|
||||
float throttle{};
|
||||
const TwoStrokeConfig configuration;
|
||||
@@ -65,6 +73,8 @@ private:
|
||||
BoundarySystem boundaries_;
|
||||
Solver solver_;
|
||||
OutdoorAudio audio_;
|
||||
RuntimeProfiler profiler_;
|
||||
std::shared_ptr<const PhysicalGeometry> geometry_;
|
||||
|
||||
static float area_for_diameter(float diameter);
|
||||
static float slide_area(float diameter, float opening);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "FluidSim/SoundEngine.hpp"
|
||||
#include "FluidSim/Desktop/DesktopUi.hpp"
|
||||
#include "FluidSim/Desktop/ScenarioMenu.hpp"
|
||||
#include "FluidSim/Desktop/PlaybackControl.hpp"
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <algorithm>
|
||||
@@ -11,10 +12,12 @@
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <future>
|
||||
#include <iomanip>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace {
|
||||
using namespace fluidsim::port;
|
||||
@@ -31,13 +34,15 @@ constexpr float throttle_lerp_rate = 10.0f;
|
||||
int main(int argc, char** argv) try {
|
||||
using namespace fluidsim::port;
|
||||
bool scenario_from_args=false;
|
||||
const auto& examples=scenario_examples();
|
||||
std::string junction_model;
|
||||
std::optional<float> junction_loss;
|
||||
auto examples=scenario_examples();
|
||||
auto selected=examples.front();
|
||||
PipeSolver selected_solver=PipeSolver::Rusanov;
|
||||
OutdoorScene selected_scene=OutdoorScene::Wall;
|
||||
for(int i=1;i<argc;++i){
|
||||
const std::string option=argv[i];
|
||||
if((option=="--example"||option=="--scenario"||option=="--scene"||option=="--exhaust"||option=="--solver")&&i+1<argc){
|
||||
if((option=="--example"||option=="--scenario"||option=="--scene"||option=="--exhaust"||option=="--solver"||option=="--junctions"||option=="--junction-loss")&&i+1<argc){
|
||||
const std::string value=argv[++i];
|
||||
if(option=="--example") {
|
||||
const auto found=std::find_if(examples.begin(),examples.end(),[&](const auto& e){return e.id==value;});
|
||||
@@ -47,7 +52,7 @@ int main(int argc, char** argv) try {
|
||||
if(value!="twin"&&value!="two-stroke"&&value!="b205"&&value!="v8"){std::cerr<<"Choose twin, two-stroke, b205 or v8\n";return 2;}
|
||||
selected=scenario_example(value=="v8"?"v8-h":value=="b205"?"saab-straight":value=="two-stroke"?"yz-racing":"twin");
|
||||
scenario_from_args=true;
|
||||
}else if(option=="--solver"){
|
||||
}else if(option=="--solver"||option=="--junctions"||option=="--junction-loss"){
|
||||
try { selected_solver=parse_pipe_solver(value); }
|
||||
catch(const std::exception& e) { std::cerr<<e.what()<<"\n"; return 2; }
|
||||
}else if(option=="--exhaust"){
|
||||
@@ -62,15 +67,15 @@ int main(int argc, char** argv) try {
|
||||
else if(value=="tunnel")selected_scene=OutdoorScene::Tunnel;
|
||||
else {std::cerr<<"Choose dry, field, wall, woodland or tunnel\n";return 2;}
|
||||
}
|
||||
}else{std::cerr<<"Usage: fluidsim_desktop [--example catalog-id] [--scenario twin|two-stroke|b205|v8] [--scene dry|field|wall|woodland|tunnel] [--exhaust racing|straight] [--solver rusanov|hlle|hllc]\n";return 2;}
|
||||
}else{std::cerr<<"Usage: fluidsim_desktop [--example catalog-id] [--scenario twin|two-stroke|b205|v8] [--scene dry|field|wall|woodland|tunnel] [--exhaust racing|straight] [--solver rusanov|hlle|hllc|muscl] [--junctions volume|characteristic|legacy] [--junction-loss 0..10]\n";return 2;}
|
||||
}
|
||||
const sf::Vector2u initial_size = scenario_from_args ? sf::Vector2u{window_width, window_height}
|
||||
: sf::Vector2u{720, 606};
|
||||
sf::ContextSettings context;
|
||||
context.depthBits=24;context.antiAliasingLevel=4;context.majorVersion=2;context.minorVersion=1;
|
||||
sf::RenderWindow window(sf::VideoMode(initial_size), "FluidSim",sf::Style::Default,sf::State::Windowed,context);
|
||||
window.setVerticalSyncEnabled(false);
|
||||
window.setFramerateLimit(60);
|
||||
window.setFramerateLimit(0);
|
||||
window.setVerticalSyncEnabled(true);
|
||||
window.setKeyRepeatEnabled(false);
|
||||
|
||||
sf::Font font;
|
||||
@@ -85,6 +90,7 @@ int main(int argc, char** argv) try {
|
||||
if(!has_font)std::cerr<<"No UI font available; configure FLUIDSIM_FONT_FILE.\n";
|
||||
const sf::Font* font_ptr=has_font?&font:nullptr;
|
||||
|
||||
std::unordered_map<std::string,float> scenario_resolution;
|
||||
while (window.isOpen()) {
|
||||
if (!scenario_from_args) {
|
||||
window.setTitle("FluidSim - Examples");
|
||||
@@ -99,13 +105,20 @@ int main(int argc, char** argv) try {
|
||||
scenario_from_args=false;
|
||||
window.setTitle("FluidSim - "+selected.title);
|
||||
window.setMinimumSize(sf::Vector2u{1040,800});
|
||||
if(!junction_model.empty()) selected.junctions.model=junction_model;
|
||||
if(junction_loss) selected.junctions.turning_loss=*junction_loss;
|
||||
if(selected.kind==ScenarioKind::TwoStroke && (!junction_model.empty() || junction_loss))
|
||||
throw std::invalid_argument("two-stroke exhaust has no configurable pipe junctions");
|
||||
if(const auto found=scenario_resolution.find(selected.id);found!=scenario_resolution.end())
|
||||
selected.engine.cells_per_meter=selected.two.cells_per_meter=found->second;
|
||||
DesktopScenario scenario(selected);
|
||||
scenario.set_pipe_solver(selected_solver);
|
||||
scenario.set_audio_scene(selected_scene);
|
||||
desktop::DesktopUi ui;
|
||||
ui.configure_resolution(selected.kind==ScenarioKind::TwoStroke?selected.two.cells_per_meter:selected.engine.cells_per_meter);
|
||||
scenario.set_listener(ui.listener(scenario.snapshot(),window.getSize()));
|
||||
std::cout << "Desktop started: scenario=" << selected.id
|
||||
<< " solver=" << pipe_solver_name(selected_solver) << " scene=" << scene_name(selected_scene) << std::endl;
|
||||
<< " junctions=" << selected.junctions.model << " solver=" << pipe_solver_name(selected_solver) << " scene=" << scene_name(selected_scene) << std::endl;
|
||||
SimulationRingBuffer ring(ring_capacity);
|
||||
for (std::size_t i = 0; i < preroll_samples; ++i) {
|
||||
const AudioFrame audio = scenario.process();
|
||||
@@ -117,8 +130,10 @@ int main(int argc, char** argv) try {
|
||||
audio.set_volume(100.0f);
|
||||
audio.start();
|
||||
std::jthread simulation([&](std::stop_token stop) {
|
||||
constexpr std::size_t batch_size = 512;
|
||||
while (ring.wait_for_space(target_fill - batch_size, stop)) {
|
||||
while(!stop.stop_requested()) {
|
||||
// Keep bursts short in wall time even at 0.01x playback.
|
||||
const auto batch_size=std::clamp<std::size_t>(static_cast<std::size_t>(std::ceil(128*audio.speed())),1,128);
|
||||
if(!ring.wait_for_space(target_fill-batch_size,stop))break;
|
||||
for (std::size_t i = 0; i < batch_size; ++i) {
|
||||
const AudioFrame frame = scenario.process();
|
||||
if (!ring.write(frame.left, frame.right, stop)) return;
|
||||
@@ -126,15 +141,14 @@ int main(int argc, char** argv) try {
|
||||
}
|
||||
});
|
||||
|
||||
double desired_speed = 1.0;
|
||||
double current_speed = desired_speed;
|
||||
double last_normal_speed = 1.0;
|
||||
bool time_warp = false;
|
||||
desktop::PlaybackControl playback_control;
|
||||
double current_speed = 1.0;
|
||||
float throttle_current = 0.0f;
|
||||
float brake_target = 0.0f, brake_current = 0.0f;
|
||||
float clutch_current = 0.0f;
|
||||
bool throttle_held = false, throttle_down = false, clutch_held = false;
|
||||
auto previous_frame = std::chrono::steady_clock::now();
|
||||
std::future<void> pipe_rebuild;
|
||||
|
||||
bool return_to_menu=false;
|
||||
while (window.isOpen() && !return_to_menu) {
|
||||
@@ -144,19 +158,12 @@ int main(int argc, char** argv) try {
|
||||
return_to_menu=true;
|
||||
break;
|
||||
}
|
||||
if(playback_control.handle_event(*event,sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LShift)||sf::Keyboard::isKeyPressed(sf::Keyboard::Key::RShift)))continue;
|
||||
if(ui.handle_event(*event,window.getSize())) continue;
|
||||
if(event->is<sf::Event::FocusLost>()) { throttle_held=false; throttle_down=false; clutch_held=false; scenario.set_starter(false); }
|
||||
if (event->is<sf::Event::Closed>()) window.close();
|
||||
if (const auto* key = event->getIf<sf::Event::KeyPressed>()) {
|
||||
switch (key->code) {
|
||||
case sf::Keyboard::Key::Space:
|
||||
time_warp = !time_warp;
|
||||
if (!time_warp) { desired_speed = last_normal_speed; }
|
||||
break;
|
||||
case sf::Keyboard::Key::PageUp:
|
||||
if(!time_warp) {desired_speed=std::min(1.,desired_speed*1.1);last_normal_speed=desired_speed;} break;
|
||||
case sf::Keyboard::Key::PageDown:
|
||||
if(!time_warp) {desired_speed=std::max(.0001,desired_speed/1.1);last_normal_speed=desired_speed;} break;
|
||||
case sf::Keyboard::Key::W: throttle_held = true; break;
|
||||
case sf::Keyboard::Key::V: scenario.set_starter(true); break;
|
||||
case sf::Keyboard::Key::C: clutch_held = true; break;
|
||||
@@ -169,7 +176,7 @@ int main(int argc, char** argv) try {
|
||||
case sf::Keyboard::Key::Z: scenario.set_neutral(); break;
|
||||
case sf::Keyboard::Key::S: throttle_down=true; break;
|
||||
case sf::Keyboard::Key::F3:
|
||||
selected_solver=static_cast<PipeSolver>((static_cast<int>(selected_solver)+1)%3);
|
||||
selected_solver=static_cast<PipeSolver>((static_cast<int>(selected_solver)+1)%4);
|
||||
scenario.set_pipe_solver(selected_solver);
|
||||
std::cout << "Pipe solver: " << pipe_solver_name(selected_solver) << std::endl;
|
||||
break;
|
||||
@@ -192,10 +199,24 @@ int main(int argc, char** argv) try {
|
||||
|
||||
if (!window.isOpen() || return_to_menu) break;
|
||||
|
||||
if(pipe_rebuild.valid() && pipe_rebuild.wait_for(std::chrono::seconds(0))==std::future_status::ready) {
|
||||
try {
|
||||
pipe_rebuild.get();const float density=scenario.snapshot().cells_per_meter;
|
||||
scenario_resolution[selected.id]=density;
|
||||
ui.resolution_finished(density,"Mesh applied. Engine restarted.");
|
||||
} catch(const std::exception& error) {
|
||||
ui.resolution_finished(scenario.snapshot().cells_per_meter,error.what());
|
||||
}
|
||||
}
|
||||
if(auto density=ui.take_resolution_request();density && !pipe_rebuild.valid()) {
|
||||
ui.resolution_started();
|
||||
pipe_rebuild=std::async(std::launch::async,[&scenario,value=*density] {scenario.set_cells_per_meter(value);});
|
||||
}
|
||||
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const float frame_dt = std::chrono::duration<float>(now - previous_frame).count();
|
||||
previous_frame = now;
|
||||
const double target_speed = time_warp ? 1.0 : desired_speed;
|
||||
const double target_speed = playback_control.target_speed();
|
||||
current_speed += (target_speed - current_speed) * (1.0 - std::exp(-8.0 * frame_dt));
|
||||
audio.set_speed(current_speed);
|
||||
|
||||
@@ -208,16 +229,18 @@ int main(int argc, char** argv) try {
|
||||
scenario.set_controls(throttle_current, brake_current, clutch_current);
|
||||
|
||||
const desktop::PlaybackInfo playback{throttle_current,brake_current,current_speed,
|
||||
ring.available_samples(),ring_capacity,audio.underrun_blocks(),audio.auto_gain(),time_warp};
|
||||
ring.available_samples(),ring_capacity,audio.underrun_blocks(),audio.auto_gain(),!playback_control.realtime()};
|
||||
const auto state=scenario.snapshot();
|
||||
scenario.set_listener(ui.listener(state,window.getSize()));
|
||||
ui.draw(window,font_ptr,state,playback);
|
||||
window.display();
|
||||
|
||||
}
|
||||
|
||||
simulation.request_stop();
|
||||
audio.stop();
|
||||
simulation.join();
|
||||
if(pipe_rebuild.valid())try {pipe_rebuild.get();scenario_resolution[selected.id]=scenario.snapshot().cells_per_meter;}catch(const std::exception& error){std::cerr<<"Pipe rebuild: "<<error.what()<<'\n';}
|
||||
}
|
||||
return 0;
|
||||
} catch(const std::exception& error) {
|
||||
|
||||
@@ -26,9 +26,16 @@ WorkspaceLayout WorkspaceLayout::calculate(sf::Vector2u size) {
|
||||
{{left,bottom},{content*.60f-8,178}},{{left+content*.60f+8,bottom},{content*.40f-8,178}},{{32,h<800?382.f:414.f},{side-32,26}}};
|
||||
}
|
||||
bool DesktopUi::handle_event(const sf::Event& event,sf::Vector2u size) {
|
||||
const auto layout=WorkspaceLayout::calculate(size);
|
||||
|
||||
const auto layout=workspace_layout(size);
|
||||
const auto set_pedal=[&](int x) {pedal_.set((x-layout.pedal.position.x)/layout.pedal.size.x);};
|
||||
if(const auto* p=event.getIf<sf::Event::MouseButtonPressed>()) {
|
||||
const auto buttons=resolution_buttons(size);
|
||||
if(p->button==sf::Mouse::Button::Left) for(int i=0;i<2;++i)
|
||||
if(buttons[i].contains(sf::Vector2f(p->position))) {
|
||||
if(!resolution_busy_) resolution_request_=std::clamp(resolution_+(i==0?-5.f:5.f),1.f,500.f);
|
||||
return true;
|
||||
}
|
||||
if(p->button==sf::Mouse::Button::Left && layout.pedal.contains(sf::Vector2f(p->position))) {
|
||||
pedal_drag_=true;set_pedal(p->position.x);return true;
|
||||
}
|
||||
@@ -61,20 +68,46 @@ bool DesktopUi::handle_event(const sf::Event& event,sf::Vector2u size) {
|
||||
return false;
|
||||
}
|
||||
AudioListener DesktopUi::listener(const ScenarioSnapshot& s,sf::Vector2u size) {
|
||||
const auto viewport=WorkspaceLayout::calculate(size).viewport;
|
||||
if(!camera_fitted_) {
|
||||
camera_.reset(viewport.size.x/(viewport.size.y-56));
|
||||
camera_fitted_=true;
|
||||
const auto viewport=workspace_layout(size).viewport;
|
||||
fit_camera(viewport.size.x/(viewport.size.y-56),s);
|
||||
return camera_.listener();
|
||||
}
|
||||
WorkspaceLayout DesktopUi::workspace_layout(sf::Vector2u size) const {
|
||||
return WorkspaceLayout::calculate(size);
|
||||
}
|
||||
std::array<sf::FloatRect,2> DesktopUi::resolution_buttons(sf::Vector2u size) {
|
||||
const auto layout=WorkspaceLayout::calculate(size);
|
||||
const float y=layout.pedal.position.y+40+12+28+(size.y<800?19.f:23.f);
|
||||
return {sf::FloatRect{{162,y-2},{24,19}},sf::FloatRect{{240,y-2},{24,19}}};
|
||||
}
|
||||
void DesktopUi::fit_camera(float aspect,const ScenarioSnapshot& s) {
|
||||
if(!camera_fitted_ || std::abs(camera_aspect_-aspect)>.01f) {
|
||||
camera_.reset(aspect);camera_fitted_=true;camera_aspect_=aspect;
|
||||
if(s.geometry) {
|
||||
Vec3 lo{1e9f,1e9f,1e9f},hi{-1e9f,-1e9f,-1e9f};
|
||||
const auto include=[&](Vec3 p) {lo={std::min(lo.x,p.x),std::min(lo.y,p.y),std::min(lo.z,p.z)};hi={std::max(hi.x,p.x),std::max(hi.y,p.y),std::max(hi.z,p.z)};};
|
||||
for(const auto& pipe:s.geometry->pipes)for(auto point:pipe.points)include(point);
|
||||
for(const auto& v:s.storage_volumes){include(v.box.minimum());include(v.box.maximum());}
|
||||
for(const auto& c:s.geometry->cylinders){include(c.origin);include(cylinder_point(c,{0,s.cylinder_rod+s.cylinder_stroke*.5f,0}));}
|
||||
camera_.target={(lo.x+hi.x)*.5f,(lo.y+hi.y)*.5f,(lo.z+hi.z)*.5f};
|
||||
const float yaw=camera_.yaw*.017453293f,pitch=camera_.pitch*.017453293f;
|
||||
float distance=.35f;
|
||||
for(int corner=0;corner<8;++corner) {
|
||||
const Vec3 p{(corner&1?hi.x:lo.x)-camera_.target.x,(corner&2?hi.y:lo.y)-camera_.target.y,(corner&4?hi.z:lo.z)-camera_.target.z};
|
||||
const float x=std::cos(yaw)*p.x+std::sin(yaw)*p.z,z=-std::sin(yaw)*p.x+std::cos(yaw)*p.z;
|
||||
const float y=std::cos(pitch)*p.y-std::sin(pitch)*z,depth=std::sin(pitch)*p.y+std::cos(pitch)*z;
|
||||
distance=std::max(distance,depth+1.12f*std::max((std::abs(x)+.035f)/(.414214f*aspect),(std::abs(y)+.035f)/.414214f));
|
||||
}
|
||||
camera_.distance=distance;
|
||||
}
|
||||
}
|
||||
return camera_.listener(s.silencers?1.8f:s.cylinder_count==8?1.4f:1.f,
|
||||
s.silencers?1.1f:s.cylinder_count==8?.7f:0.f);
|
||||
}
|
||||
void DesktopUi::draw(sf::RenderWindow& w,const sf::Font* font,const ScenarioSnapshot& s,const PlaybackInfo& p) {
|
||||
const auto size=w.getSize();const float width=float(size.x),height=float(size.y);
|
||||
w.setView(sf::View(sf::FloatRect({0,0},{width,height})));w.clear(background);
|
||||
const auto l=WorkspaceLayout::calculate(size);
|
||||
const auto l=workspace_layout(size);
|
||||
label(w,font,"FLUIDSIM",20,15,24,accent);label(w,font,"ENGINE WORKSPACE",20,48,10,muted);
|
||||
label(w,font,title(s),l.viewport.position.x+2,22,19);label(w,font,"LIVE / "+number(float(p.speed),3)+"x",width-160,25,14,accent);
|
||||
label(w,font,title(s),l.viewport.position.x+2,22,19);label(w,font,std::string(p.time_warp?"MANUAL / ":"REALTIME / ")+number(float(p.speed),3)+"x",width-192,25,14,accent);
|
||||
box(w,l.sidebar);box(w,l.viewport);box(w,l.chart);box(w,l.inspector);
|
||||
const float x=32;float y=97;
|
||||
label(w,font,"ENGINE",x,y,11,accent);y+=25;
|
||||
@@ -92,14 +125,22 @@ void DesktopUi::draw(sf::RenderWindow& w,const sf::Font* font,const ScenarioSnap
|
||||
box(w,{{l.pedal.position.x+l.pedal.size.x*p.pedal_target-5,l.pedal.position.y+2},{10,22}},sf::Color(225,225,225));
|
||||
y=l.pedal.position.y+40;
|
||||
y+=12;label(w,font,"AUDIO & SIMULATION",x,y,11,accent);y+=28;
|
||||
row("Solver [F3]",pipe_solver_name(s.pipe_solver));row("Scene [R]",scene_name(s.audio_scene));row("Auto gain [G]",p.auto_gain?"On":"Off");
|
||||
row("Solver [F3]",pipe_solver_name(s.pipe_solver));
|
||||
const auto buttons=resolution_buttons(size);
|
||||
label(w,font,"Cells/m",x,y,12,muted);
|
||||
box(w,buttons[0]);box(w,buttons[1]);
|
||||
label(w,font,"-",buttons[0].position.x+7,buttons[0].position.y,13);
|
||||
label(w,font,"+",buttons[1].position.x+7,buttons[1].position.y,13);
|
||||
label(w,font,number(resolution_),192,y,12);
|
||||
y+=height<800?19.f:23.f;
|
||||
row("Scene [R]",scene_name(s.audio_scene));row("Auto gain [G]",p.auto_gain?"On":"Off");
|
||||
row("Buffer",std::to_string(p.buffered)+" / "+std::to_string(p.capacity));row("Underruns",std::to_string(p.underruns));
|
||||
label(w,font,s.fuel_cut?"FUEL CUT":s.ignition_cut?"IGNITION CUT":s.idle_control?"IDLE CONTROL":"RUNNING",x,y+8,12,(s.fuel_cut||s.ignition_cut)?sf::Color(255,171,96):accent);
|
||||
if(height>=800) label(w,font,"W/S Raise / lower pedal\nA/D Shift Z Neutral\nC Clutch V Starter\nArrows Load End Release\nPgUp/Dn Speed Space 1x",x,height-141,11,muted);
|
||||
label(w,font,three_d_?"ENGINE VIEW / 3D":"ENGINE VIEW / SCHEMATIC",l.viewport.position.x+16,93,11,accent);
|
||||
label(w,font,three_d_?"Drag: orbit Right: pan Scroll: zoom Home: fit Tab: 2D":"Drag: pan Scroll: zoom Home: reset Tab: 3D",l.viewport.position.x+16,117,11,muted);
|
||||
label(w,font,s.valve_float?"VALVE FLOAT":s.fuel_cut?"FUEL CUT":s.ignition_cut?"IGNITION CUT":s.idle_control?"IDLE CONTROL":"RUNNING",x,y+8,12,(s.valve_float||s.fuel_cut||s.ignition_cut)?sf::Color(255,171,96):accent);
|
||||
if(height>=800) label(w,font,"W/S Raise / lower pedal\nA/D Shift Z Neutral\nC Clutch V Starter\nArrows Load End Release\nSpace Realtime / manual\nShift+scroll / PgUp/Dn speed",x,height-141,11,muted);
|
||||
label(w,font,three_d_?"ENGINE GEOMETRY / 3D":"ENGINE GEOMETRY / 2D",l.viewport.position.x+16,93,11,accent);
|
||||
label(w,font,l.viewport.size.x<600?"Drag: orbit Scroll: zoom Tab: 2D":three_d_?"Drag: orbit Right: pan Scroll: zoom Home: fit Tab: 2D":"Drag: pan Scroll: zoom Home: reset Tab: 3D",l.viewport.position.x+16,117,11,muted);
|
||||
const sf::FloatRect drawing{{l.viewport.position.x,l.viewport.position.y+56},{l.viewport.size.x,l.viewport.size.y-56}};
|
||||
if(!camera_fitted_) {camera_.reset(drawing.size.x/drawing.size.y);camera_fitted_=true;}
|
||||
fit_camera(drawing.size.x/drawing.size.y,s);
|
||||
if(three_d_) renderer_.draw(w,s,drawing,camera_);
|
||||
else {
|
||||
sf::View view(sf::FloatRect({0,0},{1280,600}));
|
||||
@@ -122,7 +163,8 @@ void DesktopUi::draw(sf::RenderWindow& w,const sf::Font* font,const ScenarioSnap
|
||||
label(w,font,std::to_string(i+1)+" "+number(pressure/1000)+" "+number(stroke*100)+"% "+(intake?"O":"-")+" / "+(exhaust?"O":"-"),ix+(s.cylinder_count>8?i/6*(l.inspector.size.x/2-4):0),iy+42+(s.cylinder_count>8?i%6:i)*15,10);
|
||||
}
|
||||
label(w,font,"Esc: menu End: release pedal",20,height-29,11,muted);
|
||||
label(w,font,resolution_status_.empty()?"Cells/m changes restart the engine":resolution_status_,l.viewport.position.x+16,l.viewport.position.y+l.viewport.size.y-22,11,muted);
|
||||
label(w,font,"Pressure: blue vacuum / green atmosphere / red 1 MPa",l.viewport.position.x+2,height-29,11,muted);
|
||||
w.display();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,32 +90,61 @@ void EngineCylinder::initialize(const Crankshaft& /*crank*/) {
|
||||
}
|
||||
|
||||
float FourStrokeCylinder::valve_area(float cycle_degrees, bool inlet) const {
|
||||
const float opens = inlet ? intake_open : exhaust_open;
|
||||
float closes = inlet ? intake_close : exhaust_close;
|
||||
const float peak_lift = inlet ? intake_valve_lift : exhaust_valve_lift;
|
||||
(void)cycle_degrees;
|
||||
const float lift = inlet ? intake_lift_ : exhaust_lift_;
|
||||
const float diameter = inlet ? intake_valve_diameter : exhaust_valve_diameter;
|
||||
if (closes < opens) closes += 720.0f;
|
||||
float mapped = std::fmod(cycle_degrees, 720.0f);
|
||||
if (mapped < 0.0f) mapped += 720.0f;
|
||||
if (mapped < opens) mapped += 720.0f;
|
||||
const float duration = closes - opens;
|
||||
if (mapped < opens || mapped > closes || duration <= 0.0f) return 0.0f;
|
||||
|
||||
const float ramp = duration * 0.25f;
|
||||
const float hold = duration - 2.0f * ramp;
|
||||
float lift = 0.0f;
|
||||
if (mapped < opens + ramp) {
|
||||
const float t = (mapped - opens) / ramp;
|
||||
lift = peak_lift * t * t * (3.0f - 2.0f * t);
|
||||
} else if (mapped < opens + ramp + hold) {
|
||||
lift = peak_lift;
|
||||
} else if (ramp > 0.0f) {
|
||||
const float t = (mapped - (opens + ramp + hold)) / ramp;
|
||||
lift = peak_lift * (1.0f - t) * (1.0f - t) * (1.0f + 2.0f * t);
|
||||
}
|
||||
return pi * diameter * lift * (inlet ? intake_valve_count : exhaust_valve_count);
|
||||
}
|
||||
|
||||
void FourStrokeCylinder::set_valve_profiles(const CamProfile& ic,const ValveDynamics& iv,const CamProfile& ec,const ValveDynamics& ev) {
|
||||
intake_cam_=⁣ intake_dynamics_=iv; exhaust_cam_=&ec; exhaust_dynamics_=ev;
|
||||
}
|
||||
FourStrokeCylinder::CamPoint FourStrokeCylinder::sample_cam(const CamProfile& profile,float degrees) {
|
||||
if(profile.points.empty()) return {};
|
||||
degrees=std::fmod(degrees,720.f); if(degrees<0)degrees+=720.f;
|
||||
auto upper=std::upper_bound(profile.points.begin(),profile.points.end(),degrees,
|
||||
[](float angle,const CamPoint& point){return angle<point.angle_degrees;});
|
||||
if(upper==profile.points.begin())return *upper;
|
||||
if(upper==profile.points.end())return profile.points.back();
|
||||
const auto& b=*upper;const auto& a=*(upper-1);
|
||||
const float t=(degrees-a.angle_degrees)/(b.angle_degrees-a.angle_degrees);
|
||||
return {degrees,a.lift_metres+(b.lift_metres-a.lift_metres)*t};
|
||||
}
|
||||
float FourStrokeCylinder::advance_valve(ValveState& state,const CamProfile& cam,const ValveDynamics& d,
|
||||
bool inlet,const Crankshaft& crank,float dt) {
|
||||
const float phase_rad=phase;
|
||||
const float now=wrap_degrees((crank.angle+phase_rad)*180.f/pi);
|
||||
const float before=wrap_degrees((crank.previous_angle+phase_rad)*180.f/pi);
|
||||
const auto cam_now=sample_cam(cam,now),cam_before=sample_cam(cam,before);
|
||||
const float cam_velocity=dt>0?(cam_now.lift_metres-cam_before.lift_metres)/dt:0;
|
||||
const float count=float(inlet?intake_valve_count:exhaust_valve_count);
|
||||
const float mass=d.mass_kg*count, spring=d.spring_rate_n_per_m*count, damping=d.damping_n_s_per_m*count;
|
||||
const float diameter=inlet?intake_valve_diameter:exhaust_valve_diameter;
|
||||
const float port_pressure=inlet?intake.pressure:exhaust.pressure;
|
||||
const float pressure_force=(port_pressure-pressure)*(pi*.25f*diameter*diameter)*count;
|
||||
const float acceleration=(pressure_force-count*d.seat_force_n-spring*state.lift-damping*state.velocity)/std::max(mass,1e-7f);
|
||||
state.velocity+=acceleration*dt;
|
||||
const float old_lift=state.lift;
|
||||
state.lift+=state.velocity*dt;
|
||||
const float lower=cam_now.lift_metres;
|
||||
if(state.lift<lower || (state.lift<=lower && state.velocity<cam_velocity)) {
|
||||
const float relative=state.velocity-cam_velocity;
|
||||
if(relative<0) contact_impulse_+=mass*(-relative)*(1+d.cam_restitution);
|
||||
state.lift=lower;state.velocity=cam_velocity-std::min(relative,0.f)*d.cam_restitution;
|
||||
}
|
||||
if(state.lift<0 || (state.lift<=0 && state.velocity<0)) {
|
||||
if(state.velocity<0)contact_impulse_+=mass*(-state.velocity)*(1+d.seat_restitution);
|
||||
state.lift=0;state.velocity=std::max(0.f,-state.velocity*d.seat_restitution);
|
||||
}
|
||||
if(state.lift>d.maximum_lift_m) {
|
||||
if(state.velocity>0)contact_impulse_+=mass*state.velocity*(1+d.stop_restitution);
|
||||
state.lift=d.maximum_lift_m;state.velocity=-std::max(0.f,state.velocity)*d.stop_restitution;
|
||||
}
|
||||
state.floating=state.lift>lower+5e-5f;
|
||||
(void)old_lift;
|
||||
return state.lift;
|
||||
}
|
||||
|
||||
void FourStrokeCylinder::pre_step(Crankshaft& crank, float dt, float /*throttle*/) {
|
||||
const float rpm = crank.omega * 60.0f / (2.0f * pi);
|
||||
if (ecu) {
|
||||
@@ -127,6 +156,9 @@ void FourStrokeCylinder::pre_step(Crankshaft& crank, float dt, float /*throttle*
|
||||
}
|
||||
|
||||
const float theta = crank.angle + phase;
|
||||
if(intake_cam_) intake_lift_=advance_valve(intake_state_,*intake_cam_,intake_dynamics_,true,crank,dt);
|
||||
if(exhaust_cam_) exhaust_lift_=advance_valve(exhaust_state_,*exhaust_cam_,exhaust_dynamics_,false,crank,dt);
|
||||
intake_floating_=intake_state_.floating;exhaust_floating_=exhaust_state_.floating;
|
||||
const float previous_volume = volume;
|
||||
volume = compute_volume(theta);
|
||||
pressure = (gamma - 1.0f) * energy / std::max(volume, 1e-12f);
|
||||
@@ -141,7 +173,8 @@ void FourStrokeCylinder::pre_step(Crankshaft& crank, float dt, float /*throttle*
|
||||
|
||||
const float previous_degrees = wrap_degrees((crank.previous_angle + phase) * 180.0f / pi);
|
||||
const float current_degrees = wrap_degrees(theta * 180.0f / pi);
|
||||
if (crossed_window_close(previous_degrees, current_degrees, intake_open, intake_close)) {
|
||||
const bool intake_closed_this_step=intake_cam_ && sample_cam(*intake_cam_,previous_degrees).lift_metres>0 && sample_cam(*intake_cam_,current_degrees).lift_metres<=0;
|
||||
if (intake_closed_this_step) {
|
||||
if (!transported_fuel)
|
||||
fuel_mass = ecu ? ecu->fuel_for_air(air_mass) : air_mass / std::max(afr, 1e-6f);
|
||||
const float charge_afr = air_mass / std::max(fuel_mass, 1e-12f);
|
||||
@@ -250,10 +283,6 @@ float EngineCylinder::wrap_degrees(float value, float cycle_degrees) {
|
||||
return value < 0.0f ? value + cycle_degrees : value;
|
||||
}
|
||||
|
||||
bool EngineCylinder::crossed_window_close(float previous, float current, float open, float close) {
|
||||
return previous >= open && previous < close && current >= close;
|
||||
}
|
||||
|
||||
void EngineCylinder::update_rev_limiter(float rpm, float dt) {
|
||||
if (!rev_limit_enabled) {
|
||||
rev_limit_active = false;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
@@ -22,6 +24,7 @@ class Reader {
|
||||
std::string path_;
|
||||
public:
|
||||
Reader(const toml::table& table,std::string path):table_(table),path_(std::move(path)) {}
|
||||
const std::string& context() const {return path_;}
|
||||
[[noreturn]] void fail(const std::string& message) const { throw std::runtime_error(path_+": "+message); }
|
||||
void required(std::initializer_list<const char*> keys) const {
|
||||
for(const auto* key:keys)if(!table_.contains(key))fail(std::string("missing required field '")+key+"'");
|
||||
@@ -67,10 +70,10 @@ public:
|
||||
if(n && n->as_array()->size()>4096)fail(std::string(key)+" has too many entries");
|
||||
return n?n->as_array():nullptr;
|
||||
}
|
||||
float number(const toml::node& n) const {
|
||||
float number(const toml::node& n,double scale=1) const {
|
||||
auto value=n.value<double>();
|
||||
if(!value || !std::isfinite(*value) || std::abs(*value)>std::numeric_limits<float>::max())fail("array entries must be finite numbers");
|
||||
return static_cast<float>(*value);
|
||||
if(!value || !std::isfinite(*value) || std::abs(*value*scale)>std::numeric_limits<float>::max())fail("array entries must be finite numbers");
|
||||
return static_cast<float>(*value*scale);
|
||||
}
|
||||
void field(const char* key,std::vector<float>& values) {
|
||||
if(const auto* a=array(key)) {values.clear();for(const auto& n:*a)values.push_back(number(n));}
|
||||
@@ -84,6 +87,51 @@ template<class T> void require(bool condition,const T& where,const char* message
|
||||
if(!condition)throw std::runtime_error(std::string(where)+": "+message);
|
||||
}
|
||||
|
||||
Vec3 read_xyz(Reader& r,const toml::node& node) {
|
||||
const auto* a=node.as_array();if(!a||a->size()!=3)r.fail("coordinates require three numbers in mm");
|
||||
return {r.number(*a->get(0),.001),r.number(*a->get(1),.001),r.number(*a->get(2),.001)};
|
||||
}
|
||||
void read_geometry(Reader r,PhysicalGeometry& g) {
|
||||
if(const auto* pipes=r.array("pipes"))for(const auto& value:*pipes) {
|
||||
if(!value.is_table())r.fail("geometry pipes must be tables");
|
||||
Reader p(*value.as_table(),r.context()+".pipes");int index=-1;p.field("index",index);
|
||||
if(index!=int(g.pipes.size()))p.fail("pipe indices must be consecutive, starting at zero");
|
||||
const auto* points=p.array("points_mm");if(!points)p.fail("points_mm is required");
|
||||
GeometryPath path;for(const auto& point:*points)path.points.push_back(read_xyz(p,point));
|
||||
p.finish();g.pipes.push_back(std::move(path));
|
||||
}
|
||||
if(const auto* volumes=r.array("volumes"))for(const auto& value:*volumes) {
|
||||
if(!value.is_table())r.fail("geometry volumes must be tables");
|
||||
Reader v(*value.as_table(),r.context()+".volumes");GeometryVolume volume;v.field("id",volume.id);
|
||||
const auto* size=v.node("size_mm");const auto* center=v.node("center_mm");const auto* corners=v.array("corners_mm");
|
||||
if(corners) {
|
||||
if(size||center||corners->size()!=2)v.fail("use two corners_mm or size_mm with center_mm");
|
||||
auto a=read_xyz(v,*corners->get(0)),b=read_xyz(v,*corners->get(1));
|
||||
volume.box.center={(a.x+b.x)*.5f,(a.y+b.y)*.5f,(a.z+b.z)*.5f};
|
||||
volume.box.size={std::abs(a.x-b.x),std::abs(a.y-b.y),std::abs(a.z-b.z)};
|
||||
} else {
|
||||
if(!size)v.fail("volume requires size_mm or corners_mm");
|
||||
volume.box.size=read_xyz(v,*size);if(center)volume.box.center=read_xyz(v,*center);
|
||||
}
|
||||
v.finish();g.volumes.push_back(std::move(volume));
|
||||
}
|
||||
if(const auto* cylinders=r.array("cylinders"))for(const auto& value:*cylinders) {
|
||||
if(!value.is_table())r.fail("geometry cylinders must be tables");
|
||||
Reader c(*value.as_table(),r.context()+".cylinders");CylinderPlacement placement;
|
||||
const auto* origin=c.node("origin_mm");if(!origin)c.fail("origin_mm is required");
|
||||
placement.origin=read_xyz(c,*origin);c.field("tilt_deg",placement.tilt_degrees);c.finish();g.cylinders.push_back(placement);
|
||||
}
|
||||
r.finish();
|
||||
}
|
||||
toml::table geometry_table(const PhysicalGeometry& geometry) {
|
||||
const auto xyz=[](Vec3 p){const auto mm=[](float x){return std::round(double(x)*1e7)/1e4;};return toml::array{mm(p.x),mm(p.y),mm(p.z)};};
|
||||
toml::array pipes,volumes,cylinders;
|
||||
for(std::size_t i=0;i<geometry.pipes.size();++i){toml::array points;for(auto p:geometry.pipes[i].points)points.push_back(xyz(p));pipes.push_back(toml::table{{"index",int(i)},{"points_mm",std::move(points)}});}
|
||||
for(const auto& v:geometry.volumes)volumes.push_back(toml::table{{"id",v.id},{"center_mm",xyz(v.box.center)},{"size_mm",xyz(v.box.size)}});
|
||||
for(const auto& c:geometry.cylinders)cylinders.push_back(toml::table{{"origin_mm",xyz(c.origin)},{"tilt_deg",double(c.tilt_degrees)}});
|
||||
return toml::table{{"pipes",std::move(pipes)},{"volumes",std::move(volumes)},{"cylinders",std::move(cylinders)}};
|
||||
}
|
||||
|
||||
// Scalar readers below keep the file units explicit at the conversion boundary.
|
||||
void read_cylinder(Reader r,CylinderConfig& c) {
|
||||
r.required({"bore_mm","stroke_mm","rod_mm","compression"});
|
||||
@@ -94,18 +142,12 @@ void read_cylinder(Reader r,CylinderConfig& c) {
|
||||
r.field("burn_start_deg",c.burn_start);
|
||||
r.field("compression",c.compression);
|
||||
r.field("energy_variation",c.energy_variation);
|
||||
r.field("exhaust_close_deg",c.exhaust_close);
|
||||
r.field("exhaust_open_deg",c.exhaust_open);
|
||||
r.field("exhaust_valve_count",c.exhaust_valve_count);
|
||||
r.field("exhaust_valve_diameter_mm",c.exhaust_valve_diameter,0.001);
|
||||
r.field("exhaust_valve_lift_mm",c.exhaust_valve_lift,0.001);
|
||||
r.field("fuel_lhv_j_per_kg",c.fuel_lhv);
|
||||
r.field("heat_transfer",c.heat_transfer);
|
||||
r.field("intake_close_deg",c.intake_close);
|
||||
r.field("intake_open_deg",c.intake_open);
|
||||
r.field("intake_valve_count",c.intake_valve_count);
|
||||
r.field("intake_valve_diameter_mm",c.intake_valve_diameter,0.001);
|
||||
r.field("intake_valve_lift_mm",c.intake_valve_lift,0.001);
|
||||
r.field("misfire_probability",c.misfire_probability);
|
||||
r.field("rod_mm",c.rod,0.001);
|
||||
r.field("stroke_mm",c.stroke,0.001);
|
||||
@@ -114,6 +156,21 @@ void read_cylinder(Reader r,CylinderConfig& c) {
|
||||
r.field("wiebe_m",c.wiebe_m);
|
||||
r.finish();
|
||||
}
|
||||
void read_cam(Reader r,FourStrokeCylinder::CamProfile& cam) {
|
||||
const auto* curve=r.array("points");
|
||||
if(curve) for(const auto& node:*curve) {
|
||||
const auto* point=node.as_array();
|
||||
if(!point || point->size()!=2)r.fail("cam points must be [angle_deg, lift_mm]");
|
||||
cam.points.push_back({r.number(*point->get(0)),r.number(*point->get(1),0.001)});
|
||||
}
|
||||
r.finish();
|
||||
}
|
||||
void read_valve(Reader r,FourStrokeCylinder::ValveDynamics& v) {
|
||||
r.field("mass_g",v.mass_kg,0.001);r.field("spring_rate_n_per_mm",v.spring_rate_n_per_m,1000);
|
||||
r.field("damping_n_s_per_m",v.damping_n_s_per_m);r.field("seat_force_n",v.seat_force_n);
|
||||
r.field("maximum_lift_mm",v.maximum_lift_m,0.001);r.field("seat_restitution",v.seat_restitution);
|
||||
r.field("cam_restitution",v.cam_restitution);r.field("stop_restitution",v.stop_restitution);r.finish();
|
||||
}
|
||||
void read_crankshaft(Reader r,CrankshaftConfig& c) {
|
||||
r.field("friction_constant_nm",c.friction_constant);
|
||||
r.field("friction_quadratic_nm_s2",c.friction_quadratic);
|
||||
@@ -183,6 +240,8 @@ void read_silencer(Reader r,SilencerConfig& c) {
|
||||
r.field("passage_diameter_mm",c.passage_diameter,0.001);
|
||||
r.field("resistance",c.resistance);
|
||||
r.field("volume_litres",c.volume,0.001);
|
||||
float diameter=0;r.field("diameter_mm",diameter,.001);
|
||||
if(diameter>0)c.volume=pi*.25f*diameter*diameter*c.length;
|
||||
const auto type=r.text("type","straight_through");
|
||||
if(type=="straight_through")c.type=SilencerType::StraightThrough;
|
||||
else if(type=="chambered")c.type=SilencerType::Chambered;
|
||||
@@ -210,6 +269,8 @@ void read_two_stroke(Reader r,TwoStrokeConfig& c) {
|
||||
r.field("bore_mm",c.bore,0.001);
|
||||
r.field("carburetor_diameter_mm",c.carburetor_diameter,0.001);
|
||||
r.field("crankcase_clearance_cc",c.crankcase_clearance,1e-06);
|
||||
r.field("reed_pipe_diameter_mm",c.reed_pipe_diameter,.001);
|
||||
r.field("transfer_pipe_diameter_mm",c.transfer_pipe_diameter,.001);
|
||||
r.field("exhaust_cell_length_mm",c.exhaust_cell_length,0.001);
|
||||
r.field("exhaust_duration_deg",c.exhaust_duration);
|
||||
r.field("exhaust_width_mm",c.exhaust_width,0.001);
|
||||
@@ -335,7 +396,7 @@ void validate_two(const TwoStrokeConfig& c,const std::string& path) {
|
||||
require(c.idle_slide_opening>=0 && c.idle_slide_opening<=1 && c.initial_rpm>0 && c.initial_rpm<=30000 &&
|
||||
c.crankshaft_inertia>0 && c.starter_torque>=0 && c.maximum_load_torque>=0 && c.idle_spark_gain>=0,
|
||||
path,"two_stroke: invalid idle or crankshaft calibration");
|
||||
require(c.carburetor_diameter>0 && c.minimum_burn_seconds>0 &&
|
||||
require(c.carburetor_diameter>0 && c.reed_pipe_diameter>0&&c.reed_pipe_diameter<=2&&c.transfer_pipe_diameter>0&&c.transfer_pipe_diameter<=2&&c.minimum_burn_seconds>0 &&
|
||||
c.friction_bar>=0 && c.friction_bar_per_mps>=0 && c.friction_bar_per_mps2>=0,
|
||||
path,"two_stroke: invalid carburetor, burn time or friction");
|
||||
for(float value:{c.jet_scale,c.pilot_jet_scale,c.main_jet_scale,c.needle_jet_scale,
|
||||
@@ -354,6 +415,7 @@ void validate_two(const TwoStrokeConfig& c,const std::string& path) {
|
||||
} // namespace
|
||||
|
||||
void validate_engine_config(const EngineConfig& c,const std::string& path) {
|
||||
require(std::isfinite(c.cells_per_meter) && (c.cells_per_meter==0 || (c.cells_per_meter>=1 && c.cells_per_meter<=500)),path,"invalid cells_per_meter");
|
||||
require(c.cylinders>=1 && c.cylinders<=12 && (c.layout==EngineLayout::Inline || c.cylinders%2==0),
|
||||
path,"engine: expected 1..12 cylinders and even banked cylinder counts");
|
||||
const auto& cylinder=c.cylinder;
|
||||
@@ -362,11 +424,17 @@ void validate_engine_config(const EngineConfig& c,const std::string& path) {
|
||||
path,"cylinder: invalid bore, stroke, rod or compression");
|
||||
require(cylinder.intake_valve_count>=1 && cylinder.intake_valve_count<=8 &&
|
||||
cylinder.exhaust_valve_count>=1 && cylinder.exhaust_valve_count<=8 &&
|
||||
cylinder.intake_valve_diameter>0 && cylinder.exhaust_valve_diameter>0 &&
|
||||
cylinder.intake_valve_lift>0 && cylinder.exhaust_valve_lift>0,path,"cylinder: invalid valve geometry");
|
||||
for(float angle:{cylinder.intake_open,cylinder.intake_close,cylinder.exhaust_open,cylinder.exhaust_close})
|
||||
require(angle>=0 && angle<720,path,"cylinder: valve events must be in [0,720) degrees");
|
||||
require(cylinder.intake_open!=cylinder.intake_close && cylinder.exhaust_open!=cylinder.exhaust_close &&
|
||||
cylinder.intake_valve_diameter>0 && cylinder.exhaust_valve_diameter>0,path,"cylinder: invalid valve geometry");
|
||||
auto valid_cam=[&](const FourStrokeCylinder::CamProfile& cam,const FourStrokeCylinder::ValveDynamics& valve) {
|
||||
require(cam.points.size()>=3 && cam.points.front().angle_degrees==0 && cam.points.back().angle_degrees==720,path,"cam: profile must cover 0..720 degrees");
|
||||
float previous=-1;
|
||||
for(const auto& point:cam.points) {require(point.angle_degrees>previous && point.angle_degrees<=720 && point.lift_metres>=0 && point.lift_metres<=valve.maximum_lift_m,path,"cam: points must increase and lifts fit valve travel");previous=point.angle_degrees;}
|
||||
require(cam.points.front().lift_metres==0 && cam.points.back().lift_metres==0,path,"cam: both cycle endpoints must have zero lift");
|
||||
require(valve.mass_kg>0 && valve.spring_rate_n_per_m>0 && valve.damping_n_s_per_m>=0 && valve.seat_force_n>0 && valve.maximum_lift_m>0 && valve.seat_restitution>=0 && valve.seat_restitution<=1 && valve.cam_restitution>=0 && valve.cam_restitution<=1 && valve.stop_restitution>=0 && valve.stop_restitution<=1,path,"valves: invalid mass, spring or restitution");
|
||||
};
|
||||
valid_cam(c.intake_cam,c.intake_valve);valid_cam(c.exhaust_cam,c.exhaust_valve);
|
||||
require(c.valve_sound.mode_hz>0 && c.valve_sound.effective_mass_kg>0 && c.valve_sound.radiation_area>=0 && c.valve_sound.damping_ratio>=0,path,"valve_sound: invalid resonance calibration");
|
||||
require(
|
||||
cylinder.burn_duration>0 && cylinder.wiebe_a>0 && cylinder.wiebe_m>=0 &&
|
||||
cylinder.energy_variation>=0 && cylinder.energy_variation<=1 &&
|
||||
cylinder.misfire_probability>=0 && cylinder.misfire_probability<=1 &&
|
||||
@@ -392,9 +460,9 @@ void validate_engine_config(const EngineConfig& c,const std::string& path) {
|
||||
count==1+2*c.cylinders && p.count==1,path,"pipes: silenced profile must be the collector's final outlet");
|
||||
++silenced;
|
||||
} else {
|
||||
require(p.diameter>0 && p.diameter<=2 && p.length>0 && p.length<=100 && p.cells>=1 && p.cells<=4096,
|
||||
require(p.diameter>0 && p.diameter<=2 && p.length>0 && p.length<=100 && (c.cells_per_meter>0 || (p.cells>=1 && p.cells<=4096)),
|
||||
path,"pipes: invalid diameter, length or cell count");
|
||||
cells+=p.cells*p.count;
|
||||
cells+=(c.cells_per_meter>0?mesh_cell_count(p.length,c.cells_per_meter):p.cells)*p.count;
|
||||
}
|
||||
count+=p.count;
|
||||
}
|
||||
@@ -419,22 +487,45 @@ ScenarioExample load_engine_file(const std::filesystem::path& path) {
|
||||
catch(const toml::parse_error& error) {std::ostringstream message;message<<error;throw std::runtime_error(message.str());}
|
||||
Reader root(table,path.string());
|
||||
int version=0;root.field("schema_version",version);
|
||||
if(version!=1)root.fail("schema_version must be 1");
|
||||
if(version!=1&&version!=2)root.fail("schema_version must be 1 or 2");
|
||||
if(version==2&&!table.contains("geometry"))root.fail("schema_version 2 requires geometry");
|
||||
ScenarioExample e;
|
||||
e.source_path=std::filesystem::absolute(path);
|
||||
root.field("id",e.id);root.field("name",e.title);root.field("category",e.category);
|
||||
root.field("description",e.description);root.field("order",e.order);
|
||||
if(e.id.empty() || e.title.empty() || e.category.empty())root.fail("id, name and category are required");
|
||||
if(e.id.find_first_not_of("abcdefghijklmnopqrstuvwxyz0123456789-_")!=std::string::npos)root.fail("id must use lowercase letters, digits, - or _");
|
||||
auto simulation=root.section("simulation");
|
||||
float density=0;
|
||||
if(simulation.node("cells_per_meter")) {
|
||||
simulation.field("cells_per_meter",density);
|
||||
if(density<1 || density>500) simulation.fail("cells_per_meter must be in 1..500");
|
||||
}
|
||||
simulation.finish();
|
||||
e.engine.cells_per_meter=e.two.cells_per_meter=density;
|
||||
if(density>0) { e.two.exhaust_cell_length=1/density;e.exhaust.cell_length=1/density; }
|
||||
const auto cycle=root.text("cycle");
|
||||
if(cycle=="two_stroke") {
|
||||
e.kind=ScenarioKind::TwoStroke;
|
||||
read_two_stroke(root.section("two_stroke",true),e.two);
|
||||
if(density>0) e.two.exhaust_cell_length=1/density;
|
||||
read_ecu(root.section("ecu"),e.two.ecu);
|
||||
read_vehicle(root.section("vehicle"),e.two.vehicle);
|
||||
read_geometry(root.section("geometry"),e.two.geometry);
|
||||
if(version==2&&e.two.geometry.empty())root.fail("geometry requires explicit pipe paths");
|
||||
try {e.two=resolve_two_stroke_geometry(std::move(e.two));}catch(const std::exception& error){root.fail(error.what());}
|
||||
validate_two(e.two,path.string());
|
||||
} else if(cycle=="four_stroke") {
|
||||
read_engine(root.section("engine",true),e.engine);
|
||||
read_cylinder(root.section("cylinder",true),e.engine.cylinder);
|
||||
auto cams=root.section("cam",true);
|
||||
read_cam(cams.section("intake",true),e.engine.intake_cam);read_cam(cams.section("exhaust",true),e.engine.exhaust_cam);cams.finish();
|
||||
auto valves=root.section("valves",true);
|
||||
auto intake_valve=valves.section("intake",true),exhaust_valve=valves.section("exhaust",true);
|
||||
read_valve(intake_valve,e.engine.intake_valve);read_valve(exhaust_valve,e.engine.exhaust_valve);valves.finish();
|
||||
auto sound=root.section("valve_sound",true);
|
||||
sound.field("mode_hz",e.engine.valve_sound.mode_hz);sound.field("effective_mass_g",e.engine.valve_sound.effective_mass_kg,0.001);
|
||||
sound.field("radiation_area_cm2",e.engine.valve_sound.radiation_area,0.0001);sound.field("damping_ratio",e.engine.valve_sound.damping_ratio);sound.finish();
|
||||
read_crankshaft(root.section("crankshaft",true),e.engine.crankshaft);
|
||||
read_ecu(root.section("ecu",true),e.engine.ecu);
|
||||
read_vehicle(root.section("vehicle",true),e.engine.vehicle);
|
||||
@@ -442,6 +533,21 @@ ScenarioExample load_engine_file(const std::filesystem::path& path) {
|
||||
read_silencers(root.section("silencers"),e.exhaust);
|
||||
auto junctions=root.section("junctions");
|
||||
junctions.field("h_pipe",e.junctions.h_pipe);junctions.field("junction_volume_cc",e.junctions.junction_volume,1e-6);
|
||||
junctions.field("model",e.junctions.model);junctions.field("turning_loss",e.junctions.turning_loss);
|
||||
if(e.junctions.model!="volume" && e.junctions.model!="characteristic" && e.junctions.model!="legacy") junctions.fail("model must be volume, characteristic, or legacy");
|
||||
if(e.junctions.turning_loss<0 || e.junctions.turning_loss>10) junctions.fail("turning_loss outside 0..10");
|
||||
if(const auto* branches=junctions.array("branches")) for(const auto& value:*branches) {
|
||||
if(!value.is_table()) junctions.fail("branches entries must be tables");
|
||||
Reader r(*value.as_table(),path.string()+".junctions.branches");
|
||||
r.required({"pipe","left","direction"}); JunctionBranchConfig branch;
|
||||
r.field("pipe",branch.pipe);r.field("left",branch.left);
|
||||
std::vector<float> direction;r.field("direction",direction);
|
||||
if(branch.pipe<0 || direction.size()!=3) r.fail("branch requires nonnegative pipe and three direction coordinates");
|
||||
double norm=0;for(int i=0;i<3;++i) { branch.direction[i]=direction[i];norm+=double(direction[i])*direction[i]; }
|
||||
if(!(norm>0)) r.fail("branch direction must be nonzero");
|
||||
for(const auto& previous:e.junctions.branches) if(previous.pipe==branch.pipe && previous.left==branch.left) r.fail("duplicate branch endpoint");
|
||||
r.finish();e.junctions.branches.push_back(branch);
|
||||
}
|
||||
junctions.finish();
|
||||
if(const auto* pipes=root.array("pipes"))for(const auto& value:*pipes) {
|
||||
if(!value.is_table())root.fail("pipes entries must be tables");
|
||||
@@ -453,6 +559,11 @@ ScenarioExample load_engine_file(const std::filesystem::path& path) {
|
||||
r.field("diameter_mm",p.diameter,.001);r.field("length_mm",p.length,.001);r.field("cells",p.cells);
|
||||
r.finish();e.engine.pipes.push_back(std::move(p));
|
||||
}
|
||||
read_geometry(root.section("geometry"),e.engine.geometry);
|
||||
if(version==2&&e.engine.geometry.empty())root.fail("geometry requires explicit pipe paths");
|
||||
try {e.engine=resolve_engine_geometry(std::move(e.engine),e.exhaust,e.junctions);}catch(const std::exception& error){root.fail(error.what());}
|
||||
if(density>0)for(auto& p:e.engine.pipes)if(!p.silenced)p.cells=mesh_cell_count(p.length,density);
|
||||
if(density>0) e.exhaust.cell_length=1/density;
|
||||
validate_engine_config(e.engine,path.string());
|
||||
require(e.junctions.junction_volume>0 && e.junctions.junction_volume<=1,path.string(),"junction_volume_cc outside (0,1000000]");
|
||||
if(e.engine.has_silenced_exhaust()) {
|
||||
@@ -476,6 +587,127 @@ ScenarioExample load_engine_file(const std::filesystem::path& path) {
|
||||
root.finish();return e;
|
||||
}
|
||||
|
||||
void migrate_engine_geometry(const std::filesystem::path& path,bool relayout) {
|
||||
const auto definition=load_engine_file(path);
|
||||
auto geometry=definition.kind==ScenarioKind::TwoStroke?definition.two.geometry:definition.engine.geometry;
|
||||
if(relayout)geometry=definition.kind==ScenarioKind::TwoStroke?default_geometry(definition.two):default_geometry(definition.engine,definition.exhaust,definition.junctions);
|
||||
auto table=toml::parse_file(path.string());
|
||||
const bool already_geometry=table["schema_version"].value_or<int>(1)==2;
|
||||
if(already_geometry&&!relayout)return;
|
||||
auto xyz=[](Vec3 p){const auto mm=[](float x){return std::round(double(x)*1e7)/1e4;};return toml::array{mm(p.x),mm(p.y),mm(p.z)};};
|
||||
toml::array pipes,volumes,cylinders;
|
||||
for(std::size_t i=0;i<geometry.pipes.size();++i) {
|
||||
toml::array points;for(auto p:geometry.pipes[i].points)points.push_back(xyz(p));
|
||||
pipes.push_back(toml::table{{"index",int(i)},{"points_mm",std::move(points)}});
|
||||
}
|
||||
for(const auto& v:geometry.volumes)volumes.push_back(toml::table{{"id",v.id},{"center_mm",xyz(v.box.center)},{"size_mm",xyz(v.box.size)}});
|
||||
for(const auto& c:geometry.cylinders)cylinders.push_back(toml::table{{"origin_mm",xyz(c.origin)},{"tilt_deg",double(c.tilt_degrees)}});
|
||||
table.insert_or_assign("geometry",toml::table{{"pipes",std::move(pipes)},{"volumes",std::move(volumes)},{"cylinders",std::move(cylinders)}});
|
||||
table.insert_or_assign("schema_version",2);
|
||||
if(definition.kind==ScenarioKind::TwoStroke) {
|
||||
auto& two=*table["two_stroke"].as_table();two.erase("crankcase_clearance_cc");
|
||||
two.insert_or_assign("reed_pipe_diameter_mm",double(definition.two.reed_pipe_diameter)*1000);
|
||||
two.insert_or_assign("transfer_pipe_diameter_mm",double(definition.two.transfer_pipe_diameter)*1000);
|
||||
} else {
|
||||
auto& engine=*table["engine"].as_table();engine.erase("plenum_volume_litres");engine.erase("collector_volume_litres");
|
||||
for(auto& pipe:*table["pipes"].as_array())pipe.as_table()->erase("length_mm");
|
||||
if(auto* junction=table["junctions"].as_table())junction->erase("junction_volume_cc");
|
||||
if(auto* silencers=table["silencers"].as_table())for(const auto* name:{"resonator","muffler"})if(auto* s=(*silencers)[name].as_table()) {
|
||||
const auto& cfg=std::string(name)=="resonator"?definition.exhaust.resonator:definition.exhaust.muffler;
|
||||
s->erase("volume_litres");s->insert_or_assign("diameter_mm",double(cfg.diameter())*1000);
|
||||
}
|
||||
}
|
||||
auto temporary=path;temporary+=".geometry.tmp";
|
||||
std::ifstream original(path);std::ostringstream preserved;std::string line,section;
|
||||
const auto trim=[](std::string s){const auto a=s.find_first_not_of(" \t\r");return a==std::string::npos?std::string{}:s.substr(a,s.find_last_not_of(" \t\r")-a+1);};
|
||||
while(std::getline(original,line)) {
|
||||
const auto text=trim(line);const auto key=trim(text.substr(0,text.find('=')));
|
||||
if(text.starts_with("[geometry")||text.starts_with("[[geometry"))break;
|
||||
if(text.starts_with("["))section=text;
|
||||
if(key=="schema_version"){preserved<<"schema_version = 2\n";continue;}
|
||||
if(section=="[engine]"&&(key=="plenum_volume_litres"||key=="collector_volume_litres"))continue;
|
||||
if(section=="[[pipes]]"&&key=="length_mm")continue;
|
||||
if(section=="[junctions]"&&key=="junction_volume_cc")continue;
|
||||
if(section=="[two_stroke]"&&key=="crankcase_clearance_cc")continue;
|
||||
if((section=="[silencers.resonator]"||section=="[silencers.muffler]")&&key=="volume_litres") {
|
||||
const auto& cfg=section=="[silencers.resonator]"?definition.exhaust.resonator:definition.exhaust.muffler;
|
||||
preserved<<"diameter_mm = "<<std::setprecision(10)<<double(cfg.diameter())*1000<<'\n';continue;
|
||||
}
|
||||
preserved<<line<<'\n';
|
||||
if(text=="[two_stroke]"&&!already_geometry)preserved<<"reed_pipe_diameter_mm = "<<definition.two.reed_pipe_diameter*1000<<"\ntransfer_pipe_diameter_mm = "<<definition.two.transfer_pipe_diameter*1000<<'\n';
|
||||
}
|
||||
{std::ofstream output(temporary);output.exceptions(std::ios::failbit|std::ios::badbit);output<<preserved.str()<<'\n'<<toml::table{{"geometry",*table["geometry"].as_table()}}<<'\n';}
|
||||
load_engine_file(temporary);
|
||||
std::filesystem::copy_file(temporary,path,std::filesystem::copy_options::overwrite_existing);
|
||||
std::filesystem::remove(temporary);
|
||||
}
|
||||
|
||||
std::filesystem::path save_tuned_engine(const ScenarioExample& source,const EngineConfig& requested,
|
||||
const std::filesystem::path& directory) {
|
||||
if(source.kind==ScenarioKind::TwoStroke)throw std::invalid_argument("Live tuning export requires a four-stroke engine");
|
||||
const auto tuning=resolve_engine_geometry(requested,source.exhaust,source.junctions);
|
||||
validate_engine_config(tuning,"export");
|
||||
auto table=toml::parse_file((source.source_path.empty()?engine_directory()/(source.id+".toml"):source.source_path).string());
|
||||
auto destination=directory/(source.id+"-tuned.toml");
|
||||
for(int suffix=2;std::filesystem::exists(destination);++suffix)
|
||||
destination=directory/(source.id+"-tuned-"+std::to_string(suffix)+".toml");
|
||||
table.insert_or_assign("id",destination.stem().string());
|
||||
table.insert_or_assign("name",source.title+" / tuned");
|
||||
table.insert_or_assign("geometry",geometry_table(tuning.geometry));table.insert_or_assign("schema_version",2);
|
||||
if(tuning.cells_per_meter>0) table.insert_or_assign("simulation",toml::table{{"cells_per_meter",double(tuning.cells_per_meter)}});
|
||||
auto write_cam=[&](const char* name,const FourStrokeCylinder::CamProfile& cam) {
|
||||
toml::array points;
|
||||
for(const auto& p:cam.points)points.push_back(toml::array{double(p.angle_degrees),double(p.lift_metres)*1000});
|
||||
table["cam"][name].as_table()->insert_or_assign("points",std::move(points));
|
||||
};
|
||||
write_cam("intake",tuning.intake_cam);write_cam("exhaust",tuning.exhaust_cam);
|
||||
auto write_valve=[&](const char* name,const FourStrokeCylinder::ValveDynamics& v) {
|
||||
auto& t=*table["valves"][name].as_table();
|
||||
t.insert_or_assign("mass_g",double(v.mass_kg)*1000);
|
||||
t.insert_or_assign("spring_rate_n_per_mm",double(v.spring_rate_n_per_m)/1000);
|
||||
t.insert_or_assign("damping_n_s_per_m",double(v.damping_n_s_per_m));
|
||||
t.insert_or_assign("seat_force_n",double(v.seat_force_n));
|
||||
t.insert_or_assign("maximum_lift_mm",double(v.maximum_lift_m)*1000);
|
||||
t.insert_or_assign("seat_restitution",double(v.seat_restitution));
|
||||
t.insert_or_assign("cam_restitution",double(v.cam_restitution));
|
||||
t.insert_or_assign("stop_restitution",double(v.stop_restitution));
|
||||
};
|
||||
write_valve("intake",tuning.intake_valve);write_valve("exhaust",tuning.exhaust_valve);
|
||||
auto& sound=*table["valve_sound"].as_table();
|
||||
sound.insert_or_assign("mode_hz",double(tuning.valve_sound.mode_hz));
|
||||
sound.insert_or_assign("effective_mass_g",double(tuning.valve_sound.effective_mass_kg)*1000);
|
||||
sound.insert_or_assign("radiation_area_cm2",double(tuning.valve_sound.radiation_area)*10000);
|
||||
sound.insert_or_assign("damping_ratio",double(tuning.valve_sound.damping_ratio));
|
||||
auto& ecu=*table["ecu"].as_table();toml::array ignition;
|
||||
for(const auto& p:tuning.ecu.ignition_map)ignition.push_back(toml::array{double(p.rpm),double(p.degrees_btdc)});
|
||||
ecu.insert_or_assign("ignition_map",std::move(ignition));
|
||||
ecu.insert_or_assign("idle_base_opening",double(tuning.ecu.idle_base_opening));
|
||||
ecu.insert_or_assign("idle_max_opening",double(tuning.ecu.idle_max_opening));
|
||||
ecu.insert_or_assign("stoichiometric_afr",double(tuning.ecu.stoichiometric_afr));
|
||||
ecu.insert_or_assign("power_afr",double(tuning.ecu.power_afr));
|
||||
if(tuning.carbureted) {
|
||||
auto& fuel=*table["fuel"].as_table();
|
||||
fuel.insert_or_assign("pilot_jet_diameter_mm",double(tuning.fuel.pilot_jet_diameter)*1000);
|
||||
fuel.insert_or_assign("main_jet_diameter_mm",double(tuning.fuel.main_jet_diameter)*1000);
|
||||
fuel.insert_or_assign("needle_jet_diameter_mm",double(tuning.fuel.needle_jet_diameter)*1000);
|
||||
}
|
||||
auto& pipes=*table["pipes"].as_array();
|
||||
if(pipes.size()!=tuning.pipes.size())throw std::invalid_argument("Pipe groups changed since the engine was opened");
|
||||
for(std::size_t i=0;i<tuning.pipes.size();++i)if(!tuning.pipes[i].silenced) {
|
||||
auto& pipe=*pipes[i].as_table();const auto& p=tuning.pipes[i];
|
||||
pipe.insert_or_assign("diameter_mm",double(p.diameter)*1000);
|
||||
if(tuning.geometry.empty())pipe.insert_or_assign("length_mm",double(p.length)*1000);else pipe.erase("length_mm");
|
||||
pipe.insert_or_assign("cells",p.cells);
|
||||
}
|
||||
auto temporary=destination;temporary+=".tmp";
|
||||
try {
|
||||
{std::ofstream output(temporary);output.exceptions(std::ios::failbit|std::ios::badbit);output<<table<<'\n';}
|
||||
load_engine_file(temporary); // Use the exact same parser and validation as startup.
|
||||
std::filesystem::rename(temporary,destination);
|
||||
} catch(...) {std::error_code ignored;std::filesystem::remove(temporary,ignored);throw;}
|
||||
return destination;
|
||||
}
|
||||
|
||||
std::vector<ScenarioExample> load_engine_directory(const std::filesystem::path& directory) {
|
||||
require(std::filesystem::is_directory(directory),directory.string(),"engine directory does not exist");
|
||||
std::vector<std::filesystem::path> files;
|
||||
|
||||
264
src/engine_editor.cpp
Normal file
264
src/engine_editor.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
#include "FluidSim/Desktop/EngineEditor.hpp"
|
||||
#include "FluidSim/Desktop/DesktopUi.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace fluidsim::port::desktop {
|
||||
namespace {
|
||||
const sf::Color ink{232,237,242},muted{152,164,176},blue{91,184,255},orange{255,184,104};
|
||||
void text(sf::RenderWindow& w,const sf::Font* font,const std::string& value,float x,float y,unsigned size=12,sf::Color color=ink) {
|
||||
if(!font)return;
|
||||
sf::Text t(*font,value,size);t.setPosition({x,y});t.setFillColor(color);w.draw(t);
|
||||
}
|
||||
void rect(sf::RenderWindow& w,sf::FloatRect r,sf::Color color,sf::Color outline={55,66,78}) {
|
||||
sf::RectangleShape shape(r.size);shape.setPosition(r.position);shape.setFillColor(color);
|
||||
shape.setOutlineColor(outline);shape.setOutlineThickness(1);w.draw(shape);
|
||||
}
|
||||
void line(sf::RenderWindow& w,sf::Vector2f a,sf::Vector2f b,sf::Color color) {
|
||||
const sf::Vertex vertices[]{{a,color},{b,color}};w.draw(vertices,2,sf::PrimitiveType::Lines);
|
||||
}
|
||||
std::string number(float v,int precision=1) {std::ostringstream s;s<<std::fixed<<std::setprecision(precision)<<v;return s.str();}
|
||||
sf::FloatRect button(sf::FloatRect panel,float x,float y,float width) {return {{panel.position.x+x,panel.position.y+y},{width,26}};}
|
||||
void draw_button(sf::RenderWindow& w,const sf::Font* font,sf::FloatRect r,const std::string& title,bool selected=false,bool enabled=true) {
|
||||
rect(w,r,selected?sf::Color{35,68,91}:sf::Color{29,36,44},selected?blue:sf::Color{55,66,78});
|
||||
text(w,font,title,r.position.x+9,r.position.y+5,11,enabled?(selected?blue:ink):muted);
|
||||
}
|
||||
}
|
||||
sf::FloatRect EngineEditor::bounds(sf::Vector2u size) {
|
||||
const auto viewport=WorkspaceLayout::calculate(size).viewport;
|
||||
const float width=std::min(660.f,viewport.size.x);
|
||||
return {{viewport.position.x+viewport.size.x-width,80},{width,float(size.y)-128}};
|
||||
}
|
||||
sf::FloatRect EngineEditor::toggle_bounds(sf::Vector2u size) {return {{float(size.x)-200,47},{180,24}};}
|
||||
void EngineEditor::configure(const ScenarioExample& e) {
|
||||
supported_=e.kind!=ScenarioKind::TwoStroke;visible_=supported_;
|
||||
original_=draft_=e.engine;applied_pipes_=e.engine.pipes;
|
||||
undo_.clear();redo_.clear();pipe_=0;live_changed_=false;
|
||||
busy_=rebuild_requested_=save_requested_=false;dragging_field_=dragging_point_=-1;tab_=Tab::Valves;
|
||||
}
|
||||
bool EngineEditor::close() {if(!visible_)return false;visible_=false;dragging_field_=dragging_point_=-1;return true;}
|
||||
std::vector<EngineEditor::Field> EngineEditor::fields() const {
|
||||
if(!supported_)return {};
|
||||
const auto& v=exhaust_?draft_.exhaust_valve:draft_.intake_valve;
|
||||
if(tab_==Tab::Valves)return {
|
||||
{Key::Mass,"Valve mass","g",v.mass_kg*1000,10,100,1},
|
||||
{Key::Spring,"Spring rate","N/mm",v.spring_rate_n_per_m/1000,10,90,1},
|
||||
{Key::Damping,"Valve damping","N s/m",v.damping_n_s_per_m,0,70,1},
|
||||
{Key::Preload,"Seat preload","N",v.seat_force_n,20,250,1},
|
||||
{Key::SoundArea,"Contact sound area","cm2",draft_.valve_sound.radiation_area*10000,0,40,1},
|
||||
{Key::SoundDamping,"Sound damping","ratio",draft_.valve_sound.damping_ratio,.3f,1.2f,2}};
|
||||
if(tab_==Tab::Fuel) {
|
||||
const float trim=draft_.ecu.ignition_map.empty()?0:draft_.ecu.ignition_map.front().degrees_btdc-original_.ecu.ignition_map.front().degrees_btdc;
|
||||
std::vector<Field> result{{Key::Ignition,"Ignition map trim","deg",trim,-15,15,1},
|
||||
{Key::Idle,"Idle throttle stop","%",draft_.ecu.idle_base_opening*100,0,draft_.ecu.idle_max_opening*100,2}};
|
||||
if(draft_.carbureted) {
|
||||
result.push_back({Key::Pilot,"Pilot jet diameter","mm",draft_.fuel.pilot_jet_diameter*1000,original_.fuel.pilot_jet_diameter*650,original_.fuel.pilot_jet_diameter*1500,3});
|
||||
result.push_back({Key::Main,"Main jet diameter","mm",draft_.fuel.main_jet_diameter*1000,original_.fuel.main_jet_diameter*650,original_.fuel.main_jet_diameter*1500,3});
|
||||
result.push_back({Key::Needle,"Needle jet diameter","mm",draft_.fuel.needle_jet_diameter*1000,original_.fuel.needle_jet_diameter*650,original_.fuel.needle_jet_diameter*1500,3});
|
||||
} else {
|
||||
result.push_back({Key::Stoich,"Cruise AFR target","AFR",draft_.ecu.stoichiometric_afr,10,18,2});
|
||||
result.push_back({Key::Power,"Power AFR target","AFR",draft_.ecu.power_afr,10,16,2});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if(draft_.pipes.empty() || draft_.pipes[pipe_].silenced)return {};
|
||||
const auto& p=draft_.pipes[pipe_];const auto& base=original_.pipes[pipe_];
|
||||
return {{Key::Length,"Pipe group length","mm",p.length*1000,50,std::max(2000.f,base.length*1750),1},
|
||||
{Key::Diameter,"Pipe group diameter","mm",p.diameter*1000,5,std::max(120.f,base.diameter*1750),1}};
|
||||
}
|
||||
void EngineEditor::begin_edit() {
|
||||
if(undo_.size()>=32)undo_.erase(undo_.begin());
|
||||
undo_.push_back(draft_);redo_.clear();status_="Changes apply to the running engine.";
|
||||
}
|
||||
void EngineEditor::undo() {if(undo_.empty() || busy_)return;redo_.push_back(draft_);draft_=std::move(undo_.back());undo_.pop_back();live_changed_=true;status_="Undid edit.";}
|
||||
void EngineEditor::redo() {if(redo_.empty() || busy_)return;undo_.push_back(draft_);draft_=std::move(redo_.back());redo_.pop_back();live_changed_=true;status_="Redid edit.";}
|
||||
void EngineEditor::reset() {if(busy_)return;begin_edit();draft_=original_;live_changed_=true;status_="Restored original tuning. Apply any pending pipe changes to rebuild.";}
|
||||
void EngineEditor::set_field(const Field& f,float value) {
|
||||
value=std::clamp(value,f.minimum,f.maximum);
|
||||
const float steps=std::pow(10.f,float(f.precision));value=std::round(value*steps)/steps;
|
||||
value=std::clamp(value,f.minimum,f.maximum);
|
||||
auto& v=exhaust_?draft_.exhaust_valve:draft_.intake_valve;
|
||||
switch(f.key) {
|
||||
case Key::Mass:v.mass_kg=value*.001f;break;
|
||||
case Key::Spring:v.spring_rate_n_per_m=value*1000;break;
|
||||
case Key::Damping:v.damping_n_s_per_m=value;break;
|
||||
case Key::Preload:v.seat_force_n=value;break;
|
||||
case Key::SoundArea:draft_.valve_sound.radiation_area=value*.0001f;break;
|
||||
case Key::SoundDamping:draft_.valve_sound.damping_ratio=value;break;
|
||||
case Key::Ignition:
|
||||
draft_.ecu.ignition_map=original_.ecu.ignition_map;
|
||||
for(auto& p:draft_.ecu.ignition_map)p.degrees_btdc=std::clamp(p.degrees_btdc+value,-90.f,90.f);
|
||||
break;
|
||||
case Key::Idle:draft_.ecu.idle_base_opening=value*.01f;break;
|
||||
case Key::Pilot:draft_.fuel.pilot_jet_diameter=value*.001f;break;
|
||||
case Key::Main:draft_.fuel.main_jet_diameter=value*.001f;break;
|
||||
case Key::Needle:draft_.fuel.needle_jet_diameter=value*.001f;break;
|
||||
case Key::Stoich:draft_.ecu.stoichiometric_afr=value;break;
|
||||
case Key::Power:draft_.ecu.power_afr=value;break;
|
||||
case Key::Length: {
|
||||
auto& p=draft_.pipes[pipe_];const auto& base=original_.pipes[pipe_];p.length=value*.001f;
|
||||
p.cells=std::clamp(int(std::ceil(p.length/(base.length/base.cells))),1,4096);return;
|
||||
}
|
||||
case Key::Diameter:draft_.pipes[pipe_].diameter=value*.001f;return;
|
||||
}
|
||||
live_changed_=true;
|
||||
}
|
||||
sf::FloatRect EngineEditor::graph_bounds(sf::Vector2u size) const {
|
||||
const auto p=bounds(size);return {{p.position.x+40,p.position.y+151},{p.size.x-64,std::min(180.f,p.size.y*.22f)}};
|
||||
}
|
||||
sf::FloatRect EngineEditor::field_bounds(sf::Vector2u size,std::size_t i) const {
|
||||
const auto p=bounds(size);const auto g=graph_bounds(size);
|
||||
const float first=tab_==Tab::Valves?g.position.y+g.size.y+64:tab_==Tab::Fuel?p.position.y+172:p.position.y+246;
|
||||
return {{p.position.x+22,first+float(i)*38},{p.size.x-44,9}};
|
||||
}
|
||||
void EngineEditor::drag(sf::Vector2f pos,sf::Vector2u size) {
|
||||
if(dragging_field_>=0) {
|
||||
const auto list=fields();const auto& f=list.at(std::size_t(dragging_field_));const auto r=field_bounds(size,std::size_t(dragging_field_));
|
||||
set_field(f,std::lerp(f.minimum,f.maximum,std::clamp((pos.x-r.position.x)/r.size.x,0.f,1.f)));
|
||||
}
|
||||
if(dragging_point_>=0) {
|
||||
auto& points=(exhaust_?draft_.exhaust_cam:draft_.intake_cam).points;
|
||||
const auto i=std::size_t(dragging_point_);const auto g=graph_bounds(size);
|
||||
const float maximum=(exhaust_?draft_.exhaust_valve:draft_.intake_valve).maximum_lift_m;
|
||||
auto& point=points.at(i);
|
||||
point.angle_degrees=std::clamp((pos.x-g.position.x)/g.size.x*720,points[i-1].angle_degrees+.1f,points[i+1].angle_degrees-.1f);
|
||||
point.lift_metres=std::clamp((1-(pos.y-g.position.y)/g.size.y)*maximum,0.f,maximum);
|
||||
live_changed_=true;
|
||||
}
|
||||
}
|
||||
bool EngineEditor::handle_event(const sf::Event& event,sf::Vector2u size) {
|
||||
if(const auto* key=event.getIf<sf::Event::KeyPressed>()) {
|
||||
if(key->code==sf::Keyboard::Key::F4) {visible_=!visible_;dragging_field_=dragging_point_=-1;return true;}
|
||||
if(visible_ && supported_ && !busy_ && key->control) {
|
||||
if(key->code==sf::Keyboard::Key::Z){undo();return true;}
|
||||
if(key->code==sf::Keyboard::Key::Y){redo();return true;}
|
||||
if(key->code==sf::Keyboard::Key::S){save_requested_=true;return true;}
|
||||
}
|
||||
}
|
||||
if(event.is<sf::Event::FocusLost>()){dragging_field_=dragging_point_=-1;return false;}
|
||||
if(const auto* click=event.getIf<sf::Event::MouseButtonPressed>()) {
|
||||
const sf::Vector2f pos(click->position);
|
||||
if(click->button==sf::Mouse::Button::Left && toggle_bounds(size).contains(pos)) {visible_=!visible_;return true;}
|
||||
if(!visible_ || !bounds(size).contains(pos))return false;
|
||||
const auto p=bounds(size);
|
||||
if(button(p,p.size.x-42,12,26).contains(pos)) {close();return true;}
|
||||
if(!supported_ || busy_ || click->button!=sf::Mouse::Button::Left)return true;
|
||||
for(int i=0;i<3;++i)if(button(p,16+float(i)*(p.size.x-32)/3,65,(p.size.x-32)/3-4).contains(pos)) {tab_=static_cast<Tab>(i);return true;}
|
||||
const float footer=p.size.y-72;
|
||||
if(button(p,16,footer,70).contains(pos)){undo();return true;}
|
||||
if(button(p,94,footer,70).contains(pos)){redo();return true;}
|
||||
if(button(p,172,footer,76).contains(pos)){reset();return true;}
|
||||
if(button(p,p.size.x-146,footer,130).contains(pos)){save_requested_=true;return true;}
|
||||
if(tab_==Tab::Valves) {
|
||||
if(button(p,20,108,90).contains(pos)){exhaust_=false;return true;}
|
||||
if(button(p,120,108,90).contains(pos)){exhaust_=true;return true;}
|
||||
const auto& points=(exhaust_?draft_.exhaust_cam:draft_.intake_cam).points;const auto g=graph_bounds(size);
|
||||
const float maximum=(exhaust_?draft_.exhaust_valve:draft_.intake_valve).maximum_lift_m;
|
||||
float distance=100;
|
||||
for(std::size_t i=1;i+1<points.size();++i) {
|
||||
const sf::Vector2f v{g.position.x+points[i].angle_degrees/720*g.size.x,g.position.y+(1-points[i].lift_metres/maximum)*g.size.y};
|
||||
const auto d=pos-v;const float squared=d.x*d.x+d.y*d.y;
|
||||
if(squared<distance) {distance=squared;dragging_point_=int(i);}
|
||||
}
|
||||
if(dragging_point_>=0){begin_edit();drag(pos,size);return true;}
|
||||
}
|
||||
if(tab_==Tab::Pipes) {
|
||||
if(button(p,20,108,32).contains(pos)){if(pipe_>0)--pipe_;return true;}
|
||||
if(button(p,p.size.x-52,108,32).contains(pos)){if(pipe_+1<draft_.pipes.size())++pipe_;return true;}
|
||||
if(button(p,20,370,220).contains(pos) && draft_.pipes!=applied_pipes_){rebuild_requested_=true;return true;}
|
||||
}
|
||||
const auto list=fields();
|
||||
for(std::size_t i=0;i<list.size();++i) {
|
||||
auto r=field_bounds(size,i);r.position.y-=19;r.size.y=34;
|
||||
if(r.contains(pos)) {begin_edit();dragging_field_=int(i);drag(pos,size);return true;}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(event.is<sf::Event::MouseButtonReleased>()) {
|
||||
const bool captured=dragging_field_>=0 || dragging_point_>=0;dragging_field_=dragging_point_=-1;
|
||||
if(captured)return true;
|
||||
}
|
||||
if(const auto* move=event.getIf<sf::Event::MouseMoved>();move && (dragging_field_>=0 || dragging_point_>=0)) {drag(sf::Vector2f(move->position),size);return true;}
|
||||
if(const auto* wheel=event.getIf<sf::Event::MouseWheelScrolled>();wheel && visible_ && bounds(size).contains(sf::Vector2f(wheel->position)))return true;
|
||||
return false;
|
||||
}
|
||||
std::optional<EngineConfig> EngineEditor::take_live_update() {
|
||||
if(!live_changed_ || busy_)return std::nullopt;
|
||||
live_changed_=false;auto config=draft_;config.pipes=applied_pipes_;return config;
|
||||
}
|
||||
std::optional<EngineConfig> EngineEditor::take_rebuild_request() {
|
||||
if(!rebuild_requested_ || busy_)return std::nullopt;
|
||||
rebuild_requested_=false;busy_=true;rebuilding_=draft_;status_="Building the edited pipe mesh...";return rebuilding_;
|
||||
}
|
||||
bool EngineEditor::take_save_request() {const bool result=save_requested_;save_requested_=false;return result;}
|
||||
void EngineEditor::finish_rebuild(bool success,const std::string& message) {
|
||||
busy_=false;if(success)applied_pipes_=rebuilding_.pipes;status_=message;
|
||||
}
|
||||
void EngineEditor::draw(sf::RenderWindow& w,const sf::Font* font,const ScenarioSnapshot& s) const {
|
||||
draw_button(w,font,toggle_bounds(w.getSize()),visible_?"F4 Close live editor":"F4 Live engine editor",visible_);
|
||||
if(!visible_)return;
|
||||
const auto p=bounds(w.getSize());const float x=p.position.x,y=p.position.y;
|
||||
rect(w,p,{18,25,33},{70,93,114});
|
||||
text(w,font,"LIVE ENGINE EDITOR",x+18,y+13,19);
|
||||
draw_button(w,font,button(p,p.size.x-42,12,26),"X");
|
||||
text(w,font,"Tune, hear, compare. Edits affect every cylinder.",x+18,y+42,11,muted);
|
||||
if(!supported_) {text(w,font,"Choose a four-stroke engine to use this demo.",x+20,y+110,14);return;}
|
||||
const char* tabs[]{"CAM + VALVES","FUEL + IGNITION","PIPE DIMENSIONS"};
|
||||
for(int i=0;i<3;++i)draw_button(w,font,button(p,16+float(i)*(p.size.x-32)/3,65,(p.size.x-32)/3-4),tabs[i],int(tab_)==i);
|
||||
if(tab_==Tab::Valves) {
|
||||
draw_button(w,font,button(p,20,108,90),"Intake",!exhaust_);draw_button(w,font,button(p,120,108,90),"Exhaust",exhaust_);
|
||||
text(w,font,"Drag curve points",x+232,y+115,11,muted);
|
||||
const auto g=graph_bounds(w.getSize());rect(w,g,{10,16,23});
|
||||
const float maximum=(exhaust_?draft_.exhaust_valve:draft_.intake_valve).maximum_lift_m;
|
||||
const auto project=[&](float angle,float lift){return sf::Vector2f{g.position.x+angle/720*g.size.x,g.position.y+(1-std::clamp(lift/maximum,0.f,1.f))*g.size.y};};
|
||||
for(int angle=0;angle<=720;angle+=180) {
|
||||
const auto a=project(float(angle),0);line(w,a,{a.x,g.position.y},{38,49,62});text(w,font,std::to_string(angle),a.x-10,g.position.y+g.size.y+5,10,muted);
|
||||
}
|
||||
text(w,font,number(maximum*1000,0),g.position.x-31,g.position.y-5,10,muted);
|
||||
text(w,font,"mm",g.position.x-30,g.position.y+15,10,muted);
|
||||
const auto& actual=exhaust_?s.exhaust_lift_trace:s.intake_lift_trace;
|
||||
for(std::size_t i=1;i<actual.size();++i)line(w,project(float(i-1)*4,actual[i-1]),project(float(i)*4,actual[i]),orange);
|
||||
const auto& points=(exhaust_?draft_.exhaust_cam:draft_.intake_cam).points;
|
||||
for(std::size_t i=1;i<points.size();++i)line(w,project(points[i-1].angle_degrees,points[i-1].lift_metres),project(points[i].angle_degrees,points[i].lift_metres),blue);
|
||||
for(std::size_t i=1;i+1<points.size();++i) {sf::CircleShape dot(3);dot.setOrigin({3,3});dot.setPosition(project(points[i].angle_degrees,points[i].lift_metres));dot.setFillColor(blue);w.draw(dot);}
|
||||
const float angle=std::fmod(s.cylinder_angles[0]*180/pi,720.f);const auto cursor=project(angle,0);
|
||||
line(w,{cursor.x,g.position.y},cursor,{90,106,120});
|
||||
text(w,font,"Cam demand",g.position.x,g.position.y+g.size.y+22,11,blue);
|
||||
text(w,font,"Actual / cylinder 1",g.position.x+125,g.position.y+g.size.y+22,11,orange);
|
||||
text(w,font,number((exhaust_?s.exhaust_lift:s.intake_lift)*1000,2)+" mm",g.position.x+320,g.position.y+g.size.y+22,11,orange);
|
||||
text(w,font,s.valve_float?"FLOAT":"CONTACT",g.position.x+g.size.x-75,g.position.y+g.size.y+22,11,s.valve_float?orange:muted);
|
||||
} else if(tab_==Tab::Fuel) {
|
||||
text(w,font,draft_.carbureted?"CARBURETOR / LIVE METERING":"INJECTION / LIVE AFR TARGETS",x+22,y+112,13,blue);
|
||||
text(w,font,"Ignition trim offsets the existing RPM map.",x+22,y+139,11,muted);
|
||||
text(w,font,"Measured AFR "+number(s.target_afr,2)+" Throttle "+number(s.throttle*100,1)+"%",x+22,y+410,13);
|
||||
text(w,font,"Changes preserve RPM, gas charge and valve motion.",x+22,y+446,11,muted);
|
||||
} else {
|
||||
draw_button(w,font,button(p,20,108,32),"<");draw_button(w,font,button(p,p.size.x-52,108,32),">");
|
||||
const auto& pipe=draft_.pipes[pipe_];
|
||||
text(w,font,pipe.id+" ("+std::to_string(pipe_+1)+" / "+std::to_string(draft_.pipes.size())+")",x+66,y+114,13,blue);
|
||||
text(w,font,std::to_string(pipe.count)+" pipe(s) in group / "+std::to_string(pipe.cells)+" cells per pipe",x+22,y+157,12);
|
||||
text(w,font,pipe.silenced?"Silencer geometry is defined by its chamber profile.":"Length changes preserve the original cell spacing.",x+22,y+185,11,muted);
|
||||
text(w,font,"Pipe edits apply together and restart the engine.",x+22,y+321,11,muted);
|
||||
draw_button(w,font,button(p,20,370,220),busy_?"Building...":"Apply pipes + restart",false,!busy_ && draft_.pipes!=applied_pipes_);
|
||||
text(w,font,draft_.pipes!=applied_pipes_?"Unapplied pipe changes":"Pipe geometry is applied",x+22,y+414,12,draft_.pipes!=applied_pipes_?orange:muted);
|
||||
}
|
||||
const auto list=fields();
|
||||
for(std::size_t i=0;i<list.size();++i) {
|
||||
const auto& f=list[i];const auto r=field_bounds(w.getSize(),i);
|
||||
text(w,font,f.label,r.position.x,r.position.y-19,11,muted);
|
||||
text(w,font,number(f.value,f.precision)+" "+f.unit,r.position.x+r.size.x-132,r.position.y-19,11);
|
||||
rect(w,r,{10,16,23});const float t=std::clamp((f.value-f.minimum)/(f.maximum-f.minimum),0.f,1.f);
|
||||
rect(w,{r.position,{r.size.x*t,r.size.y}},{47,109,149},blue);
|
||||
rect(w,{{r.position.x+r.size.x*t-3,r.position.y-3},{6,15}},blue,blue);
|
||||
}
|
||||
const float footer=p.size.y-72;
|
||||
draw_button(w,font,button(p,16,footer,70),"Undo",false,!undo_.empty());
|
||||
draw_button(w,font,button(p,94,footer,70),"Redo",false,!redo_.empty());
|
||||
draw_button(w,font,button(p,172,footer,76),"Reset");draw_button(w,font,button(p,p.size.x-146,footer,130),"Save TOML copy");
|
||||
const auto columns=std::size_t(std::max(20.f,(p.size.x-36)/6.1f));
|
||||
text(w,font,status_.substr(0,columns),x+18,y+p.size.y-37,10,muted);
|
||||
if(status_.size()>columns)text(w,font,status_.substr(columns,columns),x+18,y+p.size.y-24,10,muted);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ Vec3 cross(Vec3 a,Vec3 b) {return {a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b
|
||||
float dot(Vec3 a,Vec3 b) {return a.x*b.x+a.y*b.y+a.z*b.z;}
|
||||
Vec3 unit(Vec3 a) {float l=length(a);return l>1e-7f?Vec3{a.x/l,a.y/l,a.z/l}:Vec3{1,0,0};}
|
||||
struct PipeVisual {
|
||||
struct Ring {unsigned first;std::size_t a,b;float weight;};
|
||||
struct Ring {unsigned first;std::size_t a,b;float weight;Vec3 center;float expansion{};};
|
||||
Mesh mesh;
|
||||
std::vector<Vec3> colors;
|
||||
std::vector<Ring> rings;
|
||||
@@ -96,7 +96,10 @@ struct PipeVisual {
|
||||
for(float d:samples) {
|
||||
const auto position=path.position(d),tangent=path.tangent(d);
|
||||
if(rings.empty())normal=unit(cross(tangent,std::abs(tangent.y)<.9f?Vec3{0,1,0}:Vec3{1,0,0}));
|
||||
else {float v=dot(normal,tangent);normal=unit({normal.x-v*tangent.x,normal.y-v*tangent.y,normal.z-v*tangent.z});}
|
||||
else {
|
||||
float v=dot(normal,tangent);const Vec3 projected{normal.x-v*tangent.x,normal.y-v*tangent.y,normal.z-v*tangent.z};
|
||||
normal=length(projected)>1e-6f?unit(projected):unit(cross(tangent,std::abs(tangent.y)<.9f?Vec3{0,1,0}:Vec3{1,0,0}));
|
||||
}
|
||||
const auto binormal=unit(cross(tangent,normal));
|
||||
std::size_t b=std::min<std::size_t>(std::upper_bound(centers.begin(),centers.end(),d)-centers.begin(),centers.size()-1);
|
||||
std::size_t a=b?b-1:0;
|
||||
@@ -107,20 +110,32 @@ struct PipeVisual {
|
||||
unsigned prev=first-sides,k=(j+1)%sides;
|
||||
mesh.indices.insert(mesh.indices.end(),{prev+j,first+j,prev+k,prev+k,first+j,first+k});
|
||||
}
|
||||
rings.push_back({first,a,b,blend});
|
||||
rings.push_back({first,a,b,blend,position,0.f});
|
||||
for(unsigned j=0;j<sides;++j) {
|
||||
float angle=2*pi3*j/sides,c=std::cos(angle),sn=std::sin(angle);
|
||||
Vec3 n{normal.x*c+binormal.x*sn,normal.y*c+binormal.y*sn,normal.z*c+binormal.z*sn};
|
||||
mesh.vertices.push_back({position.x+radius*n.x,position.y+radius*n.y,position.z+radius*n.z,n.x,n.y,n.z});
|
||||
const auto offset=path.miter_offset(d,n);
|
||||
mesh.vertices.push_back({position.x+radius*offset.x,position.y+radius*offset.y,position.z+radius*offset.z,n.x,n.y,n.z});
|
||||
}
|
||||
}
|
||||
colors.resize(mesh.vertices.size());valid=true;
|
||||
}
|
||||
void update(const std::vector<GasState>& states) {
|
||||
void update(const std::vector<GasState>& states,bool exhaust) {
|
||||
constexpr unsigned sides=20;
|
||||
for(auto ring:rings) {
|
||||
for(auto& ring:rings) {
|
||||
const float p=states[ring.a].pressure+(states[ring.b].pressure-states[ring.a].pressure)*ring.weight;
|
||||
std::fill_n(colors.begin()+ring.first,sides,pressure_tint(p));
|
||||
const float rho=states[ring.a].rho+(states[ring.b].rho-states[ring.a].rho)*ring.weight;
|
||||
const float temperature=p/std::max(rho*287.f,1e-6f);
|
||||
std::fill_n(colors.begin()+ring.first,sides,pressure_tint(p,exhaust,temperature));
|
||||
const float expansion=pressure_expansion(p,temperature);
|
||||
const float ratio=(1.f+expansion)/(1.f+ring.expansion);
|
||||
for(unsigned j=0;j<sides;++j) {
|
||||
auto& vertex=mesh.vertices[ring.first+j];
|
||||
vertex.x=ring.center.x+(vertex.x-ring.center.x)*ratio;
|
||||
vertex.y=ring.center.y+(vertex.y-ring.center.y)*ratio;
|
||||
vertex.z=ring.center.z+(vertex.z-ring.center.z)*ratio;
|
||||
}
|
||||
ring.expansion=expansion;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -142,7 +157,7 @@ struct EngineRenderer3D::Impl {
|
||||
if(s.pipe_states[index].empty())return;
|
||||
auto& visual=pipes[index];
|
||||
if(!visual.matches(s,index,r))visual.build(s,index,r);
|
||||
visual.update(s.pipe_states[index]);
|
||||
visual.update(s.pipe_states[index],scenario_pipe_is_exhaust(s,index));
|
||||
visual.mesh.draw(&visual.colors);
|
||||
}
|
||||
void cylinder_part(Vec3 center,float fraction,float pressure,float angle,float tilt=0) const {
|
||||
@@ -159,6 +174,55 @@ struct EngineRenderer3D::Impl {
|
||||
}
|
||||
void engine(const ScenarioSnapshot& s) {
|
||||
const auto routes=scenario_pipe_routes(s);
|
||||
if(s.geometry) {
|
||||
for(const auto& volume:s.storage_volumes)box(volume.box.center,volume.box.size,pressure_color(volume.pressure));
|
||||
for(int i=0;i<s.cylinder_count;++i) {
|
||||
const auto& c=s.geometry->cylinders[i];const float radius=s.cylinder_bore*.5f;
|
||||
const float crank=s.cylinder_stroke*.5f,clearance=s.cylinder_clearance/(pi3*radius*radius);
|
||||
const float head=s.cylinder_rod+crank+clearance;
|
||||
const float fraction=s.two_stroke?s.cylinder_piston_fraction1:s.piston_fractions[i];
|
||||
const float piston=head-clearance-s.cylinder_stroke*std::clamp(fraction,0.f,1.f);
|
||||
const float pressure=s.two_stroke?s.cylinder_pressure1:s.cylinder_pressures[i];
|
||||
glPushMatrix();glTranslatef(c.origin.x,c.origin.y,c.origin.z);glRotatef(c.tilt_degrees,1,0,0);
|
||||
glPushMatrix();glTranslatef(0,s.cylinder_rod-crank-.004f,0);glScalef(radius+.002f,s.cylinder_stroke+clearance+.004f,radius+.002f);
|
||||
color({.4f,.4f,.4f});shell.draw();glPopMatrix();
|
||||
rod({0,piston,0},{0,head,0},radius,pressure_color(pressure));
|
||||
rod({0,piston-.006f,0},{0,piston,0},radius,{.8f,.8f,.8f});
|
||||
const float angle=s.cylinder_angles[i];const Vec3 pin{0,crank*std::cos(angle),crank*std::sin(angle)};
|
||||
rod(pin,{0,piston,0},std::min(.008f,radius*.13f),{.65f,.65f,.65f});
|
||||
rod({},pin,std::min(.012f,radius*.18f),{.42f,.42f,.42f});
|
||||
box({0,head+radius*.12f,0},{s.cylinder_bore+.008f,radius*.24f,s.cylinder_bore+.008f},{.48f,.48f,.48f});
|
||||
if(!s.two_stroke)for(int valve=0;valve<2;++valve) {
|
||||
const float x=(valve?1.f:-1.f)*radius*.4f;
|
||||
const float lift=valve?s.exhaust_lifts[i]:s.intake_lifts[i];
|
||||
const float diameter=valve?s.exhaust_valve_diameter:s.intake_valve_diameter;
|
||||
rod({x,head-lift,0},{x,head+.025f-lift,0},.0025f,{.68f,.68f,.68f});
|
||||
rod({x,head-.002f-lift,0},{x,head-lift,0},diameter*.5f,{.72f,.72f,.72f});
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
if(!s.geometry->cylinders.empty()) {
|
||||
float first=s.geometry->cylinders.front().origin.x,last=first;
|
||||
for(const auto& c:s.geometry->cylinders){first=std::min(first,c.origin.x);last=std::max(last,c.origin.x);}
|
||||
rod({first-s.cylinder_bore*.4f,0,0},{last+s.cylinder_bore*.4f,0,0},s.cylinder_stroke*.13f,{.5f,.5f,.5f});
|
||||
}
|
||||
for(std::size_t p=0;p<s.geometry->pipes.size();++p)if(!(p==25&&s.v8_headers&&!s.h_pipe))pipe(s,p,routes[p]);
|
||||
for(const auto& housing:s.pipe_housings) {
|
||||
const auto& path=s.geometry->pipes[housing.pipe];float distance=0;
|
||||
for(std::size_t k=1;k<path.points.size();++k) {
|
||||
const float next=distance+geometry_distance(path.points[k-1],path.points[k]);
|
||||
const float from=std::max(distance,housing.start),to=std::min(next,housing.start+housing.length);
|
||||
if(to>from) {
|
||||
const auto a=path.position(from),b=path.position(to),d=sub(b,a);const float len=length(d);
|
||||
glPushMatrix();glTranslatef(a.x,a.y,a.z);
|
||||
if(std::abs(d.x)+std::abs(d.z)>1e-6f)glRotatef(std::acos(std::clamp(d.y/len,-1.f,1.f))*180/pi3,d.z,0,-d.x);else if(d.y<0)glRotatef(180,1,0,0);
|
||||
glScalef(housing.diameter*.5f,len,housing.diameter*.5f);color({.45f,.45f,.45f});shell.draw();glPopMatrix();
|
||||
}
|
||||
distance=next;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(s.two_stroke) {
|
||||
cylinder_part({0,0,0},s.cylinder_piston_fraction1,s.cylinder_pressure1,s.cylinder_angles[0]);
|
||||
box({0,.07f,0},{.21f,.14f,.19f},pressure_color(s.crankcase_pressure));
|
||||
@@ -236,16 +300,24 @@ void EngineRenderer3D::draw(sf::RenderWindow& window,const ScenarioSnapshot& sta
|
||||
glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glDisable(GL_BLEND);glDisable(GL_TEXTURE_2D);glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_NORMALIZE);glEnable(GL_LIGHTING);glEnable(GL_LIGHT0);glEnable(GL_COLOR_MATERIAL);glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
||||
glMatrixMode(GL_PROJECTION);glLoadIdentity();const double nearClip=.03,halfHeight=nearClip*.41421356;
|
||||
glFrustum(-halfHeight*w/h,halfHeight*w/h,-halfHeight,halfHeight,nearClip,50);
|
||||
glFrustum(-halfHeight*w/h,halfHeight*w/h,-halfHeight,halfHeight,nearClip,std::max(50.f,camera.distance*4));
|
||||
glMatrixMode(GL_MODELVIEW);glLoadIdentity();
|
||||
const GLfloat light[]{-.4f,1,1,0},ambient[]{.35f,.35f,.35f,1},diffuse[]{1,1,1,1};
|
||||
glLightfv(GL_LIGHT0,GL_POSITION,light);glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse);glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient);
|
||||
glTranslatef(0,0,-camera.distance*(state.silencers?1.8f:state.cylinder_count==8?1.4f:1.f));glRotatef(camera.pitch,1,0,0);glRotatef(camera.yaw,0,1,0);glTranslatef(-camera.target.x-(state.silencers?1.1f:state.cylinder_count==8?.7f:0.f),-camera.target.y,-camera.target.z);
|
||||
glTranslatef(0,0,-camera.distance);glRotatef(camera.pitch,1,0,0);glRotatef(camera.yaw,0,1,0);glTranslatef(-camera.target.x,-camera.target.y,-camera.target.z);
|
||||
// Grid is indexed triangles too; no per-frame geometry allocation.
|
||||
float ground=-.025f;
|
||||
if(state.geometry) {
|
||||
for(std::size_t p=0;p<state.geometry->pipes.size();++p) {
|
||||
float radius=0;for(float area:state.pipe_areas[p])radius=std::max(radius,std::sqrt(area/pi3));
|
||||
for(auto point:state.geometry->pipes[p].points)ground=std::min(ground,point.y-radius-.015f);
|
||||
}
|
||||
for(const auto& volume:state.storage_volumes)ground=std::min(ground,volume.box.minimum().y-.015f);
|
||||
}
|
||||
for(int i=-8;i<=8;++i) {
|
||||
float p=i*.2f;
|
||||
impl_->box({p,-.025f,0},{.0015f,.001f,3.2f},{.16f,.16f,.16f});
|
||||
impl_->box({0,-.025f,p},{3.2f,.001f,.0015f},{.16f,.16f,.16f});
|
||||
impl_->box({p,ground,0},{.0015f,.001f,3.2f},{.16f,.16f,.16f});
|
||||
impl_->box({0,ground,p},{3.2f,.001f,.0015f},{.16f,.16f,.16f});
|
||||
}
|
||||
impl_->engine(state);
|
||||
glDisable(GL_SCISSOR_TEST);window.popGLStates();
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "FluidSim/Desktop/EngineSchematic.hpp"
|
||||
#include "FluidSim/Desktop/PressurePalette.hpp"
|
||||
#include "FluidSim/ScenarioGeometry.hpp"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
namespace fluidsim::port::desktop {
|
||||
sf::Color pressure_color(float pressure) {
|
||||
auto c=pressure_tint(pressure);
|
||||
sf::Color pressure_color(float pressure,bool exhaust=false) {
|
||||
auto c=pressure_tint(pressure,exhaust);
|
||||
return {static_cast<std::uint8_t>(255*c.x),static_cast<std::uint8_t>(255*c.y),static_cast<std::uint8_t>(255*c.z)};
|
||||
}
|
||||
|
||||
@@ -44,9 +45,12 @@ void draw_pipe(sf::RenderWindow& window, const ScenarioSnapshot& snapshot, std::
|
||||
const float cell_width = total_length > 0 ? (x1 - x0) * lengths[i] / total_length
|
||||
: (x1 - x0) / cells.size();
|
||||
const float thickness = areas.empty() ? 8 : 600 * std::sqrt(4 * areas[i] / pi);
|
||||
sf::RectangleShape segment({cell_width + 1.0f, thickness});
|
||||
segment.setPosition({x, center_y - thickness * .5f});
|
||||
segment.setFillColor(pressure_color(cell.pressure));
|
||||
const float temperature=cell.pressure/std::max(cell.rho*287.f,1e-6f);
|
||||
const float expanded_thickness=thickness*(1.f+pressure_expansion(cell.pressure,temperature));
|
||||
sf::RectangleShape segment({cell_width + 1.0f, expanded_thickness});
|
||||
segment.setPosition({x, center_y - expanded_thickness * .5f});
|
||||
auto tint=pressure_tint(cell.pressure,scenario_pipe_is_exhaust(snapshot,pipe_index),temperature);
|
||||
segment.setFillColor({static_cast<std::uint8_t>(255*tint.x),static_cast<std::uint8_t>(255*tint.y),static_cast<std::uint8_t>(255*tint.z)});
|
||||
window.draw(segment);
|
||||
x += cell_width;
|
||||
}
|
||||
@@ -195,6 +199,47 @@ void draw_b205_scene(sf::RenderWindow& window, const sf::Font* font, const Scena
|
||||
}
|
||||
|
||||
void draw_schematic(sf::RenderWindow& window, const sf::Font* font, const ScenarioSnapshot& state) {
|
||||
if(state.geometry) {
|
||||
const auto project=[](Vec3 p){return sf::Vector2f{p.x+p.z*.35f,-p.y+p.z*.15f};};
|
||||
sf::Vector2f lo{1e9f,1e9f},hi{-1e9f,-1e9f};
|
||||
auto include=[&](Vec3 p){auto v=project(p);lo={std::min(lo.x,v.x),std::min(lo.y,v.y)};hi={std::max(hi.x,v.x),std::max(hi.y,v.y)};};
|
||||
for(const auto& pipe:state.geometry->pipes)for(auto p:pipe.points)include(p);
|
||||
for(const auto& volume:state.storage_volumes){include(volume.box.minimum());include(volume.box.maximum());}
|
||||
for(const auto& c:state.geometry->cylinders){include(c.origin);include(cylinder_point(c,{0,state.cylinder_rod+state.cylinder_stroke,0}));}
|
||||
const float scale=std::min(1150.f/std::max(.1f,hi.x-lo.x),480.f/std::max(.1f,hi.y-lo.y));
|
||||
const auto point=[&](Vec3 p){return (project(p)-(lo+hi)*.5f)*scale+sf::Vector2f{640,400};};
|
||||
for(const auto& volume:state.storage_volumes) {
|
||||
const auto a=point(volume.box.minimum()),b=point(volume.box.maximum());
|
||||
draw_volume(window,volume.pressure,{{std::min(a.x,b.x),std::min(a.y,b.y)},{std::abs(a.x-b.x),std::abs(a.y-b.y)}});
|
||||
draw_label(window,font,volume.id,{std::min(a.x,b.x),std::min(a.y,b.y)-16},sf::Color::White,11);
|
||||
}
|
||||
for(std::size_t p=0;p<state.geometry->pipes.size();++p) {
|
||||
if(p==25&&state.v8_headers&&!state.h_pipe)continue;
|
||||
const bool exhaust=scenario_pipe_is_exhaust(state,p);
|
||||
const auto& path=state.geometry->pipes[p];float distance=0;
|
||||
std::vector<float> knots{0};for(std::size_t k=1;k<path.points.size();++k)knots.push_back(knots.back()+geometry_distance(path.points[k-1],path.points[k]));
|
||||
for(std::size_t i=0;i<state.pipe_states[p].size();++i) {
|
||||
float end=distance+state.pipe_lengths[p][i],start=distance;
|
||||
const float diameter=std::sqrt(4*state.pipe_areas[p][i]/pi);
|
||||
const auto& cell=state.pipe_states[p][i];
|
||||
const float temperature=cell.pressure/std::max(cell.rho*287.f,1e-6f);
|
||||
const auto tint=pressure_tint(cell.pressure,exhaust,temperature);
|
||||
const sf::Color cell_color{static_cast<std::uint8_t>(255*tint.x),static_cast<std::uint8_t>(255*tint.y),static_cast<std::uint8_t>(255*tint.z)};
|
||||
const float thickness=std::max(1.f,diameter*scale)*(1.f+pressure_expansion(cell.pressure,temperature));
|
||||
for(float knot:knots)if(knot>start&&knot<end){draw_graph_line(window,point(path.position(start)),point(path.position(knot)),cell_color,thickness);start=knot;}
|
||||
draw_graph_line(window,point(path.position(start)),point(path.position(end)),cell_color,thickness);distance=end;
|
||||
}
|
||||
}
|
||||
for(int i=0;i<state.cylinder_count;++i) {
|
||||
const auto& c=state.geometry->cylinders[i];const float head=state.cylinder_rod+state.cylinder_stroke*.5f+state.cylinder_clearance/(pi*state.cylinder_bore*state.cylinder_bore*.25f);
|
||||
const float fraction=state.two_stroke?state.cylinder_piston_fraction1:state.piston_fractions[i];
|
||||
const float clearance=state.cylinder_clearance/(pi*state.cylinder_bore*state.cylinder_bore*.25f);
|
||||
const auto top=cylinder_point(c,{0,head,0}),bottom=cylinder_point(c,{0,head-clearance-state.cylinder_stroke,0});
|
||||
draw_graph_line(window,point(bottom),point(top),sf::Color(80,80,80),state.cylinder_bore*scale);
|
||||
draw_graph_line(window,point(cylinder_point(c,{0,head-clearance-state.cylinder_stroke*fraction,0})),point(top),pressure_color(state.two_stroke?state.cylinder_pressure1:state.cylinder_pressures[i]),state.cylinder_bore*scale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(state.staged_headers) {
|
||||
const int n=state.cylinder_count, groups=n==3?1:2, split=n==3?n:(n+1)/2;
|
||||
|
||||
@@ -44,7 +44,7 @@ OutdoorAudio::OutdoorAudio(int rate, OutdoorAudioConfig config) : rate_(rate), c
|
||||
!std::isfinite(config.pressure_gain) || config.pressure_gain < 0 ||
|
||||
!std::isfinite(config.ear_spacing) || config.ear_spacing < 0 ||
|
||||
!finite(config.listener) || !finite(config.intake_position) || !finite(config.exhaust_position) ||
|
||||
!finite(config.second_exhaust_position))
|
||||
!finite(config.second_exhaust_position) || !finite(config.valve_position))
|
||||
throw std::invalid_argument("invalid outdoor audio configuration");
|
||||
const float norm = length(config_.listener_right);
|
||||
if (!std::isfinite(norm) || norm < 1e-6f)
|
||||
@@ -54,6 +54,7 @@ OutdoorAudio::OutdoorAudio(int rate, OutdoorAudioConfig config) : rate_(rate), c
|
||||
configure_emitter(emitters_[0], config_.intake_position);
|
||||
configure_emitter(emitters_[1], config_.exhaust_position);
|
||||
if (config_.dual_exhaust) configure_emitter(emitters_[2], config_.second_exhaust_position);
|
||||
if(config_.valve_contact_enabled)configure_emitter(emitters_[3],config_.valve_position);
|
||||
late_reverb_.dry_mix = 0;
|
||||
late_reverb_.early_mix = 0;
|
||||
late_reverb_.tail_mix = 1;
|
||||
@@ -81,6 +82,7 @@ void OutdoorAudio::update_geometry() {
|
||||
configure_emitter(emitters_[0],config_.intake_position);
|
||||
configure_emitter(emitters_[1],config_.exhaust_position);
|
||||
if(config_.dual_exhaust)configure_emitter(emitters_[2],config_.second_exhaust_position);
|
||||
if(config_.valve_contact_enabled)configure_emitter(emitters_[3],config_.valve_position);
|
||||
}
|
||||
void OutdoorAudio::configure_emitter(Emitter &emitter, Vec3 source) {
|
||||
const bool initial=emitter.filtered.empty();
|
||||
@@ -206,8 +208,8 @@ AudioFrame OutdoorAudio::render(Emitter &e, float flow, AudioFrame &dry, AudioFr
|
||||
e.position = (e.position + 1) & (e.filtered.size() - 1);
|
||||
return result;
|
||||
}
|
||||
AudioFrame OutdoorAudio::process(float intake, float exhaust, float second_exhaust) {
|
||||
if (!std::isfinite(intake) || !std::isfinite(exhaust) || !std::isfinite(second_exhaust))
|
||||
AudioFrame OutdoorAudio::process(float intake, float exhaust, float second_exhaust,float valve_contact) {
|
||||
if (!std::isfinite(intake) || !std::isfinite(exhaust) || !std::isfinite(second_exhaust) || !std::isfinite(valve_contact))
|
||||
throw std::runtime_error("nonfinite acoustic source flow");
|
||||
const OutdoorScene scene = requested_scene_.load(std::memory_order_relaxed);
|
||||
if (scene != active_scene_) {
|
||||
@@ -247,12 +249,20 @@ AudioFrame OutdoorAudio::process(float intake, float exhaust, float second_exhau
|
||||
last_dry_ = {};
|
||||
last_raw_ = {};
|
||||
reverb_input_ = 0;
|
||||
const auto a = render(emitters_[0], intake, last_dry_, last_raw_);
|
||||
const auto b = render(emitters_[1], exhaust, last_dry_, last_raw_);
|
||||
const auto c = config_.dual_exhaust
|
||||
? render(emitters_[2], second_exhaust, last_dry_, last_raw_)
|
||||
: AudioFrame{};
|
||||
const auto tail = late_reverb_.process_stereo(reverb_input_);
|
||||
return {a.left + b.left + c.left + tail.left * tail_mix_, a.right + b.right + c.right + tail.right * tail_mix_};
|
||||
const std::array<float,4> flows{intake,exhaust,second_exhaust,valve_contact};
|
||||
AudioFrame mix{};
|
||||
for(std::size_t i=0;i<sources_.size();++i) {
|
||||
auto& source=sources_[i]; source={};
|
||||
const float previous_reverb=reverb_input_;
|
||||
if((i!=2 || config_.dual_exhaust) && (i!=3 || config_.valve_contact_enabled))
|
||||
source.rendered=render(emitters_[i],flows[i],source.dry,source.unfiltered);
|
||||
if(!enabled_[i]) { reverb_input_=previous_reverb; continue; }
|
||||
mix.left+=source.rendered.left; mix.right+=source.rendered.right;
|
||||
last_dry_.left+=source.dry.left; last_dry_.right+=source.dry.right;
|
||||
last_raw_.left+=source.unfiltered.left; last_raw_.right+=source.unfiltered.right;
|
||||
}
|
||||
const auto tail=late_reverb_.process_stereo(reverb_input_);
|
||||
last_tail_={tail.left*tail_mix_,tail.right*tail_mix_};
|
||||
return {mix.left+last_tail_.left,mix.right+last_tail_.right};
|
||||
}
|
||||
} // namespace fluidsim::port
|
||||
|
||||
244
src/physical_geometry.cpp
Normal file
244
src/physical_geometry.cpp
Normal file
@@ -0,0 +1,244 @@
|
||||
#include "FluidSim/PhysicalGeometry.hpp"
|
||||
#include "FluidSim/EngineConfig.hpp"
|
||||
#include "FluidSim/TwoStrokeConfig.hpp"
|
||||
#include "FluidSim/Silencer.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
|
||||
namespace fluidsim::port {
|
||||
namespace {
|
||||
Vec3 add(Vec3 a,Vec3 b) {return {a.x+b.x,a.y+b.y,a.z+b.z};}
|
||||
Vec3 sub(Vec3 a,Vec3 b) {return {a.x-b.x,a.y-b.y,a.z-b.z};}
|
||||
Vec3 mul(Vec3 a,float b) {return {a.x*b,a.y*b,a.z*b};}
|
||||
bool finite(Vec3 a) {return std::isfinite(a.x)&&std::isfinite(a.y)&&std::isfinite(a.z);}
|
||||
GeometryBox cube(float volume,Vec3 center) {const float side=std::cbrt(volume);return {center,{side,side,side}};}
|
||||
Vec3 port(const GeometryBox& box,Vec3 toward) {
|
||||
auto d=sub(toward,box.center);
|
||||
if(geometry_distance(toward,box.center)<1e-8f)d={1,0,0};
|
||||
const float scale=.5f/std::max({std::abs(d.x)/box.size.x,std::abs(d.y)/box.size.y,std::abs(d.z)/box.size.z});
|
||||
return add(box.center,mul(d,scale));
|
||||
}
|
||||
GeometryPath routed(Vec3 a,Vec3 b,float requested) {
|
||||
const float direct=geometry_distance(a,b),length=std::max(requested,direct);
|
||||
if(length<=direct+1e-7f)return {{a,b}};
|
||||
auto d=sub(b,a);Vec3 normal=std::abs(d.z)<std::abs(d.x)+std::abs(d.y)?Vec3{-d.y,d.x,0}:Vec3{0,-d.z,d.y};
|
||||
float n=geometry_distance(normal,{});if(n<1e-8f){normal={0,0,1};n=1;}
|
||||
if(normal.y>0)normal=mul(normal,-1);
|
||||
const auto sample=[&](float height) {
|
||||
const auto control=add(mul(add(a,b),.5f),mul(normal,height/n));GeometryPath path;
|
||||
for(int i=0;i<=16;++i){const float t=float(i)/16,u=1-t;path.points.push_back(add(add(mul(a,u*u),mul(control,2*u*t)),mul(b,t*t)));}
|
||||
path.points.front()=a;path.points.back()=b;return path;
|
||||
};
|
||||
float low=0,high=length*2;
|
||||
for(int i=0;i<32;++i){const float middle=(low+high)*.5f;if(sample(middle).length()<length)low=middle;else high=middle;}
|
||||
return sample((low+high)*.5f);
|
||||
}
|
||||
Vec3 unit(Vec3 v) {const float n=geometry_distance(v,{});return n>1e-8f?mul(v,1/n):Vec3{1,0,0};}
|
||||
Vec3 boundary_axis(const PhysicalGeometry& geometry,Vec3 point,Vec3 fallback,bool entering) {
|
||||
for(const auto& volume:geometry.volumes) {
|
||||
const auto lo=volume.box.minimum(),hi=volume.box.maximum();constexpr float tolerance=1e-6f;
|
||||
if(point.x<lo.x-tolerance||point.x>hi.x+tolerance||point.y<lo.y-tolerance||point.y>hi.y+tolerance||point.z<lo.z-tolerance||point.z>hi.z+tolerance)continue;
|
||||
const std::array<float,6> distance{std::abs(point.x-lo.x),std::abs(point.x-hi.x),std::abs(point.y-lo.y),std::abs(point.y-hi.y),std::abs(point.z-lo.z),std::abs(point.z-hi.z)};
|
||||
const auto face=std::min_element(distance.begin(),distance.end())-distance.begin();
|
||||
if(distance[face]>tolerance)continue;
|
||||
const std::array<Vec3,6> normals{{{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}}};
|
||||
return mul(normals[face],entering?-1.f:1.f);
|
||||
}
|
||||
return unit(fallback);
|
||||
}
|
||||
// Author smooth bends as measured polyline geometry. The renderer never fits a
|
||||
// spline through these points; their sampled length is also the fluid length.
|
||||
GeometryPath swept(Vec3 a,Vec3 b,Vec3 start_axis,Vec3 end_axis) {
|
||||
const float distance=geometry_distance(a,b),handle=distance*.36f;
|
||||
const Vec3 c=add(a,mul(unit(start_axis),handle)),d=sub(b,mul(unit(end_axis),handle));
|
||||
GeometryPath path;constexpr int segments=16;
|
||||
for(int i=0;i<=segments;++i) {
|
||||
const float t=float(i)/segments,u=1-t;
|
||||
path.points.push_back(add(add(mul(a,u*u*u),mul(c,3*u*u*t)),add(mul(d,3*u*t*t),mul(b,t*t*t))));
|
||||
}
|
||||
path.points.front()=a;path.points.back()=b;return path;
|
||||
}
|
||||
float exhaust_length(const ExhaustConfig& e) {
|
||||
return e.inlet_length+e.outlet_length+(e.enabled?e.connecting_length+e.resonator.length+e.muffler.length:0);
|
||||
}
|
||||
}
|
||||
float geometry_distance(Vec3 a,Vec3 b) {const auto d=sub(a,b);return std::sqrt(d.x*d.x+d.y*d.y+d.z*d.z);}
|
||||
float GeometryPath::length() const {double sum=0;for(std::size_t i=1;i<points.size();++i)sum+=geometry_distance(points[i-1],points[i]);return float(sum);}
|
||||
Vec3 GeometryPath::position(float distance) const {
|
||||
if(points.empty())return {};
|
||||
distance=std::max(0.f,distance);
|
||||
for(std::size_t i=1;i<points.size();++i) {
|
||||
const float span=geometry_distance(points[i-1],points[i]);
|
||||
if(distance<=span)return add(points[i-1],mul(sub(points[i],points[i-1]),distance/span));
|
||||
distance-=span;
|
||||
}
|
||||
return points.back();
|
||||
}
|
||||
const GeometryBox* PhysicalGeometry::volume(const std::string& id) const {for(const auto& v:volumes)if(v.id==id)return &v.box;return nullptr;}
|
||||
GeometryBox* PhysicalGeometry::volume(const std::string& id) {for(auto& v:volumes)if(v.id==id)return &v.box;return nullptr;}
|
||||
Vec3 cylinder_point(const CylinderPlacement& c,Vec3 local) {
|
||||
const float a=c.tilt_degrees*pi/180;
|
||||
return add(c.origin,{local.x,local.y*std::cos(a)-local.z*std::sin(a),local.y*std::sin(a)+local.z*std::cos(a)});
|
||||
}
|
||||
PhysicalGeometry default_geometry(const EngineConfig& e,const ExhaustConfig& exhaust,const JunctionConfig& junctions) {
|
||||
PhysicalGeometry g;std::vector<float> lengths;
|
||||
for(const auto& p:e.pipes)for(int i=0;i<p.count;++i)lengths.push_back(p.silenced?exhaust_length(exhaust):p.length);
|
||||
g.pipes.resize(lengths.size());
|
||||
const int n=e.cylinders,per_bank=e.layout==EngineLayout::Inline?n:n/2;
|
||||
const float spacing=e.cylinder.bore+.018f,head=e.cylinder.rod+e.cylinder.stroke*.5f+e.cylinder.stroke/(e.cylinder.compression-1);
|
||||
std::vector<Vec3> intake,primary;
|
||||
float max_z=0,max_y=0;
|
||||
for(int i=0;i<n;++i) {
|
||||
const float tilt=e.layout==EngineLayout::Inline?0:(i<per_bank?-1.f:1.f)*(e.layout==EngineLayout::Boxer?90:e.bank_angle*.5f);
|
||||
g.cylinders.push_back({{(i%per_bank-(per_bank-1)*.5f)*spacing,0,0},tilt});
|
||||
const float side=tilt<0?-1.f:1.f;
|
||||
intake.push_back(cylinder_point(g.cylinders.back(),{0,head-.008f,-side*e.cylinder.bore*.4f}));
|
||||
primary.push_back(cylinder_point(g.cylinders.back(),{0,head-.008f,side*e.cylinder.bore*.5f}));
|
||||
max_z=std::max(max_z,std::abs(intake.back().z));max_y=std::max(max_y,intake.back().y);
|
||||
}
|
||||
const float width=per_bank*spacing,depth=2*max_z+e.cylinder.bore;
|
||||
const float plenum_height=e.plenum_volume/(width*depth);
|
||||
float runner=lengths.at(1);for(int i=1;i<n;++i)runner=std::min(runner,lengths.at(1+i));
|
||||
GeometryBox plenum{{0,max_y+runner+plenum_height*.5f,0},{width,plenum_height,depth}};
|
||||
if(e.layout==EngineLayout::Inline)plenum.center={0,max_y,intake.front().z-runner-depth*.5f};
|
||||
g.volumes.push_back({"intake_plenum",plenum});
|
||||
const auto inlet=Vec3{plenum.minimum().x,plenum.center.y,plenum.center.z};
|
||||
g.pipes[0]={{add(inlet,{-lengths[0],0,0}),inlet}};
|
||||
for(int i=0;i<n;++i)g.pipes[1+i]=routed(e.layout==EngineLayout::Inline?Vec3{intake[i].x,intake[i].y,plenum.maximum().z}:Vec3{intake[i].x,plenum.minimum().y,intake[i].z},intake[i],lengths[1+i]);
|
||||
int junction_index=0;
|
||||
auto node=[&](Vec3 center,const std::vector<std::pair<int,bool>>& ends,bool collector=false) {
|
||||
GeometryBox box=cube(collector?e.collector_volume:junctions.junction_volume,center);
|
||||
const bool storage=junctions.model=="volume";
|
||||
if(storage)g.volumes.push_back({collector?"exhaust_collector":"junction_"+std::to_string(junction_index),box});
|
||||
++junction_index;
|
||||
for(auto [p,left]:ends) {
|
||||
if(g.pipes[p].points.empty())g.pipes[p].points.resize(2);
|
||||
g.pipes[p].points[left?0:1]=center;
|
||||
}
|
||||
return [=](Vec3 toward){return storage?port(box,toward):center;};
|
||||
};
|
||||
if(e.american_headers()) {
|
||||
const std::array<std::array<int,2>,4> pairs{{{{0,1}},{{2,3}},{{4,6}},{{5,7}}}};
|
||||
std::array<Vec3,4> paired;
|
||||
const float bank_z=max_z+e.cylinder.bore*.7f+.08f;
|
||||
const float tail_z=(lengths[25]+std::cbrt(junctions.junction_volume))*.5f;
|
||||
std::array<Vec3,2> bank{{{width*.5f+.10f,-.08f,-bank_z},{width*.5f+.10f,-.08f,bank_z}}};
|
||||
std::array<Vec3,2> tail{{{bank[0].x+lengths[21],bank[0].y,-tail_z},{bank[1].x+lengths[22],bank[1].y,tail_z}}};
|
||||
for(int k=0;k<4;++k) {
|
||||
auto a=primary[pairs[k][0]],b=primary[pairs[k][1]];
|
||||
paired[k]={(a.x+b.x)*.5f+.08f,-.035f,k<2?bank[0].z:bank[1].z};
|
||||
auto endpoint=node(paired[k],{{9+pairs[k][0],false},{9+pairs[k][1],false},{17+k,true}});
|
||||
for(int cylinder:pairs[k])g.pipes[9+cylinder].points={primary[cylinder],endpoint(primary[cylinder])};
|
||||
g.pipes[17+k].points[0]=endpoint(bank[k/2]);
|
||||
}
|
||||
for(int k=0;k<2;++k) {
|
||||
auto endpoint=node(bank[k],{{17+2*k,false},{18+2*k,false},{21+k,true}});
|
||||
g.pipes[17+2*k].points[1]=endpoint(paired[2*k]);g.pipes[18+2*k].points[1]=endpoint(paired[2*k+1]);
|
||||
g.pipes[21+k].points[0]=endpoint(tail[k]);
|
||||
}
|
||||
g.pipes[25].points.resize(2);
|
||||
for(int k=0;k<2;++k) {
|
||||
if(junctions.h_pipe) {
|
||||
auto endpoint=node(tail[k],{{21+k,false},{23+k,true},{25,k==0}});
|
||||
g.pipes[21+k].points[1]=endpoint(bank[k]);
|
||||
const auto start=endpoint(add(tail[k],{1,0,0}));g.pipes[23+k].points={start,add(start,{lengths[23+k],0,0})};
|
||||
g.pipes[25].points[k]=endpoint(tail[1-k]);
|
||||
} else {
|
||||
g.pipes[21+k].points[1]=tail[k];g.pipes[23+k].points={tail[k],add(tail[k],{lengths[23+k],0,0})};
|
||||
g.pipes[25].points[k]=tail[k];
|
||||
}
|
||||
}
|
||||
} else if(e.staged_headers()) {
|
||||
const int exit=1+2*n,secondary=exit+(e.dual_outlets()?2:1),groups=e.header_groups();
|
||||
std::vector<Vec3> heads(groups);Vec3 merge{.20f,-.07f,e.layout==EngineLayout::Inline?e.cylinder.bore*.75f+.105f:0.f};
|
||||
for(int group=0;group<groups;++group) {
|
||||
std::vector<int> cylinders;float x=0;
|
||||
for(int i=0;i<n;++i)if(groups==1 || (i<(n+1)/2?0:1)==group){cylinders.push_back(i);x+=primary[i].x;}
|
||||
const float z=e.layout==EngineLayout::Inline?e.cylinder.bore*.75f+.045f+group*.045f:(group==0?-1.f:1.f)*(max_z+e.cylinder.bore*.7f+.045f);
|
||||
heads[group]={x/cylinders.size(),-.025f,z};
|
||||
std::vector<std::pair<int,bool>> ends{{secondary+group,true}};for(int i:cylinders)ends.push_back({1+n+i,false});
|
||||
auto endpoint=node(heads[group],ends);
|
||||
for(int i:cylinders)g.pipes[1+n+i].points={primary[i],endpoint(primary[i])};
|
||||
g.pipes[secondary+group].points[0]=endpoint(merge);
|
||||
}
|
||||
if(e.dual_outlets())for(int k=0;k<2;++k) {
|
||||
Vec3 m=merge;m.z=heads[k].z;auto endpoint=node(m,{{secondary+k,false},{exit+k,true}});
|
||||
g.pipes[secondary+k].points[1]=endpoint(heads[k]);const auto start=endpoint(add(m,{1,0,0}));g.pipes[exit+k].points={start,add(start,{lengths[exit+k],0,0})};
|
||||
} else {
|
||||
std::vector<std::pair<int,bool>> ends{{exit,true}};for(int k=0;k<groups;++k)ends.push_back({secondary+k,false});
|
||||
auto endpoint=node(merge,ends);for(int k=0;k<groups;++k)g.pipes[secondary+k].points[1]=endpoint(heads[k]);
|
||||
const auto start=endpoint(add(merge,{1,0,0}));g.pipes[exit].points={start,add(start,{lengths[exit],0,0})};
|
||||
}
|
||||
} else {
|
||||
const int exit=1+2*n;
|
||||
Vec3 center{.10f,-.055f,max_z+e.cylinder.bore*.65f+.035f};
|
||||
std::vector<std::pair<int,bool>> ends{{exit,true}};for(int i=0;i<n;++i)ends.push_back({1+n+i,false});
|
||||
auto endpoint=node(center,ends,true);
|
||||
for(int i=0;i<n;++i)g.pipes[1+n+i].points={primary[i],endpoint(primary[i])};
|
||||
const auto start=endpoint(add(center,{1,0,0}));g.pipes[exit].points={start,add(start,{lengths[exit],0,0})};
|
||||
}
|
||||
for(std::size_t p=1+n;p<g.pipes.size();++p) {
|
||||
const auto a=g.pipes[p].points.front(),b=g.pipes[p].points.back(),chord=sub(b,a);
|
||||
const bool primary_pipe=p<std::size_t(1+2*n);
|
||||
const bool header=primary_pipe||(e.american_headers()&&p<=22)||(e.staged_headers()&&p>=std::size_t(1+2*n+(e.dual_outlets()?2:1)));
|
||||
if(header) {
|
||||
auto start=boundary_axis(g,a,chord,false);
|
||||
if(primary_pipe) {
|
||||
const auto& cylinder=g.cylinders[p-(1+n)];const float side=cylinder.tilt_degrees<0?-1.f:1.f;
|
||||
start=sub(cylinder_point(cylinder,{0,-.15f,side}),cylinder.origin);
|
||||
}
|
||||
g.pipes[p]=swept(a,b,start,boundary_axis(g,b,chord,true));
|
||||
} else g.pipes[p]=routed(a,b,lengths[p]);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
PhysicalGeometry default_geometry(const TwoStrokeConfig& e) {
|
||||
PhysicalGeometry g;g.cylinders.push_back({{},0});g.pipes.resize(4);
|
||||
auto crank=cube(e.crankcase_clearance,{});
|
||||
crank.center.y=e.rod-e.stroke*.5f-.040f-crank.size.y*.5f;
|
||||
auto plenum=cube(.5e-3f,{});plenum.center={crank.minimum().x-.030f-plenum.size.x*.5f,crank.center.y,0};
|
||||
g.volumes={{"intake_plenum",plenum},{"crankcase",crank}};
|
||||
const Vec3 inlet{plenum.minimum().x,plenum.center.y,0};g.pipes[0]={{add(inlet,{-.1f,0,0}),inlet}};
|
||||
g.pipes[1]={{Vec3{plenum.maximum().x,plenum.center.y,0},Vec3{crank.minimum().x,crank.center.y,0}}};
|
||||
g.pipes[2]=routed({crank.maximum().x,crank.maximum().y,0},{e.bore*.5f,e.rod-e.stroke*.5f+.005f,0},.060f);
|
||||
float length=0;for(auto s:e.racing_pipe)length+=s.length;
|
||||
const Vec3 start{e.bore*.5f,e.rod+e.stroke*.5f-.025f,0};
|
||||
if(e.exhaust==TwoStrokeExhaust::Straight)g.pipes[3]={{start,add(start,{length,0,0})}};
|
||||
else {
|
||||
g.pipes[3].points.push_back(start);const std::array<float,6> angles{-20,-65,-125,-180,-200,-180};
|
||||
for(std::size_t i=0;i<angles.size();++i) {
|
||||
const float angle=angles[i]*pi/180;
|
||||
g.pipes[3].points.push_back(add(g.pipes[3].points.back(),{std::cos(angle)*e.racing_pipe[i].length,std::sin(angle)*e.racing_pipe[i].length,0}));
|
||||
}
|
||||
}
|
||||
return g;
|
||||
}
|
||||
void validate_geometry(const PhysicalGeometry& g,std::size_t pipes,std::size_t cylinders) {
|
||||
if(g.pipes.size()!=pipes||g.cylinders.size()!=cylinders)throw std::invalid_argument("geometry pipe/cylinder count does not match the fluid topology");
|
||||
for(const auto& p:g.pipes) {
|
||||
if(p.points.size()<2||p.points.size()>64||!(p.length()>1e-6f)||p.length()>100)throw std::invalid_argument("geometry pipe requires 2..64 points and length in (0,100] m");
|
||||
for(std::size_t i=0;i<p.points.size();++i)if(!finite(p.points[i])||(i&&geometry_distance(p.points[i-1],p.points[i])<1e-7f))throw std::invalid_argument("geometry pipe has nonfinite or repeated points");
|
||||
}
|
||||
std::set<std::string> ids;
|
||||
for(const auto& v:g.volumes)if(v.id.empty()||!ids.insert(v.id).second||!finite(v.box.center)||!finite(v.box.size)||v.box.size.x<=0||v.box.size.y<=0||v.box.size.z<=0||!(v.box.volume()>0)||v.box.volume()>1)throw std::invalid_argument("invalid or duplicate geometry volume");
|
||||
for(const auto& c:g.cylinders)if(!finite(c.origin)||!std::isfinite(c.tilt_degrees))throw std::invalid_argument("invalid cylinder placement");
|
||||
}
|
||||
EngineConfig resolve_engine_geometry(EngineConfig e,const ExhaustConfig& exhaust,const JunctionConfig& junctions) {
|
||||
if(e.geometry.empty()) {validate_engine_config(e);e.geometry=default_geometry(e,exhaust,junctions);}
|
||||
std::size_t count=0;for(auto p:e.pipes)count+=p.count;validate_geometry(e.geometry,count,e.cylinders);
|
||||
const auto* plenum=e.geometry.volume("intake_plenum");if(!plenum)throw std::invalid_argument("geometry requires intake_plenum volume");e.plenum_volume=plenum->volume();
|
||||
if(const auto* collector=e.geometry.volume("exhaust_collector"))e.collector_volume=collector->volume();
|
||||
else if(e.collector_volume<=0)e.collector_volume=1e-6f; // unused in zero-storage/staged topology
|
||||
if(junctions.model=="volume"&&!e.staged_headers()&&!e.american_headers()&&!e.geometry.volume("exhaust_collector"))throw std::invalid_argument("geometry requires exhaust_collector volume");
|
||||
std::size_t index=0;for(auto& p:e.pipes){if(!p.silenced)p.length=e.geometry.pipes[index].length();index+=p.count;}
|
||||
return e;
|
||||
}
|
||||
TwoStrokeConfig resolve_two_stroke_geometry(TwoStrokeConfig e) {
|
||||
if(e.geometry.empty())e.geometry=default_geometry(e);
|
||||
validate_geometry(e.geometry,4,1);
|
||||
const auto* crank=e.geometry.volume("crankcase");if(!crank||!e.geometry.volume("intake_plenum"))throw std::invalid_argument("two-stroke geometry requires crankcase and intake_plenum volumes");
|
||||
e.crankcase_clearance=crank->volume();return e;
|
||||
}
|
||||
}
|
||||
162
src/scenario.cpp
162
src/scenario.cpp
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fluidsim::port {
|
||||
FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset preset)
|
||||
@@ -14,17 +15,22 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate,const ScenarioExample& de
|
||||
: FourStrokeScenario(sample_rate,definition.engine,definition.exhaust,definition.junctions) {}
|
||||
|
||||
FourStrokeScenario::FourStrokeScenario(int sample_rate, EngineConfig configuration, ExhaustConfig exhaust, JunctionConfig fittings)
|
||||
: exhaust_config(exhaust), junction_config(fittings), engine_config(std::move(configuration)),
|
||||
: exhaust_config(exhaust), junction_config(fittings), engine_config(resolve_engine_geometry(std::move(configuration),exhaust,fittings)),
|
||||
intake_plenum(engine_config.plenum_volume,101325,300),
|
||||
exhaust_collector(engine_config.collector_volume,101325,700),
|
||||
pipes(create_pipes(engine_config,exhaust)), dt_(1.f/std::max(sample_rate,1)),
|
||||
boundaries_(pipes), solver_(pipes,boundaries_), audio_(sample_rate,[&] {
|
||||
OutdoorAudioConfig config;
|
||||
config.dual_exhaust=engine_config.dual_outlets();
|
||||
config.valve_contact_enabled=true;
|
||||
return config;
|
||||
}()) {
|
||||
const auto& engine=engine_config;
|
||||
geometry_=std::make_shared<PhysicalGeometry>(engine.geometry);
|
||||
active_tuning_=std::make_shared<EngineConfig>(engine_config);
|
||||
const auto& junctions=junction_config;
|
||||
if(junctions.model!="volume" && junctions.model!="characteristic" && junctions.model!="legacy")
|
||||
throw std::invalid_argument("invalid junction model");
|
||||
const bool v8=engine.american_headers(),staged=engine.staged_headers();
|
||||
const int count=cylinder_count();
|
||||
static_cast<CrankshaftConfig&>(crankshaft)=engine.crankshaft;
|
||||
@@ -48,6 +54,7 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, EngineConfig configurati
|
||||
for (int i=0;i<count;++i) {
|
||||
auto& c=*engines[i];
|
||||
static_cast<CylinderConfig&>(c)=engine.cylinder;
|
||||
c.set_valve_profiles(active_tuning_->intake_cam,engine.intake_valve,active_tuning_->exhaust_cam,engine.exhaust_valve);
|
||||
c.phase=engine.phase_degrees.at(i)*pi/180;
|
||||
c.transported_fuel=engine.carbureted;
|
||||
c.rev_limit_enabled = ecu.rev_limit_enabled;
|
||||
@@ -75,7 +82,7 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, EngineConfig configurati
|
||||
auto& throttle_port = intake_plenum.create_port();
|
||||
throttle_port_=&throttle_port;
|
||||
solver_.add_component(intake_plenum);
|
||||
if(!v8 && !staged) solver_.add_component(exhaust_collector);
|
||||
if(!v8 && !staged && junctions.model=="volume") solver_.add_component(exhaust_collector);
|
||||
boundaries_.add_orifice(throttle_port, 0, false, throttle_area_, .7f);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto& feed = intake_plenum.create_port();
|
||||
@@ -85,24 +92,53 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, EngineConfig configurati
|
||||
boundaries_.add_orifice(feed, 1+i, true, runner_area_);
|
||||
boundaries_.add_orifice(engines[i]->intake, 1+i, false, intake_valve_areas_[i]);
|
||||
boundaries_.add_orifice(engines[i]->exhaust, 1+count+i, true, exhaust_valve_areas_[i]);
|
||||
if (!v8 && !staged) boundaries_.add_orifice(exhaust_collector.create_port(), 1+count+i, false, header_area_);
|
||||
if (!v8 && !staged && junctions.model=="volume") boundaries_.add_orifice(exhaust_collector.create_port(), 1+count+i, false, header_area_);
|
||||
}
|
||||
if(v8) {
|
||||
auto junction=[&](std::initializer_list<JunctionEnd> ends) {
|
||||
auto fitting=std::make_unique<Junction>(junctions.junction_volume,101325,700);
|
||||
fitting->connect(boundaries_,pipes,std::span(ends.begin(),ends.size()));
|
||||
// Node axes follow the last/first route segment, unless explicitly supplied.
|
||||
ScenarioSnapshot geometry;
|
||||
geometry.geometry=geometry_;
|
||||
geometry.cylinder_count=count;geometry.layout=engine.layout;geometry.bank_angle=engine.bank_angle;
|
||||
geometry.v8_headers=v8;geometry.staged_headers=staged;geometry.dual_exhaust=engine.dual_outlets();
|
||||
geometry.h_pipe=junctions.h_pipe;geometry.silencers=engine.has_silenced_exhaust() && exhaust.enabled;geometry.exhaust_config=exhaust;
|
||||
const auto routes=scenario_pipe_routes(geometry);
|
||||
std::vector<bool> branch_used(junctions.branches.size(),false);
|
||||
int junction_index=0;
|
||||
auto junction=[&](std::span<const JunctionEnd> ends) {
|
||||
if(junctions.model=="volume") {
|
||||
const auto* box=engine.geometry.volume("junction_"+std::to_string(junction_index));
|
||||
if(!box)throw std::invalid_argument("geometry missing junction_"+std::to_string(junction_index));
|
||||
auto fitting=std::make_unique<Junction>(box->volume(),101325,700);
|
||||
fitting->connect(boundaries_,pipes,ends);
|
||||
solver_.add_component(*fitting);exhaust_junctions_.push_back(std::move(fitting));
|
||||
};
|
||||
} else {
|
||||
std::vector<BoundarySystem::JunctionFace> faces;
|
||||
for(const auto& e:ends) {
|
||||
const auto& route=routes.at(e.pipe);
|
||||
if(route.count<2) throw std::invalid_argument("junction branch has no route direction");
|
||||
const auto a=route.points[e.left?0:route.count-1], b=route.points[e.left?1:route.count-2];
|
||||
std::array<float,3> direction{b.x-a.x,b.y-a.y,b.z-a.z};
|
||||
for(std::size_t j=0;j<junctions.branches.size();++j) {
|
||||
const auto& override=junctions.branches[j];
|
||||
if(override.pipe==e.pipe && override.left==e.left) { direction=override.direction;branch_used[j]=true; }
|
||||
}
|
||||
faces.push_back({e.pipe,e.left,direction});
|
||||
}
|
||||
boundaries_.add_junction(faces,junctions.model=="legacy"?BoundarySystem::JunctionMethod::LegacyRusanov:BoundarySystem::JunctionMethod::Characteristic,junctions.turning_loss);
|
||||
}
|
||||
++junction_index;
|
||||
};
|
||||
auto join=[&](std::initializer_list<JunctionEnd> ends) { junction(std::span(ends.begin(),ends.size())); };
|
||||
if(v8) {
|
||||
// Within each bank pair cylinders with the widest available firing gaps.
|
||||
junction({{9,false},{10,false},{17,true}});
|
||||
junction({{11,false},{12,false},{18,true}});
|
||||
junction({{13,false},{15,false},{19,true}});
|
||||
junction({{14,false},{16,false},{20,true}});
|
||||
junction({{17,false},{18,false},{21,true}});
|
||||
junction({{19,false},{20,false},{22,true}});
|
||||
join({{9,false},{10,false},{17,true}});
|
||||
join({{11,false},{12,false},{18,true}});
|
||||
join({{13,false},{15,false},{19,true}});
|
||||
join({{14,false},{16,false},{20,true}});
|
||||
join({{17,false},{18,false},{21,true}});
|
||||
join({{19,false},{20,false},{22,true}});
|
||||
if(junctions.h_pipe) {
|
||||
junction({{21,false},{23,true},{25,true}});
|
||||
junction({{22,false},{24,true},{25,false}});
|
||||
join({{21,false},{23,true},{25,true}});
|
||||
join({{22,false},{24,true},{25,false}});
|
||||
} else {
|
||||
boundaries_.add_connection(21,false,23,true);
|
||||
boundaries_.add_connection(22,false,24,true);
|
||||
@@ -114,11 +150,6 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, EngineConfig configurati
|
||||
const int exit=1+2*count;
|
||||
const bool dual=engine.dual_outlets();
|
||||
const int groups=engine.header_groups(), secondary=exit+(dual?2:1);
|
||||
auto junction=[&](const std::vector<JunctionEnd>& ends) {
|
||||
auto fitting=std::make_unique<Junction>(junctions.junction_volume,101325,700);
|
||||
fitting->connect(boundaries_,pipes,ends);
|
||||
solver_.add_component(*fitting);exhaust_junctions_.push_back(std::move(fitting));
|
||||
};
|
||||
for(int group=0;group<groups;++group) {
|
||||
std::vector<JunctionEnd> ends;
|
||||
for(int i=0;i<count;++i)
|
||||
@@ -128,7 +159,7 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, EngineConfig configurati
|
||||
if(dual) {
|
||||
// Preserve independent bank pulse trains all the way to their mouths.
|
||||
for(int bank=0;bank<2;++bank) {
|
||||
junction({{secondary+bank,false},{exit+bank,true}});
|
||||
join({{secondary+bank,false},{exit+bank,true}});
|
||||
boundaries_.add_radiating_open_end(exit+bank,false,101325,pipes[exit+bank].area);
|
||||
}
|
||||
} else {
|
||||
@@ -138,23 +169,37 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, EngineConfig configurati
|
||||
boundaries_.add_radiating_open_end(exit,false,101325,pipes[exit].area);
|
||||
}
|
||||
} else {
|
||||
auto& collector_out = exhaust_collector.create_port();
|
||||
const int exit=1+2*count;
|
||||
boundaries_.add_orifice(collector_out,exit,true,tail_area_);
|
||||
if(junctions.model=="volume") {
|
||||
auto& collector_out = exhaust_collector.create_port();
|
||||
boundaries_.add_orifice(collector_out,exit,true,tail_area_);
|
||||
} else {
|
||||
std::vector<JunctionEnd> ends{{exit,true}};
|
||||
for(int i=0;i<count;++i) ends.push_back({1+count+i,false});
|
||||
junction(ends);
|
||||
}
|
||||
boundaries_.add_radiating_open_end(exit,false,101325,pipes[exit].area);
|
||||
}
|
||||
for(std::size_t i=0;i<branch_used.size();++i)
|
||||
if(junctions.model!="volume" && !branch_used[i]) throw std::invalid_argument("junction direction override does not name an active characteristic/legacy junction branch");
|
||||
boundaries_.add_radiating_open_end(0, true, 101325, pipes[0].area);
|
||||
solver_.set_profiler(&profiler_);
|
||||
audio_.set_source_positions(scenario_sound_sources(snapshot()));
|
||||
}
|
||||
|
||||
AudioFrame FourStrokeScenario::process() {
|
||||
const std::lock_guard guard(mutex_);
|
||||
const bool profile=profiler_.begin_step();
|
||||
ProfileScope total(&profiler_,profile,ProfileStage::Total);
|
||||
float contact_impulse=0;
|
||||
{ ProfileScope controls(&profiler_,profile,ProfileStage::Controls);
|
||||
step_motorcycle(crankshaft, dt_, engine_config.maximum_load_torque);
|
||||
ecu.step(dt_, throttle, crankshaft.omega * 60 / (2*pi));
|
||||
const auto engines = cylinders();
|
||||
for (int i = 0; i < cylinder_count(); ++i) {
|
||||
auto& c = *engines[i];
|
||||
c.pre_step(crankshaft, dt_, throttle);
|
||||
contact_impulse+=c.take_contact_impulse();
|
||||
const float degrees = std::fmod((crankshaft.angle+c.phase)*180/pi, 720.f);
|
||||
intake_valve_areas_[i] = c.valve_area(degrees, true);
|
||||
exhaust_valve_areas_[i] = c.valve_area(degrees, false);
|
||||
@@ -167,7 +212,8 @@ AudioFrame FourStrokeScenario::process() {
|
||||
carb_->step(dt_,throttle,opening,crankshaft.omega*60/(2*pi),std::max(throttle_port_->mass_flow,0.f),inlet.rho,inlet.pressure,intake_plenum.pressure());
|
||||
intake_plenum.add_fuel_mass(carb_->fuel_flow()*dt_);
|
||||
}
|
||||
solver_.step(dt_);
|
||||
}
|
||||
solver_.step(dt_,profile);
|
||||
intake_flow = boundaries_.open_end_mass_flow(engine_config.dual_outlets() ? 2 : 1);
|
||||
exhaust_flow = boundaries_.open_end_mass_flow(0);
|
||||
const float other_exhaust = engine_config.dual_outlets() ? boundaries_.open_end_mass_flow(1) : 0.f;
|
||||
@@ -176,12 +222,57 @@ AudioFrame FourStrokeScenario::process() {
|
||||
const float intake_source = ambient_density * boundaries_.open_end_volume_flow(engine_config.dual_outlets() ? 2 : 1);
|
||||
const float exhaust_source = ambient_density * boundaries_.open_end_volume_flow(0);
|
||||
const float other_source = engine_config.dual_outlets() ? ambient_density * boundaries_.open_end_volume_flow(1) : 0.f;
|
||||
const auto rendered = audio_.process(intake_source, exhaust_source, other_source);
|
||||
const auto& sound=active_tuning_->valve_sound;
|
||||
const float mode_omega=2*pi*sound.mode_hz;
|
||||
valve_sound_velocity_+=contact_impulse/sound.effective_mass_kg;
|
||||
valve_sound_velocity_+=(-mode_omega*mode_omega*valve_sound_displacement_-2*sound.damping_ratio*mode_omega*valve_sound_velocity_)*dt_;
|
||||
valve_sound_displacement_+=valve_sound_velocity_*dt_;
|
||||
const float valve_contact_source=ambient_density*sound.radiation_area*valve_sound_velocity_;
|
||||
ProfileScope audio_profile(&profiler_,profile,ProfileStage::Audio);
|
||||
const auto rendered = audio_.process(intake_source, exhaust_source, other_source,valve_contact_source);
|
||||
// Count sampled frames only after the complete process call has finished.
|
||||
if(profile) profiler_.finish_step(total.elapsed_ns());
|
||||
exhaust_flow += other_exhaust;
|
||||
++sample_count;
|
||||
const auto bin=std::clamp(int(std::fmod((crankshaft.angle+cylinder1.phase)*180/pi,720.f)/4),0,179);
|
||||
intake_lift_trace_[bin]=cylinder1.intake_lift();exhaust_lift_trace_[bin]=cylinder1.exhaust_lift();
|
||||
intake_lift_trace_[180]=intake_lift_trace_[0];exhaust_lift_trace_[180]=exhaust_lift_trace_[0];
|
||||
last_contact_impulse_=contact_impulse;
|
||||
return rendered;
|
||||
}
|
||||
|
||||
void FourStrokeScenario::set_tuning(const EngineConfig& tuning) {
|
||||
validate_engine_config(tuning,"live tuning");
|
||||
// The live editor only changes calibration. Geometry is rebuilt separately.
|
||||
const auto& a=tuning.cylinder;const auto& b=engine_config.cylinder;
|
||||
if(tuning.geometry!=engine_config.geometry || tuning.cylinders!=engine_config.cylinders || tuning.layout!=engine_config.layout ||
|
||||
tuning.topology!=engine_config.topology || tuning.phase_degrees!=engine_config.phase_degrees ||
|
||||
tuning.carbureted!=engine_config.carbureted || tuning.throttle_diameter!=engine_config.throttle_diameter ||
|
||||
a.bore!=b.bore || a.stroke!=b.stroke || a.rod!=b.rod || a.compression!=b.compression ||
|
||||
tuning.cells_per_meter!=engine_config.cells_per_meter || tuning.pipes!=engine_config.pipes || tuning.plenum_volume!=engine_config.plenum_volume ||
|
||||
tuning.collector_volume!=engine_config.collector_volume ||
|
||||
a.intake_valve_count!=b.intake_valve_count || a.exhaust_valve_count!=b.exhaust_valve_count ||
|
||||
a.intake_valve_diameter!=b.intake_valve_diameter || a.exhaust_valve_diameter!=b.exhaust_valve_diameter)
|
||||
throw std::invalid_argument("Live tuning cannot change engine geometry; rebuild the engine instead");
|
||||
auto next=std::make_shared<const EngineConfig>(tuning);
|
||||
auto calibration=tuning.ecu;
|
||||
// The scenario lock spans exactly one process() call. Copy/validation and
|
||||
// retirement of the old profile happen on the editing thread outside it.
|
||||
std::shared_ptr<const EngineConfig> retired;
|
||||
{
|
||||
const std::lock_guard guard(mutex_);
|
||||
retired=std::move(active_tuning_);active_tuning_=std::move(next);
|
||||
std::swap(static_cast<EcuConfig&>(ecu),calibration);
|
||||
if(carb_) {
|
||||
static_cast<CarburetorConfig&>(*carb_)=tuning.fuel;
|
||||
ecu.rev_limit_fuel_cut_enabled=false;ecu.overrun_fuel_cut_enabled=false;ecu.overrun_ignition_cut_enabled=true;
|
||||
}
|
||||
const auto engines=cylinders();
|
||||
for(int i=0;i<cylinder_count();++i)
|
||||
engines[i]->set_valve_profiles(active_tuning_->intake_cam,tuning.intake_valve,active_tuning_->exhaust_cam,tuning.exhaust_valve);
|
||||
}
|
||||
}
|
||||
|
||||
void FourStrokeScenario::set_pipe_solver(PipeSolver solver) {
|
||||
const std::lock_guard guard(mutex_);
|
||||
for(auto& pipe : pipes) pipe.solver=solver;
|
||||
@@ -242,10 +333,25 @@ float FourStrokeScenario::area_for_diameter(float diameter) {
|
||||
std::vector<Pipe1D> FourStrokeScenario::create_pipes(const EngineConfig& engine,const ExhaustConfig& exhaust) {
|
||||
validate_engine_config(engine);
|
||||
std::vector<Pipe1D> pipes;
|
||||
auto mesh_exhaust=exhaust;
|
||||
if(engine.cells_per_meter>0) mesh_exhaust.cell_length=1/engine.cells_per_meter;
|
||||
std::size_t index=0;
|
||||
for(const auto& pipe:engine.pipes)for(int i=0;i<pipe.count;++i) {
|
||||
if(pipe.silenced)pipes.push_back(make_silenced_exhaust(exhaust));
|
||||
else pipes.emplace_back(area_for_diameter(pipe.diameter),pipe.length,pipe.cells);
|
||||
const float length=engine.geometry.pipes.at(index++).length();
|
||||
if(pipe.silenced) {
|
||||
auto layout=mesh_exhaust;
|
||||
const float original=layout.inlet_length+layout.outlet_length+(layout.enabled?layout.connecting_length+layout.resonator.length+layout.muffler.length:0);
|
||||
const float scale=length/original;
|
||||
layout.inlet_length*=scale;layout.outlet_length*=scale;layout.connecting_length*=scale;
|
||||
layout.resonator.length*=scale;layout.resonator.volume*=scale;layout.muffler.length*=scale;layout.muffler.volume*=scale;
|
||||
auto profile=make_silenced_exhaust(layout);
|
||||
if(profile.cells.size()>4096) throw std::invalid_argument("silencer mesh exceeds 4096 cells");
|
||||
pipes.push_back(std::move(profile));
|
||||
}
|
||||
else pipes.emplace_back(area_for_diameter(pipe.diameter),length,engine.cells_per_meter>0?mesh_cell_count(length,engine.cells_per_meter):pipe.cells);
|
||||
}
|
||||
std::size_t total=0;for(const auto& pipe:pipes)total+=pipe.cells.size();
|
||||
if(total>32768) throw std::invalid_argument("network mesh exceeds 32768 cells");
|
||||
return pipes;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,18 @@ PipeRoute route(std::initializer_list<Anchor> anchors) {
|
||||
}
|
||||
std::array<PipeRoute, 32> scenario_pipe_routes(const ScenarioSnapshot& s) {
|
||||
std::array<PipeRoute, 32> routes{};
|
||||
if(s.geometry) {
|
||||
for(std::size_t p=0;p<s.geometry->pipes.size();++p) {
|
||||
const auto& path=s.geometry->pipes[p];auto& result=routes[p];float distance=0;
|
||||
const float total=path.length();
|
||||
for(std::size_t i=0;i<path.points.size();++i) {
|
||||
if(i)distance+=geometry_distance(path.points[i-1],path.points[i]);
|
||||
result.points[i]=path.points[i];result.fractions[i]=distance/total;
|
||||
}
|
||||
result.count=static_cast<unsigned>(path.points.size());result.fractions[result.count-1]=1;
|
||||
}
|
||||
return routes;
|
||||
}
|
||||
if (s.two_stroke) {
|
||||
routes[0]=route({{0,{-1.05f,.35f,0}},{1,{-.64f,.35f,0}}});
|
||||
routes[1]=route({{0,{-.46f,.35f,0}},{1.f/3,{-.28f,.35f,0}},{2.f/3,{-.28f,.1f,0}},{1,{-.105f,.1f,0}}});
|
||||
@@ -75,6 +87,11 @@ std::array<PipeRoute, 32> scenario_pipe_routes(const ScenarioSnapshot& s) {
|
||||
}
|
||||
return routes;
|
||||
}
|
||||
bool scenario_pipe_is_exhaust(const ScenarioSnapshot& s,std::size_t p) {
|
||||
if(s.two_stroke)return p==3;
|
||||
if(s.v8_headers)return p>=9;
|
||||
return p>=static_cast<std::size_t>(1+ s.cylinder_count);
|
||||
}
|
||||
std::array<Vec3,3> scenario_sound_sources(const ScenarioSnapshot& s) {
|
||||
const auto routes=scenario_pipe_routes(s);
|
||||
const int exhaust=s.two_stroke?3:s.v8_headers?23:1+2*s.cylinder_count;
|
||||
|
||||
@@ -5,6 +5,20 @@ namespace fluidsim::port {
|
||||
ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
ScenarioSnapshot result;
|
||||
result.geometry=geometry_;
|
||||
result.cylinder_bore=engine_config.cylinder.bore;result.cylinder_stroke=engine_config.cylinder.stroke;
|
||||
result.cylinder_rod=engine_config.cylinder.rod;result.cylinder_clearance=cylinder1.clearance_volume();
|
||||
result.intake_valve_diameter=engine_config.cylinder.intake_valve_diameter;result.exhaust_valve_diameter=engine_config.cylinder.exhaust_valve_diameter;
|
||||
result.storage_volumes.push_back({"intake_plenum",*engine_config.geometry.volume("intake_plenum"),intake_plenum.pressure()});
|
||||
if(junction_config.model=="volume") {
|
||||
if(!engine_config.american_headers()&&!engine_config.staged_headers())
|
||||
result.storage_volumes.push_back({"exhaust_collector",*engine_config.geometry.volume("exhaust_collector"),exhaust_collector.pressure()});
|
||||
for(std::size_t i=0;i<exhaust_junctions_.size();++i) {
|
||||
const auto id="junction_"+std::to_string(i);
|
||||
result.storage_volumes.push_back({id,*engine_config.geometry.volume(id),exhaust_junctions_[i]->pressure()});
|
||||
}
|
||||
}
|
||||
result.cells_per_meter=engine_config.cells_per_meter;
|
||||
result.layout=engine_config.layout;
|
||||
result.bank_angle=engine_config.bank_angle;
|
||||
result.v8_headers=engine_config.american_headers();
|
||||
@@ -12,11 +26,21 @@ ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
result.dual_exhaust=engine_config.dual_outlets();
|
||||
result.silencers = engine_config.has_silenced_exhaust() && exhaust_config.enabled;
|
||||
result.exhaust_config = exhaust_config;
|
||||
if(result.silencers) {
|
||||
const auto& e=exhaust_config;const int index=1+2*cylinder_count();
|
||||
const float scale=engine_config.geometry.pipes[index].length()/(e.inlet_length+e.connecting_length+e.resonator.length+e.muffler.length+e.outlet_length);
|
||||
result.pipe_housings.push_back({std::size_t(index),e.inlet_length*scale,e.resonator.length*scale,e.resonator.diameter()});
|
||||
result.pipe_housings.push_back({std::size_t(index),(e.inlet_length+e.resonator.length+e.connecting_length)*scale,e.muffler.length*scale,e.muffler.diameter()});
|
||||
}
|
||||
result.h_pipe = engine_config.american_headers() && junction_config.h_pipe;
|
||||
result.crossover_pressures = engine_config.american_headers() ? std::array<float,2>{pipes[21].state(0).pressure,pipes[22].state(0).pressure} : std::array<float,2>{};
|
||||
result.pipe_solver = pipes.front().solver;
|
||||
result.solver_substeps = solver_.substep_count();
|
||||
result.boundary_iterations = boundaries_.nonlinear_iterations;
|
||||
result.junction_fallbacks=boundaries_.junction_fallbacks;
|
||||
result.junction_limited_fluxes=boundaries_.junction_limited_fluxes;
|
||||
result.junction_iterations=boundaries_.junction_iterations;
|
||||
result.boundary_limited_fluxes=boundaries_.limited_fluxes;
|
||||
result.rpm = crankshaft.omega * 60.0f / (2.0f * pi);
|
||||
result.speed_kmh = vehicle.speed * 3.6f;
|
||||
result.kinetic_energy = vehicle.kinetic_energy();
|
||||
@@ -52,7 +76,15 @@ ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
result.rev_limit1 = cylinder1.rev_limit_active;
|
||||
result.rev_limit2 = cylinder2.rev_limit_active;
|
||||
result.cylinder_count = cylinder_count();
|
||||
for(int i=0;i<cylinder_count();++i)result.valve_float=result.valve_float||cylinders()[i]->valve_floating();
|
||||
result.rev_limit_rpm = ecu.rev_limit_rpm;
|
||||
result.intake_lift=cylinder1.intake_lift();result.exhaust_lift=cylinder1.exhaust_lift();
|
||||
result.valve_contact_impulse=last_contact_impulse_;
|
||||
result.intake_lift_trace=intake_lift_trace_;result.exhaust_lift_trace=exhaust_lift_trace_;
|
||||
for(std::size_t i=0;i<181;++i) {
|
||||
result.intake_cam_lifts[i]=FourStrokeCylinder::cam_lift_at(active_tuning_->intake_cam,float(i)*4);
|
||||
result.exhaust_cam_lifts[i]=FourStrokeCylinder::cam_lift_at(active_tuning_->exhaust_cam,float(i)*4);
|
||||
}
|
||||
const std::array<const FourStrokeCylinder*, 12> engines{&cylinder1, &cylinder2, &cylinder3, &cylinder4,
|
||||
&cylinder5, &cylinder6, &cylinder7, &cylinder8,&cylinder9,&cylinder10,&cylinder11,&cylinder12};
|
||||
for (int i = 0; i < cylinder_count(); ++i) {
|
||||
@@ -61,6 +93,7 @@ ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
result.piston_fractions[i] = (engines[i]->volume-engines[i]->clearance_volume())/engines[i]->swept_volume();
|
||||
result.intake_areas[i] = intake_valve_areas_[i];
|
||||
result.exhaust_areas[i] = exhaust_valve_areas_[i];
|
||||
result.intake_lifts[i]=engines[i]->intake_lift();result.exhaust_lifts[i]=engines[i]->exhaust_lift();
|
||||
}
|
||||
result.capture_pipes(pipes);
|
||||
return result;
|
||||
|
||||
@@ -9,7 +9,8 @@ Solver::Solver(std::vector<Pipe1D> &pipes, BoundarySystem &boundaries)
|
||||
|
||||
void Solver::add_component(Component &component) { components_.push_back(&component); }
|
||||
|
||||
void Solver::step(float dt) {
|
||||
void Solver::step(float dt,bool profile_sample) {
|
||||
ProfileScope scope(profiler_,profile_sample,ProfileStage::Solver);
|
||||
if (!std::isfinite(dt) || dt < 0)
|
||||
throw std::invalid_argument("invalid solver timestep");
|
||||
if (dt == 0)
|
||||
@@ -25,11 +26,11 @@ void Solver::step(float dt) {
|
||||
if (!(sub_dt > 0) || ++count > 1000000)
|
||||
throw std::runtime_error("solver timestep failed to progress");
|
||||
++substep_count_;
|
||||
boundaries_.resolve(sub_dt);
|
||||
for (auto &pipe : pipes_)
|
||||
pipe.advance(sub_dt);
|
||||
for (Component *component : components_)
|
||||
component->update_state(sub_dt);
|
||||
{ ProfileScope measured(profiler_,profile_sample,ProfileStage::Boundary);boundaries_.resolve(sub_dt); }
|
||||
{ ProfileScope measured(profiler_,profile_sample,ProfileStage::Pipe);
|
||||
for (auto &pipe : pipes_) pipe.advance(sub_dt); }
|
||||
{ ProfileScope measured(profiler_,profile_sample,ProfileStage::Components);
|
||||
for (Component *component : components_) component->update_state(sub_dt); }
|
||||
remaining -= sub_dt;
|
||||
}
|
||||
++step_count_;
|
||||
|
||||
@@ -9,14 +9,15 @@
|
||||
namespace fluidsim::port {
|
||||
|
||||
TwoStrokeScenario::TwoStrokeScenario(int sample_rate, TwoStrokeConfig config)
|
||||
: configuration(config),
|
||||
: configuration(resolve_two_stroke_geometry(config)),
|
||||
carburetor(config.carburetor_diameter),
|
||||
cylinder(config.bore, config.stroke, config.rod, config.geometric_compression(),
|
||||
config.transfer_duration, config.exhaust_duration),
|
||||
crankcase(crankshaft, config.stroke * .5f, config.rod, config.bore, config.crankcase_clearance), pipes(create_pipes(config)),
|
||||
crankcase(crankshaft, config.stroke * .5f, config.rod, config.bore, configuration.crankcase_clearance),
|
||||
intake_plenum(configuration.geometry.volume("intake_plenum")->volume(),101325,300),pipes(create_pipes(configuration)),
|
||||
dt_(1.0f / static_cast<float>(std::max(sample_rate, 1))), max_throttle_area_(area_for_diameter(config.carburetor_diameter)),
|
||||
reed_in_area_(area_for_diameter(0.040f)), reed_out_area_(0.0f),
|
||||
transfer_pipe_area_(area_for_diameter(0.032f)), transfer_valve_area_(0.0f), exhaust_valve_area_(0.0f),
|
||||
reed_in_area_(area_for_diameter(config.reed_pipe_diameter)), reed_out_area_(0.0f),
|
||||
transfer_pipe_area_(area_for_diameter(config.transfer_pipe_diameter)), transfer_valve_area_(0.0f), exhaust_valve_area_(0.0f),
|
||||
boundaries_(pipes), solver_(pipes, boundaries_), audio_(sample_rate) {
|
||||
if (!std::isfinite(config.idle_slide_opening) || config.idle_slide_opening<0 || config.idle_slide_opening>1)
|
||||
throw std::invalid_argument("carb idle slide opening must be in [0,1]");
|
||||
@@ -91,10 +92,15 @@ TwoStrokeScenario::TwoStrokeScenario(int sample_rate, TwoStrokeConfig config)
|
||||
solver_.add_component(cylinder);
|
||||
ScenarioSnapshot geometry;
|
||||
geometry.two_stroke=true;
|
||||
geometry_=std::make_shared<PhysicalGeometry>(configuration.geometry);geometry.geometry=geometry_;
|
||||
solver_.set_profiler(&profiler_);
|
||||
audio_.set_source_positions(scenario_sound_sources(geometry));
|
||||
}
|
||||
|
||||
AudioFrame TwoStrokeScenario::process() {
|
||||
const bool profile=profiler_.begin_step();
|
||||
ProfileScope total(&profiler_,profile,ProfileStage::Total);
|
||||
{ ProfileScope controls(&profiler_,profile,ProfileStage::Controls);
|
||||
const float upstream = pipes[1].state(static_cast<int>(pipes[1].cells.size()) - 1).pressure;
|
||||
reed_out_area_ = std::min(reed.step(dt_, upstream - crankcase.pressure()), reed_in_area_);
|
||||
reed_open_ = reed.lift() > 1e-6f;
|
||||
@@ -110,13 +116,17 @@ AudioFrame TwoStrokeScenario::process() {
|
||||
cylinder.pre_step(crankshaft, dt_, ecu.throttle_opening());
|
||||
transfer_valve_area_ = cylinder.valve_area(crankshaft.angle * 180.0f / pi, true);
|
||||
exhaust_valve_area_ = cylinder.valve_area(crankshaft.angle * 180.0f / pi, false);
|
||||
solver_.step(dt_);
|
||||
}
|
||||
solver_.step(dt_,profile);
|
||||
++step_count_;
|
||||
|
||||
intake_flow = boundaries_.open_end_mass_flow(1);
|
||||
exhaust_flow = boundaries_.open_end_mass_flow(0);
|
||||
return audio_.process(ambient_density * boundaries_.open_end_volume_flow(1),
|
||||
ambient_density * boundaries_.open_end_volume_flow(0));
|
||||
ProfileScope audio_profile(&profiler_,profile,ProfileStage::Audio);
|
||||
const auto result=audio_.process(ambient_density * boundaries_.open_end_volume_flow(1),
|
||||
ambient_density * boundaries_.open_end_volume_flow(0));
|
||||
if(profile) profiler_.finish_step(total.elapsed_ns());
|
||||
return result;
|
||||
}
|
||||
|
||||
void TwoStrokeScenario::set_throttle(float value) { throttle = std::clamp(value, 0.0f, 1.0f); }
|
||||
@@ -155,21 +165,38 @@ float TwoStrokeScenario::slide_area(float diameter, float opening) {
|
||||
}
|
||||
|
||||
std::vector<Pipe1D> TwoStrokeScenario::create_pipes(const TwoStrokeConfig& config) {
|
||||
if(config.cells_per_meter!=0) mesh_cell_count(.1f,config.cells_per_meter);
|
||||
std::vector<Pipe1D> result;
|
||||
result.reserve(4);
|
||||
result.emplace_back(area_for_diameter(config.carburetor_diameter), .100f, 10);
|
||||
result.emplace_back(area_for_diameter(.040f), .030f, 4);
|
||||
result.emplace_back(area_for_diameter(.032f), .060f, 6);
|
||||
const auto count=[&](float length,int legacy) {return config.cells_per_meter>0?mesh_cell_count(length,config.cells_per_meter):legacy;};
|
||||
const float cell_length=config.cells_per_meter>0?1/config.cells_per_meter:config.exhaust_cell_length;
|
||||
for(int i=0;i<3;++i) {
|
||||
const float diameter=i==0?config.carburetor_diameter:i==1?config.reed_pipe_diameter:config.transfer_pipe_diameter;
|
||||
const float length=config.geometry.pipes[i].length();
|
||||
result.emplace_back(area_for_diameter(diameter),length,count(length,i==0?10:i==1?4:6));
|
||||
}
|
||||
auto sections=config.racing_pipe;float original=0;for(const auto& s:sections)original+=s.length;
|
||||
const float scale=config.geometry.pipes[3].length()/original;for(auto& s:sections)s.length*=scale;
|
||||
if (config.exhaust == TwoStrokeExhaust::Racing) {
|
||||
result.push_back(make_profiled_pipe(config.racing_pipe, config.exhaust_cell_length));
|
||||
result.push_back(make_profiled_pipe(sections, cell_length));
|
||||
} else {
|
||||
float length = 0;
|
||||
for (const auto& section : config.racing_pipe) length += section.length;
|
||||
for (const auto& section : sections) length += section.length;
|
||||
const PipeSection straight{length, config.racing_pipe.front().inlet_diameter,
|
||||
config.racing_pipe.front().inlet_diameter};
|
||||
result.push_back(make_profiled_pipe(std::span(&straight, 1), config.exhaust_cell_length));
|
||||
result.push_back(make_profiled_pipe(std::span(&straight, 1), cell_length));
|
||||
}
|
||||
if(result.back().cells.size()>4096) throw std::invalid_argument("two-stroke exhaust exceeds 4096 cells");
|
||||
return result;
|
||||
}
|
||||
|
||||
void TwoStrokeScenario::capture_geometry(ScenarioSnapshot& s) const {
|
||||
s.geometry=geometry_;s.cylinder_bore=configuration.bore;s.cylinder_stroke=configuration.stroke;
|
||||
s.cylinder_rod=configuration.rod;s.cylinder_clearance=cylinder.clearance_volume();
|
||||
s.storage_volumes.push_back({"intake_plenum",*configuration.geometry.volume("intake_plenum"),intake_plenum.pressure()});
|
||||
auto box=*configuration.geometry.volume("crankcase");const float bottom=box.minimum().y;
|
||||
box.size.y=crankcase.volume()/(box.size.x*box.size.z);box.center.y=bottom+box.size.y*.5f;
|
||||
s.storage_volumes.push_back({"crankcase",box,crankcase.pressure()});
|
||||
}
|
||||
|
||||
} // namespace fluidsim::port
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
#include "FluidSim/Desktop/DesktopUi.hpp"
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include "FluidSim/ScenarioCatalog.hpp"
|
||||
#include "FluidSim/DesktopScenario.hpp"
|
||||
#include "FluidSim/Desktop/PlaybackControl.hpp"
|
||||
#include "FluidSim/Desktop/PipePath.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
using namespace fluidsim::port::desktop;
|
||||
void check(bool condition,const char* reason) {if(!condition)throw std::runtime_error(reason);}
|
||||
int main() {
|
||||
int main(int argc,char** argv) {
|
||||
PlaybackControl playback;
|
||||
sf::Event space=sf::Event::KeyPressed{.code=sf::Keyboard::Key::Space};
|
||||
sf::Event wheel=sf::Event::MouseWheelScrolled{sf::Mouse::Wheel::Vertical,-1.f,{400,300}};
|
||||
check(playback.realtime()&&!playback.handle_event(wheel,true),"realtime mode intercepted camera scrolling");
|
||||
check(playback.handle_event(space)&&!playback.realtime(),"Space did not disable realtime");
|
||||
check(!playback.handle_event(wheel)&&playback.target_speed()==1,"regular scroll changed manual speed");
|
||||
check(playback.handle_event(wheel,true)&&playback.target_speed()<1,"Shift+scroll did not change manual speed");
|
||||
const auto manual=playback.target_speed();playback.handle_event(space);check(playback.target_speed()==1,"Space did not restore realtime");
|
||||
playback.handle_event(space);check(playback.target_speed()==manual,"manual speed was lost");
|
||||
PipePath corner({{0,{0,0,0}},{1,{1,0,0}},{2,{1,1,0}}});
|
||||
check(corner.position(.5f)==fluidsim::port::Vec3{.5f,0,0}&&corner.position(1.5f)==fluidsim::port::Vec3{1,.5f,0},"sharp pipe bend was rounded into a spline");
|
||||
const auto miter=corner.miter_offset(1,{.70710678f,-.70710678f,0});
|
||||
check(std::abs(miter.x-1)<1e-5f&&std::abs(miter.y+1)<1e-5f,"90 degree pipe joint pinches the cross-section");
|
||||
for(auto size : {sf::Vector2u{933,1010},sf::Vector2u{1920,1080},sf::Vector2u{1040,800},sf::Vector2u{800,700}}) {
|
||||
const auto l=WorkspaceLayout::calculate(size);
|
||||
for(auto r : {l.sidebar,l.viewport,l.chart,l.inspector,l.pedal}) {
|
||||
@@ -46,5 +65,31 @@ int main() {
|
||||
check(std::abs(std::cos(y)*listener.right.x+std::sin(y)*listener.right.z-1)<1e-6f,
|
||||
"audio ears must rotate with the camera right axis");
|
||||
}
|
||||
std::cout<<"Desktop layout, spring pedal, keyboard travel and orbit camera checks passed\n";
|
||||
ui.configure_resolution(20);
|
||||
const auto buttons=DesktopUi::resolution_buttons(size);
|
||||
const auto plus=buttons[1].position+sf::Vector2f{10,8};
|
||||
ui.handle_event(sf::Event::MouseButtonPressed{sf::Mouse::Button::Left,{int(plus.x),int(plus.y)}},size);
|
||||
check(ui.take_resolution_request()==25,"resolution plus button failed");
|
||||
ui.resolution_started();
|
||||
ui.handle_event(sf::Event::MouseButtonPressed{sf::Mouse::Button::Left,{int(plus.x),int(plus.y)}},size);
|
||||
check(!ui.take_resolution_request(),"resolution changed while rebuilding");
|
||||
ui.resolution_finished(25,"Applied");
|
||||
if(argc==3 && std::string(argv[1])=="--preview") {
|
||||
const std::filesystem::path directory=argv[2];std::filesystem::create_directories(directory);
|
||||
sf::ContextSettings context;context.depthBits=24;context.majorVersion=2;context.minorVersion=1;
|
||||
sf::RenderWindow window(sf::VideoMode({1440,900}),"Geometry preview",sf::Style::Default,sf::State::Windowed,context);
|
||||
window.setVisible(false);sf::Font font("C:/Windows/Fonts/consola.ttf");
|
||||
const auto& catalog=fluidsim::port::scenario_examples();
|
||||
sf::RenderTexture contact({1280,static_cast<unsigned>((catalog.size()+3)/4)*200});contact.clear(sf::Color::Black);
|
||||
unsigned index=0;
|
||||
for(const auto& example:catalog) {
|
||||
fluidsim::port::DesktopScenario simulation(example);for(int i=0;i<512;++i)simulation.process();
|
||||
const auto state=simulation.snapshot();DesktopUi preview;preview.configure_resolution(state.cells_per_meter);preview.draw(window,&font,state,{});
|
||||
sf::Texture texture(window.getSize());texture.update(window);
|
||||
check(texture.copyToImage().saveToFile(directory/(example.id+".png")),"could not save geometry preview");
|
||||
sf::Sprite thumbnail(texture);thumbnail.setScale({320.f/window.getSize().x,200.f/window.getSize().y});thumbnail.setPosition({float(index%4)*320,float(index/4)*200});contact.draw(thumbnail);++index;
|
||||
}
|
||||
contact.display();check(contact.getTexture().copyToImage().saveToFile(directory/"catalog.png"),"could not save catalog preview");
|
||||
}
|
||||
std::cout<<"Desktop controls, resolution stepper, and camera checks passed\n";
|
||||
}
|
||||
|
||||
@@ -56,14 +56,29 @@ int main() {
|
||||
}
|
||||
check(rejected,"invalid config accepted: "+expected);
|
||||
};
|
||||
auto changed=original;replace(changed,"schema_version = 1","schema_version = 99");reject(changed,"schema_version");
|
||||
auto changed=original;replace(changed,"schema_version = 2","schema_version = 99");reject(changed,"schema_version");
|
||||
changed=original;replace(changed,"bore_mm = 75.0","bore_mn = 75.0");reject(changed,"bore_mm");
|
||||
changed=original;replace(changed,"bore_mm = 75.0","bore_mm = -75.0");reject(changed,"cylinder");
|
||||
changed=original;replace(changed,"cylinders = 2","cylinders = 2.5");reject(changed,"integer");
|
||||
changed=original;replace(changed,"layout = \"inline\"","layout = \"flatbread\"");reject(changed,"layout");
|
||||
changed=original;replace(changed,"topology = \"collector\"","topology = \"american_v8\"");reject(changed,"V8");
|
||||
changed=original;replace(changed,"cells = 10","cells = 1000000");reject(changed,"cell");
|
||||
changed=original;replace(changed,"cells_per_meter = 50.0","cells_per_meter = 1000000");reject(changed,"cells_per_meter");
|
||||
changed=original;replace(changed,"phase_degrees = [0.0, 180.0]","phase_degrees = [0.0]");reject(changed,"phase_degrees");
|
||||
reject(original+"\n[junctions]\nmodel = \"mystery\"\n","model must be");
|
||||
reject(original+"\n[junctions]\nturning_loss = -1\n","turning_loss");
|
||||
reject(original+"\n[[junctions.branches]]\npipe=3\nleft=false\ndirection=[0,0,0]\n","nonzero");
|
||||
{
|
||||
std::ofstream output(file);
|
||||
output<<original<<"\n[junctions]\nmodel=\"characteristic\"\nturning_loss=0.5\n"
|
||||
<<"[[junctions.branches]]\npipe=3\nleft=false\ndirection=[-1,0,0]\n";
|
||||
}
|
||||
const auto directed=load_engine_file(file);
|
||||
check(directed.junctions.model=="characteristic" && directed.junctions.branches.size()==1,"junction configuration was not loaded");
|
||||
{
|
||||
DesktopScenario scenario(directed);
|
||||
for(int i=0;i<2048;++i) scenario.process();
|
||||
check(scenario.snapshot().pipe_positivity_repairs==0,"configured characteristic engine needs positivity repairs");
|
||||
}
|
||||
reject(original+"\n[unknown_section]\nvalue = 1\n","unknown field");
|
||||
reject("schema_version = [","Error");
|
||||
|
||||
|
||||
@@ -794,6 +794,38 @@ int main(int argc,char** argv) {
|
||||
"thermal relaxation differs from exact exponential");
|
||||
});
|
||||
|
||||
test("pipe solver scratch follows runtime solver changes", [] {
|
||||
Pipe1D pipe(.001f,.2f,16);
|
||||
pipe.left_ghost=pipe.state(0);
|
||||
pipe.right_ghost=pipe.state(15);
|
||||
pipe.solver=PipeSolver::Rusanov;
|
||||
pipe.prepare_step();
|
||||
const auto rusanov_bytes=pipe.scratch_bytes();
|
||||
pipe.solver=PipeSolver::Hlle;
|
||||
pipe.prepare_step();
|
||||
const auto hlle_bytes=pipe.scratch_bytes();
|
||||
pipe.solver=PipeSolver::Muscl;
|
||||
pipe.prepare_step();
|
||||
const auto muscl_bytes=pipe.scratch_bytes();
|
||||
check(rusanov_bytes<hlle_bytes && hlle_bytes<muscl_bytes,
|
||||
"solver-specific work buffers were not allocated on demand");
|
||||
for(auto solver : {PipeSolver::Rusanov,PipeSolver::Hlle,PipeSolver::Hllc,
|
||||
PipeSolver::Muscl,PipeSolver::Rusanov}) {
|
||||
pipe.solver=solver;
|
||||
for(int step=0;step<8;++step) {
|
||||
pipe.left_ghost=pipe.state(0);
|
||||
pipe.right_ghost=pipe.state(15);
|
||||
const float dt=.5f*pipe.prepare_step();
|
||||
pipe.advance(dt);
|
||||
}
|
||||
}
|
||||
for(int i=0;i<16;++i) {
|
||||
const auto state=pipe.state(i);
|
||||
check(std::isfinite(state.rho)&&std::isfinite(state.pressure)&&
|
||||
state.rho>0&&state.pressure>0,"solver switch produced a nonphysical pipe state");
|
||||
}
|
||||
});
|
||||
|
||||
test("sealed crankcase compression conserves mass above five bar", [] {
|
||||
Crankshaft crank;
|
||||
crank.angle = 0;
|
||||
|
||||
79
tests/junction_tests.cpp
Normal file
79
tests/junction_tests.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "FluidSim/Solver.hpp"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
using namespace fluidsim::port;
|
||||
namespace {
|
||||
void check(bool condition,const char* message) { if(!condition) throw std::runtime_error(message); }
|
||||
struct Outcome { std::array<double,3> mass{}, pressure{}; std::uint64_t fallbacks{}; };
|
||||
Outcome flow(bool reverse,bool rotate,float loss,bool mixed=false,bool swap_donors=false) {
|
||||
std::vector<Pipe1D> pipes;
|
||||
for(int j=0;j<3;++j) {
|
||||
pipes.emplace_back(.001f*(mixed?j+1:1),.2f,8);
|
||||
for(auto& cell:pipes.back().cells) {
|
||||
const double rho=mixed?(j==0?1.4:1.1):ambient_density;
|
||||
const double p=mixed?(j==0?120000:101325):101325;
|
||||
const double u=(swap_donors?(j==0?0:-50):(j==0?70:0))*(reverse?-1:1);
|
||||
cell={float(rho),float(rho*u),float(p/pipe_gm1+.5*rho*u*u),j==0?.7f:1.f,j==0?.1f:0.f};
|
||||
}
|
||||
}
|
||||
BoundarySystem boundaries(pipes);
|
||||
std::array<std::array<float,3>,3> axes{{{-1,0,0},{1,0,0},{0,1,0}}};
|
||||
if(rotate) for(auto& axis:axes) axis={-axis[1],axis[0],axis[2]};
|
||||
boundaries.add_junction({{0,reverse,axes[0]},{1,!reverse,axes[1]},{2,!reverse,axes[2]}},BoundarySystem::JunctionMethod::Characteristic,loss);
|
||||
boundaries.add_closed_end(0,!reverse);boundaries.add_closed_end(1,reverse);boundaries.add_closed_end(2,reverse);
|
||||
const auto totals=[&] {
|
||||
std::array<double,4> t{};
|
||||
for(auto& p:pipes) for(int i=0;i<int(p.cells.size());++i) {
|
||||
const double m=p.cell_mass(i);
|
||||
t[0]+=m;t[1]+=double(p.cells[i].energy)*p.cell_area(i)*p.cell_length(i);
|
||||
t[2]+=m*p.cells[i].air;t[3]+=m*p.cells[i].fuel;
|
||||
}
|
||||
return t;
|
||||
};
|
||||
const auto initial=totals();Solver solver(pipes,boundaries);solver.minimum_substeps=1;
|
||||
// End before waves reflected by the sealed far ends reach the fitting.
|
||||
for(int i=0;i<30;++i) solver.step(1e-5f);
|
||||
const auto final=totals();
|
||||
for(int j=0;j<4;++j) check(std::abs(final[j]-initial[j])<std::max(1e-10,std::abs(initial[j])*1e-5),"junction lost mass, energy, or species");
|
||||
Outcome result;
|
||||
for(int j=0;j<3;++j) {
|
||||
const int endpoint=(j==0?reverse:!reverse)?0:7;
|
||||
result.pressure[j]=pipes[j].state(endpoint).pressure;
|
||||
for(int i=0;i<8;++i) result.mass[j]+=pipes[j].cell_mass(i);
|
||||
check(pipes[j].positivity_repairs==0,"junction needed positivity repair");
|
||||
}
|
||||
result.fallbacks=boundaries.junction_fallbacks;
|
||||
check(result.fallbacks==0,"subsonic junction unexpectedly fell back");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
try {
|
||||
const auto ideal=flow(false,false,0);
|
||||
check(std::abs(ideal.mass[1]-ideal.mass[2])<1e-10,"ideal equal-area outlets are asymmetric");
|
||||
const auto directed=flow(false,false,1);
|
||||
check(directed.mass[1]>directed.mass[2]+1e-8,"turning loss does not favor straight-through flow");
|
||||
const auto rotated=flow(false,true,1), reversed=flow(true,false,1);
|
||||
for(int j=0;j<3;++j) {
|
||||
check(std::abs(rotated.mass[j]-directed.mass[j])<1e-10,"rotating junction changes flow");
|
||||
check(std::abs(reversed.mass[j]-directed.mass[j])<1e-9,"pipe coordinate reversal changes flow");
|
||||
}
|
||||
flow(false,false,.5f,true);flow(true,true,.5f,true);
|
||||
flow(false,false,.5f,true,true);flow(true,true,.5f,true,true);
|
||||
// Supersonic endpoint data must explicitly select the conservative fallback.
|
||||
std::vector<Pipe1D> pipes;for(int j=0;j<2;++j) pipes.emplace_back(.001f,.1f,4);
|
||||
for(auto& cell:pipes[0].cells) { const float u=500;cell.momentum=cell.rho*u;cell.energy+=.5f*cell.rho*u*u; }
|
||||
BoundarySystem boundaries(pipes);
|
||||
boundaries.add_junction({{0,false},{1,true}});
|
||||
boundaries.add_closed_end(0,true);boundaries.add_closed_end(1,false);
|
||||
Solver solver(pipes,boundaries);solver.minimum_substeps=1;solver.step(1e-6f);
|
||||
check(boundaries.junction_fallbacks==1,"supersonic fallback was not reported");
|
||||
bool rejected=false;
|
||||
try { BoundarySystem invalid(pipes);invalid.add_junction({{0,false},{1,true}},BoundarySystem::JunctionMethod::Characteristic,1); }
|
||||
catch(const std::invalid_argument&) {rejected=true;}
|
||||
check(rejected,"directionless turning-loss node was accepted");
|
||||
std::cout<<"Junction conservation, species, direction, rotation, reversal, and fallback tests passed\n";
|
||||
} catch(const std::exception& e) { std::cerr<<e.what()<<'\n';return 1; }
|
||||
}
|
||||
79
tests/live_tuning_tests.cpp
Normal file
79
tests/live_tuning_tests.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "FluidSim/DesktopScenario.hpp"
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
|
||||
using namespace fluidsim::port;
|
||||
namespace {
|
||||
void check(bool value,const char* message) {if(!value)throw std::runtime_error(message);}
|
||||
bool near(float a,float b) {return std::abs(a-b)<1e-5f;}
|
||||
struct TempDirectory {
|
||||
std::filesystem::path path=std::filesystem::temp_directory_path()/
|
||||
("fluidsim-live-tuning-"+std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
||||
TempDirectory(){std::filesystem::create_directory(path);}
|
||||
~TempDirectory(){std::error_code ignored;std::filesystem::remove_all(path,ignored);}
|
||||
};
|
||||
}
|
||||
int main() {
|
||||
const auto& source=scenario_example("single-450");
|
||||
FourStrokeScenario simulation(44100,source);
|
||||
for(int i=0;i<1024;++i)simulation.process();
|
||||
const float rpm=simulation.crankshaft.omega,angle=simulation.crankshaft.angle;
|
||||
const float pressure=simulation.cylinder1.pressure,lift=simulation.cylinder1.intake_lift();
|
||||
const auto samples=simulation.sample_count;
|
||||
auto tuned=source.engine;
|
||||
tuned.intake_valve.mass_kg=.047f;tuned.intake_valve.spring_rate_n_per_m=45000;
|
||||
tuned.intake_valve.damping_n_s_per_m=32;tuned.valve_sound.radiation_area=.0005f;
|
||||
tuned.ecu.idle_base_opening=.055f;tuned.fuel.pilot_jet_diameter*=1.1f;
|
||||
for(auto& p:tuned.intake_cam.points)p.lift_metres*=.8f;
|
||||
for(auto& p:tuned.ecu.ignition_map)p.degrees_btdc+=4;
|
||||
simulation.set_tuning(tuned);
|
||||
check(simulation.crankshaft.omega==rpm && simulation.crankshaft.angle==angle && simulation.sample_count==samples,"live edit restarted the engine");
|
||||
check(simulation.cylinder1.pressure==pressure && simulation.cylinder1.intake_lift()==lift,"live edit reset cylinder or valve state");
|
||||
const auto snapshot=simulation.snapshot();
|
||||
check(near(snapshot.intake_cam_lifts[120],FourStrokeCylinder::cam_lift_at(tuned.intake_cam,480)),"live cam profile was not published");
|
||||
check(near(simulation.ecu.idle_base_opening,.055f),"ECU calibration was not applied");
|
||||
for(int i=0;i<2048;++i) {
|
||||
const auto frame=simulation.process();
|
||||
check(std::isfinite(frame.left) && std::isfinite(frame.right),"live tuning produced nonfinite audio");
|
||||
}
|
||||
auto invalid=tuned;invalid.pipes[0].length*=1.5f;
|
||||
bool rejected=false;try {simulation.set_tuning(invalid);}catch(const std::invalid_argument&){rejected=true;}
|
||||
check(rejected,"mesh edits must require a rebuild");
|
||||
invalid=tuned;invalid.intake_valve.mass_kg=std::numeric_limits<float>::quiet_NaN();
|
||||
rejected=false;try {simulation.set_tuning(invalid);}catch(const std::exception&){rejected=true;}
|
||||
check(rejected,"invalid calibration accepted");
|
||||
|
||||
TempDirectory temp;
|
||||
const auto saved=save_tuned_engine(source,tuned,temp.path);
|
||||
const auto loaded=load_engine_file(saved);
|
||||
check(loaded.id=="single-450-tuned" && loaded.source_path!=source.source_path,"export replaced source identity");
|
||||
check(near(loaded.engine.intake_valve.mass_kg,tuned.intake_valve.mass_kg),"valve mass export changed units");
|
||||
check(near(loaded.engine.fuel.pilot_jet_diameter,tuned.fuel.pilot_jet_diameter),"carburetor edit was not exported");
|
||||
check(near(loaded.engine.ecu.ignition_map[0].degrees_btdc,tuned.ecu.ignition_map[0].degrees_btdc),"ignition trim was not exported");
|
||||
check(near(loaded.engine.intake_cam.points[10].lift_metres,tuned.intake_cam.points[10].lift_metres),"cam profile export changed units");
|
||||
auto at_limit=tuned;at_limit.intake_cam.points[10].lift_metres=at_limit.intake_valve.maximum_lift_m;
|
||||
check(save_tuned_engine(source,at_limit,temp.path)!=saved,"repeat export overwrote an engine");
|
||||
|
||||
DesktopScenario desktop(source);
|
||||
desktop.set_controls(.2f,.1f,.6f);desktop.set_pipe_solver(PipeSolver::Hlle);desktop.set_audio_scene(OutdoorScene::Dry);
|
||||
auto pipes=tuned;auto& route=pipes.geometry.pipes[0];const auto end=route.points.back(),start=route.points.front();
|
||||
route.points.front()={end.x+(start.x-end.x)*1.2f,end.y+(start.y-end.y)*1.2f,end.z+(start.z-end.z)*1.2f};
|
||||
pipes.pipes[0].length=route.length();
|
||||
desktop.rebuild_engine(pipes);
|
||||
const auto rebuilt=desktop.snapshot();
|
||||
const float length=std::accumulate(rebuilt.pipe_lengths[0].begin(),rebuilt.pipe_lengths[0].end(),0.f);
|
||||
check(near(length,pipes.pipes[0].length),"rebuilt mesh uses old dimensions");
|
||||
check(rebuilt.pipe_solver==PipeSolver::Hlle && rebuilt.audio_scene==OutdoorScene::Dry && near(rebuilt.clutch,.6f),"rebuild lost scene or controls");
|
||||
std::atomic<bool> finite{true};
|
||||
std::jthread worker([&]{for(int i=0;i<4096;++i) {auto f=desktop.process();if(!std::isfinite(f.left)||!std::isfinite(f.right))finite=false;}});
|
||||
for(int i=0;i<16;++i) {auto live=pipes;live.intake_valve.mass_kg+=float(i)*.0001f;desktop.set_tuning(live);desktop.snapshot();}
|
||||
desktop.rebuild_engine(pipes);
|
||||
worker.join();check(finite,"concurrent editing or rebuild corrupted the simulation");
|
||||
std::cout<<"Live tuning state, export round trip, mesh rebuild and concurrent publication passed\n";
|
||||
}
|
||||
47
tests/mesh_resolution_tests.cpp
Normal file
47
tests/mesh_resolution_tests.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "FluidSim/DesktopScenario.hpp"
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
using namespace fluidsim::port;
|
||||
void check(bool value,const char* reason) {if(!value)throw std::runtime_error(reason);}
|
||||
double volume(const ScenarioSnapshot& s) {
|
||||
double sum=0;
|
||||
for(int p=0;p<32;++p) for(std::size_t i=0;i<s.pipe_areas[p].size();++i)
|
||||
sum+=double(s.pipe_areas[p][i])*s.pipe_lengths[p][i];
|
||||
return sum;
|
||||
}
|
||||
int main() {
|
||||
try {
|
||||
check(mesh_cell_count(.1f,100)==10,"decimal cell count rounded upward");
|
||||
for(const auto& example:scenario_examples())
|
||||
check((example.kind==ScenarioKind::TwoStroke?example.two.cells_per_meter:example.engine.cells_per_meter)>0,"scenario lacks mesh density");
|
||||
for(const auto* id:{"single-450","yz-racing","saab-chambered"}) {
|
||||
DesktopScenario scenario(scenario_example(id));
|
||||
scenario.set_controls(.3f,.1f,.6f);scenario.set_pipe_solver(PipeSolver::Hllc);scenario.set_audio_scene(OutdoorScene::Dry);
|
||||
const double original_volume=volume(scenario.snapshot());
|
||||
std::atomic<bool> finite{true};
|
||||
std::jthread worker([&]{for(int i=0;i<2048;++i) {const auto f=scenario.process();if(!std::isfinite(f.left)||!std::isfinite(f.right))finite=false;}});
|
||||
scenario.set_cells_per_meter(35);
|
||||
worker.join();check(finite,"concurrent resolution rebuild corrupted audio");
|
||||
auto state=scenario.snapshot();
|
||||
check(state.cells_per_meter==35 && state.pipe_solver==PipeSolver::Hllc && state.audio_scene==OutdoorScene::Dry,"resolution rebuild lost options");
|
||||
check(std::abs(volume(state)-original_volume)<original_volume*1e-5,"remeshing changed pipe volume");
|
||||
for(const auto& lengths:state.pipe_lengths) for(float length:lengths)
|
||||
check(length<=1.f/35+1e-6f,"profile or uniform pipe ignored cells/m");
|
||||
check(std::abs(state.clutch-.6f)<1e-5f,"resolution rebuild lost controls");
|
||||
const auto old_count=state.pipe_states[0].size();
|
||||
for(float invalid:{0.f,-1.f,501.f,std::numeric_limits<float>::quiet_NaN()}) {
|
||||
bool rejected=false;try{scenario.set_cells_per_meter(invalid);}catch(const std::exception&){rejected=true;}
|
||||
check(rejected,"invalid density accepted");
|
||||
check(scenario.snapshot().pipe_states[0].size()==old_count,"failed rebuild changed live mesh");
|
||||
}
|
||||
}
|
||||
DesktopScenario a(scenario_example("single-450")),b(scenario_example("single-650"));
|
||||
const float density=b.snapshot().cells_per_meter;a.set_cells_per_meter(50);
|
||||
check(b.snapshot().cells_per_meter==density,"resolution leaked between scenarios");
|
||||
std::cout<<"Uniform/profile mesh resolution, volume, rebuild, isolation and validation checks passed\n";
|
||||
} catch(const std::exception& e) {std::cerr<<e.what()<<'\n';return 1;}
|
||||
}
|
||||
@@ -181,6 +181,26 @@ int main() {
|
||||
check(std::isfinite(frame.left) && std::isfinite(frame.right),"catalog listener wiring failed");
|
||||
}
|
||||
|
||||
// Source stems reconstruct the mix, and muting leaves diagnostic stems alive.
|
||||
auto stem_config=config();
|
||||
stem_config.dual_exhaust=true; stem_config.valve_contact_enabled=true;
|
||||
OutdoorAudio stems(44100,stem_config), muted(44100,stem_config);
|
||||
for(std::size_t j=0;j<4;++j) muted.set_source_enabled(j,false);
|
||||
for(int i=0;i<12000;++i) {
|
||||
const float x=.01f*std::sin(i*.07f);
|
||||
const auto mix=stems.process(x,x*.4f,-x*.2f,x*.1f);
|
||||
auto sum=stems.tail_frame();
|
||||
for(const auto& source:stems.source_frames()) {
|
||||
sum.left+=source.rendered.left; sum.right+=source.rendered.right;
|
||||
}
|
||||
check(std::abs(sum.left-mix.left)<1e-6f && std::abs(sum.right-mix.right)<1e-6f,
|
||||
"source stems do not reconstruct rendered mix");
|
||||
const auto silent=muted.process(x,x*.4f,-x*.2f,x*.1f);
|
||||
check(silent.left==0 && silent.right==0,"muted sources feed listening mix or reverb");
|
||||
check(muted.source_frames()[0].rendered.left==stems.source_frames()[0].rendered.left,
|
||||
"muting changes diagnostic source history");
|
||||
}
|
||||
|
||||
ReedValve reed;
|
||||
for (int i = 0; i < 10000; i++)
|
||||
reed.step(1.f / 44100, 100);
|
||||
|
||||
67
tests/physical_geometry_tests.cpp
Normal file
67
tests/physical_geometry_tests.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "FluidSim/DesktopScenario.hpp"
|
||||
#include "FluidSim/ScenarioGeometry.hpp"
|
||||
#include <toml.hpp>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
using namespace fluidsim::port;
|
||||
void check(bool value,const char* message){if(!value)throw std::runtime_error(message);}
|
||||
int main() try {
|
||||
for(const auto& e:scenario_examples()) {
|
||||
DesktopScenario scenario(e);const auto state=scenario.snapshot();
|
||||
check(bool(state.geometry),"scenario lacks physical geometry");const auto routes=scenario_pipe_routes(state);
|
||||
for(std::size_t p=0;p<state.geometry->pipes.size();++p) {
|
||||
const float mesh=std::accumulate(state.pipe_lengths[p].begin(),state.pipe_lengths[p].end(),0.f);
|
||||
check(std::abs(mesh-state.geometry->pipes[p].length())<1e-5f*std::max(1.f,mesh),"fluid length differs from render centerline");
|
||||
check(routes[p].count==state.geometry->pipes[p].points.size(),"renderer lost a bend");
|
||||
for(unsigned k=0;k<routes[p].count;++k)check(geometry_distance(routes[p].points[k],state.geometry->pipes[p].points[k])<1e-7f,"render route differs from input geometry");
|
||||
}
|
||||
check(!state.storage_volumes.empty(),"storage volumes missing from rendering snapshot");
|
||||
for(const auto& v:state.storage_volumes) {
|
||||
check(v.box.volume()>0&&std::isfinite(v.pressure),"invalid physical storage volume");
|
||||
const auto lo=v.box.minimum(),hi=v.box.maximum();int ports=0;
|
||||
for(const auto& p:state.geometry->pipes)for(auto endpoint:{p.points.front(),p.points.back()}) {
|
||||
constexpr float tolerance=2e-6f;
|
||||
const bool inside=endpoint.x>=lo.x-tolerance&&endpoint.x<=hi.x+tolerance&&endpoint.y>=lo.y-tolerance&&endpoint.y<=hi.y+tolerance&&endpoint.z>=lo.z-tolerance&&endpoint.z<=hi.z+tolerance;
|
||||
const bool surface=std::min({std::abs(endpoint.x-lo.x),std::abs(endpoint.x-hi.x),std::abs(endpoint.y-lo.y),std::abs(endpoint.y-hi.y),std::abs(endpoint.z-lo.z),std::abs(endpoint.z-hi.z)})<tolerance;
|
||||
if(inside&&surface)++ports;
|
||||
}
|
||||
if(ports<2)throw std::runtime_error(e.id+": storage volume has disconnected pipe ports: "+v.id);
|
||||
}
|
||||
for(int i=0;i<state.cylinder_count;++i) {
|
||||
const auto& c=state.geometry->cylinders[i];const float angle=-c.tilt_degrees*pi/180;
|
||||
const auto attached=[&](Vec3 p) {
|
||||
p={p.x-c.origin.x,p.y-c.origin.y,p.z-c.origin.z};
|
||||
const float y=p.y*std::cos(angle)-p.z*std::sin(angle),z=p.y*std::sin(angle)+p.z*std::cos(angle);
|
||||
return std::abs(p.x)<=state.cylinder_bore*.65f&&std::abs(z)<=state.cylinder_bore*.65f&&y>=state.cylinder_rod-state.cylinder_stroke*.5f-.005f&&y<=state.cylinder_rod+state.cylinder_stroke*.5f+state.cylinder_clearance/(pi*state.cylinder_bore*state.cylinder_bore*.25f)+.005f;
|
||||
};
|
||||
const auto& intake=state.geometry->pipes[state.two_stroke?2:1+i];
|
||||
const auto& exhaust=state.geometry->pipes[state.two_stroke?3:1+state.cylinder_count+i];
|
||||
if(!attached(intake.points.back())||!attached(exhaust.points.front()))throw std::runtime_error(e.id+": cylinder port is disconnected from its geometry");
|
||||
}
|
||||
if(e.kind!=ScenarioKind::TwoStroke){FourStrokeScenario four(44100,e);check(std::abs(four.intake_plenum.volume()-e.engine.geometry.volume("intake_plenum")->volume())<1e-8f,"plenum simulation ignores geometry");}
|
||||
}
|
||||
const auto average_primary=[](const ScenarioExample& e){float sum=0;for(int i=0;i<e.engine.cylinders;++i)sum+=e.engine.geometry.pipes[1+e.engine.cylinders+i].length();return sum/e.engine.cylinders;};
|
||||
check(average_primary(scenario_example("v8-short"))<average_primary(scenario_example("v8-h"))&&average_primary(scenario_example("v8-h"))<average_primary(scenario_example("v8-long")),"short and long header variants lost their physical distinction");
|
||||
auto table=toml::parse_file(scenario_example("single-450").source_path.string());
|
||||
auto& volumes=*table["geometry"]["volumes"].as_array();
|
||||
toml::table* plenum_table=nullptr;
|
||||
for(auto& v:volumes)if((*v.as_table())["id"].value_or<std::string>("")=="intake_plenum")plenum_table=v.as_table();
|
||||
check(plenum_table!=nullptr,"test volume not found");auto& plenum=*plenum_table;
|
||||
plenum.erase("size_mm");plenum.erase("center_mm");
|
||||
plenum.insert_or_assign("corners_mm",toml::array{toml::array{100.,200.,300.},toml::array{0.,0.,0.}});
|
||||
auto& pipe=*table["geometry"]["pipes"].as_array()->get(0)->as_table();
|
||||
pipe.insert_or_assign("points_mm",toml::array{toml::array{0.,0.,0.},toml::array{30.,40.,0.},toml::array{30.,40.,120.}});
|
||||
const auto file=std::filesystem::temp_directory_path()/("fluidsim-geometry-"+std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())+".toml");
|
||||
const auto write=[&]{{std::ofstream out(file);out<<table;}};
|
||||
write();const auto loaded=load_engine_file(file);FourStrokeScenario changed(44100,loaded);
|
||||
check(std::abs(changed.intake_plenum.volume()-.006f)<1e-8f,"corner-defined volume conversion is wrong");
|
||||
check(geometry_distance(loaded.engine.geometry.volume("intake_plenum")->center,{.05f,.1f,.15f})<1e-7f,"corner center is wrong");
|
||||
check(std::abs(std::accumulate(changed.pipes[0].cell_lengths.begin(),changed.pipes[0].cell_lengths.end(),0.f)-.17f)<1e-6f,"path length does not drive simulation");
|
||||
pipe.insert_or_assign("points_mm",toml::array{toml::array{0.,0.,0.},toml::array{0.,0.,0.}});write();
|
||||
bool rejected=false;try{load_engine_file(file);}catch(const std::exception& e){rejected=std::string(e.what()).find(file.filename().string())!=std::string::npos;}
|
||||
std::filesystem::remove(file);check(rejected,"degenerate geometry accepted or missing file diagnostic");
|
||||
std::cout<<"All scenario centerlines, storage dimensions, corner volumes and invalid geometry passed\n";
|
||||
}catch(const std::exception& e){std::cerr<<e.what()<<'\n';return 1;}
|
||||
@@ -77,6 +77,14 @@ int main() {
|
||||
require(std::abs(direction.x*direction.x+direction.y*direction.y+direction.z*direction.z-1)<1e-4f,"pipe path tangent must be normalized");
|
||||
auto atm=desktop::pressure_tint(101325),vac=desktop::pressure_tint(0),peak=desktop::pressure_tint(1000000);
|
||||
require(atm.y>.8f && vac.z>.99f && peak.x>.99f,"pressure palette must show atmosphere green, vacuum blue, spikes red");
|
||||
const auto vacuum_before=desktop::pressure_tint(40000),vacuum_after=desktop::pressure_tint(40000,true);
|
||||
const auto small_intake_pulse=desktop::pressure_tint(104325),small_exhaust_pulse=desktop::pressure_tint(104325,true);
|
||||
require(vacuum_before.x==vacuum_after.x&&vacuum_before.y==vacuum_after.y&&vacuum_before.z==vacuum_after.z,
|
||||
"exhaust highlighting must not change the established underpressure palette");
|
||||
require(small_intake_pulse.x>.9f&&small_intake_pulse.y>.8f&&small_intake_pulse.z<.1f,
|
||||
"a small positive intake pulse must be visible as yellow");
|
||||
require(small_exhaust_pulse.x>.95f&&small_exhaust_pulse.y<.4f,
|
||||
"a small positive exhaust pulse must be visible as orange-red");
|
||||
Ecu fast_actuator;
|
||||
for(int i=0;i<230;++i)fast_actuator.step(1.f/44100,1,5000);
|
||||
require(fast_actuator.throttle_opening()>.99f,"throttle actuator must settle within about 5 ms");
|
||||
|
||||
172
tools/acoustic_benchmark.cpp
Normal file
172
tools/acoustic_benchmark.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
#include "FluidSim/Junction.hpp"
|
||||
#include "FluidSim/Solver.hpp"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
using namespace fluidsim::port;
|
||||
|
||||
namespace {
|
||||
constexpr double pressure=101325, area=.001;
|
||||
struct Result { double incident{}, reflected{}, transmitted{}, mass_drift{}, energy_drift{};
|
||||
std::array<std::complex<double>,2> incident_spectrum{}, reflected_spectrum{}, transmitted_spectrum{};
|
||||
std::uint64_t repairs{}, limited{}, steps{}, fallbacks{}; };
|
||||
Result run(const std::string& kind,int n,float courant,PipeSolver scheme,
|
||||
double volume,float discharge,const std::filesystem::path& trace) {
|
||||
const bool straight=kind=="straight", split=kind=="split", star=kind=="star" || kind=="legacy-star" || kind=="star-unequal";
|
||||
const int branches=star || kind=="volume-y" ? 3 : 2;
|
||||
Junction chamber(float(volume),pressure,300);
|
||||
const double rho=chamber.density(), c=std::sqrt(1.4*pressure/rho), z=rho*c;
|
||||
std::vector<Pipe1D> pipes;
|
||||
if(straight) pipes.emplace_back(area,4,2*n);
|
||||
else for(int j=0;j<branches;++j) pipes.emplace_back(area*(kind=="star-unequal"?j+1:1),2,n);
|
||||
for(auto& p:pipes) {
|
||||
p.solver=scheme; p.damping_multiplier=0; p.energy_relaxation_rate=0;
|
||||
for(int i=0;i<int(p.cells.size());++i) {
|
||||
const double x=(i+.5)*p.dx;
|
||||
const double pulse=&p==&pipes[0] ? 100*std::exp(-std::pow((x-.6)/.12,2)) : 0;
|
||||
const double density=rho+pulse/(c*c), u=pulse/z;
|
||||
p.cells[i]={float(density),float(density*u),float((pressure+pulse)/pipe_gm1+.5*density*u*u),1,0};
|
||||
}
|
||||
}
|
||||
BoundarySystem boundaries(pipes);
|
||||
boundaries.add_closed_end(0,true);
|
||||
if(straight) boundaries.add_closed_end(0,false);
|
||||
else {
|
||||
for(int j=1;j<branches;++j) boundaries.add_closed_end(j,false);
|
||||
if(split) boundaries.add_connection(0,false,1,true);
|
||||
else if(star) boundaries.add_junction({{0,false},{1,true},{2,true}},kind=="legacy-star"?BoundarySystem::JunctionMethod::LegacyRusanov:BoundarySystem::JunctionMethod::Characteristic);
|
||||
else {
|
||||
std::vector<JunctionEnd> ends{{0,false,discharge},{1,true,discharge}};
|
||||
if(branches==3) ends.push_back({2,true,discharge});
|
||||
chamber.connect(boundaries,pipes,ends);
|
||||
}
|
||||
}
|
||||
Solver solver(pipes,boundaries); solver.minimum_substeps=1;
|
||||
const bool has_volume=!straight && !split && !star;
|
||||
if(has_volume) solver.add_component(chamber);
|
||||
auto totals=[&] {
|
||||
std::array<double,2> t{has_volume?chamber.mass():0,has_volume?chamber.internal_energy():0};
|
||||
for(const auto& p:pipes) for(int i=0;i<int(p.cells.size());++i) {
|
||||
t[0]+=p.cell_mass(i); t[1]+=double(p.cells[i].energy)*p.cell_area(i)*p.cell_length(i);
|
||||
}
|
||||
return t;
|
||||
};
|
||||
const auto initial=totals(); Result r;
|
||||
std::ofstream out(trace);
|
||||
if(!out) throw std::runtime_error("cannot open trace");
|
||||
out<<std::setprecision(10);
|
||||
out<<"time_s,upstream_pressure_pa,upstream_velocity_m_s,downstream_pressure_pa,downstream_velocity_m_s\n";
|
||||
const int up=int(1.4/pipes[0].dx);
|
||||
const int down=int((straight?2.6:.6)/pipes.back().dx);
|
||||
double time=0;
|
||||
// Stop before far-end reflections return to either probe. Integrate acoustic
|
||||
// characteristics p+/- = (p' +/- rho*c*u)/2, not squared total pressure.
|
||||
while(time<.009) {
|
||||
const float dt=float(std::min(.009-time,courant*(2./n)/(c+.5)));
|
||||
const auto a=pipes[0].state(up), b=pipes.back().state(down);
|
||||
const double plus=(a.pressure-pressure+z*a.velocity)/2;
|
||||
const double minus=(a.pressure-pressure-z*a.velocity)/2;
|
||||
for(int frequency=0;frequency<2;++frequency) {
|
||||
const double hz=frequency==0?500:1000;
|
||||
const auto weight=std::exp(std::complex<double>(0,-2*3.141592653589793*hz*time))*double(dt);
|
||||
r.incident_spectrum[frequency]+=plus*weight;
|
||||
r.reflected_spectrum[frequency]+=minus*weight;
|
||||
r.transmitted_spectrum[frequency]+=(b.pressure-pressure+z*b.velocity)*.5*weight;
|
||||
}
|
||||
r.incident+=plus*plus*area/z*dt;
|
||||
r.reflected+=minus*minus*area/z*dt;
|
||||
if(straight) {
|
||||
const double v=(b.pressure-pressure+z*b.velocity)/2;
|
||||
r.transmitted+=v*v*area/z*dt;
|
||||
} else for(int j=1;j<branches;++j) {
|
||||
const auto q=pipes[j].state(down);
|
||||
const double v=(q.pressure-pressure+z*q.velocity)/2;
|
||||
r.transmitted+=v*v*pipes[j].cell_area(down)/z*dt;
|
||||
}
|
||||
out<<time<<','<<a.pressure-pressure<<','<<a.velocity<<','<<b.pressure-pressure<<','<<b.velocity<<'\n';
|
||||
solver.step(dt); time+=dt;
|
||||
}
|
||||
const auto final=totals();
|
||||
r.mass_drift=(final[0]-initial[0])/initial[0];
|
||||
r.energy_drift=(final[1]-initial[1])/initial[1];
|
||||
for(auto& p:pipes) r.repairs+=p.positivity_repairs;
|
||||
r.fallbacks=boundaries.junction_fallbacks;
|
||||
r.limited=boundaries.limited_fluxes; r.steps=solver.substep_count();
|
||||
if(!(r.incident>0) || !std::isfinite(r.transmitted) || r.repairs ||
|
||||
std::abs(r.mass_drift)>1e-4 || std::abs(r.energy_drift)>1e-4)
|
||||
throw std::runtime_error("acoustic benchmark robustness/conservation failure: "+trace.string()+" mass="+std::to_string(r.mass_drift)+" energy="+std::to_string(r.energy_drift)+" limited="+std::to_string(r.limited)+" repairs="+std::to_string(r.repairs));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
int main(int argc,char** argv) {
|
||||
try {
|
||||
const std::filesystem::path dir=argc>1?argv[1]:"out/acoustics";
|
||||
std::filesystem::create_directories(dir);
|
||||
std::ofstream summary(dir/"summary.csv");
|
||||
summary<<std::setprecision(10);
|
||||
summary<<"case,solver,cells_per_2m,courant,volume_m3,discharge,incident_j,reflected_ratio,transmitted_ratio,unaccounted_ratio,mass_relative_drift,energy_relative_drift,limited_fluxes,positivity_repairs,substeps,transmission_over_straight,reflection_over_straight,ideal_reflected_ratio,ideal_transmitted_ratio,status,junction_fallbacks,t500_gain_over_straight,t500_phase_error_rad,t1000_gain_over_straight,t1000_phase_error_rad\n";
|
||||
double straight_transmission=0, straight_reflection=0, coarse_transmission=0;
|
||||
std::array<double,6> first_order_transmission{};
|
||||
std::array<std::complex<double>,2> straight_spectrum{};
|
||||
int cases=0, flagged=0;
|
||||
for(const auto* scheme:{"rusanov","hlle","hllc","muscl"})
|
||||
for(int n:{40,80,160}) for(float courant:{.4f,.8f})
|
||||
for(const auto* kind:{"straight","split","star","legacy-star","star-unequal","volume","volume-y"})
|
||||
for(double volume:{.00005,.0005,.005}) {
|
||||
if((std::string(kind)=="straight" || std::string(kind)=="split" || (std::string(kind)=="star" || std::string(kind)=="legacy-star" || std::string(kind)=="star-unequal")) && volume!=.00005) continue;
|
||||
for(float discharge:{1.f,.7f}) {
|
||||
if((std::string(kind)=="straight" || std::string(kind)=="split" || (std::string(kind)=="star" || std::string(kind)=="legacy-star" || std::string(kind)=="star-unequal")) && discharge!=1) continue;
|
||||
const std::string id=std::string(kind)+"-"+scheme+"-"+std::to_string(n)+"-"+std::to_string(courant)+"-"+std::to_string(volume)+"-"+std::to_string(discharge);
|
||||
const auto r=run(kind,n,courant,parse_pipe_solver(scheme),volume,discharge,dir/(id+".csv"));
|
||||
const double reflected=r.reflected/r.incident, transmitted=r.transmitted/r.incident;
|
||||
if(std::string(kind)=="straight") {
|
||||
straight_transmission=transmitted; straight_reflection=reflected;
|
||||
for(int frequency=0;frequency<2;++frequency)
|
||||
straight_spectrum[frequency]=r.transmitted_spectrum[frequency]/r.incident_spectrum[frequency];
|
||||
const int slot=(n==40?0:n==80?2:4)+(courant>.5f?1:0);
|
||||
if(std::string(scheme)=="rusanov") first_order_transmission[slot]=transmitted;
|
||||
if(std::string(scheme)=="muscl" && transmitted<first_order_transmission[slot]+.05)
|
||||
throw std::runtime_error("MUSCL pulse attenuation improvement regressed");
|
||||
if(reflected>1e-4 || transmitted<=0 || transmitted>1.01)
|
||||
throw std::runtime_error("straight acoustic propagation regression");
|
||||
if(courant==.4f) {
|
||||
if(n>40 && transmitted<=coarse_transmission)
|
||||
throw std::runtime_error("straight pulse does not converge with mesh refinement");
|
||||
coarse_transmission=transmitted;
|
||||
}
|
||||
}
|
||||
if(std::string(kind)=="split" &&
|
||||
(std::abs(transmitted-straight_transmission)>1e-7 || std::abs(reflected-straight_reflection)>1e-7))
|
||||
throw std::runtime_error("split connection differs from continuous pipe");
|
||||
if(std::string(kind)=="star" || std::string(kind)=="star-unequal") {
|
||||
const double expected_r=std::string(kind)=="star"?1./9:4./9;
|
||||
const double expected_t=1-expected_r;
|
||||
if(std::abs(reflected/straight_transmission-expected_r)>.04 ||
|
||||
std::abs(transmitted/straight_transmission-expected_t)>.07 || r.fallbacks)
|
||||
throw std::runtime_error("characteristic junction acoustic scattering regression: "+id+" R="+std::to_string(reflected/straight_transmission)+" T="+std::to_string(transmitted/straight_transmission)+" fallback="+std::to_string(r.fallbacks));
|
||||
}
|
||||
const bool contaminated=r.limited || reflected+transmitted>1.05;
|
||||
++cases; flagged+=contaminated;
|
||||
summary<<kind<<','<<scheme<<','<<n<<','<<courant<<','<<volume<<','<<discharge<<','<<r.incident<<','<<reflected<<','<<transmitted<<','<<1-reflected-transmitted<<','<<r.mass_drift<<','<<r.energy_drift<<','<<r.limited<<','<<r.repairs<<','<<r.steps<<','<<transmitted/straight_transmission<<','<<reflected/straight_transmission<<',';
|
||||
if(std::string(kind)=="straight" || std::string(kind)=="split") summary<<"0,1,";
|
||||
else if(std::string(kind)=="star-unequal") summary<<4./9<<','<<5./9<<',';
|
||||
else if(std::string(kind)=="star" || std::string(kind)=="legacy-star") summary<<1./9<<','<<8./9<<',';
|
||||
else summary<<",,";
|
||||
summary<<(contaminated?"flagged":"ok")<<','<<r.fallbacks;
|
||||
for(int frequency=0;frequency<2;++frequency) {
|
||||
const auto corrected=r.transmitted_spectrum[frequency]/r.incident_spectrum[frequency]/straight_spectrum[frequency];
|
||||
summary<<','<<std::abs(corrected)<<','<<std::arg(corrected);
|
||||
if(std::string(kind)=="star" && n==160 && (std::abs(std::abs(corrected)-2./3)>.08 || std::abs(std::arg(corrected))>.15))
|
||||
throw std::runtime_error("junction frequency/phase regression: "+id);
|
||||
}
|
||||
summary<<'\n';
|
||||
}
|
||||
}
|
||||
std::cout<<"Validated "<<cases<<" cases ("<<flagged<<" flagged for limiting or acoustic amplification). Wrote acoustic pulse benchmark to "<<dir<<'\n';
|
||||
} catch(const std::exception& e) { std::cerr<<e.what()<<'\n'; return 1; }
|
||||
}
|
||||
276
tools/analyze_scenario_profile.py
Normal file
276
tools/analyze_scenario_profile.py
Normal file
@@ -0,0 +1,276 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Create a Markdown summary from fluidsim_scenario_profile CSV output."""
|
||||
import csv
|
||||
import statistics
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def med(rows, field):
|
||||
return statistics.median(float(row[field]) for row in rows)
|
||||
|
||||
|
||||
def main():
|
||||
source = Path(sys.argv[1] if len(sys.argv) > 1 else "profile-runs.csv")
|
||||
target = Path(sys.argv[2] if len(sys.argv) > 2 else "profile-report.md")
|
||||
rows = list(csv.DictReader(source.open(newline="", encoding="utf-8")))
|
||||
if not rows:
|
||||
raise SystemExit("No profile rows found")
|
||||
engines = sorted({r["scenario"] for r in rows})
|
||||
solvers = ["rusanov", "hlle", "hllc", "muscl"]
|
||||
densities = sorted({int(r["cells_per_meter"]) for r in rows})
|
||||
lines = [
|
||||
"# FluidSim engine and solver performance profile",
|
||||
"",
|
||||
"**Run date:** 2026-10-24 ",
|
||||
"**Raw measurements:** [profile-runs.csv](profile-runs.csv) ",
|
||||
"**Harness:** `tools/scenario_profile.cpp` ",
|
||||
"**Analyzer:** `tools/analyze_scenario_profile.py`",
|
||||
"",
|
||||
"These runs predate the geometry-defined header layouts. Current scenarios have revised header lengths; rerun the harness for current performance figures.",
|
||||
"",
|
||||
"## Summary",
|
||||
"",
|
||||
"The solver is the main cost in every tested configuration. At 20 cells/m it takes about 76–92% of measured `process()` time; controls take 3–9%, audio rendering 3–12%, and component updates 2–3% of solver time. Across the run matrix, the median boundary share of solver time falls from 56.5% at 20 cells/m to 30.5% at 80 cells/m; pipe updates rise from 32.8% to 55.0%. The bottleneck shifts from boundary resolution toward pipe-cell advancement as density grows.",
|
||||
"",
|
||||
"Mesh density has a nonlinear runtime effect because smaller cells also require more CFL substeps. Raising density from 20 to 80 cells/m increased median frame cost by 3.0×–6.4× across these engines. The V8 was most expensive: at 80 cells/m it used about 1,054 cells and took about 134 µs per frame in the profiled run.",
|
||||
"",
|
||||
"At a fixed density of 20 cells/m, Rusanov was the fastest solver. Relative to Rusanov at that same density, MUSCL cost 16–50% more depending on engine, while HLLE and HLLC were generally 3–25% more. At your solver-specific listening targets, MUSCL at 25 cells/m is the fastest overall because it reaches your preferred sound at a coarser mesh.",
|
||||
"",
|
||||
"Across all tested scenarios and densities, the median sampled frame cost was 11.6 µs for Rusanov, 13.0 µs for HLLE, 13.5 µs for HLLC, and 15.9 µs for MUSCL. Those pooled values summarize this exact sweep and are affected by its chosen scenario and density mix.",
|
||||
"",
|
||||
"No pipe positivity repairs or HLLC fallbacks occurred in the measured runs.",
|
||||
"",
|
||||
"## Method",
|
||||
"",
|
||||
f"- {len(engines)} TOML scenarios, four solvers, {len(densities)} mesh densities, and two repetitions: {len(rows)} measured runs.",
|
||||
f"- Scenarios: {', '.join(engines)}. `yz-fat` is the two-stroke case; the others are four-stroke.",
|
||||
f"- Densities: {', '.join(map(str, densities))} cells/m, applied to the scenario's configured geometry.",
|
||||
"- Solvers: Rusanov, HLLE, HLLC, and MUSCL. Solver choice was applied to every pipe in each scenario.",
|
||||
"- Each run warmed up for 5,000 frames, then measured 22,050 frames (0.5 simulated seconds) at 44.1 kHz. Engine speed was reset to the scenario's configured initial RPM (or 4,500 RPM when unset) before every frame; the two-stroke was held at 7,000 RPM. Throttle was 55%, load 10%, clutch 0%.",
|
||||
"- Internal profiling sampled every other measured `process()` call. Each run therefore contains 11,025 profiled frames. End-to-end wall time includes all measured frames; stage timings come from sampled frames.",
|
||||
"- Build: Release, MinGW GCC 16.2.0, Windows, Intel Core i5-12600K. The machine was otherwise used interactively, so small differences should not be over-interpreted.",
|
||||
"",
|
||||
"## Cost at 20 cells/m",
|
||||
"",
|
||||
"Each cell shows median end-to-end wall microseconds per frame and wall/simulated-time ratio across the two repetitions. A ratio below 1.0 means this isolated scenario ran faster than real time. Boundary, pipe, and component columns are their share of inclusive solver time; controls and audio are their share of total sampled process time.",
|
||||
"",
|
||||
"| Scenario | Solver | Cells | µs/frame | Wall / sim | Controls | Audio | Boundary / solver | Pipe / solver | Components / solver |",
|
||||
"|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|",
|
||||
]
|
||||
for engine in engines:
|
||||
for solver in solvers:
|
||||
subset = [r for r in rows if r["scenario"] == engine and int(r["cells_per_meter"]) == 20 and r["solver"] == solver]
|
||||
if not subset:
|
||||
continue
|
||||
total = med(subset, "total_ms_per_frame")
|
||||
solver_ms = med(subset, "solver_ms_per_frame")
|
||||
boundary = med(subset, "boundary_ms_per_frame") / solver_ms * 100
|
||||
pipe = med(subset, "pipe_ms_per_frame") / solver_ms * 100
|
||||
component = med(subset, "components_ms_per_frame") / solver_ms * 100
|
||||
controls = med(subset, "controls_ms_per_frame") / total * 100
|
||||
audio = med(subset, "audio_ms_per_frame") / total * 100
|
||||
lines.append(f"| {engine} | {solver} | {subset[0]['total_cells']} | {med(subset, 'wall_us_per_frame'):.1f} | {med(subset, 'real_time_factor'):.2f} | {controls:.0f}% | {audio:.0f}% | {boundary:.0f}% | {pipe:.0f}% | {component:.0f}% |")
|
||||
lines += [
|
||||
"",
|
||||
"The three solver sub-stages are nested inside the solver measurement, so their percentages should not be added to the solver percentage. Their shares also do not sum to 100%: solver setup, CFL preparation, and loop overhead make up the remainder.",
|
||||
"",
|
||||
"## Mesh-density scaling",
|
||||
"",
|
||||
"Median profiled total cost per frame, aggregated over all four solvers and both repetitions. Cell counts are the actual total across all pipes in the scenario.",
|
||||
"",
|
||||
"| Scenario | Density: cells / µs | 80 vs 20 cost |",
|
||||
"|---|---|---:|",
|
||||
]
|
||||
for engine in engines:
|
||||
row_parts = []
|
||||
values = {}
|
||||
for density in densities:
|
||||
subset = [r for r in rows if r["scenario"] == engine and int(r["cells_per_meter"]) == density]
|
||||
values[density] = med(subset, "total_ms_per_frame") * 1000
|
||||
row_parts.append(f"{density}: {subset[0]['total_cells']} / {values[density]:.1f}")
|
||||
factor = values[80] / values[20] if 20 in values and 80 in values else 0
|
||||
lines.append(f"| {engine} | {'; '.join(row_parts)} | {factor:.2f}× |")
|
||||
lines += [
|
||||
"",
|
||||
"## Solver cost at 20 cells/m",
|
||||
"",
|
||||
"Change in median `total_ms_per_frame` versus Rusanov for the same scenario and mesh density.",
|
||||
"",
|
||||
"| Scenario | Rusanov | HLLE | HLLC | MUSCL |",
|
||||
"|---|---:|---:|---:|---:|",
|
||||
]
|
||||
for engine in engines:
|
||||
subset = [r for r in rows if r["scenario"] == engine and int(r["cells_per_meter"]) == 20]
|
||||
base = med([r for r in subset if r["solver"] == "rusanov"], "total_ms_per_frame")
|
||||
values = []
|
||||
for solver in solvers:
|
||||
cost = med([r for r in subset if r["solver"] == solver], "total_ms_per_frame")
|
||||
values.append(f"{(cost / base - 1) * 100:+.0f}%")
|
||||
lines.append(f"| {engine} | {' | '.join(values)} |")
|
||||
|
||||
quality_files = [target.parent / f"quality-{solver}.csv" for solver in solvers]
|
||||
scalar_files = [target.parent / f"no-simd-{solver}.csv" for solver in solvers]
|
||||
lazy_files = [target.parent / f"lazy2-{solver}.csv" for solver in solvers]
|
||||
fused_files = [target.parent / f"fused-{solver}.csv" for solver in solvers]
|
||||
density50_file = target.parent / "profile-50-baseline.csv"
|
||||
if density50_file.exists():
|
||||
density50 = list(csv.DictReader(density50_file.open(newline="", encoding="utf-8")))
|
||||
lines += [
|
||||
"",
|
||||
"## All solvers at 50 cells/m",
|
||||
"",
|
||||
"This fixed-density sweep isolates solver cost at your preferred mesh scale. Values are medians across six scenarios and two repetitions; boundary and pipe shares are fractions of inclusive solver time.",
|
||||
"",
|
||||
"[50 cells/m raw runs](profile-50-baseline.csv)",
|
||||
"",
|
||||
"| Solver | Median µs/frame | Boundary / solver | Pipe / solver |",
|
||||
"|---|---:|---:|---:|",
|
||||
]
|
||||
for solver in solvers:
|
||||
subset = [r for r in density50 if r["solver"] == solver]
|
||||
boundary = statistics.median(float(r["boundary_ms_per_frame"]) / float(r["solver_ms_per_frame"]) * 100 for r in subset)
|
||||
pipe = statistics.median(float(r["pipe_ms_per_frame"]) / float(r["solver_ms_per_frame"]) * 100 for r in subset)
|
||||
lines.append(f"| {solver} | {med(subset, 'wall_us_per_frame'):.1f} | {boundary:.1f}% | {pipe:.1f}% |")
|
||||
if all(path.exists() for path in quality_files):
|
||||
quality_rows = [r for path in quality_files for r in csv.DictReader(path.open(newline="", encoding="utf-8"))]
|
||||
combined = target.parent / "quality-target-runs.csv"
|
||||
with combined.open("w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=list(quality_rows[0]))
|
||||
writer.writeheader()
|
||||
writer.writerows(quality_rows)
|
||||
lines += [
|
||||
"",
|
||||
"## User-rated quality targets",
|
||||
"",
|
||||
"You reported that these densities sound great: Rusanov 70 cells/m, HLLE 60, HLLC 45, and MUSCL 25. The following timings compare those listening targets; the benchmark measures compute and output statistics, not subjective sound quality.",
|
||||
"",
|
||||
"[Quality-target raw runs](quality-target-runs.csv)",
|
||||
"",
|
||||
"| Solver | Cells/m | Median µs/frame (six scenarios) | Median wall/sim | V8 cells | V8 µs/frame | V8 wall/sim |",
|
||||
"|---|---:|---:|---:|---:|---:|---:|",
|
||||
]
|
||||
for solver in solvers:
|
||||
subset = [r for r in quality_rows if r["solver"] == solver]
|
||||
v8 = [r for r in subset if r["scenario"] == "v8-h"]
|
||||
lines.append(f"| {solver} | {subset[0]['cells_per_meter']} | {med(subset, 'wall_us_per_frame'):.1f} | {med(subset, 'real_time_factor'):.2f} | {v8[0]['total_cells']} | {med(v8, 'wall_us_per_frame'):.1f} | {med(v8, 'real_time_factor'):.2f} |")
|
||||
lines += [
|
||||
"",
|
||||
"MUSCL at its 25 cells/m target had the lowest median compute cost across these cases. On the V8, it was about 30 µs/frame versus about 63 µs for HLLC at 45 cells/m, 68 µs for Rusanov at 70, and 76 µs for HLLE at 60. A wall/sim ratio above 1 means the isolated scenario takes longer than real time on this CPU.",
|
||||
]
|
||||
if all(path.exists() for path in scalar_files):
|
||||
scalar_rows = [r for path in scalar_files for r in csv.DictReader(path.open(newline="", encoding="utf-8"))]
|
||||
key = lambda r: (r["scenario"], r["solver"], r["repetition"])
|
||||
fast = {key(r): r for r in quality_rows}
|
||||
scalar = {key(r): r for r in scalar_rows}
|
||||
lines += [
|
||||
"",
|
||||
"### Compiler SIMD comparison",
|
||||
"",
|
||||
"Compared the Release build (GCC auto-vectorization enabled) with `FLUIDSIM_ENABLE_SIMD=OFF`, using the same quality-target matrix and run lengths.",
|
||||
"",
|
||||
"| Solver | Median SIMD speedup | Matched audio output |",
|
||||
"|---|---:|---|",
|
||||
]
|
||||
for solver in solvers:
|
||||
keys = [k for k in fast.keys() & scalar.keys() if k[1] == solver]
|
||||
ratios = [float(scalar[k]["wall_us_per_frame"]) / float(fast[k]["wall_us_per_frame"]) for k in keys]
|
||||
max_audio_delta = max(abs(float(fast[k]["audio_checksum"]) - float(scalar[k]["audio_checksum"])) for k in keys)
|
||||
lines.append(f"| {solver} | {(med([{'v': v} for v in ratios], 'v') - 1) * 100:+.1f}% | audio checksums identical (max delta {max_audio_delta:.0f}) |")
|
||||
lines += [
|
||||
"",
|
||||
"Positive speedup means vectorization was faster. The changes are small and mixed (roughly 0–3% median, within the noise of these short runs), while measured audio RMS, peaks, and checksums matched exactly. The current AoS cell/flux layout is not yielding a large automatic-SIMD gain; an explicit SoA or batched kernel would need a focused prototype and a broader numerical comparison.",
|
||||
"",
|
||||
"Paired raw runs by solver: " + ", ".join(f"{solver} [SIMD](quality-{solver}.csv) / [scalar](no-simd-{solver}.csv)" for solver in solvers) + ".",
|
||||
]
|
||||
if all(path.exists() for path in lazy_files):
|
||||
lazy_rows = [r for path in lazy_files for r in csv.DictReader(path.open(newline="", encoding="utf-8"))]
|
||||
key = lambda r: (r["scenario"], r["solver"], r["repetition"])
|
||||
before = {key(r): r for r in quality_rows}
|
||||
after = {key(r): r for r in lazy_rows}
|
||||
lines += [
|
||||
"",
|
||||
"### Lazy solver scratch buffers",
|
||||
"",
|
||||
"The pipe now allocates MUSCL reconstruction buffers only for MUSCL, and Roe caches only for HLLE/HLLC. Rusanov no longer allocates either unused cache. On the V8 at each solver's quality target:",
|
||||
"",
|
||||
"| Solver | Cells | Scratch before | Scratch after | Saved |",
|
||||
"|---|---:|---:|---:|---:|",
|
||||
]
|
||||
for solver in solvers:
|
||||
k = next(k for k in before if k[0] == "v8-h" and k[1] == solver)
|
||||
b = before[k]
|
||||
a = after[k]
|
||||
old_bytes = 120 * int(b["total_cells"]) + 20 * int(b["pipe_count"])
|
||||
new_bytes = int(a["scratch_bytes"])
|
||||
lines.append(f"| {solver} | {b['total_cells']} | {old_bytes:,} B | {new_bytes:,} B | {old_bytes-new_bytes:,} B ({(old_bytes-new_bytes)/old_bytes*100:.0f}%) |")
|
||||
keys = before.keys() & after.keys()
|
||||
ratios = [float(after[k]["wall_us_per_frame"]) / float(before[k]["wall_us_per_frame"]) for k in keys]
|
||||
max_delta = max(abs(float(after[k]["audio_checksum"]) - float(before[k]["audio_checksum"])) for k in keys)
|
||||
lines += [
|
||||
"",
|
||||
f"The buffer change reduced solver scratch allocation without changing audio checksums (maximum delta {max_delta:.0f}). It did not produce a throughput gain in this short paired comparison (median frame time changed {(med([{'v': v} for v in ratios], 'v')-1)*100:+.1f}% after the change), so keep it as a memory-footprint reduction rather than counting it as a CPU optimization. Scratch stays allocated after a solver is first selected, allowing fast mode switches.",
|
||||
"",
|
||||
"Paired raw runs: " + ", ".join(f"{solver} [before](quality-{solver}.csv) / [after](lazy2-{solver}.csv)" for solver in solvers) + ".",
|
||||
]
|
||||
if all(path.exists() for path in fused_files):
|
||||
fused_rows = [r for path in fused_files for r in csv.DictReader(path.open(newline="", encoding="utf-8"))]
|
||||
fused = {key(r): r for r in fused_rows}
|
||||
common = after.keys() & fused.keys()
|
||||
changes = []
|
||||
for solver in solvers:
|
||||
keys = [k for k in common if k[1] == solver]
|
||||
speedups = [float(after[k]["wall_us_per_frame"]) / float(fused[k]["wall_us_per_frame"]) for k in keys]
|
||||
change = (med([{"v": v} for v in speedups], "v") - 1) * 100
|
||||
changes.append(f"{solver} {change:+.1f}%")
|
||||
audio_delta = max(abs(float(after[k]["audio_checksum"]) - float(fused[k]["audio_checksum"])) for k in common)
|
||||
lines += [
|
||||
"",
|
||||
"A separate experiment fused primitive conversion, state validation, and minimum-timestep reduction into one pipe pass. Paired speed changes were " + ", ".join(changes) + f"; audio checksums stayed identical (maximum delta {audio_delta:.0f}). There was no consistent gain, so that loop change was reverted.",
|
||||
"",
|
||||
"Fused-pass raw runs: " + ", ".join(f"[{solver}](fused-{solver}.csv)" for solver in solvers) + ".",
|
||||
]
|
||||
lines += [
|
||||
"",
|
||||
"## CPU versus memory and threading",
|
||||
"",
|
||||
"A Windows process sample during the 50 cells/m sweep showed about 103% process CPU (approximately one full logical CPU), 7.1 MiB working set, and 3.8 MiB private bytes. The i5-12600K has 10 cores / 16 logical processors. At 50 cells/m, the V8 has 662 pipe cells; its pipe data plus solver scratch is about 96 KiB before the scratch-buffer reduction and about 60 KiB for Rusanov afterward. This is an inference of CPU-bound execution rather than RAM-capacity pressure: the working data is small and fits in the CPU's private L2 cache, but hardware cache-miss/bandwidth counters were not collected, so L1/L2 traffic is not ruled out.",
|
||||
"",
|
||||
"The existing per-step thread benchmark measured the V8's 26 pipes at 50 cells/m: 1 worker took 0.049 s, 2 took 0.188 s, and 4 took 0.267 s for 4,000 steps. Only its artificial 64-pipe × 256-cell case benefited (0.908 s with 1 worker, 0.546 s with 4). Real engine pipes are too small to amortize per-step synchronization; don’t parallelize each pipe step without a persistent task system and a much larger workload.",
|
||||
"",
|
||||
"An experimental GCC `-march=native` build crashed in the five-cylinder 50 cells/m profile with Windows access-violation exit `0xC0000005`; it was rejected. The default portable Release build remains the tested build.",
|
||||
"",
|
||||
"The focused post-change test run passed 8/8: mesh resolution, junctions, scenario catalog, Rusanov/HLLE/HLLC/MUSCL fluid validation, and outdoor audio.",
|
||||
]
|
||||
lines += [
|
||||
"",
|
||||
"## Interpretation and limits",
|
||||
"",
|
||||
"### Optimization priorities",
|
||||
"",
|
||||
"1. For the 50 cells/m listening range, start with pipe advancement for HLLE/HLLC: pipe updates use about 51–57% of solver time. At your target densities, they remain the largest stage for the V8 with Rusanov 70, HLLE 60, and HLLC 45. Reducing unnecessary per-cell passes or improving the cell/flux layout is the most promising CPU work.",
|
||||
"2. Boundary resolution is still a large second target (about 30–47% of solver time at 50 cells/m), and is the largest stage for the twin and for MUSCL in several cases. Optimize the characteristic-junction root solve only with the acoustic junction benchmarks guarding its behavior.",
|
||||
"3. Leave component updates and audio rendering for later; they are smaller absolute costs in the larger engines. Keep optimizing the pipe and boundary stages first.",
|
||||
"",
|
||||
"- Boundary resolution and pipe advancement trade places as density and solver change. At 50 cells/m, boundaries are largest for Rusanov, while pipe advancement leads for HLLE and HLLC; the V8's junction network still makes boundaries substantial.",
|
||||
"- Increasing density raises both the number of cells and the number of solver substeps needed to meet the CFL limit. This explains why runtime growth can exceed the cell-count growth alone.",
|
||||
"- At low densities, controls and audio are a larger fraction of total work because there are few cells to update. Their absolute time stays comparatively small as the mesh grows.",
|
||||
"- Results are for this Release build and machine, with profiling enabled on alternating frames. Instrumentation adds some timing overhead; the tables are best used for relative comparisons within this run. Very short runs, other compilers, build flags, CPUs, and background load can change absolute timings.",
|
||||
"- This benchmark isolates one scenario at a time. It excludes desktop rendering, UI work, output-device scheduling, and audio callback buffering. It does not compare sound quality or engine-state accuracy across mesh densities or solver methods.",
|
||||
"- Two repetitions provide a directional profile, not a high-confidence microbenchmark. Repeat on a quiet machine before using small differences to drive optimization decisions.",
|
||||
"",
|
||||
"## Reproduce",
|
||||
"",
|
||||
"```powershell",
|
||||
"cmake --build out/build/windows-gcc --target fluidsim_scenario_profile -j 8",
|
||||
"out/build/windows-gcc/fluidsim_scenario_profile verification/performance/2026-10-24/profile-runs.csv 5000 22050 2",
|
||||
"py -3 tools/analyze_scenario_profile.py verification/performance/2026-10-24/profile-runs.csv verification/performance/2026-10-24/profile-report.md",
|
||||
"```",
|
||||
"",
|
||||
]
|
||||
target.write_text("\n".join(lines), encoding="utf-8")
|
||||
print(f"Wrote {target}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "FluidSim/ScenarioCatalog.hpp"
|
||||
#include "FluidSim/TwoStrokeScenario.hpp"
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
@@ -24,22 +25,21 @@ public:
|
||||
if (!out_)
|
||||
throw std::runtime_error("cannot open WAV: " + path);
|
||||
out_.write("RIFF", 4);
|
||||
integer(36 + frames * 4, 4);
|
||||
integer(36 + frames * 8, 4);
|
||||
out_.write("WAVEfmt ", 8);
|
||||
integer(16, 4);
|
||||
integer(1, 2);
|
||||
integer(3, 2); // IEEE float preserves quiet diagnostic sources.
|
||||
integer(2, 2);
|
||||
integer(44100, 4);
|
||||
integer(44100 * 4, 4);
|
||||
integer(4, 2);
|
||||
integer(16, 2);
|
||||
integer(44100 * 8, 4);
|
||||
integer(8, 2);
|
||||
integer(32, 2);
|
||||
out_.write("data", 4);
|
||||
integer(frames * 4, 4);
|
||||
integer(frames * 8, 4);
|
||||
}
|
||||
void sample(AudioFrame f) {
|
||||
for (float x : {f.left, f.right}) {
|
||||
const auto v = static_cast<std::int16_t>(std::lround(std::clamp(x, -1.f, 1.f) * 32767));
|
||||
integer(static_cast<std::uint16_t>(v), 2);
|
||||
integer(std::bit_cast<std::uint32_t>(x), 4);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -66,7 +66,7 @@ struct Metrics {
|
||||
}
|
||||
};
|
||||
template <class Scenario>
|
||||
void capture(const std::string &prefix, int frames, float pedal, OutdoorScene scene, TwoStrokeConfig config, PipeSolver solver, float fixed_rpm, float warmup, const ScenarioExample* example=nullptr) {
|
||||
void capture(const std::string &prefix, int frames, float pedal, OutdoorScene scene, TwoStrokeConfig config, PipeSolver solver, float fixed_rpm, float warmup, const ScenarioExample* example=nullptr, const std::string& solo="all") {
|
||||
std::unique_ptr<Scenario> s;
|
||||
if constexpr (std::is_same_v<Scenario, TwoStrokeScenario>) s = std::make_unique<Scenario>(44100, config);
|
||||
else if constexpr (std::is_same_v<Scenario, FourStrokeScenario>) {
|
||||
@@ -77,17 +77,34 @@ void capture(const std::string &prefix, int frames, float pedal, OutdoorScene sc
|
||||
s->set_pipe_solver(solver);
|
||||
s->throttle = pedal;
|
||||
s->set_audio_scene(scene);
|
||||
bool valid_solo=solo=="all";
|
||||
for(std::size_t i=0;i<OutdoorAudio::source_names.size();++i) {
|
||||
const bool selected=solo==OutdoorAudio::source_names[i];
|
||||
valid_solo|=selected;
|
||||
s->set_audio_source_enabled(i,solo=="all" || selected);
|
||||
}
|
||||
if(!valid_solo) throw std::runtime_error("choose --solo all, intake, exhaust, exhaust-2, or valve-contact");
|
||||
for(int i=0; i<int(std::lround(warmup*44100)); ++i) {
|
||||
if(fixed_rpm>0) s->crankshaft.omega=fixed_rpm*2*pi/60;
|
||||
s->process();
|
||||
}
|
||||
Wav rendered(prefix + "-rendered.wav", frames), dry(prefix + "-dry.wav", frames),
|
||||
raw(prefix + "-unfiltered.wav", frames);
|
||||
Metrics m, d, r;
|
||||
Metrics m, d, r, tail_metrics;
|
||||
std::array<std::unique_ptr<Wav>,4> stems;
|
||||
std::array<Metrics,4> source_metrics;
|
||||
for(std::size_t i=0;i<stems.size();++i)
|
||||
stems[i]=std::make_unique<Wav>(prefix+"-"+OutdoorAudio::source_names[i]+".wav",frames);
|
||||
Wav tail(prefix+"-tail.wav",frames);
|
||||
int cuts = 0;
|
||||
for (int i = 0; i < frames; i++) {
|
||||
if(fixed_rpm>0) s->crankshaft.omega=fixed_rpm*2*pi/60;
|
||||
auto f = s->process(), df = s->dry_audio(), rf = s->unfiltered_audio();
|
||||
for(std::size_t j=0;j<stems.size();++j) {
|
||||
const auto stem=s->source_audio()[j].rendered;
|
||||
stems[j]->sample(stem); source_metrics[j].add(stem);
|
||||
}
|
||||
tail.sample(s->tail_audio()); tail_metrics.add(s->tail_audio());
|
||||
m.add(f);
|
||||
d.add(df);
|
||||
r.add(rf);
|
||||
@@ -97,16 +114,27 @@ void capture(const std::string &prefix, int frames, float pedal, OutdoorScene sc
|
||||
if (i % 4410 == 0)
|
||||
cuts += s->snapshot().fuel_cut;
|
||||
}
|
||||
for(std::size_t j=0;j<stems.size();++j) source_metrics[j].print(OutdoorAudio::source_names[j]);
|
||||
tail_metrics.print("shared tail");
|
||||
m.print("rendered");
|
||||
d.print("dry filtered");
|
||||
r.print("unfiltered spatial");
|
||||
std::uint64_t repairs=0, fallbacks=0;
|
||||
for(const auto& pipe:s->pipes) { repairs+=pipe.positivity_repairs; fallbacks+=pipe.hllc_fallbacks; }
|
||||
if constexpr (std::is_same_v<Scenario, FourStrokeScenario> || std::is_base_of_v<FourStrokeScenario,Scenario>) {
|
||||
const auto diagnostics=s->snapshot();
|
||||
std::cout<<"junction_model="<<s->junction_config.model<<" junction_fallbacks="<<diagnostics.junction_fallbacks
|
||||
<<" junction_limited_fluxes="<<diagnostics.junction_limited_fluxes<<" junction_iterations="<<diagnostics.junction_iterations<<" limited_fluxes="<<diagnostics.boundary_limited_fluxes<<'\n';
|
||||
}
|
||||
std::cout<<"pipe_positivity_repairs="<<repairs<<" hllc_fallbacks="<<fallbacks<<'\n';
|
||||
std::cout << "fuel-cut checkpoints=" << cuts << " final_rpm=" << s->snapshot().rpm
|
||||
<< " scene=" << scene_name(scene) << '\n';
|
||||
}
|
||||
} // namespace
|
||||
int main(int argc, char **argv) {
|
||||
try {
|
||||
std::string example_id;
|
||||
std::string example_id, solo="all", junction_model;
|
||||
float junction_loss=-1;
|
||||
std::string scenario = "twin", prefix = "build/audio/twin", scene = "wall";
|
||||
float seconds = 6, pedal = 1, fixed_rpm = 0, warmup = 0;
|
||||
TwoStrokeConfig config;
|
||||
@@ -116,7 +144,16 @@ int main(int argc, char **argv) {
|
||||
if (i + 1 >= argc)
|
||||
throw std::runtime_error("missing option value");
|
||||
std::string value = argv[++i];
|
||||
if(key=="--example") example_id=value;
|
||||
if(key=="--junctions") {
|
||||
if(value!="volume" && value!="characteristic" && value!="legacy") throw std::runtime_error("choose volume, characteristic, or legacy junctions");
|
||||
junction_model=value;
|
||||
}
|
||||
else if(key=="--junction-loss") {
|
||||
junction_loss=std::stof(value);
|
||||
if(!std::isfinite(junction_loss) || junction_loss<0 || junction_loss>10) throw std::runtime_error("junction loss must be 0..10");
|
||||
}
|
||||
else if(key=="--solo") solo=value;
|
||||
else if(key=="--example") example_id=value;
|
||||
else if (key == "--scenario")
|
||||
scenario = value;
|
||||
else if (key == "--out")
|
||||
@@ -160,21 +197,30 @@ int main(int argc, char **argv) {
|
||||
if (!std::filesystem::path(prefix).parent_path().empty())
|
||||
std::filesystem::create_directories(std::filesystem::path(prefix).parent_path());
|
||||
const int frames = int(std::lround(seconds * 44100));
|
||||
const auto examples=scenario_examples();
|
||||
auto examples=scenario_examples();
|
||||
if(!junction_model.empty() || junction_loss>=0) {
|
||||
if(example_id.empty()) example_id=scenario=="v8"?"v8-h":scenario=="b205"?"saab-straight":scenario=="twin"?"twin":"yz-racing";
|
||||
for(auto& example:examples) {
|
||||
if(!junction_model.empty()) example.junctions.model=junction_model;
|
||||
if(junction_loss>=0) example.junctions.turning_loss=junction_loss;
|
||||
}
|
||||
}
|
||||
if(!example_id.empty()) {
|
||||
const auto example=std::find_if(examples.begin(),examples.end(),[&](const auto& e){return e.id==example_id;});
|
||||
if(example==examples.end()) throw std::runtime_error("unknown example: "+example_id);
|
||||
if(example->kind==ScenarioKind::TwoStroke && (!junction_model.empty() || junction_loss>=0))
|
||||
throw std::runtime_error("two-stroke exhaust has no configurable pipe junctions");
|
||||
if(example->kind==ScenarioKind::TwoStroke)
|
||||
capture<TwoStrokeScenario>(prefix,frames,pedal,selected,example->two,solver,fixed_rpm,warmup);
|
||||
else capture<FourStrokeScenario>(prefix,frames,pedal,selected,config,solver,fixed_rpm,warmup,&*example);
|
||||
capture<TwoStrokeScenario>(prefix,frames,pedal,selected,example->two,solver,fixed_rpm,warmup,nullptr,solo);
|
||||
else capture<FourStrokeScenario>(prefix,frames,pedal,selected,config,solver,fixed_rpm,warmup,&*example,solo);
|
||||
} else if (scenario == "twin")
|
||||
capture<FourStrokeTwinScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<FourStrokeTwinScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else if (scenario == "b205")
|
||||
capture<SaabB205Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<SaabB205Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else if (scenario == "two-stroke")
|
||||
capture<TwoStrokeScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<TwoStrokeScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else if (scenario == "v8")
|
||||
capture<AmericanV8Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<AmericanV8Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else
|
||||
throw std::runtime_error("choose twin, two-stroke, b205 or v8");
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
59
tools/audio_preview.py
Normal file
59
tools/audio_preview.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""Create peak-normalized listening copies of PCM16 or float32 capture WAVs.
|
||||
|
||||
Usage: py tools/audio_preview.py out/audio/single-450-baseline
|
||||
Original files retain calibration; preview levels must not be compared by source.
|
||||
"""
|
||||
import argparse
|
||||
import math
|
||||
from pathlib import Path
|
||||
import struct
|
||||
import wave
|
||||
|
||||
|
||||
def preview(path, destination):
|
||||
data = path.read_bytes()
|
||||
if data[:4] != b"RIFF" or data[8:12] != b"WAVE":
|
||||
raise ValueError(f"Not a WAV: {path}")
|
||||
offset = 12
|
||||
fmt = payload = None
|
||||
while offset + 8 <= len(data):
|
||||
tag, size = struct.unpack_from("<4sI", data, offset)
|
||||
chunk = data[offset + 8:offset + 8 + size]
|
||||
if tag == b"fmt ":
|
||||
fmt = struct.unpack_from("<HHIIHH", chunk)
|
||||
elif tag == b"data":
|
||||
payload = chunk
|
||||
offset += 8 + size + size % 2
|
||||
if fmt is None or payload is None:
|
||||
raise ValueError(f"Missing WAV chunks: {path}")
|
||||
encoding, channels, rate, _, _, bits = fmt
|
||||
if (encoding, bits) == (3, 32):
|
||||
values = [x[0] for x in struct.iter_unpack("<f", payload)]
|
||||
elif (encoding, bits) == (1, 16):
|
||||
values = [x[0] / 32768 for x in struct.iter_unpack("<h", payload)]
|
||||
else:
|
||||
raise ValueError(f"Unsupported WAV format: {path}")
|
||||
if not all(math.isfinite(x) for x in values):
|
||||
raise ValueError(f"Nonfinite audio: {path}")
|
||||
peak = max(map(abs, values), default=0)
|
||||
if peak == 0:
|
||||
print(f"{path.name}: silent; no preview")
|
||||
return
|
||||
gain = 0.8 / peak
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
target = destination / (path.stem + "-preview.wav")
|
||||
with wave.open(str(target), "wb") as out:
|
||||
out.setparams((channels, 2, rate, 0, "NONE", "not compressed"))
|
||||
out.writeframes(b"".join(struct.pack("<h", round(x * gain * 32767)) for x in values))
|
||||
print(f"{target.name}: gain {20 * math.log10(gain):+.1f} dB")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("prefix", type=Path)
|
||||
args = parser.parse_args()
|
||||
paths = sorted(args.prefix.parent.glob(args.prefix.name + "-*.wav"))
|
||||
if not paths:
|
||||
parser.error("no matching capture WAVs")
|
||||
for path in paths:
|
||||
preview(path, args.prefix.parent / "previews")
|
||||
9
tools/migrate_geometry.cpp
Normal file
9
tools/migrate_geometry.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "FluidSim/ScenarioCatalog.hpp"
|
||||
#include <iostream>
|
||||
int main(int argc,char** argv) try {
|
||||
const auto directory=argc>1?std::filesystem::path(argv[1]):fluidsim::port::engine_directory();
|
||||
const bool relayout=argc>2&&std::string(argv[2])=="--relayout";
|
||||
if(std::filesystem::is_regular_file(directory)){fluidsim::port::migrate_engine_geometry(directory,relayout);return 0;}
|
||||
const auto definitions=fluidsim::port::load_engine_directory(directory);
|
||||
for(const auto& definition:definitions){fluidsim::port::migrate_engine_geometry(definition.source_path,relayout);std::cout<<definition.id<<'\n';}
|
||||
} catch(const std::exception& e){std::cerr<<e.what()<<'\n';return 1;}
|
||||
91
tools/scenario_profile.cpp
Normal file
91
tools/scenario_profile.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include "FluidSim/ScenarioCatalog.hpp"
|
||||
#include "FluidSim/TwoStrokeScenario.hpp"
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace fluidsim::port;
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
template<class Scenario>
|
||||
void measure_case(const ScenarioExample& definition, int density, PipeSolver solver,
|
||||
int repetition, int warmup_frames, int measured_frames, Scenario& scenario, std::ostream& out) {
|
||||
scenario.set_pipe_solver(solver);
|
||||
float target_rpm=7000.f;
|
||||
if constexpr (std::is_same_v<Scenario, FourStrokeScenario>) {
|
||||
scenario.set_controls(.55f, .1f, 0.f);
|
||||
target_rpm=definition.engine.initial_rpm > 0 ? definition.engine.initial_rpm : 4500.f;
|
||||
} else {
|
||||
scenario.set_controls(.55f, .1f, 0.f);
|
||||
}
|
||||
for (int i=0;i<warmup_frames;++i) { scenario.crankshaft.omega=target_rpm*2*pi/60; scenario.process(); }
|
||||
scenario.enable_profiling(true);
|
||||
const auto begin=Clock::now();
|
||||
double audio_energy=0,audio_checksum=0;
|
||||
float audio_peak=0;
|
||||
for (int i=0;i<measured_frames;++i) {
|
||||
scenario.crankshaft.omega=target_rpm*2*pi/60;
|
||||
const auto frame=scenario.process();
|
||||
if(!std::isfinite(frame.left)||!std::isfinite(frame.right)) throw std::runtime_error("nonfinite profiled audio");
|
||||
audio_energy+=double(frame.left)*frame.left+double(frame.right)*frame.right;
|
||||
audio_peak=std::max({audio_peak,std::abs(frame.left),std::abs(frame.right)});
|
||||
audio_checksum+=double(frame.left)*(i+1)+double(frame.right)*(i%251+1);
|
||||
}
|
||||
const double wall=std::chrono::duration<double>(Clock::now()-begin).count();
|
||||
const auto& profile=scenario.profile_totals();
|
||||
std::size_t cells=0;
|
||||
std::size_t scratch_bytes=0;
|
||||
for(const auto& pipe:scenario.pipes) { cells+=pipe.cells.size();scratch_bytes+=pipe.scratch_bytes(); }
|
||||
std::uint64_t repairs=0,fallbacks=0;
|
||||
for(const auto& pipe:scenario.pipes) { repairs+=pipe.positivity_repairs; fallbacks+=pipe.hllc_fallbacks; }
|
||||
double ms[7]{};
|
||||
for(int i=0;i<7;++i) ms[i]=profile.sampled_steps ? profile.nanoseconds[i]/1e6/profile.sampled_steps : 0;
|
||||
out<<definition.id<<','<<(definition.kind==ScenarioKind::TwoStroke?"two-stroke":"four-stroke")<<','<<density<<','
|
||||
<<pipe_solver_name(solver)<<','<<repetition<<','<<scenario.pipes.size()<<','<<cells<<','<<measured_frames<<','
|
||||
<<profile.sampled_steps<<','<<std::setprecision(8)<<wall<<','<<wall/measured_frames*1e6<<','<<wall/(measured_frames/44100.0)<<','
|
||||
<<scratch_bytes<<',';
|
||||
for(int i=0;i<7;++i) out<<ms[i]<<',';
|
||||
out<<profile_percentile_ms(profile,.50)<<','<<profile_percentile_ms(profile,.95)<<','<<repairs<<','<<fallbacks<<','
|
||||
<<std::sqrt(audio_energy/(2*measured_frames))<<','<<audio_peak<<','<<audio_checksum<<'\n';
|
||||
}
|
||||
|
||||
int main(int argc,char** argv) {
|
||||
const std::string output=argc>1?argv[1]:"scenario-profile.csv";
|
||||
const int warmup=argc>2?std::stoi(argv[2]):5000;
|
||||
const int frames=argc>3?std::stoi(argv[3]):22050;
|
||||
const int reps=argc>4?std::stoi(argv[4]):2;
|
||||
std::vector<std::string> ids={"single-450","twin","five","v8-h","yz-fat","saab-chambered"};
|
||||
if(argc>6 && std::string(argv[6])!="all") ids={argv[6]};
|
||||
const std::vector<int> densities=argc>5?std::vector<int>{std::stoi(argv[5])}:
|
||||
std::vector<int>{10,20,40,50,80};
|
||||
std::vector<PipeSolver> solvers={PipeSolver::Rusanov,PipeSolver::Hlle,PipeSolver::Hllc,PipeSolver::Muscl};
|
||||
if(argc>7) solvers={parse_pipe_solver(argv[7])};
|
||||
std::ofstream file(output);
|
||||
if(!file) { std::cerr<<"cannot open output: "<<output<<'\n'; return 2; }
|
||||
file<<"scenario,kind,cells_per_meter,solver,repetition,pipe_count,total_cells,frames,sampled_frames,wall_seconds,wall_us_per_frame,real_time_factor,scratch_bytes,total_ms_per_frame,controls_ms_per_frame,solver_ms_per_frame,boundary_ms_per_frame,pipe_ms_per_frame,components_ms_per_frame,audio_ms_per_frame,p50_frame_ms,p95_frame_ms,positivity_repairs,hllc_fallbacks,audio_rms,audio_peak,audio_checksum\n";
|
||||
int completed=0, total=static_cast<int>(ids.size()*densities.size()*solvers.size()*reps);
|
||||
for(const auto& id:ids) for(int density:densities) for(auto solver:solvers) for(int rep=1;rep<=reps;++rep) {
|
||||
const auto& def=scenario_example(id);
|
||||
auto config=def;
|
||||
config.engine.cells_per_meter=static_cast<float>(density);
|
||||
config.two.cells_per_meter=static_cast<float>(density);
|
||||
if(def.kind==ScenarioKind::TwoStroke) {
|
||||
config.two.exhaust_cell_length=1.0f/density;
|
||||
TwoStrokeScenario scenario(44100,config.two);
|
||||
measure_case(def,density,solver,rep,warmup,frames,scenario,file);
|
||||
} else {
|
||||
FourStrokeScenario scenario(44100,config);
|
||||
measure_case(def,density,solver,rep,warmup,frames,scenario,file);
|
||||
}
|
||||
file.flush();
|
||||
std::cerr<<"completed "<<++completed<<"/"<<total<<" "<<id<<" density="<<density<<" solver="<<pipe_solver_name(solver)<<" rep="<<rep<<'\n';
|
||||
}
|
||||
}
|
||||
185
verification/geometry-header-lengths.csv
Normal file
185
verification/geometry-header-lengths.csv
Normal file
@@ -0,0 +1,185 @@
|
||||
engine,pipe_index,role,previous_length_mm,geometry_length_mm
|
||||
big-carb,9,primaries,750.0,217.248
|
||||
big-carb,10,primaries,750.0,162.56
|
||||
big-carb,11,primaries,750.0,217.248
|
||||
big-carb,12,primaries,750.0,162.56
|
||||
big-carb,13,primaries,750.0,278.871
|
||||
big-carb,14,primaries,750.0,278.871
|
||||
big-carb,15,primaries,750.0,170.011
|
||||
big-carb,16,primaries,750.0,170.011
|
||||
big-carb,17,secondaries,400.0,382.761
|
||||
big-carb,18,secondaries,400.0,121.48
|
||||
big-carb,19,secondaries,400.0,317.058
|
||||
big-carb,20,secondaries,400.0,186.27
|
||||
big-carb,21,bank_collectors,550.0,527.514
|
||||
big-carb,22,bank_collectors,550.0,527.514
|
||||
busso,7,primaries,650.0,362.466
|
||||
busso,8,primaries,650.0,315.14
|
||||
busso,9,primaries,650.0,300.251
|
||||
busso,10,primaries,650.0,223.793
|
||||
busso,11,primaries,650.0,146.864
|
||||
busso,12,primaries,650.0,125.698
|
||||
ej20,5,primaries,650.0,458.345
|
||||
ej20,6,primaries,650.0,432.05
|
||||
ej20,7,primaries,650.0,139.544
|
||||
ej20,8,primaries,650.0,56.452
|
||||
f20,5,primary_1,520.0,235.578
|
||||
f20,6,primary_2,585.0,235.578
|
||||
f20,7,primary_3,650.0,250.978
|
||||
f20,8,primary_4,520.0,250.978
|
||||
f20,10,secondary_10,420.0,277.916
|
||||
f20,11,secondary_11,540.0,66.47
|
||||
five,6,primary_1,520.0,257.205
|
||||
five,7,primary_2,585.0,234.66
|
||||
five,8,primary_3,650.0,257.205
|
||||
five,9,primary_4,520.0,255.345
|
||||
five,10,primary_5,585.0,255.345
|
||||
five,12,secondary_12,420.0,272.078
|
||||
five,13,secondary_13,540.0,20.983
|
||||
flat6,7,primaries,650.0,453.208
|
||||
flat6,8,primaries,650.0,411.807
|
||||
flat6,9,primaries,650.0,399.573
|
||||
flat6,10,primaries,650.0,192.691
|
||||
flat6,11,primaries,650.0,68.392
|
||||
flat6,12,primaries,650.0,44.961
|
||||
ltwin,3,primaries,650.0,361.659
|
||||
ltwin,4,primaries,650.0,121.948
|
||||
rb26,7,primary_1,520.0,230.146
|
||||
rb26,8,primary_2,585.0,202.663
|
||||
rb26,9,primary_3,650.0,230.146
|
||||
rb26,10,primary_4,520.0,245.586
|
||||
rb26,11,primary_5,585.0,220.149
|
||||
rb26,12,primary_6,650.0,245.586
|
||||
rb26,14,secondary_14,420.0,327.721
|
||||
rb26,15,secondary_15,540.0,12.434
|
||||
saab-chambered,5,primaries,280.0,351.447
|
||||
saab-chambered,6,primaries,280.0,280.087
|
||||
saab-chambered,7,primaries,280.0,241.712
|
||||
saab-chambered,8,primaries,280.0,244.991
|
||||
saab-expansion,5,primaries,280.0,351.447
|
||||
saab-expansion,6,primaries,280.0,280.087
|
||||
saab-expansion,7,primaries,280.0,241.712
|
||||
saab-expansion,8,primaries,280.0,244.991
|
||||
saab-open,5,primaries,280.0,351.447
|
||||
saab-open,6,primaries,280.0,280.087
|
||||
saab-open,7,primaries,280.0,241.712
|
||||
saab-open,8,primaries,280.0,244.991
|
||||
saab-straight,5,primaries,280.0,351.447
|
||||
saab-straight,6,primaries,280.0,280.087
|
||||
saab-straight,7,primaries,280.0,241.712
|
||||
saab-straight,8,primaries,280.0,244.991
|
||||
single-450,2,primaries,650.0,218.917
|
||||
single-650,2,primaries,650.0,269.186
|
||||
six-long,7,primary_1,520.0,258.773
|
||||
six-long,8,primary_2,585.0,233.953
|
||||
six-long,9,primary_3,650.0,258.773
|
||||
six-long,10,primary_4,520.0,272.777
|
||||
six-long,11,primary_5,585.0,249.455
|
||||
six-long,12,primary_6,650.0,272.777
|
||||
six-long,14,secondary_14,420.0,327.721
|
||||
six-long,15,secondary_15,540.0,12.434
|
||||
triple,4,primary_1,520.0,213.136
|
||||
triple,5,primary_2,585.0,187.741
|
||||
triple,6,primary_3,650.0,213.136
|
||||
triple,8,secondary_8,420.0,176.671
|
||||
twin-270,3,primaries,650.0,243.295
|
||||
twin-270,4,primaries,650.0,204.507
|
||||
twin,3,primaries,200.0,249.312
|
||||
twin,4,primaries,200.0,208.232
|
||||
v10,11,primary_1,520.0,266.257
|
||||
v10,12,primary_2,585.0,167.815
|
||||
v10,13,primary_3,650.0,128.915
|
||||
v10,14,primary_4,520.0,167.815
|
||||
v10,15,primary_5,585.0,266.257
|
||||
v10,16,primary_6,650.0,266.257
|
||||
v10,17,primary_7,520.0,167.815
|
||||
v10,18,primary_8,585.0,128.915
|
||||
v10,19,primary_9,650.0,167.815
|
||||
v10,20,primary_10,520.0,266.257
|
||||
v10,23,secondary_23,420.0,169.159
|
||||
v10,24,secondary_24,540.0,169.159
|
||||
v12,13,primary_1,520.0,267.408
|
||||
v12,14,primary_2,585.0,182.128
|
||||
v12,15,primary_3,650.0,125.028
|
||||
v12,16,primary_4,520.0,125.028
|
||||
v12,17,primary_5,585.0,182.128
|
||||
v12,18,primary_6,650.0,267.408
|
||||
v12,19,primary_7,520.0,267.408
|
||||
v12,20,primary_8,585.0,182.128
|
||||
v12,21,primary_9,650.0,125.028
|
||||
v12,22,primary_10,520.0,125.028
|
||||
v12,23,primary_11,585.0,182.128
|
||||
v12,24,primary_12,650.0,267.408
|
||||
v12,27,secondary_27,420.0,168.746
|
||||
v12,28,secondary_28,540.0,168.746
|
||||
v8-dual,9,primaries,750.0,215.493
|
||||
v8-dual,10,primaries,750.0,164.663
|
||||
v8-dual,11,primaries,750.0,215.493
|
||||
v8-dual,12,primaries,750.0,164.663
|
||||
v8-dual,13,primaries,750.0,267.946
|
||||
v8-dual,14,primaries,750.0,267.946
|
||||
v8-dual,15,primaries,750.0,168.157
|
||||
v8-dual,16,primaries,750.0,168.157
|
||||
v8-dual,17,secondaries,400.0,344.902
|
||||
v8-dual,18,secondaries,400.0,109.109
|
||||
v8-dual,19,secondaries,400.0,285.577
|
||||
v8-dual,20,secondaries,400.0,167.554
|
||||
v8-dual,21,bank_collectors,550.0,575.518
|
||||
v8-dual,22,bank_collectors,550.0,575.518
|
||||
v8-dual,25,crossover,780.0,816.84
|
||||
v8-h,9,primaries,750.0,215.493
|
||||
v8-h,10,primaries,750.0,164.663
|
||||
v8-h,11,primaries,750.0,215.493
|
||||
v8-h,12,primaries,750.0,164.663
|
||||
v8-h,13,primaries,750.0,267.946
|
||||
v8-h,14,primaries,750.0,267.946
|
||||
v8-h,15,primaries,750.0,168.157
|
||||
v8-h,16,primaries,750.0,168.157
|
||||
v8-h,17,secondaries,400.0,344.902
|
||||
v8-h,18,secondaries,400.0,109.109
|
||||
v8-h,19,secondaries,400.0,285.577
|
||||
v8-h,20,secondaries,400.0,167.554
|
||||
v8-h,21,bank_collectors,550.0,558.179
|
||||
v8-h,22,bank_collectors,550.0,558.179
|
||||
v8-large,9,primaries,750.0,215.493
|
||||
v8-large,10,primaries,750.0,164.663
|
||||
v8-large,11,primaries,750.0,215.493
|
||||
v8-large,12,primaries,750.0,164.663
|
||||
v8-large,13,primaries,750.0,267.946
|
||||
v8-large,14,primaries,750.0,267.946
|
||||
v8-large,15,primaries,750.0,168.157
|
||||
v8-large,16,primaries,750.0,168.157
|
||||
v8-large,17,secondaries,400.0,344.902
|
||||
v8-large,18,secondaries,400.0,109.109
|
||||
v8-large,19,secondaries,400.0,285.577
|
||||
v8-large,20,secondaries,400.0,167.554
|
||||
v8-large,21,bank_collectors,550.0,558.179
|
||||
v8-large,22,bank_collectors,550.0,558.179
|
||||
v8-long,9,primaries,900.0,410.859
|
||||
v8-long,10,primaries,900.0,329.5
|
||||
v8-long,11,primaries,900.0,410.859
|
||||
v8-long,12,primaries,900.0,329.5
|
||||
v8-long,13,primaries,900.0,467.152
|
||||
v8-long,14,primaries,900.0,467.152
|
||||
v8-long,15,primaries,900.0,298.245
|
||||
v8-long,16,primaries,900.0,298.245
|
||||
v8-long,17,secondaries,400.0,344.902
|
||||
v8-long,18,secondaries,400.0,109.109
|
||||
v8-long,19,secondaries,400.0,285.577
|
||||
v8-long,20,secondaries,400.0,167.554
|
||||
v8-long,21,bank_collectors,550.0,558.179
|
||||
v8-long,22,bank_collectors,550.0,558.179
|
||||
v8-short,9,primaries,600.0,173.74
|
||||
v8-short,10,primaries,600.0,140.089
|
||||
v8-short,11,primaries,600.0,173.74
|
||||
v8-short,12,primaries,600.0,140.089
|
||||
v8-short,13,primaries,600.0,223.501
|
||||
v8-short,14,primaries,600.0,223.501
|
||||
v8-short,15,primaries,600.0,157.11
|
||||
v8-short,16,primaries,600.0,157.11
|
||||
v8-short,17,secondaries,400.0,344.902
|
||||
v8-short,18,secondaries,400.0,109.109
|
||||
v8-short,19,secondaries,400.0,285.577
|
||||
v8-short,20,secondaries,400.0,167.554
|
||||
v8-short,21,bank_collectors,550.0,558.179
|
||||
v8-short,22,bank_collectors,550.0,558.179
|
||||
|
25
verification/performance/2026-10-24/default-five-test.csv
Normal file
25
verification/performance/2026-10-24/default-five-test.csv
Normal file
@@ -0,0 +1,25 @@
|
||||
scenario,kind,cells_per_meter,solver,repetition,pipe_count,total_cells,frames,sampled_frames,wall_seconds,wall_us_per_frame,real_time_factor,total_ms_per_frame,controls_ms_per_frame,solver_ms_per_frame,boundary_ms_per_frame,pipe_ms_per_frame,components_ms_per_frame,audio_ms_per_frame,p50_frame_ms,p95_frame_ms,positivity_repairs,hllc_fallbacks
|
||||
single-450,four-stroke,50,rusanov,1,4,131,5000,2500,0.0221766,4.43532,0.19559761,0.0045904,0.00029724,0.00371408,0.0013946,0.00172644,7.936e-05,0.00047056,0.0045,0.0045,0,0
|
||||
single-450,four-stroke,50,hlle,1,4,131,5000,2500,0.0298873,5.97746,0.26360599,0.00608568,0.00031204,0.00520532,0.00142852,0.00296664,8.048e-05,0.00046164,0.0055,0.0065,0,0
|
||||
single-450,four-stroke,50,hllc,1,4,131,5000,2500,0.0324929,6.49858,0.28658738,0.006661,0.00030784,0.00577968,0.00142544,0.00353328,8.296e-05,0.0004676,0.0065,0.0065,0,0
|
||||
single-450,four-stroke,50,muscl,1,4,131,5000,2500,0.0427053,8.54106,0.37666075,0.0086688,0.00030336,0.00779792,0.00297476,0.00399228,8.168e-05,0.00046232,0.0085,0.0085,0,0
|
||||
twin,four-stroke,50,rusanov,1,6,55,5000,2500,0.0234109,4.68218,0.20648414,0.0048414,0.00036636,0.003913,0.0025476,0.00091236,0.0001218,0.00045752,0.0045,0.0075,0,0
|
||||
twin,four-stroke,50,hlle,1,6,55,5000,2500,0.0264447,5.28894,0.23324225,0.0054552,0.00036908,0.00453396,0.0024906,0.00148312,0.0001244,0.00045072,0.0045,0.0085,0,0
|
||||
twin,four-stroke,50,hllc,1,6,55,5000,2500,0.0286684,5.73368,0.25285529,0.00591868,0.00037288,0.00498284,0.00260644,0.0018032,0.00012824,0.000457,0.0045,0.0095,0,0
|
||||
twin,four-stroke,50,muscl,1,6,55,5000,2500,0.0337112,6.74224,0.29733278,0.00693444,0.00038912,0.00599156,0.00332472,0.00209188,0.0001288,0.00045044,0.0055,0.0105,0,0
|
||||
five,four-stroke,50,rusanov,1,14,343,5000,2500,0.0895132,17.90264,0.78950642,0.01815772,0.00081088,0.01673892,0.00846708,0.0059292,0.00034728,0.0004972,0.0205,0.0215,0,0
|
||||
five,four-stroke,50,hlle,1,14,343,5000,2500,0.133426,26.6852,1.1768173,0.02675072,0.0009624,0.02510568,0.00925144,0.01224052,0.00039596,0.0005586,0.0295,0.0325,0,0
|
||||
five,four-stroke,50,hllc,1,14,343,5000,2500,0.172315,34.463,1.5198183,0.03039436,0.00094916,0.02872924,0.00944852,0.01554452,0.00043216,0.00059528,0.0315,0.0515,0,0
|
||||
five,four-stroke,50,muscl,1,14,343,5000,2500,0.2017581,40.35162,1.7795064,0.04055332,0.0009302,0.03896732,0.01783364,0.01755344,0.00041908,0.00053652,0.0445,0.0475,0,0
|
||||
v8-h,four-stroke,50,rusanov,1,26,662,5000,2500,0.1798743,35.97486,1.5864913,0.03607572,0.00136824,0.03395516,0.01562336,0.01415284,0.00061336,0.00063232,0.0425,0.0455,0,0
|
||||
v8-h,four-stroke,50,hlle,1,26,662,5000,2500,0.2461426,49.22852,2.1709777,0.04931684,0.00139948,0.0470782,0.01617044,0.02484084,0.00063652,0.00071104,0.0575,0.0645,0,0
|
||||
v8-h,four-stroke,50,hllc,1,26,662,5000,2500,0.2689101,53.78202,2.3717871,0.054181,0.00135556,0.05198136,0.01624432,0.02972492,0.00060668,0.00071292,0.0635,0.0835,0,0
|
||||
v8-h,four-stroke,50,muscl,1,26,662,5000,2500,0.340461,68.0922,3.002866,0.06829276,0.00127412,0.06627316,0.02883468,0.03174308,0.00064368,0.00062556,0.0835,0.0905,0,0
|
||||
yz-fat,two-stroke,50,rusanov,1,4,70,5000,2500,0.0563677,11.27354,0.49716311,0.01165048,0.00031712,0.01087784,0.00549588,0.00386268,0.00028332,0.00035296,0.0115,0.0135,0,0
|
||||
yz-fat,two-stroke,50,hlle,1,4,70,5000,2500,0.0712716,14.25432,0.62861551,0.01464896,0.00034904,0.01385312,0.00542264,0.00644052,0.000286,0.00034304,0.0145,0.0165,0,0
|
||||
yz-fat,two-stroke,50,hllc,1,4,70,5000,2500,0.0763663,15.27326,0.67355077,0.01571584,0.00031624,0.01495828,0.00534936,0.0076164,0.0003036,0.00034232,0.0155,0.0165,0,0
|
||||
yz-fat,two-stroke,50,muscl,1,4,70,5000,2500,0.0906575,18.1315,0.79959915,0.01856376,0.00031808,0.01779808,0.0071104,0.00868528,0.00028244,0.00034488,0.0185,0.0195,0,0
|
||||
saab-chambered,four-stroke,50,rusanov,1,10,301,5000,2500,0.0887478,17.74956,0.7827556,0.0179724,0.000745,0.0165752,0.00725352,0.006773,0.0003276,0.00053304,0.0165,0.0245,0,0
|
||||
saab-chambered,four-stroke,50,hlle,1,10,301,5000,2500,0.1215358,24.30716,1.0719458,0.02448896,0.00072844,0.02313632,0.00709296,0.01260368,0.00030968,0.0005096,0.0235,0.0255,0,0
|
||||
saab-chambered,four-stroke,50,hllc,1,10,301,5000,2500,0.1324411,26.48822,1.1681305,0.02655668,0.00070284,0.02523496,0.00696064,0.01487744,0.0003076,0.00049696,0.0255,0.0275,0,0
|
||||
saab-chambered,four-stroke,50,muscl,1,10,301,5000,2500,0.1796392,35.92784,1.5844177,0.036017,0.0006922,0.03468728,0.01377652,0.01751864,0.00032228,0.00051936,0.0345,0.0365,0,0
|
||||
|
13
verification/performance/2026-10-24/fused-hllc.csv
Normal file
13
verification/performance/2026-10-24/fused-hllc.csv
Normal file
@@ -0,0 +1,13 @@
|
||||
scenario,kind,cells_per_meter,solver,repetition,pipe_count,total_cells,frames,sampled_frames,wall_seconds,wall_us_per_frame,real_time_factor,scratch_bytes,total_ms_per_frame,controls_ms_per_frame,solver_ms_per_frame,boundary_ms_per_frame,pipe_ms_per_frame,components_ms_per_frame,audio_ms_per_frame,p50_frame_ms,p95_frame_ms,positivity_repairs,hllc_fallbacks,audio_rms,audio_peak,audio_checksum
|
||||
single-450,four-stroke,45,hllc,1,4,119,22050,11025,0.226753,10.283583,0.453506,9600,0.010504744,0.00033513832,0.0095517914,0.0025144943,0.0056832925,0.00013962812,0.0005081542,0.0115,0.0125,0,0,0.043393295,0.3492032,-33516.677
|
||||
single-450,four-stroke,45,hllc,2,4,119,22050,11025,0.2273775,10.311905,0.454755,9600,0.010573279,0.00032452608,0.0096300952,0.0025129252,0.0057707211,0.00015024943,0.000506839,0.0115,0.0125,0,0,0.043393295,0.3492032,-33516.677
|
||||
twin,four-stroke,45,hllc,1,6,51,22050,11025,0.1395075,6.3268707,0.279015,4200,0.0065239002,0.0004158458,0.0054552653,0.00292439,0.0019081633,0.00014010884,0.00053018594,0.0045,0.0105,0,0,0.020964235,0.087753639,-17579.35
|
||||
twin,four-stroke,45,hllc,2,6,51,22050,11025,0.134874,6.1167347,0.269748,4200,0.0062841995,0.00041102041,0.0052507664,0.0028056871,0.0018331156,0.00014101587,0.00051551927,0.0045,0.0095,0,0,0.020964235,0.087753639,-17579.35
|
||||
five,four-stroke,45,hllc,1,14,313,22050,11025,0.7043746,31.944426,1.4087492,25320,0.031781651,0.0009593288,0.030065261,0.010523184,0.015685488,0.00044372789,0.00061826757,0.0295,0.0505,0,0,0.024103642,0.069309026,29082.476
|
||||
five,four-stroke,45,hllc,2,14,313,22050,11025,0.6817808,30.919764,1.3635616,25320,0.031089515,0.00089840363,0.029520154,0.010440871,0.015260671,0.00043317007,0.00055311565,0.0295,0.0345,0,0,0.024103642,0.069309026,29082.476
|
||||
v8-h,four-stroke,45,hllc,1,26,601,22050,11025,1.4013227,63.55205,2.8026454,48600,0.063683184,0.0013378503,0.061552063,0.020429714,0.033837025,0.00095687075,0.00067591837,0.0605,0.0685,0,0,0.023209132,0.068203621,35894.278
|
||||
v8-h,four-stroke,45,hllc,2,26,601,22050,11025,1.3803378,62.600354,2.7606756,48600,0.062786122,0.0013044082,0.06069327,0.020193968,0.033333188,0.0009505034,0.00067097506,0.0605,0.0665,0,0,0.023209132,0.068203621,35894.278
|
||||
yz-fat,two-stroke,45,hllc,1,4,63,22050,11025,0.3248706,14.733361,0.6497412,5120,0.015149941,0.00033209977,0.01432127,0.0054405714,0.0069541587,0.00029183673,0.00039266213,0.0145,0.0155,0,0,0.012617898,0.062623143,6581.8354
|
||||
yz-fat,two-stroke,45,hllc,2,4,63,22050,11025,0.3236508,14.678041,0.6473016,5120,0.015069868,0.00032561451,0.014249188,0.0054333424,0.0069055329,0.00028797279,0.00038923356,0.0145,0.0155,0,0,0.012617898,0.062623143,6581.8354
|
||||
saab-chambered,four-stroke,45,hllc,1,10,273,22050,11025,0.5518963,25.029311,1.1037926,22040,0.025288934,0.00075125624,0.023891565,0.0070525533,0.013600027,0.00031453061,0.00053470295,0.0245,0.0255,0,0,0.0046967565,0.017882032,39673.188
|
||||
saab-chambered,four-stroke,45,hllc,2,10,273,22050,11025,0.5494029,24.916231,1.0988058,22040,0.02511083,0.00069336961,0.023768771,0.0070486349,0.013515746,0.00031092063,0.00053026757,0.0245,0.0255,0,0,0.0046967565,0.017882032,39673.188
|
||||
|
13
verification/performance/2026-10-24/fused-hlle.csv
Normal file
13
verification/performance/2026-10-24/fused-hlle.csv
Normal file
@@ -0,0 +1,13 @@
|
||||
scenario,kind,cells_per_meter,solver,repetition,pipe_count,total_cells,frames,sampled_frames,wall_seconds,wall_us_per_frame,real_time_factor,scratch_bytes,total_ms_per_frame,controls_ms_per_frame,solver_ms_per_frame,boundary_ms_per_frame,pipe_ms_per_frame,components_ms_per_frame,audio_ms_per_frame,p50_frame_ms,p95_frame_ms,positivity_repairs,hllc_fallbacks,audio_rms,audio_peak,audio_checksum
|
||||
single-450,four-stroke,60,hlle,1,4,156,22050,11025,0.2699482,12.242549,0.5398964,12560,0.012483556,0.00031012245,0.011569551,0.0027820771,0.006976263,0.00015788662,0.00049303401,0.0125,0.0135,0,0,0.042480939,0.44339529,-7325.8487
|
||||
single-450,four-stroke,60,hlle,2,4,156,22050,11025,0.2861725,12.978345,0.572345,12560,0.013163283,0.00033742404,0.012185351,0.0029106122,0.0073480181,0.00017331519,0.00053260771,0.0125,0.0185,0,0,0.042480939,0.44339529,-7325.8487
|
||||
twin,four-stroke,60,hlle,1,6,68,22050,11025,0.1870163,8.4814649,0.3740326,5560,0.0086773152,0.00037509297,0.0077045533,0.0038972154,0.002815229,0.00018769161,0.00049344218,0.0085,0.0125,0,0,0.019982735,0.077876091,-19911.264
|
||||
twin,four-stroke,60,hlle,2,6,68,22050,11025,0.1922604,8.7192925,0.3845208,5560,0.0089856327,0.00041107483,0.007917034,0.0039755828,0.0029109297,0.00019119274,0.0005355737,0.0095,0.0125,0,0,0.019982735,0.077876091,-19911.264
|
||||
five,four-stroke,60,hlle,1,14,411,22050,11025,0.7560888,34.289741,1.5121776,33160,0.034633116,0.00086585034,0.03310332,0.010930594,0.017191175,0.00045463946,0.00054821769,0.0325,0.0475,0,0,0.023922801,0.069260068,28186.437
|
||||
five,four-stroke,60,hlle,2,14,411,22050,11025,0.7722134,35.021016,1.5444268,33160,0.035018812,0.00091385034,0.033422975,0.011102948,0.01721795,0.00045916553,0.00056463492,0.0315,0.0515,0,0,0.023922801,0.069260068,28186.437
|
||||
v8-h,four-stroke,60,hlle,1,26,794,22050,11025,1.6621008,75.378721,3.3242016,64040,0.075711093,0.001263737,0.073679701,0.022620009,0.041107311,0.00085119274,0.00064839909,0.0655,0.0985,0,0,0.022692543,0.065287925,37056.354
|
||||
v8-h,four-stroke,60,hlle,2,26,794,22050,11025,1.6683265,75.661066,3.336653,64040,0.076016934,0.0012778322,0.073936626,0.022752027,0.041154032,0.00085946485,0.0006872381,0.0655,0.0985,0,0,0.022692543,0.065287925,37056.354
|
||||
yz-fat,two-stroke,60,hlle,1,4,81,22050,11025,0.3416302,15.493433,0.6832604,6560,0.015876027,0.00034703855,0.01504693,0.005505941,0.0073312744,0.00028359184,0.00037781406,0.0155,0.0175,0,0,0.013830628,0.069703102,6103.5286
|
||||
yz-fat,two-stroke,60,hlle,2,4,81,22050,11025,0.3414487,15.485202,0.6828974,6560,0.01588137,0.00034490703,0.015047039,0.0054764626,0.0073373515,0.0002962449,0.00038029025,0.0155,0.0175,0,0,0.013830628,0.069703102,6103.5286
|
||||
saab-chambered,four-stroke,60,hlle,1,10,356,22050,11025,0.6287173,28.513256,1.2574346,28680,0.028825741,0.0007111746,0.027438739,0.007574966,0.015542367,0.00032743764,0.00056229478,0.0265,0.0395,0,0,0.0038942062,0.013391916,30491.41
|
||||
saab-chambered,four-stroke,60,hlle,2,10,356,22050,11025,0.6213095,28.177302,1.242619,28680,0.028399175,0.00070341043,0.027025832,0.007438966,0.015287093,0.00032465306,0.0005556644,0.0265,0.0385,0,0,0.0038942062,0.013391916,30491.41
|
||||
|
13
verification/performance/2026-10-24/fused-muscl.csv
Normal file
13
verification/performance/2026-10-24/fused-muscl.csv
Normal file
@@ -0,0 +1,13 @@
|
||||
scenario,kind,cells_per_meter,solver,repetition,pipe_count,total_cells,frames,sampled_frames,wall_seconds,wall_us_per_frame,real_time_factor,scratch_bytes,total_ms_per_frame,controls_ms_per_frame,solver_ms_per_frame,boundary_ms_per_frame,pipe_ms_per_frame,components_ms_per_frame,audio_ms_per_frame,p50_frame_ms,p95_frame_ms,positivity_repairs,hllc_fallbacks,audio_rms,audio_peak,audio_checksum
|
||||
single-450,four-stroke,25,muscl,1,4,67,22050,11025,0.1207051,5.4741542,0.2414102,7048,0.0056283991,0.00030226757,0.0047359819,0.0022857687,0.0020405896,8.1705215e-05,0.00048489796,0.0055,0.0055,0,0,0.048889616,0.53468895,-4420.8798
|
||||
single-450,four-stroke,25,muscl,2,4,67,22050,11025,0.1201182,5.4475374,0.2402364,7048,0.0056231474,0.00030870748,0.0047284898,0.0022821224,0.0020352109,8.0589569e-05,0.00048273923,0.0055,0.0055,0,0,0.048889616,0.53468895,-4420.8798
|
||||
twin,four-stroke,25,muscl,1,6,28,22050,11025,0.101845,4.6188209,0.20369,3032,0.0047535964,0.00040931519,0.0037210249,0.0024937506,0.00087921088,0.00010722902,0.00051560998,0.0045,0.0055,0,0,0.021345219,0.095168315,-17220.858
|
||||
twin,four-stroke,25,muscl,2,6,28,22050,11025,0.0966549,4.3834422,0.1933098,3032,0.0045384853,0.00037672562,0.0035658685,0.0023995374,0.00084745578,0.00010509751,0.00049126531,0.0045,0.0055,0,0,0.021345219,0.095168315,-17220.858
|
||||
five,four-stroke,25,muscl,1,14,176,22050,11025,0.3300924,14.970177,0.6601848,18584,0.015122975,0.00083388662,0.013641433,0.0077705215,0.0049303764,0.00021189116,0.00053053968,0.0145,0.0155,0,0,0.024139173,0.088497825,30661.011
|
||||
five,four-stroke,25,muscl,2,14,176,22050,11025,0.3492916,15.840889,0.6985832,18584,0.015937116,0.00093246259,0.014334494,0.0080950567,0.0052388027,0.00023365079,0.00055497506,0.0145,0.0225,0,0,0.024139173,0.088497825,30661.011
|
||||
v8-h,four-stroke,25,muscl,1,26,333,22050,11025,0.6409428,29.067701,1.2818856,35152,0.029262204,0.0012698141,0.027210358,0.015206177,0.010328118,0.00039207256,0.00066624943,0.0285,0.0305,0,0,0.045346992,0.33563548,43853.021
|
||||
v8-h,four-stroke,25,muscl,2,26,333,22050,11025,0.6774216,30.722068,1.3548432,35152,0.030821995,0.0013487256,0.028639175,0.016007918,0.010845333,0.00042159637,0.00071086621,0.0285,0.0345,0,0,0.045346992,0.33563548,43853.021
|
||||
yz-fat,two-stroke,25,muscl,1,4,38,22050,11025,0.2847994,12.916073,0.5695988,4032,0.013311392,0.00036107029,0.012423347,0.0063281088,0.0049026667,0.00027940136,0.00041877551,0.0125,0.0165,0,0,0.010449031,0.050818499,6591.2704
|
||||
yz-fat,two-stroke,25,muscl,2,4,38,22050,11025,0.2711458,12.296862,0.5422916,4032,0.01269151,0.00034397279,0.011848236,0.0060514014,0.0046448254,0.00027451247,0.00039845805,0.0125,0.0135,0,0,0.010449031,0.050818499,6591.2704
|
||||
saab-chambered,four-stroke,25,muscl,1,10,155,22050,11025,0.4817611,21.848576,0.9635222,16320,0.022108399,0.00069845805,0.02073395,0.010338921,0.0088230295,0.0003119093,0.00056509751,0.0215,0.0225,0,0,0.0043141097,0.016827723,34823.247
|
||||
saab-chambered,four-stroke,25,muscl,2,10,155,22050,11025,0.4796544,21.753034,0.9593088,16320,0.022006213,0.00069043991,0.020655819,0.010321016,0.0087824943,0.00030727438,0.00054684807,0.0215,0.0225,0,0,0.0043141097,0.016827723,34823.247
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user