LedB

La taxonomía de objetivos de aprendizaje de Marzano y Kendall (2007) incorpora, en el máximo nivel, el Sistema de Conciencia del Ser (autorregulación)

Modificar los hábitos de habla en un espacio mejorado acústicamente no es automático, requiere facilitar la autorregulación (evaluando la importancia, la eficacia, las emociones y la motivación)

Objetivo: facilitar a los hablantes que se autorregulen con la toma de conciencia del nivel de logro en la mejora.

Para ello crearemos un dispositivo colectivo que mide y muestra visualmente el nivel de intensidad sonora. 

🎯 Autoregulación Escolar: El Semáforo Acústico Inteligente

🚦 Transformando Espacios Educativos a través de la Conciencia Sonora

Más allá de ser una herramienta de aprendizaje STEM, este sonómetro visual se convierte en un agente de cambio conductual que promueve ambientes escolares más saludables y productivos.


🟢 ZONA VERDE (40-55 dB) → 📚 CONCENTRACIÓN ÓPTIMA
   ├── Lectura individual fluida
   ├── Trabajo en grupos pequeños
   └── Explicaciones del profesorado claras

🟡 ZONA AMARILLA (55-70 dB) → ⚠️ ALERTA PREVENTIVA
   ├── Actividades colaborativas moderadas
   ├── Discusiones dirigidas
   └── Transiciones entre actividades

🔴 ZONA ROJA (+70 dB) → 🚨 ACCIÓN NECESARIA
   ├── Ruido excesivo que interfiere
   ├── Pérdida de concentración
   └── Necesidad de intervención inmediata

💡 Beneficios Observados:

  • Autorregulación inmediata: Los estudiantes ajustan su volumen al ver los LEDs
  • Reducción del estrés docente: Menos necesidad de intervenciones verbales
  • Mejora del rendimiento: Ambiente más propicio para el aprendizaje
  • Desarrollo de la conciencia social: Respeto por el espacio compartido


🍽️ COMEDORES: Ambiente Alimentario Saludable

🎨 Estrategia Visual del "Termómetro del Comedor"
🟢 COMIDA TRANQUILA (50-65 dB)
   └── 😌 Digestión óptima + Conversación relajada
   └── 🗣️ Socialización saludable
   └── ✨ Experiencia gastronómica positiva

🟡 SOCIALIZACIÓN ACTIVA (65-75 dB)
   └── 👥 Interacción social normal
   └── 🎉 Celebraciones moderadas
   └── ⚖️ Balance entre social y salud

🔴 SOBRECARGA SENSORIAL (+75 dB)
   └── 😰 Estrés alimentario
   └── 🔊 Comunicación dificultada
   └── 💢 Ambiente poco saludable


🎯 Principios Pedagógicos Aplicados

🟢 Refuerzo Positivo Inmediato
  • Verde = Aprobación: Los estudiantes sienten satisfacción inmediata
  • Gamificación natural: "Mantener el verde" se convierte en un juego
  • Reconocimiento social: El grupo se autorregula colectivamente
🟡 Zona de Atención Sin Castigo
  • Amarillo = Prevención: Alerta temprana sin consecuencias negativas
  • Oportunidad de corrección: Tiempo para autoajuste antes del problema
  • Aprendizaje gradual: Desarrollo de la conciencia acústica
🔴 Indicador de Acción Necesaria
  • Rojo = Llamada de atención: Señal clara pero no punitiva
  • Responsabilidad compartida: Todo el grupo participa en la solución
  • Reflexión sobre consecuencias: Conexión entre ruido y bienestar


🧠 Psicología de la Autoregulación Visual

⚡ Feedback Inmediato vs Intervención Tardía

SISTEMA TRADICIONAL:
Ruido → Molestia → Intervención Adulta → Corrección
  🔊             😤                      👨‍🏫                              📉
(Reactivo - Genera conflicto)

SISTEMA SONÓMETRO LED:
Ruido → Visualización → Autorregulación → Mantenimiento
  🔊               🌈                             😊                           ✅
(Proactivo - Genera conciencia)



📈 Impacto en la Convivencia Escolar

🎓 Competencias de Ciudadanía Desarrolladas

CompetenciaDesarrolloEvidencia Observable
🤝 Empatía AcústicaConsideración hacia otrosReducción voluntaria del volumen
🧘 AutorregulaciónControl interno del comportamientoAjuste proactivo sin supervisión
👥 Responsabilidad ColectivaCuidado del ambiente comúnIntervención positiva entre pares
📊 Conciencia AmbientalComprensión causa-efectoCorrelación ruido-bienestar


