import { useEffect, useRef, useState } from "react"; import type { WireViewSample } from "../types.js"; // Current difference between any two pins that indicates a bad contact. const PIN_IMBALANCE_A = 2; // Show only after the imbalance holds for this many consecutive samples (~1 s each). // AI workloads produce frequent short load ramps that skew one pin transiently, // so the threshold is deliberately high: a bad contact stays imbalanced, a ramp does not. const SHOW_AFTER = 7; // Keep showing this many samples after the imbalance clears (grace period). const HIDE_AFTER = 5; export interface ImbalanceAlert { diff: number; maxI: number; minI: number; /** 1-based pin index carrying the most current */ hiPin: number; /** 1-based pin index carrying the least current */ loPin: number; } /** * Debounced pin-current imbalance detection. * * A single sample can transiently skew (load change, measurement glitch), so * the alert only appears after the imbalance persists for a few samples, and * stays visible briefly after it clears instead of flickering. */ export function useWireviewImbalance( sample: WireViewSample | null, ): ImbalanceAlert | null { const [alert, setAlert] = useState(null); const alertRef = useRef(null); const streak = useRef(0); const grace = useRef(0); useEffect(() => { function update(next: ImbalanceAlert | null) { alertRef.current = next; setAlert(next); } if (!sample || sample.pins.length < 2) { streak.current = 0; grace.current = 0; if (alertRef.current) update(null); return; } const currents = sample.pins.map((p) => p.current_a); const maxI = Math.max(...currents); const minI = Math.min(...currents); const diff = maxI - minI; if (diff > PIN_IMBALANCE_A) { streak.current += 1; grace.current = 0; if (streak.current >= SHOW_AFTER) { update({ diff, maxI, minI, hiPin: currents.indexOf(maxI) + 1, loPin: currents.indexOf(minI) + 1, }); } } else { streak.current = 0; if (alertRef.current) { grace.current += 1; if (grace.current >= HIDE_AFTER) update(null); } } }, [sample]); return alert; }