add hysteresis to limp rpm, boost, injector duty (#4541)
* add hysteresis * changelog
This commit is contained in:
parent
684923f4c1
commit
b305308ef6
|
@ -31,6 +31,7 @@ Release template (copy/paste this for new release):
|
|||
- Manual electronic throttle synchronization #3680
|
||||
- Delay before enabling AC compressor #4502
|
||||
- Require full sync for odd cylinder count #4533
|
||||
- Hysteresis on some fuel cuts to avoid engine damage #4541
|
||||
|
||||
### Fixed
|
||||
- Inverted vvt control #4464
|
||||
|
|
|
@ -45,7 +45,8 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) {
|
|||
? interpolate2d(Sensor::get(SensorType::Clt).value_or(0), engineConfiguration->cltRevLimitRpmBins, engineConfiguration->cltRevLimitRpm)
|
||||
: (float)engineConfiguration->rpmHardLimit;
|
||||
|
||||
if (rpm > revLimit) {
|
||||
// Require 50 rpm drop before resuming
|
||||
if (m_revLimitHysteresis.test(rpm, revLimit, revLimit - 50)) {
|
||||
if (engineConfiguration->cutFuelOnHardLimit) {
|
||||
allowFuel.clear(ClearReason::HardLimit);
|
||||
}
|
||||
|
@ -72,8 +73,10 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) {
|
|||
}
|
||||
|
||||
// Limit fuel only on boost pressure (limiting spark bends valves)
|
||||
if (engineConfiguration->boostCutPressure != 0) {
|
||||
if (Sensor::getOrZero(SensorType::Map) > engineConfiguration->boostCutPressure) {
|
||||
float mapCut = engineConfiguration->boostCutPressure;
|
||||
if (mapCut != 0) {
|
||||
// require drop of 20kPa to resume fuel
|
||||
if (m_boostCutHysteresis.test(Sensor::getOrZero(SensorType::Map), mapCut, mapCut - 20)) {
|
||||
allowFuel.clear(ClearReason::BoostCut);
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +121,8 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) {
|
|||
|
||||
// If duty cycle is high, impose a fuel cut rev limiter.
|
||||
// This is safer than attempting to limp along with injectors or a pump that are out of flow.
|
||||
if (getInjectorDutyCycle(rpm) > 96.0f) {
|
||||
// only reset once below 20% duty to force the driver to lift
|
||||
if (m_injectorDutyCutHysteresis.test(getInjectorDutyCycle(rpm), 96, 20)) {
|
||||
allowFuel.clear(ClearReason::InjectorDutyCycle);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,23 @@ struct LimpState {
|
|||
}
|
||||
};
|
||||
|
||||
class Hysteresis {
|
||||
public:
|
||||
// returns true if value > rising, false if value < falling, previous if falling < value < rising.
|
||||
bool test(float value, float rising, float falling) {
|
||||
if (value > rising) {
|
||||
m_state = true;
|
||||
} else if (value < falling) {
|
||||
m_state = false;
|
||||
}
|
||||
|
||||
return m_state;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_state = false;
|
||||
};
|
||||
|
||||
class LimpManager {
|
||||
public:
|
||||
// This is called from periodicFastCallback to update internal state
|
||||
|
@ -78,6 +95,10 @@ public:
|
|||
private:
|
||||
void setFaultRevLimit(int limit);
|
||||
|
||||
Hysteresis m_revLimitHysteresis;
|
||||
Hysteresis m_boostCutHysteresis;
|
||||
Hysteresis m_injectorDutyCutHysteresis;
|
||||
|
||||
// Start with no fault rev limit
|
||||
int32_t m_faultRevLimit = INT32_MAX;
|
||||
|
||||
|
|
|
@ -36,3 +36,20 @@ TEST(Deadband, InsideDeadband) {
|
|||
// Now it should flip back
|
||||
EXPECT_TRUE(d.gt(0, -5.01));
|
||||
}
|
||||
|
||||
TEST(Hysteresis, basic) {
|
||||
Hysteresis h;
|
||||
|
||||
// Below 'rising', should stay false
|
||||
EXPECT_FALSE(h.test(15, 30, 20));
|
||||
EXPECT_FALSE(h.test(25, 30, 20));
|
||||
|
||||
// over 'rising', should go true
|
||||
EXPECT_TRUE(h.test(31, 30, 20));
|
||||
|
||||
// drop back below 'rising', should stay true
|
||||
EXPECT_TRUE(h.test(25, 30, 20));
|
||||
|
||||
// drop below 'falling', should go false
|
||||
EXPECT_FALSE(h.test(15, 30, 20));
|
||||
}
|
||||
|
|
|
@ -106,13 +106,18 @@ TEST(limp, boostCut) {
|
|||
dut.updateState(1000, 0);
|
||||
EXPECT_TRUE(dut.allowInjection());
|
||||
|
||||
// Above threshold, injection cut
|
||||
Sensor::setMockValue(SensorType::Map, 120);
|
||||
// Above rising threshold, injection cut
|
||||
Sensor::setMockValue(SensorType::Map, 105);
|
||||
dut.updateState(1000, 0);
|
||||
EXPECT_FALSE(dut.allowInjection());
|
||||
|
||||
// Below threshold, should recover
|
||||
Sensor::setMockValue(SensorType::Map, 80);
|
||||
// Below rising threshold, but should have hysteresis, so not cut yet
|
||||
Sensor::setMockValue(SensorType::Map, 95);
|
||||
dut.updateState(1000, 0);
|
||||
EXPECT_FALSE(dut.allowInjection());
|
||||
|
||||
// Below falling threshold, fuel restored
|
||||
Sensor::setMockValue(SensorType::Map, 79);
|
||||
dut.updateState(1000, 0);
|
||||
EXPECT_TRUE(dut.allowInjection());
|
||||
|
||||
|
|
Loading…
Reference in New Issue