Banner publicitario de PCBWay
torres.electronico

Procesamiento Digital de Señales en Arduino

En el mundo de la electrónica, los sensores suelen enfrentarse a dos grandes enemigos: el ruido eléctrico de alta frecuencia (que hace que las lecturas oscilen sin control) y el desplazamiento de la línea base o DC offset (cambios lentos o niveles fijos que dificultan detectar variaciones rápidas).
Tradicionalmente, estos problemas se resolvían soldando resistencias y condensadores para crear filtros analógicos. Sin embargo, gracias al Procesamiento Digital de Señales (DSP), podemos replicar este comportamiento directamente en el sketch (programa/código) de nuestro Arduino.


En este tutorial, aprenderás a sustituir componentes físicos por ecuaciones de diferencias. Veremos cómo implementar desde cero:
  • Filtros Pasabajos (Low-Pass): Para suavizar señales y eliminar el "ruido" de sensores ruidosos.
  • Filtros Pasaaltos (High-Pass): Para eliminar componentes continuas y centrar la señal en los cambios significativos.
Al finalizar, no solo entenderás la lógica matemática detrás de estos filtros, sino que aplicaremos ambos en un caso real:
“El monitoreo de ritmo cardíaco”, donde la limpieza de la señal es la diferencia entre un dato útil y un valor aleatorio.

A_Introduccion:
Para implementar filtros pasabajos y pasaaltos por software en Arduino, se sustituyen los componentes físicos (resistencias, capacitores y amplificadores operacionales) por ecuaciones de diferencias que procesan la señal muestreada digitalmente.
A continuación, se presentan las implementaciones para filtros de primer orden:

1. Filtro Pasabajos (Low-Pass Filter)
Este filtro permite el paso de frecuencias bajas y atenúa el ruido de alta frecuencia. Es ideal para suavizar lecturas de sensores ruidosos.

Ecuación:
𝑦[𝑛]=𝛼⋅𝑥[𝑛]+(1−𝛼)⋅𝑦[𝑛−1]

Donde:
𝑥[𝑛] es la lectura actual del ADC.
𝑦[𝑛−1] es el valor filtrado anterior.
𝛼 es el factor de suavizado (entre 0 y 1). Un 𝛼 más pequeño filtra más agresivamente

Ejemplo:
CSS:
float alpha = 0.1; // Factor de filtrado (0.1 = filtrado fuerte, 0.9 = suave)
float filteredValue = 0;

void loop()
    {
     int rawValue = analogRead(A0);
     // Implementación del filtro pasabajos
     filteredValue = (alpha * rawValue) + ((1.0 - alpha) * filteredValue);
     Serial.println(filteredValue);
     delay(10); // Importante mantener un tiempo de muestreo constante
    }

2. Filtro Pasaaltos (High-Pass Filter)
Este filtro permite el paso de frecuencias altas y bloquea componentes continuos (DC) o cambios lentos.

Ecuación:
𝑦[𝑛]=𝛼⋅(𝑦[𝑛−1]+𝑥[𝑛]−𝑥[𝑛−1])

Ejemplo:
CSS:
float alpha = 0.8;
float prevX = 0;
float filteredY = 0;

void loop()
    {
     int currentX = analogRead(A0);
     // Implementación del filtro pasaaltos
     filteredY = alpha * (filteredY + currentX - prevX);
     prevX = currentX; // Guardar para el siguiente ciclo
     Serial.println(filteredY);
     delay(10);
    }

A tener en cuenta:
-Tiempo de muestreo:
A diferencia de los circuitos analógicos con operacionales, la frecuencia de corte en software depende de la velocidad a la que ejecutas el loop. Para resultados precisos, usa micros() para asegurar intervalos constantes.
-Cálculo de 𝛼 : Si conoces la frecuencia de corte deseada (𝑓𝑐) y el tiempo de muestreo (𝑑𝑡),puedes calcular 𝛼 para el pasabajos como: 𝛼=𝑑𝑡𝑅𝐶+𝑑𝑡 , donde 𝑅𝐶=12𝜋𝑓𝑐
-Librerías: Si necesitas filtros más complejos (como Butterworth de segundo orden), existen librerías como Arduino-Filters que facilitan la implementación sin manejar manualmente las ecuaciones…