🧠 Impacto Neurológico
  • Reducción del cortisol: Menos estrés por ruido excesivo
  • Mejora de la concentración: Ambiente más propicio para el focus
  • Calidad del sueño: Menos fatiga auditiva acumulada

👂 Protección Auditiva
  • Prevención de daños: Exposición controlada a niveles seguros
  • Educación en salud auditiva: Conciencia sobre límites saludables
  • Hábitos de por vida: Desarrollo de sensibilidad acústica permanente

🌱 Desarrollo Social
  • Comunicación efectiva: Mejor calidad en las conversaciones
  • Resolución de conflictos: Menos tensiones por ruido excesivo
  • Inclusión: Ambiente más cómodo para estudiantes sensibles

🔧 Componentes STEM Integrados

STEMComponenteAplicación
🧪 ScienceAnálisis FFT + Ponderación AFísica del sonido y psicoacústica
💻 TechnologyMicrófono I2S + ESP32Procesamiento digital de señales
⚙️ EngineeringDiseño de circuitos + LEDsSistemas embebidos y visualización
📊 MathematicsAlgoritmos DSP + EstadísticaTransformadas, promedios y mapeo


📈 Medir el sonido


No es sencillo por varios motivos que podéis consultar en este enlace

Queremos una sensibilidad y una banda de frecuencia suficiente para medir desde 40 dB hasta 90 dB con ponderación dB(A) que es la que se corresponde con la percepción de nuestro oido.

Nuestra elección, por coste rendimiento, ha sido el micrófono digital MEMS INP441
Como segunda opción, el MEMS ICS-43434

Ambos trabajan con el interface I2S que encontramos en el ESP32.

Algunos prototipos comunes de semáforos de ruido utilizan micrófonos analógicos electret, por lo general el resultado está más cerca de unas luces de fiesta que de un auténtico medidor de intensidad del sonido. 


⚙️Placa controladora

Si necesitamos disponer de interface I2S hay que verificar que está disponible en nuestra controladora. 
Nuestro prototipo utiliza una ESP32-S3 supermini. Tambien ha funcionado con la azdelivery Lolin32  y ESP32 D1 R32 


📊Visualización

Para visualizar los dB medidos utilizamos una tira Neopixel.

El número de leds iluminados de la tira corresponden al nivel de dB(A) medido.
El color va variando, los primeros leds verdes, después pasan a ámbar y los niveles máximos en rojo. 
Es un híbrido de semáforo y vúmetro led (vúmetrro semafórico)

⚙️Prototipo








⚙️Conexiones

1. Micrófono I2S al ESP32

Micrófono I2SESP32 GPIO
VDD (3.3V)                        3.3V
GND                        GND
SD (DATA)                        GPIO 1
SCK (BCLK)                        GPIO 2
WS (LRCLK)                        GPIO 7
L/R            GND (para canal izquierdo)

2. Tira LED WS2812B al ESP32

WS2812B    ESP32 GPIO    Fuente Externa
DIN (Data)        GPIO 8            -
5V                -            5V
GND        GND            GND

Nota importante: Para la alimentación de los LEDs:

  • Si son pocos LEDs (como en este caso), se puede usar la salida 5V del ESP32
  • Para más de 8-10 LEDs, usar una fuente externa de 5V y conectar GND común

3. Consideraciones adicionales

  1. Capacitor de filtrado
    • Colocar un capacitor de 1000μF entre 5V y GND cerca de la tira LED. Ayuda a estabilizar la alimentación y previene picos de corriente
  2. Resistencia de protección
    • Colocar una resistencia de 330-470Ω entre GPIO 8 y la entrada de datos de la tira LED
    • Protege el primer LED y el GPIO del microcontrolador

📊Test de medición

Para la realización de la prueba hemos añadido una pantalla OLED que muestra los dB medidos para poder comparar con la medición del sonómetro comercial.

Nuestro visualizador mide entre 40 y 90 dB.
Los micrófonos MEMS tinen una limitación en la medición de intensidades de sonido. No miden por debajo de 30 dB. En nuestro caso es irrelevante porque en un contexto de actividad escolar casi siempre se dan lecturas por encima de 50 dB.








