From 11d58f8d5a8eaafe96662da04059c2da2306eccb Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Wed, 22 Jun 2022 13:49:24 -0700 Subject: [PATCH] clt based rpm limit (#4267) --- firmware/controllers/limp_manager.cpp | 21 ++++++----- firmware/integration/rusefi_config.txt | 8 ++--- firmware/tunerstudio/rusefi.input | 12 ++++++- unit_tests/tests/test_limp.cpp | 50 ++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 13 deletions(-) diff --git a/firmware/controllers/limp_manager.cpp b/firmware/controllers/limp_manager.cpp index cbb13af12f..61eb8d300c 100644 --- a/firmware/controllers/limp_manager.cpp +++ b/firmware/controllers/limp_manager.cpp @@ -10,15 +10,20 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) { Clearable allowFuel = engineConfiguration->isInjectionEnabled; Clearable allowSpark = engineConfiguration->isIgnitionEnabled; - // User-configured hard RPM limit - if (rpm > engineConfiguration->rpmHardLimit) { - warning(CUSTOM_OBD_NAN_INJECTION, "Hit hard limit %d", engineConfiguration->rpmHardLimit); - if (engineConfiguration->cutFuelOnHardLimit) { - allowFuel.clear(ClearReason::HardLimit); - } + { + // User-configured hard RPM limit, either constant or CLT-lookup + float revLimit = engineConfiguration->useCltBasedRpmLimit + ? interpolate2d(Sensor::get(SensorType::Clt).value_or(0), engineConfiguration->cltRevLimitRpmBins, engineConfiguration->cltRevLimitRpm) + : (float)engineConfiguration->rpmHardLimit; - if (engineConfiguration->cutSparkOnHardLimit) { - allowSpark.clear(ClearReason::HardLimit); + if (rpm > revLimit) { + if (engineConfiguration->cutFuelOnHardLimit) { + allowFuel.clear(ClearReason::HardLimit); + } + + if (engineConfiguration->cutSparkOnHardLimit) { + allowSpark.clear(ClearReason::HardLimit); + } } } diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index d80bd6f152..d988ec288f 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1023,7 +1023,7 @@ end_struct bit invertSecondaryTriggerSignal;+This setting flips the signal from the secondary engine speed sensor. bit cutFuelOnHardLimit,"yes","no" -bit cutSparkOnHardLimit,"yes","no" +bit cutSparkOnHardLimit,"yes","no";Be careful enabling this: some engines are known to self-disassemble their valvetrain with a spark cut. Fuel cut is much safer. bit launchFuelCutEnable bit launchSparkCutEnable;+This is the Cut Mode normally used bit boardUseCrankPullUp,"Hall","VR" @@ -1071,7 +1071,7 @@ bit useIacPidMultTable;+This flag allows to use a special 'PID Multiplier' table bit isBoostControlEnabled bit launchSmoothRetard;+Interpolates the Ignition Retard from 0 to 100% within the RPM Range bit isPhaseSyncRequiredForIgnition;Some engines are OK running semi-random sequential while other engine require phase synchronization - bit unused1476b8 +bit useCltBasedRpmLimit,"yes","no";If enabled, use a curve for RPM limit (based on coolant temperature) instead of a constant value. bit unused_1484_bit_24 bit unused_1484_bit_25 bit unused_1484_bit_26 @@ -1352,8 +1352,8 @@ custom stepper_num_micro_steps_e 1 bits, U08, @OFFSET@, [0:3], @@stepper_num_mic linear_sensor_s highPressureFuel; linear_sensor_s lowPressureFuel; -int8_t[CLT_LIMITER_CURVE_SIZE] cltRevLimitRpmBins;CLT-based target RPM for hard limit depending on CLT like on Lexus LFA;"C", 1, 0, -70, 120, 0 -uint16_t[CLT_LIMITER_CURVE_SIZE] cltRevLimitRpm;See idleRpmPid;"", 1, 0, 0, 8000, 0 +int8_t[CLT_LIMITER_CURVE_SIZE] cltRevLimitRpmBins;;"C", 1, 0, -40, 120, 0 +uint16_t[CLT_LIMITER_CURVE_SIZE] cltRevLimitRpm;;"RPM", 1, 0, 0, 20000, 0 gppwm_note_t[SCRIPT_CURVE_COUNT iterate] scriptCurveName; diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index d2fcab6ada..e6a371377c 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -486,6 +486,14 @@ enable2ndByteCanID = false yBins = crankingFuelCoefE100 gauge = CLTGauge + curve = cltRevLimitCurve, "" + columnLabel = "Coolant", "RPM Limit" + xAxis = -40, 120, 9 + yAxis = 0, 8000, 9 + xBins = cltRevLimitRpmBins, coolant + yBins = cltRevLimitRpm + gauge = CLTGauge + curve = etbTpsBiasCurve, "Electronic TB Bias Curve" columnLabel = "TPS", "duty bias" xAxis = 0, 50, 11 @@ -1374,6 +1382,7 @@ menuDialog = main menu = "&Base &Engine" subMenu = engineChars, "Base engine" subMenu = limitsAndFallback, "Limits and fallbacks" + subMenu = cltRevLimitCurve, "CLT-based RPM Limit", 0, { (cutFuelOnHardLimit || cutSparkOnHardLimit) && useCltBasedRpmLimit } subMenu = triggerConfiguration, "Trigger" subMenu = triggerConfiguration_IO, "Advanced Trigger" subMenu = triggerConfiguration_gap, "Trigger Gap Override" @@ -3306,7 +3315,8 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" dialog = limitsSettings, "Limits" field = "Cut fuel on RPM limit", cutFuelOnHardLimit field = "Cut spark on RPM limit", cutSparkOnHardLimit - field = "RPM hard limit", rpmHardLimit, { cutFuelOnHardLimit || cutSparkOnHardLimit } + field = "Use CLT-based RPM limit curve", useCltBasedRpmLimit, { cutFuelOnHardLimit || cutSparkOnHardLimit } + field = "RPM hard limit", rpmHardLimit, { (cutFuelOnHardLimit || cutSparkOnHardLimit) && !useCltBasedRpmLimit } field = "Boost cut pressure", boostCutPressure field = "Minimum oil pressure after start", minOilPressureAfterStart diff --git a/unit_tests/tests/test_limp.cpp b/unit_tests/tests/test_limp.cpp index 1207c1670f..84746d2ef9 100644 --- a/unit_tests/tests/test_limp.cpp +++ b/unit_tests/tests/test_limp.cpp @@ -43,6 +43,56 @@ TEST(limp, revLimit) { EXPECT_TRUE(dut.allowInjection()); } +TEST(limp, revLimitCltBased) { + EngineTestHelper eth(TEST_ENGINE); + + engineConfiguration->rpmHardLimit = 2500; + + // Configure CLT-based rev limit curve + engineConfiguration->useCltBasedRpmLimit = true; + copyArray(engineConfiguration->cltRevLimitRpmBins, { 10, 20, 30, 40 }); + copyArray(engineConfiguration->cltRevLimitRpm, { 1000, 2000, 3000, 4000 }); + + LimpManager dut; + + // Check low temperature first + Sensor::setMockValue(SensorType::Clt, 10); + + // Under rev limit, inj/ign allowed + dut.updateState(900, 0); + EXPECT_TRUE(dut.allowIgnition()); + EXPECT_TRUE(dut.allowInjection()); + + // Over rev limit, no injection + dut.updateState(1100, 0); + EXPECT_FALSE(dut.allowIgnition()); + EXPECT_FALSE(dut.allowInjection()); + + // Now recover back to under limit + dut.updateState(900, 0); + EXPECT_TRUE(dut.allowIgnition()); + EXPECT_TRUE(dut.allowInjection()); + + + // Check middle temperature + Sensor::setMockValue(SensorType::Clt, 35); + + // Under rev limit, inj/ign allowed + dut.updateState(3400, 0); + EXPECT_TRUE(dut.allowIgnition()); + EXPECT_TRUE(dut.allowInjection()); + + // Over rev limit, no injection + dut.updateState(3600, 0); + EXPECT_FALSE(dut.allowIgnition()); + EXPECT_FALSE(dut.allowInjection()); + + // Now recover back to under limit + dut.updateState(3400, 0); + EXPECT_TRUE(dut.allowIgnition()); + EXPECT_TRUE(dut.allowInjection()); +} + TEST(limp, boostCut) { EngineTestHelper eth(TEST_ENGINE);