B_ De la teoría a la practica…
A continuación, un sketch práctico que toma una lectura analógica y aplica simultáneamente un Filtro Pasabajos (LPF) para suavizar ruido y un Filtro Pasaaltos (HPF) para detectar cambios rápidos o eliminar la componente continua (offset).

Ejemplo:
CSS:
// Variables para el Filtro Pasabajos (LPF)
float alphaLPF = 0.15; // Suavizado: valores bajos = más filtrado
float filteredLPF = 0;

// Variables para el Filtro Pasaaltos (HPF)
float alphaHPF = 0.85; // Estabilidad: cercano a 1 para dejar pasar solo picos rápidos
float prevRawValue = 0;
float filteredHPF = 0;

const int sensorPin = A0;

void setup()
    {
     Serial.begin(115200);
     // Inicialización para evitar saltos bruscos al arranque
     filteredLPF = analogRead(sensorPin);
     prevRawValue = filteredLPF;
    }

void loop()
    {
     int rawValue = analogRead(sensorPin);
     // 1. FILTRO PASABAJOS (Suaviza la señal)
     // Ecuación: y[n] = α*x[n] + (1-α)*y[n-1]
     filteredLPF = (alphaLPF * rawValue) + ((1.0 - alphaLPF) * filteredLPF);

     // 2. FILTRO PASAALTOS (Detecta cambios rápidos/quita el DC)
     // Ecuación: y[n] = α*(y[n-1] + x[n] - x[n-1])
     filteredHPF = alphaHPF * (filteredHPF + rawValue - prevRawValue);

    // Guardar valor actual para el siguiente cálculo del HPF
    prevRawValue = rawValue;

    // Visualización en el Serial Plotter
    Serial.print("Original:"); Serial.print(rawValue);
    Serial.print(",");
    Serial.print("PasaBajos:"); Serial.print(filteredLPF);
    Serial.print(",");
    Serial.print("PasaAltos:"); Serial.println(filteredHPF);
    delay(10); // Frecuencia de muestreo de ~100Hz
   }

Para implementar ambos filtros sobre una misma señal, el enfoque más eficiente es procesarlos en serie o en paralelo dentro del mismo ciclo de muestreo.

-Ajuste de 𝛼: En el Pasabajos, un 𝛼 pequeño (ej. 0.05) elimina mucho ruido pero introduce retardo (lag).
-En el Pasaaltos, si el valor filtrado tiende a quedarse en 0 aunque la señal se mueva lento, el filtro está cumpliendo su función de eliminar la componente continua.
-Consistencia Temporal: Para aplicaciones profesionales (como audio o ECG), el uso de delay() no es preciso. Se recomienda usar temporizadores o librerías especializadas como Arduino-Filters que gestionan el tiempo de muestreo internamente para garantizar una respuesta en frecuencia exacta.

C_Usos prácticos?

-Acelerómetros:
El Pasabajos filtra las vibraciones del motor en un dron para que el acelerómetro solo detecte la inclinación real.

-Audio Simple: El Pasabajos puede actuar como un control de "Tono" (treble cut) si procesas una señal de audio digital.

-Sensores de Flexión: En guantes robóticos, el Pasabajos evita que los dedos mecánicos tiemblen por pequeñas variaciones eléctricas en los sensores de flexión.

