GCC Code Coverage Report


Directory: ./
File: unit_tests/tests/trigger/test_trigger_noiseless.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 100.0% 76 0 76
Functions: 100.0% 8 0 8
Branches: 43.7% 52 0 119
Decisions: 91.7% 11 - 12

Line Branch Decision Exec Source
1 /**
2 * @file test_trigger_noiseless.cpp
3 *
4 * @date Apr 20, 2018
5 */
6
7 #include "pch.h"
8
9 #include "trigger_decoder.h"
10 #include "event_queue.h"
11 #include "trigger_central.h"
12 #include "main_trigger_callback.h"
13 #include "advance_map.h"
14 #include "speed_density.h"
15 #include "fuel_math.h"
16 #include "spark_logic.h"
17 #include "trigger_universal.h"
18
19 extern bool printTriggerDebug;
20
21 1908 static void fireEvent(EngineTestHelper *eth, bool isRise) {
22 // mostly we fire only rise events (useOnlyRisingEdgeForTrigger=true).
23 // but for noise filtering, both edges should be processed, so we fire falling events too
24
2/2
✓ Branch 0 taken 954 times.
✓ Branch 1 taken 954 times.
2/2
✓ Decision 'true' taken 954 times.
✓ Decision 'false' taken 954 times.
1908 if (isRise)
25 954 eth->firePrimaryTriggerRise();
26
1/2
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 954 times.
✗ Decision 'false' not taken.
954 else if (engineConfiguration->useNoiselessTriggerDecoder)
27 954 eth->firePrimaryTriggerFall();
28 1908 }
29
30 /* ________ __ _ _ __
31 * __|_|_|__| OR | | | |________
32 * spikes signal spikes signal
33 */
34 1856 static void noisyPulse(EngineTestHelper *eth, int idx, int durationUs, bool isRise, int noiseIdx, int durationNoiseUs, int offsetNoiseUs, int numSpikes) {
35 // skip some time at the beginning
36 1856 eth->moveTimeForwardUs(offsetNoiseUs);
37 1856 durationUs -= offsetNoiseUs;
38 // add noise spikes
39
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1849 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 1849 times.
1856 if (idx == noiseIdx) {
40 // calculate the distance between noise spikes (evenly spaced)
41 7 int noiseIntervalUs = (durationUs - durationNoiseUs * numSpikes) / numSpikes;
42
43
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 7 times.
2/2
✓ Decision 'true' taken 26 times.
✓ Decision 'false' taken 7 times.
33 for (int i = 0; i < numSpikes; i++) {
44 // start spike
45 26 fireEvent(eth, isRise);
46 26 eth->moveTimeForwardUs(durationNoiseUs);
47 26 durationUs -= durationNoiseUs;
48 // end spike
49 26 fireEvent(eth, !isRise);
50
51 // add space between spikes
52 26 eth->moveTimeForwardUs(noiseIntervalUs);
53 26 durationUs -= noiseIntervalUs;
54 }
55 }
56
57 // add the rest of pulse period
58 1856 eth->moveTimeForwardUs(durationUs);
59 1856 fireEvent(eth, isRise);
60 1856 }
61
62 8 static void fireNoisyCycle60_2(EngineTestHelper *eth, int numCycles, int durationUs, int noiseIdx, int durationNoiseUs, int offsetNoiseUs, int numSpikes) {
63 8 int idx = 0;
64
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 8 times.
24 for (int cycles = 0; cycles < numCycles; cycles++) {
65 16 int count = 60 - 2 - 1;
66
2/2
✓ Branch 0 taken 912 times.
✓ Branch 1 taken 16 times.
2/2
✓ Decision 'true' taken 912 times.
✓ Decision 'false' taken 16 times.
928 for (int i = 0; i < count; i++) {
67 // rising
68 912 noisyPulse(eth, idx++, durationUs, true, noiseIdx, durationNoiseUs, offsetNoiseUs, numSpikes);
69 // falling
70 912 noisyPulse(eth, idx++, durationUs, false, noiseIdx, durationNoiseUs, offsetNoiseUs, numSpikes);
71 }
72 // skip 2 teeth (durationUs * 4)
73 // and add 1st rising teeth of the next cycle
74 16 noisyPulse(eth, idx++, (durationUs * 4) + durationUs, true, noiseIdx, durationNoiseUs, offsetNoiseUs, numSpikes);
75 // falling
76 16 noisyPulse(eth, idx++, durationUs, false, noiseIdx, durationNoiseUs, offsetNoiseUs, numSpikes);
77 }
78 8 }
79
80 7 static void resetTrigger(EngineTestHelper &eth) {
81 7 eth.applyTriggerWaveform();
82 7 eth.engine.triggerCentral.noiseFilter.resetAccumSignalData();
83 // reset error counter
84 7 eth.engine.triggerCentral.triggerState.totalTriggerErrorCounter = 0;
85 7 }
86
87 1 static void testNoiselessDecoderProcedure(EngineTestHelper &eth, int errorToleranceCnt) {
88 1 printf("*** (bc->useNoiselessTriggerDecoder = %s)\r\n",
89
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 engineConfiguration->useNoiselessTriggerDecoder ? "true" : "false");
90
91 1 resetTrigger(eth);
92
93 // first, no noise
94 1 fireNoisyCycle60_2(&eth, 2, 1000, -1, 0, 0, 0);
95
96 // should be no errors anyway
97
3/9
✓ Branch 3 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 19 not taken.
✗ Branch 22 not taken.
✓ Branch 29 taken 1 time.
✗ Branch 30 not taken.
1 ASSERT_EQ( 0u, engine->triggerCentral.triggerState.totalTriggerErrorCounter) << "testNoiselessDecoderProcedure totalTriggerErrorCounter";
98 // check if we're imitating the 60-2 signal correctly
99
4/10
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
✓ Branch 34 taken 1 time.
✗ Branch 35 not taken.
1 ASSERT_EQ( 0, eth.engine.triggerCentral.triggerState.getCurrentIndex()) << "index #1";
100 // check rpm (60secs / (1000us * 60teeth)) = 1000rpm
101
4/10
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
✓ Branch 34 taken 1 time.
✗ Branch 35 not taken.
1 ASSERT_EQ( 1000, Sensor::getOrZero(SensorType::Rpm)) << "testNoiselessDecoder RPM";
102
103 // add noise1 - 1 spike in the middle of the 2nd rising pulse
104 1 fireNoisyCycle60_2(&eth, 2, 1000, 2, 10, 500, 1);
105
106
3/9
✓ 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.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_NEAR(errorToleranceCnt, engine->triggerCentral.triggerState.totalTriggerErrorCounter, EPS4D) << "testNoiselessDecoder noise#1";
107
108 1 resetTrigger(eth);
109
110 // add noise2 - 1 spike in the middle of the 2nd falling pulse
111 1 fireNoisyCycle60_2(&eth, 2, 1000, 3, 10, 500, 1);
112
113 //assertEqualsM("noise#2", errorToleranceCnt, engine->triggerCentral.triggerState.totalTriggerErrorCounter);
114
115 1 resetTrigger(eth);
116
117 // add noise3 - in the middle of the sync.gap,
118 // so that we cannot tell for sure if it's a start of another 'extra' tooth or just a noise inside the gap,
119 // that's why we used expectedEventCount[] in our filtering algo to make a prediction about gap
120 1 fireNoisyCycle60_2(&eth, 2, 1000, 114, 10, 1500, 1);
121
122 // so everything runs smoothly!
123
3/9
✓ 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.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_NEAR(errorToleranceCnt, engine->triggerCentral.triggerState.totalTriggerErrorCounter, EPS4D) << "noise#3";
124
125 1 resetTrigger(eth);
126
127 // add noise4 - too close to the start of the real next signal, so the noise spike is accepted as a signal
128 // but when the real signal comes shortly afterwards, it we be treated as a noise spike,
129 1 fireNoisyCycle60_2(&eth, 2, 1000, 4, 10, 980, 1);
130
131 // and we won't get out of sync!
132
3/9
✓ 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.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_NEAR(errorToleranceCnt, engine->triggerCentral.triggerState.totalTriggerErrorCounter, EPS4D) << "noise#4";
133
134 1 resetTrigger(eth);
135
136 // add noise5 - one very long 333us noise spike
137 1 fireNoisyCycle60_2(&eth, 2, 1000, 4, 333, 10, 1);
138 // still ok
139
3/9
✓ 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.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_NEAR(errorToleranceCnt, engine->triggerCentral.triggerState.totalTriggerErrorCounter, EPS4D) << "noise#5";
140
141 1 resetTrigger(eth);
142
143 // add noise6 - 10 short spikes across the entire signal pulse
144 1 const int failProofNumSpikes = 10;
145 1 fireNoisyCycle60_2(&eth, 2, 1000, 4, 5, 10, failProofNumSpikes);
146
147 // we barely survived this time
148
3/9
✓ 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.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_NEAR(errorToleranceCnt, engine->triggerCentral.triggerState.totalTriggerErrorCounter, EPS4D) << "testNoiselessDecoder noise#6";
149
150 1 resetTrigger(eth);
151
152 // add noise7 - 34 short spikes across the entire signal pulse
153 1 fireNoisyCycle60_2(&eth, 2, 1000, 2, 10, 10, failProofNumSpikes + 1);
154
155 // alas, this is a hard case even for noiseless decoder, and it fails...
156 // but still we're close to 33% signal-noise ratio threshold - not bad!
157 // so here's an error anyway!
158
3/9
✓ Branch 3 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 19 not taken.
✗ Branch 22 not taken.
✓ Branch 29 taken 1 time.
✗ Branch 30 not taken.
1 ASSERT_EQ( 1u, engine->triggerCentral.triggerState.totalTriggerErrorCounter) << "testNoiselessDecoder noise#7_fail_test";
159 }
160
161 4 TEST(trigger, noiselessDecoder) {
162
1/1
✓ Branch 1 taken 1 time.
1 printf("====================================================================================== testNoiselessDecoder\r\n");
163
164
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
165
166 1 engineConfiguration->ignitionMode = IM_WASTED_SPARK;
167
168 // we'll test on 60-2 wheel
169
1/1
✓ Branch 1 taken 1 time.
1 eth.setTriggerType(trigger_type_e::TT_TOOTHED_WHEEL_60_2);
170
171
3/8
✓ 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.
✓ Branch 26 taken 1 time.
✗ Branch 27 not taken.
1 ASSERT_EQ( 0u, engine->triggerCentral.triggerState.totalTriggerErrorCounter);
172
4/10
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
✓ Branch 34 taken 1 time.
✗ Branch 35 not taken.
1 ASSERT_EQ( 0, Sensor::getOrZero(SensorType::Rpm)) << "testNoiselessDecoder RPM";
173
174 //printTriggerDebug = true;
175
176 #if 0
177 // try normal trigger mode, no noise filtering
178 engineConfiguration->useNoiselessTriggerDecoder = false;
179 // for test validation, it should be 1 trigger error
180 testNoiselessDecoderProcedure(eth, 1);
181 #endif
182
183 // now enable our noise filtering algo
184 1 engineConfiguration->useNoiselessTriggerDecoder = true;
185 // should be 0 errors!
186
1/1
✓ Branch 1 taken 1 time.
1 testNoiselessDecoderProcedure(eth, 0);
187
188 //printTriggerDebug = false;
189 1 }
190