Files
FluidSimCpp/include/FluidSim/TwoStrokeConfig.hpp

75 lines
3.6 KiB
C++

#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 {
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;
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 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%)
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<PipeSection, 6> 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