#pragma once #include "FluidSim/AudioProcessing.hpp" #include "FluidSim/Atmosphere.hpp" #include "FluidSim/Engine.hpp" #include "FluidSim/Ecu.hpp" #include "FluidSim/Fluid.hpp" #include "FluidSim/MechanicalSoundProcessor.hpp" #include "FluidSim/OutdoorAudio.hpp" #include "FluidSim/Solver.hpp" #include "FluidSim/Vehicle.hpp" #include "FluidSim/MotorcycleTest.hpp" #include "FluidSim/Turbocharger.hpp" #include #include #include #include #include namespace fluidsim::port { enum class ScenarioKind { Twin, TwoStroke, SaabB205, TurboTwin }; enum class FourStrokePreset { Twin, SaabB205 }; struct ScenarioSnapshot { bool turbo_enabled{}; TurboSnapshot turbo{}; int cylinder_count{2}; float rev_limit_rpm{10000}; std::array cylinder_pressures{}, piston_fractions{}, intake_areas{}, exhaust_areas{}; std::uint64_t solver_substeps{}, boundary_iterations{}; float rpm{}, speed_kmh{}, kinetic_energy{}, average_power{}, average_torque{}; float cylinder_pressure1{}, cylinder_pressure2{}; float cylinder_temperature1{}, cylinder_temperature2{}; float cylinder_piston_fraction1{}, cylinder_piston_fraction2{}; float valve1_intake_area{}, valve1_exhaust_area{}, valve2_intake_area{}, valve2_exhaust_area{}; float intake_pressure{}, exhaust_pressure{}; float throttle{}, pedal{}, target_afr{}, clutch{}, intake_flow{}, exhaust_flow{}; bool idle_control{}, fuel_cut{}, two_stroke{}, reed_open{}; bool racing_exhaust{}; float crankcase_pressure{}; OutdoorScene audio_scene{OutdoorScene::Wall}; int gear{}; bool rev_limit1{}, rev_limit2{}, mechanical_sound_enabled{}; std::array, 12> pipe_states; std::array, 12> pipe_areas, pipe_lengths; void capture_pipes(const std::vector& pipes) { for (std::size_t k = 0; k < pipes.size(); ++k) { pipe_areas[k] = pipes[k].cell_areas; pipe_lengths[k] = pipes[k].cell_lengths; pipe_states[k].reserve(pipes[k].cells.size()); for (std::size_t i = 0; i < pipes[k].cells.size(); ++i) pipe_states[k].push_back(pipes[k].state(static_cast(i))); } } }; // Shared four-stroke topology: independent runners/headers and shared plenums. // Presets retain the original 600 cc twin and add a B205-sized inline-four. class FourStrokeScenario : public MotorcycleTest { public: explicit FourStrokeScenario(int sample_rate = 44100, FourStrokePreset preset = FourStrokePreset::Twin, bool turbo_enabled = false); const FourStrokePreset preset; int cylinder_count() const { return preset == FourStrokePreset::SaabB205 ? 4 : 2; } std::array cylinders() { return {&cylinder1, &cylinder2, &cylinder3, &cylinder4}; } AudioFrame process(); void set_controls(float throttle_value, float load_value, float clutch_value); void toggle_mechanical_sound(); void set_audio_scene(OutdoorScene scene); void set_monitor_filter(bool enabled); AudioFrame dry_audio() const; AudioFrame unfiltered_audio() const; void shift_up(); void shift_down(); void set_neutral(); void set_first_gear(); ScenarioSnapshot snapshot() const; float throttle{}; bool mechanical_sound_enabled{}; float mechanical_mix{0.02f}; Ecu ecu{}; std::unique_ptr turbo; Crankshaft crankshaft{}; FourStrokeCylinder cylinder1{}, cylinder2{}, cylinder3{}, cylinder4{}; Atmosphere intake_atmosphere{}; Volume0D intake_plenum{1.0e-3f, 101325.0f, 300.0f}; Volume0D exhaust_collector{0.15e-3f, 101325.0f, 700.0f}; std::vector pipes; float intake_flow{}, exhaust_flow{}; float last_mix_l{}, last_mix_r{}; std::uint64_t sample_count{}; private: float intake_boundary_area_{}, throttle_area_{}, runner_area_{}, header_area_{}, tail_area_{}; std::array intake_valve_areas_{}, exhaust_valve_areas_{}; float dt_{}; BoundarySystem boundaries_; Solver solver_; OutdoorAudio audio_; MechanicalSoundProcessor mechanical_sound_; mutable std::mutex mutex_; static float area_for_diameter(float diameter); static std::vector create_pipes(FourStrokePreset preset, bool turbo_enabled); }; using FourStrokeTwinScenario = FourStrokeScenario; class TurboTwinScenario : public FourStrokeScenario { public: explicit TurboTwinScenario(int sample_rate = 44100) : FourStrokeScenario(sample_rate, FourStrokePreset::Twin, true) {} }; class SaabB205Scenario : public FourStrokeScenario { public: explicit SaabB205Scenario(int sample_rate = 44100) : FourStrokeScenario(sample_rate, FourStrokePreset::SaabB205) {} }; } // namespace fluidsim::port