GCC Code Coverage Report


Directory: ./
File: unit_tests/tests/test_knock.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 100.0% 87 0 87
Functions: 100.0% 17 0 17
Branches: 56.2% 91 0 162
Decisions: 100.0% 16 - 16

Line Branch Decision Exec Source
1 #include "pch.h"
2
3 #include "knock_logic.h"
4
5 struct MockKnockController : public KnockControllerBase {
6 3024 float getKnockThreshold() const override {
7 // Knock threshold of 20dBv
8 3024 return 20;
9 }
10
11 3024 float getMaximumRetard() const override {
12 // Maximum 8 degrees retarded
13 3024 return 8;
14 }
15 };
16
17 4 TEST(Knock, frequencyApproximation) {
18 // that's first harmonic while default is knockDetectionUseDoubleFrequency for second harmonic
19
3/8
✓ 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.
✓ Branch 24 taken 1 time.
✗ Branch 25 not taken.
1 ASSERT_NEAR(7.3456, bore2frequency(78/*mm*/), EPS2D);
20 }
21
22 4 TEST(Knock, Retards) {
23
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
24
25 // Aggression of 10%
26 1 engineConfiguration->knockRetardAggression = 10;
27
28 1 MockKnockController dut;
29
1/1
✓ Branch 1 taken 1 time.
1 dut.onFastCallback();
30
31 // No retard unless we knock
32
4/9
✓ 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.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ(dut.getKnockRetard(), 0);
33
34 // Send some weak knocks, should yield no response
35
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++) {
36
1/1
✓ Branch 1 taken 10 times.
10 dut.onKnockSenseCompleted(0, 10, 0);
37 }
38
39
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.getKnockRetard(), 0);
40
41 // Send a strong knock!
42
1/1
✓ Branch 1 taken 1 time.
1 dut.onKnockSenseCompleted(0, 30, 0);
43
44 // Should retard 10% of the distance between current timing and "maximum"
45
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.getKnockRetard(), 2);
46
47 // Send tons of strong knocks, make sure we don't go over the configured limit
48
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 100 times.
✓ Decision 'false' taken 1 time.
101 for (size_t i = 0; i < 100; i++) {
49
1/1
✓ Branch 1 taken 100 times.
100 dut.onKnockSenseCompleted(0, 30, 0);
50 }
51
52
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.getKnockRetard(), 8);
53 1 }
54
55 4 TEST(Knock, Reapply) {
56
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
57
58 1 MockKnockController dut;
59
1/1
✓ Branch 1 taken 1 time.
1 dut.onFastCallback();
60
61 // Aggression of 10%
62 1 engineConfiguration->knockRetardAggression = 10;
63 // Apply 1 degree/second
64 1 engineConfiguration->knockRetardReapplyRate = 1;
65
66 // disable suppress for test
67 1 engineConfiguration->knockSuppressMinTps = 0;
68
69 // Send a strong knock!
70
1/1
✓ Branch 1 taken 1 time.
1 dut.onKnockSenseCompleted(0, 30, 0);
71
72 // Should retard 10% of the distance between current timing and "maximum"
73
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.getKnockRetard(), 2);
74
75 1 constexpr auto fastPeriodSec = FAST_CALLBACK_PERIOD_MS / 1000.0f;
76
77 // call the fast callback, should reapply 1 degree * callback period
78
1/1
✓ Branch 1 taken 1 time.
1 dut.onFastCallback();
79
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.getKnockRetard(), 2 - 1.0f * fastPeriodSec);
80
81 // 10 updates total
82
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 time.
10 for (size_t i = 0; i < 9; i++) {
83
1/1
✓ Branch 1 taken 9 times.
9 dut.onFastCallback();
84 }
85
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.getKnockRetard(), 2 - 10 * 1.0f * fastPeriodSec);
86
87 // Spend a long time without knock
88
2/2
✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 1000 times.
✓ Decision 'false' taken 1 time.
1001 for (size_t i = 0; i < 1000; i++) {
89
1/1
✓ Branch 1 taken 1000 times.
1000 dut.onFastCallback();
90 }
91
92 // Should have no knock retard
93
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.getKnockRetard(), 0);
94 2 }
95
96 4 TEST(Knock, FuelTrim) {
97
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
98
99 // Aggression of 10%
100 1 engineConfiguration->knockFuelTrimAggression = 10;
101 1 engineConfiguration->knockFuelTrim = 30;
102
103 1 MockKnockController dut;
104
1/1
✓ Branch 1 taken 1 time.
1 dut.onFastCallback();
105
106 // No trim unless we knock
107
4/9
✓ 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.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ(dut.getFuelTrimMultiplier(), 1.0);
108
109 // Send some weak knocks, should yield no response
110
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++) {
111
1/1
✓ Branch 1 taken 10 times.
10 dut.onKnockSenseCompleted(0, 10, 0);
112 }
113
114
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.getFuelTrimMultiplier(), 1.0);
115
116 // Send a strong knock!
117
1/1
✓ Branch 1 taken 1 time.
1 dut.onKnockSenseCompleted(0, 30, 0);
118
119 // Should retard 10% of the distance between current timing and "maximum"
120
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.getFuelTrimMultiplier(), 1.03);
121
122 // Send tons of strong knocks, make sure we don't go over the configured limit
123
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 100 times.
✓ Decision 'false' taken 1 time.
101 for (size_t i = 0; i < 100; i++) {
124
1/1
✓ Branch 1 taken 100 times.
100 dut.onKnockSenseCompleted(0, 30, 0);
125 }
126
127
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.getFuelTrimMultiplier(), 1.3);
128 1 }
129
130 4 TEST(Knock, FuelTrimReapply) {
131
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
132
133 1 MockKnockController dut;
134
1/1
✓ Branch 1 taken 1 time.
1 dut.onFastCallback();
135
136 // Aggression of 100%
137 1 engineConfiguration->knockFuelTrimAggression = 10;
138 // Apply 1%/second
139 1 engineConfiguration->knockFuelTrimReapplyRate = 1;
140
141 // fuel trim 30%
142 1 engineConfiguration->knockFuelTrim = 30;
143
144 // disable suppress for test
145 1 engineConfiguration->knockSuppressMinTps = 0;
146
147 // Send a strong knock!
148
1/1
✓ Branch 1 taken 1 time.
1 dut.onKnockSenseCompleted(0, 30, 0);
149
150 // 100% trim
151 1 float trim = 1.03;
152
153 // Should retard 100% of the distance between current timing and "maximum"
154
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.getFuelTrimMultiplier(), trim);
155
156 1 constexpr auto fastPeriodSec = FAST_CALLBACK_PERIOD_MS / 1000.0f;
157
158 // call the fast callback, should reapply 1% trim * callback period
159
1/1
✓ Branch 1 taken 1 time.
1 dut.onFastCallback();
160
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.getFuelTrimMultiplier(), trim - 0.01f * fastPeriodSec);
161
162 // 10 updates total
163
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 time.
10 for (size_t i = 0; i < 9; i++) {
164
1/1
✓ Branch 1 taken 9 times.
9 dut.onFastCallback();
165 }
166
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.getFuelTrimMultiplier(), trim - 10 * 0.01f * fastPeriodSec);
167
168 // Spend a long time without knock
169
2/2
✓ Branch 0 taken 2000 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 2000 times.
✓ Decision 'false' taken 1 time.
2001 for (size_t i = 0; i < 2000; i++) {
170
1/1
✓ Branch 1 taken 2000 times.
2000 dut.onFastCallback();
171 }
172
173 // Should have no knock retard
174
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.getFuelTrimMultiplier(), 1.0);
175 2 }
176