histogram_codec: peak count is uint8 (not uint16 LE) — properly cracks
the BE9558 / BE18003 extension-byte case The bytes at [7]/[11]/[15]/[19] are an annotation field (purpose still unclear — empirically non-zero on intervals with sub-Hz or unmeasurable freq), NOT the high byte of the peak count. The N844 fixture corpus the original RE was done against had zero values in those bytes for every block, so uint8 and uint16 LE were equivalent there — but on real BE9558 Tran-drift events and BE18003 Histogram+Continuous events the uint16 LE interpretation produced peaks up to 268 in/s and 35× inflated PVS sums. Cross-correlated against BW's per-interval ASCII export on: - K558LKZU/LL1P/LL3K → 100% T/V/L/M peak match (1435 blocks each) - T003LKZR/LL0O/LL1M → 100% T/V/L, 99.3% M (0.05 dB rounding only) - N599LKZS/LL0L → 100% all channels - N844 fixture corpus → 100% all channels (unchanged) Annotations preserved on every record for future RE; the defensive _MAX_PEAK_COUNT bound is no longer needed (uint8 maxes at 1.275 in/s, well below any physical limit). Synthetic regression test added using the verbatim K558LKZU.RE0H interval-12 block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -335,3 +335,51 @@ def test_geo_count_to_ins_scale():
|
||||
assert geo_count_to_ins(1) == pytest.approx(0.005)
|
||||
assert geo_count_to_ins(10) == pytest.approx(0.050)
|
||||
assert geo_count_to_ins(0) == 0.0
|
||||
|
||||
|
||||
# ── Regression: peak is uint8 byte[N], NOT uint16 LE byte[N:N+2] ────────────
|
||||
#
|
||||
# Block taken verbatim from K558LKZU.RE0H (BE9558) interval 12 — a real
|
||||
# field event where the Tran channel had developed a DC offset and was
|
||||
# producing sub-Hz drift content the device couldn't characterize.
|
||||
# The annotation byte at [7] = 0xd2 is non-zero in that case. The
|
||||
# legacy codec read [6:8] as uint16 LE, producing T_peak = 53763 →
|
||||
# 268 in/s — physically impossible and 35× too high for the actual
|
||||
# 0.015 in/s value (T_lo = 3 alone gives the correct count).
|
||||
# Verified against the paired BW ASCII export.
|
||||
_K558_INTERVAL_12_BLOCK = bytes.fromhex(
|
||||
"00 00 0c 01 0a 00 03 d2 45 00 02 00 02 00 02 00"
|
||||
"02 00 10 00 06 00 00 00 0e 91 2f 00 1e 0a 00 00".replace(" ", "")
|
||||
)
|
||||
|
||||
|
||||
def test_extension_byte_does_not_inflate_peak():
|
||||
"""The annotation byte at [7]/[11]/[15]/[19] must NOT contribute to
|
||||
the peak count. Decoded T_peak must be 3 (uint8 byte[6]), NOT
|
||||
53763 (uint16 LE byte[6:8])."""
|
||||
body = _K558_INTERVAL_12_BLOCK
|
||||
records = decode_histogram_body_full(body)
|
||||
assert records is not None
|
||||
assert len(records) == 1
|
||||
r = records[0]
|
||||
assert r["t_peak"] == 3, f"T_peak should be 3 (uint8), got {r['t_peak']}"
|
||||
assert r["v_peak"] == 2
|
||||
assert r["l_peak"] == 2
|
||||
assert r["m_peak"] == 16
|
||||
# Half-periods unchanged — still uint16 LE.
|
||||
assert r["t_halfp"] == 0x0045 # 69 → 7.4 Hz
|
||||
assert r["m_halfp"] == 6 # → 85.3 Hz
|
||||
# Annotation byte is preserved (for future RE) but does not affect peak.
|
||||
assert r["annotations"] == (0xd2, 0x00, 0x00, 0x00)
|
||||
|
||||
|
||||
def test_extension_byte_decoded_to_correct_in_s():
|
||||
"""End-to-end: the channel-grouped output for the K558 ext block
|
||||
should give T = 3 counts = 0.015 in/s, not 53763 counts = 268 in/s."""
|
||||
channels = decode_histogram_body(_K558_INTERVAL_12_BLOCK)
|
||||
assert channels is not None
|
||||
assert channels["Tran"] == [3]
|
||||
assert geo_count_to_ins(channels["Tran"][0]) == pytest.approx(0.015)
|
||||
assert channels["Vert"] == [2]
|
||||
assert channels["Long"] == [2]
|
||||
assert channels["MicL"] == [16]
|
||||
|
||||
Reference in New Issue
Block a user