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 = 30; // seconds | ||
40 | ||||
41 | 1 | float rpm = config->veRpmBins[0]; | ||
42 | 1 | float load = config->veLoadBins[0]; | ||
43 | 1 | ClosedLoopFuelResult clInput; | ||
44 | 1 | ClosedLoopFuelResult clResult; | ||
45 | ||||
46 | 1 | clInput.banks[0] = clInput.banks[1] = 1.5; | ||
47 | // Run for 100 sec | |||
48 |
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)) | |
49 | ||||
50 | // Disabled should not affect | |||
51 |
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); | |
52 | ||||
53 | // Enabling | |||
54 | 1 | engineConfiguration->ltft.enabled = true; | ||
55 | 1 | engineConfiguration->ltft.correctionEnabled = true; | ||
56 | ||||
57 | // Run for 100 sec with positive correction | |||
58 | 1 | clInput.banks[0] = clInput.banks[1] = 1.5; | ||
59 |
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)) | |
60 | ||||
61 | // test hiting maxAdd limit | |||
62 |
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); | |
63 | ||||
64 | // Other cells should not be affected | |||
65 |
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); | |
66 | ||||
67 | // Run for 100 sec with negative correction | |||
68 | 1 | clInput.banks[0] = clInput.banks[1] = 0.5; | ||
69 |
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)) | |
70 | ||||
71 | // test hiting maxRemove limit | |||
72 |
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); | |
73 | ||||
74 | // Other cells should not be affected | |||
75 |
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); | |
76 | ||||
77 | #if 0 | |||
78 | rpm = config->veRpmBins[0] - (config->veRpmBins[1] - config->veRpmBins[0]) - 1; | |||
79 | load = config->veLoadBins[0] - (config->veLoadBins[1] - config->veLoadBins[0]) - 1; | |||
80 | // we are not learning, buts but still calculating correction if far outside table | |||
81 | // test far outside | |||
82 | ASSERT_LTFT_RESULT(ltft.getTrims(rpm, load), 1.0, 1.0); | |||
83 | ASSERT_LTFT_RESULT(ltft.getTrims(10000, 1000), 1.0, 1.0); | |||
84 | #endif | |||
85 | 1 | } | ||
86 | ||||
87 | 4 | TEST(LTFT, testSlowCallbackLoadError) { | ||
88 |
1/1✓ Branch 2 taken 1 time.
|
1 | EngineTestHelper eth(engine_type_e::TEST_ENGINE); | |
89 | ||||
90 | 1 | LtftState ltftState; | ||
91 | 1 | LongTermFuelTrim ltft; | ||
92 | ||||
93 | // reset to zero | |||
94 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltftState.load(); | |
95 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltft.init(<ftState); | |
96 | ||||
97 | // mock loading state | |||
98 | 1 | ltft.ltftLearning = false; | ||
99 | 1 | ltft.ltftLoadPending = true; | ||
100 |
1/1✓ Branch 1 taken 1 time.
|
1 | engine->rpmCalculator.setRpmValue(1000); | |
101 | ||||
102 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltft.onSlowCallback(); | |
103 | // still in loading time: | |||
104 |
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); | |
105 |
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); | |
106 | ||||
107 | 1 | ltft.ltftLoadPending = true; | ||
108 | ||||
109 | // too much time loading! | |||
110 |
1/1✓ Branch 1 taken 1 time.
|
1 | advanceTimeUs(8'000'000); | |
111 | ||||
112 |
1/1✓ Branch 1 taken 1 time.
|
1 | ltft.onSlowCallback(); | |
113 |
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); | |
114 |
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); | |
115 | 2 | } | ||
116 |