Introducción

La detección temprana de fatiga vocal y la evaluación objetiva de la técnica vocal en cantantes y profesionales de la voz requieren enfoques cuantitativos que integren variables acústicas y medidas psicométricas. Este artículo presenta un estudio simulado (n = 240 mediciones) donde se modela la relación entre indicadores acústicos (HNR, jitter, shimmer, intensidad) y un puntaje de fatiga vocal (0–100), además de comparar un grupo con entrenamiento técnico versus un grupo control.

Objetivo

Cuantificar:

  1. La asociación lineal entre variables acústicas y fatiga vocal (coeficiente de Pearson con IC 95%).
  2. Diferencias de fatiga y técnica entre grupos (pruebas de hipótesis y tamaños de efecto).
  3. Un modelo lineal multivariable para evaluar asociaciones ajustadas.

Materiales y métodos

Paquetes

library(tidyverse)
library(knitr)
library(kableExtra)
library(psych)
library(broom)

Generación de datos (reproducible)

set.seed(42)

n <- 240

datos <- tibble(
  ID = 1:n,
  Grupo = sample(c("Entrenamiento_técnico", "Control"), size = n, replace = TRUE),
  Sesion = sample(1:6, size = n, replace = TRUE),
  F0_Hz = rnorm(n, mean = 220, sd = 30),
  Intensidad_dB = rnorm(n, mean = 75, sd = 5) + ifelse(Grupo == "Entrenamiento_técnico", 1.5, 0),
  Jitter_pct = rgamma(n, shape = 2.0, scale = 0.15),
  Shimmer_pct = rgamma(n, shape = 2.2, scale = 0.20),
  HNR_dB = rnorm(n, mean = 18, sd = 3) + ifelse(Grupo == "Entrenamiento_técnico", 0.8, 0),
  SpectralTilt_dB = rnorm(n, mean = -12, sd = 2)
)

fatiga_lat <- 0.8*datos$Jitter_pct + 0.6*datos$Shimmer_pct - 0.25*(datos$HNR_dB - 18) +
  0.15*(datos$Sesion - 3) + rnorm(n, 0, 0.4)

tecnica_lat <- ifelse(datos$Grupo == "Entrenamiento_técnico", 1.0, 0) +
  0.1*(datos$Intensidad_dB - 75) - 0.05*(datos$SpectralTilt_dB + 12) + rnorm(n, 0, 0.5)

datos <- datos %>%
  mutate(
    Fatiga_0_100 = pmin(pmax(50 + 12*fatiga_lat, 0), 100),
    Tecnica_0_100 = pmin(pmax(60 + 10*tecnica_lat, 0), 100)
  )

# Vista rápida (primeras 12 filas)
datos %>%
  select(ID, Grupo, Sesion, HNR_dB, Jitter_pct, Shimmer_pct, Fatiga_0_100, Tecnica_0_100) %>%
  slice(1:12) %>%
  mutate(across(where(is.numeric), ~round(.x, 3))) %>%
  kable(caption = "Tabla 1. Extracto de la base de datos (primeras 12 filas).") %>%
  kable_styling(full_width = FALSE)
Tabla 1. Extracto de la base de datos (primeras 12 filas).
ID Grupo Sesion HNR_dB Jitter_pct Shimmer_pct Fatiga_0_100 Tecnica_0_100
1 Entrenamiento_técnico 1 12.975 0.138 1.374 72.966 62.489
2 Entrenamiento_técnico 3 23.687 0.305 0.385 40.165 56.766
3 Entrenamiento_técnico 3 17.714 0.351 1.018 60.123 66.058
4 Entrenamiento_técnico 6 16.919 0.072 0.409 53.176 66.647
5 Control 4 15.260 0.898 0.821 77.542 62.198
6 Control 4 13.004 0.132 0.478 70.878 57.831
7 Control 4 19.250 0.282 0.344 59.652 50.428
8 Control 3 12.866 0.309 0.389 77.797 63.268
9 Entrenamiento_técnico 1 19.761 0.526 0.269 48.579 82.477
10 Control 1 14.885 0.256 0.034 51.013 67.531
11 Entrenamiento_técnico 1 20.367 0.264 0.467 45.405 66.908
12 Control 6 20.235 0.350 0.984 57.444 55.026

Estadística descriptiva