-Monitoreo de Ritmo Cardíaco (PPG) mediante un sensor de pulso infrarrojo: En este escenario, la señal que entrega el sensor es extremadamente ruidosa y "sucia" para procesarla directamente.
Si aplicamos en este caso Filtro Pasabajos (LPF): Se usaria para eliminar el "ruido blanco" y las interferencias de alta frecuencia (como el parpadeo de luces fluorescentes o ruido eléctrico). Esto suaviza la señal para que el pulso se vea como una onda curva y no como una línea "astillada".
Si sumamos el Filtro Pasaaltos (HPF): Lograriamos eliminar el Offset DC (la línea base). Cuando mueves un poco el dedo en el sensor, la señal sube o baja de nivel bruscamente. El pasaaltos "centra" la señal en cero, permitiendo que solo detectes los cambios rápidos (los latidos), sin importar si el sensor está recibiendo más o menos luz ambiental en ese momento.

Veamos un ejemplo de código combinado para este sensor:
Este sketch procesa la señal de un sensor de pulso en el pin A0 y entrega una señal limpia lista para contar latidos

CSS:
// Parámetros de filtrado
float alphaLPF = 0.2;
float alphaHPF = 0.95;
float filteredLPF = 0;
float filteredHPF = 0;
float prevLPF = 0;

// Variables para el conteo de pulsos
const float threshold = 20.0; // Umbral de detección (ajustar según sensor)
bool pulseDetected = false;
unsigned long lastBeatTime = 0;
float bpm = 0;

void setup()
    {
     Serial.begin(115200);
    }

void loop()
    {
     int rawValue = analogRead(A0);
     // 1. FILTRADO (Pasabajos + Pasaaltos en cascada)
     filteredLPF = (alphaLPF * rawValue) + ((1.0 - alphaLPF) * filteredLPF);
     filteredHPF = alphaHPF * (filteredHPF + filteredLPF - prevLPF);
     prevLPF = filteredLPF;

     // 2. DETECCIÓN DE LATIDO (Lógica de umbral)
     // Si la señal supera el umbral y no habíamos detectado un pulso aún...
     if (filteredHPF > threshold && !pulseDetected)
        {
         pulseDetected = true;
         unsigned long currentTime = millis();
         unsigned long duration = currentTime - lastBeatTime;
         // Validar que el latido sea realista (evitar rebotes menores a 300ms / 200 BPM)
         if (duration > 300)
            {
             bpm = 60000.0 / duration; // 60,000 ms en un minuto
             lastBeatTime = currentTime;
            }
         }
     // Resetear la detección cuando la señal baja del umbral (con un poco de histéresis)
     if (filteredHPF < (threshold * 0.8))
        {
         pulseDetected = false;
        }

     // 3. SALIDA DE DATOS
     Serial.print("Señal_Limpia:"); Serial.print(filteredHPF);
     Serial.print(",");
     Serial.print("Umbral:"); Serial.print(threshold);
     Serial.print(",");
     Serial.print("BPM:"); Serial.println(bpm);
     delay(10); // Muestreo de 100Hz
    }

Para poder hacer un sistema de monitoreo cardíaco, necesitamos añadir una lógica de detección de umbral (threshold) y un cálculo de tiempo entre latidos.
La señal que sale del filtro pasaaltos (filteredHPF) está centrada en cero. Un latido se detecta cuando la señal sube por encima de un umbral positivo y luego baja. Usamos millis() para calcular los latidos por minuto (BPM).
-Validación de Tiempo (duration > 300): En el procesamiento de señales, es vital evitar falsos positivos. Un corazón humano rara vez late a más de 200 BPM en reposo, por lo que ignoramos cualquier "pico" que ocurra demasiado rápido después del anterior.

-Histéresis (threshold * 0.8): No reseteamos la detección inmediatamente en el umbral, sino un poco más abajo. Esto evita que el ruido pequeño en la punta del latido cuente como múltiples pulsos.

-Cálculo de BPM: La fórmula (60000 / duración) convierte el intervalo de milisegundos entre dos latidos en la frecuencia cardíaca estándar.
Si notamos que el BPM salta mucho, se puede aplicar un tercer filtro pasabajos exclusivamente a la variable bpm para suavizar la lectura final que se muestra al usuario.


Fuente: (e-book) ProyectosARDUINOdesdeCERO Autor: ETI Patagonia
Atrás
Arriba