This commit is contained in:
david rice
2026-04-23 13:36:27 +01:00
parent 84ccfb7379
commit 73a7c99377
2 changed files with 36 additions and 14 deletions

View File

@@ -65,6 +65,15 @@ CLK_LP_LOW_MIN_NS = 300.0
HS_BURST_AMPLITUDE_MIN_MV = 40.0 # mV — below this, no real HS burst is present HS_BURST_AMPLITUDE_MIN_MV = 40.0 # mV — below this, no real HS burst is present
# Lowered from 50 mV: 48 mV capture (0001) was a false alarm; true flicker (0008) at 34 mV. # Lowered from 50 mV: 48 mV capture (0001) was a false alarm; true flicker (0008) at 34 mV.
# HS oscillation fraction thresholds.
# Measures fraction of post-LP-low window (100 ns margin, 3 µs look-ahead) where rolling_std
# exceeds HS_OSC_STD_V. With dynamic video at 432 Mbps DDR each bit spans ~4.6 ns; transitions
# (~1 ns) fire the 1 ns rolling window ~20% of the time → healthy HS → osc_frac ≈ 0.140.22.
# Blanking/control packets carry uniform data → osc_frac ≈ 0.000.02 (confirmed NOT flicker).
# Partial or transient HS dropout sits between these bands → suspicious → send to Claude.
HS_OSC_FRACTION_SUSPICIOUS_LO = 0.04 # below this: dead HS — blanking / control (normal)
HS_OSC_FRACTION_SUSPICIOUS_HI = 0.13 # above this: healthy HS; between bands → flag
# Mode A minimum amplitude: LP-11-return edge artifacts produce near-zero amplitude in the # Mode A minimum amplitude: LP-11-return edge artifacts produce near-zero amplitude in the
# burst window (burst is pure LP-low DC between two LP-11 regions). Require ≥ this to # burst window (burst is pure LP-low DC between two LP-11 regions). Require ≥ this to
@@ -754,6 +763,7 @@ class LPMetrics:
# A capture is flagged when the LP-low plateau is absent or shorter than # A capture is flagged when the LP-low plateau is absent or shorter than
# FLICKER_LP_LOW_MAX_NS. Normal captures show ~340 ns; flicker shows 050 ns. # FLICKER_LP_LOW_MAX_NS. Normal captures show ~340 ns; flicker shows 050 ns.
hs_rolling_std_found: bool = False # rolling-std fired in HS window after LP-low ended hs_rolling_std_found: bool = False # rolling-std fired in HS window after LP-low ended
hs_osc_fraction: Optional[float] = None # fraction of post-LP-low window (100 ns margin, 3 µs) where rolling_std ≥ HS_OSC_STD_V
flicker_suspect: bool = False flicker_suspect: bool = False
warnings: list = field(default_factory=list) warnings: list = field(default_factory=list)
@@ -894,6 +904,7 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
hs_burst_dur_ns = None hs_burst_dur_ns = None
hs_amplitude_mv = None hs_amplitude_mv = None
hs_rolling_std_found = False hs_rolling_std_found = False
hs_osc_fraction = None
s_end = None s_end = None
rstd = None rstd = None
@@ -949,8 +960,6 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
) )
# Did rolling-std fire in the actual HS window (after LP-low ended)? # Did rolling-std fire in the actual HS window (after LP-low ended)?
# With dynamic display content (video), genuine HS keeps rolling-std above
# threshold; absent HS does not. Used to gate Mode B/D false positives.
if lp_low_duration_ns is not None: if lp_low_duration_ns is not None:
lp_low_end_idx = s_end + int((lp_low_duration_ns + 50.0) * 1e-9 / dt) lp_low_end_idx = s_end + int((lp_low_duration_ns + 50.0) * 1e-9 / dt)
hs_check_end = min(lp_low_end_idx + int(1000e-9 / dt), len(rstd)) hs_check_end = min(lp_low_end_idx + int(1000e-9 / dt), len(rstd))
@@ -958,6 +967,14 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
hs_rolling_std_found = bool( hs_rolling_std_found = bool(
np.any(rstd[lp_low_end_idx:hs_check_end] >= HS_OSC_STD_V) np.any(rstd[lp_low_end_idx:hs_check_end] >= HS_OSC_STD_V)
) )
# hs_osc_fraction: 100 ns margin past LP-low end, look ahead 3 µs
# (lp_low_end_idx already includes 50 ns; add 50 ns more = 100 ns total)
hs_osc_start = lp_low_end_idx + int(50e-9 / dt)
hs_osc_end = min(hs_osc_start + int(3000e-9 / dt), len(rstd))
if hs_osc_end - hs_osc_start >= int(500e-9 / dt):
hs_osc_fraction = round(
float(np.mean(rstd[hs_osc_start:hs_osc_end] >= HS_OSC_STD_V)), 4
)
# ── Warnings ───────────────────────────────────────────────────────── # ── Warnings ─────────────────────────────────────────────────────────
warnings = [] warnings = []
@@ -994,7 +1011,7 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
f"(TCLK_PREPARE+TCLK_ZERO minimum) — SN65DSI83 may fail to lock CLK lane" f"(TCLK_PREPARE+TCLK_ZERO minimum) — SN65DSI83 may fail to lock CLK lane"
) )
# Flicker suspect: three confirmed failure modes on this hardware: # Flicker suspect: confirmed failure modes on this hardware:
# #
# A) Normal LP-low (~342380 ns) → bridge misses SoT → returns to LP-11 # A) Normal LP-low (~342380 ns) → bridge misses SoT → returns to LP-11
# Signature: lp11_to_hs fires at real LP-low end (~347 ns), hs_amplitude ≈ 1530 mV. # Signature: lp11_to_hs fires at real LP-low end (~347 ns), hs_amplitude ≈ 1530 mV.
@@ -1005,18 +1022,18 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
# Signature: lp11_to_hs is None (rolling-std < HS_OSC_STD_V throughout 500 ns # Signature: lp11_to_hs is None (rolling-std < HS_OSC_STD_V throughout 500 ns
# lookahead), hs_amplitude < 50 mV, LP-11 returns ~500 ns later. # lookahead), hs_amplitude < 50 mV, LP-11 returns ~500 ns later.
# #
# B) Short LP-low (< 200 ns, vs nominal ~342380 ns) → anomalous SoT timing. # B) (removed — short-LP-low flicker is now caught by Mode F if osc_frac is in the
# Flag on LP-low duration alone: any lp_low < 200 ns is outside the normal range # suspicious zone; Mode B was causing false positives on blanking packets which
# and warrants investigation regardless of amplitude or rolling-std state. # legitimately have short LP-low and low amplitude due to uniform DC HS data)
# Confirmed: capture 0124 (lp_low=108 ns).
# #
# C) No LP-11 detected at all → MIPI link silent or stuck. # C) No LP-11 detected at all → MIPI link silent or stuck.
# #
# F) Normal LP-low but partial/transient HS dropout: hs_osc_fraction in suspicious zone
# (HS_OSC_FRACTION_SUSPICIOUS_LO < osc_frac < HS_OSC_FRACTION_SUSPICIOUS_HI).
# Healthy HS: ~0.140.22. Blanking/control (normal): ~0.000.02. Dropout: 0.040.13.
# Confirmed: capture 0105 Apr-23 run (osc_frac=0.079, lp_low=380 ns).
#
# Only flag DAT lane (CLK is continuous HS — LP states not expected). # Only flag DAT lane (CLK is continuous HS — LP states not expected).
_lp_low_short = (
lp_low_duration_ns is not None
and lp_low_duration_ns < 200.0 # below this, LP-low is anomalously brief
)
hs_burst_absent = ( hs_burst_absent = (
hs_amplitude_mv is not None hs_amplitude_mv is not None
and hs_amplitude_mv < HS_BURST_AMPLITUDE_MIN_MV and hs_amplitude_mv < HS_BURST_AMPLITUDE_MIN_MV
@@ -1035,8 +1052,6 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
# Mode A2: rolling-std never fired — HS absent or amplitude below HS_OSC_STD_V; # Mode A2: rolling-std never fired — HS absent or amplitude below HS_OSC_STD_V;
# weak oscillations are misclassified as LP-low, masking the true HS failure # weak oscillations are misclassified as LP-low, masking the true HS failure
or lp11_to_hs_ns is None or lp11_to_hs_ns is None
# Mode B: LP-low anomalously short + low amplitude = marginal HS launch.
or _lp_low_short
) )
) )
# Mode C: no LP-11 at all → link silent (but exclude CLK which is always HS) # Mode C: no LP-11 at all → link silent (but exclude CLK which is always HS)
@@ -1045,6 +1060,12 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
and not continuous_hs_clk and not continuous_hs_clk
and not lp11_regions and not lp11_regions
) )
mode_f_partial_hs = (
lp_transition_valid
and lp_low_duration_ns is not None
and hs_osc_fraction is not None
and HS_OSC_FRACTION_SUSPICIOUS_LO < hs_osc_fraction < HS_OSC_FRACTION_SUSPICIOUS_HI
)
flicker_suspect = ( flicker_suspect = (
channel == "dat" channel == "dat"
and ( and (
@@ -1054,7 +1075,7 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
and ( and (
lp_low_duration_ns is None lp_low_duration_ns is None
or hs_burst_absent or hs_burst_absent
or _lp_low_short or mode_f_partial_hs
) )
) )
) )
@@ -1077,6 +1098,7 @@ def analyze_lp_file(path: Path) -> "LPMetrics":
lp_transition_valid = lp_transition_valid, lp_transition_valid = lp_transition_valid,
clk_lp_startup_ok = clk_lp_startup_ok, clk_lp_startup_ok = clk_lp_startup_ok,
hs_rolling_std_found = hs_rolling_std_found, hs_rolling_std_found = hs_rolling_std_found,
hs_osc_fraction = hs_osc_fraction,
flicker_suspect = flicker_suspect, flicker_suspect = flicker_suspect,
warnings = warnings, warnings = warnings,
) )