From 4f45ff5a2006edfa05be51e6299a3ea757366b94 Mon Sep 17 00:00:00 2001 From: david rice Date: Wed, 22 Apr 2026 09:56:51 +0100 Subject: [PATCH] Changes --- __pycache__/csv_preprocessor.cpython-312.pyc | Bin 46722 -> 47410 bytes csv_preprocessor.py | 41 ++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/__pycache__/csv_preprocessor.cpython-312.pyc b/__pycache__/csv_preprocessor.cpython-312.pyc index 7d7e5782314c658a707c0d922029810e6b192fa5..d82c25821dd9eca6c1a7e3b643c172f350287948 100644 GIT binary patch delta 4005 zcmZ`*YfxLq72ds)0HG@+Kms8UAP@rae!u+$^D+iMk~CK05X@ePfnZmXZH!mJNyyaB zkQ#f_7zf9pahgy&6Wh7XBtJT>+j=@q-A+ZEbQtO%_OzXJ@@N#?nWi)COwUTXh{VkW zojrT@Jic@G?B4s#7s5L$Lc&eGJ|4mI$LYWCldqpju;A=d`4?JAirX&53aA~C)G0(P zmjtea(53Kz+&LsoiYHbnSJDi3M1*SwE@kmJU6($kcIT0d(EO@CSz}w}tRe1kY&K+q zj#G=s*8itBnI+|uZ1~xwf>1n{j4#1svAMWC? zHpv5RCuonc-4KuYa+p`Ab2%s*Ak<Dok=a2)PYF@ zsSnk?94cQS6@)9naZ2%#s)TE!CJmt77;)YR&YSLY-b9*}-O#QJRhRD??1+9n*fx`H zvO!s2w-I8g$tI}xx=0dDFy9P%>!l5(WuyQh&sBnnFuKvbQ9x3>wCNHKH^lH1gPk|D zPUsMFx4>Gfv~l=(_SL~;cI{BCNVbf$g0Ukc1Vy}seXT0dwT)RpwOwi%KE=(8+7x%n zNCeVuMea7KtrhLr0IoZsg*v3p;TPGMIxT;_)TwB?w~obuucEaQn0HHChvz~tvO5hd zpw{4S_9t~#VvhrPa@@UKgLH=c*+p|zm()9lUQsJPG1`rY;O>2-cX}i|9>#~!xN0{# zj9uFfwy6+`XZ^-xxnJ{zN;tMdZrAq5;wR;w8V3YCD(jQ)3b^OOmu59)axiUDgmYoVX;+ZjpxvhS~Ilx6iYGbada?P@mUF`UdwO93%3x{`Oe>U-{jU zkNolR=Tz9p{xRxclhY;;pPViiKjsMEgTT+BJEv2e?5pWMeNKKrZJBl4QahJ2?DEbR z9u)8+Y~f^q?qO&#&u&g0VShfkMI!;*Ea%Of6L25<_2~jU$UZy$pk@rjU2F^cRZOKG zp&!(;lLIpQ<%{*IT7L}NSZrp2v1H*yExX&kIpahvQS$?>zomD$pK`HC%#p=rwb^IL|H-^$9* zWa-i$g>3y9ej80^?lZYKojrBNHd(90Ci)4uoc)=;qE$aOU#`NR_?F(P|16&^szWn* zHYaLn79Y7kVwlhX)vxMjQ|oYvVu295eJ-wmX3DjD37Men?*&?%L zjc?eH31}C89{coc*`(8#u0*AI)cIE2YSHq2&`RNlm}o4&+?2Tf0-6tZQXABPZ?DT= z2pPBrgmGcS3azSzSpmnuXI?yQ9uuItmbF-w3Y8*63!|xh*N#V$ak1aNY%j8UMyNHM zXlNS}{06@r`Y(YRtjJ#!^+twe{yt5OW=0ciyk)+b zC71h)6{N6Q9JM1R_VsK=8?`7USuI-$sI7KzbbSO0)E0qxxqq< zX~}mrffB`^0w=4K>O?e-J^2_>HA!P1&UMC?(K1gGEoFgoX4ZF3jNMCh-tatyJyoGg z>!IS)-Bk27Dp5mtY+;MK3@Q@aoSI}t*XIz)dPSqeg-D{0Ux=Y6^g4^!HYv8*(e?Xm zjZf!Oqi_AHJ+DP(IChzx8c7bs&W)~z=8kVfFY~%+k~a}-W?sn_X)@7-UdUVkDK|Ky zK;f<`=Vb}4mr$Lj2=?4X6MY+3!^7zUopNskLRvm_0f$f!)d|gAOgx|7P{>Q=ub^h4 zJ&2*~15gaJZ}X}*SOqCu)R0J6qk!|i_3ZKUX57jSozI9s1YJo{>qRK1IQJuTF(1ACRa@%w7&|a#?tpVB${egdocfqZV`3-GI@+TZtCU9LJMy~a8{Cu1M@6qJfzQjJJ zx-cWeB6;RQmtgGX?_E2f^FXnX%gH|dNmmws)q2izVISvy%(?Gza)=X&?RsN#);wol z=A@VFZ0BSLCp$UW#V)>4E-YKwrsK&89i8nRecK-LY=RY69lQI+Qz=`4UDkN}q%pFr z_P`fL=mUW5d$WiA;?1$l<%H1#eWUvi^Yy-cWPDkK?~#Egq=6AGVZ{sU%aTB{_aK<| z^^fg;vVU~{LGQ8-zE?*2y!%F_F`p-t*&YDs0qVIyYo3|uR zUS4<@8<*0v;p1dUG#=Z+Nvm9W@uDzkL}F$@=UTGmyuK??*!;e4v9RTuZ_%~&#@ zbvwW4wkhRI+o`tM>iL8P8c1)xE-t2b-!g5xrxFU10!BwL9vPF4bu8Ijfi(G(x1Pm@ z3~l_9nEp{_-J)2xqRL=L-tL)9)RzWDWVFqz0|v*6o=;6EG4n%XW5C%M$Z1?Lb5RC} z<{tJsW{kxG^Su1M%t7WBxoBT z>U?!T%wJK#{*<-hO27FBP@UJ>@^y2{|zCw-vRyOY_D zD@`$8-YeVL=_}9I9|G2Mgp+S|+Bla{P9ESS+<2Vxb8?jRUVTBwKPEk)em=`Sxq2f0 zZJ5J9@_x!D-g#9UgEDgh$Qn$Lt#S~j4q%)eM4aAJAwd@uLV|8)e|J-An;OT=I)aFg r^G)|cV{m62JM!-5wo*f+FUuy6Lh=T%ZX}l2@~p=)@MwI>qlxU2aVL%7vK(AikS6&Y zYT+d6#9#&qUZE;44XsaynJ5GP>V*ws1mi5UYi3AgdJn zwsy#^CLMr(YqqJCuwM;!ZQ?4@84n?pc%NV*47bPH1tjK(9anH>V1{02Fd2Dk#*GNY zIzhKaY#%zrJ_{GH4@Y$-(iQIl=YT8(L)^ulsH%8o(KzfQ$ ztXu5vLfhLR^g0-+wc@&=x0cLlmVE^!3=pkNT&H-)dPnpisaz_7{RXjj=p?gNmT58K zTXtXVwSFsr5@oSIz9;K=0`}1{TMbz+_RXL(Y9%5@TM-dreJ}JKj%U_UJc`CtThS;E zZ2>3fvQNd>d?mhp+uEtZ+*RBZ_o|V$>U+M5qq*diJHvFk{ zzxkE{k4ZmX^97W+BDydULT6{&? zJH8PMdd%88{OrO044Gi>g5Zt`K!B_j`F^2m2%aSh|t! z(c!PyYeR0y^~SR*_MeLy_VS@)x-WUgQP_8tOZAg670zS-><+MNhi$B=$Il)fHfZl~ zldB9DI+&->&VomF3hpwA9eG~BG4{8qkg*>?NNnLG#!9BUH3ZluX>j_qfOjwz3t^E( z*z=l~K-|sVWFKk&4MX?+D7(F{jO{&kQx#2XnfDz#+x)f-N7+Btc9u*=iJCvqN_#1* zGCq@0ws~(6`_tQh0n=Z<)8$F|6%{oq=ENM|hS0Q-7-99tYu$yZ;DU{o7AlWm+OZp@ zoh*IaYjkac9@9nXV(MZSj{C8T-8$|LM;GIb!(E*&NmVVxDPGJAC0S269PX4`(N0Eb z2`?X3H)}uPQhBJ8Sqy`ZLz!;F0ae$NOQHQ~7pBs!r)Q4(N@;>81m$=~QiT zd8$~^&;TvJs$W37f*m+j><`ikxEy_~?)MpC{$puAb^i|G8oH{cF%Sh#>^U_|brMWb(2&F3*1JFvgb7l>$WanpEfPOkt zlMj4J+k@*Ymq!~QVq#kK6wtgF9naY!c@ZXd9zrzW6LY6jXsEkKu1E6_$-0CYLE z0d1mopetxT&}LcgwHCxrd}LZ=;04J9^lvYC@_ zbMg$Uxmc%5tOh>Zzz$q|HHW_??yD2Y6k+yDeHu-2r#QlPUHUG2bZM2-IJ{>hzB9RJ zSR6?u}6-;jS(W$tfgUtDj|CO9^m zSfliVhJC;$#yI&uEcrhfiT#{B%Si@W&W*D#r6WfEx=qMObc{{?Y%=E(?BR!!e`aMj z&H^-_+?d0T7cnlKL!3TVA;CB&$bw#W=NGFT!z!#j5tu`Koo#t6uX8(eEd0xd?nvHx buli$e>-vCjGoa};YHo&|y;{vDTF(C$4k!N^ diff --git a/csv_preprocessor.py b/csv_preprocessor.py index a8751eb..e1b204f 100644 --- a/csv_preprocessor.py +++ b/csv_preprocessor.py @@ -65,6 +65,10 @@ CLK_LP_LOW_MIN_NS = 300.0 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. +HS_BURST_AMPLITUDE_HIGH_MV = 70.0 # mV — above this with short LP-low → anomalous LP states +# Normal HS (dynamic video) = ~15–40 mV P95-P5/2 on LP probe (RC-filtered). +# LP-01/LP-10 states in the burst window (cap 0042 type) produce 130+ mV → flag these. + # 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 # distinguish a genuine weak-HS attempt from a false rolling-std trigger on LP-11 return. @@ -752,6 +756,7 @@ class LPMetrics: # Flicker detection # 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 0–50 ns. + hs_rolling_std_found: bool = False # rolling-std fired in HS window after LP-low ended flicker_suspect: bool = False warnings: list = field(default_factory=list) @@ -891,6 +896,9 @@ def analyze_lp_file(path: Path) -> "LPMetrics": n_hs_bursts = 0 hs_burst_dur_ns = None hs_amplitude_mv = None + hs_rolling_std_found = False + s_end = None + rstd = None if len(lp11_regions) >= 1: # Measure LP-11 → HS exit gap (LP-01 + LP-00 combined) using a rolling @@ -943,6 +951,17 @@ def analyze_lp_file(path: Path) -> "LPMetrics": float(np.percentile(burst_volts, 5))) / 2 * 1000, 1 ) + # 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: + 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)) + if lp_low_end_idx < len(rstd): + hs_rolling_std_found = bool( + np.any(rstd[lp_low_end_idx:hs_check_end] >= HS_OSC_STD_V) + ) + # ── Warnings ───────────────────────────────────────────────────────── warnings = [] continuous_hs_clk = (not lp11_regions) and (channel == "clk") and (float(volts.max()) < LP11_HIGH_V) @@ -1027,16 +1046,27 @@ def analyze_lp_file(path: Path) -> "LPMetrics": # 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 or lp11_to_hs_ns is None - # Mode B: LP-low anomalously short + low amplitude = marginal HS launch - or _lp_low_short + # Mode B: LP-low anomalously short + low amplitude = marginal HS launch. + # Gated by hs_rolling_std_found: if HS actually launched (rolling-std fires + # after LP-low ends), LP-low being short is a timing anomaly but not a flicker. + or (_lp_low_short and not hs_rolling_std_found) # Mode D: LP-low normal, noise-spike lp11_to_hs (< 50 ns), low HS amplitude. - # Requires dynamic display content (video) during the test — with static/DC content - # the probe noise floor is 15–35 mV regardless of HS health, making this unreliable. + # Requires video/dynamic content. Gate: if rolling-std fires after LP-low ends, + # HS launched normally and the early lp11_to_hs was just the LP-low edge trigger. or (lp11_to_hs_ns is not None and lp11_to_hs_ns < LP_LOW_DUR_MIN_NS - and not _lp_low_short) + and not _lp_low_short + and not hs_rolling_std_found) ) ) + # Mode E: short LP-low with anomalously HIGH amplitude — LP-01/LP-10 states in the + # burst window (link failed to launch HS cleanly). Normal LP probe HS = 15–40 mV; + # LP-01/LP-10 DC levels produce 70+ mV. Confirmed: cap 0042 (lp_low=61 ns, amp=133 mV). + hs_burst_anomalous = ( + _lp_low_short + and hs_amplitude_mv is not None + and hs_amplitude_mv > HS_BURST_AMPLITUDE_HIGH_MV + ) # Mode C: no LP-11 at all → link silent (but exclude CLK which is always HS) link_silent = ( channel == "dat" @@ -1056,6 +1086,7 @@ def analyze_lp_file(path: Path) -> "LPMetrics": # positives when noise triggers gave lp_low < 50 ns with normal HS. lp_low_duration_ns is None or hs_burst_absent + or hs_burst_anomalous ) ) )