docs(series4): RESOLVED -- the 0x0C float is the PER-SAMPLE peak vector sum

Exact to 0.000% on all four bench waveforms, against a PVS recomputed from the
decoded samples.  The offset (Tran label - 12) is now established rather than
inferred: four independent confirmations plus a fifth on the other firmware
line.

RETRACTION.  The previous entry observed the float running 2-5% above
max(T,V,L) and concluded it was NOT the peak vector sum, "because computed PVS
runs higher than both".  That computed PVS was sqrt(T^2+V^2+L^2) from the three
REPORTED CHANNEL PEAKS, which is an upper bound on the real quantity rather
than the quantity -- the channel maxima do not occur at the same instant, so
combining them overstates the true peak.  Every row of the old table is in fact
consistent with max(T,V,L) <= stored <= sqrt(sum of squares).

I also got this wrong in the other direction today and want it recorded.  On
UM20147's event the stored float matched sqrt(sum of peak squares) to 0.048%,
and I called it the vector sum on that basis.  It is not -- that event's peaks
merely happen to be nearly coincident in time.  The six CB events separated the
two formulas immediately, with errors to -9.5%.  ONE SAMPLE AGREEING WITH A
FORMULA IS NOT EVIDENCE WHEN A SECOND FORMULA FITS IT EQUALLY WELL.

Why it is worth having: it is a FREE SELF-CHECK ON THE DECODER.  The device
computed this number from the same samples we decode, independently of our
codec, so a mismatch means the decode is wrong.  Given this codebase's history
of silent channel truncation -- walker bugs that shorten a channel and raise
nothing -- a per-event invariant costing one float comparison is cheap
insurance, and worth wiring into the download path.

Also added the full 0x0C field map from real UM20147 bytes: timestamp, the
record-type byte, sensor-location label, setup name, serial, the PVS float and
the four channel labels with their offsets.

