diff --git a/firmware/config/boards/hellen/cypress/config/controllers/algo/auto_generated_enums.cpp b/firmware/config/boards/hellen/cypress/config/controllers/algo/auto_generated_enums.cpp index 0c345a1101..8fd1bc25ab 100644 --- a/firmware/config/boards/hellen/cypress/config/controllers/algo/auto_generated_enums.cpp +++ b/firmware/config/boards/hellen/cypress/config/controllers/algo/auto_generated_enums.cpp @@ -677,8 +677,6 @@ case DBG_16: return "DBG_16"; case DBG_34: return "DBG_34"; -case DBG_43: - return "DBG_43"; case DBG_44: return "DBG_44"; case DBG_ALTERNATOR_PID: @@ -733,6 +731,8 @@ case DBG_IDLE_CONTROL: return "DBG_IDLE_CONTROL"; case DBG_IGNITION_TIMING: return "DBG_IGNITION_TIMING"; +case DBG_INJECTOR_COMPENSATION: + return "DBG_INJECTOR_COMPENSATION"; case DBG_INSTANT_RPM: return "DBG_INSTANT_RPM"; case DBG_ION: diff --git a/firmware/config/boards/kinetis/config/controllers/algo/auto_generated_enums.cpp b/firmware/config/boards/kinetis/config/controllers/algo/auto_generated_enums.cpp index 82af359c6b..7b7dcfe395 100644 --- a/firmware/config/boards/kinetis/config/controllers/algo/auto_generated_enums.cpp +++ b/firmware/config/boards/kinetis/config/controllers/algo/auto_generated_enums.cpp @@ -473,8 +473,6 @@ case DBG_16: return "DBG_16"; case DBG_34: return "DBG_34"; -case DBG_43: - return "DBG_43"; case DBG_44: return "DBG_44"; case DBG_ALTERNATOR_PID: @@ -529,6 +527,8 @@ case DBG_IDLE_CONTROL: return "DBG_IDLE_CONTROL"; case DBG_IGNITION_TIMING: return "DBG_IGNITION_TIMING"; +case DBG_INJECTOR_COMPENSATION: + return "DBG_INJECTOR_COMPENSATION"; case DBG_INSTANT_RPM: return "DBG_INSTANT_RPM"; case DBG_ION: diff --git a/firmware/controllers/algo/auto_generated_enums.cpp b/firmware/controllers/algo/auto_generated_enums.cpp index b8adabb627..23e087a92f 100644 --- a/firmware/controllers/algo/auto_generated_enums.cpp +++ b/firmware/controllers/algo/auto_generated_enums.cpp @@ -619,8 +619,6 @@ case DBG_16: return "DBG_16"; case DBG_34: return "DBG_34"; -case DBG_43: - return "DBG_43"; case DBG_44: return "DBG_44"; case DBG_ALTERNATOR_PID: @@ -675,6 +673,8 @@ case DBG_IDLE_CONTROL: return "DBG_IDLE_CONTROL"; case DBG_IGNITION_TIMING: return "DBG_IGNITION_TIMING"; +case DBG_INJECTOR_COMPENSATION: + return "DBG_INJECTOR_COMPENSATION"; case DBG_INSTANT_RPM: return "DBG_INSTANT_RPM"; case DBG_ION: diff --git a/firmware/controllers/algo/fuel/injector_model.cpp b/firmware/controllers/algo/fuel/injector_model.cpp index 19d28c1258..e62e49b379 100644 --- a/firmware/controllers/algo/fuel/injector_model.cpp +++ b/firmware/controllers/algo/fuel/injector_model.cpp @@ -1,4 +1,6 @@ #include "injector_model.h" +#include "tunerstudio_outputs.h" +#include "map.h" EXTERN_ENGINE; @@ -15,10 +17,58 @@ constexpr float convertToGramsPerSecond(float ccPerMinute) { return ccPerSecond * 0.72f; // 0.72g/cc fuel density } +expected InjectorModel::getAbsoluteRailPressure() const { + switch (CONFIG(injectorCompensationMode)) { + case ICM_FixedRailPressure: + // TODO: should this add baro pressure instead of 1atm? + return (CONFIG(fuelReferencePressure) + 101.325f); + case ICM_SensedRailPressure: + // TODO: what happens when the sensor fails? + return Sensor::get(SensorType::FuelPressureInjector); + default: return unexpected; + } +} + +float InjectorModel::getInjectorFlowRatio() const { + // Compensation disabled, use reference flow. + if (CONFIG(injectorCompensationMode) == ICM_None) { + return 1.0f; + } + + float referencePressure = CONFIG(fuelReferencePressure); + expected absRailPressure = getAbsoluteRailPressure(); + + // If sensor failed, best we can do is disable correction + if (!absRailPressure) { + return 1.0f; + } + + float map = getMap(PASS_ENGINE_PARAMETER_SIGNATURE); + + // TODO: what to do when pressureDelta is less than 0? + float pressureDelta = absRailPressure.Value - map; + float pressureRatio = pressureDelta / referencePressure; + float flowRatio = sqrtf(pressureRatio); + +#if EFI_TUNER_STUDIO + if (CONFIG(debugMode) == DBG_INJECTOR_COMPENSATION) { + tsOutputChannels.debugFloatField1 = pressureDelta; + tsOutputChannels.debugFloatField2 = pressureRatio; + tsOutputChannels.debugFloatField3 = flowRatio; + } +#endif // EFI_TUNER_STUDIO + + // TODO: should the flow ratio be clamped? + return flowRatio; +} + float InjectorModel::getInjectorMassFlowRate() const { - // TODO: injector flow dependent upon rail pressure (and temperature/ethanol content?) + // TODO: injector flow dependent upon temperature/ethanol content? auto injectorVolumeFlow = CONFIG(injector.flow); - return convertToGramsPerSecond(injectorVolumeFlow); + + float flowRatio = getInjectorFlowRatio(); + + return flowRatio * convertToGramsPerSecond(injectorVolumeFlow); } float InjectorModel::getDeadtime() const { diff --git a/firmware/controllers/algo/fuel/injector_model.h b/firmware/controllers/algo/fuel/injector_model.h index 4ff58ac1d1..160834b850 100644 --- a/firmware/controllers/algo/fuel/injector_model.h +++ b/firmware/controllers/algo/fuel/injector_model.h @@ -1,6 +1,7 @@ #pragma once #include "engine.h" +#include "expected.h" struct IInjectorModel { virtual void prepare() = 0; @@ -14,6 +15,8 @@ public: virtual floatms_t getDeadtime() const = 0; virtual float getInjectorMassFlowRate() const = 0; + virtual float getInjectorFlowRatio() const = 0; + virtual expected getAbsoluteRailPressure() const = 0; virtual void postState(float deadTime) const { (void)deadTime; }; @@ -22,11 +25,13 @@ private: float m_massFlowRate = 0; }; -class InjectorModel final : public InjectorModelBase { +class InjectorModel : public InjectorModelBase { public: DECLARE_ENGINE_PTR; void postState(float deadtime) const override; floatms_t getDeadtime() const override; float getInjectorMassFlowRate() const override; + float getInjectorFlowRatio() const override; + expected getAbsoluteRailPressure() const override; }; diff --git a/firmware/controllers/algo/rusefi_enums.h b/firmware/controllers/algo/rusefi_enums.h index 0d19a211de..5e336ed5ad 100644 --- a/firmware/controllers/algo/rusefi_enums.h +++ b/firmware/controllers/algo/rusefi_enums.h @@ -758,7 +758,7 @@ typedef enum { DBG_COMPOSITE_LOG = 40, DBG_FSIO_EXPRESSION_8_14 = 41, DBG_FSIO_SPECIAL = 42, - DBG_43 = 43, + DBG_INJECTOR_COMPENSATION = 43, DBG_44 = 44, Force_4_bytes_size_debug_mode_e = ENUM_32_BITS, @@ -1016,3 +1016,9 @@ typedef enum __attribute__ ((__packed__)) { IPT_Low = 0, IPT_High = 1, } injector_pressure_type_e; + +typedef enum __attribute__ ((__packed__)) { + ICM_None = 0, + ICM_FixedRailPressure = 1, + ICM_SensedRailPressure = 2, +} injector_compensation_mode_e; diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index fc616c6c57..6e8dbec4a9 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -273,7 +273,7 @@ float baseFuel;+Base mass of the per-cylinder fuel injected during cranking. Th int16_t rpm;+This sets the RPM limit below which the ECU will use cranking fuel and ignition logic, typically this is around 350-450rpm. \nset cranking_rpm X;"RPM", 1, 0, 0, 3000, 0 end_struct -#define debug_mode_e_enum "Alternator PID", "TPS acceleration enrichment", "GPPWM", "Idle Control", "Engine Load accl enrich", "Trigger Counters", "FSIO_ADC", "AUX_PID_1", "VVT input", "Cranking", "Timing", "Closed-loop fuel corr PID", "VSS", "SD card", "sr5", "Knock", "mode16", "Electronic Throttle", "Executor", "Bench Test / TS commands", "Aux Valves", "Analog inputs #1", "INSTANT_RPM", "FSIO_EXPRESSION_1_7", "Status", "CJ125", "CAN", "MAP", "Metrics", "ETB#2", "Ion Sense", "TLE8888", "Analog inputs #2", "Dwell Metric", "INVALID", "ETB Logic", "Boost Control", "Start/Stop", "Launch", "ETB Autotune", "FSIO_COMPOSITE_LOG", "FSIO_EXPRESSION_8_14", "FSIO_SPECIAL", "Mode43", "Mode44" +#define debug_mode_e_enum "Alternator PID", "TPS acceleration enrichment", "GPPWM", "Idle Control", "Engine Load accl enrich", "Trigger Counters", "FSIO_ADC", "AUX_PID_1", "VVT input", "Cranking", "Timing", "Closed-loop fuel corr PID", "VSS", "SD card", "sr5", "Knock", "mode16", "Electronic Throttle", "Executor", "Bench Test / TS commands", "Aux Valves", "Analog inputs #1", "INSTANT_RPM", "FSIO_EXPRESSION_1_7", "Status", "CJ125", "CAN", "MAP", "Metrics", "ETB#2", "Ion Sense", "TLE8888", "Analog inputs #2", "Dwell Metric", "INVALID", "ETB Logic", "Boost Control", "Start/Stop", "Launch", "ETB Autotune", "FSIO_COMPOSITE_LOG", "FSIO_EXPRESSION_8_14", "FSIO_SPECIAL", "Injector Compensation", "Mode44" custom debug_mode_e 4 bits, U32, @OFFSET@, [0:5], @@debug_mode_e_enum@@ #define vvt_mode_e_enum "Inactive", "Single Tooth Second Half", "2GZ", "Miata NB2", "Single Tooth First Half", "Bosch Quick Start", "4/1", "mode7" @@ -1245,8 +1245,12 @@ custom tle8888_mode_e 1 bits, U08, @OFFSET@, [0:1], "Auto", "SemiAuto", "Manual" tle8888_mode_e tle8888mode; pin_output_mode_e LIS302DLCsPinMode; - uint8_t[2] unusedSomethingWasHere;;"units", 1, 0, -20, 100, 0 - float unused244_1;;"units", 1, 0, -20, 100, 0 + + custom injector_compensation_mode_e 1 bits, U08, @OFFSET@, [0:1], "None", "Fixed rail pressure", "Sensed Rail Pressure" + injector_compensation_mode_e injectorCompensationMode; + + uint8_t unused2419;;"units", 1, 0, -20, 100, 0 + float fuelReferencePressure;+This is the pressure at which your injector flow is known.\nFor example if your injectors flow 400cc/min at 3.5 bar, enter 350kpa here.;"kPa", 1, 0, 0, 700000, 0 float unused244_2;;"units", 1, 0, -20, 100, 0 float unused244_3;;"units", 1, 0, -20, 100, 0 float unused2432;;"units", 1, 0, -20, 100, 0 diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index cce4acc304..ecd0f479cc 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -413,22 +413,22 @@ enable2ndByteCanID = false ; wall of debug mode :) ; https://rusefi.com/wiki/index.php?title=Manual:Debug_fields -; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 -; Alternator TPS Acceleration GPPWM Idle Engine Load Acc Trigger Counters VVT Cranking Ignition Timing ETB PID FSIO_1_7 CJ125 CAN TLE8888 Analog inputs 2 Boost Start Launcher ETB Autotune FSIO_8_14 FSIO_SPECIAL +; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 +; Alternator TPS Acceleration GPPWM Idle Engine Load Acc Trigger Counters VVT Cranking Ignition Timing ETB PID FSIO_1_7 CJ125 CAN TLE8888 Analog inputs 2 Boost Start Launcher ETB Autotune FSIO_8_14 FSIO_SPECIAL Injector flow compensation ; DBG_ALTERNATOR_PID DBG_TPS_ACCEL DBG_GPPWM DBG_IDLE_CONTROL - debugFieldF1List = bits, U08, [0:7], "Controller Output", "From TPS", "GPPWM 1", "Controller Output", "Idle output", "Channel 1 Rise Counter", "", "", "VVT Event Position","", "Ign IAT Corr", "", "", "", "", "", "", "ETB Controller Output", "", "", "df1", "df1", "22df1", "fsio 1", "24:df1", "CJ125: output", "", "", "", "", "", "", "TPS1 Pri/Sec Diff", "", "", "", "Boost Open Loop Duty", "S unused" "", "Osc Amplitude", "", "fsio 8", "idle offset","" - debugFieldF2List = bits, U08, [0:7], "I-Term", "To TPS", "GPPWM 2", "I-Term", "Idle df2", "Channel 2 Rise Counter", "", "", "VVT Ratio", "", "Ign CLT Corr", "", "", "", "", "", "", "ETB I-Term", "", "", "df2", "df2", "22df2", "fsio 2", "24:df2", "CJ125: i-term", "", "", "", "", "", "", "TPS2 Pri/Sec Diff", "", "", "", "Boost Closed Loop Duty","S unused" "", "Duty Amplitude", "", "fsio 9", "idle min", "" - debugFieldF3List = bits, U08, [0:7], "Previous Error", "Current TPS<>TPS", "GPPWM 3", "prev error", "Idle df3", "ICU sum", "", "", "", "", "Ign FSIO Adj", "", "", "", "", "", "", "ETB err", "", "", "df3", "df3", "22df3", "fsio 3", "24:df3", "CJ125: err", "", "", "", "", "", "", "TPS1/2 Diff", "", "", "", "", "S unused" "", "Tu", "", "fsio 10", "", "" - debugFieldF4List = bits, U08, [0:7], "I Gain", "Extra Fuel", "GPPWM 4", "I Gain", "Idle df4", "VVT rise", "", "", "", "", "Ign PID Adj", "", "", "", "", "", "", "ETB I setting", "", "", "df4", "df4", "22df4", "fsio 4", "24:df4", "CJ125: UA", "", "", "", "", "", "", "Acc Pedal Pri/Sec Diff","", "", "", "", "S unused" "", "Ku", "", "fsio 11", "", "" - debugFieldF5List = bits, U08, [0:7], "D Gain", "df5", "df5", "D Gain", "Idle df5", "VVT fall", "df5", "", "", "", "", "", "", "", "", "", "", "ETB D setting", "df5", "df5", "df5", "df5", "22df5", "fsio 5", "24:df5", "CJ125: UR", "", "", "", "", "", "", "", "", "", "", "", "S unused" "", "Kp", "", "fsio 12", "", "" - debugFieldF6List = bits, U08, [0:7], "D Term", "", "", "D Term", "Idle df6", "Current Gap", "", "", "", "", "", "", "", "", "", "", "", "ETB df6", "", "", "df6", "df6", "22df6", "fsio 6", "24:df6", "cj: f7", "", "", "", "", "", "", "", "", "", "", "", "S unused" "", "Ki", "", "fsio 13", "", "" - debugFieldF7List = bits, U08, [0:7], "Max-Value", "", "", "Max-Value", "Idle df7", "", "", "", "", "", "", "", "", "", "", "", "", "ETB df7", "", "", "df7", "df7", "22df7", "fsio 7", "24:df7", "cj: f7", "", "", "", "", "", "", "", "", "", "", "", "S unused" "", "Kd", "", "fsio 14", "", "" + debugFieldF1List = bits, U08, [0:7], "Controller Output", "From TPS", "GPPWM 1", "Controller Output", "Idle output", "Channel 1 Rise Counter", "", "", "VVT Event Position","", "Ign IAT Corr", "", "", "", "", "", "", "ETB Controller Output", "", "", "df1", "df1", "22df1", "fsio 1", "24:df1", "CJ125: output", "", "", "", "", "", "", "TPS1 Pri/Sec Diff", "", "", "", "Boost Open Loop Duty", "S unused" "", "Osc Amplitude", "", "fsio 8", "idle offset", "Pressure across injector(kpa)", "" + debugFieldF2List = bits, U08, [0:7], "I-Term", "To TPS", "GPPWM 2", "I-Term", "Idle df2", "Channel 2 Rise Counter", "", "", "VVT Ratio", "", "Ign CLT Corr", "", "", "", "", "", "", "ETB I-Term", "", "", "df2", "df2", "22df2", "fsio 2", "24:df2", "CJ125: i-term", "", "", "", "", "", "", "TPS2 Pri/Sec Diff", "", "", "", "Boost Closed Loop Duty","S unused" "", "Duty Amplitude", "", "fsio 9", "idle min", "Pressure ratio vs. nominal", "" + debugFieldF3List = bits, U08, [0:7], "Previous Error", "Current TPS<>TPS", "GPPWM 3", "prev error", "Idle df3", "ICU sum", "", "", "", "", "Ign FSIO Adj", "", "", "", "", "", "", "ETB err", "", "", "df3", "df3", "22df3", "fsio 3", "24:df3", "CJ125: err", "", "", "", "", "", "", "TPS1/2 Diff", "", "", "", "", "S unused" "", "Tu", "", "fsio 10", "", "Flow ratio vs. configured", "" + debugFieldF4List = bits, U08, [0:7], "I Gain", "Extra Fuel", "GPPWM 4", "I Gain", "Idle df4", "VVT rise", "", "", "", "", "Ign PID Adj", "", "", "", "", "", "", "ETB I setting", "", "", "df4", "df4", "22df4", "fsio 4", "24:df4", "CJ125: UA", "", "", "", "", "", "", "Acc Pedal Pri/Sec Diff","", "", "", "", "S unused" "", "Ku", "", "fsio 11", "", "", "" + debugFieldF5List = bits, U08, [0:7], "D Gain", "df5", "df5", "D Gain", "Idle df5", "VVT fall", "df5", "", "", "", "", "", "", "", "", "", "", "ETB D setting", "df5", "df5", "df5", "df5", "22df5", "fsio 5", "24:df5", "CJ125: UR", "", "", "", "", "", "", "", "", "", "", "", "S unused" "", "Kp", "", "fsio 12", "", "", "" + debugFieldF6List = bits, U08, [0:7], "D Term", "", "", "D Term", "Idle df6", "Current Gap", "", "", "", "", "", "", "", "", "", "", "", "ETB df6", "", "", "df6", "df6", "22df6", "fsio 6", "24:df6", "cj: f7", "", "", "", "", "", "", "", "", "", "", "", "S unused" "", "Ki", "", "fsio 13", "", "", "" + debugFieldF7List = bits, U08, [0:7], "Max-Value", "", "", "Max-Value", "Idle df7", "", "", "", "", "", "", "", "", "", "", "", "", "ETB df7", "", "", "df7", "df7", "22df7", "fsio 7", "24:df7", "cj: f7", "", "", "", "", "", "", "", "", "", "", "", "S unused" "", "Kd", "", "fsio 14", "", "", "" - debugFieldI1List = bits, U08, [0:7], "P-Gain", "", "", "P-Gain", "Idle di1", "Channel 1 Fall Counter", "", "", "VVT Sync Counter", "", "Multispark Count", "", "", "", "", "", "", "ETB P-Gain", "", "", "di1", "di1", "22di1", "", "24:di1", "CJ125: state", "read count","", "", "", "", "SPI Counter", "", "", "", "", "", "Start Count" "", "", "", "", "", "" - debugFieldI2List = bits, U08, [0:7], "Offset", "", "", "Offset", "Idle di2", "Channel 2 Fall Counter", "", "", "", "", "", "", "", "", "", "", "", "ETB di2", "", "", "di2", "di2", "22di2", "", "24:di2", "", "write count","", "", "", "", "Latest Transmit","", "", "", "", "", "S unused" "", "", "", "", "", "" - debugFieldI3List = bits, U08, [0:7], "Reset Cnt", "", "", "Reset Cnt", "Idle di3", "Cycle Index", "", "", "", "", "", "", "", "", "", "", "", "ETB di3", "", "", "di3", "di3", "22di3", "", "24:di3", "", "write err", "", "", "", "", "Latest Received","", "", "", "", "", "S unused" "", "", "", "", "", "" - debugFieldI4List = bits, U08, [0:7], "Period", "", "", "State", "Idle di4", "Cycle Cnt 1", "", "", "", "", "", "", "", "", "", "", "", "ETB di4", "", "", "di4", "di4", "22di4", "", "24:di4", "", "", "", "", "", "", "Init Count", "", "", "", "", "", "S unused" "", "", "", "", "", "" - debugFieldI5List = bits, U08, [0:7], "", "", "", "", "Idle di5", "Cycle Cnt 2", "", "", "", "", "", "", "", "", "", "di5", "di5", "ETB di5", "di5", "di5", "di5", "di5", "22di5", "di5", "di5", "di5", "di5", "di5", "di5", "di5", "di5", "di5", "", "di5", "di5", "di5", "di5", "S di5" "", "", "", "", "", "" + debugFieldI1List = bits, U08, [0:7], "P-Gain", "", "", "P-Gain", "Idle di1", "Channel 1 Fall Counter", "", "", "VVT Sync Counter", "", "Multispark Count", "", "", "", "", "", "", "ETB P-Gain", "", "", "di1", "di1", "22di1", "", "24:di1", "CJ125: state", "read count","", "", "", "", "SPI Counter", "", "", "", "", "", "Start Count" "", "", "", "", "", "", "" + debugFieldI2List = bits, U08, [0:7], "Offset", "", "", "Offset", "Idle di2", "Channel 2 Fall Counter", "", "", "", "", "", "", "", "", "", "", "", "ETB di2", "", "", "di2", "di2", "22di2", "", "24:di2", "", "write count","", "", "", "", "Latest Transmit","", "", "", "", "", "S unused" "", "", "", "", "", "", "" + debugFieldI3List = bits, U08, [0:7], "Reset Cnt", "", "", "Reset Cnt", "Idle di3", "Cycle Index", "", "", "", "", "", "", "", "", "", "", "", "ETB di3", "", "", "di3", "di3", "22di3", "", "24:di3", "", "write err", "", "", "", "", "Latest Received","", "", "", "", "", "S unused" "", "", "", "", "", "", "" + debugFieldI4List = bits, U08, [0:7], "Period", "", "", "State", "Idle di4", "Cycle Cnt 1", "", "", "", "", "", "", "", "", "", "", "", "ETB di4", "", "", "di4", "di4", "22di4", "", "24:di4", "", "", "", "", "", "", "Init Count", "", "", "", "", "", "S unused" "", "", "", "", "", "", "" + debugFieldI5List = bits, U08, [0:7], "", "", "", "", "Idle di5", "Cycle Cnt 2", "", "", "", "", "", "", "", "", "", "di5", "di5", "ETB di5", "di5", "di5", "di5", "di5", "22di5", "di5", "di5", "di5", "di5", "di5", "di5", "di5", "di5", "di5", "", "di5", "di5", "di5", "di5", "S di5" "", "", "", "", "", "", "" [ConstantsExtensions] ; defaultValue is used to provide TunerStudio with a value to use in the case of @@ -1754,6 +1754,8 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" dialog = injChars, "Injector Settings", yAxis field = "Injector Flow", injector_flow, {isInjectionEnabled == 1} field = "Fuel rail pressure sensor", injectorPressureType, { isInjectionEnabled && (highPressureFuel_hwChannel || lowPressureFuel_hwChannel) } + field = "Injector flow compensation mode", injectorCompensationMode, { isInjectionEnabled } + field = "Injector reference pressure", fuelReferencePressure, { isInjectionEnabled && injectorCompensationMode != 0 } dialog = fuelParams, "Fuel characteristics", yAxis field = "Stoichiometric ratio", stoichRatioPrimary, {isInjectionEnabled == 1} diff --git a/unit_tests/tests/ignition_injection/test_injector_model.cpp b/unit_tests/tests/ignition_injection/test_injector_model.cpp index aca0417bd1..ed3481eb9e 100644 --- a/unit_tests/tests/ignition_injection/test_injector_model.cpp +++ b/unit_tests/tests/ignition_injection/test_injector_model.cpp @@ -10,6 +10,8 @@ class MockInjectorModel : public InjectorModelBase { public: MOCK_METHOD(floatms_t, getDeadtime, (), (const, override)); MOCK_METHOD(float, getInjectorMassFlowRate, (), (const, override)); + MOCK_METHOD(float, getInjectorFlowRatio, (), (const, override)); + MOCK_METHOD(expected, getAbsoluteRailPressure, (), (const, override)); }; TEST(InjectorModel, Prepare) { @@ -53,3 +55,121 @@ TEST(InjectorModel, Deadtime) { engine->sensors.vBatt = 7; EXPECT_EQ(dut.getDeadtime(), 14); } + +struct TesterGetFlowRate : public InjectorModel { + MOCK_METHOD(float, getInjectorFlowRatio, (), (const, override)); +}; + +struct TesterGetRailPressure : public InjectorModel { + MOCK_METHOD(expected, getAbsoluteRailPressure, (), (const, override)); +}; + +class FlowRateFixture : public ::testing::TestWithParam { +}; + +INSTANTIATE_TEST_SUITE_P( + InjectorModel, + FlowRateFixture, + ::testing::Values(0.1f, 0.5f, 1.0f, 2.0f, 10.0f) +); + +TEST_P(FlowRateFixture, FlowRateRatio) { + float flowRatio = GetParam(); + + StrictMock dut; + EXPECT_CALL(dut, getInjectorFlowRatio()).WillOnce(Return(flowRatio)); + + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + INJECT_ENGINE_REFERENCE(&dut); + engineConfiguration->injector.flow = 500; + + // 500 cc/min = 6g/s + float expectedFlow = flowRatio * 6.0f; + + // Check that flow is adjusted correctly + EXPECT_FLOAT_EQ(expectedFlow, dut.getInjectorMassFlowRate()); +} + +TEST_P(FlowRateFixture, PressureRatio) { + float pressureRatio = GetParam(); + // Flow ratio should be the sqrt of pressure ratio + float expectedFlowRatio = sqrtf(pressureRatio); + float fakeMap = 35.0f; + + StrictMock dut; + EXPECT_CALL(dut, getAbsoluteRailPressure()).WillOnce(Return(400 * pressureRatio + fakeMap)); + + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + INJECT_ENGINE_REFERENCE(&dut); + + // Use injector compensation + engineConfiguration->injectorCompensationMode = ICM_SensedRailPressure; + + // Reference pressure is 400kPa + engineConfiguration->fuelReferencePressure = 400.0f; + + // MAP sensor always reads 35 kpa + engine->mockMapValue = fakeMap; + + // Should return the expected ratio + EXPECT_FLOAT_EQ(expectedFlowRatio, dut.getInjectorFlowRatio()); +} + +TEST(InjectorModel, VariableInjectorFlowModeNone) { + StrictMock dut; + + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + INJECT_ENGINE_REFERENCE(&dut); + + engineConfiguration->injectorCompensationMode = ICM_None; + + // This shoudn't call getAbsoluteRailPressure, it should just return 1.0 + EXPECT_FLOAT_EQ(1, dut.getInjectorFlowRatio()); +} + +TEST(InjectorModel, RailPressureFixed) { + InjectorModel dut; + + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + INJECT_ENGINE_REFERENCE(&dut); + + // Reference pressure is 350kpa + engineConfiguration->fuelReferencePressure = 350; + engineConfiguration->injectorCompensationMode = ICM_FixedRailPressure; + + // Should be reference pressure + 1 atm + EXPECT_FLOAT_EQ(101.325f + 350.0f, dut.getAbsoluteRailPressure().value_or(0)); +} + +TEST(InjectorModel, RailPressureSensed) { + InjectorModel dut; + + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + INJECT_ENGINE_REFERENCE(&dut); + + // Reference pressure is 350kpa + engineConfiguration->injectorCompensationMode = ICM_SensedRailPressure; + + // Should just return rail sensor value + Sensor::setMockValue(SensorType::FuelPressureInjector, 100); + EXPECT_FLOAT_EQ(100, dut.getAbsoluteRailPressure().value_or(-1)); + Sensor::setMockValue(SensorType::FuelPressureInjector, 200); + EXPECT_FLOAT_EQ(200, dut.getAbsoluteRailPressure().value_or(-1)); + Sensor::setMockValue(SensorType::FuelPressureInjector, 300); + EXPECT_FLOAT_EQ(300, dut.getAbsoluteRailPressure().value_or(-1)); +} + +TEST(InjectorModel, FailedPressureSensor) { + InjectorModel dut; + + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + INJECT_ENGINE_REFERENCE(&dut); + + // Reference pressure is 350kpa + engineConfiguration->injectorCompensationMode = ICM_SensedRailPressure; + + // Sensor is broken! + Sensor::resetMockValue(SensorType::FuelPressureInjector); + + EXPECT_EQ(1.0f, dut.getInjectorFlowRatio()); +}