Síntesis desde captura ‐ Simulador ECG - tresvi/ECG_Viewer GitHub Wiki

Descripción

En el siguiente ejemplo se partirá desde la captura de la señal trabajada en el ejemplo del ECG para generar un sintetizador de señal ECG de calidad profesional con posibilidad de variar la frecuencia cardíaca. Se utilizará la plataforma Arduino, pero puede utilizarse cualquier tipo de Microcontrolador que se pueda programar en C o C++, como PICs, ESP32, etc.
El circuito completo del circuito y la simulación de proteus y el correspondiente programa del ejemplo se encuentra en la carpeta Hard\8-Sintesis_ECG\Simulador_ECG.pdsprj

Procedimiento

Paso 1. Elegir la señal a sintetizar.

Se deberá abrir el archivo .csv capturado que se desee sintetizar, o bien alguno de los ejemplos en la carpeta:

  • Hard\7-ECG_Basico\ECG_20_Seg_FILTRADO.txt
  • Hard\7-ECG_Basico\ECG_20_Seg_NO_FILTRADO.txt

image

Paso 2. Exportar la señal a una tabla del tipo C/C++

En este caso se usará ECG_20_Seg_FILTRADO.txt, el cual posee contine una señal correctamente capturada de ECG real de un paciente sano. Una vez abierto dirigirse a la opcion "Exportar a tabla lenguaje de Prog." y exportar la tabla a un archivo con los parametros por default (estilo C/C++, salto de linea c/10 valores y escalar para 10 bits).
Atención: El ejemplo que muestra el programa en la pantalla de exportación, es para escalados de 8 bits de tablas que entren en RAM del dispositivo (menos de 2KB). El procedimiento que se realiza a continuacion, es para resoluciones mayores (hasta 16 bits) y de tablas grandes que entren en la memoria de programa del dispositivo (32 KB en este caso, es decir como máximo 16.000 muestras de 10 bits). Al exportar, el programa mostrará una ventana indicando que el proceso finalizó correctamente.

image

Atención: Al exportarse la señal, no importa la calibración ni el periodo de muestreo ya que el programa re-escalar buscará una amplitud perfecta para aprovechar al maximo toda la resolución pedida, conservando toda la claidad de la señal original.

Paso 3. Crear el programa.

