more testable idle logic (#2140)

* header

* test

* impl
This commit is contained in:
Matthew Kennedy 2020-12-26 05:32:01 -08:00 committed by GitHub
parent b2b05659dc
commit 542cb6a420
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 0 deletions

View File

@ -201,6 +201,31 @@ int IdleController::getTargetRpm(float clt) const {
return fsioBump + interpolate2d("cltRpm", clt, CONFIG(cltIdleRpmBins), CONFIG(cltIdleRpm));
}
IIdleController::Phase IdleController::determinePhase(int rpm, int targetRpm, SensorResult tps) const {
if (!engine->rpmCalculator.isRunning()) {
return Phase::Cranking;
}
if (!tps) {
// If the TPS has failed, assume the engine is running
return Phase::Running;
}
// if throttle pressed, we're out of the idle corner
if (tps.Value > CONFIG(idlePidDeactivationTpsThreshold)) {
return Phase::Running;
}
// If rpm too high (but throttle not pressed), we're coasting
int maximumIdleRpm = targetRpm + CONFIG(idlePidRpmUpperLimit);
if (rpm > maximumIdleRpm) {
return Phase::Coasting;
}
// No other conditions met, we are idling!
return Phase::Idling;
}
static percent_t manualIdleController(float cltCorrection DECLARE_ENGINE_PARAMETER_SUFFIX) {
percent_t correctedPosition = cltCorrection * CONFIG(manIdlePosition);

View File

@ -13,6 +13,14 @@
#include "periodic_task.h"
struct IIdleController {
enum class Phase : uint8_t {
Cranking, // Below cranking threshold
Idling, // Below idle RPM, off throttle
Coasting, // Off throttle but above idle RPM
Running, // On throttle
};
virtual Phase determinePhase(int rpm, int targetRpm, SensorResult tps) const;
virtual int getTargetRpm(float clt) const = 0;
};
@ -29,6 +37,9 @@ public:
// TARGET DETERMINATION
int getTargetRpm(float clt) const override;
// PHASE DETERMINATION: what is the driver trying to do right now?
Phase determinePhase(int rpm, int targetRpm, SensorResult tps) const override;
};
void updateIdleControl();

View File

@ -144,3 +144,43 @@ TEST(idle_v2, testTargetRpm) {
EXPECT_FLOAT_EQ(100, dut.getTargetRpm(10));
EXPECT_FLOAT_EQ(500, dut.getTargetRpm(50));
}
using ICP = IIdleController::Phase;
TEST(idle_v2, testDeterminePhase) {
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
IdleController dut;
INJECT_ENGINE_REFERENCE(&dut);
// TPS threshold 5% for easy test
CONFIG(idlePidDeactivationTpsThreshold) = 5;
// RPM window is 100 RPM above target
CONFIG(idlePidRpmUpperLimit) = 100;
// First test stopped engine
engine->rpmCalculator.setRpmValue(0);
EXPECT_EQ(ICP::Cranking, dut.determinePhase(0, 1000, unexpected));
// Now engine is running!
// Controller doesn't need this other than for isCranking()
engine->rpmCalculator.setRpmValue(1000);
// Test invalid TPS, but inside the idle window
EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, unexpected));
// Valid TPS should now be inside the zone
EXPECT_EQ(ICP::Idling, dut.determinePhase(1000, 1000, 0));
// Above TPS threshold should be outside the zone
EXPECT_EQ(ICP::Running, dut.determinePhase(1000, 1000, 10));
// Above target, below (target + upperLimit) should be in idle zone
EXPECT_EQ(ICP::Idling, dut.determinePhase(1099, 1000, 0));
// above upper limit and on throttle should be out of idle zone
EXPECT_EQ(ICP::Running, dut.determinePhase(1101, 1000, 10));
// Below TPS but above RPM should be outside the zone
EXPECT_EQ(ICP::Coasting, dut.determinePhase(1101, 1000, 0));
EXPECT_EQ(ICP::Coasting, dut.determinePhase(5000, 1000, 0));
}