This commit is contained in:
David Rice
2026-05-26 08:06:49 +02:00
parent 39f4355b8d
commit 423766f7a3
3 changed files with 213 additions and 19 deletions

BIN
.gitignore vendored Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

91
rebuild_eye.py Normal file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/env python3
"""
Rebuild the folded CLK+ eye diagram for the v2 report.
The original plot_eye() in make_flicker_report.py looks for an LP-11 → HS
transition (CLK+ > 0.5 V then falling). In session 20260515_135656 the
captures landed entirely in HS state (CLK+ stays in ~0.070.36 V), so the
edge detector returned None for every segment and the plot rendered with
zero overlays.
This script auto-detects the common mode per segment and folds around
every crossing of common mode — which is what the eye really wants.
"""
from __future__ import annotations
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
ARRIVE_PURPLE = "#5f016f"
ARRIVE_PURPLE_DARK = "#3e0049"
SESSION = Path("data/flicker_bursts/20260515_135656")
BURST = 15
N_SEGS = 20
UI_NS = 2.315
OUT = Path("flicker_investigation_report_v2_plots/mipi_typical_eye.png")
def fold_segment(t_ns: np.ndarray, v_mv: np.ndarray, ui_ns: float,
ax: plt.Axes) -> int:
"""Overlay every common-mode crossing in this segment as a ±1 UI slice."""
cm = float(np.median(v_mv))
above = (v_mv > cm).astype(int)
edges = np.where(np.diff(above) != 0)[0]
n = 0
for e in edges:
t_cross = t_ns[e]
mask = (t_ns >= t_cross - ui_ns) & (t_ns <= t_ns[e] + ui_ns)
if mask.sum() < 3:
continue
ax.plot(t_ns[mask] - t_cross, v_mv[mask] - cm,
color=ARRIVE_PURPLE, linewidth=0.4, alpha=0.18)
n += 1
return n
def main() -> None:
clk_files = sorted(SESSION.glob(f"burst_{BURST:04d}_*_mipi_seg*_clk.csv"))
if not clk_files:
raise SystemExit(f"no CLK files for burst {BURST} in {SESSION}")
fig, ax = plt.subplots(figsize=(8.5, 3.0))
total_segs = 0
total_xings = 0
for f in clk_files[:N_SEGS]:
arr = np.genfromtxt(f, delimiter=",")
t_ns = arr[:, 0] * 1e9
v_mv = arr[:, 1] * 1000
n = fold_segment(t_ns, v_mv, UI_NS, ax)
if n:
total_segs += 1
total_xings += n
ax.axhline(0, color="grey", linewidth=0.4, alpha=0.5)
ax.axvline(-UI_NS / 2, color="grey", linestyle=":", linewidth=0.4, alpha=0.5)
ax.axvline(+UI_NS / 2, color="grey", linestyle=":", linewidth=0.4, alpha=0.5)
ax.set_xlabel(f"time (ns, folded on UI = {UI_NS} ns)")
ax.set_ylabel("CLK+ common-mode (mV)")
ax.set_xlim(-UI_NS, UI_NS)
ax.set_title(
f"CLK+ folded eye ({total_segs} segments × ~{total_xings // max(total_segs,1)} "
f"crossings overlaid on a 2-UI window, burst {BURST})",
color=ARRIVE_PURPLE, fontsize=11)
ax.grid(True, alpha=0.25)
ax.text(0.01, 0.95,
f"{total_segs} segments × ~{total_xings // max(total_segs,1)} cycles overlaid",
transform=ax.transAxes, fontsize=9, color=ARRIVE_PURPLE_DARK,
bbox=dict(facecolor="white", edgecolor="none", alpha=0.85), va="top")
OUT.parent.mkdir(parents=True, exist_ok=True)
fig.tight_layout()
fig.savefig(OUT, dpi=140)
print(f"wrote {OUT} ({total_segs} segments, {total_xings} crossings)")
if __name__ == "__main__":
main()