RPM soft limit and hysteresis #5214, #5224 (#5228)

* [DRAFT] RPM soft limit and hysteresis #5214, #5224

* fix m_timingRetard

* fix rpmHardLimitHyst

* unit-tests for #5214, #5224
This commit is contained in:
Andreika 2023-04-11 00:18:51 +03:00 committed by GitHub
parent 0316460f27
commit 919ed2d934
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 4 deletions

View File

@ -137,6 +137,8 @@ float getRunningFuel(float baseFuel) {
correction *= engine->launchController.getFuelCoefficient();
#endif
correction *= getLimpManager()->getLimitingFuelCorrection();
engine->fuelComputer.totalFuelCorrection = correction;
float runningFuel = baseFuel * correction;

View File

@ -104,7 +104,9 @@ static void prepareCylinderIgnitionSchedule(angle_t dwellAngleDuration, floatms_
// Offset by this cylinder's position in the cycle
+ getCylinderAngle(event->cylinderIndex, event->cylinderNumber)
// Pull any extra timing for knock retard
+ engine->module<KnockController>()->getKnockRetard();
+ engine->module<KnockController>()->getKnockRetard()
// Degrees of timing REMOVED from actual timing during soft RPM limit window
+ getLimpManager()->getLimitingTimingRetard();
efiAssertVoid(CUSTOM_SPARK_ANGLE_1, !cisnan(sparkAngle), "sparkAngle#1");

View File

@ -60,8 +60,9 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) {
? interpolate2d(Sensor::getOrZero(SensorType::Clt), engineConfiguration->cltRevLimitRpmBins, engineConfiguration->cltRevLimitRpm)
: (float)engineConfiguration->rpmHardLimit;
// Require 50 rpm drop before resuming
if (m_revLimitHysteresis.test(rpm, revLimit, revLimit - 50)) {
// Require configurable rpm drop before resuming
float revLimitLow = revLimit - engineConfiguration->rpmHardLimitHyst;
if (m_revLimitHysteresis.test(rpm, revLimit, revLimitLow)) {
if (engineConfiguration->cutFuelOnHardLimit) {
allowFuel.clear(ClearReason::HardLimit);
}
@ -70,6 +71,10 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) {
allowSpark.clear(ClearReason::HardLimit);
}
}
m_timingRetard = interpolateClamped(revLimitLow, 0, revLimit, engineConfiguration->rpmSoftLimitTimingRetard, rpm);
percent_t fuelAdded = interpolateClamped(revLimitLow, 0, revLimit, engineConfiguration->rpmSoftLimitFuelAdded, rpm);
m_fuelCorrection = 1.0f + fuelAdded / 100;
}
#if EFI_SHAFT_POSITION_INPUT
@ -227,3 +232,15 @@ LimpState LimpManager::allowIgnition() const {
}
return {true, ClearReason::None};
}
angle_t LimpManager::getLimitingTimingRetard() const {
if (!engineConfiguration->cutSparkOnHardLimit)
return 0;
return m_timingRetard;
}
float LimpManager::getLimitingFuelCorrection() const {
if (!engineConfiguration->cutFuelOnHardLimit)
return 1.0f; // no correction
return m_fuelCorrection;
}

View File

@ -113,6 +113,9 @@ public:
bool allowTriggerInput() const;
angle_t getLimitingTimingRetard() const;
float getLimitingFuelCorrection() const;
// Other subsystems call these APIs to indicate a problem has occurred
void reportEtbProblem();
void fatalError();
@ -139,6 +142,9 @@ private:
// Ignition switch state
bool m_ignitionOn = false;
angle_t m_timingRetard = 0;
float m_fuelCorrection = 1.0f;
};
LimpManager * getLimpManager();

View File

@ -3677,10 +3677,16 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@@@ts_command_e_TS_
field = "Cut fuel on RPM limit", cutFuelOnHardLimit
field = "Cut spark on RPM limit", cutSparkOnHardLimit
field = "Use CLT-based RPM limit curve", useCltBasedRpmLimit, { cutFuelOnHardLimit || cutSparkOnHardLimit }
field = "RPM hard limit", rpmHardLimit, { (cutFuelOnHardLimit || cutSparkOnHardLimit) && !useCltBasedRpmLimit }
field = "RPM hard limit", rpmHardLimit, { (cutFuelOnHardLimit || cutSparkOnHardLimit) && !useCltBasedRpmLimit }
field = "RPM limit hysteresis", rpmHardLimitHyst
field = "Boost cut pressure", boostCutPressure
field = "Minimum oil pressure after start", minOilPressureAfterStart
dialog = softRpmLimitSettings, "Soft RPM Limit"
field = "Window size", rpmSoftLimitWindowSize
field = "Timing retard", rpmSoftLimitTimingRetard, { cutSparkOnHardLimit }
field = "Fuel added", rpmSoftLimitFuelAdded, { cutFuelOnHardLimit }
dialog = etbLimits, "Electronic Throttle Limiting"
field = "Smoothly close the throttle to limit RPM."
field = "Soft limiter start", etbRevLimitStart
@ -3692,6 +3698,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@@@ts_command_e_TS_
dialog = limitsAndFallbackLeft
panel = limitsSettings
panel = softRpmLimitSettings, West, { (cutFuelOnHardLimit || cutSparkOnHardLimit) && !useCltBasedRpmLimit }
panel = etbLimits
panel = fallbacks