Noted in passing: the setup name appears as "test2" in 0x0C, "test2.MMB" in
0x41 and "test2.mmb" in 0x40 -- three commands, three spellings of one file, in
one session.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
2026-09-30 14:27:31 -04:00
co-authored by Claude Opus 5
parent 7d1b033a05
commit a5237bb3b4
+74 -3
View File
@@ -1811,7 +1811,55 @@ given it, and `/db/import/idf_file` needs no change at all.
must carry it out of the chain walk. Losing it means losing the ability to must carry it out of the chain walk. Losing it means losing the ability to
name the file correctly. name the file correctly.
### ⚠ Unresolved: the `0x0C` peak float ### ✅ RESOLVED 2026-09-30: the `0x0C` float is the PER-SAMPLE peak vector sum
**`0x0C` content[`Tran` label − 12], float32 BE, = the peak vector sum computed
sample by sample.** Exact to 0.000% on all four bench waveforms, against a PVS
recomputed from the decoded samples:
| key | `0x0C` float | per-sample PVS | err | `sqrt(Σpeak²)` | `max(T,V,L)` |
|---|---|---|---|---|---|
| `…82` | 1.37198 | 1.37198 | **+0.000%** | 1.41746 | 1.37063 |
| `…83` | 2.35414 | 2.35414 | **+0.000%** | 2.37824 | 2.22274 |
| `…84` | 3.51515 | 3.51515 | **−0.000%** | 3.78731 | 3.44194 |
| `…85` | 0.42267 | 0.42267 | **−0.000%** | 0.46678 | 0.41985 |
> #### ⚠ Retraction — why this looked unresolved
>
> The previous entry (below, kept) observed the float running 2–5% above
> `max(T,V,L)` and concluded it was **not** the peak vector sum, because
> "computed PVS runs *higher* than both".
>
> That computed PVS was `sqrt(T² + V² + L²)` **from the three reported channel
> peaks** — and that is an *upper bound* on the real thing, not the real thing.
> The channel maxima do not occur at the same instant, so combining them
> overstates the true peak. Every measurement in the old table is consistent
> with the correct answer: `max(T,V,L) ≤ stored ≤ sqrt(Σpeak²)`, in all five rows.
>
> A near-miss worth recording: on UM20147's event the stored float matched
> `sqrt(Σpeak²)` to **0.048%**, which briefly looked like proof it *was* that
> quantity. It is not — the peaks on that event simply happen to be nearly
> coincident in time. **One sample agreeing with a formula is not evidence when
> a second formula fits it equally well;** the six CB events separated them
> immediately (errors to −9.5%).
**The offset is now established, not inferred** — four independent confirmations
at 0.000%, plus a fifth on the other firmware line.
**Why this is worth having: it is a free self-check on the decoder.** The device
computed this number from the same samples we decode, independently of our
codec. If a decoded event's per-sample PVS does not match the stored float, the
decode is wrong. Given this codebase's history of *silent* channel truncation —
walker bugs that shorten a channel and raise nothing — a per-event invariant
that costs one float comparison is cheap insurance. Worth wiring into the
download path.
⚠ It remains true that `max(T,V,L)` and `sqrt(Σpeak²)` are **not**
interchangeable with it, so a consumer wanting the vector sum must use this
field or decode the samples — it cannot be reconstructed from the three
per-channel peaks.
#### Superseded: the original "unresolved" entry
The float32 extracted from `0x0C` runs 2–5% above `max(Tran, Vert, Long)` from The float32 extracted from `0x0C` runs 2–5% above `max(Tran, Vert, Long)` from
the decoded samples: the decoded samples:
@@ -1824,15 +1872,38 @@ the decoded samples:
| `…84` | 3.5152 | 3.4419 | | `…84` | 3.5152 | 3.4419 |
| `…85` | 0.4227 | 0.4198 | | `…85` | 0.4227 | 0.4198 |
It is not peak vector sum either (computed PVS runs *higher* than both). The ~~It is not peak vector sum either (computed PVS runs *higher* than both). The
field may not be the peak at all — its offset was inferred from a byte marker, field may not be the peak at all — its offset was inferred from a byte marker,
not established. **Do not rely on it** until it is pinned properly. not established. **Do not rely on it** until it is pinned properly.~~
Worth noting the histogram (`…81`) and the loudest waveform (`…84`) report Worth noting the histogram (`…81`) and the loudest waveform (`…84`) report
*identical* peaks to four decimals, in both measures. That is self-consistent: *identical* peaks to four decimals, in both measures. That is self-consistent:
the histogram's single 1-minute interval spans the whole thumping session, so the histogram's single 1-minute interval spans the whole thumping session, so
its maximum should equal the loudest event in it. its maximum should equal the loudest event in it.
### `0x0C` field map, from UM20147 (11.0BD, 2026-09-30)
Real bytes, 221 B response → 210 B content declared at `data[0] = 0xd2`:
```
content[ 0] day 0x1e = 30
content[ 1] month 0x09
content[ 2:4] year BE 0x07ea = 2026
content[ 4] ⚠ 0xb3 = 179 — unidentified, same slot as 0x1C's content[6]
content[ 5:8] h:m:s 13:27:33
content[11] RECORD TYPE 0x08 histogram / 0x07 waveform
content[12] "Location\0" sensor-location label
content[34] "test2\0" the setup file name, without its extension
content[76] "UM20147\0" serial
content[86] float32 BE the per-sample PEAK VECTOR SUM (= Tran − 12)
content[98] "Tran\0\0" + float32 BE at +6
content[112] "Vert" … content[126] "Long" … content[140] "Mic" …
```
⚠ The setup name here is `test2` — no extension — where `0x41` reported
`test2.MMB` and `0x40` reported `test2.mmb` in the same session. Three commands,
three spellings of one file. See *Setup-name case*.
## Event download, per-event delete, and ACH config (2026-09-25) ## Event download, per-event delete, and ACH config (2026-09-25)
Three captures with operator-supplied ground truth, including Thor screenshots of Three captures with operator-supplied ground truth, including Thor screenshots of