#!/usr/bin/env python3 """Offline: when does each screen ARRIVE, and when does it SETTLE? `rest.t` is the last hold keyframe, not when a screen stops moving -- the port paces its boot sequencer off it and is late. This reads the timing probe's TSV and reports, per screen segment: arrive first frame the classifier labels that screen settle first frame after `arrive` where inter-frame motion stays below the quiet threshold for SETTLE_HOLD consecutive frames dwell how long the label persists The quiet threshold is CALIBRATED FROM THE RUN, not assumed: it is a multiple of the motion floor observed while a label is stable and late in its segment. """ import sys import numpy as np SETTLE_HOLD = 4 # consecutive quiet frames before calling it settled def main(path): rows = [] meta = [] for ln in open(path): if ln.startswith("#"): meta.append(ln.rstrip()) continue f = ln.rstrip("\n").split("\t") if len(f) < 8: continue rows.append((float(f[0]), int(f[1]), float(f[2]), float(f[3]), f[7])) if not rows: print("no data rows"); return 2 t = np.array([r[0] for r in rows]) motion = np.array([r[3] for r in rows]) labels = [r[4] for r in rows] n = len(rows) fps = n / (t[-1] - t[0]) if t[-1] > t[0] else 0 print(f"{n} frames, {t[-1]-t[0]:.1f} s, {fps:.2f} fps") for m in meta: if m.startswith("#summary") or m.startswith("#event"): print(" " + m) valid = motion[motion >= 0] if valid.size == 0: print("no motion data"); return 2 floor = float(np.percentile(valid, 10)) quiet = max(floor * 3.0, 0.05) print(f"\nmotion floor (10th pct) {floor:.4f} -> quiet threshold {quiet:.4f}") # Segment by contiguous label. segs = [] i = 0 while i < n: j = i while j + 1 < n and labels[j + 1] == labels[i]: j += 1 segs.append((labels[i], i, j)) i = j + 1 print(f"\n{'screen':<14} {'arrive':>8} {'settle':>8} {'build-in':>9} {'leaves':>8} {'dwell':>8} {'frames':>7}") for lab, a, b in segs: if b - a < 2: continue settle = None run = 0 for k in range(a, b + 1): if 0 <= motion[k] < quiet: run += 1 if run >= SETTLE_HOLD: settle = t[k - SETTLE_HOLD + 1] break else: run = 0 build = f"{settle - t[a]:9.3f}" if settle is not None else " -" s = f"{settle:8.3f}" if settle is not None else " -" print(f"{lab:<14} {t[a]:8.3f} {s} {build} {t[b]:8.3f} {t[b]-t[a]:8.3f} {b-a+1:7d}") return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1]))