0% encontró este documento útil (0 votos)
13 vistas12 páginas

ECG Informe Completo

Este informe detalla la síntesis digital de una señal ECG utilizando un microcontrolador PIC18F4550 y un conversor R–2R, con el objetivo de generar una forma de onda P–QRS–T a 1 Hz. Se abordan aspectos como el diseño de la señal, el muestreo, la normalización y la implementación de filtros, además de la validación numérica y la complejidad computacional. La señal sintética permite simular condiciones controladas para el diagnóstico y la investigación en el área biomédica.

Cargado por

Juan David
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
13 vistas12 páginas

ECG Informe Completo

Este informe detalla la síntesis digital de una señal ECG utilizando un microcontrolador PIC18F4550 y un conversor R–2R, con el objetivo de generar una forma de onda P–QRS–T a 1 Hz. Se abordan aspectos como el diseño de la señal, el muestreo, la normalización y la implementación de filtros, además de la validación numérica y la complejidad computacional. La señal sintética permite simular condiciones controladas para el diagnóstico y la investigación en el área biomédica.

Cargado por

Juan David
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

SEÑAL ECG

MATERIA: PROCESAMIENTO DIGITAL DE SEÑALES

DOCENTE: ING. GERMAN PEREIRA MUÑOZ

ESTUDIANTE: JUAN DAVID QUISPE MAMANI

PARALELO: 8 vo ING. MECATRÓNICA

FECHA: 23 / 09 / 2025

LA PAZ – BOLIVIA
2025
Introducción
El presente informe describe el proceso de síntesis digital de una señal ECG utilizando un
microcontrolador PIC18F4550 y un conversor digital–analógico R–2R. El objetivo es
obtener una forma de onda periódica con morfología realista P–QRS–T y frecuencia de 1 Hz,
correspondiente a 60 latidos por minuto, la cual pueda ser visualizada mediante simulación
en Proteus y servir como base para aplicaciones de procesamiento digital de señales en el
área biomédica.

Se presentan los cálculos de diseño, desde la elección de la frecuencia de muestreo,


modelado de la forma de onda mediante funciones gaussianas, discretización y
normalización a 8 bits, hasta la configuración del temporizador interno para garantizar una
frecuencia de interrupción estable. Asimismo, se consideran opciones de suavizado por
interpolación y filtros FIR, así como la validación numérica de puntos clave de la señal y el
análisis de la complejidad computacional.

Marco Teórico del ECG


El electrocardiograma (ECG) es el registro gráfico de la actividad eléctrica del corazón. Cada
ciclo cardiaco genera un conjunto de ondas que representan eventos eléctricos específicos:
- Onda P: despolarización auricular.
- Complejo QRS: despolarización ventricular.
- Onda T: repolarización ventricular.
Los intervalos PR, ST y QT son parámetros clínicos relevantes para identificar arritmias,
isquemias y otras alteraciones cardiacas. Su importancia radica en que constituyen una
herramienta no invasiva, económica y ampliamente difundida en el diagnóstico médico.
Importancia en el Área Biomédica
La señal ECG es fundamental para el diagnóstico de patologías cardiacas. El uso de modelos
sintéticos permite realizar simulaciones controladas en ambientes académicos y de
investigación, evitando depender de registros clínicos reales. Esto facilita la docencia, la
experimentación con filtros digitales, compresión de datos y el diseño de sistemas de
monitoreo.

Señales Sintéticas de ECG


La generación de señales ECG artificiales permite reproducir condiciones de frecuencia
cardiaca y amplitud bajo control del usuario. Existen diferentes modelos matemáticos, como
la suma de senoidales o el uso de funciones gaussianas. En este trabajo se adoptó un modelo
gaussiano que representa adecuadamente las ondas P, QRS y T. Esto facilita la
implementación en hardware mediante microcontroladores.

Aplicación de la Electrónica Digital


La implementación se realizó con un microcontrolador PIC18F4550, el cual utiliza una LUT
(tabla de valores) y un conversor R–2R para generar la señal analógica. El temporizador
interno configura una ISR periódica que actualiza la salida en PORTD. Además, se
implementó comunicación UART a 9600 bps para modificar parámetros como frecuencia
(Hz) y amplitud (%). La simulación en Proteus junto con una interfaz gráfica en
Python/Thonny demuestra la flexibilidad del diseño.

