
    hj<                    v    d Z ddlmZ ddlZddlZddlmZ ddlZd Z	d Z
d Zd
dZed	k(  r e e             y)a  Score AI load cycles against the furnace log by PHASE, not by event matching.

The furnace is close to a metronome. In the pilot hour its charge interval was
212-229 s, and load cycles arrive at a similar rate, so a +-90 s matching window
gives ~0.77 recall to *any* detector firing every ~210 s -- including one firing
at random. Measured on the pilot: recall 0.938 at the true offset vs 0.773 mean
at |offset| >= 180 s, and several wrong offsets scored 1.000. Recall/precision
therefore say almost nothing here, and the old 0.84 headline should not be
quoted.

What does carry information is PHASE. If the detector really sees loading, each
AI cycle should land at a repeatable point inside the furnace's charge-to-charge
interval. If it is noise, phases spread uniformly. Because the interval is not
constant across the day (breaks stretch it), phase is normalised per interval:

    phase = (t_ai - charge_prev) / (charge_next - charge_prev)   in [0, 1)

then tested for concentration with the Rayleigh test. `--control` re-runs the
same test on random timestamps to confirm the test is calibrated -- it should
reject at about the nominal 5%.

Pilot result for reference: R=0.754, p<0.001, mean phase +41 s after charge,
circular SD 26 s; the random control passed 5.5% of the time.
    )annotationsN)Pathc                   t        j                  t        |      t              }g g }}| D ]s  }t        j                  ||      dz
  }|dk  s|dz   t        |      k\  r3||   ||dz      }}||k  rF|j                  ||z
  ||z
  z         |j                  ||z
         u t        j                  |      t        j                  |      fS )zGNormalised position of each event inside its enclosing charge interval.   r   )npasarraysortedfloatsearchsortedlenappend)	eventschargeschoutspanstiabs	            W/home/brad/proj/sonice-ai-sentinel-edge/cursor-glass-factory/scripts/a1_phase_metric.pyphase_ofr   $   s    	F7OU	+BRC OOB"Q&q5AESW$!ubQi16

AEa!e$%QU ::c?BJJu---    c                d   t        |       dk  rddt        d      fS dt        j                  z  | z  }t        j                  |      j                         t        j                  |      j                         }}t        t        j                  ||            }t        |       }||z  |z  }t        t        j                  |       dd|z  ||z  z
  d|z  z  z   z        }t        t        |d      d      }t        t        j                  t        j                  ||            dz  d	z        }|||fS )
z=Return (R, p, mean_phase). R=0 uniform, R=1 perfectly locked.   g        g      ?nan   r      ih  g     v@)r   r
   r   picosmeansinhypotexpminmaxdegreesarctan2)	phasesangCSRnZpmus	            r   rayleighr2   4   s    
6{QCu%%
bee)f
C66#;rvvc{//1qAbhhq!nAFA	A	AbffaRjAQQ1q5 99:;AC3KA	

2::a+,s2e;	<Ba8Or   c                    t        t        j                  dt        j                  t	        | d            z        dt        j
                  z  z        S )Ng&.>r   )r
   r   sqrtlogr&   r   )r-   s    r   circ_sd_fracr7   C   s7    bffSD\223q255yABBr   c                 V
   t        j                         } | j                  ddd       | j                  ddd       | j                  dd       | j                  d	t        d
d       | j                  ddg d       | j                  dt        d d       | j                  dt        d        | j                  dt        d       | j                  dd       | j	                         }t        j                  t        |j                        j                  d            d   }t        j                  t        |j                        j                  d            }|d   |j                     }|d   }|D cg c]  }||j                     |j                  z     }}|st        d      |j                  |j                  n
t!        |      }|j"                  |j"                  n
t%        |      }	|D 
cg c]  }
||
cxk  r|	k  sn n|
 }}
