| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | /* | |||
| 2 | * @file test_long_term_fuel_trim.cpp | |||
| 3 | * | |||
| 4 | * @date Jun 6, 2025 | |||
| 5 | * @author Andrey Gusakov, 2025 | |||
| 6 | * @author Andrey Belomutskiy, (c) 2012-2025 | |||
| 7 | */ | |||
| 8 | ||||
| 9 | #include "pch.h" | |||
| 10 | ||||
| 11 | #define ITERATE_TIME(time, action) \ | |||
| 12 | for (size_t i = 0; i < (time * 1000 / FAST_CALLBACK_PERIOD_MS); i++) { \ | |||
| 13 | (action); \ | |||
| 14 | } | |||
| 15 | ||||
| 16 | #define ASSERT_LTFT_RESULT(action, val0, val1) \ | |||
| 17 | { \ | |||
| 18 | ClosedLoopFuelResult clResult = action; \ | |||
| 19 | ASSERT_FLOAT_EQ(clResult.banks[0], val0); \ | |||
| 20 | ASSERT_FLOAT_EQ(clResult.banks[1], val1); \ | |||
| 21 | } | |||
| 22 | ||||
| 23 | 4 | TEST(LTFT, testLearning) | ||
| 24 | { | |||
| 25 |
1/1✓ Branch 2 taken 1 time.
|
1 | EngineTestHelper eth(engine_type_e::TEST_ENGINE); | |
| 26 | ||||
| 27 | 1 | LtftState ltftState; | ||
| 28 | 1 | LongTermFuelTrim ltft; | ||
| 29 | ||||
| 30 | // reset to zero | |||
| 31 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltftState.load(); | |
| 32 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltft.init(<ftState); | |
| 33 | ||||
| 34 | 1 | engineConfiguration->ltft.enabled = false; | ||
| 35 | 1 | engineConfiguration->ltft.correctionEnabled = false; | ||
| 36 | 1 | engineConfiguration->ltft.deadband = 0.5; // % | ||
| 37 | 1 | engineConfiguration->ltft.maxAdd = 15.0; // % | ||
| 38 | 1 | engineConfiguration->ltft.maxRemove = 5; // % | ||
| 39 | 1 | engineConfiguration->ltft.timeConstant[ftRegionIdle] = 30; // seconds | ||
| 40 | 1 | engineConfiguration->ltft.timeConstant[ftRegionOverrun] = 30; // seconds | ||
| 41 | 1 | engineConfiguration->ltft.timeConstant[ftRegionPower] = 30; // seconds | ||
| 42 | 1 | engineConfiguration->ltft.timeConstant[ftRegionCruise] = 30; // seconds | ||
| 43 | ||||
| 44 | 1 | float rpm = config->veRpmBins[0]; | ||
| 45 | 1 | float load = config->veLoadBins[0]; | ||
| 46 | 1 | ClosedLoopFuelResult clInput; | ||
| 47 | 1 | ClosedLoopFuelResult clResult; | ||
| 48 | ||||
| 49 | 1 | clInput.region = ftRegionIdle; | ||
| 50 | 1 | clInput.banks[0] = clInput.banks[1] = 1.5; | ||
| 51 | // Run for 100 sec | |||
| 52 |
3/3✓ Branch 1 taken 20000 times.
✓ Branch 4 taken 20000 times.
✓ Branch 5 taken 1 time.
|
20001 | ITERATE_TIME(100, ltft.learn(clInput, rpm, load)) | |
| 53 | ||||
| 54 | // Disabled should not affect | |||
| 55 |
7/17✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
✓ Branch 31 taken 1 time.
✗ Branch 34 not taken.
✓ Branch 35 taken 1 time.
✗ Branch 38 not taken.
✗ Branch 43 not taken.
✗ Branch 46 not taken.
✓ Branch 53 taken 1 time.
✗ Branch 54 not taken.
|
2 | ASSERT_LTFT_RESULT(ltft.getTrims(rpm, load), 1.0, 1.0); | |
| 56 | ||||
| 57 | // Enabling | |||
| 58 | 1 | engineConfiguration->ltft.enabled = true; | ||
| 59 | 1 | engineConfiguration->ltft.correctionEnabled = true; | ||
| 60 | ||||
| 61 | // Run for 100 sec with positive correction | |||
| 62 | 1 | clInput.banks[0] = clInput.banks[1] = 1.5; | ||
| 63 |
3/3✓ Branch 1 taken 20000 times.
✓ Branch 4 taken 20000 times.
✓ Branch 5 taken 1 time.
|
20001 | ITERATE_TIME(100, ltft.learn(clInput, rpm, load)) | |
| 64 | ||||
| 65 | // test hiting maxAdd limit | |||
| 66 |
7/17✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
✓ Branch 31 taken 1 time.
✗ Branch 34 not taken.
✓ Branch 35 taken 1 time.
✗ Branch 38 not taken.
✗ Branch 43 not taken.
✗ Branch 46 not taken.
✓ Branch 53 taken 1 time.
✗ Branch 54 not taken.
|
2 | ASSERT_LTFT_RESULT(ltft.getTrims(rpm, load), 1.15, 1.15); | |
| 67 | ||||
| 68 | // Other cells should not be affected | |||
| 69 |
7/17✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
✓ Branch 31 taken 1 time.
✗ Branch 34 not taken.
✓ Branch 35 taken 1 time.
✗ Branch 38 not taken.
✗ Branch 43 not taken.
✗ Branch 46 not taken.
✓ Branch 53 taken 1 time.
✗ Branch 54 not taken.
|
2 | ASSERT_LTFT_RESULT(ltft.getTrims(5000, 50), 1.0, 1.0); | |
| 70 | ||||
| 71 | // Run for 100 sec with negative correction | |||
| 72 | 1 | clInput.banks[0] = clInput.banks[1] = 0.5; | ||
| 73 |
3/3✓ Branch 1 taken 20000 times.
✓ Branch 4 taken 20000 times.
✓ Branch 5 taken 1 time.
|
20001 | ITERATE_TIME(100, ltft.learn(clInput, rpm, load)) | |
| 74 | ||||
| 75 | // test hiting maxRemove limit | |||
| 76 |
7/17✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
✓ Branch 31 taken 1 time.
✗ Branch 34 not taken.
✓ Branch 35 taken 1 time.
✗ Branch 38 not taken.
✗ Branch 43 not taken.
✗ Branch 46 not taken.
✓ Branch 53 taken 1 time.
✗ Branch 54 not taken.
|
2 | ASSERT_LTFT_RESULT(ltft.getTrims(rpm, load), 0.95, 0.95); | |
| 77 | ||||
| 78 | // Other cells should not be affected | |||
| 79 |
7/17✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
✓ Branch 31 taken 1 time.
✗ Branch 34 not taken.
✓ Branch 35 taken 1 time.
✗ Branch 38 not taken.
✗ Branch 43 not taken.
✗ Branch 46 not taken.
✓ Branch 53 taken 1 time.
✗ Branch 54 not taken.
|
2 | ASSERT_LTFT_RESULT(ltft.getTrims(5000, 50), 1.0, 1.0); | |
| 80 | ||||
| 81 | #if 0 | |||
| 82 | rpm = config->veRpmBins[0] - (config->veRpmBins[1] - config->veRpmBins[0]) - 1; | |||
| 83 | load = config->veLoadBins[0] - (config->veLoadBins[1] - config->veLoadBins[0]) - 1; | |||
| 84 | // we are not learning, buts but still calculating correction if far outside table | |||
| 85 | // test far outside | |||
| 86 | ASSERT_LTFT_RESULT(ltft.getTrims(rpm, load), 1.0, 1.0); | |||
| 87 | ASSERT_LTFT_RESULT(ltft.getTrims(10000, 1000), 1.0, 1.0); | |||
| 88 | #endif | |||
| 89 | 1 | } | ||
| 90 | ||||
| 91 | 4 | TEST(LTFT, testSlowCallbackLoadError) { | ||
| 92 |
1/1✓ Branch 2 taken 1 time.
|
1 | EngineTestHelper eth(engine_type_e::TEST_ENGINE); | |
| 93 | ||||
| 94 | 1 | LtftState ltftState; | ||
| 95 | 1 | LongTermFuelTrim ltft; | ||
| 96 | ||||
| 97 | // reset to zero | |||
| 98 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltftState.load(); | |
| 99 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltft.init(<ftState); | |
| 100 | ||||
| 101 | // mock loading state | |||
| 102 | 1 | ltft.ltftLearning = false; | ||
| 103 | 1 | ltft.ltftLoadPending = true; | ||
| 104 |
1/1✓ Branch 1 taken 1 time.
|
1 | engine->rpmCalculator.setRpmValue(1000); | |
| 105 | ||||
| 106 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltft.onSlowCallback(); | |
| 107 | // still in loading time: | |||
| 108 |
1/6✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 18 not taken.
✗ Branch 21 not taken.
|
1 | EXPECT_TRUE(ltft.ltftLoadPending); | |
| 109 |
1/6✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 18 not taken.
✗ Branch 21 not taken.
|
1 | EXPECT_FALSE(ltft.ltftLoadError); | |
| 110 | ||||
| 111 | 1 | ltft.ltftLoadPending = true; | ||
| 112 | ||||
| 113 | // too much time loading! | |||
| 114 |
1/1✓ Branch 1 taken 1 time.
|
1 | advanceTimeUs(8'000'000); | |
| 115 | ||||
| 116 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltft.onSlowCallback(); | |
| 117 |
1/6✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 18 not taken.
✗ Branch 21 not taken.
|
1 | EXPECT_FALSE(ltft.ltftLoadPending); | |
| 118 |
1/6✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 18 not taken.
✗ Branch 21 not taken.
|
1 | EXPECT_TRUE(ltft.ltftLoadError); | |
| 119 | 2 | } | ||
| 120 |