#pragma once #include "FluidSim/PipeProfile.hpp" #include "FluidSim/Ecu.hpp" #include "FluidSim/Vehicle.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 { EcuConfig ecu=[] { EcuConfig e; e.idle_control=EcuConfig::IdleControl::FixedOpening; e.throttle_time_constant=.0002f;e.throttle_rate=5000; e.ignition_map={{0,10},{3000,18},{6000,24},{9000,18},{11000,12},{13000,6},{15000,2},{18000,0}}; e.idle_rpm=3000;e.idle_max_opening=.3f;e.rev_limit_enabled=false; e.overrun_cut_rpm=5000;e.overrun_resume_rpm=3500; e.rev_limit_fuel_cut_enabled=false;e.overrun_fuel_cut_enabled=false;e.overrun_ignition_cut_enabled=true; return e; }(); VehicleConfig vehicle=[] { VehicleConfig v; v.primary_reduction=64.f/19;v.final_drive_ratio=49.f/13; v.gear_ratios={31.f/13,29.f/15,27.f/17,23.f/17,20.f/17,19.f/18}; v.mass=170;v.wheel_radius=.3313f; return v; }(); float initial_rpm{3000}, starter_torque{8}, maximum_load_torque{10}; float crankshaft_inertia{.01f}; 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 pilot_jet_scale{.75f}, main_jet_scale{1.6f}, needle_jet_scale{1.f}; float needle_low_scale{2.72f}, needle_mid_scale{.8f}; float needle_off_idle_scale{12.f}, needle_transition_scale{9.f}, needle_tip_scale{5.f}; float needle_quarter_scale{1.4f}, needle_upper_scale{.76f}; float pilot_transition_scale{1.f}, pilot_tip_scale{1.f}; float jet_scale{1.f}; // multiplier on effective jet diameters float crankcase_clearance{150e-6f}; float carburetor_diameter{.0381f}; 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%) 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