all of the changes
This commit is contained in:
203
src/scenario.cpp
203
src/scenario.cpp
@@ -1,29 +1,32 @@
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include "FluidSim/Constants.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace fluidsim::port {
|
||||
|
||||
FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selected_preset, bool turbo_enabled)
|
||||
: preset(selected_preset),
|
||||
intake_plenum(selected_preset == FourStrokePreset::AmericanV8 ? 4e-3f : selected_preset == FourStrokePreset::SaabB205 ? 3e-3f : 1e-3f, 101325, 300),
|
||||
exhaust_collector(selected_preset == FourStrokePreset::AmericanV8 ? 1.5e-3f : 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)),
|
||||
FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selected_preset, ExhaustConfig exhaust, V8ExhaustConfig v8_exhaust, EngineConfig engine)
|
||||
: preset(selected_preset), exhaust_config(exhaust), v8_exhaust_config(v8_exhaust), engine_config(engine),
|
||||
intake_plenum(engine.cylinders ? .001f*engine.cylinders : selected_preset == FourStrokePreset::AmericanV8 ? 4e-3f : selected_preset == FourStrokePreset::SaabB205 ? 3e-3f : 1e-3f, 101325, 300),
|
||||
exhaust_collector(engine.cylinders ? .00025f*engine.cylinders : selected_preset == FourStrokePreset::AmericanV8 ? 1.5e-3f : selected_preset == FourStrokePreset::SaabB205 ? .6e-3f : .15e-3f, 101325, 700),
|
||||
pipes(create_pipes(selected_preset, exhaust, v8_exhaust, engine)), dt_(1.f / std::max(sample_rate, 1)),
|
||||
boundaries_(pipes), solver_(pipes, boundaries_), audio_(sample_rate, [&] {
|
||||
OutdoorAudioConfig config;
|
||||
config.dual_exhaust = selected_preset == FourStrokePreset::AmericanV8;
|
||||
return config;
|
||||
}()), mechanical_sound_(sample_rate) {
|
||||
}()) {
|
||||
const bool saab = preset == FourStrokePreset::SaabB205;
|
||||
const bool v8 = preset == FourStrokePreset::AmericanV8;
|
||||
if (v8 && turbo_enabled) throw std::invalid_argument("American V8 preset is naturally aspirated");
|
||||
const int count = cylinder_count();
|
||||
if(engine.cylinders<0 || engine.cylinders>12 || (engine.layout!=EngineLayout::Inline && engine.cylinders%2)) throw std::invalid_argument("invalid engine cylinder layout");
|
||||
starter_torque = v8 ? 180.f : saab ? 65.f : 18.f;
|
||||
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) {
|
||||
solver_.minimum_substeps = 2; // Acoustic CFL may subdivide further.
|
||||
// Rough 9-5 wagon with driver; FM55 B05 overall reductions from WIS.
|
||||
vehicle.mass = 1600 + 75;
|
||||
vehicle.primary_reduction = 1;
|
||||
@@ -57,10 +60,6 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selecte
|
||||
vehicle.drag_coefficient = .4f;
|
||||
vehicle.frontal_area = 2.f;
|
||||
ecu.idle_rpm = 750;
|
||||
ecu.throttle_time_constant = .065f;
|
||||
ecu.throttle_rate = 2.3f;
|
||||
ecu.throttle_closing_time_constant = .16f;
|
||||
ecu.throttle_closing_rate = 1.4f;
|
||||
ecu.idle_base_opening = .08f;
|
||||
ecu.idle_spark_gain = .02f;
|
||||
ecu.ignition_map = {{0, 10}, {750, 12}, {2500, 28}, {4000, 32}, {6000, 30}};
|
||||
@@ -68,9 +67,27 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selecte
|
||||
ecu.rev_resume_rpm = 6750;
|
||||
ecu.overrun_cut_rpm = 2000;
|
||||
ecu.overrun_resume_rpm = 1100;
|
||||
// One minimum substep; acoustic CFL still subdivides when needed.
|
||||
// Port-coupled fittings use one minimum substep; acoustic CFL may subdivide further.
|
||||
solver_.minimum_substeps = 1;
|
||||
}
|
||||
if(engine.cylinders) {
|
||||
solver_.minimum_substeps=1;
|
||||
const float litres=count*pi*.25f*engine.bore*engine.bore*engine.stroke*1000;
|
||||
crankshaft.omega=engine.idle_rpm*1.4f*2*pi/60;crankshaft.inertia=std::max(.04f,litres*.12f);
|
||||
crankshaft.friction_constant=litres*4;crankshaft.friction_viscous=litres*.004f;
|
||||
starter_torque=litres*25;vehicle.mass=count<=2?240:1400;vehicle.clutch_capacity=litres*220;
|
||||
ecu.idle_rpm=engine.idle_rpm;ecu.rev_limit_rpm=engine.rev_limit;ecu.rev_resume_rpm=engine.rev_limit-250;
|
||||
ecu.idle_spark_gain=.02f;ecu.idle_base_opening=.05f;
|
||||
if(engine.carbureted) {
|
||||
ecu.idle_control=Ecu::IdleControl::FixedOpening;ecu.idle_base_opening=engine.idle_opening;
|
||||
ecu.overrun_fuel_cut_enabled=false;
|
||||
carb_=std::make_unique<Carburetor>(.085f);
|
||||
const float jet_scale=engine.carb_jet_scale*std::sqrt(litres/.5f);
|
||||
carb_->pilot_jet_diameter*=jet_scale*engine.carb_pilot_scale;carb_->main_jet_diameter*=jet_scale;carb_->needle_jet_diameter*=jet_scale;
|
||||
carb_->bowl_capacity=.1f;carb_->bowl_refill_rate=.1f;
|
||||
intake_plenum.add_fuel_mass(intake_plenum.mass()/14.7f);
|
||||
}
|
||||
}
|
||||
vehicle.set_neutral();
|
||||
vehicle.clutch_input = clutch;
|
||||
const auto engines = cylinders();
|
||||
@@ -78,7 +95,7 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selecte
|
||||
const std::array<int, 8> firing_order{1, 5, 4, 2, 6, 3, 7, 8};
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto& c = *engines[i];
|
||||
c.phase = phases[i];
|
||||
c.phase = phases[i%4];
|
||||
if (v8) {
|
||||
const auto position = std::find(firing_order.begin(), firing_order.end(), i+1) - firing_order.begin();
|
||||
c.phase = std::fmod(4*pi - float(position)*pi*.5f, 4*pi);
|
||||
@@ -105,21 +122,28 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selecte
|
||||
c.intake_valve_diameter = .045f; c.exhaust_valve_diameter = .037f;
|
||||
c.intake_valve_lift = .010f; c.exhaust_valve_lift = .010f;
|
||||
}
|
||||
if(engine.cylinders) {
|
||||
c.phase=engine.custom_phases?engine.phase_degrees[i]*pi/180:std::fmod(4*pi-i*4*pi/count,4*pi);
|
||||
c.bore=engine.bore;c.stroke=engine.stroke;c.rod=engine.rod;c.compression=engine.compression;
|
||||
c.intake_valve_diameter=engine.bore*.38f;c.exhaust_valve_diameter=engine.bore*.32f;
|
||||
c.intake_valve_lift=engine.bore*.10f;c.exhaust_valve_lift=engine.bore*.09f;
|
||||
c.transported_fuel=engine.carbureted;
|
||||
}
|
||||
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 || v8) {
|
||||
if (saab || v8 || engine.cylinders) {
|
||||
// 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);
|
||||
if(engine.carbureted) {c.fuel_mass=c.air_mass/15.7f;c.air_mass-=c.fuel_mass;}
|
||||
c.update_state(0);
|
||||
}
|
||||
}
|
||||
intake_boundary_area_ = pipes.front().area;
|
||||
runner_area_ = pipes[1].area;
|
||||
header_area_ = pipes[1+count].area;
|
||||
tail_area_ = pipes[1+2*count].area;
|
||||
@@ -128,50 +152,56 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selecte
|
||||
pipe.energy_relaxation_rate = 0;
|
||||
}
|
||||
auto& throttle_port = intake_plenum.create_port();
|
||||
solver_.add_component(intake_atmosphere);
|
||||
throttle_port_=&throttle_port;
|
||||
solver_.add_component(intake_plenum);
|
||||
solver_.add_component(exhaust_collector);
|
||||
if (v8) solver_.add_component(second_bank_collector);
|
||||
if (turbo_enabled) {
|
||||
turbo = std::make_unique<Turbocharger>(saab ? TurboConfig::gt17() : TurboConfig{});
|
||||
ecu.boost_control_enabled = saab;
|
||||
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_);
|
||||
}
|
||||
if(!v8) solver_.add_component(exhaust_collector);
|
||||
boundaries_.add_orifice(throttle_port, 0, false, throttle_area_, .7f);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto& feed = intake_plenum.create_port();
|
||||
// 1--4 and 5--8 are separate physical banks for this firing order.
|
||||
auto& collector_in = (v8 && i >= 4 ? second_bank_collector : 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_);
|
||||
if (!v8) boundaries_.add_orifice(exhaust_collector.create_port(), 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);
|
||||
if (v8) {
|
||||
auto& outlet = second_bank_collector.create_port();
|
||||
boundaries_.add_orifice(outlet, 18, true, tail_area_);
|
||||
boundaries_.add_open_end(18, false, 101325, pipes[18].area);
|
||||
if(v8) {
|
||||
auto junction=[&](std::initializer_list<JunctionEnd> ends) {
|
||||
auto fitting=std::make_unique<Junction>(v8_exhaust.junction_volume,101325,700);
|
||||
fitting->connect(boundaries_,pipes,std::span(ends.begin(),ends.size()));
|
||||
solver_.add_component(*fitting);exhaust_junctions_.push_back(std::move(fitting));
|
||||
};
|
||||
// Within each bank pair cylinders with the widest available firing gaps.
|
||||
junction({{9,false},{10,false},{17,true}});
|
||||
junction({{11,false},{12,false},{18,true}});
|
||||
junction({{13,false},{15,false},{19,true}});
|
||||
junction({{14,false},{16,false},{20,true}});
|
||||
junction({{17,false},{18,false},{21,true}});
|
||||
junction({{19,false},{20,false},{22,true}});
|
||||
if(v8_exhaust.h_pipe) {
|
||||
junction({{21,false},{23,true},{25,true}});
|
||||
junction({{22,false},{24,true},{25,false}});
|
||||
} else {
|
||||
boundaries_.add_connection(21,false,23,true);
|
||||
boundaries_.add_connection(22,false,24,true);
|
||||
boundaries_.add_closed_end(25,true);boundaries_.add_closed_end(25,false);
|
||||
}
|
||||
boundaries_.add_radiating_open_end(23,false,101325,pipes[23].area);
|
||||
boundaries_.add_radiating_open_end(24,false,101325,pipes[24].area);
|
||||
} else {
|
||||
auto& collector_out = exhaust_collector.create_port();
|
||||
const int exit=1+2*count;
|
||||
boundaries_.add_orifice(collector_out,exit,true,tail_area_);
|
||||
boundaries_.add_radiating_open_end(exit,false,101325,pipes[exit].area);
|
||||
}
|
||||
boundaries_.add_radiating_open_end(0, true, 101325, pipes[0].area);
|
||||
}
|
||||
|
||||
AudioFrame FourStrokeScenario::process() {
|
||||
const std::lock_guard guard(mutex_);
|
||||
step_motorcycle(crankshaft, dt_, preset == FourStrokePreset::AmericanV8 ? 300.f : preset == FourStrokePreset::SaabB205 ? 200.f : 30.f);
|
||||
ecu.step(dt_, throttle, crankshaft.omega * 60 / (2*pi));
|
||||
if (turbo) {
|
||||
ecu.control_boost(dt_, throttle, crankshaft.omega * 60/(2*pi), intake_plenum.pressure(), turbo->compressor_outlet.pressure());
|
||||
turbo->set_wastegate_duty(ecu.wastegate_duty());
|
||||
}
|
||||
const auto engines = cylinders();
|
||||
for (int i = 0; i < cylinder_count(); ++i) {
|
||||
auto& c = *engines[i];
|
||||
@@ -182,19 +212,30 @@ AudioFrame FourStrokeScenario::process() {
|
||||
}
|
||||
const float opening = ecu.throttle_opening();
|
||||
const float angle = opening * pi * .5f;
|
||||
throttle_area_ = area_for_diameter(preset == FourStrokePreset::AmericanV8 ? .065f : preset == FourStrokePreset::SaabB205 ? .052f : .026f) * (1-std::cos(angle));
|
||||
throttle_area_ = area_for_diameter(engine_config.cylinders ? (engine_config.carbureted?.085f:.065f) : preset == FourStrokePreset::AmericanV8 ? .065f : preset == FourStrokePreset::SaabB205 ? .052f : .026f) * (1-std::cos(angle));
|
||||
if(carb_) {
|
||||
const auto inlet=pipes[0].state(int(pipes[0].cells.size())-1);
|
||||
carb_->step(dt_,throttle,opening,crankshaft.omega*60/(2*pi),std::max(throttle_port_->mass_flow,0.f),inlet.rho,inlet.pressure,intake_plenum.pressure());
|
||||
intake_plenum.add_fuel_mass(carb_->fuel_flow()*dt_);
|
||||
}
|
||||
solver_.step(dt_);
|
||||
intake_flow = intake_atmosphere.port.mass_flow;
|
||||
intake_flow = boundaries_.open_end_mass_flow(preset == FourStrokePreset::AmericanV8 ? 2 : 1);
|
||||
exhaust_flow = boundaries_.open_end_mass_flow(0);
|
||||
const float other_exhaust = preset == FourStrokePreset::AmericanV8 ? boundaries_.open_end_mass_flow(1) : 0.f;
|
||||
const auto rendered = audio_.process(intake_flow, exhaust_flow, other_exhaust);
|
||||
// Compact mouth radiation responds to volume velocity. Use ambient-equivalent
|
||||
// mass flow so hot/cold donor-density changes do not enter the derivative.
|
||||
const float intake_source = ambient_density * boundaries_.open_end_volume_flow(preset == FourStrokePreset::AmericanV8 ? 2 : 1);
|
||||
const float exhaust_source = ambient_density * boundaries_.open_end_volume_flow(0);
|
||||
const float other_source = preset == FourStrokePreset::AmericanV8 ? ambient_density * boundaries_.open_end_volume_flow(1) : 0.f;
|
||||
const auto rendered = audio_.process(intake_source, exhaust_source, other_source);
|
||||
exhaust_flow += other_exhaust;
|
||||
const float mechanical = mechanical_sound_enabled
|
||||
? 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};
|
||||
return rendered;
|
||||
}
|
||||
|
||||
void FourStrokeScenario::set_pipe_solver(PipeSolver solver) {
|
||||
const std::lock_guard guard(mutex_);
|
||||
for(auto& pipe : pipes) pipe.solver=solver;
|
||||
}
|
||||
|
||||
void FourStrokeScenario::set_audio_scene(OutdoorScene scene) {
|
||||
@@ -210,6 +251,11 @@ AudioFrame FourStrokeScenario::unfiltered_audio() const {
|
||||
const std::lock_guard<std::mutex> guard(mutex_); return audio_.unfiltered_frame();
|
||||
}
|
||||
|
||||
void FourStrokeScenario::set_starter(bool engaged) {
|
||||
const std::lock_guard guard(mutex_);
|
||||
starter_engaged=engaged;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -217,11 +263,6 @@ void FourStrokeScenario::set_controls(float throttle_value, float load_value, fl
|
||||
clutch = std::clamp(clutch_value, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void FourStrokeScenario::toggle_mechanical_sound() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
mechanical_sound_enabled = !mechanical_sound_enabled;
|
||||
}
|
||||
|
||||
void FourStrokeScenario::shift_up() {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
vehicle.shift_up();
|
||||
@@ -245,10 +286,14 @@ void FourStrokeScenario::set_first_gear() {
|
||||
ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
const std::lock_guard<std::mutex> guard(mutex_);
|
||||
ScenarioSnapshot result;
|
||||
result.turbo_enabled = bool(turbo);
|
||||
result.boost_target = ecu.boost_target();
|
||||
result.wastegate_duty = ecu.wastegate_duty();
|
||||
if (turbo) result.turbo = turbo->snapshot();
|
||||
result.layout=engine_config.cylinders?engine_config.layout:preset==FourStrokePreset::AmericanV8?EngineLayout::V:EngineLayout::Inline;
|
||||
result.bank_angle=engine_config.cylinders?engine_config.bank_angle:56;
|
||||
result.v8_headers=preset==FourStrokePreset::AmericanV8;
|
||||
result.silencers = preset == FourStrokePreset::SaabB205 && exhaust_config.enabled;
|
||||
result.exhaust_config = exhaust_config;
|
||||
result.h_pipe = preset==FourStrokePreset::AmericanV8 && v8_exhaust_config.h_pipe;
|
||||
result.crossover_pressures = preset==FourStrokePreset::AmericanV8 ? std::array<float,2>{pipes[21].state(0).pressure,pipes[22].state(0).pressure} : std::array<float,2>{};
|
||||
result.pipe_solver = pipes.front().solver;
|
||||
result.solver_substeps = solver_.substep_count();
|
||||
result.boundary_iterations = boundaries_.nonlinear_iterations;
|
||||
result.rpm = crankshaft.omega * 60.0f / (2.0f * pi);
|
||||
@@ -267,10 +312,11 @@ ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
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.exhaust_pressure = preset==FourStrokePreset::AmericanV8 ? pipes[21].state(0).pressure : exhaust_collector.pressure();
|
||||
result.second_bank_pressure = preset==FourStrokePreset::AmericanV8 ? pipes[22].state(0).pressure : 101325;
|
||||
result.throttle = ecu.throttle_opening();
|
||||
result.pedal = throttle;
|
||||
result.target_afr = ecu.target_afr();
|
||||
result.target_afr = carb_?carb_->indicated_afr():ecu.target_afr();
|
||||
result.idle_control = ecu.idle_active();
|
||||
result.fuel_cut = ecu.fuel_cut();
|
||||
result.audio_scene = audio_.scene();
|
||||
@@ -280,12 +326,12 @@ ScenarioSnapshot FourStrokeScenario::snapshot() const {
|
||||
result.gear = vehicle.current_gear;
|
||||
result.rev_limit1 = cylinder1.rev_limit_active;
|
||||
result.rev_limit2 = cylinder2.rev_limit_active;
|
||||
result.mechanical_sound_enabled = mechanical_sound_enabled;
|
||||
result.cylinder_count = cylinder_count();
|
||||
result.rev_limit_rpm = ecu.rev_limit_rpm;
|
||||
const std::array<const FourStrokeCylinder*, 8> engines{&cylinder1, &cylinder2, &cylinder3, &cylinder4,
|
||||
&cylinder5, &cylinder6, &cylinder7, &cylinder8};
|
||||
const std::array<const FourStrokeCylinder*, 12> engines{&cylinder1, &cylinder2, &cylinder3, &cylinder4,
|
||||
&cylinder5, &cylinder6, &cylinder7, &cylinder8,&cylinder9,&cylinder10,&cylinder11,&cylinder12};
|
||||
for (int i = 0; i < cylinder_count(); ++i) {
|
||||
result.cylinder_angles[i] = crankshaft.angle + engines[i]->phase;
|
||||
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];
|
||||
@@ -299,20 +345,32 @@ float FourStrokeScenario::area_for_diameter(float diameter) {
|
||||
return pi * diameter * diameter * 0.25f;
|
||||
}
|
||||
|
||||
std::vector<Pipe1D> FourStrokeScenario::create_pipes(FourStrokePreset preset, bool turbo_enabled) {
|
||||
std::vector<Pipe1D> FourStrokeScenario::create_pipes(FourStrokePreset preset, const ExhaustConfig& exhaust, const V8ExhaustConfig& v8_exhaust, const EngineConfig& engine) {
|
||||
if(engine.cylinders) {
|
||||
if(engine.cylinders<1||engine.cylinders>12||engine.bore<=0||engine.stroke<=0||engine.rod<=engine.stroke*.5f)throw std::invalid_argument("invalid custom engine dimensions");
|
||||
std::vector<Pipe1D> result;
|
||||
result.emplace_back(area_for_diameter(.075f),.20f,4);
|
||||
for(int i=0;i<engine.cylinders;++i)result.emplace_back(area_for_diameter(.035f),.25f,5);
|
||||
for(int i=0;i<engine.cylinders;++i)result.emplace_back(area_for_diameter(.038f),.65f,13);
|
||||
result.emplace_back(area_for_diameter(.060f),1.5f,30);
|
||||
return result;
|
||||
}
|
||||
const bool saab = preset == FourStrokePreset::SaabB205;
|
||||
if (preset == FourStrokePreset::AmericanV8) {
|
||||
// One inlet/throttle -> shared plenum -> short individual runners.
|
||||
// Independent exhaust banks. Cells stay long enough to avoid routine
|
||||
// Bank collectors feed twin pipes joined by a finite-length H crossover.
|
||||
// Cells stay long enough to avoid routine
|
||||
// extra CFL substeps during high-vacuum coast-down.
|
||||
std::vector<Pipe1D> result;
|
||||
result.emplace_back(area_for_diameter(.070f), .18f, 3);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
result.emplace_back(area_for_diameter(.038f), .12f, 2);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
result.emplace_back(area_for_diameter(.040f), .60f + .06f*(i%4), 12);
|
||||
result.emplace_back(area_for_diameter(.050f), 1.8f, 36);
|
||||
result.emplace_back(area_for_diameter(.050f), 1.95f, 39);
|
||||
result.emplace_back(area_for_diameter(v8_exhaust.primary_diameter),v8_exhaust.primary_length,int(std::ceil(v8_exhaust.primary_length/.05f)));
|
||||
for(int i=0;i<4;++i) result.emplace_back(area_for_diameter(.045f),.40f,8);
|
||||
for(int i=0;i<2;++i) result.emplace_back(area_for_diameter(.050f),.55f,11);
|
||||
for(int i=0;i<2;++i) result.emplace_back(area_for_diameter(.050f),1.25f,25);
|
||||
result.emplace_back(area_for_diameter(.038f),.78f,16);
|
||||
return result;
|
||||
}
|
||||
const int count = saab ? 4 : 2;
|
||||
@@ -323,11 +381,8 @@ std::vector<Pipe1D> FourStrokeScenario::create_pipes(FourStrokePreset preset, bo
|
||||
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 ? (turbo_enabled ? 8 : 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);
|
||||
}
|
||||
result.emplace_back(area_for_diameter(saab ? .060f : .028f), saab ? 1.4f : .40f, saab ? 40 : 10);
|
||||
if (saab) result.back() = make_silenced_exhaust(exhaust);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user