n_barras <- 500
mu_x1 <- 30
sigma_x1 <- sqrt(0.81)
mu_x2 <- 18
sigma_x2 <- 0.3
lsl <- 45
usl <- 55
parametros_barras <- tibble(
parametro = c("Media x1", "Desviación x1", "Media x2", "Desviación x2", "LSL", "USL"),
valor = c(mu_x1, sigma_x1, mu_x2, sigma_x2, lsl, usl)
)
knitr::kable(parametros_barras, caption = "Parámetros suministrados para la simulación de las barras")
| parametro | valor |
|---|---|
| Media x1 | 30.0 |
| Desviación x1 | 0.9 |
| Media x2 | 18.0 |
| Desviación x2 | 0.3 |
| LSL | 45.0 |
| USL | 55.0 |
sim_barras <- tibble(
barra = 1:n_barras,
x1 = rnorm(n_barras, mean = mu_x1, sd = sigma_x1),
x2 = rnorm(n_barras, mean = mu_x2, sd = sigma_x2)
) |>
mutate(
longitud_total = x1 + x2,
dentro_especificacion = between(longitud_total, lsl, usl)
)
media_longitud <- mean(sim_barras$longitud_total)
sd_longitud <- sd(sim_barras$longitud_total)
prop_fuera <- mean(!sim_barras$dentro_especificacion)
prop_test <- prop.test(sum(!sim_barras$dentro_especificacion), n_barras)
Cp <- (usl - lsl) / (6 * sd_longitud)
Cpk <- min((usl - media_longitud) / (3 * sd_longitud), (media_longitud - lsl) / (3 * sd_longitud))
resumen_barras <- tibble(
media_longitud = media_longitud,
sd_longitud = sd_longitud,
prob_fuera = as.numeric(prop_test$estimate),
ic_fuera_inf = prop_test$conf.int[1],
ic_fuera_sup = prop_test$conf.int[2],
Cp = Cp,
Cpk = Cpk
)
resumen_barras |>
mutate(across(everything(), round, digits = 4)) |>
knitr::kable(caption = "Indicadores obtenidos para la soldadura de las barras")
| media_longitud | sd_longitud | prob_fuera | ic_fuera_inf | ic_fuera_sup | Cp | Cpk |
|---|---|---|---|---|---|---|
| 47.98 | 0.9454 | 0.002 | 1e-04 | 0.0129 | 1.763 | 1.052 |
sim_barras |>
ggplot(aes(x = longitud_total, fill = dentro_especificacion)) +
geom_histogram(binwidth = 0.5, color = "white", alpha = 0.8) +
geom_vline(xintercept = c(lsl, usl), linetype = "dashed", color = "red") +
scale_fill_manual(values = c("#e4572e", "#4caf50"), name = "Estado", labels = c("Fuera de especificación", "Dentro de especificación")) +
labs(x = "Longitud total (cm)", y = "Frecuencia")
Distribución de la longitud total de las barras ensambladas
Los índices de capacidad obtenidos permiten discutir si el proceso está bajo control. Como referencia, valores de \(C_p\) y \(C_{pk}\) mayores o iguales a 1.33 suelen considerarse aceptables para procesos críticos. Esta simulación entregará evidencias cuantitativas al ejecutar el documento.
Se asume un único servidor (estación de reproceso) que atiende en orden de llegada (FIFO). Las piezas arriban cada 20 minutos de forma determinista. El número de defectos por pieza sigue una distribución Binomial con tamaño 3 y probabilidad de 0.8, cumpliendo la media de 2.4 defectos. Cada defecto requiere un tiempo exponencial independiente con tasa 0.2 por defecto.
simular_reproceso <- function(replica,
n_piezas = 200,
interarribo = 20,
max_defectos = 3,
prob_defecto = 0.8,
tasa_reparacion = 0.2) {
arribos <- seq(0, by = interarribo, length.out = n_piezas)
defectos <- rbinom(n_piezas, size = max_defectos, prob = prob_defecto)
tiempos_servicio <- map_dbl(defectos, function(d) {
if (d == 0) return(0)
sum(rexp(d, rate = tasa_reparacion))
})
inicio_servicio <- numeric(n_piezas)
fin_servicio <- numeric(n_piezas)
for (i in seq_len(n_piezas)) {
if (i == 1) {
inicio_servicio[i] <- arribos[i]
} else {
inicio_servicio[i] <- max(arribos[i], fin_servicio[i - 1])
}
fin_servicio[i] <- inicio_servicio[i] + tiempos_servicio[i]
}
tibble(
replica = replica,
pieza = seq_len(n_piezas),
arribo = arribos,
defectos = defectos,
servicio = tiempos_servicio,
inicio = inicio_servicio,
fin = fin_servicio,
espera = inicio_servicio - arribos,
tiempo_sistema = fin_servicio - arribos
)
}
resultados_reproceso <- map_dfr(1:10, simular_reproceso)
resumen_reproceso <- resultados_reproceso |>
group_by(replica) |>
summarise(
tiempo_total_min = max(fin),
piezas_sin_defectos = sum(defectos == 0),
espera_promedio = mean(espera),
tiempo_sistema_promedio = mean(tiempo_sistema),
.groups = "drop"
) |>
mutate(tiempo_total_horas = tiempo_total_min / 60)
tiempo_total_ci <- t.test(resumen_reproceso$tiempo_total_horas, conf.level = 0.95)
tiempo_total_ci
##
## One Sample t-test
##
## data: resumen_reproceso$tiempo_total_horas
## t = 1632, df = 9, p-value <2e-16
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## 66.51 66.70
## sample estimates:
## mean of x
## 66.6
resumen_reproceso |>
mutate(across(c(tiempo_total_min, espera_promedio, tiempo_sistema_promedio), round, digits = 2),
tiempo_total_horas = round(tiempo_total_horas, 3)) |>
knitr::kable(caption = "Resultados por réplica para la estación de reproceso")
| replica | tiempo_total_min | piezas_sin_defectos | espera_promedio | tiempo_sistema_promedio | tiempo_total_horas |
|---|---|---|---|---|---|
| 1 | 4001 | 3 | 2.07 | 13.86 | 66.68 |
| 2 | 3995 | 2 | 2.07 | 14.32 | 66.58 |
| 3 | 3993 | 0 | 1.48 | 13.07 | 66.55 |
| 4 | 4003 | 2 | 2.91 | 15.50 | 66.72 |
| 5 | 4004 | 4 | 1.63 | 13.17 | 66.74 |
| 6 | 3984 | 0 | 1.29 | 13.47 | 66.40 |
| 7 | 3999 | 2 | 1.94 | 14.29 | 66.65 |
| 8 | 4004 | 3 | 1.09 | 12.75 | 66.74 |
| 9 | 3995 | 2 | 2.81 | 15.36 | 66.58 |
| 10 | 3984 | 1 | 1.16 | 12.75 | 66.39 |
resumen_reproceso |>
ggplot(aes(x = factor(replica), y = tiempo_total_horas)) +
geom_col(fill = "#1f77b4", alpha = 0.8) +
geom_hline(yintercept = mean(resumen_reproceso$tiempo_total_horas), linetype = "dashed", color = "red") +
labs(x = "Réplica", y = "Tiempo total (horas)")
Tiempo total requerido para procesar 200 piezas (10 réplicas)
El intervalo de confianza de 95% para el tiempo total (en horas) obtenido por la prueba t anterior cuantifica la incertidumbre sobre el tiempo esperado para procesar las 200 piezas.
Se modela un solo camión con un único punto de carga disponible. Cada ciclo completo incluye cargar, transportar hacia el destino, descargar y regresar a la base.
simular_camion <- function(replica,
horizonte_horas = 10,
carga_rango = c(20, 40),
descarga_rango = c(15, 25),
viaje_media = 40) {
limite_tiempo <- horizonte_horas * 60
reloj <- 0
viaje <- 0
registros <- vector("list", 0)
while (TRUE) {
tiempo_carga <- runif(1, min = carga_rango[1], max = carga_rango[2])
viaje_ida <- rexp(1, rate = 1 / viaje_media)
tiempo_descarga <- runif(1, min = descarga_rango[1], max = descarga_rango[2])
viaje_regreso <- rexp(1, rate = 1 / viaje_media)
ciclo_total <- tiempo_carga + viaje_ida + tiempo_descarga + viaje_regreso
if (reloj + ciclo_total > limite_tiempo) break
reloj <- reloj + ciclo_total
viaje <- viaje + 1
registros[[viaje]] <- tibble(
replica = replica,
viaje = viaje,
tiempo_carga = tiempo_carga,
viaje_ida = viaje_ida,
tiempo_descarga = tiempo_descarga,
viaje_regreso = viaje_regreso,
ciclo_total = ciclo_total,
tiempo_acumulado = reloj
)
}
bitacora <- if (length(registros) > 0) bind_rows(registros) else tibble(
replica = replica,
viaje = integer(0),
tiempo_carga = numeric(0),
viaje_ida = numeric(0),
tiempo_descarga = numeric(0),
viaje_regreso = numeric(0),
ciclo_total = numeric(0),
tiempo_acumulado = numeric(0)
)
resumen <- tibble(
replica = replica,
viajes = nrow(bitacora),
tiempo_utilizado = if (nrow(bitacora) > 0) max(bitacora$tiempo_acumulado) else 0,
tiempo_promedio_viaje = if (nrow(bitacora) > 0) mean(bitacora$ciclo_total) else NA_real_
)
list(bitacora = bitacora, resumen = resumen)
}
resultados_camion <- map(1:5, simular_camion)
bitacora_camion <- map_dfr(resultados_camion, "bitacora")
resumen_camion <- map_dfr(resultados_camion, "resumen") |>
mutate(
tiempo_utilizado_horas = tiempo_utilizado / 60,
tiempo_promedio_viaje = tiempo_promedio_viaje
)
ci_viajes <- t.test(resumen_camion$viajes, conf.level = 0.95)
prob_al_menos_10 <- mean(resumen_camion$viajes >= 10)
ci_viajes
##
## One Sample t-test
##
## data: resumen_camion$viajes
## t = 21, df = 4, p-value = 3e-05
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## 3.645 4.755
## sample estimates:
## mean of x
## 4.2
resumen_camion |>
mutate(
tiempo_utilizado_horas = round(tiempo_utilizado_horas, 2),
tiempo_promedio_viaje = round(tiempo_promedio_viaje, 2)
) |>
knitr::kable(caption = "Rendimiento del camión por réplica")
| replica | viajes | tiempo_utilizado | tiempo_promedio_viaje | tiempo_utilizado_horas |
|---|---|---|---|---|
| 1 | 4 | 545.9 | 136.47 | 9.10 |
| 2 | 5 | 447.4 | 89.47 | 7.46 |
| 3 | 4 | 596.0 | 149.01 | 9.93 |
| 4 | 4 | 569.7 | 142.41 | 9.49 |
| 5 | 4 | 418.9 | 104.73 | 6.98 |
if (nrow(bitacora_camion) > 0) {
bitacora_camion |>
mutate(tiempo_acumulado_horas = tiempo_acumulado / 60) |>
ggplot(aes(x = viaje, y = tiempo_acumulado_horas, color = factor(replica))) +
geom_line() +
geom_point() +
labs(x = "Viaje", y = "Tiempo acumulado (horas)", color = "Réplica")
}
Tiempo acumulado tras cada viaje completado
El intervalo de confianza anterior corresponde al número esperado de viajes por jornada de 10 horas. Además, la proporción de réplicas con al menos 10 entregas es:
prob_al_menos_10
## [1] 0
A partir de los resultados anteriores, se sugieren las siguientes alternativas:
Cada recomendación debe evaluarse con simulaciones adicionales ajustando los parámetros correspondientes para cuantificar su impacto en el número de viajes diarios.
En conjunto, las tres simulaciones muestran la utilidad de la modelación Monte Carlo para diagnosticar variabilidad y evaluar alternativas operativas antes de implementar cambios en el mundo real.