Cálculos de Diseño
Síntesis de Señal ECG
Requisitos y decisión de diseño

• Queremos una ECG periódica de 1 Hz con morfología P–QRS–T realista.

• El DAC es un R–2R de 8 bits → salida 0..255, cuantización 1 LSB.

• Usaremos una LUT de N = 1000 puntos (1 ms por muestra) y Timer2 a 1 kHz, o bien ISR a
5 kHz con upsampling ×5 para suavizar.

• Para justificar formalmente, documentamos: muestreo, modelo de forma, discretización,


normalización y temporizador.
1) Muestreo básico

Periodo T = 1 s → f0 = 1 Hz.

Elegimos Fs = 1000 Hz para tener resolución temporal de 1 ms.

Número de puntos por ciclo: N = Fs · T = 1000 · 1 = 1000.

Tiempo discreto: t[n] = n/Fs, n = 0,1,…,999.

2) Modelo de forma – Suma de gaussianas

La ECG continua se compone de cinco gaussianas (P, Q, R, S, T) más segmentos casi planos
(PR y ST).

Ecuación: y(t) = Σ Ai·exp(−(t−μi)^2/(2σi^2)) + y_base(t).

Relación FWHM→σ: σ = FWHM / (2·√(2·ln 2)) ≈ FWHM / 2.355.

Parámetros clínicos elegidos (T = 1 s):

Onda μi [s] FWHM σi [ms] Ai (adim.) μi σi


[ms] [muestras] [muestras]
P 0.180 80 34.0 +0.12 180 34.0
Q 0.460 28 11.9 -0.08 460 11.9
R 0.500 18 7.6 +1.00 500 7.6
S 0.540 28 11.9 -0.35 540 11.9
T 0.780 160 67.9 +0.40 780 67.9
Segmento PR: rampa leve desde baseline (0) hasta 0.02 entre t=0 y Q.

Segmento ST: elevación suave de +0.03 entre S y (T−0.08).

3) Discretización (N = 1000)

Definimos x[n] = n/N ∈ [0,1). Evaluamos cada gaussiana en x[n]:

g_i[n] = Ai · exp(−(x[n] − μi)^2 / (2 σi^2)).

La señal bruta: y[n] = Σ g_i[n] + y_base[n].

Cálculo ejemplo en n = 500 (onda R):

x = 500/1000 = 0.5; para R: μR=0.50, σR≈0.00764 → exp(−(0)^2/(2σ^2))=1 →


contribución A_R=+1.00.

Para Q en n=500: Δ = 0.5−0.46=0.04; 2σ_Q^2 ≈ 2·(0.01189)^2 ≈ 0.000283;


exp(−0.04^2/0.000283) ≈ exp(−5.65) ≈ 0.0035; A_Q·g ≈ −0.08·0.0035 ≈ −2.8×10⁻⁴
(despreciable).

4) Normalización a 8 bits
1) Buscar extremos: ymin, ymax de y[n].

2) Escalar a z[n] ∈ [−1,1]: z[n] = 2·(y[n]−ymin)/(ymax−ymin) − 1.

3) Aplicar offset/ganancia: u[n] = clip( DC + 0.5·GAIN·z[n], 0, 1 ), con DC=0.52, GAIN=0.96.

4) Cuantizar 8 bits: DAC[n] = round(255·u[n]).

Con los parámetros anteriores se obtiene: ymin=-0.34922, ymax=0.99858.

El rango útil u[n] ocupa ~0.96 del total (por GAIN), con media ≈ 0.355 y pico a pico de 0.96.

En códigos: media(DAC) ≈ 90.5, pico a pico ≈ 245 cuentas.

5) Temporizador Timer2 para 1 kHz (Fosc = 4 MHz)

Fórmula: Fs_ISR = (Fosc/4) / (Presc · (PR2+1) · Post).

Elegimos Presc=1:4 y Post=1:1. Entonces:

• Fosc/4 = 4 MHz / 4 = 1 MHz.

• Denominador buscado = Fs_ISR·Presc·Post = 1000 · 4 · 1 = 4000.

• (PR2+1) = 1e6 / 4000 = 250. → PR2 = 249 (entero).

Bits: T2CKPS=01 (1:4), TOUTPS=0000 (1:1), PR2=249. La ISR dispara cada 1 ms.

6) Opción de suavizado por software (ISR 5 kHz)

Para reducir el ‘staircase’: ISR a 5 kHz + interpolación lineal ×5 + FIR 8–32 taps.

Con Fosc/4 = 1 MHz, Presc=1:4, Post=1:5:

• Denominador = 5000 · 4 · 5 = 100000.

• (PR2+1) = 1e6 / 100000 = 10 → PR2 = 9.

Así, la LUT sigue siendo de 1000 puntos (1 Hz), pero el DAC se actualiza 5 veces por muestra
base con interpolación, dando trazos más suaves.

7) Conversión digital–analógica y amplitud

Con R–2R a VDD=5 V, el escalón ideal de 1 LSB es 5/255 ≈ 19.6 mV en vacío.

La carga (R1||R2 ≈ 500 Ω) atenúa; el OPAMP en seguidor recupera nivel pero el pre–filtro
R17–C1 define el ancho de banda visible.

Para visualizar ECG (1 Hz), conviene f_c del filtro RC en 10–100 Hz. Ejemplo: R17=10 kΩ,
C1=1 µF → f_c ≈ 15.9 Hz.
8) Validación numérica puntual

n = 180 (x = 0.180): y = P:+0.1200 Q:-0.0000 R:+0.0000 S:-0.0000 T:+0.0000


BASE:+0.0078 → y_total = +0.1278

n = 460 (x = 0.460): y = P:+0.0000 Q:-0.0800 R:+0.0000 S:-0.0000 T:+0.0000


BASE:+0.0000 → y_total = -0.0800

n = 500 (x = 0.500): y = P:+0.0000 Q:-0.0003 R:+1.0000 S:-0.0012 T:+0.0001


BASE:+0.0000 → y_total = +0.9986

n = 540 (x = 0.540): y = P:+0.0000 Q:-0.0000 R:+0.0000 S:-0.3500 T:+0.0008


BASE:+0.0000 → y_total = -0.3492

n = 780 (x = 0.780): y = P:+0.0000 Q:-0.0000 R:+0.0000 S:-0.0000 T:+0.4000


BASE:+0.0000 → y_total = +0.4000

9) Complejidad y memoria

• LUT de 1000 bytes (8 bits).

• ISR 1 kHz: una lectura LUT y escritura en LATD.

• ISR 5 kHz: interpolación lineal (2 multipl. + sumas) + FIR (M sumas), con M=8..32.

• CPU a 4 MHz (1 MIPS): 5 kHz con FIR de 8–16 taps es viable.

10) Reproducción de resultados en mikroC

• Genera la LUT con los parámetros de la tabla y el algoritmo de normalización.

• Configura Timer2 según la sección 5 o 6 (1 kHz o 5 kHz).

• Escribe DAC[n] en LATD dentro de la ISR; usa RA0 como pin de prueba para medir Fs_ISR.
Constantes finales:

PR2 (1 kHz): 249.00 → usar 249; PR2 (5 kHz con Post=1:5): 9.00 → usar 9.

Amplitudes: AP=+0.12, AQ=−0.08, AR=+1.00, AS=−0.35, AT=+0.40.

Centros (muestras): μP=180, μQ=460, μR=500, μS=540, μT=780.

Anchuras (σ en muestras): σP≈33.97, σQ≈11.89, σR≈7.64, σS≈11.89, σT≈67.95.

Normalización: DC=0.52, GAIN=0.96, salida 8 bits 0..255.

Código de MikroC
#include <math.h>
/*** ====== Configuración de frecuencia visible ====== ***/

// Pon 1 para 1 Hz real (1 s por ciclo) o 10 para 10 Hz (0.1 s por ciclo).

#define ECG_HZ 10