En el prototipo trabajamos con una tira de 11 leds (neopixel) lo que equivale a 5 dB por led.
Vista la precisión, podemos incrementar el número de leds por tira hasta 25, equivaldria a 2 dB por led. 

En las imágenes de comprobación de precisión, pueden verse las lecturas del prototipo y de una versión funcional de mayor tamaño (40 cm x 10 cm), con cuatro tiras led para asegurar la visualización con luz de dia y a distancia.

Listo para trabajar la autorregulación de los hablantes en nuevos espacios de aprendizaje. 

También en comedores escolares acústicamente mejorados.








💻Código Arduino.

Estructura y componentes principales
  1. Hardware utilizado:
    • Microcontrolador ESP32
    • Micrófono digital I2S INMP441
    • Tira de LEDs WS2812B (11 LEDs configurados)
  2. Bibliotecas clave:
    • Arduino.h - Framework base
    • driver/i2s.h - Interfaz de audio digital
    • FastLED.h - Control de LEDs
    • CircularBuffer.hpp - Gestión de buffer circular para datos
    • arduinoFFT.h - Análisis de frecuencias

Flujo de funcionamiento

El sistema opera en un ciclo continuo con estas etapas:

  1. Configuración inicial (setup()):
    • Inicialización de LEDs (apagados)
    • Configuración del bus I2S para comunicación con el micrófono
    • Preparación de estructuras de datos para FFT
  2. Ciclo principal (loop()):
    • Captura constante de audio a través de I2S
    • Actualización de visualización LED cada 50ms (configurable)
  3. Procesamiento de audio (processAudio()):
    • Cálculo de RMS (Root Mean Square) de la señal
    • Aplicación de FFT para análisis espectral
    • División del espectro en 12 bandas de frecuencia
    • Aplicación de ponderación A (simula respuesta del oído humano)
    • Conversión a decibelios (dBA)
    • Almacenamiento en buffer circular
  4. Visualización (updateLEDDisplay()):
    • Mapeo de niveles de sonido a número de LEDs activos
    • Asignación de colores según intensidad:
      • Verde: niveles bajos
      • Amarillo: niveles medios
      • Rojo: niveles altos

Características técnicas clave

  • Muestreo de audio:
    • Frecuencia: 44.1 kHz (calidad CD)
    • Resolución: 32 bits
    • Buffer DMA: 8 buffers de 1024 muestras
  • Análisis espectral:
    • FFT de 1024 puntos
    • Ventana Hanning/Hamming para mejor precisión
    • 12 bandas de frecuencia en escala logarítmica
  • Procesamiento acústico:
    • Cálculo de RMS verdadero
    • Ponderación A (dBA) para simular percepción humana
    • Rango configurable: 40-90 dB

Diagrama de flujo de datos

Micrófono I2S → Captura muestras → Cálculo RMS → FFT → 
Análisis por bandas → Ponderación A → Conversión a dB → 
Buffer circular → Promediado → Mapeo a LEDs → Visualización

Optimizaciones implementadas

  1. Rendimiento:
    • Uso de DMA para captura de audio sin bloqueo
    • Ventana FFT para reducir efectos de borde
    • Buffer circular para estabilizar lecturas
  2. Precisión acústica:
    • Ponderación A para mejor representación de percepción humana
    • Escala logarítmica para bandas de frecuencia
    • Promediado temporal para reducir fluctuaciones

/**
 * ESP32 Sound Level Meter with LED Display
 * 
 * Este sistema captura audio mediante un micrófono I2S digital, 
 * procesa la señal para calcular niveles de sonido en dB(A),
 * y visualiza los resultados en una tira de LEDs WS2812B.
 * 
 * Características:
 * - Captura de audio digital mediante interfaz I2S
 * - Análisis FFT para procesamiento en dominio de frecuencia
 * - Ponderación A para simular la respuesta del oído humano
 * - Visualización mediante LEDs con escala de colores según intensidad
 * 
 * Hardware recomendado:
 * - ESP32 (cualquier variante)
 * - Micrófono digital I2S (INMP441, SPH0645, etc.)
 * - Tira de LEDs WS2812B
 * 
 * Conexiones:
 * - I2S WS (Word Select/LRCLK): GPIO 7
 * - I2S SD (Serial Data): GPIO 1
 * - I2S SCK (Serial Clock/BCLK): GPIO 2
 * - LED Data: GPIO 8
 * 
 * Autor: Vicent Villena Serrano
 * Herramienta de refinamiento: Claude AI
 * Fecha: Mayo 2025
 */