desc_global <- datos %>%
  select(HNR_dB, Jitter_pct, Shimmer_pct, Intensidad_dB, Fatiga_0_100, Tecnica_0_100) %>%
  pivot_longer(cols = everything(), names_to = "Variable", values_to = "Valor") %>%
  group_by(Variable) %>%
  summarise(
    n = sum(!is.na(Valor)),
    Media = round(mean(Valor, na.rm = TRUE), 3),
    DE = round(sd(Valor, na.rm = TRUE), 3),
    Min = round(min(Valor, na.rm = TRUE), 3),
    Q1 = round(quantile(Valor, 0.25, na.rm = TRUE), 3),
    Mediana = round(median(Valor, na.rm = TRUE), 3),
    Q3 = round(quantile(Valor, 0.75, na.rm = TRUE), 3),
    Max = round(max(Valor, na.rm = TRUE), 3),
    .groups = "drop"
  )

desc_global %>%
  kable(caption = "Tabla 2. Estadísticos descriptivos globales.") %>%
  kable_styling(full_width = FALSE)
Tabla 2. Estadísticos descriptivos globales.
Variable n Media DE Min Q1 Mediana Q3 Max
Fatiga_0_100 240 55.979 11.031 28.020 48.682 56.039 64.374 80.067
HNR_dB 240 18.494 3.067 10.731 16.263 18.507 20.682 25.762
Intensidad_dB 240 75.352 5.009 61.410 71.930 75.352 78.862 91.145
Jitter_pct 240 0.307 0.211 0.011 0.138 0.271 0.419 1.325
Shimmer_pct 240 0.439 0.282 0.034 0.236 0.385 0.607 2.123
Tecnica_0_100 240 64.681 8.582 39.754 59.021 64.188 70.115 87.547
desc_por_grupo <- datos %>%
  group_by(Grupo) %>%
  summarise(
    n = n(),
    Fatiga_media = round(mean(Fatiga_0_100), 3),
    Fatiga_DE = round(sd(Fatiga_0_100), 3),
    Tecnica_media = round(mean(Tecnica_0_100), 3),
    Tecnica_DE = round(sd(Tecnica_0_100), 3),
    HNR_media = round(mean(HNR_dB), 3),
    HNR_DE = round(sd(HNR_dB), 3),
    .groups = "drop"
  )

desc_por_grupo %>%
  kable(caption = "Tabla 3. Descriptivos por grupo.") %>%
  kable_styling(full_width = FALSE)
Tabla 3. Descriptivos por grupo.
Grupo n Fatiga_media Fatiga_DE Tecnica_media Tecnica_DE HNR_media HNR_DE
Control 133 56.952 10.890 60.028 6.410 18.296 3.114
Entrenamiento_técnico 107 54.768 11.136 70.465 7.344 18.739 3.005

Análisis correlacional

El coeficiente de Pearson

En investigación correlacional, el coeficiente de correlación de Pearson (r) evalúa la relación lineal entre dos variables cuantitativas continuas.

Matriz de correlaciones (selección)

vars <- datos %>%
  select(HNR_dB, Jitter_pct, Shimmer_pct, Intensidad_dB, Tecnica_0_100, Fatiga_0_100)

cor_mat <- cor(vars)

cor_mat %>%
  round(3) %>%
  as.data.frame() %>%
  rownames_to_column("Variable") %>%
  kable(caption = "Tabla 4. Matriz de correlaciones (Pearson).") %>%
  kable_styling(full_width = FALSE)
Tabla 4. Matriz de correlaciones (Pearson).
Variable HNR_dB Jitter_pct Shimmer_pct Intensidad_dB Tecnica_0_100 Fatiga_0_100
HNR_dB 1.000 0.001 0.020 0.004 0.043 -0.814
Jitter_pct 0.001 1.000 -0.029 0.066 0.088 0.160
Shimmer_pct 0.020 -0.029 1.000 -0.038 -0.113 0.155
Intensidad_dB 0.004 0.066 -0.038 1.000 0.566 -0.021
Tecnica_0_100 0.043 0.088 -0.113 0.566 1.000 -0.069
Fatiga_0_100 -0.814 0.160 0.155 -0.021 -0.069 1.000

Correlaciones principales con IC 95%

Para el IC 95% de r se utiliza la transformación de Fisher (z).

pearson_ci <- function(r, n, alpha = 0.05){
  z <- atanh(r)
  se <- 1/sqrt(n - 3)
  zcrit <- qnorm(1 - alpha/2)
  lo <- tanh(z - zcrit*se)
  hi <- tanh(z + zcrit*se)
  c(lo, hi)
}

