feat: introduce comprehensive simulation analyzer component with detailed tracking and metric calculation capabilities.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user