Commit
This commit is contained in:
BIN
.gitignore
vendored
Normal file
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
91
rebuild_eye.py
Normal 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.07–0.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()
|
||||
Reference in New Issue
Block a user