View File

@ -1,5 +1,6 @@
#include "pch.h"
#include "fuel_math.h"
#include "limp_manager.h"
TEST(limp, testFatalError) {
@ -93,6 +94,76 @@ TEST(limp, revLimitCltBased) {
EXPECT_TRUE(dut.allowInjection());
}
TEST(limp, revHardLimitHyst) {
EngineTestHelper eth(TEST_ENGINE);
engineConfiguration->rpmHardLimit = 2500;
engineConfiguration->rpmHardLimitHyst = 200;
LimpManager dut;
// Under rev limit, inj/ign allowed
dut.updateState(2500, 0);
EXPECT_TRUE(dut.allowIgnition());
EXPECT_TRUE(dut.allowInjection());
// Over rev limit, no injection or ignition
dut.updateState(2501, 0);
EXPECT_FALSE(dut.allowIgnition());
EXPECT_FALSE(dut.allowInjection());
// Now set back inside the limit window - still not allowed
dut.updateState(2300, 0);
EXPECT_FALSE(dut.allowIgnition());
EXPECT_FALSE(dut.allowInjection());
// Now recover back to under lower limit
dut.updateState(2299, 0);
EXPECT_TRUE(dut.allowIgnition());
EXPECT_TRUE(dut.allowInjection());
}
TEST(limp, revSoftLimit) {
EngineTestHelper eth(FORD_ASPIRE_1996);
engineConfiguration->rpmHardLimit = 2500;
engineConfiguration->rpmHardLimitHyst = 200;
engineConfiguration->rpmSoftLimitTimingRetard = 10; // 10 deg
engineConfiguration->rpmSoftLimitFuelAdded = 20; // 20%
eth.engine.updateSlowSensors();
Sensor::setMockValue(SensorType::Clt, 36.605f);
Sensor::setMockValue(SensorType::Iat, 30.0f);
// this is 5ms base fuel with some default CLT/IAT corrections
static const float baseFuel = 5.0f;
static const float normalRunningFuel = 5.3679f;
// Under rev limit, no inj/ign corrections
Sensor::setMockValue(SensorType::Rpm, 2300);
eth.engine.periodicFastCallback();
EXPECT_FLOAT_EQ(0, getLimpManager()->getLimitingTimingRetard());
EXPECT_FLOAT_EQ(1, getLimpManager()->getLimitingFuelCorrection());
// this is normal injection mode, no limiting fuel corrections
ASSERT_NEAR(normalRunningFuel, getRunningFuel(baseFuel), EPS4D) << "base fuel";
// For upper rev limit, we expect maximum inj/ign corrections
Sensor::setMockValue(SensorType::Rpm, 2500);
eth.engine.periodicFastCallback();
EXPECT_FLOAT_EQ(10, getLimpManager()->getLimitingTimingRetard()); // 10 deg
EXPECT_FLOAT_EQ(1.2f, getLimpManager()->getLimitingFuelCorrection()); // 20%
ASSERT_NEAR(normalRunningFuel * 1.2f, getRunningFuel(baseFuel), EPS4D) << "base fuel"; // 20%
// In the middle of the limit window, we expect 50% interpolated inj/ign corrections
Sensor::setMockValue(SensorType::Rpm, 2400);
eth.engine.periodicFastCallback();
EXPECT_FLOAT_EQ(5, getLimpManager()->getLimitingTimingRetard()); // 5 deg
EXPECT_FLOAT_EQ(1.1f, getLimpManager()->getLimitingFuelCorrection()); // 10%
ASSERT_NEAR(normalRunningFuel * 1.1f, getRunningFuel(baseFuel), EPS4D) << "base fuel"; // 10%
}
TEST(limp, boostCut) {
EngineTestHelper eth(TEST_ENGINE);