d3f77d1d96
Decoded the structural framing of the Blastware waveform body — the bytes between the 21-byte STRT record and the 26-byte file footer. The body is a sequence of tagged variable-length blocks, NOT raw int16 LE. Five tag types (10/20/00/30/40 NN) and their lengths are now confirmed against the 4-event May 2026 fixture bundle. Body splits cleanly into ~16 segments (for a 1280-sample event) separated by 40 02 segment headers carrying a monotonically incrementing uint32 LE counter at bytes [8:12]. What's done: - minimateplus/waveform_codec.py — block walker, segment splitter, segment header parser. decode_waveform_v2 is a stub returning None until the byte-to-sample mapping is solved; client.py is unchanged. - tests/test_waveform_codec.py — 31 tests covering block detection, lengths, contiguous-walk, segment splitting, segment-header parsing, and counter monotonicity. All pass. - tests/fixtures/decode-re-5-8-26/ — bundled fixtures (4 events, BW binary + Blastware ASCII export each). - docs/instantel_protocol_reference.md §7.6.1 — replaced retraction box with the verified structural decoding plus an explicit list of what's still open. What's still open: the per-byte mapping inside 10 NN / 20 NN blocks. 96 channel-permutation × nibble-order × sign-convention combinations were brute-force tested; none match BW's ASCII export to within ±1 ADC count. The codec is more elaborate than uniform 4-bit deltas — likely a hybrid variable-bit-width scheme with segment-anchor resync points. Next recommended step: capture an event with a known calibration tone to pin down magnitude scaling. Walker also bails out partway through event-b (open issue documented in both the module and the protocol reference).
43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
"""Compare event-c and event-d (same N_samples) to find header vs data bytes."""
|
|
import sys
|
|
sys.path.insert(0, ".")
|
|
from analysis.load_bundle import load_bundle
|
|
|
|
|
|
def main():
|
|
bc = load_bundle("event-c")
|
|
bd = load_bundle("event-d")
|
|
|
|
# Compare prefixes
|
|
nc, nd = len(bc.body), len(bd.body)
|
|
n = min(nc, nd)
|
|
diffs = []
|
|
for i in range(n):
|
|
if bc.body[i] != bd.body[i]:
|
|
diffs.append(i)
|
|
print(f"event-c body={nc}, event-d body={nd}")
|
|
print(f"Total diffs (first {n}): {len(diffs)}")
|
|
|
|
# Show common prefix
|
|
same_prefix = 0
|
|
for i in range(n):
|
|
if bc.body[i] == bd.body[i]:
|
|
same_prefix += 1
|
|
else:
|
|
break
|
|
print(f"Common prefix length: {same_prefix}")
|
|
print(f"event-c prefix: {bc.body[:same_prefix].hex(' ')}")
|
|
|
|
# Look for runs of common bytes
|
|
print(f"\nFirst 32 diff positions: {diffs[:32]}")
|
|
|
|
# Show the "diff fingerprint" of the first 100 bytes
|
|
print(f"\n pos c d")
|
|
for i in range(0, 100):
|
|
marker = " " if bc.body[i] == bd.body[i] else "*"
|
|
bd_b = bd.body[i] if i < nd else None
|
|
print(f" {i:>3} {bc.body[i]:02x}{marker} {bd_b:02x}" if bd_b is not None else f" {i:>3} {bc.body[i]:02x}{marker}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|