pares <- tribble(
  ~Variable_X, ~Variable_Y,
  "HNR_dB", "Fatiga_0_100",
  "Jitter_pct", "Fatiga_0_100",
  "Shimmer_pct", "Fatiga_0_100",
  "Tecnica_0_100", "Fatiga_0_100"
)

tabla_pearson <- pares %>%
  rowwise() %>%
  mutate(
    n = nrow(datos),
    r = cor(datos[[Variable_X]], datos[[Variable_Y]]),
    p = cor.test(datos[[Variable_X]], datos[[Variable_Y]], method = "pearson")$p.value,
    IC = list(pearson_ci(r, n))
  ) %>%
  ungroup() %>%
  mutate(
    r = round(r, 4),
    p_valor = format(p, scientific = TRUE, digits = 3),
    IC95 = map_chr(IC, ~paste0("[", round(.x[1],3), ", ", round(.x[2],3), "]"))
  ) %>%
  select(Variable_X, Variable_Y, r, IC95, p_valor)

tabla_pearson %>%
  kable(caption = "Tabla 5. Correlaciones de Pearson con IC 95% (Fisher-z).") %>%
  kable_styling(full_width = FALSE)
Tabla 5. Correlaciones de Pearson con IC 95% (Fisher-z).
Variable_X Variable_Y r IC95 p_valor
HNR_dB Fatiga_0_100 -0.8142 [-0.853, -0.767] 3.96e-58
Jitter_pct Fatiga_0_100 0.1597 [0.034, 0.281] 1.32e-02
Shimmer_pct Fatiga_0_100 0.1555 [0.029, 0.277] 1.59e-02
Tecnica_0_100 Fatiga_0_100 -0.0694 [-0.194, 0.058] 2.84e-01

Gráficos (dispersión, cajas, barras y tendencia)

# Dispersión HNR vs Fatiga con recta de regresión
ggplot(datos, aes(x = HNR_dB, y = Fatiga_0_100)) +
  geom_point(alpha = 0.65) +
  geom_smooth(method = "lm", se = TRUE) +
  labs(
    title = "Figura 1. Dispersión: HNR vs Fatiga",
    x = "HNR (dB)",
    y = "Fatiga (0–100)"
  )

# Boxplot Fatiga por grupo
ggplot(datos, aes(x = Grupo, y = Fatiga_0_100)) +
  geom_boxplot() +
  labs(
    title = "Figura 2. Boxplot de fatiga por grupo",
    x = NULL,
    y = "Fatiga (0–100)"
  ) +
  theme(axis.text.x = element_text(angle = 10, hjust = 1))

# Histograma de fatiga
ggplot(datos, aes(x = Fatiga_0_100)) +
  geom_histogram(bins = 20) +
  labs(
    title = "Figura 3. Histograma del puntaje de fatiga",
    x = "Fatiga (0–100)",
    y = "Frecuencia"
  )

# Barras: promedio de técnica por grupo
datos %>%
  group_by(Grupo) %>%
  summarise(Tecnica_media = mean(Tecnica_0_100), .groups = "drop") %>%
  ggplot(aes(x = Grupo, y = Tecnica_media)) +
  geom_col() +
  labs(
    title = "Figura 4. Promedio de técnica por grupo",
    x = NULL,
    y = "Técnica promedio (0–100)"
  ) +
  theme(axis.text.x = element_text(angle = 10, hjust = 1))

# Tendencia: fatiga promedio por sesión
datos %>%
  group_by(Sesion) %>%
  summarise(Fatiga_media = mean(Fatiga_0_100), .groups = "drop") %>%
  ggplot(aes(x = Sesion, y = Fatiga_media)) +
  geom_line() +
  geom_point(size = 2) +
  scale_x_continuous(breaks = 1:6) +
  labs(
    title = "Figura 5. Tendencia del promedio de fatiga por sesión",
    x = "Sesión",
    y = "Fatiga promedio (0–100)"
  )

Inferencia: comparación entre grupos

Prueba t de Welch y tamaño de efecto

t_welch <- t.test(Fatiga_0_100 ~ Grupo, data = datos)

# d de Cohen (aprox., usando DE combinada)
x <- datos %>% filter(Grupo == "Entrenamiento_técnico") %>% pull(Fatiga_0_100)
y <- datos %>% filter(Grupo == "Control") %>% pull(Fatiga_0_100)
d_cohen <- (mean(x) - mean(y)) / sqrt((sd(x)^2 + sd(y)^2)/2)

