Rela AIRela AI Docs
OEE

Precisión del OEE

Cómo Rela-ai filtra los sesgos estructurales (sensores muertos, PLCs compartidos, downtime fabricado) para que el OEE refleje la realidad operativa — no un número cosmético.

Precisión del OEE

El OEE que muestra un dashboard sólo sirve si refleja la realidad. Una auditoría reveló varios puntos donde el cálculo tradicional se desvía de la operación real: downtime inventado por heurísticas, sensores muertos que producen 0% falso, PLCs compartidos que inflan métricas por doble conteo, calibración rota escondida bajo un tope de 100%. Esta página documenta cada uno de esos puntos y cómo se cerraron.

¿Para qué sirve?

  • Saber si el número de OEE que mirás es confiable o está contaminado por config errónea.
  • Auditar el cálculo punto por punto contra el estándar Nakajima.
  • Detectar sensores muertos o PLCs compartidos que inflan/deflan el número silenciosamente.

¿Cómo funciona?

Cada fuente de sesgo se cerró con un filtro explícito y un flag en la respuesta JSON. Si el cálculo se ve afectado, la respuesta lo dice: status=stale_source, downtime_estimation=true, performance_capped=true. El operador ve el número Y sabe si es confiable.

Resumen ejecutivo

OEE verificable: cada desvío del estándar Nakajima está cubierto por un filtro explícito y un flag en la respuesta. El operador ve la realidad — incluyendo cuando la realidad está contaminada por config incorrecta.

AntesAhora
Downtime fijo 5 min por evento (parada de 2h reportada como 5 min)Duración real desde metadata.duration_seconds + flag downtime_estimation
Sensor muerto → OEE=0% falsoFiltro de staleness + status=stale_source
PLC compartido entre líneas → conteo duplicadoScope por asset_id en el $match
Performance > 100% silenciosamente capeadoperformance_pct_raw + performance_capped flag
Buffer/store-and-forward desalineaba períodosmetadata.timestamp sobre created_at
Config huérfana (asset/source borrado)Validación 404 en configure
Cambios de umbrales reescribían el histórico sin huellaAudit trail fire-and-forget
Turnos y PM tanquean availabilityshift_pattern + subtract_scheduled_maintenance
Trend se truncaba en un error transitorioLoop robusto + ventanas de día calendario
Sin Pareto de paradas ni version stampdowntime_breakdown + config_version

Hallazgos cerrados

🔴 Críticos (H)

OEE-H1 — Duración real de downtime

El cálculo histórico usaba 5 min por evento de downtime, independientemente de la duración real. Un paro de 2 horas reportado como un solo evento contaba 5 min; un paro de 10 segundos con 12 rebotes contaba 60 min. La Disponibilidad resultante era aleatoria respecto a la realidad.

Ahora el resolvedor sigue una prioridad:

  1. Suma de metadata.duration_seconds (primera clase, medido).
  2. Suma de metadata.duration_minutes (atajo de conveniencia).
  3. Heurística legacy 5 min × conteo (compatibilidad, pero marcado).

La respuesta incluye downtime_estimation con valores measured, heuristic o none para que el dashboard muestre un aviso cuando el número es aproximado.

{
  "downtime_minutes": 90.0,
  "downtime_estimation": "measured"
}

OEE-H2 — Guardia de staleness en el count source

Un sensor de conteo marcado como stale por el sensor_watchdog ya no alimenta el cálculo. En su lugar, la respuesta corta con status="stale_source" y un mensaje guiando al usuario al watchdog. Previene OEE=0% falso cuando el sensor murió y la línea sigue produciendo normal.

{
  "status": "stale_source",
  "message": "Count source is stale; OEE not computed."
}

OEE-H3 — Scope por asset_id

Cuándo dos activos comparten el mismo count_source_id (típico: dos líneas detrás del mismo PLC), cada evento se contaba una vez por cada activo — Rendimiento y Calidad inflados simétricamente en ambos, downtime duplicado. El $match ahora incluye una cláusula $or que acepta eventos con asset_id a nivel raíz, dentro de metadata, o ausente (single-asset legacy).

OEE-H4 — Performance real + performance_capped

performance > 100% no es un glitch — es un indicador fuerte de calibración rota (cycle_time subconfigurado o doble conteo). El código legado capaba silenciosamente a 100%. La respuesta ahora expone ambos:

{
  "performance_pct": 100.0,
  "performance_pct_raw": 173.6,
  "performance_capped": true
}

El KPI de OEE sigue usando el valor capeado (Nakajima define el rango 0-100), pero el dashboard puede mostrar un badge "calibración a revisar" cuando raw > 100.

🟡 Medios (M)

OEE-M1 — Timestamp real vs created_at

El $match prefiere metadata.timestamp (ISO) cuando el evento lo lleva; created_at es el fallback. Corrige el sesgo del buffer/store-and-forward: una lectura que ocurrió a las 14:00 pero se re-ingiere a las 14:45 ahora cae en el bucket de 14:00, no 14:45.

OEE-M2 — shift_pattern por día

Nuevo campo en la config:

{
  "shift_pattern": {
    "hours_by_weekday": {"1": 8, "2": 8, "3": 8, "4": 8, "5": 8}
  }
}

