From a032c47e62b1e0ebfc7eea09564567c95bc946b1 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 20 Dec 2025 10:52:27 +0530 Subject: [PATCH] feat: implement a comprehensive simulation analyzer module for tracking and calculating performance metrics. --- .../modules/simulation/analyzer/analyzer.tsx | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/app/src/modules/simulation/analyzer/analyzer.tsx b/app/src/modules/simulation/analyzer/analyzer.tsx index df1f4da..3c0e37e 100644 --- a/app/src/modules/simulation/analyzer/analyzer.tsx +++ b/app/src/modules/simulation/analyzer/analyzer.tsx @@ -184,6 +184,9 @@ function Analyzer() { > >({}); + // Track previous actions for ArmBots to detect cycle completion + const previousArmBotActionsRef = useRef>({}); + // Material lifecycle tracking const materialLifecycleRef = useRef< Record< @@ -215,6 +218,7 @@ function Analyzer() { performanceSnapshotsRef.current = {}; bottleneckEventsRef.current = {}; previousAssetStatesRef.current = {}; + previousArmBotActionsRef.current = {}; materialLifecycleRef.current = {}; setAnalysis(null); setAnalyzing(false); @@ -554,6 +558,14 @@ function Analyzer() { const trackStateChange = useCallback((assetId: string, fromState: string, toState: string) => { const timestamp = Date.now(); + // Increment error count if entering error state + if (toState === "error") { + if (!errorCountsRef.current[assetId]) { + errorCountsRef.current[assetId] = 0; + } + errorCountsRef.current[assetId]++; + } + if (!assetStateChangesRef.current[assetId]) { assetStateChangesRef.current[assetId] = []; } @@ -1126,7 +1138,7 @@ function Analyzer() { const materialFlow = calculateMaterialFlowMetricsForAsset(armBot.modelUuid); const cyclesCompleted = completedActionsRef.current[armBot.modelUuid] || 0; const pickAndPlaceCount = completedActionsRef.current[`${armBot.modelUuid}_pickplace`] || cyclesCompleted; - const defects = errorCountsRef.current[`${armBot.modelUuid}_defects`] || 0; + const defects = errorCount; // Use main error count directly const qualityMetrics = calculateQualityMetrics(armBot.modelUuid, pickAndPlaceCount, defects); @@ -1143,7 +1155,7 @@ function Analyzer() { const energyMetrics = calculateEnergyMetrics("roboticArm", armBot.activeTime || 0); // Calculate success rates - const pickAttempts = pickAndPlaceCount + (errorCountsRef.current[armBot.modelUuid] || 0); + const pickAttempts = pickAndPlaceCount + errorCount; const pickSuccessRate = pickAttempts > 0 ? (pickAndPlaceCount / pickAttempts) * 100 : 100; const placeAccuracy = pickSuccessRate * 0.98; // Assuming 98% of successful picks are placed correctly @@ -2297,6 +2309,33 @@ function Analyzer() { }); }, [conveyors, machines, armBots, vehicles, humans, cranes, storageUnits, isPlaying, getMaterialsByModel, trackStateChange, trackBottleneckEvent, updatePreviousAssetState]); + // Monitor ArmBot action changes to track cycles + useEffect(() => { + if (!isPlaying) return; + + armBots.forEach((armBot) => { + const previousActionUuid = previousArmBotActionsRef.current[armBot.modelUuid]; + const currentActionUuid = armBot.currentAction?.actionUuid; + + // Check if action completed (transition from an action to no action or different action) + if (previousActionUuid && previousActionUuid !== currentActionUuid) { + // Action completed + if (!completedActionsRef.current[armBot.modelUuid]) { + completedActionsRef.current[armBot.modelUuid] = 0; + } + completedActionsRef.current[armBot.modelUuid]++; + + // Also update pick and place count which is used in analysis + if (!completedActionsRef.current[`${armBot.modelUuid}_pickplace`]) { + completedActionsRef.current[`${armBot.modelUuid}_pickplace`] = 0; + } + completedActionsRef.current[`${armBot.modelUuid}_pickplace`]++; + } + + previousArmBotActionsRef.current[armBot.modelUuid] = currentActionUuid; + }); + }, [armBots, isPlaying]); + // Periodic WIP and throughput snapshots useEffect(() => { if (!isPlaying) return;