tabla_t <- tibble(
  Comparacion = "Fatiga (Entrenamiento vs Control)",
  Media_entrenamiento = round(mean(x), 3),
  Media_control = round(mean(y), 3),
  t = round(unname(t_welch$statistic), 3),
  gl = round(unname(t_welch$parameter), 1),
  p_valor = format(t_welch$p.value, scientific = TRUE, digits = 3),
  d_Cohen = round(d_cohen, 3)
)

tabla_t %>%
  kable(caption = "Tabla 6. Prueba t (Welch) y tamaño de efecto (d de Cohen).") %>%
  kable_styling(full_width = FALSE)
Tabla 6. Prueba t (Welch) y tamaño de efecto (d de Cohen).
Comparacion Media_entrenamiento Media_control t gl p_valor d_Cohen
Fatiga (Entrenamiento vs Control) 54.768 56.952 1.525 224.9 1.29e-01 -0.198

Modelo lineal multivariable

modelo <- lm(Fatiga_0_100 ~ HNR_dB + Jitter_pct + Shimmer_pct + Sesion + Grupo, data = datos)

resumen_modelo <- broom::tidy(modelo) %>%
  mutate(
    estimate = round(estimate, 4),
    std.error = round(std.error, 4),
    statistic = round(statistic, 3),
    p.value = format(p.value, scientific = TRUE, digits = 3)
  )

glance_modelo <- broom::glance(modelo) %>%
  transmute(R2 = round(r.squared, 3), R2_ajustado = round(adj.r.squared, 3), AIC = round(AIC, 2))

resumen_modelo %>%
  kable(caption = "Tabla 7. Coeficientes del modelo lineal (OLS).") %>%
  kable_styling(full_width = FALSE)
Tabla 7. Coeficientes del modelo lineal (OLS).
term estimate std.error statistic p.value
(Intercept) 98.8719 2.0588 48.025 3.65e-123
HNR_dB -3.0054 0.1006 -29.875 8.18e-82
Jitter_pct 8.9249 1.4557 6.131 3.68e-09
Shimmer_pct 7.5480 1.0942 6.898 4.88e-11
Sesion 1.9749 0.1757 11.239 1.02e-23
GrupoEntrenamiento_técnico -0.2599 0.6206 -0.419 6.76e-01
glance_modelo %>%
  kable(caption = "Tabla 8. Métricas globales del modelo.") %>%
  kable_styling(full_width = FALSE)
Tabla 8. Métricas globales del modelo.
R2 R2_ajustado AIC
0.819 0.815 1436.62
# Diagnósticos básicos
par(mfrow = c(2,2))
plot(modelo)

par(mfrow = c(1,1))

Conclusiones

En el marco del estudio simulado realizado, los resultados obtenidos permiten extraer varias conclusiones relevantes sobre la relación entre variables acústicas objetivas, fatiga vocal y entrenamiento técnico.

En primer lugar, el Harmonics-to-Noise Ratio (HNR) mostró una asociación negativa fuerte y consistente con la fatiga vocal, lo que sugiere que una mayor proporción armónico-ruido indicativa de una producción vocal más estable y eficiente se relaciona con menores niveles de percepción de fatiga. Este hallazgo es coherente con la literatura previa que vincula una mejor calidad vocal con menor esfuerzo fonatorio.

Por otro lado, los parámetros de jitter y shimmer, indicadores de inestabilidad en la frecuencia y amplitud de la señal vocal, presentaron asociaciones positivas débiles pero estadísticamente significativas con la fatiga vocal. Aunque la magnitud de estas asociaciones fue moderada, los resultados sugieren que incrementos en la irregularidad vibratoria de las cuerdas vocales podrían contribuir, incluso de forma sutil, a una mayor percepción de cansancio vocal.

Asimismo, el grupo con entrenamiento técnico vocal evidenció mayores puntajes de técnica vocal y una leve reducción en los niveles de fatiga, lo que respalda la hipótesis de que la formación técnica puede actuar como un factor protector frente al esfuerzo vocal excesivo. Si bien la diferencia en fatiga fue moderada, la tendencia observada resulta clínicamente relevante.

Finalmente, el modelo multivariable confirmó que el efecto negativo del HNR sobre la fatiga vocal se mantiene incluso tras ajustar por covariables acústicas y técnicas, lo que refuerza la importancia de este parámetro como predictor independiente de la fatiga vocal en el contexto analizado.

En conjunto, estos resultados resaltan el valor de integrar medidas acústicas objetivas y variables de entrenamiento técnico en el estudio de la fatiga vocal, aportando evidencia preliminar que podría orientar futuras investigaciones con muestras empíricas y diseños longitudinales.