Add turbocharged twin scenario and cross-platform test harness
This commit is contained in:
87
tests/two_stroke_regression.cpp
Normal file
87
tests/two_stroke_regression.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "FluidSim/TwoStrokeScenario.hpp"
|
||||
#include "FluidSim/DynoCurve.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace fluidsim::port;
|
||||
|
||||
int main() {
|
||||
TwoStrokeScenario scenario;
|
||||
bool reed_open_seen = false, reed_closed_seen = false, above_old_limit = false;
|
||||
DynoCurve dyno;
|
||||
float peak = 0, maximum_rpm = 0;
|
||||
for (int sample = 0; sample < 14 * 44100; ++sample) {
|
||||
scenario.set_throttle(sample >= 2 * 44100 && sample < 6 * 44100 ? .6f : 0.f);
|
||||
const auto audio = scenario.process();
|
||||
if (!std::isfinite(audio.left) || !std::isfinite(audio.right))
|
||||
throw std::runtime_error("Nonfinite two-stroke audio");
|
||||
peak = std::max({peak, std::abs(audio.left), std::abs(audio.right)});
|
||||
if (sample % 44 != 0)
|
||||
continue;
|
||||
const auto state = scenario.snapshot();
|
||||
if (!std::isfinite(state.rpm) || !(state.cylinder_pressure > 0) ||
|
||||
!(state.crankcase_pressure > 0) || !(state.intake_pressure > 0))
|
||||
throw std::runtime_error("Invalid two-stroke physical state");
|
||||
if (scenario.ecu.rev_limited() || scenario.cylinder.rev_limit_active)
|
||||
throw std::runtime_error("Two-stroke rev limiter is active");
|
||||
if (sample >= 2 * 44100 && sample < 6 * 44100) {
|
||||
if (state.fuel_cut)
|
||||
throw std::runtime_error("Two-stroke cut fuel with the pedal open");
|
||||
above_old_limit |= state.rpm > 10200;
|
||||
}
|
||||
dyno.update(state.rpm, scenario.crankshaft.average_power / 1000,
|
||||
scenario.crankshaft.average_torque);
|
||||
reed_open_seen |= state.reed_open;
|
||||
reed_closed_seen |= !state.reed_open;
|
||||
maximum_rpm = std::max(maximum_rpm, state.rpm);
|
||||
}
|
||||
const auto final = scenario.snapshot();
|
||||
if (!above_old_limit)
|
||||
throw std::runtime_error("Two-stroke did not exceed the old rev limit");
|
||||
if (!reed_open_seen || !reed_closed_seen)
|
||||
throw std::runtime_error("Reed did not open and close");
|
||||
if (final.rpm < 2000 || final.rpm > 4000)
|
||||
throw std::runtime_error("Two-stroke idle did not recover after throttle release");
|
||||
if (peak >= 1)
|
||||
throw std::runtime_error("Two-stroke audio exceeds device range");
|
||||
for (const auto &pipe : scenario.pipes)
|
||||
if (pipe.positivity_repairs != 0)
|
||||
throw std::runtime_error("Two-stroke required pipe positivity repairs");
|
||||
// Launch the same motorcycle used by the twin, then exercise gear controls.
|
||||
scenario.shift_up();
|
||||
scenario.set_controls(.7f, 0, 0);
|
||||
for (int sample = 0; sample < 6 * 44100; ++sample) {
|
||||
const auto audio = scenario.process();
|
||||
if (!std::isfinite(audio.left) || !std::isfinite(audio.right))
|
||||
throw std::runtime_error("Nonfinite motorcycle launch audio");
|
||||
if (scenario.ecu.rev_limited())
|
||||
throw std::runtime_error("Limiter re-enabled under motorcycle load");
|
||||
}
|
||||
if (scenario.vehicle.current_gear != 1 || scenario.vehicle.speed < 1 ||
|
||||
!std::isfinite(scenario.vehicle.kinetic_energy()) || scenario.vehicle.engagement < .9f)
|
||||
throw std::runtime_error("Two-stroke motorcycle did not launch with clutch engaged");
|
||||
scenario.shift_up();
|
||||
if (scenario.vehicle.current_gear != 2)
|
||||
throw std::runtime_error("Two-stroke did not shift up");
|
||||
scenario.shift_down();
|
||||
if (scenario.vehicle.current_gear != 1)
|
||||
throw std::runtime_error("Two-stroke did not shift down");
|
||||
scenario.set_neutral();
|
||||
if (scenario.vehicle.current_gear != 0)
|
||||
throw std::runtime_error("Two-stroke neutral selection failed");
|
||||
bool positive_power = false, positive_torque = false;
|
||||
for (const auto& point : dyno.bins()) {
|
||||
positive_power |= point.power_kw > 0;
|
||||
positive_torque |= point.torque_nm > 0;
|
||||
}
|
||||
if (!positive_power || !positive_torque)
|
||||
throw std::runtime_error("Two-stroke dyno did not record power and torque");
|
||||
for (const auto& pipe : scenario.pipes)
|
||||
if (pipe.positivity_repairs != 0)
|
||||
throw std::runtime_error("Motorcycle launch required pipe positivity repairs");
|
||||
std::cout << "Two-stroke regression passed: peak=" << peak << ", maximum RPM=" << maximum_rpm
|
||||
<< ", recovered RPM=" << final.rpm << ", bike speed=" << scenario.vehicle.speed * 3.6f
|
||||
<< " km/h\n";
|
||||
}
|
||||
Reference in New Issue
Block a user