#pragma once #include "FluidSim/PipeProfile.hpp" namespace fluidsim::port { enum class SilencerType { StraightThrough, ExpansionResonator, Chambered }; struct SilencerConfig { SilencerType type{SilencerType::Chambered}; float volume{.018f}, length{.65f}, core_diameter{.055f}; int chambers{2}; float passage_diameter{.058f}; float resistance{2.f}; // linear momentum decay, 1/s (packing surrogate) float loss_coefficient{.35f}; // total dimensionless quadratic flow resistance float diameter() const { return std::sqrt(4*volume/(pi*length)); } }; struct ExhaustConfig { bool enabled{true}; float inlet_length{1.4f}, outlet_length{.35f}, connecting_length{.8f}, diameter{.060f}, cell_length{.035f}; SilencerConfig resonator{SilencerType::StraightThrough,.006f,.40f,.060f,1,.060f,2, .1f}; SilencerConfig muffler{SilencerType::StraightThrough,.018f,.65f,.060f,1,.060f,4, .35f}; }; inline Pipe1D make_silenced_exhaust(const ExhaustConfig& c) { std::vector sections; std::vector linear, quadratic; auto add=[&](float length,float a,float b,float r=0,float k=0) { if(!std::isfinite(length)||length<=0||!std::isfinite(r)||r<0||!std::isfinite(k)||k<0) throw std::invalid_argument("invalid silencer resistance or length"); sections.push_back({length,a,b}); linear.push_back(r); quadratic.push_back(k/length); }; add(c.inlet_length,c.diameter,c.diameter); if(c.enabled) for(int index=0;index<2;++index) { if(index) add(c.connecting_length,c.diameter,c.diameter); const auto& s=index?c.muffler:c.resonator; if(!std::isfinite(s.volume)||s.volume<=0||!std::isfinite(s.length)||s.length<=0||s.chambers<1||s.chambers>16 || s.core_diameter<=0 || s.passage_diameter<=0) throw std::invalid_argument("invalid silencer geometry"); const float d=s.type==SilencerType::StraightThrough?s.core_diameter:s.diameter(); const int n=s.type==SilencerType::Chambered?s.chambers:1; float previous=c.diameter; for(int i=0;i