#include <Arduino.h>
#include <driver/i2s.h>
#include <FastLED.h>
#include <CircularBuffer.hpp>
#include <arduinoFFT.h>

// ==================== CONFIGURACIÓN DE CONSTANTES ====================

// Configuración de LED
#define LED_PIN     8       // El pin GPIO conectado a la entrada de datos de la tira WS2812
#define NUM_LEDS    11      // Número de LEDs en la tira (ajustable según configuración)
#define LED_TYPE    WS2812B // Tipo de LED (WS2812, WS2812B, WS2811, etc.)
#define COLOR_ORDER GRB     // Orden de color (GRB para WS2812, puede variar según modelo)
#define BRIGHTNESS  150     // Brillo global (0-255)
#define STRIPS      1       // Número de tiras LED conectadas en zigzag (para configuraciones avanzadas)
#define STEP        (254/NUM_LEDS/STRIPS) // Incremento de color entre LEDs sucesivos

// Configuración de I2S (protocolo de audio digital)
#define I2S_WS      7       // Word Select (LRCLK) - Selecciona canal I/D
#define I2S_SD      1       // Serial Data - Datos del micrófono
#define I2S_SCK     2       // Serial Clock (BCLK) - Reloj de bits
#define I2S_PORT    I2S_NUM_0 // Puerto I2S del ESP32 (0 o 1)

// Parámetros de audio mejorados
#define SAMPLE_RATE       44100   // Frecuencia de muestreo en Hz (calidad CD)
#define SAMPLE_BITS       32      // Bits por muestra
#define DMA_BUFFER_COUNT  8       // Número de buffers DMA para I2S
#define DMA_BUFFER_LENGTH 1024    // Tamaño de cada buffer DMA en samples
#define UPDATE_INTERVAL   50      // Intervalo de actualización visual en ms
#define BUFFER_SIZE       50      // Tamaño del buffer circular para promediar lecturas
#define DB_MIN            40      // Nivel mínimo de dB para mapeo a LEDs
#define DB_MAX            90      // Nivel máximo de dB para mapeo a LEDs

// Configuración de FFT (Transformada Rápida de Fourier)
#define FFT_SAMPLES       1024    // Número de muestras para FFT (potencia de 2)
#define NUM_BANDS         12      // Número de bandas de frecuencia para el análisis espectral

// ==================== VARIABLES GLOBALES ====================

// Buffer circular para almacenar niveles de sonido y reducir fluctuaciones
CircularBuffer<float, BUFFER_SIZE> buffer;
unsigned long lastUpdateTime = 0;  // Timestamp de la última actualización de LEDs

// Array de LEDs para control mediante FastLED
CRGB leds[NUM_LEDS];

// Variables para cálculo de FFT
ArduinoFFT<double> FFT;        // Objeto FFT
double vReal[FFT_SAMPLES];     // Parte real de los datos FFT
double vImag[FFT_SAMPLES];     // Parte imaginaria de los datos FFT
float bandValues[NUM_BANDS];   // Valores de energía para cada banda de frecuencia
float aWeightedSum = 0;        // Suma ponderada de energía (curva A)

// Task handle para procesamiento en segundo plano (no utilizado en esta versión)
TaskHandle_t audioProcessingTask;

// ==================== DECLARACIONES DE FUNCIONES ====================

void setupLEDs();              // Inicializa la tira de LEDs
void setupI2S();               // Configura el periférico I2S para captura de audio
void captureAudio();           // Captura muestras de audio desde el micrófono
void processAudio(int32_t* samples, int samplesRead);  // Procesa muestras de audio capturadas
void updateLEDDisplay(float averageDB);                // Actualiza visualización LED según nivel
float calculateAverageFromBuffer();                    // Calcula promedio desde buffer circular
void performFFT(double *vReal, double *vImag, int samples);  // Realiza análisis FFT
float applyAWeighting(float* bandValues, int numBands);      // Aplica ponderación A
float calculateRMS(int32_t* samples, int samplesRead);       // Calcula valor RMS
float freqToAWeight(float freq);                             // Calcula factor de ponderación A para frecuencia

// ==================== FUNCIONES PRINCIPALES ====================

/**
 * Configuración inicial del sistema
 */
