Detect the finger at 1.5x the floor, not 2x -- catch the landing frame
Three loop changes have now failed to move quick-tap accuracy: the frame gap
from 500 to 40 ms, the rising edge from two matcher runs to one (3x cheaper
frame), and waking on the touch edge instead of polling. All three left every
press at exactly one frame and the rate at 2 of 10. The transcript says why:
frame 20 @ 4005ms: metric=247 irq=1 finger landing, below threshold
frame 21 @ 4399ms: metric=366 FINGER rej detected; this frame costs ~400 ms
frame 22 @ 4562ms: metric=132 already gone
A frame that detects a finger takes 400-580 ms to process, of which the
trustlet's own REPORT_EVENT is about 300, and a quick tap lasts 400-600 ms.
There is no room for a second frame however early the loop wakes. Speed was
never the constraint.
But the landing frames are being thrown away. 209 and 247 against a 133 floor,
with the interrupt already asserted, discarded by a 2x threshold -- and they are
the only frames a quick tap has to spare. 1.5x puts the threshold at 200: above
the highest idle drift observed (147), below the lowest landing frame seen
(209). The tests pin it between those two measurements rather than to a
constant, and assert that 2x would have discarded both.
Single variable against the labelled 2-of-10 baseline.
This commit is contained in:
parent
578e2321fa
commit
fe6ad11951
2 changed files with 29 additions and 10 deletions
|
|
@ -71,21 +71,28 @@ int main() {
|
|||
Check(!b.Ready(), "uncalibrated");
|
||||
Check(!b.IsFinger(1000000), "an uncalibrated baseline calls nothing a finger");
|
||||
|
||||
for (int i = 0; i < 5; i++) b.Observe(132);
|
||||
for (int i = 0; i < 5; i++) b.Observe(133);
|
||||
Check(b.Ready(), "calibrated after five idle samples");
|
||||
Check(b.Floor() == 132, "floor");
|
||||
Check(b.Threshold() == 264, "threshold is 2x the floor");
|
||||
Check(b.Floor() == 133, "floor");
|
||||
Check(b.Threshold() == 199, "threshold is 1.5x the floor");
|
||||
|
||||
// The real measurement: idle 132-133, finger 345-366.
|
||||
// The real measurement: idle 133 with drift to 147, landing frames
|
||||
// 209-247, full contact 355-375. The threshold has to sit between the
|
||||
// drift and the landing frames -- catching a landing frame is the only
|
||||
// way a quick tap gets a second image.
|
||||
Check(!b.IsFinger(133), "an idle frame is not a finger");
|
||||
Check(b.IsFinger(345) && b.IsFinger(366), "a pressed frame is");
|
||||
Check(!b.IsFinger(147), "the highest observed idle drift is not a finger");
|
||||
Check(b.IsFinger(209), "a LANDING frame is a finger (2x would have missed it)");
|
||||
Check(b.IsFinger(247), "so is a partial-contact frame");
|
||||
Check(b.IsFinger(355) && b.IsFinger(375), "full contact certainly is");
|
||||
Check(133 * 2 > 247, "2x would have discarded both landing frames");
|
||||
|
||||
// The floor is the max of the idle samples. A drifting idle must not
|
||||
// become a false finger.
|
||||
Baseline drift;
|
||||
for (std::int32_t m : {18, 20, 22, 24, 26}) drift.Observe(m);
|
||||
Check(drift.Floor() == 26, "floor takes the maximum, not the first sample");
|
||||
Check(!drift.IsFinger(24), "drift within the idle range is not a finger");
|
||||
Check(!drift.IsFinger(26), "drift within the idle range is not a finger");
|
||||
|
||||
// Extra samples after calibration do not move it.
|
||||
Baseline fixed;
|
||||
|
|
|
|||
Loading…
Reference in a new issue