#!/usr/bin/env python3 """Analyze a captured frame: extract pulse timing structure. Usage: .venv/bin/python tools/analyze.py captures/.npz """ import sys import numpy as np path = sys.argv[1] d = np.load(path) volts = d["volts"] srate = float(d["srate"]) dt_us = 1e6 / srate # threshold midway between the two dominant plateaus hi_level = np.median(volts) # idle dominates the frame -> median = idle (high) lo_level = np.percentile(volts, 10) thr = (hi_level + lo_level) / 2 bits = (volts > thr).astype(np.int8) print(f"levels: high~{hi_level:.2f} low~{lo_level:.2f} thr={thr:.2f} (raw units)") # run-length encode edges = np.flatnonzero(np.diff(bits)) + 1 starts = np.concatenate(([0], edges)) ends = np.concatenate((edges, [len(bits)])) levels = bits[starts] dur_us = (ends - starts) * dt_us print(f"{len(levels)} runs total") print("\nidx level dur_us (first/last runs are idle padding)") for i, (lv, du) in enumerate(zip(levels, dur_us)): tag = "H" if lv else "L" print(f"{i:4d} {tag} {du:10.2f}")