import re, sys import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt frames, eyes, bodies = [], [], [] hits = [] # (frame_at_hit, t, p, y, v) last_f = None for line in open("../content/gtrace_a.log", encoding="utf-8", errors="replace"): m = re.match(r"\[gtrace\] g=\S+ f=(\d+) eye=(\S+) (\S+) (\S+) body=(\S+) (\S+) (\S+)", line) if m: last_f = int(m.group(1)) frames.append(last_f) eyes.append(tuple(float(m.group(i)) for i in (2,3,4))) bodies.append(tuple(float(m.group(i)) for i in (5,6,7))) continue m = re.match(r"\[gtrace\] g=\S+ HIT t=(\S+) p=(\S+) y=(\S+) v=(\S+)", line) if m: hits.append((last_f, *[float(m.group(i)) for i in (1,2,3,4)])) print(f"trace frames: {len(frames)}, hits: {len(hits)}") print(f"frame range: {frames[0]}..{frames[-1]}") # stats per volley: peak |eye|, settle import math mag = [math.sqrt(e[0]**2+e[1]**2+e[2]**2) for e in eyes] peak = max(mag); print(f"peak |eyePos| = {peak:.4f} u (clamp legal range +-0.1/0.15 per axis)") peakY = max(abs(e[1]) for e in eyes); peakX = max(abs(e[0]) for e in eyes); peakZ = max(abs(e[2]) for e in eyes) print(f"peak per-axis |x|={peakX:.4f} |y|={peakY:.4f} |z|={peakZ:.4f}") bad = [e for e in eyes if any(x != x for x in e)] print(f"NaN frames: {len(bad)}") # oscillation period of Y (zero crossings) in the first big volley ys = [e[1] for e in eyes] cross = [frames[i] for i in range(1,len(ys)) if ys[i-1]*ys[i] < 0 and frames[i]-frames[i-1] == 1] if len(cross) > 3: gaps = [b-a for a,b in zip(cross, cross[1:]) if b-a < 30] if gaps: print(f"Y half-period ~{sum(gaps)/len(gaps):.1f} frames (full period ~{2*sum(gaps)/len(gaps):.1f})") # settle check: gap in frames = eye at rest (below 1e-9 magnitude threshold not logged) gapct = sum(1 for a,b in zip(frames, frames[1:]) if b-a > 5) print(f"rest gaps (>5 frames unlogged = settled to ~0): {gapct}") fig, ax = plt.subplots(2, 1, figsize=(16, 8), sharex=True) ax[0].plot(frames, [e[0] for e in eyes], '.', ms=2, label='eye X (lateral)') ax[0].plot(frames, [e[1] for e in eyes], '.', ms=2, label='eye Y (vert)') ax[0].plot(frames, [e[2] for e in eyes], '.', ms=2, label='eye Z (fore/aft)') for h in [h for h in hits if h[0] is not None]: ax[0].axvline(h[0], color='r', alpha=.25, lw=.8) ax[0].legend(); ax[0].set_ylabel('eyePosition (u)'); ax[0].set_title('Gyro eye spring — red lines = hits received') ax[1].plot(frames, [b[0] for b in bodies], '.', ms=2, label='body X (pitch)') ax[1].plot(frames, [b[1] for b in bodies], '.', ms=2, label='body Y') ax[1].plot(frames, [b[2] for b in bodies], '.', ms=2, label='body Z (roll)') for h in [h for h in hits if h[0] is not None]: ax[1].axvline(h[0], color='r', alpha=.25, lw=.8) ax[1].legend(); ax[1].set_ylabel('bodyOrientation (rad)'); ax[1].set_xlabel('frame') plt.tight_layout(); plt.savefig("GYRO_TRACE.png", dpi=90) print("wrote GYRO_TRACE.png")