/** * Graphique montrant l'évolution du nombre de clients pour identifier le régime permanent */ import { useMemo } from 'react'; import { Box, Paper, Typography, Alert, AlertTitle, } from '@mui/material'; import { Line } from 'react-chartjs-2'; import { useSimulationStore } from '../../store/simulationStore'; import { formatTime } from '../../utils/timeFormat'; interface SteadyStateChartProps { warmupTime?: number; } export default function SteadyStateChart({ warmupTime }: SteadyStateChartProps) { const { results, config, timeUnit } = useSimulationStore(); const { chartData, stats } = useMemo(() => { if (!results?.time_series) { return { chartData: null, stats: null }; } const { timestamps, customers_in_system } = results.time_series; if (!timestamps || timestamps.length === 0) { return { chartData: null, stats: null }; } const warmup = warmupTime || config?.warmup_time || 0; // Séparer période de chauffe et régime permanent const warmupData = timestamps .map((time, i) => ({ time, clients: customers_in_system[i] })) .filter(d => d.time < warmup); const steadyStateData = timestamps .map((time, i) => ({ time, clients: customers_in_system[i] })) .filter(d => d.time >= warmup); // Calculer statistiques du régime permanent let steadyStats = null; if (steadyStateData.length > 0) { const steadyStateClients = steadyStateData.map(d => d.clients); const mean = steadyStateClients.reduce((a, b) => a + b, 0) / steadyStateClients.length; const variance = steadyStateClients.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / steadyStateClients.length; const stdDev = Math.sqrt(variance); const min = Math.min(...steadyStateClients); const max = Math.max(...steadyStateClients); const cv = (stdDev / mean) * 100; steadyStats = { warmup, mean, stdDev, min, max, cv, warmupPoints: warmupData.length, steadyStatePoints: steadyStateData.length, }; } // Préparer les données pour Chart.js const data = { labels: timestamps.map(t => formatTime(t, timeUnit)), datasets: [ { label: 'Nombre de clients', data: customers_in_system, borderColor: 'rgb(25, 118, 210)', backgroundColor: 'rgba(25, 118, 210, 0.1)', borderWidth: 2, fill: true, tension: 0.1, pointRadius: 0, pointHoverRadius: 4, segment: { borderColor: (ctx: any) => { const idx = ctx.p0DataIndex; const time = timestamps[idx]; return time < warmup ? 'rgba(237, 108, 2, 0.6)' : 'rgb(25, 118, 210)'; }, backgroundColor: (ctx: any) => { const idx = ctx.p0DataIndex; const time = timestamps[idx]; return time < warmup ? 'rgba(237, 108, 2, 0.1)' : 'rgba(25, 118, 210, 0.1)'; }, }, }, ], }; return { chartData: data, stats: steadyStats }; }, [results, timeUnit, warmupTime, config]); if (!results) { return null; } if (!chartData || !stats) { return ( Séries temporelles non disponibles Les données de séries temporelles n'ont pas été collectées pour cette simulation. ); } const options = { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index' as const, intersect: false, }, plugins: { legend: { position: 'top' as const, }, tooltip: { callbacks: { title: (items: any[]) => { if (items.length > 0) { return `Temps: ${items[0].label}`; } return ''; }, label: (context: any) => { return `Clients: ${context.parsed.y}`; }, }, }, }, scales: { x: { title: { display: true, text: `Temps (${timeUnit})`, }, ticks: { maxTicksLimit: 10, }, }, y: { title: { display: true, text: 'Nombre de clients', }, beginAtZero: true, }, }, }; return ( 📈 Évolution du Système - Détection du Régime Permanent {/* Informations sur le régime permanent */} Période de chauffe {formatTime(stats.warmup, timeUnit)} {stats.warmupPoints} points échantillonnés Régime permanent {stats.steadyStatePoints} points L moyen = {stats.mean.toFixed(3)} clients Coefficient de variation {stats.cv.toFixed(1)}% {stats.cv < 10 ? 'Très stable' : stats.cv < 30 ? 'Stable' : 'Variable'} {/* Statistiques du régime permanent */} Statistiques du régime permanent: Moyenne {stats.mean.toFixed(3)} Écart-type {stats.stdDev.toFixed(3)} Minimum {stats.min} Maximum {stats.max} {/* Graphique */} {/* Explications */} 📖 Interprétation: Courbe bleue: Nombre de clients dans le système au fil du temps Zone orange (gauche): Période de chauffe ({stats.warmupPoints} points) où le système démarre Zone bleue (droite): Régime permanent ({stats.steadyStatePoints} points) après {formatTime(stats.warmup, timeUnit)} Moyenne en régime permanent: L = {stats.mean.toFixed(3)} clients Coefficient de variation: {stats.cv.toFixed(1)}% - Plus il est faible, plus le système est stable ); }