ISO weekday: 1=lunes, 7=domingo. Una planta que corre Mon-Fri 8h y está apagada los fines de semana ve planned=0 min en sábado, no 0% OEE contra un plan fantasma de 480 min.

OEE-M3 — PM planificado resta del planned

Nuevo flag subtract_scheduled_maintenance: true (default). Los _maintenance_plans con next_due_at dentro del período reducen planned_minutes en lugar de contar como downtime. Un PM de 4h dentro de un turno de 8h ya no reporta Availability=50% (como si el PM fuera una falla); ahora planned se convierte en 240 min y Availability se mantiene 100% para las 4h restantes de producción real. Opt-out disponible para tenants cuya convención de auditoría interna sí cuenta el PM como downtime.

OEE-M4 — Validación de asset_id + count_source_id

POST /configure devuelve 404 si el asset_id no existe (ni como ObjectId de _assets._id ni como asset_code) o si el count_source_id no existe en _machine_event_sources. Evita configuraciones huérfanas que producen un OEE=0% silencioso cuando el activo o la fuente han sido eliminados.

OEE-M5 — Audit trail en mutación de config

Cualquier cambio a los 6 campos regulados (planned_production_hours, ideal_cycle_time_seconds, count_source_id, count_metric_field, reject_metric_field, downtime_event_type) escribe una entrada en _audit_trail con actor, timestamp, snapshot previo y nuevo. Un auditor puede responder "quién movió ideal_cycle_time_seconds de 2.5 a 3.0 el 3 de marzo".

OEE-M6 — Trend robusto ante errores transitorios

Un error transitorio en la DB (p.ej. un timeout en día 3 de un trend de 7 días) ya no trunca el resultado. Cada día se calcula en su propio try/except; los fallos devuelven {"date": "...", "status": "error"} como placeholder y el loop sigue. Sólo un 404 (not-configured) detiene el loop por ser un error de configuración, no transitorio.

OEE-M7 — Ventanas de día calendario

Las ventanas del trend están ancladas a medianoche UTC (00:00 → 24:00) en lugar de ventanas rodantes de 24 h ancladas al momento de llamada. La etiqueta "2026-04-17" ahora coincide exactamente con la ventana que representa.

🟢 Bajos (L)

OEE-L2 — Breakdown Pareto del downtime

Nueva lista downtime_breakdown en la respuesta, agrupada por event_type y ordenada descendente por minutos:

{
  "downtime_breakdown": [
    {"event_type": "STOP_COMPRESSOR", "event_count": 2, "minutes": 40.0},
    {"event_type": "STOP_CHANGEOVER", "event_count": 3, "minutes": 20.0}
  ]
}

Responde "¿cuál fue la mayor causa de pérdida de tiempo?" sin un segundo query.

OEE-L3 — config_version en la respuesta

Cada configure_oee hace $inc.config_version en MongoDB. Cada calculate_oee estampa el config_version activo en la respuesta. Así un OEE histórico queda anclado al conjunto de umbrales que lo produjo — la pregunta de auditoría "¿con qué config se calculó ese 87%?" es trivialmente resoluble.

Estructura de la respuesta completa

{
  "asset_id": "line-01",
  "oee_pct": 72.3,
  "availability_pct": 93.8,
  "performance_pct": 85.0,
  "performance_pct_raw": 85.0,
  "performance_capped": false,
  "quality_pct": 98.2,
  "total_count": 4800,
  "good_count": 4714,
  "reject_count": 86,
  "planned_minutes": 480.0,
  "operating_minutes": 450.0,
  "downtime_minutes": 30.0,
  "downtime_estimation": "measured",
  "downtime_breakdown": [
    {"event_type": "STOP_COMPRESSOR", "event_count": 2, "minutes": 22.0},
    {"event_type": "STOP_CHANGEOVER", "event_count": 1, "minutes": 8.0}
  ],
  "scheduled_maintenance_minutes": 0.0,
  "config_version": 7,
  "period_start": "2026-04-17T00:00:00+00:00",
  "period_end": "2026-04-18T00:00:00+00:00"
}

Colecciones MongoDB tocadas

ColecciónUso
_oee_configsConfig per-asset con config_version monotónico.
_machine_eventsFuente única de eventos (producción + downtime) — filtrada por asset_id + timestamp real.
_machine_event_sourcesEstado connected/stale leído por el guard de OEE-H2.
_assetsValidación de asset_id en configure (dual-lookup ObjectId o asset_code).
_maintenance_plansVentanas planificadas que reducen planned_minutes (OEE-M3).
_audit_trailEntradas fire-and-forget con action=oee_config_updated.

Beneficios clave

  • Toma de decisiones sobre datos reales, no heurísticas.
  • Cero OEE=0% falso por sensor muerto.
  • Cero doble conteo entre líneas que comparten PLC.
  • Calibración visible: performance_pct_raw > 100 dispara revisión.
  • Trend estable: etiquetas y ventanas alineadas, errores transitorios no truncan.
  • Audit-ready: cada mutación de umbral deja huella, cada KPI histórico lleva su config_version.

En esta página