void setup() {
  Serial.begin(115200); 
  Serial.println("Inicializando sonómetro ESP32...");
  
  setupLEDs();
  setupI2S();
  
  lastUpdateTime = millis();
  
  // Inicializa el array de imaginarios para la FFT
  for (int i = 0; i < FFT_SAMPLES; i++) {
    vImag[i] = 0;
  }
  
  Serial.println("Sistema inicializado correctamente");
}

/**
 * Bucle principal del programa
 */
void loop() {
  // Captura continua de audio
  captureAudio();
  
  // Actualiza la visualización LED cada UPDATE_INTERVAL ms
  if (millis() - lastUpdateTime >= UPDATE_INTERVAL) {
    lastUpdateTime = millis();
    
    // Obtiene el promedio de nivel sonoro desde el buffer circular
    float avgDB = calculateAverageFromBuffer();
    
    // Actualiza visualización de LEDs con el valor promediado
    updateLEDDisplay(avgDB);
  }
}

// ==================== IMPLEMENTACIÓN DE FUNCIONES ====================

/**
 * Configura la tira de LEDs con los parámetros definidos
 */
void setupLEDs() {
  Serial.println("Configurando LEDs...");
  
  // Inicializar la tira de LEDs con corrección de color típica
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
  
  // Apagar todos los LEDs al inicio
  fill_solid(leds, NUM_LEDS, CRGB::Black);
  FastLED.show();
  
  Serial.printf("LEDs configurados: %d LEDs en pin %d\n", NUM_LEDS, LED_PIN);
}

/**
 * Configura el periférico I2S para la adquisición de audio digital
 */
void setupI2S() {
  Serial.println("Configurando interfaz I2S...");
  
  // Estructura de configuración I2S
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),  // Modo maestro, solo recepción
    .sample_rate = SAMPLE_RATE,                           // Frecuencia de muestreo (44.1 kHz)
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,         // Resolución de 32 bits
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,          // Solo canal izquierdo
    .communication_format = I2S_COMM_FORMAT_I2S,          // Formato estándar I2S
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,             // Prioridad de interrupción
    .dma_buf_count = DMA_BUFFER_COUNT,                    // Número de buffers DMA
    .dma_buf_len = DMA_BUFFER_LENGTH,                     // Longitud de cada buffer
    .use_apll = true,                                     // Usar APLL para mayor precisión
    .tx_desc_auto_clear = false,                          // No auto-limpiar descriptores TX
    .fixed_mclk = 0                                       // No usar MCLK fijo
  };

  // Configuración de pines I2S
  i2s_pin_config_t pin_config = {
    .bck_io_num = I2S_SCK,           // Bit clock
    .ws_io_num = I2S_WS,             // Word select
    .data_out_num = I2S_PIN_NO_CHANGE, // No usamos salida de datos
    .data_in_num = I2S_SD            // Entrada de datos desde micrófono
  };

  // Instalación del driver I2S
  i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  i2s_set_pin(I2S_PORT, &pin_config);
  
  Serial.printf("I2S configurado: %d Hz, %d bits en pines WS:%d, SD:%d, SCK:%d\n", 
                SAMPLE_RATE, SAMPLE_BITS, I2S_WS, I2S_SD, I2S_SCK);
}

/**
 * Captura muestras de audio desde el micrófono I2S
 */
void captureAudio() {
  static int32_t samples[DMA_BUFFER_LENGTH];  // Buffer estático para muestras de audio
  size_t bytes_read;

  // Lee muestras de audio desde I2S con espera indefinida
  i2s_read(I2S_PORT, samples, sizeof(samples), &bytes_read, portMAX_DELAY);
  
  // Convierte bytes leídos a número de muestras
  int samples_read = bytes_read / sizeof(int32_t);
  
  // Procesa las muestras capturadas
  processAudio(samples, samples_read);
}

/**
 * Procesa las muestras de audio capturadas mediante FFT y cálculos acústicos
 * 
 * @param samples Puntero al array de muestras capturadas
 * @param samplesRead Número de muestras disponibles
 */
