1 1. Cargar directorio y datos

# Definimos el directorio de trabajo donde están los archivos CSV
setwd("C:/Users/rebec/Desktop/DOCTORADO/2025/Experimentos/OE1/Exp16grados/12-06-2025")

# Cargamos las librerías necesarias
library(readr)    # Para importar archivos CSV
library(dplyr)    # Para manipulación de datos
library(readxl)   # Para leer archivos Excel

1.1 1.1 Importar datos crudos

# Importamos los datos de los sensores 1, 2 y 3
datos.rebeca.brutos1 <- read_csv("AD448125-S1,2,3.CSV") %>%
  rename(
    Date.Time = `Date/Time`,        # Renombramos para evitar caracteres problemáticos
    Sensor.serial = User,           # Nombre más representativo para el ID del sensor
    Sensor.serial2 = `Sensor serial`# En caso tengamos dos columnas similares, diferenciamos
  )

# Importamos los datos de los sensores 4, 5 y 6
datos.rebeca.brutos2 <- read_csv("A8447716-S4,5,6.CSV") %>%
  rename(
    Date.Time = `Date/Time`,
    Sensor.serial = `Sensor serial`,
    Sensor.serial2 = `User`
  )

# Combinamos ambos archivos en una sola tabla
datos <- rbind(datos.rebeca.brutos1, datos.rebeca.brutos2)

2 2. Asociar sensores con cámaras

# Cargamos la tabla de cámaras, que asocia sensores con las cámaras de incubación
camaras <- read_excel("camaras.xlsx")

# Extraemos los IDs de los sensores, eliminando valores faltantes
sensores <- na.omit(camaras$ID)

3 3. Filtrar y renombrar por sensor

# Para cada sensor, creamos una tabla separada que contenga solo las variables necesarias
for (i in seq_along(sensores)) {
  sensor <- sensores[i]
  tabla_filtrada <- datos[datos$Sensor.serial == sensor, c("Date.Time", "Value", "Value2")]
  colnames(tabla_filtrada) <- c("Date", "OxySens", "TempSens") # Renombramos columnas
  assign(paste0("tabla_sensor_", sensor), tabla_filtrada) # Creamos una variable para cada tabla
}

4 4. Unir tablas y calcular minutos

# Tomamos como referencia la primera tabla (Sensor 1)
tabla_referencia <- get(paste0("tabla_sensor_", sensores[1]))
DataClean.test <- tabla_referencia
colnames(DataClean.test)[2:3] <- c("OxySens1", "TempSens1")

# Agregamos los datos de los otros sensores a la tabla principal
for (i in 2:length(sensores)) {
  sensor <- sensores[i]
  tabla_actual <- get(paste0("tabla_sensor_", sensor))
  DataClean.test <- cbind(DataClean.test, tabla_actual[, c("OxySens", "TempSens")])
  colnames(DataClean.test)[(ncol(DataClean.test) - 1):(ncol(DataClean.test))] <- 
    c(paste0("OxySens", i), paste0("TempSens", i))
}

# Convertimos la fecha a formato POSIXct para cálculos temporales
DataClean.test$Date <- as.POSIXct(DataClean.test$Date, format = "%d.%m.%Y %H:%M:%S")

# Calculamos el tiempo transcurrido en minutos desde el inicio del experimento
DataClean.test$Minutes <- as.numeric(difftime(DataClean.test$Date, min(DataClean.test$Date), units = "mins"))

5 5. Detección automática de incubaciones

# Función que estima la pendiente de O2 vs tiempo para detectar disminuciones de O2
calcular_pendiente <- function(y_vals, x_vals) {
  modelo <- lm(y_vals ~ x_vals)
  coef(modelo)[2]
}

# Definimos el tamaño de la ventana (n puntos consecutivos)
n <- 10
DataClean.test$IncubStatus <- 0

# Para cada subconjunto de 10 puntos, evaluamos la pendiente
for (i in 1:(nrow(DataClean.test) - n + 1)) {
  subset <- DataClean.test[i:(i + n - 1), ]
  pendiente <- calcular_pendiente(subset$OxySens2, subset$Minutes)
  DataClean.test$IncubStatus[i:(i + n - 1)] <- ifelse(pendiente > 0, 0, 1) # 1 si O2 baja
}

# Refinamos: eliminamos los primeros 4 valores negativos para evitar falsos positivos
reemplazar_primeros_n <- function(vector, n) {
  contador <- 0
  reemplazar <- FALSE
  for (i in 1:length(vector)) {
    if (vector[i] == 1) {
      if (contador < n) {
        vector[i] <- 0
        contador <- contador + 1
      }
      reemplazar <- TRUE
    } else if (reemplazar) {
      contador <- 0
      reemplazar <- FALSE
    }
  }
  return(vector)
}

DataClean.test$IncubStatus <- reemplazar_primeros_n(DataClean.test$IncubStatus, 4)

6 6. Numerar incubaciones

# Creamos una columna para identificar el número de cada incubación
DataClean.test$IncubNumber <- 0
incub_counter <- 0
for (i in 1:nrow(DataClean.test)) {
  if (DataClean.test$IncubStatus[i] == 1) {
    if (i == 1 || DataClean.test$IncubStatus[i - 1] == 0) {
      incub_counter <- incub_counter + 1
    }
    DataClean.test$IncubNumber[i] <- incub_counter
  }
}
# Revisamos los números de incubación detectados
unique(DataClean.test$IncubNumber)
##  [1]  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
## [26] 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
## [51] 50 51

7 7. Cálculo de saturación de oxígeno

# Usamos la función DO.saturation del paquete rMR
library(biglm)
library(DBI)
library(rMR)

# Calculamos la saturación de O2 del Sensor 1 con temperatura, salinidad y elevación conocidas
DataClean.test$OxySat1 <- DO.saturation(DataClean.test$OxySens1, DataClean.test$TempSens1, elevation.m = 0, salinity = 35) * 100

# Guardamos el dataset final procesado
write.csv(DataClean.test, file = "DataClean.csv", row.names = FALSE)

8 8. Visualización de resultados

# Graficamos la señal de cada sensor
par(mfrow = c(3, 2))
for (i in 1:6) {
  plot(DataClean.test$Minutes, DataClean.test[[paste0("OxySens", i)]], type = "l",
       ylab = "DO (mg/L)", xlab = "Minutos", main = paste("Sensor", i))
}

# Destacamos con líneas rojas los segmentos identificados como incubaciones
par(mfrow = c(3, 2))
for (i in 1:6) {
  plot(DataClean.test$Minutes, DataClean.test[[paste0("OxySens", i)]], type = "l",
       ylab = "DO (mg/L)", xlab = "Minutos", main = paste("Sensor", i))
  lines(DataClean.test$Minutes[DataClean.test$IncubStatus == 1],
        DataClean.test[[paste0("OxySens", i)]][DataClean.test$IncubStatus == 1],
        col = "red", lwd = 2)
}