/*** ====== Muestreo / upsampling ====== ***/

#define UPS 5 // upsampling x5 -> ISR 5 kHz (constante)

#if (ECG_HZ == 1)

#define LUT_LEN 1000 // 1000 puntos -> 1 s a 1 kHz base

#elif (ECG_HZ == 10)

#define LUT_LEN 100 // 100 puntos -> 0.1 s a 1 kHz base

#else

#error "ECG_HZ debe ser 1 o 10"

#endif

/*** ====== Parámetros de forma (gaussianas) ====== ***/

// Amplitudes relativas (antes de normalizar)

#define AMP_P ( 0.12)

#define AMP_Q (-0.08)

#define AMP_R ( 1.00)

#define AMP_S (-0.35)

#define AMP_T ( 0.40)

// Posiciones (0..1 dentro del ciclo)

#define POS_P (0.18)

#define POS_Q (0.46)

#define POS_R (0.50)

#define POS_S (0.54)

#define POS_T (0.78)

// Anchuras (s en fracción del ciclo)

#define SIG_P (0.030)

#define SIG_Q (0.012)

#define SIG_R (0.008)

#define SIG_S (0.012)

#define SIG_T (0.055)


// Niveles de línea base (segmentos casi planos)

#define BASELINE (0.00) // nivel de reposo

#define ST_ELEVATION (0.03) // ligera elevación en ST (0?no elevación)

// Escalado final a 8 bits

const float DC_OFFSET = 0.52f; // centro alrededor de mitad de escala

const float GAIN = 0.96f; // aprovecha casi todo el rango

/*** ====== Buffers / estado ====== ***/

unsigned char lut[LUT_LEN]; // LUT base (1 kHz) – ocupa 1000 ó 100 bytes

unsigned int i_base = 0; // índice LUT (0..LUT_LEN-1)

unsigned char frac = 0; // 0..UPS-1 (fase fraccional)

// FIR 8 taps (promedio móvil)

#define FIR_TAPS 8

unsigned int fir_sum = 0;

unsigned char fir_buf[FIR_TAPS];

unsigned char fir_pos = 0;

/*** ====== Helpers ====== ***/

float fminf(float a, float b){ return (a<b)?a:b; }

float fmaxf(float a, float b){ return (a>b)?a:b; }

// Gaussiana centrada en mu con sigma – usamos exp() (double) que sí soporta mikroC

