Add turbocharged twin scenario and cross-platform test harness
This commit is contained in:
327
src/scenario.cpp
327
src/scenario.cpp
@@ -5,168 +5,184 @@
|
||||
|
||||
namespace fluidsim::port {
|
||||
|
||||
FourStrokeTwinScenario::FourStrokeTwinScenario(int sample_rate)
|
||||
: pipes(create_pipes()),
|
||||
dt_(1.0f / static_cast<float>(std::max(sample_rate, 1))),
|
||||
boundaries_(pipes), solver_(pipes, boundaries_),
|
||||
intake_radiation_(sample_rate), exhaust_radiation_(sample_rate),
|
||||
reverb_(sample_rate), mechanical_sound_(sample_rate) {
|
||||
crankshaft.omega = 2000.0f * 2.0f * pi / 60.0f;
|
||||
crankshaft.inertia = 0.04f;
|
||||
crankshaft.friction_constant = 5.0f;
|
||||
crankshaft.friction_viscous = 0.003f;
|
||||
|
||||
FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selected_preset, bool turbo_enabled)
|
||||
: preset(selected_preset),
|
||||
intake_plenum(selected_preset == FourStrokePreset::SaabB205 ? 3e-3f : 1e-3f, 101325, 300),
|
||||
exhaust_collector(selected_preset == FourStrokePreset::SaabB205 ? .6e-3f : .15e-3f, 101325, 700),
|
||||
pipes(create_pipes(selected_preset, turbo_enabled)), dt_(1.f / std::max(sample_rate, 1)),
|
||||
boundaries_(pipes), solver_(pipes, boundaries_), audio_(sample_rate), mechanical_sound_(sample_rate) {
|
||||
const bool saab = preset == FourStrokePreset::SaabB205;
|
||||
const int count = cylinder_count();
|
||||
crankshaft.omega = (saab ? 1200 : 2000) * 2 * pi / 60;
|
||||
crankshaft.inertia = saab ? .18f : .04f;
|
||||
crankshaft.friction_constant = saab ? 12.f : 5.f;
|
||||
crankshaft.friction_viscous = saab ? .012f : .003f;
|
||||
if (saab) {
|
||||
// Rough 9-5 wagon with driver; FM55 B05 overall reductions from WIS.
|
||||
vehicle.mass = 1600 + 75;
|
||||
vehicle.primary_reduction = 1;
|
||||
vehicle.final_drive_ratio = 4.05f;
|
||||
vehicle.gear_ratios = {13.70f/4.05f, 7.12f/4.05f, 4.77f/4.05f, 3.62f/4.05f, 2.67f/4.05f};
|
||||
vehicle.wheel_radius = .317f;
|
||||
vehicle.rotational_inertia = 3.6f;
|
||||
vehicle.drag_coefficient = .32f;
|
||||
vehicle.frontal_area = 2.2f;
|
||||
vehicle.clutch_capacity = 300;
|
||||
ecu.idle_rpm = 850;
|
||||
ecu.idle_spark_gain = .025f;
|
||||
ecu.idle_minimum_advance = -10;
|
||||
ecu.rev_limit_rpm = 6500;
|
||||
ecu.rev_resume_rpm = 6250;
|
||||
ecu.overrun_cut_rpm = 2000;
|
||||
ecu.overrun_resume_rpm = 1300;
|
||||
}
|
||||
vehicle.set_neutral();
|
||||
vehicle.clutch_input = clutch;
|
||||
|
||||
cylinder1.intake_valve_diameter = 0.030f;
|
||||
cylinder1.intake_valve_lift = 0.0080f;
|
||||
cylinder1.exhaust_valve_diameter = 0.026f;
|
||||
cylinder1.exhaust_valve_lift = 0.0075f;
|
||||
cylinder2.phase = pi;
|
||||
cylinder2.intake_valve_diameter = 0.030f;
|
||||
cylinder2.intake_valve_lift = 0.0080f;
|
||||
cylinder2.exhaust_valve_diameter = 0.026f;
|
||||
cylinder2.exhaust_valve_lift = 0.0075f;
|
||||
cylinder1.rev_limit_enabled = cylinder2.rev_limit_enabled = true;
|
||||
cylinder1.rev_limit_rpm = cylinder2.rev_limit_rpm = 10000.0f;
|
||||
cylinder1.rev_limit_cut_time = cylinder2.rev_limit_cut_time = 0.020f;
|
||||
cylinder1.rev_limit_hysteresis = cylinder2.rev_limit_hysteresis = 250.0f;
|
||||
cylinder1.initialize(crankshaft);
|
||||
cylinder2.initialize(crankshaft);
|
||||
|
||||
const float intake_area = area_for_diameter(0.0275f);
|
||||
const float exhaust_area = area_for_diameter(0.028f);
|
||||
runner_area_ = intake_area;
|
||||
header_area_ = tail_area_ = exhaust_area;
|
||||
for (auto& pipe : pipes) {
|
||||
pipe.damping_multiplier = 1.0f;
|
||||
pipe.energy_relaxation_rate = 0.5f;
|
||||
pipe.ambient_pressure = 101325.0f;
|
||||
const auto engines = cylinders();
|
||||
const std::array<float, 4> phases{0, pi, 3*pi, 2*pi}; // I4 firing: 1-3-4-2
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto& c = *engines[i];
|
||||
c.phase = phases[i];
|
||||
if (saab) {
|
||||
c.bore = .090f;
|
||||
c.stroke = .078f;
|
||||
c.rod = .153f; // estimated, not a verified B205 rod measurement
|
||||
c.compression = 8.8f;
|
||||
c.intake_valve_count = c.exhaust_valve_count = 2;
|
||||
}
|
||||
c.intake_valve_diameter = saab ? .032f : .030f;
|
||||
c.intake_valve_lift = saab ? .0085f : .008f;
|
||||
c.exhaust_valve_diameter = saab ? .028f : .026f;
|
||||
c.exhaust_valve_lift = saab ? .008f : .0075f;
|
||||
c.rev_limit_enabled = true;
|
||||
c.rev_limit_rpm = ecu.rev_limit_rpm;
|
||||
c.rev_limit_hysteresis = 250;
|
||||
c.rev_limit_cut_time = .020f;
|
||||
c.ecu = &ecu;
|
||||
c.initialize(crankshaft);
|
||||
if (saab) {
|
||||
// Initialize each phased cylinder at its actual piston position.
|
||||
c.volume = c.compute_volume(c.phase);
|
||||
c.air_mass = ambient_density * c.volume;
|
||||
c.energy = 101325 * c.volume / (gamma - 1);
|
||||
c.update_state(0);
|
||||
}
|
||||
}
|
||||
|
||||
throttle_port_ = &intake_plenum.create_port();
|
||||
runner_feed1_ = &intake_plenum.create_port();
|
||||
runner_feed2_ = &intake_plenum.create_port();
|
||||
collector_in1_ = &exhaust_collector.create_port();
|
||||
collector_in2_ = &exhaust_collector.create_port();
|
||||
collector_out_ = &exhaust_collector.create_port();
|
||||
|
||||
intake_radiation_.pipe_end = {-0.20f, 0.0f, 0.0f};
|
||||
intake_radiation_.pipe_axis = {-1.0f, 0.0f, 0.0f};
|
||||
intake_radiation_.gain = 30.0f;
|
||||
intake_radiation_.directivity_balance = 0.30f;
|
||||
intake_radiation_.flow_tau = 0.005f;
|
||||
intake_radiation_.smooth_tau = 0.020f;
|
||||
exhaust_radiation_.pipe_end = {0.55f, 0.0f, 0.0f};
|
||||
exhaust_radiation_.pipe_axis = {1.0f, 0.0f, 0.0f};
|
||||
exhaust_radiation_.gain = 25.0f;
|
||||
exhaust_radiation_.directivity_balance = 0.30f;
|
||||
exhaust_radiation_.flow_tau = 0.005f;
|
||||
exhaust_radiation_.smooth_tau = 0.020f;
|
||||
|
||||
reverb_.dry_mix = 0.0f;
|
||||
reverb_.early_mix = 0.30f;
|
||||
reverb_.tail_mix = 0.22f;
|
||||
reverb_.transient_feedback_boost = 0.40f;
|
||||
reverb_.transient_hf_boost = 3.5f;
|
||||
reverb_.saturation_drive = 1.5f;
|
||||
|
||||
solver_.add_component(cylinder1);
|
||||
solver_.add_component(cylinder2);
|
||||
intake_boundary_area_ = pipes.front().area;
|
||||
runner_area_ = pipes[1].area;
|
||||
header_area_ = pipes[1+count].area;
|
||||
tail_area_ = pipes[1+2*count].area;
|
||||
for (auto& pipe : pipes) {
|
||||
pipe.damping_multiplier = saab ? 0.f : 1.f;
|
||||
pipe.energy_relaxation_rate = 0;
|
||||
}
|
||||
auto& throttle_port = intake_plenum.create_port();
|
||||
solver_.add_component(intake_atmosphere);
|
||||
solver_.add_component(intake_plenum);
|
||||
solver_.add_component(exhaust_collector);
|
||||
|
||||
boundaries_.add_open_end(0, true, 101325.0f, intake_area);
|
||||
boundaries_.add_open_end(5, false, 101325.0f, exhaust_area);
|
||||
boundaries_.add_orifice(*throttle_port_, 0, false, throttle_area_, 0.7f);
|
||||
boundaries_.add_orifice(*runner_feed1_, 1, true, runner_area_);
|
||||
boundaries_.add_orifice(*runner_feed2_, 2, true, runner_area_);
|
||||
boundaries_.add_orifice(cylinder1.intake, 1, false, valve1_in_);
|
||||
boundaries_.add_orifice(cylinder2.intake, 2, false, valve2_in_);
|
||||
boundaries_.add_orifice(cylinder1.exhaust, 3, true, valve1_out_);
|
||||
boundaries_.add_orifice(cylinder2.exhaust, 4, true, valve2_out_);
|
||||
boundaries_.add_orifice(*collector_in1_, 3, false, header_area_);
|
||||
boundaries_.add_orifice(*collector_in2_, 4, false, header_area_);
|
||||
boundaries_.add_orifice(*collector_out_, 5, true, tail_area_);
|
||||
if (turbo_enabled) {
|
||||
turbo = std::make_unique<Turbocharger>();
|
||||
const int fresh = 2+2*count, exhaust_exit = fresh+1;
|
||||
boundaries_.add_orifice(intake_atmosphere.port, fresh, true, intake_boundary_area_);
|
||||
turbo->connect(boundaries_, pipes, fresh, false, 0, true, 1+2*count, false, exhaust_exit, true);
|
||||
solver_.add_component(*turbo);
|
||||
} else {
|
||||
boundaries_.add_orifice(intake_atmosphere.port, 0, true, intake_boundary_area_);
|
||||
}
|
||||
boundaries_.add_orifice(throttle_port, 0, false, throttle_area_, .7f);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto& feed = intake_plenum.create_port();
|
||||
auto& collector_in = exhaust_collector.create_port();
|
||||
solver_.add_component(*engines[i]);
|
||||
boundaries_.add_orifice(feed, 1+i, true, runner_area_);
|
||||
boundaries_.add_orifice(engines[i]->intake, 1+i, false, intake_valve_areas_[i]);
|
||||
boundaries_.add_orifice(engines[i]->exhaust, 1+count+i, true, exhaust_valve_areas_[i]);
|
||||
boundaries_.add_orifice(collector_in, 1+count+i, false, header_area_);
|
||||
}
|
||||
auto& collector_out = exhaust_collector.create_port();
|
||||
boundaries_.add_orifice(collector_out, 1+2*count, true, tail_area_);
|
||||
const int exhaust_exit = turbo_enabled ? 3+2*count : 1+2*count;
|
||||
boundaries_.add_open_end(exhaust_exit, false, 101325, pipes[exhaust_exit].area);
|
||||
}
|
||||
|
||||
AudioFrame FourStrokeTwinScenario::process() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
crankshaft.load_torque = std::clamp(load, 0.0f, 1.0f) * 30.0f;
|
||||
vehicle.clutch_input = std::clamp(clutch, 0.0f, 1.0f);
|
||||
crankshaft.step(dt_);
|
||||
crankshaft.drivetrain_torque = vehicle.update(crankshaft.omega, crankshaft.inertia, dt_);
|
||||
cylinder1.pre_step(crankshaft, dt_, throttle);
|
||||
cylinder2.pre_step(crankshaft, dt_, throttle);
|
||||
|
||||
const float throttle_fraction = std::clamp(throttle, 0.0f, 1.0f);
|
||||
throttle_area_ = throttle_fraction <= 0.001f ? 0.0f : area_for_diameter(0.026f) * throttle_fraction;
|
||||
const auto cycle_degrees = [this](float phase) {
|
||||
float value = std::fmod((crankshaft.angle + phase) * 180.0f / pi, 720.0f);
|
||||
return value < 0.0f ? value + 720.0f : value;
|
||||
};
|
||||
valve1_in_ = cylinder1.valve_area(cycle_degrees(cylinder1.phase), true);
|
||||
valve2_in_ = cylinder2.valve_area(cycle_degrees(cylinder2.phase), true);
|
||||
valve1_out_ = cylinder1.valve_area(cycle_degrees(cylinder1.phase), false);
|
||||
valve2_out_ = cylinder2.valve_area(cycle_degrees(cylinder2.phase), false);
|
||||
|
||||
AudioFrame FourStrokeScenario::process() {
|
||||
const std::lock_guard guard(mutex_);
|
||||
step_motorcycle(crankshaft, dt_, preset == FourStrokePreset::SaabB205 ? 200.f : 30.f);
|
||||
ecu.step(dt_, throttle, crankshaft.omega * 60 / (2*pi));
|
||||
const auto engines = cylinders();
|
||||
for (int i = 0; i < cylinder_count(); ++i) {
|
||||
auto& c = *engines[i];
|
||||
c.pre_step(crankshaft, dt_, throttle);
|
||||
const float degrees = std::fmod((crankshaft.angle+c.phase)*180/pi, 720.f);
|
||||
intake_valve_areas_[i] = c.valve_area(degrees, true);
|
||||
exhaust_valve_areas_[i] = c.valve_area(degrees, false);
|
||||
}
|
||||
const float angle = ecu.throttle_opening() * pi * .5f;
|
||||
throttle_area_ = area_for_diameter(preset == FourStrokePreset::SaabB205 ? .052f : .026f) * (1-std::cos(angle));
|
||||
solver_.step(dt_);
|
||||
intake_flow = boundaries_.open_end_mass_flow(0);
|
||||
exhaust_flow = boundaries_.open_end_mass_flow(1);
|
||||
const AudioFrame intake_audio = intake_radiation_.process(intake_flow);
|
||||
const AudioFrame exhaust_audio = exhaust_radiation_.process(exhaust_flow);
|
||||
intake_flow = intake_atmosphere.port.mass_flow;
|
||||
exhaust_flow = boundaries_.open_end_mass_flow(0);
|
||||
const auto rendered = audio_.process(intake_flow, exhaust_flow);
|
||||
const float mechanical = mechanical_sound_enabled
|
||||
? mechanical_sound_.process(crankshaft, cylinder1, load) * mechanical_mix : 0.0f;
|
||||
const float reverb_input = intake_radiation_.last_mono_pressure() * intake_send +
|
||||
exhaust_radiation_.last_mono_pressure() * exhaust_send +
|
||||
mechanical * mechanical_send;
|
||||
const AudioFrame wet = reverb_.process_stereo(reverb_input);
|
||||
const float flow_left = std::tanh(intake_audio.left + exhaust_audio.left + wet.left * reverb_send_gain);
|
||||
const float flow_right = std::tanh(intake_audio.right + exhaust_audio.right + wet.right * reverb_send_gain);
|
||||
last_mix_l = std::isfinite(flow_left + mechanical)
|
||||
? std::clamp(flow_left + mechanical, -1.0f, 1.0f) : 0.0f;
|
||||
last_mix_r = std::isfinite(flow_right + mechanical)
|
||||
? std::clamp(flow_right + mechanical, -1.0f, 1.0f) : 0.0f;
|
||||
? mechanical_sound_.process(crankshaft, cylinder1, load) * mechanical_mix : 0;
|
||||
last_mix_l = rendered.left + mechanical;
|
||||
last_mix_r = rendered.right + mechanical;
|
||||
++sample_count;
|
||||
return {last_mix_l, last_mix_r};
|
||||
}
|
||||
|
||||
void FourStrokeTwinScenario::set_controls(float throttle_value, float load_value, float clutch_value) {
|
||||
void FourStrokeScenario::set_audio_scene(OutdoorScene scene) {
|
||||
const std::lock_guard<std::mutex> guard(mutex_); audio_.set_scene(scene);
|
||||
}
|
||||
void FourStrokeScenario::set_monitor_filter(bool enabled) {
|
||||
const std::lock_guard<std::mutex> guard(mutex_); audio_.set_monitor_filter(enabled);
|
||||
}
|
||||
AudioFrame FourStrokeScenario::dry_audio() const {
|
||||
const std::lock_guard<std::mutex> guard(mutex_); return audio_.dry_frame();
|
||||
}
|
||||
AudioFrame FourStrokeScenario::unfiltered_audio() const {
|
||||
const std::lock_guard<std::mutex> guard(mutex_); return audio_.unfiltered_frame();
|
||||
}
|
||||
|
||||
void FourStrokeScenario::set_controls(float throttle_value, float load_value, float clutch_value) {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
throttle = std::clamp(throttle_value, 0.0f, 1.0f);
|
||||
load = std::clamp(load_value, 0.0f, 1.0f);
|
||||
clutch = std::clamp(clutch_value, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void FourStrokeTwinScenario::toggle_mechanical_sound() {
|
||||
void FourStrokeScenario::toggle_mechanical_sound() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
mechanical_sound_enabled = !mechanical_sound_enabled;
|
||||
}
|
||||
|
||||
void FourStrokeTwinScenario::shift_up() {
|
||||
void FourStrokeScenario::shift_up() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
vehicle.shift_up();
|
||||
}
|
||||
|
||||
void FourStrokeTwinScenario::shift_down() {
|
||||
void FourStrokeScenario::shift_down() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
vehicle.shift_down();
|
||||
}
|
||||
|
||||
void FourStrokeTwinScenario::set_neutral() {
|
||||
void FourStrokeScenario::set_neutral() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
vehicle.set_neutral();
|
||||
}
|
||||
|
||||
void FourStrokeTwinScenario::set_first_gear() {
|
||||
void FourStrokeScenario::set_first_gear() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
vehicle.set_first_gear();
|
||||
}
|
||||
|
||||
ScenarioSnapshot FourStrokeTwinScenario::snapshot() const {
|
||||
ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
ScenarioSnapshot result;
|
||||
result.turbo_enabled = bool(turbo);
|
||||
if (turbo) result.turbo = turbo->snapshot();
|
||||
result.solver_substeps = solver_.substep_count();
|
||||
result.boundary_iterations = boundaries_.nonlinear_iterations;
|
||||
result.rpm = crankshaft.omega * 60.0f / (2.0f * pi);
|
||||
result.speed_kmh = vehicle.speed * 3.6f;
|
||||
result.kinetic_energy = vehicle.kinetic_energy();
|
||||
@@ -178,13 +194,18 @@ ScenarioSnapshot FourStrokeTwinScenario::snapshot() const {
|
||||
result.cylinder_temperature2 = cylinder2.temperature();
|
||||
result.cylinder_piston_fraction1 = (cylinder1.volume - cylinder1.clearance_volume()) / cylinder1.swept_volume();
|
||||
result.cylinder_piston_fraction2 = (cylinder2.volume - cylinder2.clearance_volume()) / cylinder2.swept_volume();
|
||||
result.valve1_intake_area = valve1_in_;
|
||||
result.valve1_exhaust_area = valve1_out_;
|
||||
result.valve2_intake_area = valve2_in_;
|
||||
result.valve2_exhaust_area = valve2_out_;
|
||||
result.valve1_intake_area = intake_valve_areas_[0];
|
||||
result.valve1_exhaust_area = exhaust_valve_areas_[0];
|
||||
result.valve2_intake_area = intake_valve_areas_[1];
|
||||
result.valve2_exhaust_area = exhaust_valve_areas_[1];
|
||||
result.intake_pressure = intake_plenum.pressure();
|
||||
result.exhaust_pressure = exhaust_collector.pressure();
|
||||
result.throttle = throttle;
|
||||
result.throttle = ecu.throttle_opening();
|
||||
result.pedal = throttle;
|
||||
result.target_afr = ecu.target_afr();
|
||||
result.idle_control = ecu.idle_active();
|
||||
result.fuel_cut = ecu.fuel_cut();
|
||||
result.audio_scene = audio_.scene();
|
||||
result.clutch = clutch;
|
||||
result.intake_flow = intake_flow;
|
||||
result.exhaust_flow = exhaust_flow;
|
||||
@@ -192,31 +213,39 @@ ScenarioSnapshot FourStrokeTwinScenario::snapshot() const {
|
||||
result.rev_limit1 = cylinder1.rev_limit_active;
|
||||
result.rev_limit2 = cylinder2.rev_limit_active;
|
||||
result.mechanical_sound_enabled = mechanical_sound_enabled;
|
||||
for (std::size_t pipe_index = 0; pipe_index < pipes.size(); ++pipe_index) {
|
||||
auto& states = result.pipe_states[pipe_index];
|
||||
states.reserve(pipes[pipe_index].cells.size());
|
||||
for (std::size_t cell = 0; cell < pipes[pipe_index].cells.size(); ++cell)
|
||||
states.push_back(pipes[pipe_index].state(static_cast<int>(cell)));
|
||||
result.cylinder_count = cylinder_count();
|
||||
result.rev_limit_rpm = ecu.rev_limit_rpm;
|
||||
const std::array<const FourStrokeCylinder*, 4> engines{&cylinder1, &cylinder2, &cylinder3, &cylinder4};
|
||||
for (int i = 0; i < cylinder_count(); ++i) {
|
||||
result.cylinder_pressures[i] = engines[i]->pressure;
|
||||
result.piston_fractions[i] = (engines[i]->volume-engines[i]->clearance_volume())/engines[i]->swept_volume();
|
||||
result.intake_areas[i] = intake_valve_areas_[i];
|
||||
result.exhaust_areas[i] = exhaust_valve_areas_[i];
|
||||
}
|
||||
result.capture_pipes(pipes);
|
||||
return result;
|
||||
}
|
||||
|
||||
float FourStrokeScenario::area_for_diameter(float diameter) {
|
||||
return pi * diameter * diameter * 0.25f;
|
||||
}
|
||||
|
||||
std::vector<Pipe1D> FourStrokeScenario::create_pipes(FourStrokePreset preset, bool turbo_enabled) {
|
||||
const bool saab = preset == FourStrokePreset::SaabB205;
|
||||
const int count = saab ? 4 : 2;
|
||||
std::vector<Pipe1D> result;
|
||||
result.reserve(4+2*count);
|
||||
result.emplace_back(area_for_diameter(saab ? .060f : .0275f), saab ? .15f : .06f, saab ? 8 : 10);
|
||||
for (int i = 0; i < count; ++i)
|
||||
result.emplace_back(area_for_diameter(saab ? .032f : .0275f), saab ? .25f : .12f, 10);
|
||||
for (int i = 0; i < count; ++i)
|
||||
result.emplace_back(area_for_diameter(saab ? .034f : .028f), saab ? .28f : .20f, saab ? 10 : 6);
|
||||
result.emplace_back(area_for_diameter(saab ? .060f : .028f), turbo_enabled ? .12f : (saab ? 1.4f : .40f), saab ? 40 : 10);
|
||||
if (turbo_enabled) {
|
||||
result.emplace_back(area_for_diameter(saab ? .060f : .0275f), .10f, 8);
|
||||
result.emplace_back(area_for_diameter(saab ? .060f : .032f), .60f, 24);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float FourStrokeTwinScenario::area_for_diameter(float diameter) {
|
||||
return pi * diameter * diameter * 0.25f;
|
||||
}
|
||||
|
||||
std::vector<Pipe1D> FourStrokeTwinScenario::create_pipes() {
|
||||
const float intake_area = area_for_diameter(0.0275f);
|
||||
const float exhaust_area = area_for_diameter(0.028f);
|
||||
std::vector<Pipe1D> result;
|
||||
result.reserve(6);
|
||||
result.emplace_back(intake_area, 0.06f, 10);
|
||||
result.emplace_back(intake_area, 0.12f, 10);
|
||||
result.emplace_back(intake_area, 0.12f, 10);
|
||||
result.emplace_back(exhaust_area, 0.20f, 6);
|
||||
result.emplace_back(exhaust_area, 0.20f, 6);
|
||||
result.emplace_back(exhaust_area, 0.40f, 10);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fluidsim::port
|
||||
|
||||
Reference in New Issue
Block a user