feat(offset): detector v3 — pre-trigger floor with a constant-floor test

Brian's method, and better than v2's whole-record median: the pre-trigger
window is definitionally quiet (the buffer captured before the trigger fired),
whereas a median is merely robust to the event. Requiring the floor to hold
across pre-trigger / middle / end rejects transients that a median cannot.

    per channel:  pre/mid/end medians, spread = max - min
    offset when   |pre| >= floor AND spread <= 0.02 in/s
    real fault    >= 3 consecutive flagged events on that channel

The empirical noise floor justifies the threshold and validates the decoder:
across 19,244 non-flagged channel-events the pre-trigger floor is 62.7% exactly
0.000, 94.5% within +/-1 quantisation unit, median +0.0000, mean -0.0008. There
is no systematic zero-point bias — an independent confirmation of the
32000-count geo scale.

The result is threshold-insensitive across a 2x range (0.020 to 0.040 in/s),
which is what separates a real signal from a tuned one:

  FINAL: 5 of 45 units (11%) — BE9558, BE11529, BE12599, BE13117, BE18438

BE11007 and BE10895 drop out; the spread test identifies them as transients
rather than pedestals. v1's 11% headline was right by luck — it included
BE11007 and named the wrong channel on most units.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgTe8CamXAHcAmaQ6QNcog
This commit is contained in:
2026-08-28 21:18:33 +00:00
co-authored by Claude Opus 5
parent 1fdc665675
commit ad84a04404
2 changed files with 160 additions and 0 deletions
+65
View File
@@ -18,6 +18,11 @@
> (`scratch/offset_scan2.py`, per-channel median) shows the pedestal is
> **persistent**, exactly as the field experience says. See §2b and §3b.
>
> **Then Brian proposed a better detector still** — measure the floor during
> the *pre-trigger* window, and require it to hold across pre/middle/end.
> That is now the detector of record (§2c). Final answer: **5 of 45 units
> (11%)**, stable across a 2x threshold range.
>
> Sections below that were written against v1 are marked; v1 numbers are kept
> for the reasoning trail, not as current fact.
@@ -160,6 +165,65 @@ Longest / clearest runs:
BE12599 began **2026-08-14**, not 08-17 as v1 reported, and was still faulting
at the last event in the archive.
### 2c. Detector v3 — PRE-TRIGGER floor + constant-floor test (CURRENT)
`scratch/offset_scan3.py`. Brian's method, and better than v2 for a reason
worth naming: **the pre-trigger window is definitionally quiet** — it is the
buffer captured before the trigger fired — whereas a whole-record median is
merely *robust* to the event. `pretrig_samples` comes from the STRT record.
```
per channel:
pre = median of the first pretrig_samples samples
mid = median of the middle third
end = median of the final third
spread = max(pre,mid,end) - min(pre,mid,end)
offset when |pre| >= floor AND spread <= 0.02 in/s
real fault when a channel is flagged on >=3 CONSECUTIVE events
```
A DC offset is a **constant floor** — present before the trigger, during, and
after. The spread test rejects transients (settling, handling, a long event
tail) that move one segment relative to the others, which is what v2's
whole-record median could not do.
**The empirical noise floor justifies the threshold.** Across 19,244
non-flagged channel-events the pre-trigger floor distributes as:
| floor | share |
|---|---|
| −1 unit (−0.005) | 18.4% |
| **0.000** | **62.7%** |
| +1 unit (+0.005) | 13.4% |
**94.5% within ±1 quantisation unit; median exactly +0.0000, mean −0.0008.**
So there is **no systematic zero-point bias in the decoder** — an independent
confirmation of the 32000-count scale. A healthy channel really does read
0.000, and "any constant floor that is not 0.000" is the right signal, with
±1 unit of slack for quantisation.
**The result is threshold-insensitive**, which is what distinguishes a real
signal from a tuned one:
| floor | units flagged | sustained units |
|---|---|---|
| 2 units (0.010) | 34 | 15 ← into the noise |
| 3 units (0.015) | 26 | 8 |
| **4 units (0.020)** | 17 | **5** |
| **5 units (0.025)** — Instantel's | 12 | **5** |
| **8 units (0.040)** | 8 | **5** |
### FINAL RESULT: 5 of 45 units (11%)
**BE9558, BE11529, BE12599, BE13117, BE18438.**
Unchanged across a 2x threshold range. BE11007 and BE10895 drop out — the
spread test identifies them as transients, not pedestals.
The 11% headline happens to match v1's, but the reasoning and the unit list
differ: v1 included BE11007 and named the wrong *channel* on most units.
---
## 3. Archive results (2026-08-28)
@@ -447,3 +511,4 @@ doubled two reported figures before it was caught.
| 2026-08-28 | Instantel FAQs supplied: autozero procedure, the **2027–2069** window, the **>5 counts** threshold. Explains the ~10% re-zero success rate. |
| 2026-08-28 | Bimodality established; sensor check proven **blind** to offsets; `SUB 0x0E` identified as the best open lead. |
| 2026-08-28 | **v1 detector retracted.** Brian challenged the "come and go" finding against field experience. Two flaws found: dominant-axis-only scoring and mean-instead-of-median. Corrected detector shows persistent pedestals on **8 of 45 units**, and the gaps are service windows. |
| 2026-08-28 | **Detector v3 (Brian's method):** pre-trigger floor + pre/mid/end consistency. Healthy channels proven to sit at 0.000 +/-1 unit (94.5%), confirming no decoder zero-point bias. Final: **5 of 45 units (11%)**, threshold-insensitive. |