ce5dc640ba
User asked the right question: do events without 30 NN blocks decode fully? Answer: YES. event-a: Tran 3328 ✓ Vert 3328 ✓ Long 3328 ✓ (28 segments, 0 '30 NN') event-c: Tran 1280 ✓ Vert 1280 ✓ Long 1280 ✓ (12 segments, 0 '30 NN') event-d: Tran 1280 ✓ Vert 1280 ✓ Long 1280 ✓ (12 segments, 0 '30 NN') 17,664 ADC samples decoded byte-exact against BW's ASCII export. Zero divergences across event-a, event-c, event-d. This means the codec is FULLY SOLVED for any event without 30 NN blocks. The remaining gap is the 30 NN block format only — used for high-amplitude regions where deltas exceed int8 range. For quiet events (or quiet stretches of loud events), the decoder is complete. 9 new regression tests bring the total to 55, all passing. Files: tests/test_waveform_codec.py + docs/waveform_codec_re_status.md + new analysis/verify_quiet_bundle.py.
56 lines
2.0 KiB
Python
56 lines
2.0 KiB
Python
"""Run decode_waveform_v2 against the 5-8-26 quiet bundle to test the
|
|
'quiet events should decode fully' hypothesis."""
|
|
import os, sys
|
|
sys.path.insert(0, ".")
|
|
from minimateplus.waveform_codec import decode_waveform_v2, walk_body, find_data_start
|
|
from analysis.load_bundle import _parse_txt
|
|
|
|
|
|
def main():
|
|
base = "tests/fixtures/decode-re-5-8-26"
|
|
for evt in sorted(os.listdir(base)):
|
|
folder = os.path.join(base, evt)
|
|
if not os.path.isdir(folder):
|
|
continue
|
|
# Find the binary (not .TXT)
|
|
bin_name = next(
|
|
(f for f in os.listdir(folder) if not f.endswith(".TXT")),
|
|
None,
|
|
)
|
|
if not bin_name:
|
|
continue
|
|
bin_path = os.path.join(folder, bin_name)
|
|
txt_path = bin_path + ".TXT"
|
|
if not os.path.exists(txt_path):
|
|
# Sometimes the TXT name differs slightly
|
|
for f in os.listdir(folder):
|
|
if f.endswith(".TXT"):
|
|
txt_path = os.path.join(folder, f)
|
|
break
|
|
with open(bin_path, "rb") as f:
|
|
body = f.read()[43:-26]
|
|
decoded = decode_waveform_v2(body)
|
|
_, samples = _parse_txt(txt_path)
|
|
|
|
# Count 30 NN blocks
|
|
blocks = walk_body(body, find_data_start(body))
|
|
n_30 = sum(1 for b in blocks if b.tag_hi == 0x30)
|
|
n_40 = sum(1 for b in blocks if b.tag_hi == 0x40)
|
|
|
|
print(f"\n=== {evt} === body={len(body)} segments={n_40} '30 NN' blocks={n_30}")
|
|
if decoded is None:
|
|
print(" decoder returned None")
|
|
continue
|
|
for ch in ("Tran", "Vert", "Long"):
|
|
truth = [round(v * 200) for v in samples[ch]]
|
|
pred = decoded[ch]
|
|
n = min(len(pred), len(truth))
|
|
matches = sum(1 for i in range(n) if pred[i] == truth[i])
|
|
div = next((i for i in range(n) if pred[i] != truth[i]), -1)
|
|
print(f" {ch}: decoded={len(pred):>5} truth={len(truth):>5} "
|
|
f"matches={matches:>5}/{n:<5} first div={div}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|