void processAudio(int32_t* samples, int samplesRead) {
  // Calcular RMS verdadero (medida de la amplitud de la señal)
  float rms = calculateRMS(samples, samplesRead);
  
  // Preparar datos para FFT aplicando ventana de Hanning
  for (int i = 0; i < FFT_SAMPLES && i < samplesRead; i++) {
    // Aplicar ventana de Hanning para reducir fugas espectrales
    float hann = 0.5 * (1 - cos(2 * PI * i / (FFT_SAMPLES - 1)));
    vReal[i] = (double)samples[i] * hann;
    vImag[i] = 0.0; // Parte imaginaria inicializada a 0
  }
  
  // Realizar la transformada rápida de Fourier (FFT)
  performFFT(vReal, vImag, FFT_SAMPLES);
  
  // Dividir el espectro en bandas de frecuencia (escala logarítmica)
  for (int i = 0; i < NUM_BANDS; i++) {
    // Cálculo de límites de cada banda usando escala logarítmica
    int lowerBin = 2 + pow(2, i * 10.0 / NUM_BANDS); 
    int upperBin = 2 + pow(2, (i + 1) * 10.0 / NUM_BANDS);
    
    // Limitar los índices al rango válido de la FFT
    lowerBin = constrain(lowerBin, 2, FFT_SAMPLES / 2 - 1);
    upperBin = constrain(upperBin, 2, FFT_SAMPLES / 2 - 1);
    
    // Calcular el promedio de energía en esta banda
    float sum = 0;
    for (int j = lowerBin; j <= upperBin; j++) {
      sum += vReal[j];
    }
    bandValues[i] = sum / (upperBin - lowerBin + 1);
  }
  
  // Aplicar ponderación A (simula respuesta del oído humano)
  float dbA = applyAWeighting(bandValues, NUM_BANDS);
  
  // Convertir a decibelios con ponderación A (dBA)
  // Referencia estándar: 32768 es punto medio de int16 para normalización
  float dbLevel = 20 * log10(dbA / 32768.0) + 0; 
  
  // Almacena el nivel en el buffer circular para suavizado temporal
  buffer.push(dbLevel);
  
  // Mostrar nivel de sonido en la consola serial
  Serial.printf("Sound level: %.1f dB(A)\n", dbLevel);
}

/**
 * Calcula el valor RMS verdadero (Root Mean Square) de la señal
 * RMS es una medida estadística de la magnitud de una cantidad variable
 * 
 * @param samples Puntero al array de muestras
 * @param samplesRead Número de muestras disponibles
 * @return Valor RMS calculado
 */
float calculateRMS(int32_t* samples, int samplesRead) {
  double sum = 0;
  for (int i = 0; i < samplesRead; i++) {
    // Elevar al cuadrado cada muestra y acumular
    sum += (double)samples[i] * samples[i];
  }
  // Dividir por el número de muestras y obtener la raíz cuadrada
  return sqrt(sum / samplesRead);
}

/**
 * Realizar FFT en los datos de audio usando la biblioteca ArduinoFFT
 * 
 * @param vReal Puntero al array con la parte real de los datos
 * @param vImag Puntero al array con la parte imaginaria de los datos
 * @param samples Número de muestras a procesar
 */
void performFFT(double *vReal, double *vImag, int samples) {
  // Crear objeto FFT con los arrays proporcionados
  FFT = ArduinoFFT<double>(vReal, vImag, samples, SAMPLE_RATE);
  
  // Aplicar ventana Hamming para mejorar precisión espectral
  FFT.windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  
  // Calcular la FFT
  FFT.compute(FFT_FORWARD);
  
  // Convertir valores complejos a magnitudes
  FFT.complexToMagnitude();
}

/**
 * Aplica la ponderación A a las bandas de frecuencia para simular
 * la respuesta del oído humano a diferentes frecuencias
 * 
 * @param bandValues Array con valores de energía por banda
 * @param numBands Número de bandas disponibles
 * @return Valor ponderado según curva A
 */
float applyAWeighting(float* bandValues, int numBands) {
  float weightedSum = 0;
  float totalWeight = 0;
  
  for (int i = 0; i < numBands; i++) {
    // Calcular la frecuencia central aproximada de cada banda (Hz)
    float freq = SAMPLE_RATE * (pow(2, i * 10.0 / numBands) + pow(2, (i + 1) * 10.0 / numBands)) / (4 * FFT_SAMPLES);
    
    // Obtener el factor de ponderación A para esta frecuencia
    float aWeight = freqToAWeight(freq);
    
    // Aplicar el peso al valor de energía de la banda
    weightedSum += bandValues[i] * aWeight;
    totalWeight += aWeight;
  }
  
  // Normalizar por el total de pesos para mantener escala correcta
  if (totalWeight > 0) {
    return weightedSum / totalWeight;
  }
  return weightedSum;
}

