GCC Code Coverage Report


Directory: ./
File: unit_tests/tests/ignition_injection/test_fuel_math.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 100.0% 278 0 278
Functions: 100.0% 43 0 43
Branches: 60.2% 356 0 591
Decisions: 100.0% 10 - 10

Line Branch Decision Exec Source
1 #include "pch.h"
2 #include "fuel_math.h"
3 #include "alphan_airmass.h"
4 #include "maf_airmass.h"
5 #include "speed_density_airmass.h"
6 #include "util/injection_crank_helper.h"
7
8 using ::testing::StrictMock;
9 using ::testing::FloatNear;
10 using ::testing::InSequence;
11 using ::testing::_;
12
13 4 TEST(FuelMath, getStandardAirCharge) {
14
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
15
16 // Miata 1839cc 4cyl
17 1 engineConfiguration->displacement = 1.839f;
18 1 engineConfiguration->cylindersCount = 4;
19
20
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(0.5535934f, getStandardAirCharge());
21
22 // LS 5.3 liter v8
23 1 engineConfiguration->displacement = 5.327f;
24 1 engineConfiguration->cylindersCount = 8;
25
26
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(0.80179232f, getStandardAirCharge());
27
28 // Chainsaw - single cylinder 32cc
29 1 engineConfiguration->displacement = 0.032f;
30 1 engineConfiguration->cylindersCount = 1;
31
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(0.038531788f, getStandardAirCharge());
32
33 // Leopard 1 47.666 liter v12
34 1 engineConfiguration->displacement = 47.666f;
35 1 engineConfiguration->cylindersCount = 12;
36
37
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(4.782959f, getStandardAirCharge());
38 2 }
39
40 4 TEST(AirmassModes, AlphaNNormal) {
41
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
42 // 4 cylinder 4 liter = easy math
43 1 engineConfiguration->displacement = 4.0f;
44 1 engineConfiguration->cylindersCount = 4;
45
46
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> veTable;
47
48
6/6
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 16 taken 1 time.
✓ Branch 20 taken 1 time.
3 EXPECT_CALL(veTable, getValue(1200, FloatNear(0.71f, EPS4D)))
49
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(35.0f));
50
51
1/1
✓ Branch 2 taken 1 time.
1 AlphaNAirmass dut(veTable);
52
53 // that's 0.71% not 71%
54
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 0.71f);
55
56 // Mass of 1 liter of air * VE
57 1 mass_t expectedAirmass = 1.2047f * 0.35f;
58
59
1/1
✓ Branch 1 taken 1 time.
1 auto result = dut.getAirmass(1200, false);
60
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(result.CylinderAirmass, expectedAirmass, EPS4D);
61
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(result.EngineLoadPercent, 0.71f, EPS4D);
62 2 }
63
64 4 TEST(AirmassModes, AlphaNUseIat) {
65
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
66 // 4 cylinder 4 liter = easy math
67 1 engineConfiguration->displacement = 4.0f;
68 1 engineConfiguration->cylindersCount = 4;
69
70
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> veTable;
71
72
6/6
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 16 taken 1 time.
✓ Branch 20 taken 1 time.
3 EXPECT_CALL(veTable, getValue(1200, FloatNear(0.71f, EPS4D)))
73
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillRepeatedly(Return(35.0f));
74
75
1/1
✓ Branch 2 taken 1 time.
1 AlphaNAirmass dut(veTable);
76
77 // that's 0.71% not 71%
78
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 0.71f);
79
80 // Mass of 1 liter of air * VE
81 1 mass_t expectedAirmass = 1.2047f * 0.35f;
82
83
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(dut.getAirmass(1200, false).CylinderAirmass, expectedAirmass, EPS4D);
84
85 1 engineConfiguration->alphaNUseIat = true;
86
87 // Cold we get more airmass
88 1 float expectedAirmassCold = expectedAirmass * (273.0f + 20) / (273.0f + 0);
89
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Iat, 0);
90
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(dut.getAirmass(1200, false).CylinderAirmass, expectedAirmassCold, EPS4D);
91
92 // Hot we get less airmass
93 1 float expectedAirmassHot = expectedAirmass * (273.0f + 20) / (273.0f + 40);
94
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Iat, 40);
95
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(dut.getAirmass(1200, false).CylinderAirmass, expectedAirmassHot, EPS4D);
96 2 }
97
98 4 TEST(AirmassModes, AlphaNFailedTps) {
99
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
100
101 // Shouldn't get called
102
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> veTable;
103
104
1/1
✓ Branch 2 taken 1 time.
1 AlphaNAirmass dut(veTable);
105
106 // explicitly reset the sensor
107
1/1
✓ Branch 1 taken 1 time.
1 Sensor::resetMockValue(SensorType::Tps1);
108 // Ensure that it's actually failed
109
3/9
✓ Branch 3 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
✓ Branch 33 taken 1 time.
✗ Branch 34 not taken.
1 ASSERT_FALSE(Sensor::get(SensorType::Tps1).Valid);
110
111
1/1
✓ Branch 2 taken 1 time.
1 auto result = dut.getAirmass(1200, false);
112
2/6
✓ Branch 3 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 11 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
1 EXPECT_EQ(result.CylinderAirmass, 0);
113 1 }
114
115 4 TEST(AirmassModes, MafNormal) {
116
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
117 1 engineConfiguration->cylindersCount = 4;
118 1 engineConfiguration->displacement = 1.3;
119 1 engineConfiguration->fuelAlgorithm = engine_load_mode_e::LM_REAL_MAF;
120 1 engineConfiguration->injector.flow = 200;
121
122
1/1
✓ Branch 2 taken 1 time.
1 MockVp3d veTable;
123 // Ensure that the correct cell is read from the VE table
124
6/6
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 16 taken 1 time.
✓ Branch 20 taken 1 time.
3 EXPECT_CALL(veTable, getValue(6000, FloatNear(70.9814f, EPS4D)))
125
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(75.0f));
126
127
1/1
✓ Branch 2 taken 1 time.
1 MafAirmass dut(veTable);
128
129
1/1
✓ Branch 1 taken 1 time.
1 auto airmass = dut.getAirmassImpl(200, 6000, false);
130
131 // Check results
132
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(0.277777f * 0.75f, airmass.CylinderAirmass, EPS4D);
133
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(70.9814f, airmass.EngineLoadPercent, EPS4D);
134 2 }
135
136 4 TEST(AirmassModes, VeOverride) {
137
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> veTable;
138
139 {
140
1/1
✓ Branch 2 taken 1 time.
1 InSequence is;
141
142 // Default
143
8/8
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 23 taken 1 time.
✓ Branch 26 taken 1 time.
✓ Branch 29 taken 1 time.
1 EXPECT_CALL(veTable, getValue(_, 10.0f)).WillOnce(Return(0));
144 // TPS
145
8/8
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 23 taken 1 time.
✓ Branch 26 taken 1 time.
✓ Branch 29 taken 1 time.
1 EXPECT_CALL(veTable, getValue(_, 30.0f)).WillOnce(Return(0));
146 1 }
147
148 struct DummyAirmassModel : public AirmassVeModelBase {
149 DummyAirmassModel(const ValueProvider3D& veTable) : AirmassVeModelBase(veTable) {}
150
151 AirmassResult getAirmass(float rpm, bool postState) override {
152 // Default load value 10, will be overriden
153 getVe(rpm, 10.0f, postState);
154
155 return {};
156 }
157 };
158
159
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
160
1/1
✓ Branch 2 taken 1 time.
1 DummyAirmassModel dut(veTable);
161
162 // Use default mode - will call with 10
163
1/1
✓ Branch 1 taken 1 time.
1 dut.getAirmass(0, true);
164
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_FLOAT_EQ(engine->engineState.veTableYAxis, 10.0f);
165
166 // Override to TPS
167 1 engineConfiguration->veOverrideMode = VE_TPS;
168
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 30.0f);
169
1/1
✓ Branch 1 taken 1 time.
1 dut.getAirmass(0, true);
170
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_FLOAT_EQ(engine->engineState.veTableYAxis, 30.0f);
171 2 }
172
173 4 TEST(AirmassModes, FallbackMap) {
174
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> veTable;
175
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> mapFallback;
176
177 // Failed map -> use 75
178 {
179
1/1
✓ Branch 2 taken 1 time.
1 InSequence is;
180
181 // Working map -> return 33 (should be unused)
182
8/8
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 23 taken 1 time.
✓ Branch 26 taken 1 time.
✓ Branch 29 taken 1 time.
1 EXPECT_CALL(mapFallback, getValue(1234, 20)).WillOnce(Return(33));
183
184 // Failed map -> use 75
185
8/8
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 23 taken 1 time.
✓ Branch 26 taken 1 time.
✓ Branch 29 taken 1 time.
1 EXPECT_CALL(mapFallback, getValue(5678, 20)).WillOnce(Return(75));
186 1 }
187
188
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
189
190
1/1
✓ Branch 2 taken 1 time.
1 SpeedDensityAirmass dut(veTable, mapFallback);
191
192 // TPS at 20%
193
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 20);
194
195 // Working MAP sensor at 40 kPa
196
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Map, 40);
197
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1234, false), 40);
198
199 // Failed MAP sensor, should use table
200
1/1
✓ Branch 1 taken 1 time.
1 Sensor::resetMockValue(SensorType::Map);
201
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(5678, false), 75);
202 2 }
203
204 void setInjectionMode(int value);
205
206 #if FUEL_RPM_COUNT == 16
207 4 TEST(FuelMath, testDifferentInjectionModes) {
208
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
209
1/1
✓ Branch 1 taken 1 time.
1 setupSimpleTestEngineWithMafAndTT_ONE_trigger(&eth);
210
211
5/5
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 17 taken 1 time.
3 EXPECT_CALL(*eth.mockAirmass, getAirmass(_, _))
212
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillRepeatedly(Return(AirmassResult{1.3440001f, 50.0f}));
213
214
1/1
✓ Branch 1 taken 1 time.
1 setInjectionMode((int)IM_BATCH);
215
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
216
2/7
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ( 20, engine->engineState.injectionDuration) << "injection while batch";
217
218
1/1
✓ Branch 1 taken 1 time.
1 setInjectionMode((int)IM_SIMULTANEOUS);
219
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
220
2/7
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ( 10, engine->engineState.injectionDuration) << "injection while simultaneous";
221
222
1/1
✓ Branch 1 taken 1 time.
1 setInjectionMode((int)IM_SEQUENTIAL);
223
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
224
2/7
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ( 40, engine->engineState.injectionDuration) << "injection while IM_SEQUENTIAL";
225
226
1/1
✓ Branch 1 taken 1 time.
1 setInjectionMode((int)IM_SINGLE_POINT);
227
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
228
2/7
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ( 40, engine->engineState.injectionDuration) << "injection while IM_SINGLE_POINT";
229
3/8
✓ Branch 3 taken 1 time.
✓ Branch 8 taken 1 time.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 time.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✗ Branch 25 not taken.
✗ Branch 28 not taken.
1 EXPECT_EQ( 0u, eth.recentWarnings()->getCount()) << "warningCounter#testDifferentInjectionModes";
230 2 }
231 #endif //FUEL_RPM_COUNT == 16
232
233 #if FUEL_RPM_COUNT == 16
234 4 TEST(FuelMath, deadtime) {
235
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
236
237
1/1
✓ Branch 1 taken 1 time.
1 setupSimpleTestEngineWithMafAndTT_ONE_trigger(&eth);
238
239
5/5
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 17 taken 1 time.
3 EXPECT_CALL(*eth.mockAirmass, getAirmass(_, _))
240
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillRepeatedly(Return(AirmassResult{1.3440001f, 50.0f}));
241
242 // First test with no deadtime
243
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
244
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_FLOAT_EQ( 20, engine->engineState.injectionDuration);
245
246 // Now add some deadtime
247
1/1
✓ Branch 1 taken 1 time.
1 setFlatInjectorLag(2.0f);
248
249 // Should have deadtime now!
250
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
251
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_FLOAT_EQ( 20 + 2, engine->engineState.injectionDuration);
252 2 }
253 #endif //FUEL_RPM_COUNT == 16
254
255 #ifndef SUPPRESS_FUEL_MATH_FUEL_TRIM_TEST
256 #if FUEL_RPM_COUNT == 16
257 4 TEST(FuelMath, CylinderFuelTrim) {
258
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
259
260
5/5
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 17 taken 1 time.
3 EXPECT_CALL(*eth.mockAirmass, getAirmass(_, _))
261
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillRepeatedly(Return(AirmassResult{1, 50.0f}));
262
263
1/1
✓ Branch 1 taken 1 time.
1 setTable(config->fuelTrims[0].table, -4);
264
1/1
✓ Branch 1 taken 1 time.
1 setTable(config->fuelTrims[1].table, -2);
265
1/1
✓ Branch 1 taken 1 time.
1 setTable(config->fuelTrims[2].table, 2);
266
1/1
✓ Branch 1 taken 1 time.
1 setTable(config->fuelTrims[3].table, 4);
267
268 // run the fuel math
269
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
270
271 // Check that each cylinder gets the expected amount of fuel
272 1 float unadjusted = 0.072142f;
273
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.injectionMass[0], unadjusted * 0.96, EPS4D);
274
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.injectionMass[1], unadjusted * 0.98, EPS4D);
275
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.injectionMass[2], unadjusted * 1.02, EPS4D);
276
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.injectionMass[3], unadjusted * 1.04, EPS4D);
277 2 }
278 #endif //FUEL_RPM_COUNT == 16
279 #endif
280
281 struct MockIdle : public MockIdleController {
282 bool isIdling = false;
283
284 24 bool isIdlingOrTaper() const override {
285 24 return isIdling;
286 }
287 };
288
289 4 TEST(FuelMath, IdleVeTable) {
290
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
291
292
1/1
✓ Branch 2 taken 1 time.
1 MockAirmass dut;
293
294 // Install mock idle controller
295
1/1
✓ Branch 2 taken 1 time.
1 MockIdle idler;
296
1/1
✓ Branch 1 taken 1 time.
1 engine->engineModules.get<IdleController>().set(&idler);
297
298 // Main VE table returns 50
299
8/8
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 23 taken 1 time.
✓ Branch 26 taken 1 time.
✓ Branch 29 taken 1 time.
1 EXPECT_CALL(dut.veTable, getValue(_, _)).WillRepeatedly(Return(50));
300
301 // Idle VE table returns 40
302 1 setTable(config->idleVeTable, 40);
303
304 // Enable separate idle VE table
305 1 engineConfiguration->useSeparateVeForIdle = true;
306 1 engineConfiguration->idlePidDeactivationTpsThreshold = 10;
307
308 // Set TPS so this works
309
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 0);
310
311 // Gets normal VE table
312 1 idler.isIdling = false;
313
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.5f);
314
315 // Gets idle VE table
316 1 idler.isIdling = true;
317
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.4f);
318
319 // Below half threshold, fully use idle VE table
320
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 0);
321
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.4f);
322
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 2);
323
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.4f);
324
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 5);
325
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.4f);
326
327 // As TPS approaches idle threshold, phase-out the idle VE table
328
329
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 6);
330
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.42f);
331
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 8);
332
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.46f);
333
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 10);
334
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getVe(1000, 50, false), 0.5f);
335 2 }
336
337 4 TEST(FuelMath, getCycleFuelMassTest) {
338
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
339
1/1
✓ Branch 1 taken 1 time.
1 setLinearCurve(config->crankingTpsCoef, /*from*/1, /*to*/8, 1);
340
1/1
✓ Branch 1 taken 1 time.
1 setTestFuelCrankingTable(4000 * 1.5f);
341
342
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::DriverThrottleIntent, 35.0f);
343
344 // test running fuel as crank fuel case
345 1 engineConfiguration->useRunningMathForCranking = true;
346
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(getCycleFuelMass(true, 0.05f), 0.171f, EPS3D);
347
348 1 engineConfiguration->useRunningMathForCranking = false;
349
350 // simulate cranking
351
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1 time.
6 for (size_t i = 0; i < 5; i++) {
352
1/1
✓ Branch 1 taken 5 times.
5 engine->rpmCalculator.onNewEngineCycle();
353 }
354
355
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(getCycleFuelMass(true, 0.05f), 20.571f, EPS3D);
356
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.crankingFuel.coolantTemperatureCoefficient, 1, EPS3D);
357
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.crankingFuel.tpsCoefficient, 3.428f, EPS3D);
358
359
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 1 time.
11 for (size_t i = 0; i < 10; i++) {
360
1/1
✓ Branch 1 taken 10 times.
10 engine->rpmCalculator.onNewEngineCycle();
361 }
362
363
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(getCycleFuelMass(true, 0.05f), 20.571f, EPS3D);
364
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.crankingFuel.coolantTemperatureCoefficient, 1, EPS3D);
365
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.crankingFuel.tpsCoefficient, 3.428f, EPS3D);
366
367 // simulate TPS error:
368
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setInvalidMockValue(SensorType::DriverThrottleIntent);
369
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 1 time.
11 for (size_t i = 0; i < 10; i++) {
370
1/1
✓ Branch 1 taken 10 times.
10 engine->rpmCalculator.onNewEngineCycle();
371 }
372
373
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(getCycleFuelMass(true, 0.05f), 6.0f, EPS3D);
374
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->engineState.crankingFuel.tpsCoefficient, 1, EPS3D);
375 2 }
376
377 4 TEST(FuelMath, postCrankingFactorAxis){
378
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
379
1/1
✓ Branch 1 taken 1 time.
1 setupSimpleTestEngineWithMafAndTT_ONE_trigger(&eth);
380
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
381
1/1
✓ Branch 1 taken 1 time.
1 setTestFuelCrankingTable(4000 * 1.5f);
382
383 // simulate cranking
384
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 30 times.
✓ Decision 'false' taken 1 time.
31 for (size_t i = 0; i < 30; i++) {
385
1/1
✓ Branch 1 taken 30 times.
30 engine->rpmCalculator.onNewEngineCycle();
386 }
387
1/1
✓ Branch 1 taken 1 time.
1 setLinearCurve(config->postCrankingCLTBins, /*from*/-20, /*to*/80, 20);
388
1/1
✓ Branch 1 taken 1 time.
1 setLinearCurve(config->postCrankingDurationBins, /*from*/0, /*to*/150, 40);
389 1 setTable(config->postCrankingFactor, 5);
390
391 1 config->postCrankingFactor[0][0] = 1;
392 1 config->postCrankingFactor[0][1] = 1;
393
394
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Clt, -20);
395
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
396
397
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->fuelComputer.running.postCrankingFuelCorrection, 1, EPS3D);
398
399
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Clt, 70);
400
1/1
✓ Branch 1 taken 1 time.
1 engine->periodicFastCallback();
401
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(engine->fuelComputer.running.postCrankingFuelCorrection, 5, EPS3D);
402 2 }
403
404
405 4 TEST(AirmassModes, PredictiveMapCalculation) {
406
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> veTable;
407
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockVp3d> mapFallback;
408
409 // Configure the mock MAP estimation table to return specific values
410
5/5
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 9 taken 1 time.
✓ Branch 12 taken 1 time.
✓ Branch 16 taken 1 time.
3 EXPECT_CALL(mapFallback, getValue(1500, 30.0f))
411
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillRepeatedly(Return(85.0f)); // Predicted MAP is 85 kPa
412
413
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
414
415 // Configure engine for predictive MAP mode
416 1 engineConfiguration->accelEnrichmentMode = AE_MODE_PREDICTIVE_MAP;
417
418 // FIXME! setLinearCurve(config->predictiveMapBlendDurationValues, /*value*/0.5, /*precision*/0.1);
419
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 1 time.
5 for (auto index = 0;index < efi::size(config->predictiveMapBlendDurationValues);index++) {
420 4 config->predictiveMapBlendDurationValues[index] = 0.5f;
421 }
422
423 // Create our speed density airmass model
424
1/1
✓ Branch 2 taken 1 time.
1 SpeedDensityAirmass dut(veTable, mapFallback);
425
426 // Setup TPS sensor
427
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Tps1, 30.0f);
428
429 // Setup MAP sensor
430
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Map, 65.0f);
431
432
1/1
✓ Branch 1 taken 1 time.
1 auto& tpsAccel = *engine->module<TpsAccelEnrichment>();
433 // Without an acceleration event, we should get the actual MAP sensor value
434
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1500, false), 65.0f);
435
436 // Now trigger acceleration event
437 1 tpsAccel.m_accelEventJustOccurred = true;
438
439 // Now the predictive MAP should be used, which is 85 kPa from the map estimation table
440
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1500, true), 85.0f);
441
442 // Subsequent calls should still give predicted until blend starts
443
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1500, false), 85.0f);
444
445 // Test at 25% blend progress (75% predicted, 25% actual)
446 // Simulate passing 25% of blend time (125ms)
447
1/1
✓ Branch 1 taken 1 time.
1 eth.moveTimeForwardMs(125); // 25% of 500ms
448 // Expected: 85 - (85-65) * 0.25 = 85 - 5 = 80
449
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(dut.getMap(1500, false), 80.0f, EPS4D);
450
451 // At 50% blend progress
452
1/1
✓ Branch 1 taken 1 time.
1 eth.moveTimeForwardMs(125); // Now at 250ms
453 // Expected: 85 - (85-65) * 0.5 = 85 - 10 = 75
454
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(dut.getMap(1500, false), 75.0f, EPS4D);
455
456 // At 75% blend progress
457
1/1
✓ Branch 1 taken 1 time.
1 eth.moveTimeForwardMs(125); // Now at 375ms
458 // Expected: 85 - (85-65) * 0.75 = 85 - 15 = 70
459
3/7
✓ Branch 2 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.
1 EXPECT_NEAR(dut.getMap(1500, false), 70.0f, EPS4D);
460
461 // Test after blend is complete - should return to sensor value
462 // Move time past blend duration (more than 500ms total)
463
1/1
✓ Branch 1 taken 1 time.
1 eth.moveTimeForwardMs(125); // Now at 500ms
464 // Should be back to the actual MAP value
465
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1500, false), 65.0f);
466
467 // Test MAP prediction cancellation
468 1 tpsAccel.m_accelEventJustOccurred = true;
469
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1500, false), 85.0f);
470
471 // Now increase the actual MAP to exceed the predicted value
472
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Map, 90.0f);
473
474 // Prediction should be canceled, and we should get the actual MAP
475
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1500, false), 90.0f);
476
477 // 5. Test with failed MAP sensor
478
1/1
✓ Branch 1 taken 1 time.
1 Sensor::resetMockValue(SensorType::Map);
479
480 // Should use the fallback MAP from the table
481
3/7
✓ Branch 2 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.
1 EXPECT_FLOAT_EQ(dut.getMap(1500, false), 85.0f);
482 2 }
483