static float gauss(float x, float mu, float sigma){

double d = (double)x - (double)mu;

double val = - (d*d) / (2.0 * (double)sigma * (double)sigma);

return (float)exp(val);

/*** ====== Señal ECG "médica" en 0..1 (sin escalar a 8 bits) ====== ***/

static float ecg_shape(float x){ // x en [0,1)

float y = 0.0f;

// Segmento PR casi plano antes de QRS

if (x < POS_Q) {

// leve pendiente positiva hacia Q

float alpha = (x - 0.00f) / (POS_Q - 0.00f);

if (alpha < 0.0f) alpha = 0.0f; if (alpha > 1.0f) alpha = 1.0f;
y = BASELINE * (1.0f - alpha) + (BASELINE + 0.02f) * alpha;

// Complejo QRS por gaussianas cortas y altas

y += AMP_Q * gauss(x, POS_Q, SIG_Q);

y += AMP_R * gauss(x, POS_R, SIG_R);

y += AMP_S * gauss(x, POS_S, SIG_S);

// Segmento ST (ligeramente elevado y casi plano)

if (x > POS_S && x < (POS_T - 0.08f)) {

float alpha = (x - POS_S) / ((POS_T - 0.08f) - POS_S);

if (alpha < 0.0f) alpha = 0.0f; if (alpha > 1.0f) alpha = 1.0f;

y += (BASELINE + ST_ELEVATION) * (0.6f + 0.4f*alpha);

// Onda P y T (anchas y suaves)

y += AMP_P * gauss(x, POS_P, SIG_P);

y += AMP_T * gauss(x, POS_T, SIG_T);

return y;

/*** ====== Construcción de la LUT (1 kHz base) ====== ***/

void build_lut(void){

float y, ymin = 1e9, ymax = -1e9, x;

unsigned int n;

// medir extremos

for (n = 0; n < LUT_LEN; n++){

x = (float)n / (float)LUT_LEN;

y = ecg_shape(x);

if (y < ymin) ymin = y;

if (y > ymax) ymax = y;

// normalizar a 0..255 con offset/ganancia

for (n = 0; n < LUT_LEN; n++){

x = (float)n / (float)LUT_LEN;

y = ecg_shape(x);
if (ymax > ymin) y = 2.0f * ((y - ymin) / (ymax - ymin)) - 1.0f; // -1..+1

else y = 0.0f;

y = DC_OFFSET + 0.5f * GAIN * y; // 0..1

if (y < 0.0f) y = 0.0f; if (y > 1.0f) y = 1.0f; // clip

lut[n] = (unsigned char)(y * 255.0f + 0.5f);

/*** ====== Inicialización de HW ====== ***/

void init_hw(void){

// Todo digital / comparadores OFF

ADCON1 = 0x0F;

CMCON = 0x07;

#ifdef PSPMODE_bit

PSPMODE_bit = 0; // asegura PORTD como puerto normal

#endif

// PORTD -> R-2R

TRISD = 0x00;

LATD = 0x80;

// RC0/RC1 (sumador al op-amp) en 0

TRISC.B0 = 0; LATC.B0 = 0;

TRISC.B1 = 0; LATC.B1 = 0;

// RA0 test 5 kHz

TRISA.B0 = 0; LATA.B0 = 0;

// Timer2: Fs_ISR = 5 kHz (Presc=1:4, PR2=9, Post=1:5)

T2CON = 0x00;

PR2 = 9; // (PR2+1)=10

T2CON |= 0x20; // Post 1:5 (TOUTPS=0100b)

T2CON |= 0x01; // Presc 1:4 (T2CKPS=01b)

TMR2IF_bit = 0;

TMR2IE_bit = 1;

PEIE_bit = 1;

GIE_bit = 1;
TMR2ON_bit = 1;

// FIR init

unsigned char i;

fir_sum = 0; fir_pos = 0;

for (i = 0; i < FIR_TAPS; i++) { fir_buf[i] = 128; fir_sum += 128; }

/*** ====== ISR 5 kHz (upsampling ×5 + FIR) ====== ***/

void interrupt(){

if (TMR2IF_bit){

unsigned char y0, y1, y_i, y_out;

unsigned int acc;

// test

LATA.B0 ^= 1;

// interpolación lineal entre muestras base (1 kHz)

y0 = lut[i_base];

y1 = (i_base + 1 < LUT_LEN) ? lut[i_base + 1] : lut[0];

acc = (unsigned int)y0 * (UPS - frac) + (unsigned int)y1 * frac;

y_i = (unsigned char)((acc + (UPS/2)) / UPS); // redondeo

// FIR 8 taps -> divide por 8

fir_sum -= fir_buf[fir_pos];

fir_buf[fir_pos] = y_i;

fir_sum += y_i;

fir_pos++; if (fir_pos >= FIR_TAPS) fir_pos = 0;

y_out = (unsigned char)((fir_sum >> 3) & 0xFF);

LATD = y_out;

// avanzar fase

frac++;

if (frac >= UPS) { frac = 0; i_base++; if (i_base >= LUT_LEN) i_base = 0; }

TMR2IF_bit = 0;

}
}

/*** ====== Main ====== ***/

void main(){

init_hw();

build_lut();

while(1){ /* la ISR hace todo */ }

Circuito Simulado en Proteus

Conclusiones
El modelo implementado permite reproducir una señal ECG de forma fiel y controlada,
demostrando la viabilidad de su síntesis en microcontroladores con recursos limitados. El
control a través de la interfaz gráfica ofrece la posibilidad de simular diferentes escenarios
clínicos (bradicardia, taquicardia) y facilita el análisis en entornos académicos. Este trabajo
integra conocimientos de procesamiento digital de señales, electrónica analógica y
programación, constituyendo un ejemplo práctico de aplicación biomédica.

También podría gustarte