|st        d       |D cg c]  }||cxk  r|	k  sn n| }}t'        ||      \  }}t)        |      \  }}}t+        |      rt-        t/        j0                  |            n
t-        d!      }t.        j2                  j5                  d
      }d
}t7        |j8                        D ]D  }|j;                  ||	t+        |            }t'        ||      \  }}t)        |      \  }}}||d"k  z  }F |t%        |j8                  d#      z  }i d$|j                  d%|j                  d&t+        |      d't+        |      d(|r!t=        t+        |      t+        |      z  d)      nd d*|r0t=        d+t+        |      t+        |      z
  z  t+        |      z  d#      nd d,t        t+        |            d-t=        |d#      d.t=        |d/      d0t=        |d1      d2||k(  rt=        ||z  d#      nd d3||k(  rt=        t?        |      |z  d#      nd d4t=        |d)      d5tA        |d"k        d6|D cg c]  }t=        t-        |      d/       c}d7tC        ||      D cg c]  \  }}t=        t-        ||z        d#       c}}d8|d"k  rd9nd:}|jD                  r?t        |jD                        jG                  t        jH                  |d;d<=      d>z   d       tK        t        jH                  |d;d<=             y
c c}w c c}
w c c}w c c}w c c}}w )?Nz--cyclesTzload_cycles_v2.json)requiredhelpz	--furnacezfurnace_20260617.jsonz--clip)r9   z
--video-t0r   z(clip-local offset of the analysed window)typedefaultr:   z--keyt_start)r=   t_peakt_end)r<   choicesz--win-startz'clip-local start of the analysed windowz	--win-end)r;   r<   z	--control   z--out )r<   zutf-8)encodingcyclesper_clipcharge_video_tzno AI cyclesz(no AI cycles inside the requested windowr   g?r   clipanchorn_ai_cyclesn_furnace_charges_in_windowcount_ratior   count_error_pctd   n_phasedmedian_interval_secphase_Rr   
rayleigh_p   mean_offset_sec_after_chargecircular_sd_seccontrol_false_positive_ratelockedr)   offsets_secinterpretationzAI cycles are phase-locked to the machine-logged furnace charges; the random-timestamp control rejects at the nominal rate, so the test is calibrated.z`Phase is not distinguishable from uniform -- no evidence the detector tracks the furnace rhythm.Fr   )ensure_asciiindent
)&argparseArgumentParseradd_argumentint
parse_argsjsonloadsr   rD   	read_textfurnacerG   keyvideo_t0
SystemExit	win_startr%   win_endr&   r   r2   r   r
   r   medianrandomdefault_rngrangecontroluniformroundr7   boolzipr   
write_textdumpsprint)apargscycfurrG   r   cevlohir   gin_winphr   r-   r0   r1   periodrngnpass_fakefppcctrlvsreps                                r   mainr   G   s   		 	 	"BOOJ4IOJOOK$5LOMOOHtO,OOLsA<fOgOOGY8VOWOOMT@iOjOOKc4O8OOKc3O7OOGRO(==?D
**T$++&00'0B
CH
MC
**T$,,'1171C
DCz?499%D#$G/2	3!!DHH+
%	3B	3((
  >>53r7B1s2wB	(2<R<!	(B	(CDD 1AB!LbLa1F1W%IB|HAq"(+E
U299U#$eF
))


"CE4<<  {{2r3r7+w'AB<2qd	
 3t||Q''D		$(( 	s2w 	&s6{	
 	&uSWs6{2A6d 	TZ5B#f+(=!>V!LaP`d 	CBL 	uVQ/ 	5A; 	eAqk 	'6AQb6k1(=W[ 	6AQ5a6!91=W[ 	&uT1~ 	$q4x." 	r2!5q1%2#$ 	3r5>J41aeAElA.J%& 	 4x"21C8 xxTXX!!$**SuQ"ORV"Vah!i	$**SuQ
78u 
4 
) 2@ 3Js*   9#T5TT T1TT 3"T%
__main__)returnr_   )__doc__
__future__r   r\   ra   pathlibr   numpyr   r   r2   r7   r   __name__rg    r   r   <module>r      sN   2 #    . CL^ z
TV
 r   