/**
 * Calcula el factor de ponderación A para una frecuencia dada
 * La curva de ponderación A simula la sensibilidad del oído humano
 * a diferentes frecuencias (menos sensible a frecuencias muy bajas o muy altas)
 * 
 * @param freq Frecuencia en Hz para la que se calcula el factor
 * @return Factor de ponderación A (0-1)
 */
float freqToAWeight(float freq) {
  // Fórmula de aproximación para la curva de ponderación A
  float f2 = freq * freq;
  float f4 = f2 * f2;
  
  // Constantes para la fórmula estándar de ponderación A
  const float c1 = 12200 * 12200;  // Constante relacionada con la frecuencia de resonancia del oído
  const float c2 = 20.6 * 20.6;    // Constante relacionada con respuesta a bajas frecuencias
  const float c3 = 107.7 * 107.7;  // Constante de ajuste de respuesta de medias frecuencias
  const float c4 = 737.9 * 737.9;  // Constante de ajuste de respuesta de altas frecuencias
  
  // Calculamos la ponderación A según la fórmula estándar IEC 61672:2003
  float num = c1 * f4;
  float denom = (f2 + c2) * sqrt((f2 + c3) * (f2 + c4)) * (f2 + c1);
  
  float A = num / denom;
  
  return A;
}

/**
 * Calcula el promedio de los niveles de sonido almacenados en el buffer
 * para estabilizar la visualización y reducir fluctuaciones rápidas
 * 
 * @return Nivel promedio en dB(A)
 */
float calculateAverageFromBuffer() {
  if (buffer.isEmpty()) {
    return 0.0;  // Evitar cálculos innecesarios si el buffer está vacío
  }
  
  float avg = 0.0;
  
  // Calcula el promedio de todos los valores en el buffer circular
  using index_t = decltype(buffer)::index_t;
  for (index_t i = 0; i < buffer.size(); i++) {
    avg += buffer[i];
  }
  avg /= buffer.size();
  
  Serial.print("Average dB(A): ");
  Serial.println(avg);
  
  return avg;
}

/**
 * Actualiza la visualización LED según el nivel de sonido promedio
 * Utiliza un esquema de colores que va de verde (bajo) a rojo (alto)
 * 
 * @param averageDB Nivel de sonido promedio en dB(A)
 */
void updateLEDDisplay(float averageDB) {
  // Mapea el nivel de audio a la cantidad de LEDs a encender
  // DB_MIN y DB_MAX definen el rango de trabajo del sonómetro
  int max_led = map(averageDB, DB_MIN, DB_MAX, 1, NUM_LEDS/STRIPS);
  max_led = constrain(max_led, 0, NUM_LEDS/STRIPS);
  
  Serial.print("LEDs activos: ");
  Serial.println(max_led);
  
  // Limpia la pantalla LED (apaga todos los LEDs)
  FastLED.clear();
  
  // Configura los LEDs con un gradiente de color según la intensidad
  for(int i = 0; i < max_led; i++) {
    // Colores basados en niveles de dB(A)
    CRGB color;
    if (i < NUM_LEDS / (3 * STRIPS)) {
      // Verde para niveles bajos (0-33%)
      color = CRGB(0, 255 - i * STEP, 0);
    } else if (i < 2 * NUM_LEDS / (3 * STRIPS)) {
      // Amarillo para niveles medios (33-66%)
      color = CRGB(i * STEP, 255 - i * STEP, 0);
    } else {
      // Rojo para niveles altos (66-100%)
      color = CRGB(255, 0, 0);
    }
    
    // Asigna el color calculado al LED actual
    leds[i] = color;
    
    // Código para múltiples tiras conectadas en zigzag (deshabilitado por defecto)
    // Descomentar y ajustar para usar múltiples tiras conectadas en zigzag
    /*
    // Tira 2: orden inverso (para conexión en zigzag)
    int i2 = 2 * NUM_LEDS/STRIPS - i - 1;
    leds[i2] = color;
    
    // Tira 3: orden normal
    int i3 = i + 2 * NUM_LEDS/STRIPS;
    leds[i3] = color;
    
    // Tira 4: orden inverso
    int i4 = 4 * NUM_LEDS/STRIPS - i - 1;
    leds[i4] = color;
    */
  }
  
  // Actualiza físicamente los LEDs
  FastLED.show();
}
  

No hay comentarios:

Publicar un comentario