#include "FluidSim/Machine.hpp" #include #include #include #include #include using namespace fluidsim::port; namespace { void check(bool condition,const char* why){if(!condition)throw std::runtime_error(why);} bool close(double a,double b){return std::abs(a-b)<=1e-8*std::max({1e-12,std::abs(a),std::abs(b)});} templatevoid rejects(F action,const char* why){bool rejected=false;try{action();}catch(const std::exception&){rejected=true;}check(rejected,why);} SensorEcuMeasurements measurements(double pressure=100000,double temperature=300,double rpm=3000){ SensorEcuMeasurements m;m.speed=SignalValue::number(rpm*2*double(pi)/60);m.angle=SignalValue::number(.125);m.speed.timing=m.angle.timing=SignalTiming{1,1,0,.125,std::get(m.speed.value)};m.map=SignalValue::number(pressure);m.iat=SignalValue::number(temperature);return m; } SensorEcuState estimate(SensorEcuConfig config,SensorEcuMeasurements m){SensorEcu ecu(std::move(config));return ecu.sample(m,0);} } int main(int argc,char** argv)try{ if(argc==3&&std::string(argv[1])=="--write-example"){save_machine(machine_speed_density_example(),argv[2]);return 0;} for(int i=0;i0;fire|=p.combustion;}} check(fuel&&fire,"Wired speed-density example failed actual fuel transport/combustion"); auto missing=doc;missing.logic.disconnect({connector,"iat"});rejects([&]{MachineSimulation invalid(missing);},"Unwired required IAT was silently defaulted"); auto gauge_doc=doc;gauge_doc.logic.find(pressure)->sensor_kind=MachineSensorKind::DifferentialPressure;check(!logic_connection_preview(gauge_doc.logic,{pressure,"value"},{connector,"map"}).allowed,"Differential-pressure source accepted as MAP"); auto calibrated=doc;calibrated.find(ecu)->sensor_ecu.displacement*=2;rejects([&]{sim.apply_tuning(calibrated);},"Displacement changed during Test without Build"); const auto path=std::filesystem::temp_directory_path()/("fluidsim-sd-"+std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())+".machine.toml");save_machine(doc,path);const auto loaded=load_machine(path);std::filesystem::remove(path); check(loaded.logic==doc.logic&&loaded.find(ecu)->sensor_ecu==doc.find(ecu)->sensor_ecu&&loaded.find(host)->injector==doc.find(host)->injector,"Speed-density calibration, schema or injector failed save/load"); std::vector ids;for(const auto& p:doc.parts)ids.push_back(p.id);const auto assembly=machine_extract_assembly(doc,ids,"Speed-density engine");MachineDocument pasted;machine_insert_assembly(pasted,assembly,{});MachineSimulation copied(pasted,22050);copied.process(); auto routed=doc;const auto manual=routed.logic.add(LogicNodeKind::Switch).id,zero=routed.logic.add(LogicNodeKind::NumberConstant).id,select=routed.logic.add(LogicNodeKind::Select).id;routed.logic.find(zero)->quantity=routed.logic.find(select)->quantity=SignalQuantity::Pressure;routed.logic.find(zero)->pressure_reference=routed.logic.find(select)->pressure_reference=PressureReference::Absolute; routed.logic.disconnect({connector,"map"});routed.logic.connect({pressure,"value"},{select,"a"});routed.logic.connect({zero,"out"},{select,"b"});routed.logic.connect({manual,"out"},{select,"select"});routed.logic.connect({select,"out"},{connector,"map"}); MachineSimulation switched(routed,22050);for(int i=0;i<10000;++i)switched.process();switched.set_logic_control(manual,true);for(int i=0;i<1000;++i)switched.process();for(const auto& p:switched.snapshot().parts){if(p.id==ecu)check(p.sensor_fault&&p.ignition_cut,"Invalid MAP failed to cut ECU outputs");if(p.id==host)check(p.fuel_flow==0,"Invalid MAP retained injector delivery");if(p.id==cylinder)check(!p.combustion,"Invalid MAP retained controlled combustion");} switched.set_logic_control(manual,false);bool recovered=false;for(int i=0;i<10000;++i){switched.process();if(i%16==0)for(const auto& p:switched.snapshot().parts)if(p.id==cylinder)recovered|=p.combustion;}check(recovered,"Restored MAP failed to recover physical combustion"); auto no_host=doc;no_host.find_sensor(no_host.logic.find(temperature)->sensor)->target.part=0;MachineSimulation absent(no_host,22050);absent.process();for(const auto& p:absent.snapshot().parts)if(p.id==host)check(p.injector_delivered==0,"Missing IAT host used hidden gas temperature"); std::cout<<"Speed-density ideal-gas/VE calibration, MAP/IAT typing, live faults, combustion and persistence passed\n";return 0; }catch(const std::exception& error){std::cerr<