#pragma once #include "FluidSim/PipeProfile.hpp" #include namespace fluidsim::port { 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 { TwoStrokeExhaust exhaust{TwoStrokeExhaust::Racing}; float bore{.054f}, stroke{.0545f}, rod{.110f}; float trapped_compression{8.2f}; // exhaust-closure volume / clearance volume float transfer_duration{130}, exhaust_duration{190}; float transfer_width{.050f}, exhaust_width{.036f}; // summed effective window widths float jet_scale{1.f}; // multiplier on effective jet diameters float crankcase_clearance{150e-6f}; float carburetor_diameter{.0381f}; float idle_slide_opening{.045f}; // fixed mechanical stop, normalized 0..1 (4.5%) float minimum_burn_seconds{.0008f}; // Empirical mechanical FMEP = A + B*mean_piston_speed + C*speed^2. // Generic correlation estimates, not a measured YZ125 coast-down fit. float friction_bar{.4f}, friction_bar_per_mps{.09f}, friction_bar_per_mps2{.0009f}; float exhaust_cell_length{.01f}; std::array racing_pipe{{ {.160f, .036f, .036f}, // header {.180f, .036f, .060f}, // shallow first diffuser {.190f, .060f, .105f}, // second diffuser {.130f, .105f, .105f}, // belly {.210f, .105f, .022f}, // convergent / baffle cone {.240f, .022f, .022f} // stinger }}; float geometric_compression() const { const float theta = (180 + exhaust_duration * .5f) * pi / 180; const float radius = stroke * .5f, sine = std::sin(theta); const float travel = radius * (1 - std::cos(theta)) + rod - std::sqrt(rod*rod - radius*radius*sine*sine); return 1 + (trapped_compression - 1) * stroke / travel; } }; } // namespace fluidsim::port