Crear el programa para el proyecto en el IDE de Arduino (o el que corresponda). Tomar el archivo generado en el paso anterior, copiar la tabla y pegarla al comienzo del mismo (esto es solo por comodidad, en gral como buena práctica se prefiere declararlo despues de los #include).
Luego en la primer línea de la tabla pegada, a continuacion de la declaracion del tamaño que va entre corchetes, agregarle la palabra PROGMEM, si esta no la tiene, como se ve a continuación

const unsigned short tabla[10000] PROGMEM = {119 ,119 ,114 ,114 ,114 ,114 ,114 ,119 ,119 ,119
   ,124 ,124 ,124 ,124 ,129 ,129 ,129 ,129 ,134 ,134
  ...
  ...

Esta directiva en los vectores hace que dicho vector se almacene en memoria flash de programa, dado que de manera contraria tal cantidad de datos no podria almacenarse en RAM. Por esto, cuando haga falta acceder a dicho contenido del vector, se hará por medio de la función pgm_read_word(&tabla[i]);

NOTA MICROS PIC y ESP32:El procedimiento descrito además de ser válido para Arduino, sirve para microcontroladores de la flia. ESP32. En caso de utilizar la familia PIC, la operación es mucho mas simple, no es necesario agregar nada (con la directiva const al comienzo de la declaracion del vector alcanza) y el acceso al dato se hace de manera directa, por ejemplo: unsigned int valor = tabla[i];

A continuación del vector tabla pegado, colocar el resto del código fuente

/*aca arriba iría la tabla que imide alrededor de 1000 líneas*/

#include <avr/pgmspace.h>
#include <LiquidCrystal.h>

// Configuración de pines para el LCD
const int rs = 13;  // Pin RS del LCD conectado a D13
const int en = 12;  // Pin E del LCD conectado a D12
const int d4 = A3;  // Pin D4 del LCD conectado a A3
const int d5 = A2;  // Pin D5 del LCD conectado a A2
const int d6 = A1;  // Pin D6 del LCD conectado a A1
const int d7 = A0;  // Pin D7 del LCD conectado a A0

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int BOTON_RUN = A5;


void setup() {
  // Configurar el pin 9 como salida
  pinMode(9, OUTPUT);
  pinMode(BOTON_RUN, INPUT);

  // Configuración del Timer 1 para Fast PWM con 10 bits
  TCCR1A = 0; // Limpiar registro de control A
  TCCR1B = 0; // Limpiar registro de control B

  // Configurar Fast PWM con resolución de 10 bits
  TCCR1A = (1 << WGM11) | (1 << WGM10); // Modo Fast PWM (10 bits)
  TCCR1B = (1 << WGM12) | (1 << CS10);  // Sin prescaler (frecuencia máxima)

  // Habilitar salida PWM en el pin 9 (OC1A)
  TCCR1A |= (1 << COM1A1);

  //Inicializar display
  lcd.begin(16, 2);
  lcd.setCursor(0, 0); // Posicionar el cursor en la segunda fila
  lcd.print("*Simulador ECG*");
    
   pinMode(BOTON_RUN, INPUT_PULLUP);
   analogReference(DEFAULT);
}


void loop() {

  int retardo = LeerPotenciometro();

  // Recorrer la tabla y emitir valores por PWM
  for (uint16_t i = 0; i < 10000; i++) {
    
    // Leer el valor de la tabla desde la memoria de programa
    unsigned short valor = pgm_read_word(&tabla[i]);

    // Asignar el valor al registro OCR1A (ajusta el duty cycle)
    OCR1A = valor;
    
    // Retardo para reconstruir la señal
    delayMicroseconds(retardo);

    while (digitalRead(BOTON_RUN) == HIGH)
    {
      retardo = LeerPotenciometro();
      delay(10);
    }
    
  }
}


int LeerPotenciometro(){
  int valorADC = analogRead(A4);    //Leo el potenciometro de Frec. Cardiaca
  int valorDelay = map(valorADC, 0, 1023, 1000, 3000);
  int valorPPM = map(valorADC, 0, 1023, 43, 129);
  lcd.setCursor(0, 1);
  lcd.print("PPM:            ");
  lcd.setCursor(5, 1);
  lcd.print(valorPPM);
  return valorDelay;
}

Paso 4. Circuito en Proteus

image

Una vez cargado el programa, comenzar la simulación. Para generar la señal de salida, debe estar cerrado el switch SET/RUN. Con el potenciometro FRECUENCIA_CARDIACA se podrá variar la frecuencia del ECG previamente abriendo el switch SET/RUN para ver la variación (cerrarlo nuevamente para generar la señal). Con el potenciometro en el medio, se logrará una frecuencia idéntica a la de la señal capturada, pero desplazandose hacia los limites, se podrá generar aumentos y disminuciones, simulando un ECG con bradicardia y taquicardia.

Resultados

En el osciloscopio de proteus pueden verse 3 señales:

  • Canal A (amarillo): Señal ECG Original, la cual fue capturada para luego ser sintetizada.
  • Canal B (azul): Señal sintetizada en PWM y filtrada.
  • Canal c (bordó): Señal a la salida del dispoisitivo, luego de pasar por el atenuador/amplificador de salida. Comparando visualmente puede verse la perfecta similitud de la señal filtrada y su gran calidad.

image

Simulando Taquicardia

Si elevamos la frecuencia cardiaca desde el potenciometro correspondiente, podemos ver la simulación de una taquicardia con un notable aumento en la frecuencia de la señal sintetizada.

image

Simulando Bradicardia

Si bajamos la frecuencia cardíaca desde el potenciometro correspondiente, podemos ver la simulación de bradicardia con un notable descenso en la frecuencia de la señal sintetizada.

image