diff --git a/firmware/controllers/actuators/idle_thread.cpp b/firmware/controllers/actuators/idle_thread.cpp index 98c52c4025..5f27d77da4 100644 --- a/firmware/controllers/actuators/idle_thread.cpp +++ b/firmware/controllers/actuators/idle_thread.cpp @@ -187,7 +187,7 @@ IIdleController::Phase IdleController::determinePhase(int rpm, int targetRpm, Se // If still in the cranking taper, disable closed loop idle if (crankingTaperFraction < 1) { - return Phase::CrankToRunTaper; + return Phase::CrankToIdleTaper; } // No other conditions met, we are idling! @@ -506,8 +506,8 @@ float getIdleTimingAdjustment(int rpm) { return idleControllerInstance.getIdleTimingAdjustment(rpm); } -bool isIdling() { - return idleControllerInstance.isIdling(); +bool isIdlingOrTaper() { + return idleControllerInstance.isIdlingOrTaper(); } static void applyPidSettings(DECLARE_ENGINE_PARAMETER_SIGNATURE) { diff --git a/firmware/controllers/actuators/idle_thread.h b/firmware/controllers/actuators/idle_thread.h index 99012c9b4b..67217570bf 100644 --- a/firmware/controllers/actuators/idle_thread.h +++ b/firmware/controllers/actuators/idle_thread.h @@ -18,7 +18,7 @@ struct IIdleController { Cranking, // Below cranking threshold Idling, // Below idle RPM, off throttle Coasting, // Off throttle but above idle RPM - CrankToRunTaper, // Taper between cranking and running + CrankToIdleTaper, // Taper between cranking and idling Running, // On throttle }; @@ -59,8 +59,8 @@ public: float getClosedLoop(IIdleController::Phase phase, float tpsPos, int rpm, int targetRpm) override; // Allow querying state from outside - bool isIdling() { - return m_lastPhase == Phase::Idling; + bool isIdlingOrTaper() { + return m_lastPhase == Phase::Idling || (CONFIG(useSeparateIdleTablesForCrankingTaper) && m_lastPhase == Phase::CrankToIdleTaper); } private: @@ -79,7 +79,7 @@ percent_t getIdlePosition(); float getIdleTimingAdjustment(int rpm); -bool isIdling(); +bool isIdlingOrTaper(); void applyIACposition(percent_t position DECLARE_ENGINE_PARAMETER_SUFFIX); void setManualIdleValvePosition(int positionPercent); diff --git a/firmware/controllers/algo/advance_map.cpp b/firmware/controllers/algo/advance_map.cpp index d5c30eeaee..a9be7e2308 100644 --- a/firmware/controllers/algo/advance_map.cpp +++ b/firmware/controllers/algo/advance_map.cpp @@ -50,7 +50,7 @@ static angle_t getRunningAdvance(int rpm, float engineLoad DECLARE_ENGINE_PARAME float advanceAngle = advanceMap.getValue((float) rpm, engineLoad); // get advance from the separate table for Idle - if (CONFIG(useSeparateAdvanceForIdle) && isIdling()) { + if (CONFIG(useSeparateAdvanceForIdle) && isIdlingOrTaper()) { float idleAdvance = interpolate2d(rpm, config->idleAdvanceBins, config->idleAdvance); auto [valid, tps] = Sensor::get(SensorType::DriverThrottleIntent); diff --git a/firmware/controllers/algo/airmass/airmass.cpp b/firmware/controllers/algo/airmass/airmass.cpp index 3e94fb6707..78e2eb5f40 100644 --- a/firmware/controllers/algo/airmass/airmass.cpp +++ b/firmware/controllers/algo/airmass/airmass.cpp @@ -24,7 +24,7 @@ float AirmassVeModelBase::getVe(int rpm, float load) const { auto tps = Sensor::get(SensorType::Tps1); // get VE from the separate table for Idle if idling - if (isIdling() && tps && CONFIG(useSeparateVeForIdle)) { + if (isIdlingOrTaper() && tps && CONFIG(useSeparateVeForIdle)) { float idleVe = interpolate2d(rpm, config->idleVeBins, config->idleVe); // interpolate between idle table and normal (running) table using TPS threshold ve = interpolateClamped(0.0f, idleVe, CONFIG(idlePidDeactivationTpsThreshold), ve, tps.Value); diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index dd267a7a1f..03e3092bc8 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -587,7 +587,7 @@ bit cj125isUrDivided;+Is your UR CJ125 output wired to MCU via resistor divider? bit useCicPidForIdle;+Switch between Industrial and Cic PID implementation bit useTLE8888_cranking_hack; bit useInstantRpmForIdle; -bit unused76b19; +bit useSeparateIdleTablesForCrankingTaper;+This uses separate ignition timing and VE tables not only for idle conditions, also during the postcranking-to-idle taper transition (See also afterCrankingIACtaperDuration). bit launchControlEnabled; bit rollingLaunchEnabled; bit antiLagEnabled; diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index c48f2727fb..8fc73de58a 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -2708,6 +2708,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" dialog = idleExtra, "Extra Idle Features" field = "Use idle ignition table", useSeparateAdvanceForIdle field = "Use idle VE table", useSeparateVeForIdle + field = "Use idle tables for cranking taper", useSeparateIdleTablesForCrankingTaper field = "Use coasting idle table", useIacTableForCoasting, {idleMode == 0} field = useInstantRpmForIdle, useInstantRpmForIdle field = "Detailed status in console", isVerboseIAC diff --git a/unit_tests/tests/test_idle_controller.cpp b/unit_tests/tests/test_idle_controller.cpp index cd88c70330..83fc374ca6 100644 --- a/unit_tests/tests/test_idle_controller.cpp +++ b/unit_tests/tests/test_idle_controller.cpp @@ -98,7 +98,7 @@ TEST(idle_v2, testDeterminePhase) { EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, 0, 25, 10)); // Check that shortly after cranking, the cranking taper inhibits closed loop idle - EXPECT_EQ(ICP::CrankToRunTaper, dut.determinePhase(1000, 1000, 0, 0, 0.5f)); + EXPECT_EQ(ICP::CrankToIdleTaper, dut.determinePhase(1000, 1000, 0, 0, 0.5f)); // Above TPS threshold should be outside the zone EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, 10, 0, 10)); @@ -246,19 +246,19 @@ TEST(idle_v2, openLoopRunningTaper) { // 0 cycles - no taper yet, pure cranking value EXPECT_FLOAT_EQ(75, dut.getOpenLoop(ICP::Running, 30, 0, 0)); - EXPECT_FLOAT_EQ(75, dut.getOpenLoop(ICP::CrankToRunTaper, 30, 0, 0)); + EXPECT_FLOAT_EQ(75, dut.getOpenLoop(ICP::CrankToIdleTaper, 30, 0, 0)); // 1/2 taper - half way, 50% each value -> outputs 50 EXPECT_FLOAT_EQ(50, dut.getOpenLoop(ICP::Running, 30, 0, 0.5f)); - EXPECT_FLOAT_EQ(50, dut.getOpenLoop(ICP::CrankToRunTaper, 30, 0, 0.5f)); + EXPECT_FLOAT_EQ(50, dut.getOpenLoop(ICP::CrankToIdleTaper, 30, 0, 0.5f)); // 1x taper - fully tapered, should be running value EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::Running, 30, 0, 1.0f)); - EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::CrankToRunTaper, 30, 0, 1.0f)); + EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::CrankToIdleTaper, 30, 0, 1.0f)); // 2x taper - still fully tapered, should be running value EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::Running, 30, 0, 2.0f)); - EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::CrankToRunTaper, 30, 0, 2.0f)); + EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::CrankToIdleTaper, 30, 0, 2.0f)); } TEST(idle_v2, getCrankingTaperFraction) {