\(Variable\) \(de\) \(Estudio\): Dirección del Viento (\(^\circ\)).
Se determina que esta variable es Cuantitativa Continua. La dirección del viento condiciona directamente la carga aerodinámica y la estabilidad estructural de los paneles fotovoltaicos. Debido a la dispersión de los datos y la alta variabilidad de las corrientes de aire, se opta por una Estrategia de Triple Segmentación Estadística:
\(Fase\) \(de\) \(Segmentación\): Se establecieron dos puntos de corte estratégicos en \(89.2^\circ\) y \(198.9^\circ\), dividiendo la muestra en tres secciones lógicas. Esto permite modelar cada rango direccional de forma independiente, evitando los errores de ajuste que generaría un modelo global único.
\(Modelos\) \(Aceptados\): Distribución de Weibull Reflejada (primer segmento, \(\le 89.2^\circ\)), Distribución de Weibull (segundo segmento, entre \(89.2^\circ\) y \(198.9^\circ\)) y Distribución Normal (tercer segmento, \(> 198.9^\circ\)). Los tres fueron validados exitosamente mediante el Test de Pearson y la Prueba Chi-cuadrado \(\chi^2\), proporcionando una base sólida y confiable para predecir el impacto eólico en la infraestructura.
Importamos el archivo “Dataset_Mundial_Final.xls” desde una ruta local y lo almacenamos en el objeto Datos.
suppressPackageStartupMessages(library(tidyverse))
suppressPackageStartupMessages(library(readxl))
Datos <- read_excel("C:/Users/ASUS/OneDrive/Escritorio/ESTADÍSTICA/EXPO/ACTIVIDADES/Dataset_Mundial_Final.xls",
sheet = "Dataset_Mundial_Final")
str(Datos)## tibble [58,978 × 29] (S3: tbl_df/tbl/data.frame)
## $ OBJECTID : num [1:58978] 2 3 4 5 6 7 8 9 10 11 ...
## $ code : chr [1:58978] "00001-AFG-P" "00002-AFG-P" "00003-AFG-P" "00004-AFG-P" ...
## $ plant_name : chr [1:58978] "Badghis Solar Power Plant" "Balkh solar farm" "Behsood solar farm" "Dab Pal 4 solar farm" ...
## $ country : chr [1:58978] "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
## $ operational_status : chr [1:58978] "cancelled - inferred 4 y" "cancelled - inferred 4 y" "cancelled - inferred 4 y" "shelved - inferred 2 y" ...
## $ longitude : num [1:58978] 62.9 67.1 70.4 66.2 65.7 ...
## $ latitude : num [1:58978] 35.1 36.7 34.4 33.8 31.7 ...
## $ elevation : num [1:58978] 918 359 629 2288 1060 ...
## $ area : num [1:58978] 6.74 10.72 487.73 111.8 1929.96 ...
## $ size : chr [1:58978] "Small" "Small" "Small" "Small" ...
## $ slope : num [1:58978] 7.38 0.49 1.1 6.16 1.23 ...
## $ slope_type : chr [1:58978] "Moderado" "Plano o casi plano" "Plano o casi plano" "Moderado" ...
## $ curvature : num [1:58978] -0.024 0 0 0.045 -0.005 -0.005 -0.015 0 0 -0.009 ...
## $ curvature_type : chr [1:58978] "Superficies cóncavas / Valles" "Superficies planas o intermedias" "Superficies planas o intermedias" "Superficies convexas / Crestas" ...
## $ aspect : num [1:58978] 96.8 358.5 36.2 305.8 248.4 ...
## $ aspect_type : chr [1:58978] "East" "North" "Northeast" "Northwest" ...
## $ dist_to_road : num [1:58978] 7037.1 92.7 112.1 1705.3 115.8 ...
## $ ambient_temperature : num [1:58978] 14.4 17.88 21.32 8.86 19.64 ...
## $ ghi : num [1:58978] 5.82 5.58 5.8 6.75 6.62 ...
## $ humidity : num [1:58978] 47.7 42.3 36.4 37.3 24.2 ...
## $ wind_speed : num [1:58978] 0.039 0.954 0.234 0.943 0.37 ...
## $ wind_direction : num [1:58978] 187.5 207.4 255.6 160.3 97.7 ...
## $ dt_wind : chr [1:58978] "South" "Southwest" "West" "South" ...
## $ solar_aptitude : num [1:58978] 0.72 0.635 0.685 0.659 0.819 0.819 0.818 0.642 0.63 0.374 ...
## $ solar_aptitude_rounded: num [1:58978] 7 6 7 7 8 8 8 6 6 4 ...
## $ solar_aptittude_class : chr [1:58978] "Alta" "Alta" "Alta" "Alta" ...
## $ capacity : num [1:58978] 32 40 60 3000 100 100 36 50 25 100 ...
## $ optimal_tilt : num [1:58978] 30 31 31.1 33 31 ...
## $ pv_potential : num [1:58978] 4.61 4.41 4.57 5.42 5.17 ...
Extraemos la variable de dirección del viento, omitimos las celdas en blanco o con valores iguales a cero y verificamos el tamaño muestral para asegurar la representatividad y validez estadística de los datos en el análisis de las corrientes eólicas.
La tabla de frecuencias de la dirección del viento se organizó utilizando la regla de Sturges para definir el número de intervalos. El ancho de cada clase se calculó según el rango total de los datos, lo que permitió clasificar de forma precisa y ordenada cómo varía el viento en la zona de estudio.
suppressPackageStartupMessages(library(gt))
suppressPackageStartupMessages(library(dplyr))
viento_datos <- Datos$wind_direction
viento_datos <- viento_datos[!is.na(viento_datos) & viento_datos != 0]
n_viento <- length(viento_datos)
K_viento <- floor(1 + 3.322 * log10(n_viento))
min_viento <- min(viento_datos)
max_viento <- max(viento_datos)
breaks_viento <- seq(min_viento, max_viento, length.out = K_viento + 1)
lim_inf_v <- breaks_viento[1:K_viento]
lim_sup_v <- breaks_viento[2:(K_viento+1)]
MC_v <- (lim_inf_v + lim_sup_v) / 2
ni_v <- as.vector(table(cut(viento_datos, breaks = breaks_viento, right = FALSE, include.lowest = TRUE)))
hi_v <- (ni_v / sum(ni_v)) * 100
Ni_asc_v <- cumsum(ni_v)
Ni_desc_v <- rev(cumsum(rev(ni_v)))
Hi_asc_v <- cumsum(hi_v)
Hi_desc_v <- rev(cumsum(rev(hi_v)))
df_tabla_viento <- data.frame(
Li = sprintf("%.2f", lim_inf_v),
Ls = sprintf("%.2f", lim_sup_v),
MC = sprintf("%.2f", MC_v),
ni = as.character(ni_v),
hi = sprintf("%.2f", hi_v),
Ni_asc = as.character(Ni_asc_v),
Ni_desc = as.character(Ni_desc_v),
Hi_asc = sprintf("%.2f", Hi_asc_v),
Hi_desc = sprintf("%.2f", Hi_desc_v),
stringsAsFactors = FALSE
)
df_tabla_viento %>%
gt() %>%
tab_header(
title = md(paste0("**TABLA N\u00b0: 1: DISTRIBUCI\u00d3N DE FRECUENCIAS DE LA DIRECCI\u00d3N DEL VIENTO**"))
) %>%
cols_label(
Li = "Lim. Inf",
Ls = "Lim. Sup",
MC = "Marca Clase (Xi)",
ni = "ni",
hi = "hi (%)",
Ni_asc = "Ni Asc.",
Ni_desc = "Ni Desc.",
Hi_asc = "Hi Asc. (%)",
Hi_desc = "Hi Desc. (%)"
) %>%
cols_align(align = "center", columns = everything()) %>%
tab_style(
style = list(cell_fill(color = "white"), cell_text(color = "#4F4F4F", weight = "bold")),
locations = cells_title()
) %>%
tab_style(
style = list(cell_fill(color = "#F0F0F0"), cell_text(weight = "bold", color = "#4F4F4F")),
locations = cells_column_labels()
) %>%
tab_options(
table.border.top.color = "#D3D3D3",
table.border.bottom.color = "#D3D3D3",
column_labels.border.bottom.color = "#D3D3D3",
data_row.padding = px(6)
)| TABLA N°: 1: DISTRIBUCIÓN DE FRECUENCIAS DE LA DIRECCIÓN DEL VIENTO | ||||||||
| Lim. Inf | Lim. Sup | Marca Clase (Xi) | ni | hi (%) | Ni Asc. | Ni Desc. | Hi Asc. (%) | Hi Desc. (%) |
|---|---|---|---|---|---|---|---|---|
| 1.40 | 23.34 | 12.37 | 10 | 0.02 | 10 | 58836 | 0.02 | 100.00 |
| 23.34 | 45.29 | 34.32 | 61 | 0.10 | 71 | 58826 | 0.12 | 99.98 |
| 45.29 | 67.23 | 56.26 | 99 | 0.17 | 170 | 58765 | 0.29 | 99.88 |
| 67.23 | 89.18 | 78.20 | 269 | 0.46 | 439 | 58666 | 0.75 | 99.71 |
| 89.18 | 111.12 | 100.15 | 7411 | 12.60 | 7850 | 58397 | 13.34 | 99.25 |
| 111.12 | 133.06 | 122.09 | 6373 | 10.83 | 14223 | 50986 | 24.17 | 86.66 |
| 133.06 | 155.01 | 144.03 | 4296 | 7.30 | 18519 | 44613 | 31.48 | 75.83 |
| 155.01 | 176.95 | 165.98 | 4010 | 6.82 | 22529 | 40317 | 38.29 | 68.52 |
| 176.95 | 198.89 | 187.92 | 3091 | 5.25 | 25620 | 36307 | 43.54 | 61.71 |
| 198.89 | 220.84 | 209.87 | 4329 | 7.36 | 29949 | 33216 | 50.90 | 56.46 |
| 220.84 | 242.78 | 231.81 | 14574 | 24.77 | 44523 | 28887 | 75.67 | 49.10 |
| 242.78 | 264.73 | 253.75 | 11813 | 20.08 | 56336 | 14313 | 95.75 | 24.33 |
| 264.73 | 286.67 | 275.70 | 2454 | 4.17 | 58790 | 2500 | 99.92 | 4.25 |
| 286.67 | 308.61 | 297.64 | 37 | 0.06 | 58827 | 46 | 99.98 | 0.08 |
| 308.61 | 330.56 | 319.58 | 8 | 0.01 | 58835 | 9 | 100.00 | 0.02 |
| 330.56 | 352.50 | 341.53 | 1 | 0.00 | 58836 | 1 | 100.00 | 0.00 |
Este gráfico permite ver rápidamente cómo se distribuye la dirección del viento y dónde se concentran los valores. Ayuda a identificar las direcciones predominantes de forma intuitiva, lo que complementa perfectamente los datos numéricos de la tabla de frecuencias.
Variable <- na.omit(Datos$wind_direction[Datos$wind_direction > 0])
n_total <- length(Variable)
min_v <- min(Variable)
max_v <- max(Variable)
K_global <- floor(1 + 3.322 * log10(n_total))
cortes_globales <- seq(min_v, max_v, length.out = K_global + 1)
cortes_globales[length(cortes_globales)] <- max_v + 0.000001
col_lila <- "#B0C4DE"
par(mar = c(6, 4, 3, 1))
h_base <- hist(Variable, breaks = cortes_globales, plot = FALSE, right = FALSE)
h_base$counts <- (h_base$counts / n_total) * 100
h_base$density <- h_base$counts / sum(h_base$counts)
plot(h_base,
freq = TRUE,
main = "Gr\u00e1fica N\u00ba1: Distribuci\u00f3n Emp\u00edrica de Direcci\u00f3n del Viento",
xlab = "",
ylab = "Porcentaje (%)",
col = col_lila,
border = "white",
axes = FALSE,
ylim = c(0, max(h_base$counts, na.rm = TRUE) * 1.2))
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = h_base$breaks, labels = round(h_base$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)Debido a que la dirección del viento presenta varios picos de frecuencia (comportamiento multimodal), es imposible ajustarla con un solo modelo. Por eso, se dividió la muestra en tres partes usando los cortes de \(89.2^\circ\) y \(198.9^\circ\).
Esta segmentación permite aislar tres comportamientos distintos:
Influencia nororiental (\(0^\circ\) a \(89.2^\circ\)).
Transición oriente-sur (\(89.2^\circ\) a \(198.9^\circ\)).
Espectro occidental (\(198.9^\circ\) a \(360^\circ\)).
Al reducir la dispersión interna de cada grupo, logramos que los modelos matemáticos se ajusten con total precisión a la dinámica real de cada dirección, sin alterar los datos originales.
Variable <- na.omit(Datos$wind_direction[Datos$wind_direction > 0])
n_total <- length(Variable) # N total para el cálculo del porcentaje
min_v <- min(Variable)
max_v <- max(Variable)
K_global <- floor(1 + 3.322 * log10(n_total))
cortes_globales <- seq(min_v, max_v, length.out = K_global + 1)
cortes_globales[length(cortes_globales)] <- max_v + 0.000001
col_lila <- "#B0C4DE"
col_rojo <- "#C0392B"
Corte_1 <- 89.2
Corte_2 <- 198.9
par(mar = c(6, 4, 3, 1))
h_base <- hist(Variable, breaks = cortes_globales, plot = FALSE, right = FALSE)
h_base$counts <- (h_base$counts / n_total) * 100
h_base$density <- h_base$counts / sum(h_base$counts) # Sincronización interna
plot(h_base,
freq = TRUE, # Usamos los counts ya transformados a %
main = "Gr\u00e1fica N\u00ba 2: Distribuci\u00f3n Emp\u00edrica de Direcci\u00f3n del Viento",
xlab = "",
ylab = "Porcentaje (%)",
col = col_lila,
border = "white",
axes = FALSE,
ylim = c(0, max(h_base$counts, na.rm = TRUE) * 1.25)) # Espacio extra para la leyenda
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = h_base$breaks, labels = round(h_base$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)
abline(v = c(Corte_1, Corte_2), col = col_rojo, lwd = 3, lty = 2)
legend("topright",
legend = c(paste("Corte 1:", Corte_1, "\u00b0"),
paste("Corte 2:", Corte_2, "\u00b0")),
col = col_rojo, lty = 2, lwd = 3, bty = "n", cex = 0.8)Variable_Completa <- na.omit(Datos$wind_direction[Datos$wind_direction > 0])
n_total <- length(Variable_Completa) # N total para la escala porcentual
min_v <- min(Variable_Completa)
max_v <- max(Variable_Completa)
K_global <- floor(1 + 3.322 * log10(n_total))
cortes_globales <- seq(min_v, max_v, length.out = K_global + 1)
cortes_globales[length(cortes_globales)] <- max_v + 0.000001
cortes_seg_nuevo <- cortes_globales[cortes_globales <= (89.2 + 0.1)]
Segmento_Nuevo <- Variable_Completa[Variable_Completa <= max(cortes_seg_nuevo)]
par(mar = c(6, 4, 3, 1))
col_lila <- "#B0C4DE"
h_seg_nuevo <- hist(Segmento_Nuevo, breaks = cortes_seg_nuevo, plot = FALSE, right = FALSE)
h_seg_nuevo$counts <- (h_seg_nuevo$counts / n_total) * 100
h_seg_nuevo$density <- h_seg_nuevo$counts / sum(h_seg_nuevo$counts) # Sincronización interna
plot(h_seg_nuevo,
freq = TRUE, # Forzamos el uso de los counts ya transformados a %
main = "Gr\u00e1fica N\u00ba 3: Sector Nororiental (0\u00b0 a 89.2\u00b0)",
xlab = "",
ylab = "Porcentaje (%)",
col = col_lila,
border = "white",
axes = FALSE,
ylim = c(0, max(h_seg_nuevo$counts, na.rm = TRUE) * 1.2),
xlim = c(min_v, max(cortes_seg_nuevo)))
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = h_seg_nuevo$breaks, labels = round(h_seg_nuevo$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)# if(!is.null(dev.list())) dev.off()
Variable_Completa <- na.omit(Datos$wind_direction[Datos$wind_direction > 0])
n_total <- length(Variable_Completa) # Base para el cálculo porcentual
min_v <- min(Variable_Completa)
max_v <- max(Variable_Completa)
K_global <- floor(1 + 3.322 * log10(n_total))
cortes_globales <- seq(min_v, max_v, length.out = K_global + 1)
cortes_globales[length(cortes_globales)] <- max_v + 0.000001
cortes_seg_medio <- cortes_globales[cortes_globales >= (89.2 - 0.1) & cortes_globales <= (198.9 + 0.1)]
Segmento_Medio <- Variable_Completa[Variable_Completa > min(cortes_seg_medio) & Variable_Completa <= max(cortes_seg_medio)]
par(mar = c(6, 4, 3, 1))
col_lila <- "#B0C4DE"
h_seg_medio <- hist(Segmento_Medio, breaks = cortes_seg_medio, plot = FALSE, right = FALSE)
h_seg_medio$counts <- (h_seg_medio$counts / n_total) * 100
h_seg_medio$density <- h_seg_medio$counts / sum(h_seg_medio$counts)
plot(h_seg_medio,
freq = TRUE, # Forzamos el uso de los counts ya transformados a %
main = "Gr\u00e1fica N\u00ba 4: Transici\u00f3n Oriental - Sur (89.2\u00b0 a 198.9\u00b0)",
xlab = "",
ylab = "Porcentaje (%)",
col = col_lila,
border = "white",
axes = FALSE,
ylim = c(0, max(h_seg_medio$counts, na.rm = TRUE) * 1.2),
xlim = c(min(cortes_seg_medio), max(cortes_seg_medio)))
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = h_seg_medio$breaks, labels = round(h_seg_medio$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)# 1. LIMPIEZA OBLIGATORIA
# if(!is.null(dev.list())) dev.off()
Variable_Completa <- na.omit(Datos$wind_direction[Datos$wind_direction > 0])
n_total <- length(Variable_Completa) # N total para la escala porcentual
min_v <- min(Variable_Completa)
max_v <- max(Variable_Completa)
K_global <- floor(1 + 3.322 * log10(n_total))
cortes_globales <- seq(min_v, max_v, length.out = K_global + 1)
cortes_globales[length(cortes_globales)] <- max_v + 0.000001
cortes_seg_final <- cortes_globales[cortes_globales >= (198.9 - 0.1)]
Segmento_Final <- Variable_Completa[Variable_Completa > min(cortes_seg_final)]
par(mar = c(6, 4, 3, 1))
col_lila <- "#B0C4DE"
h_seg_final <- hist(Segmento_Final, breaks = cortes_seg_final, plot = FALSE, right = FALSE)
h_seg_final$counts <- (h_seg_final$counts / n_total) * 100
h_seg_final$density <- h_seg_final$counts / sum(h_seg_final$counts) # Sincronización interna
plot(h_seg_final,
freq = TRUE, # Forzamos el uso de los counts ya transformados a %
main = "Gr\u00e1fica N\u00ba 5: Hemisferio Occidental (198.9\u00b0 a 360\u00b0)",
xlab = "",
ylab = "Porcentaje (%)",
col = col_lila,
border = "white",
axes = FALSE,
ylim = c(0, max(h_seg_final$counts, na.rm = TRUE) * 1.2),
xlim = c(min(cortes_seg_final), max(cortes_seg_final)))
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = h_seg_final$breaks, labels = round(h_seg_final$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)Con la segmentación lista, empezamos el análisis con el primer grupo de \(0^\circ\) a \(89.2^\circ\). Estudiar este rango por separado facilita el uso de pruebas de bondad de ajuste para identificar el modelo que mejor describa este cuadrante de forma independiente.
suppressPackageStartupMessages(library(MASS))
Variable_Completa <- na.omit(Datos$wind_direction[Datos$wind_direction > 0])
n_total <- length(Variable_Completa)
min_v <- min(Variable_Completa)
max_v <- max(Variable_Completa)
K_global <- floor(1 + 3.322 * log10(n_total))
cortes_globales <- seq(min_v, max_v, length.out = K_global + 1)
cortes_globales[length(cortes_globales)] <- max_v + 0.000001
cortes_seg_nuevo <- cortes_globales[cortes_globales <= (89.2 + 0.1)]
Segmento_Nuevo <- Variable_Completa[Variable_Completa <= max(cortes_seg_nuevo)]
C_Constante <- 90
Datos_Reflejados <- (C_Constante - Segmento_Nuevo) + 0.01
ajuste_weibull <- suppressWarnings(fitdistr(Datos_Reflejados[Datos_Reflejados > 0], "weibull"))
shape_ref <- ajuste_weibull$estimate["shape"]
scale_ref <- ajuste_weibull$estimate["scale"]
par(mar = c(6, 4, 3, 1))
h_seg_nuevo <- hist(Segmento_Nuevo, breaks = cortes_seg_nuevo, plot = FALSE, right = FALSE)
h_seg_nuevo$counts <- (h_seg_nuevo$counts / n_total) * 100
h_seg_nuevo$density <- h_seg_nuevo$counts / sum(h_seg_nuevo$counts) # Sincronización
plot(h_seg_nuevo,
freq = TRUE, # Forzamos el uso de counts porcentuales
main = "Gr\u00e1fica N\u00ba 6: Ajuste Weibull Reflejado (Sector Nororiental)",
xlab = "",
ylab = "Porcentaje (%)",
col = "#B0C4DE", border = "white", axes = FALSE,
ylim = c(0, max(h_seg_nuevo$counts, na.rm = TRUE) * 1.3))
axis(2, las=2, cex.axis=0.7)
axis(1, at = h_seg_nuevo$breaks, labels = round(h_seg_nuevo$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx=NA, ny=NULL, col="#D7DBDD", lty="dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)
x_curva <- seq(min(cortes_seg_nuevo), max(cortes_seg_nuevo), length.out = 100)
y_densidad <- dweibull((C_Constante - x_curva) + 0.01, shape = shape_ref, scale = scale_ref)
ancho_barra <- cortes_globales[2] - cortes_globales[1]
y_curva_hi <- y_densidad * ancho_barra * 100 * (length(Segmento_Nuevo) / n_total)
lines(x_curva, y_curva_hi, col = "#C0392B", lwd = 3)
legend("topleft",
legend = c("Datos Emp\u00edricos", "Conjetura Weibull Ref."),
col = c("#B0C4DE", "#C0392B"), lwd = c(8, 3), bty = "n", cex = 0.7)n1 <- length(Segmento_Nuevo)
K1 <- length(cortes_seg_nuevo) - 1
probs1 <- numeric(K1)
for(i in 1:K1) {
lim_inf_ref <- C_Constante - cortes_seg_nuevo[i+1] + 0.01
lim_sup_ref <- C_Constante - cortes_seg_nuevo[i] + 0.01
probs1[i] <- pweibull(lim_sup_ref, shape = shape_ref, scale = scale_ref) -
pweibull(lim_inf_ref, shape = shape_ref, scale = scale_ref)
}
probs1 <- probs1 / sum(probs1)
n_base <- 100
Fo1 <- as.vector(table(cut(Segmento_Nuevo, breaks = cortes_seg_nuevo, right = FALSE))) * (n_base / n1)
Fe1 <- probs1 * n_base
chi1 <- sum((Fo1 - Fe1)^2 / Fe1)
crit1 <- qchisq(0.99, max(1, K1 - 1 - 2))
res1 <- if(chi1 < crit1) "APROBADO" else "RECHAZADO"
pear1 <- cor(Fo1, Fe1) * 100
cat("VALIDACI\u00d3N SEGMENTO 1 (Weibull Reflejada):\n")## VALIDACIÓN SEGMENTO 1 (Weibull Reflejada):
## Resultado Chi-cuadrado: APROBADO
## Chi-calculado: 4.49 | Chi-crítico: 6.63
## Correlación de Pearson: 99.32 %
Para este rango, usamos el modelo Weibull Estándar porque los datos muestran una asimetría marcada hacia un sector específico. Al ser el estándar en ingeniería eólica para vientos con un pico de frecuencia definido, nos permite capturar con precisión la tendencia del viento hacia el sur de la planta.
suppressPackageStartupMessages(library(MASS))
n_total <- length(Variable_Completa)
n_seg2 <- length(Segmento_Medio)
desplazamiento2 <- min(cortes_seg_medio)
Datos_Weibull2 <- (Segmento_Medio - desplazamiento2) + 0.01
ajuste_weibull2 <- suppressWarnings(
fitdistr(Datos_Weibull2[Datos_Weibull2 > 0], "weibull",
start = list(shape = 1.2, scale = mean(Datos_Weibull2)))
)
shape_seg2 <- ajuste_weibull2$estimate["shape"]
scale_seg2 <- ajuste_weibull2$estimate["scale"]
par(mar = c(6, 4, 3, 1))
h_seg_medio <- hist(Segmento_Medio, breaks = cortes_seg_medio, plot = FALSE, right = FALSE)
h_seg_medio$counts <- (h_seg_medio$counts / n_total) * 100
h_seg_medio$density <- h_seg_medio$counts / sum(h_seg_medio$counts)
plot(h_seg_medio, freq = TRUE,
main = "Gr\u00e1fica N\u00ba 7: Ajuste Weibull (89.2\u00b0 a 198.9\u00b0)",
xlab = "", ylab = "Porcentaje (%)",
col = "#B0C4DE", border = "white", axes = FALSE,
ylim = c(0, max(h_seg_medio$counts, na.rm = TRUE) * 1.3))
x_c <- seq(min(cortes_seg_medio), max(cortes_seg_medio), length.out = 300)
y_teorica <- dweibull((x_c - desplazamiento2) + 0.01, shape = shape_seg2, scale = scale_seg2)
ancho <- h_seg_medio$breaks[2] - h_seg_medio$breaks[1]
y_final <- y_teorica * ancho * 100 * (n_seg2 / n_total)
lines(x_c, y_final, col = "#C0392B", lwd = 4)
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = h_seg_medio$breaks, labels = round(h_seg_medio$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)
legend("topright", legend = c("Datos Emp\u00edricos", "Modelo Weibull"),
col = c("#B0C4DE", "#C0392B"), lwd = c(8, 4), bty = "n", cex = 0.7)K2 <- length(cortes_seg_medio) - 1
probs2 <- numeric(K2)
for(i in 1:K2) {
probs2[i] <- pweibull(cortes_seg_medio[i+1] - desplazamiento2 + 0.01, shape = shape_seg2, scale = scale_seg2) -
pweibull(cortes_seg_medio[i] - desplazamiento2 + 0.01, shape = shape_seg2, scale = scale_seg2)
}
probs2 <- probs2 / sum(probs2)
n_base <- 100
Fo2 <- as.vector(table(cut(Segmento_Medio, breaks = cortes_seg_medio, right = FALSE))) * (n_base / n_seg2)
Fe2 <- probs2 * n_base
chi2 <- sum((Fo2 - Fe2)^2 / Fe2)
crit2 <- qchisq(0.99, max(1, K2 - 1 - 2))
res2 <- if(chi2 < crit2) "APROBADO" else "RECHAZADO"
pear2 <- cor(Fo2, Fe2) * 100
cat("VALIDACI\u00d3N SEGMENTO 2 (Weibull):\n")## VALIDACIÓN SEGMENTO 2 (Weibull):
## Resultado Chi-cuadrado: APROBADO
## Chi-calculado: 8.75 | Chi-crítico: 9.21
## Correlación de Pearson: 93.39 %
Para este tramo, se utilizó el modelo Normal porque los datos son simétricos y centralizados. Al tener esa forma de campana, es el modelo más eficiente para describir vientos estables que se concentran en un promedio hacia el oeste.
n_seg3 <- length(Segmento_Final)
media_seg3 <- mean(Segmento_Final)
sd_seg3 <- sd(Segmento_Final)
par(mar = c(6, 4, 3, 1))
h_seg_final <- hist(Segmento_Final, breaks = cortes_seg_final, plot = FALSE, right = FALSE)
h_seg_final$counts <- (h_seg_final$counts / n_total) * 100
h_seg_final$density <- h_seg_final$counts / sum(h_seg_final$counts)
plot(h_seg_final,
freq = TRUE,
main = "Gr\u00e1fica N\u00ba 8: Ajuste Normal (198.9\u00b0 a 360\u00b0)",
xlab = "", ylab = "Porcentaje (%)",
col = "#B0C4DE", border = "white", axes = FALSE,
ylim = c(0, max(h_seg_final$counts, na.rm = TRUE) * 1.3),
xlim = c(min(cortes_seg_final), max(cortes_seg_final)))
x_curva <- seq(min(cortes_seg_final), max(cortes_seg_final), length.out = 200)
y_densidad <- dnorm(x_curva, mean = media_seg3, sd = sd_seg3)
ancho_barra <- h_seg_final$breaks[2] - h_seg_final$breaks[1]
y_final <- y_densidad * ancho_barra * 100 * (n_seg3 / n_total)
lines(x_curva, y_final, col = "#C0392B", lwd = 4)
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = h_seg_final$breaks, labels = round(h_seg_final$breaks, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.8)
legend("topright", legend = c("Datos Emp\u00edricos", "Modelo Normal"),
col = c("#B0C4DE", "#C0392B"), lwd = c(8, 4), bty = "n", cex = 0.7)K3 <- length(cortes_seg_final) - 1
probs3 <- numeric(K3)
for(i in 1:K3) {
probs3[i] <- pnorm(cortes_seg_final[i+1], mean = media_seg3, sd = sd_seg3) -
pnorm(cortes_seg_final[i], mean = media_seg3, sd = sd_seg3)
}
probs3 <- probs3 / sum(probs3)
n_base <- 100
Fo3 <- as.vector(table(cut(Segmento_Final, breaks = cortes_seg_final, right = FALSE))) * (n_base / n_seg3)
Fe3 <- probs3 * n_base
chi3 <- sum((Fo3 - Fe3)^2 / Fe3)
crit3 <- qchisq(0.99, max(1, K3 - 1 - 2))
res3 <- if(chi3 < crit3) "APROBADO" else "RECHAZADO"
pear3 <- cor(Fo3, Fe3) * 100
cat("VALIDACI\u00d3N SEGMENTO 3 (Normal):\n")## VALIDACIÓN SEGMENTO 3 (Normal):
## Resultado Chi-cuadrado: APROBADO
## Chi-calculado: 1.85 | Chi-crítico: 13.28
## Correlación de Pearson: 99.97 %
# if(!is.null(dev.list())) dev.off()
par(mar = c(6, 4, 4, 2))
col_seg1 <- "#AED6F1" # Azul
col_seg2 <- "#A9DFBF" # Verde
col_seg3 <- "#FAD7A0" # Naranja
n_total <- length(Variable_Completa)
prop1 <- length(Segmento_Nuevo) / n_total
prop2 <- length(Segmento_Medio) / n_total
prop3 <- length(Segmento_Final) / n_total
h_global <- hist(Variable_Completa, breaks = cortes_globales, plot = FALSE)
h_global$counts <- (h_global$counts / n_total) * 100
h_global$density <- h_global$counts / sum(h_global$counts) # Sincronización interna
colores_barras <- ifelse(h_global$breaks[-1] <= 89.2, col_seg1,
ifelse(h_global$breaks[-1] <= 198.9, col_seg2, col_seg3))
plot(h_global,
freq = TRUE,
col = colores_barras, border = "white",
main = "Gr\u00e1fica N\u00ba 9: Modelo H\u00edbrido Escalado de Direcci\u00f3n del Viento",
xlab = "", ylab = "Porcentaje (%)",
axes = FALSE, ylim = c(0, max(h_global$counts, na.rm = TRUE) * 1.3))
abline(v = c(89.2, 198.9), col = "gray40", lty = "dashed", lwd = 2)
ancho_barra <- h_global$breaks[2] - h_global$breaks[1]
x1 <- seq(min_v, 89.2, length.out = 100)
y1 <- dweibull(90 - x1, shape = shape_ref, scale = scale_ref) * ancho_barra * 100 * prop1
lines(x1, y1, col = "blue4", lwd = 4)
x2 <- seq(89.2, 198.9, length.out = 100)
y2 <- dweibull(x2 - desplazamiento2, shape = shape_seg2, scale = scale_seg2) * ancho_barra * 100 * prop2
lines(x2, y2, col = "darkgreen", lwd = 4)
x3 <- seq(198.9, 360, length.out = 100)
y3 <- dnorm(x3, mean = media_seg3, sd = sd_seg3) * ancho_barra * 100 * prop3
lines(x3, y3, col = "darkorange3", lwd = 4)
axis(2, las = 2, cex.axis = 0.7)
axis(1, at = round(cortes_globales, 1), labels = round(cortes_globales, 1), las = 2, cex.axis = 0.6)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")
mtext("Direcci\u00f3n del Viento (\u00b0)", side = 1, line = 4.5, cex = 0.9)
legend("topright",
legend = c("S1: Weibull Reflejada", "S2: Weibull Est\u00e1ndar", "S3: Normal"),
col = c("blue4", "darkgreen", "darkorange3"),
lwd = 4, bty = "n", cex = 0.75, title = "Modelos H\u00edbridos")n_base <- 100
n1 <- length(Segmento_Nuevo)
K1 <- length(cortes_seg_nuevo) - 1
probs1 <- numeric(K1)
for(i in 1:K1) {
lim_inf_ref <- 90 - cortes_seg_nuevo[i+1] + 0.01
lim_sup_ref <- 90 - cortes_seg_nuevo[i] + 0.01
probs1[i] <- pweibull(lim_sup_ref, shape = shape_ref, scale = scale_ref) -
pweibull(lim_inf_ref, shape = shape_ref, scale = scale_ref)
}
probs1 <- probs1 / sum(probs1)
Fo1 <- as.vector(table(cut(Segmento_Nuevo, breaks = cortes_seg_nuevo, right = FALSE))) * (n_base / n1)
Fe1 <- probs1 * n_base
chi1 <- sum((Fo1 - Fe1)^2 / Fe1)
crit1 <- qchisq(0.99, max(1, K1 - 1 - 2))
res1 <- if(chi1 < crit1) "APROBADO" else "RECHAZADO"
pear1 <- cor(Fo1, Fe1) * 100
n2 <- length(Segmento_Medio)
K2 <- length(cortes_seg_medio) - 1
probs2 <- numeric(K2)
for(i in 1:K2) {
probs2[i] <- pweibull((cortes_seg_medio[i+1] - desplazamiento2) + 0.01, shape = shape_seg2, scale = scale_seg2) -
pweibull((cortes_seg_medio[i] - desplazamiento2) + 0.01, shape = shape_seg2, scale = scale_seg2)
}
probs2 <- probs2 / sum(probs2)
Fo2 <- as.vector(table(cut(Segmento_Medio, breaks = cortes_seg_medio, right = FALSE))) * (n_base / n2)
Fe2 <- probs2 * n_base
chi2 <- sum((Fo2 - Fe2)^2 / Fe2)
crit2 <- qchisq(0.99, max(1, K2 - 1 - 2))
res2 <- if(chi2 < crit2) "APROBADO" else "RECHAZADO"
pear2 <- cor(Fo2, Fe2) * 100
n3 <- length(Segmento_Final)
K3 <- length(cortes_seg_final) - 1
probs3 <- numeric(K3)
for(i in 1:K3) {
probs3[i] <- pnorm(cortes_seg_final[i+1], mean = media_seg3, sd = sd_seg3) -
pnorm(cortes_seg_final[i], mean = media_seg3, sd = sd_seg3)
}
probs3 <- probs3 / sum(probs3)
Fo3 <- as.vector(table(cut(Segmento_Final, breaks = cortes_seg_final, right = FALSE))) * (n_base / n3)
Fe3 <- probs3 * n_base
chi3 <- sum((Fo3 - Fe3)^2 / Fe3)
crit3 <- qchisq(0.99, max(1, K3 - 1 - 2))
res3 <- if(chi3 < crit3) "APROBADO" else "RECHAZADO"
pear3 <- cor(Fo3, Fe3) * 100
library(knitr)
resumen_viento <- data.frame(
"Segmento" = c("S1: Nororiental (Weibull Ref)",
"S2: Transici\u00f3n E-S (Weibull)",
"S3: Occidental (Normal)"),
"Pearson (%)" = c(round(pear1, 2), round(pear2, 2), round(pear3, 2)),
"Chi-Calc" = c(round(chi1, 2), round(chi2, 2), round(chi3, 2)),
"Chi-Crit" = c(round(crit1, 2), round(crit2, 2), round(crit3, 2)),
"Estado" = c(res1, res2, res3)
)
resumen_viento[nrow(resumen_viento) + 1, ] <- c("Autor: Fernando Neira", "", "", "", "")
kable(resumen_viento,
format = "markdown",
align = "lcccc",
caption = "Tabla No. 2: Resumen de validaci\u00f3n de los modelos (Direcci\u00f3n del Viento)")| Segmento | Pearson…. | Chi.Calc | Chi.Crit | Estado |
|---|---|---|---|---|
| S1: Nororiental (Weibull Ref) | 99.32 | 4.49 | 6.63 | APROBADO |
| S2: Transición E-S (Weibull) | 93.39 | 8.75 | 9.21 | APROBADO |
| S3: Occidental (Normal) | 99.97 | 1.85 | 13.28 | APROBADO |
| Autor: Fernando Neira |
Habiendo validado que el comportamiento de la orientación de incidencia solar se ajusta a un modelo híbrido estratificado, procedemos a proyectar escenarios operativos para la optimización de la planta:
\(Pregunta\) \(1\) : ¿Cuál es la probabilidad de que el viento sople desde el Sur/Sureste (entre \(120\)° y \(198.9\)°), ayudando a enfriar los paneles solares para que no pierdan eficiencia por el calor del mediodía?
\(Pregunta\) \(2\): Si instalamos \(120\) sensores de ráfagas, ¿cuántos de ellos detectarán vientos provenientes del Oeste/Noroeste (entre \(250\)° y \(320\)°), los cuales podrían obligar a poner los paneles en ‘modo de protección’ para evitar que se dañen?
n_sub <- length(Segmento_Medio) + length(Segmento_Final)
w2 <- length(Segmento_Medio) / n_sub
w3 <- length(Segmento_Final) / n_sub
prob_p1 <- (pweibull(198.9 - desplazamiento2, shape_seg2, scale_seg2) -
pweibull(120 - desplazamiento2, shape_seg2, scale_seg2)) * w2
prob_p2 <- (pnorm(320, media_seg3, sd_seg3) -
pnorm(250, media_seg3, sd_seg3)) * w3
sensores_p2 <- round(prob_p2 * 120)
f_hibrida_S2_S3 <- function(x) {
y <- numeric(length(x))
idx2 <- x <= 198.9
y[idx2] <- dweibull(x[idx2] - desplazamiento2, shape_seg2, scale_seg2) * w2
idx3 <- x > 198.9
y[idx3] <- dnorm(x[idx3], mean = media_seg3, sd = sd_seg3) * w3
return(y)
}
par(mar = c(5, 5, 4, 2))
curve(f_hibrida_S2_S3, from = 89.2, to = 360, lwd = 3, col = "#2E4053",
main = "Gr\u00e1fica No. 10: Riesgos y Eficiencia en Planta Solar",
xlab = "Direcci\u00f3n del Viento (\u00b0)", ylab = "Densidad",
axes = FALSE, ylim = c(0, max(f_hibrida_S2_S3(seq(90,360,1))) * 1.5))
x_p1 <- seq(120, 198.9, length.out = 100)
polygon(c(120, x_p1, 198.9), c(0, f_hibrida_S2_S3(x_p1), 0), col = rgb(0.1, 0.6, 0.1, 0.5), border = NA)
x_p2 <- seq(250, 320, length.out = 100)
polygon(c(250, x_p2, 320), c(0, f_hibrida_S2_S3(x_p2), 0), col = rgb(0.8, 0.2, 0.1, 0.5), border = NA)
axis(1, at = seq(90, 360, 30), cex.axis = 0.7)
axis(2, las = 2, cex.axis = 0.7)
grid(lty = "dotted")
legend("topright", bty = "n", cex = 0.7,
legend = c("Modelo H\u00edbrido (S2-S3)",
paste0("Enfriamiento (", round(prob_p1*100,2), "%)"),
paste0("Seguridad (", round(prob_p2*100,2), "%)")),
col = c("#2E4053", rgb(0.1, 0.6, 0.1, 0.5), rgb(0.8, 0.2, 0.1, 0.5)),
pch = c(NA, 15, 15), lty = c(1, NA, NA))\(Respuesta\) \(1\) : Se determinó una probabilidad del \(23.15\)% de que el viento sople desde el sector sur (\(120\)° a \(198.9\)°). Este flujo es clave para el proyecto, ya que favorece el enfriamiento natural de los paneles, ayudando a que no pierdan eficiencia por exceso de calor durante las horas de mayor radiación.
\(Respuesta\) \(2\) : Existe una probabilidad del \(15.87\)% de vientos provenientes del sector oeste (\(250\)° a \(320\)°), lo que representa una zona de riesgo estructural. Por lo tanto, de los \(120\) sensores proyectados, se estima que \(19\) unidades deberán configurarse con protocolos de seguridad y anclaje para proteger los paneles de posibles ráfagas fuertes.
El TLC establece que, dada una muestra suficientemente grande (\(n\) > \(30\)), la distribución de las medias muestrales seguirá una distribución Normal. Esto nos permite estimar la Media Poblacional (\(\mu\)) verdadera utilizando intervalos de confianza.Los postulados de confianza empírica sugieren: \(P(\bar{x} - E < \mu < \bar{x} + E) \approx 68\%\) \(P(\bar{x} - 2E < \mu < \bar{x} + 2E) \approx 95\%\) \(P(\bar{x} - 3E < \mu < \bar{x} + 3E) \approx 99\%\) Donde el Margen de Error (E) se define como: \[E = \frac{\sigma}{\sqrt{n}}\]
library(gt)
library(dplyr)
x_bar <- mean(Variable_Completa)
sigma_muestral <- sd(Variable_Completa)
n_tlc <- length(Variable_Completa)
error_est <- sigma_muestral / sqrt(n_tlc)
margen_error_95 <- 2 * error_est
lim_inf_tlc <- x_bar - margen_error_95
lim_sup_tlc <- x_bar + margen_error_95
tabla_tlc_data <- data.frame(
Parametro = "Direcci\u00f3n del Viento Promedio (\u00b0)",
Lim_Inferior = lim_inf_tlc,
Media_Muestral = x_bar,
Lim_Superior = lim_sup_tlc,
Error_Estandar = paste0("+/- ", sprintf("%.4f", margen_error_95)),
Confianza = "95% (2*E)"
)
tabla_tlc_final <- tabla_tlc_data %>%
gt() %>%
tab_header(
title = md("**ESTIMACI\u00d3N DE LA MEDIA POBLACIONAL**"),
subtitle = "Direcci\u00f3n del Viento - Aplicaci\u00f3n del Teorema del L\u00edmite Central"
) %>%
cols_label(
Parametro = "Par\u00e1metro",
Lim_Inferior = "L\u00edmite Inferior",
Media_Muestral = "Media Calculada",
Lim_Superior = "L\u00edmite Superior",
Error_Estandar = "Error Estimado"
) %>%
fmt_number(
columns = c(Lim_Inferior, Media_Muestral, Lim_Superior),
decimals = 4
) %>%
tab_style(
style = list(cell_fill(color = "#EBF5FB"), cell_text(color = "#1A5276", weight = "bold")),
locations = cells_body(columns = Media_Muestral)
)
tabla_tlc_final| ESTIMACIÓN DE LA MEDIA POBLACIONAL | |||||
| Dirección del Viento - Aplicación del Teorema del Límite Central | |||||
| Parámetro | Límite Inferior | Media Calculada | Límite Superior | Error Estimado | Confianza |
|---|---|---|---|---|---|
| Dirección del Viento Promedio (°) | 192.9495 | 193.4319 | 193.9142 | +/- 0.4823 | 95% (2*E) |
La dirección del viento se analizó mediante una triple segmentación con cortes en \(89.2^\circ\) y \(198.9^\circ\), permitiendo un ajuste preciso mediante los modelos Weibull Reflejado, Weibull y Normal, todos validados satisfactoriamente. Gracias al Teorema del Límite Central, se determinó con un \(95\%\) de confianza que la dirección media poblacional se ubica entre \(192.95^\circ\) y \(193.91^\circ\). Este resultado (\(\mu = 193.43^\circ \pm 0.48^\circ\)) confirma un flujo eólico estable que favorece la operatividad térmica de los paneles y proporciona una base sólida para el diseño estructural, minimizando riesgos y optimizando la planificación técnica del proyecto.