Add cranking taper duration multiplier based on CLT (#370)

* Add Cranking taper duration multiplier based on CLT

* Fixed same merge error in TS config

* Fixed existing unit test for getCrankingTaperFraction, and added a new one to test multiplier table for cranking taper duration.

* Fixed existing header file for unit test getCrankingTaperFraction

* Changed naming

* changed logic

* Forgot to update name here too

* Forgot to update name here too, second time
This commit is contained in:
Stefan de Kraker 2024-02-26 02:36:30 +01:00 committed by GitHub
parent b26d5ba475
commit 4c65992017
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 84 additions and 14 deletions

View File

@ -79,8 +79,14 @@ IIdleController::Phase IdleController::determinePhase(int rpm, int targetRpm, Se
return Phase::Idling;
}
float IdleController::getCrankingTaperFraction() const {
return (float)engine->rpmCalculator.getRevolutionCounterSinceStart() / engineConfiguration->afterCrankingIACtaperDuration;
float IdleController::getCrankingTaperFraction(float clt) const {
float taperDuration = engineConfiguration->afterCrankingIACtaperDuration;
if (engineConfiguration->useCrankingIdleTaperTableSetting) {
taperDuration *= interpolate2d(clt, config->cltCrankingTaperCorrBins, config->cltCrankingTaperCorr);
}
return (float)engine->rpmCalculator.getRevolutionCounterSinceStart() / taperDuration;
}
float IdleController::getCrankingOpenLoop(float clt) const {
@ -309,7 +315,7 @@ float IdleController::getIdlePosition(float rpm) {
m_lastTargetRpm = targetRpm;
// Determine cranking taper
float crankingTaper = getCrankingTaperFraction();
float crankingTaper = getCrankingTaperFraction(clt);
// Determine what operation phase we're in - idling or not
float vehicleSpeed = Sensor::getOrZero(SensorType::VehicleSpeed);

View File

@ -30,7 +30,7 @@ struct IIdleController {
virtual float getRunningOpenLoop(float rpm, float clt, SensorResult tps) = 0;
virtual float getOpenLoop(Phase phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction) = 0;
virtual float getClosedLoop(Phase phase, float tps, int rpm, int target) = 0;
virtual float getCrankingTaperFraction() const = 0;
virtual float getCrankingTaperFraction(float clt) const = 0;
virtual bool isIdlingOrTaper() const = 0;
virtual float getIdleTimingAdjustment(int rpm) = 0;
};
@ -49,7 +49,7 @@ public:
// PHASE DETERMINATION: what is the driver trying to do right now?
Phase determinePhase(int rpm, int targetRpm, SensorResult tps, float vss, float crankingTaperFraction) override;
float getCrankingTaperFraction() const override;
float getCrankingTaperFraction(float clt) const override;
// OPEN LOOP CORRECTIONS
percent_t getCrankingOpenLoop(float clt) const override;

View File

@ -981,6 +981,7 @@ bit skippedWheelOnCam,"On camshaft","On crankshaft";Where is your primary skippe
bit complexWallModel,"Advanced (tables)","Basic (constants)";Should we use tables to vary tau/beta based on CLT/MAP, or just with fixed values?
bit alwaysInstantRpm
bit isMapAveragingEnabled
bit useCrankingIdleTaperTableSetting; If enabled, use separate temperature multiplier table for cranking taper duration.
bit overrideCrankingIacSetting;If enabled, use separate temperature multiplier table for cranking idle position.\nIf disabled, use normal running multiplier table applied to the cranking base position.
bit useSeparateAdvanceForIdle;This activates a separate ignition timing table for idle conditions, this can help idle stability by using ignition retard and advance either side of the desired idle speed. Extra retard at low idle speeds will prevent stalling and extra advance at high idle speeds can help reduce engine power and slow the idle speed.
bit isWaveAnalyzerEnabled
@ -1556,6 +1557,9 @@ uint8_t[PEDAL_TO_TPS_SIZE] autoscale pedalToTpsRpmBins;;"RPM", 100, 0, 0, 25000,
float[CLT_CRANKING_CURVE_SIZE] cltCrankingCorrBins;CLT-based cranking position multiplier for simple manual idle controller;"C", 1, 0, -100, 250, 2
float[CLT_CRANKING_CURVE_SIZE] cltCrankingCorr ;CLT-based cranking position multiplier for simple manual idle controller;"%", 1, 0, 0, 500, 2
int8_t[CLT_CRANKING_CURVE_SIZE] cltCrankingTaperCorrBins;CLT-based taper duration multiplier for simple manual idle controller;"C", 1, 0, -100, 120, 2
uint8_t[CLT_CRANKING_CURVE_SIZE] autoscale cltCrankingTaperCorr ;CLT-based taper duration multiplier for simple manual idle controller;"%", 0.02, 0, 0, 5, 2
uint8_t[IDLE_ADVANCE_CURVE_SIZE] autoscale idleAdvanceBins;Optional timing advance table for Idle (see useSeparateAdvanceForIdle);"RPM", 50, 0, 0, 12000, 0
float[IDLE_ADVANCE_CURVE_SIZE] idleAdvance ;Optional timing advance table for Idle (see useSeparateAdvanceForIdle);"deg", 1, 0, -20, 90, 1
uint8_t[IDLE_VE_SIZE] autoscale idleVeRpmBins;;"RPM", 10, 0, 0, 2500, 0

View File

@ -543,6 +543,14 @@ enable2ndByteCanID = false
yBins = cltCrankingCorr
gauge = CLTGauge
curve = cltCrankingTaperDurationCurve, "Cranking taper duration multiplier"
columnLabel = "Coolant", "Multiplier"
xAxis = -40, 120, 9
yAxis = 0, 3, 10
xBins = cltCrankingTaperCorrBins, coolant
yBins = cltCrankingTaperCorr
gauge = CLTGauge
curve = cltIdleRPMCurve, "Idle Target RPM"
columnLabel = "Coolant", "RPM"
xAxis = -40, 120, 9
@ -1790,6 +1798,7 @@ menuDialog = main
subMenu = std_separator
subMenu = cltCrankingCurve, "Cranking IAC CLT multiplier", 0, {overrideCrankingIacSetting == 1}
subMenu = cltCrankingTaperDurationCurve, "Cranking taper duration multiplier", 0, {useCrankingIdleTaperTableSetting == 1}
menu = "&Idle"
subMenu = idleSettings, "Idle settings"
@ -3823,6 +3832,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@@@ts_command_e_TS_
field = "Cranking base IAC position", crankingIACposition
field = "After cranking IAC taper duration",afterCrankingIACtaperDuration
field = "Override cranking IAC CLT multiplier", overrideCrankingIacSetting
field = "Use cranking taper duration multiplier", useCrankingIdleTaperTableSetting
dialog = crankingIgnition, "Ignition"
field = "Timing Advance mode", useSeparateAdvanceForCranking

View File

@ -130,7 +130,7 @@ class MockIdleController : public IIdleController {
MOCK_METHOD(float, getRunningOpenLoop, (float rpm, float clt, SensorResult tps), (override));
MOCK_METHOD(float, getOpenLoop, (IIdleController::Phase phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction), (override));
MOCK_METHOD(float, getClosedLoop, (IIdleController::Phase phase, float tps, int rpm, int target), (override));
MOCK_METHOD(float, getCrankingTaperFraction, (), (const, override));
MOCK_METHOD(float, getCrankingTaperFraction, (float clt), (const, override));
MOCK_METHOD(bool, isIdlingOrTaper, (), (const, override));
MOCK_METHOD(float, getIdleTimingAdjustment, (int rpm), (override));
};

View File

@ -275,28 +275,78 @@ TEST(idle_v2, getCrankingTaperFraction) {
EngineTestHelper eth(engine_type_e::TEST_ENGINE);
StrictMock<MockOpenLoopIdler> dut;
float expectedClt = 37;
engineConfiguration->afterCrankingIACtaperDuration = 500;
engineConfiguration->useCrankingIdleTaperTableSetting = false;
// 0 cycles - no taper yet, pure cranking value
EXPECT_FLOAT_EQ(0, dut.getCrankingTaperFraction());
EXPECT_FLOAT_EQ(0, dut.getCrankingTaperFraction(expectedClt));
// 250 cycles - half way, 50% each value -> outputs 50
for (size_t i = 0; i < 250; i++) {
engine->rpmCalculator.onNewEngineCycle();
}
EXPECT_FLOAT_EQ(0.5f, dut.getCrankingTaperFraction());
EXPECT_FLOAT_EQ(0.5f, dut.getCrankingTaperFraction(expectedClt));
// 500 cycles - fully tapered, should be running value
for (size_t i = 0; i < 250; i++) {
engine->rpmCalculator.onNewEngineCycle();
}
EXPECT_FLOAT_EQ(1, dut.getCrankingTaperFraction());
EXPECT_FLOAT_EQ(1, dut.getCrankingTaperFraction(expectedClt));
// 1000 cycles - still fully tapered, should be running value
for (size_t i = 0; i < 500; i++) {
engine->rpmCalculator.onNewEngineCycle();
}
EXPECT_FLOAT_EQ(2, dut.getCrankingTaperFraction());
EXPECT_FLOAT_EQ(2, dut.getCrankingTaperFraction(expectedClt));
}
TEST(idle_v2, getCrankingTaperFractionWithMultiplier) {
EngineTestHelper eth(engine_type_e::TEST_ENGINE);
StrictMock<MockOpenLoopIdler> dut;
float expectedClt = 40;
engineConfiguration->afterCrankingIACtaperDuration = 200;
engineConfiguration->useCrankingIdleTaperTableSetting = true;
float curve[CLT_CRANKING_CURVE_SIZE] = {
1.0, // 0C
1.0, // 10C
1.0, // 20C
0.5, // 30C
0.4, // 40C
0.3, // 50C
0.2, // 60C
0.1 // 70C
};
for (int i = 0; i < CLT_CRANKING_CURVE_SIZE; i++) {
config->cltCrankingTaperCorrBins[i] = i * 10;
config->cltCrankingTaperCorr[i] = curve[i];
}
// 0 cycles - no taper yet, pure cranking value
EXPECT_FLOAT_EQ(0, dut.getCrankingTaperFraction(expectedClt));
// 50 cycles in - total taper duration should be 200 * 0.4 (40C) = 80 cyclyes instead of 200
for (size_t i = 0; i < 50; i++) {
engine->rpmCalculator.onNewEngineCycle();
}
// So 80*0.625 = 50 cycles
EXPECT_FLOAT_EQ(0.625f, dut.getCrankingTaperFraction(expectedClt));
// testing 20C colder, should use 1.0f so 200*0.25 = 50 cycles
EXPECT_FLOAT_EQ(0.25f, dut.getCrankingTaperFraction(expectedClt - 20));
// 200 cycles in - total taper duration should be done by 40C
for (size_t i = 0; i < 150; i++) {
engine->rpmCalculator.onNewEngineCycle();
}
// Taper last only 80 cycles, so 2.5*80 = 200 cycles
EXPECT_FLOAT_EQ(2.5f, dut.getCrankingTaperFraction(expectedClt));
// Taper last full length
EXPECT_FLOAT_EQ(1.0f, dut.getCrankingTaperFraction(expectedClt - 20));
}
TEST(idle_v2, openLoopCoastingTable) {
@ -376,7 +426,7 @@ struct IntegrationIdleMock : public IdleController {
MOCK_METHOD(ICP, determinePhase, (int rpm, int targetRpm, SensorResult tps, float vss, float crankingTaperFraction), (override));
MOCK_METHOD(float, getOpenLoop, (ICP phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction), (override));
MOCK_METHOD(float, getClosedLoop, (ICP phase, float tps, int rpm, int target), (override));
MOCK_METHOD(float, getCrankingTaperFraction, (), (const, override));
MOCK_METHOD(float, getCrankingTaperFraction, (float clt), (const, override));
};
TEST(idle_v2, IntegrationManual) {
@ -394,7 +444,7 @@ TEST(idle_v2, IntegrationManual) {
.WillOnce(Return(1000));
// 30% of the way through cranking taper
EXPECT_CALL(dut, getCrankingTaperFraction())
EXPECT_CALL(dut, getCrankingTaperFraction(expectedClt))
.WillOnce(Return(0.3f));
// Determine phase will claim we're idling
@ -427,7 +477,7 @@ TEST(idle_v2, IntegrationAutomatic) {
.WillOnce(Return(1000));
// 40% of the way through cranking taper
EXPECT_CALL(dut, getCrankingTaperFraction())
EXPECT_CALL(dut, getCrankingTaperFraction(expectedClt))
.WillOnce(Return(0.4f));
// Determine phase will claim we're idling
@ -463,7 +513,7 @@ TEST(idle_v2, IntegrationClamping) {
.WillOnce(Return(1000));
// 50% of the way through cranking taper
EXPECT_CALL(dut, getCrankingTaperFraction())
EXPECT_CALL(dut, getCrankingTaperFraction(expectedClt))
.WillOnce(Return(0.5f));
// Determine phase will claim we're idling