Conversation
… zeros The exact-zero rejection this branch already carried is right for the firmware fault it was written for and wrong for everything else that makes the counter read backwards. A corrupted non-zero value, a duplicated packet and a reordered one all still added 2^24 ticks - testNonZeroBackwardStepIsStillAWrap asserted exactly that. PR #301 found the gap and fixed the missing half: it detects reordered and duplicated packets by comparing the backward step against a window derived from the sampling rate. That idea is adopted here. Its polarity is not: #301 makes "corrupt" the default and calls something a wrap only when it clears maxTicks - 10 periods, so a roll-over preceded by more than ten lost samples is misread as corruption. Forward motion has to be the default. Each sample is now classified by its modular forward distance from the last: duplicate, reordered, invalid zero, or forward - and forward, which is a wrap when the raw value fell, is what everything else falls through to. Three things in that are load-bearing, each verified by mutation: - The comparison is modular, not on unwrapped values. Asking whether the new candidate is below the last one misses a packet arriving late from BEFORE a wrap boundary: its candidate sits nearly a modulo ahead, so it is accepted, and the next real sample is read as a second wrap. 16777206, 5, 16777206, 70 costs 512 s twice under the old shape. - The window is eight sample periods, not a fraction of the modulo. A reorder swaps adjacent packets; a dropout spanning the wrap point is most of a modulo. At modulo/8 on the 2-byte counter every dropout between 1.75 s and 2.0 s reads as a reorder and the wrap is silently lost - and that is an ordinary Bluetooth gap. - An unknown rate gives a window of zero, never infinity. 32768/0 is POSITIVE_INFINITY in Java, and an infinite window makes every backward step a reorder and loses every wrap - worse than the naive rule being replaced. #301 derives the window without that guard, so a device whose rate has not been read yet silently reverts to the original defect. Callers derive the window per sample through getReorderWindowTicks(), so a rate written mid-session is picked up by the next sample and there is no cached window to reset. It comes from getSamplingRateShimmer(), which is populated on both paths before the first sample is parsed - seeded at construction, set from the SD header before the first record, and set during the Bluetooth connect. Shimmer2 and Shimmer2R get a window of zero. Their tick domain is unsettled - this class divides their 16-bit counter by 32768 while the C# API divides by 1024 - so a rate-derived window would be wrong in one of the two. They keep the behaviour they have always had. The first sample of a stream is passed through rather than measured against the reset state. Under a modular rule a first raw value near the top of the range would otherwise read as a packet reordered across a boundary and place a whole recording one modulo early. Rule and vectors: log-and-stream-common, docs/SHIMMER3_STREAMING_DATA_FORMAT.md section 2.1 and Test/conformance/timestamp_unwrap.json. Co-Authored-By: Mas Azalya <43565312+MAzalya@users.noreply.github.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Superseded by #300, which adopts the half of this that I had missed. Closing here, but What this PR got right, and #300 did notMy branch rejected an exact The six-device table in DEV-1030 is also better evidence of the mechanism than anything I Why the polarity is inverted in #300The rule here makes "corrupt" the default and calls something a roll-over only when the Three things I found simulating this rule against the bytes of the affected recording, 1. At the rate the affected trial actually ran, the fix takes over the whole file.
At the rounded rate the interpolated value overshoots each following real sample by four The duration still comes out right, which is exactly why the manual check looked clean. An 2. An unset rate silently restores the original defect. 3. A roll-over preceded by more than ten lost samples is misread as corruption. This is What else changed on the wayReviewing the merge turned up two problems in my rule, not this one:
Where it is nowThe rule is specified once in
Worth a look at #300 when you have a moment, and thanks for catching the gap. |
|
Closing as superseded by #300 — see the comment above. The reorder/duplicate detection from here is carried across with a Co-Authored-By on the commit; reopen if you would rather take it forward on this branch instead. |
No description provided.