| 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 ð) { | ||
| 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 ð, 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(ð, 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(ð, 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(ð, 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(ð, 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(ð, 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(ð, 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(ð, 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(ð, 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 |