feat: introduce comprehensive simulation analyzer component with detailed tracking and metric calculation capabilities.

This commit is contained in:
2025-12-20 10:55:39 +05:30
parent a032c47e62
commit 6ab4d1c0a9

View File

@@ -555,7 +555,7 @@ function Analyzer() {
/**
* Track asset state change
*/
const trackStateChange = useCallback((assetId: string, fromState: string, toState: string) => {
const trackStateChange = useCallback((assetId: string, fromState: string, toState: string, context?: { actionName?: string }) => {
const timestamp = Date.now();
// Increment error count if entering error state
@@ -564,6 +564,18 @@ function Analyzer() {
errorCountsRef.current[assetId] = 0;
}
errorCountsRef.current[assetId]++;
// Granular error tracking based on action type
if (context?.actionName) {
const actionName = context.actionName.toLowerCase();
if (actionName.includes("pick")) {
if (!errorCountsRef.current[`${assetId}_pick`]) errorCountsRef.current[`${assetId}_pick`] = 0;
errorCountsRef.current[`${assetId}_pick`]++;
} else if (actionName.includes("place")) {
if (!errorCountsRef.current[`${assetId}_place`]) errorCountsRef.current[`${assetId}_place`] = 0;
errorCountsRef.current[`${assetId}_place`]++;
}
}
}
if (!assetStateChangesRef.current[assetId]) {
@@ -1155,9 +1167,23 @@ function Analyzer() {
const energyMetrics = calculateEnergyMetrics("roboticArm", armBot.activeTime || 0);
// Calculate success rates
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
// Calculate success rates
const pickSuccessCount = completedActionsRef.current[`${armBot.modelUuid}_pick`] || pickAndPlaceCount / 2;
const placeSuccessCount = completedActionsRef.current[`${armBot.modelUuid}_place`] || pickAndPlaceCount / 2;
const pickErrors = errorCountsRef.current[`${armBot.modelUuid}_pick`] || 0;
const placeErrors = errorCountsRef.current[`${armBot.modelUuid}_place`] || 0;
// If granular errors are 0 but main error count > 0, distribute them (fallback)
const remainingErrors = Math.max(0, errorCount - pickErrors - placeErrors);
const effectivePickErrors = pickErrors + (remainingErrors > 0 ? Math.ceil(remainingErrors / 2) : 0);
const effectivePlaceErrors = placeErrors + (remainingErrors > 0 ? Math.floor(remainingErrors / 2) : 0);
const pickAttempts = pickSuccessCount + effectivePickErrors;
const placeAttempts = placeSuccessCount + effectivePlaceErrors;
const pickSuccessRate = pickAttempts > 0 ? (pickSuccessCount / pickAttempts) * 100 : 100;
const placeAccuracy = placeAttempts > 0 ? (placeSuccessCount / placeAttempts) * 100 : 100;
// Update historical data
@@ -2279,7 +2305,7 @@ function Analyzer() {
const allAssets = [
...conveyors.map((c) => ({ id: c.modelUuid, state: c.state, isActive: !c.isPaused, type: "conveyor" as const })),
...machines.map((m) => ({ id: m.modelUuid, state: m.state, isActive: m.isActive, type: "machine" as const })),
...armBots.map((a) => ({ id: a.modelUuid, state: a.state, isActive: a.isActive, type: "roboticArm" as const })),
...armBots.map((a) => ({ id: a.modelUuid, state: a.state, isActive: a.isActive, type: "roboticArm" as const, currentAction: a.currentAction })),
...vehicles.map((v) => ({ id: v.modelUuid, state: v.state, isActive: v.isActive, type: "vehicle" as const })),
...humans.map((h) => ({ id: h.modelUuid, state: h.state, isActive: h.isActive, type: "human" as const })),
...cranes.map((c) => ({ id: c.modelUuid, state: c.state, isActive: c.isActive, type: "crane" as const })),
@@ -2293,7 +2319,7 @@ function Analyzer() {
if (previousState) {
// Check for state change
if (previousState.state !== asset.state) {
trackStateChange(asset.id, previousState.state, asset.state);
trackStateChange(asset.id, previousState.state, asset.state, asset.type === "roboticArm" ? { actionName: (asset as any).currentAction?.actionName } : undefined);
}
// Check for material count change (potential bottleneck)
@@ -2330,6 +2356,24 @@ function Analyzer() {
completedActionsRef.current[`${armBot.modelUuid}_pickplace`] = 0;
}
completedActionsRef.current[`${armBot.modelUuid}_pickplace`]++;
// Granular pick/place tracking
if (previousActionUuid) {
// We need to look up what action this UUID corresponded to
// Since we don't store the action map history, we check the current config
// This assumes configuration hasn't changed, which is true for runtime
const action = armBot.point.actions.find((a) => a.actionUuid === previousActionUuid);
if (action) {
const actionName = action.actionName.toLowerCase();
if (actionName.includes("pick")) {
if (!completedActionsRef.current[`${armBot.modelUuid}_pick`]) completedActionsRef.current[`${armBot.modelUuid}_pick`] = 0;
completedActionsRef.current[`${armBot.modelUuid}_pick`]++;
} else if (actionName.includes("place")) {
if (!completedActionsRef.current[`${armBot.modelUuid}_place`]) completedActionsRef.current[`${armBot.modelUuid}_place`] = 0;
completedActionsRef.current[`${armBot.modelUuid}_place`]++;
}
}
}
}
previousArmBotActionsRef.current[armBot.modelUuid] = currentActionUuid;