UNIVERSIDADA U T ~ N O M A METROPOLITANA - I v’ CIENCIAS BASICAS E INGENIERIA ING. ELECTRONICA PROYECTO DE INGENIERIA ELECTRONICA ELECTROCARDIOGRAFO / Trimestre 99-I Proyecto de inzeniería electrónica INTRODUCCI~N: Uno de las principales técnicas para el diagnostico de enfermedades cardiacas esta basado en el electrocardiograma (ECG). El electrocardiógrafo o máquina de ECG permite la deducción de muchos defectos eléctricos o mecánicos de el corazón mediante la medición de los ECGs, las cuales son medidas potenciales en la superficie del cuerpo. Con un electrocardiógrafo se puede determinar el ritmo cardiaco y otros parámetros cardiacos. Existen tres técnicas básicas utilizadas en la electrocardiografia clínica. El más común es el electrocardiograma clínico estándar. Este examen es aplicado en una clínica física, en donde se toman 12 diferencias de potencial distintas, llamadas muestras ECG, las cuales son tomadas de la superficie del cuerpo de un paciente descansando. Una segunda aproximación utiliza otro conjunto de potenciales de la superficie del cuerpo, como entradas a un modelo vectorial tridimensional de excitación cardiaca. Esto produce una vista gráfica de la excitación del corazón, llamada vectocardiograma (VCG). Finalmente, durante un lapso de tiempo se monitorea a los pacientes de cuidado intensivo o ambulatorios, a quienes se les toma uno o dos ECGs, estos son observados para ver las alteraciones del ritmo cardiaco. Esta aproximación se denomina Análisis de la Arritmia. En conclusión, las tres técnicas básicas utilizadas en la electrocardiografia son: 1. El ECG clínico estándar (12 muestras) 2. VCG (3 muestras ortogonales) 3. ECG monitoreado (1 o 2 muestras). Tan solo con la observación de las señales eléctricas de la superficie del cuerpo, los cardiólogos pueden determinar el estado funcional del corazón. Pensando en el ECG como una señal eléctrica, este varia conforme cambia el estado mecánico del corazón. El estudio de la cardiología esta basado en la grabación de los ECGs de cientos de pacientes a lo largo de los años y la observación de las relaciones entre varias formas de onda en la señal y las diferentes anormalidades. De esta forma, la electrocardiografia es muy empírica, basada en su mayoría en conocimiento experimental. Una parte importante para la medición de los ECGs son los electrodos. Desde hace tiempo, los electrodos metálicos fueron desarrollados para conectar eléctricamente al cuerpo. Un electrolito, usualmente compuesto de una solución salina en un gel, forma la interface eléctrica entre el electrodo metálico y la piel. En el cuerpo, las corrientes son producidas por el movimiento de iones por donde esta un alambre, las corrientes dadas por el movimiento de los electrones. Los sistemas de electrodos hacen la conversión de corrientes ionicas a corrientes electrónicas. Los metales conductivos tales como la mezcla de niquel-plata son utilizados como electrodos del ECG, pero estos tienen un problema. Los dos electrodos necesarios para adquirir un ECG, junto con el electrolito y la parte salada del torso, actúan como una batería. Un offset de dc ocurre a lo largo de los electrodos, el cual puede ser tan grande o mayor que el pico de una señal ECG. Una capa de doble carga (iones positivos y negativos separados por una distancia) ocurre en el electrolito. El movimiento de el electrodo tal como el provocado por el movimiento del paciente, altera esta doble capa y los cambios en el dc offset. Por lo que este potencial offset es amplificado alrededor de 1000 veces a lo largo del ECG, pequeños cambios dan un incremento a lo largo de la solución salina en la señal de salida. Un electrodo que se Seminario de proyectos Proyecto de ingeniería electrónica comporta de esta manera es llamada electrodo polarizable y solamente se utiliza en pacientes descansando. El material más usado para los electrodos en estos días son de plata-plata clorado (Ag-AgCl), de aquí se aproxima a un electrodo no polarizado. Este electrodo tiene un potencial de offset muy pequeño. Tiene una capa de AgCl depositado en un plato de Ag. Los iones del clorato se mueven en el cuerpo, en el electrolito y la capa de AgCl, donde ellos los convierten en un flujo de electrones en el plato de Ag y en el alambre conectado. Esta aproximación reduce el potencial offset de dc a un valor muy pequeño comparado con el del pico de la señal del ECG. Así el movimiento del electrodo provoca un cambio más pequeño en la amplificación del ECG que el del electrodo polarizable. C~ndiciopdel Generador cardiaco equivalente + Potenciaks de la supedicie del cuerpo (Electmcardiogramas) Dipolo (Vector) Figura 1. La Figura 1 muestra como un modelo físico, llamado generador equivalente cardiaco, puede se utilizado para representar la actividad eléctrica cardiaca. El modelo físico popular es un dipolo de corriente que es representado matemáticamente como un vector de variación en el tiempo el cual da el incremento para el vectocardiograma clínico (VCG). Einthoven postuló que la excitación cardiaca puede ser modelada como un vector. El también afirmó que los miembros son como conexiones directas a puntos en el torso tal como el conjunto de flujos de corriente dentro del cuerpo como por el flujo del dipolo fuente dentro de tórax y no fluye significantemente dentro dichos miembros. De esta manera el visualizó una situación donde los electrodos podrían estar conectados a los hombros y para un punto cercano al ombligo él no había restringido el uso de tinas de solución salina. Einthoven dibujo un triángulo usando como vértices los hombros y el ombligo; observó que los lados del triángulo tenían el mismo largo. Este triángulo, como se muestra en la Figura 2, se conoce como el triángulo equilátero de Einthoven. Si el vector representando la diferencia de la excitación cardiaca es conocido, entonces la diferencia de potencial medida entre las dos hombros (es decir, dos vértices del triángulo) es proporcional a la proyección de el vector en el lado de el triángulo el cual conecta los hombros. Seminario de proyectos Proyecto de ingeniería electrónica La Figura 2 muestra la relación entre el vector de Einthoven y cada uno de los tres muestras de las derivaciones frontales (muestra I, I1 y 111). Los signos positivos muestran cuales conexiones van a la entrada positiva del amplificador para cada muestra. I + LL Figura 2. Una corriente dipolar es una fuente de corriente y un corriente invertida separado por una distancia. Tal que cada dipolo tiene una magnitud y una dirección la cual cambia a través de un pulso cardiaco, como las celdas en un corazón depolarizado, estas muestras tienen la representación vectorial donde p(t) es el vector cardiaco de variación en el tiempo, pi(t) son los componentes ortogonales del vector también llamados muestras escalares; x, y, z son los vectores unitarios en las direcciones x, y, z, respectivamente. Un reconocido investigador del VCG en los ~ O ' S , llamado Frank, trazo un molde de yeso del cuerpo de un sujeto como el que se muestra en la Figura 3, probado en agua, y lleno de agua salada. El colocó una fuente dipolar compuesta de dos electrodos en una barra, puesto en el torso del modelo a la altura del corazón. Una fuente de corriente sustituía la corriente de los electrodos, los cuales entonces producían fluidos de corriente en el conductor. Desde los electrodos empotrados en el yeso, Frank media la distribución del potencial en la superficie del cuerpo como muchos puntos torácicos, de la fuente de corriente. De las mediciones en cada estudio, encontró los coeficientes de transferencia geométrica que relaciona la fuente dipolar con cada uno de los potenciales de la superficie del cuerpo. del torso Figura 3. Seminario de proyectos Electrodo rabado de la Proyecto de ingeniería electrónica Una vez que los coeficientes de transferencia son conocidos, el problema de avance de la electrocardiografía puede ser resuelto por cualquier fuente de dipolo. La solución de avance proporciona el potencial para cualquier punto arbitrario en la superficie del cuerpo para dado dipolo cardiaco. Vn= tnx px(t) + tny py(t) + f n z pz(t) Esta solución para el avance muestra que el potencial Vn (t) (el ECG) para cualquier punto n en la superficie del cuerpo esta dada por la suma linear de los productos del conjunto de coeficientes de transferencia [hi]único para ese punto y los correspondientes componentes del vector del dipolo ortogonal [pi(t)]. Los ECGs están variando en el tiempo como sus componentes del dipolo, mientras los coeficientes de transferencia solamente dependen de la geometría torácica y los homogéneos. Así para un conjunto de k potenciales de la superficie (muestras), existe un conjunto de k ecuaciones que pueden ser expresadas en un a matriz de la forma V=TxP donde V es un vector k x 1 que representa los potenciales variantes en el tiempo, T es una matriz de coeficientes de transferencia de k x 3, los cuales están acotados y P es el vector cardiaco de variación en el tiempo de 3 x 1. Por supuesto que el vector cardiaco y los coeficientes de transferencia son desconocidos para un caso particular. Por lo regular si tenemos una forma de calcular este vector cardiaco, podremos usarlo en la solución del problema de avance y obtener el ECG para cualquier lugar de la superficie del cuerpo. La aproximación para la solución de este problema esta basado en un modelo físico del torso humano. El modelo proporciona los coeficientes de transferencia, que relaciona los potenciales con muchos puntos de la superficie del cuerpo, para el vector cardiaco. Con esta información, escogemos tres muestras del ECG que suma las características intrínsecas del ECG anormal deseado para simularlo. Entonces resolvemos el problema inverso para encontrar el vector del dipolo cardiaco P=BxV donde B es una matriz de 3 x k de coeficientes de muestras que es directamente derivado de invertir la matriz T de coeficientes de transferencia. Así, para los tres componentes del vector cardiaco, hay tres ecuaciones lineales de la forma Si escogemos k muestras de ECG de la superficie del cuerpo { vl(t), u2(t), ..., m(t) } para los cuales los coeficientes de las muestras son conocidos del modelo físico del torso humano, podemos resolver el problema inverso y calcular el vector cardiaco de la variación en el tiempo. Una vez que tenemos estos componentes del dipolo, podemos solucionar el problema de avance para calcular el ECG para cualquier punto de la superficie del cuerpo. La Figura 4 muestra como un ECG es medido utilizando electrodos colocados sobre la superficie del cuerpo y conectados a un instrumento amplificador (ECG). Para los Seminario de proyectos Provecto de ingeniería electrónica puntos en el tiempo, que apuntan en la dirección del vector, que están hacía la parte positiva del amplificador del electrodo conectado, la salida de la señal del ECG será positiva. Si los puntos están hacía el electrodo negativo, el ECG será negativo. El movimiento variante en el tiempo del vector cardiaco produce el ECG de la superficie del cuerpo para un pulso cardiaco, con sus ondas características P y T, y su complejo QRS. En la Figura 4 se muestra como podemos observar las diferencias de potencial entre los miembros, como fuentes de voltaje ideal, donde se hace cada voltaje medible, utilizando un instrumento amplificador con una impedancia muy alta. Es claro que estos tres voltajes forman un ciclo cerrado medible. De la ley de voltajes de Kirchhoff, la suma de los voltajes alrededor del ciclo es igual a cero. De esta forma I1 - I - I11 = o donde podemos reescribir esta ecuación para expresar cualquiera de los muestras en términos de las otras dos. I1 = I - I11 I = I1 - I11 I11 = I1 - I Así es claro que uno de esos voltajes es completamente redundante; es posible medir cualquiera de los otros dos y calcular el tercero. En efecto, eso es lo que las maquinas de ECG hacen. Muchas maquinas miden las muestras I y 11, y calculan la muestra 111. Figura 4. Seminario de provectos Proyecto de ingeniería electrónica La primera instrumentación tuvo una ganancia inadecuada para la producción de suficientes trazos de ECG para todos los sujetos, de esta manera la Figura 5 muestra la manera de producir una mayor amplitud de las señales. En este caso, la señal del brazo izquierdo, llamado derivacion aumentada aVL, es medido utilizando el promedio de los potenciales de los otros dos miembros como una referencia. Se puede analizar esta configuración utilizando teoría de circuitos común. Donde el ciclo del fondo de la izquierda esta dado por i x R + i x R - 11= O O i x R= II/2 (Ec. 1) y para el ciclo del fondo de la derecha esta dado por -i x R + I11 + aVL= O aVL= i x R - I11 (Ec. 2) sustituyendo el valor de la Ec. 1 en la Ec. 2 se obtiene aVL= II/2 - III= (I1 - 2 x III)/2 I RA aVL R Figura 5. Seminario de proyectos Proyecto de ingeniería electrónica Del ciclo de arriba al centro 11= I11 + I sustituyendo se obtiene aVL= (I11 + I - 2 x iii)/2= (I - 111)/2 Este es el voltaje equivalente de Thévenin para el muestra aumentada del aVL como un promedio de los potenciales de las dos muestras frontales como una referencia. Es claro que un aVL es una muestra redundante dado que puede ser expresado en términos de las otras dos muestras. Las otras dos muestras aumentadas, un aVR y un aVF, similarmente ambas pueden ser expresadas como funciones de las muestras I y 111. Así encontramos tres muestras adicionales, las cuales pueden ser calculadas a partir de las muestras frontales y así todas son redundantes sin nueva información real. De esta forma, dada la naturaleza empírica de la electrocardiologia, sin embargo el físico necesita ver la apariencia de estas muestras para facilitar el diagnóstico. Este problema se resuelve vectorialmente mediante una muestra de derivación aumentada en términos de dos de las derivaciones standard. Las derivaciones están representadas por vectores orientados en las direcciones de los lados correspondientes al triángulo, pero centrados al origen común. Para encontrar un aVL, como en este ejemplo, se utilizan los vectores de los dos derivaciones para encontrar el vector resultante, en este caso, el del lado brazo izquierdo. Se utiliza la muestra I como uno de los vectores para sumar, dado que su sentido positivo esta conectado con el brazo izquierdo. El vector de la muestra I11 se desprecia dado que su sentido es negativo en relación con el brazo izquierdo. La muestra aVL es la mitad del valor de la suma de los vectores de las muestras I y -111. Se puede representar el conjunto completo de vectores representando las derivaciones frontales. De esta descripción, se pueden encontrar rápidamente los tres derivaciones aumentadas como funciones de las muestras frontales. De esta forma tenemos el sistema básico de tres muestras utilizado en la cardiología. El más popular es el que utiliza una aproximación de 1 2 muestras, el cual define un conjunto de 12 diferencias de potencial que componen el ECG clínico estándar. Un segundo conjunto de muestras designa las posiciones de los electrodos para las grabación del VCG. Los sistemas de monitoreo, comúnmente analiza uno o los dos. Se tienen 1 2 muestras del ECG clínico estándar que se monitorean. El amplificador para esta instrumentación tiene un diseño especial para la electrocardiografia. En un moderno microprocesador que hay en las máquinas para ECG, hay ocho amplificadores similares, los cuales graban simultáneamente las muestras I, I1 y V1-V6; entonces calculan las muestras las muestras 111, aVL, aVR y aVF para el reporte final. El posicionamiento de los electrodos, para un sistema de muestras VCG Frank, es el más popular, mundialmente, sistema de muestras de VCG. Las aplicaciones de monitoreo no usan un estándar de las posiciones de los electrodos, pero usualmente utiliza dos muestras. Dado que el principal acierto de estos sistemas es el del reconocimiento de los pulsos cardiacos y el análisis del ritmo; los electrodos son colocados donde la señal primaria del ECG tiene una amplitud de onda R grande. Dado que la muestra I1 tiene una amplitud pico muy grande para muchos pacientes, ésta muestra es recomendada frecuentemente como la primer opción de Seminario de proyectos Provecto de ingeniería electrónica muestra primaria para muchos fabricantes. Una segunda muestra con diferentes posiciones de los electrodos sirve como un respaldo, en el caso que la primer muestra tenga problemas. La regularmente se manejan tres anchos de banda utilizados en las distintas aplicaciones en la electrocardiografia. El ancho de banda clínico utilizado para la grabación de ECG estándar de 12 muestras es entre 0.05-100 Hz. Para aplicaciones de monitoreo, tales como para los paciente de cuidado intensivo y para los pacientes ambulatorios, el ancho de banda Es restringido a 0.5-50 Hz. En estos ambientes, las perturbaciones del ritmo (las arritmias), son más importantes que los cambios morfológicos en las formas de onda. De esta forma, el ancho de banda restringido, atenúa el ruido de alta frecuencia provocado por las contracciones musculares (ruido EMG) y el ruido de baja frecuencia provocado por el movimiento de los electrodos. Un tercer ancho de banda utilizado para medir el ritmo cardiac0 (cardiotacometro) maximiza el radio de señal de ruido para detectar el complejo QRS. El filtro permite el paso de las frecuencias del complejo QRS, mientras rechaza el ruido, incluyendo las ondas que no son QRS, tales como las ondas P y T. Este filtro ayuda a detectar los complejos QRS, pero distorsiona el ECG, tanto que la apariencia de la señal filtrada no es clínicamente aceptable. Alguna otra aplicación no muestra ampliamente el ancho de banda superior a los 500 Hz. Hay pequeños eventos de frecuencia muy alta que pasen en ECG siguiendo al complejo QRS. El pico de amplitud de una señal de ECG esta en el rango de 1 mV, y un amplificador de ECG, comúnmente, tiene una ganancia de alrededor de 1,000, para dar una señal pico del rango de 1 V. Seminario de proyectos Prwecto de inneniería electrónica J O 0 0 0 0 0 0 0 -t í; - El ALGORITMO. Dadas las características de la tarjeta de prueba, es necesario implementar un programa que al adquirir el dato lo filtre, puesto que esta tarjeta carece de un filtro que cumpla con tal fin.Esta ííltración nos permitirá obtener datos más aproximados a los reales, ya que existen muchos factores eléctricos que pueden alterar la señal original, éstos pueden ser tales como, la tensión muscular, el tipo de eléctrodos, etc. El algoritmo utilizado es el de detección del complejo QRS a tiempo real de la señal de ECG. Éste realizará una detección basándose en análisis dígital de pendientes, amplitud y ancho. En forma general, el algoritmo esta compuesto de tres etapas principales: pasabandas, derivación e integración, las cuales serán descritas a continuación. Filtro pasa banda El filtro pasa banda reducirá una detección falsa causada por las interferencias diversas presentadas en una sena1 de ECG. Este filtrado permite usar umbrales bajos, de ese modo se incrementara la sencitividad de la deteccion. El algoritmo automáticamente ajustará umbrales y parametros para adaptar a los cambios del ECG como la morfologia del QRS. La primera etapa del pasa banda es el pasa bajas, que esta representado por la ecuación y(nT)=2y(nT-T)-y(nT-2T)+x(nT)-2x(nT-6T)+x(nT-l2T) Ec. 1 donde la frecuencia de corte es aproximadamente 11 Hz y una ganancia de 36. La implementación dentro del algoritmo real esta dada por la siguiente función: float P-Bajas(float dat) { int i; float aux; fx[l2]=dat; aux=2*fy[l]-fy[O]+dat-2*fx[6]+fx[O]; for(i=O;i<l2;i++) fx[i]=fx[i+l]; fyP1 =fy[ll; fy[l]=aux; return(aux); 1 En el arreglo fx se representa a x(n) que es de tamaño 12 y que se va actualizando conforme llega un dato, haciendo un recorrido de los valores que ya se encontraban con anterioridad, para de esta manera aplicar la Ec. 1. Para el caso de y(@, es representada por el arreglo fy, que es de tamaño 2, esto debido a que en realidad siempre se utilizan dos celdas; una que trae el valor anterior y otra que almacena el valor de la evaluación actual. La segunda etapa es el filtro pasa altas que utiliza la siguiente ecuacion de diferencias y(nT)=32x(nT-16T)-[y(nT-T)+x(nT)-X(nT-32 T)] Ec. 2 cuya frecuencia de corte es de 5Hz y una ganencia de 32. La función que realiza esta ecuación dentro del algoritmo es la siguiente: float P-Altas(float datl) { float aux; int t; fxl[32] =datl; aux=(32*fxl[16])-(yant+ datl-fxl[O]); for(t=0$<32$++) fxl[t]=fxl[t+l]; yant=aux; return( aux); I ésta recibe el valor generado por el pasa bajas y le aplica un análisis parecido a la función que lo antecede. En este caso los arreglos que representan a x(n) y a y(n), respectivamente son fxl y yant, para el arreglos de y(n) solo requiere de una variable que almacene el resultado anterior. El resultado final es elevado al cuadrado, para posteriormente ser el valor de entrada de la derivación. Derivada Despues del filtrado se obtiene inforrnacion de la pendiente, utilizando la siguiente ecuación de diferencias: y(nT)=(í/¿?T)[-x(nT-2 T)-2x(nT-T)+2x(nT+T)+x(nT+2T)] Ec. 3 La función que representa este paso es la siguiente: float Deriva(float dt) { float temp; int i; DRV[4] =dt; temp=( (2*DRV[3])+DRV[4]-DRV[O]-(2*DRV[1]))*0.125; for(i=O;i<4;i++) DRV[i]=DRV[i+l]; return(temp); 1 en este caso, cada punto que es derivado, es almacenado en el arreglo DRV, que en la Ec. 3 es x(n), y que cada entrada a esta función va recorriendo los valores, quedando en la posición 3 el último obtenido, el resultado final del punto queda en temp. Elevación al cuadrado En este paso, la señal es elevada al cuadrado punto a punto; donde la esta operacion esta representada por: esto hace a todos los puntos positivos, una amplificación no lineal de la salida y la derivada enfatiza frecuencias mas altas. Integración Este último paso es para la obtención de la característica de la forma de onda en relacion con la pendiente de la onda, y se utilizará la siguiente ecuacion de diferencias: y(nT)=(I/N) [x(nT-(N- I ) T)+x(nT-(N-2)T)+...+x(nT)] Ec. 5 donde N es el numero de muestras en el ancho de la ventana de integracion. La funcion que realiza este calculo es la siguiente: float Integra(float dt) { int i; float al; INTGINI =dt; itg=itg-INTG[O]+dt; a l =it@; for(i=O;i<N;i++) INTG[i]=INTG[i+l]; return(a1); 1 en este caso el arreglo x(n) este representado por INT y el valor del resultado queda en itg, que seria el resultado de la Ec. 5, y(n) . El resto de las funciones agregadas, son para adecuar y graficar los valores de los puntos obtenidos; posteriormente se realiza la descripición de cada una de las funciones. -LA TARJETA. La tarjeta que se utilizó para la pruebas preliminares del software fue la PCL-812PG, posteriormente se utilizará una de diseño propio, y que esta descrita en la primer parte del reporte este proyecto. Se utilizara la tarjeta PCL 812PG (Enhanced Multi-lab card) para hacer la adquisicion y conversion A/D y D/A, mediante software se implementa el filtro, consistente en un pasa banda, derivacion e integracion. Desmipción de la tarjeta La PCL-812PG es una tarjeta de adquisición de datos de alto desempeño, velocidad y multi-funciones para IBM PC/XT/AT y computadoras compatibles. las aplicaciones incluyen adquisición de datos, procesos de control, evaluación automática y automatización. Como características generales se pueden establecer las siguientes: - 16 canales de entrada analógica. - Un convertidor de aproximaciones sucesivas para convertir entradas analógicas. El máximo rango de muestre0 A/D es de 30KHZ en modo DMA. - Rangos de entrada analógica programable por software Bipolar: +/ -5V,. +/ -2.5V,+/ -1.25V,+/-0.625V,+/-0.3125V. La habilidad para transferir datos convertidos de A/D por un programa de control, rutina de atención a interrupción o transferencia por DMA. - Un Timer/Counter programable INTEL 8253-5 que nos da pulsos a un rango e 0.5 MHz a 35 minutos /pulso. La base de tiempo del timer es de 2 MHz. Un canal contador de 16 bits es reservado para aplicaciones de configuración. - Mapa de direcciones del puerto de entrada/salida La siguiente descripción proporciona la ubicación de cada registro y los controladores relacionados a la dirección base: Ubicación I I I I Base + O Base + 1 Base + 2 Base + 3 Base + 4 Base + 5 Base + 6 Base + 7 Base + 8 Base + 9 Base + 10 Base + 11 Base + 12 Base + 13 Base + 14 Base + 15 Lee I I I I Contador O Contador 1 Contador 2 No se utiliza A/D Byte bajo A/D Byte alto D/I byte bajo D/I bvte alto No se usa No se usa No se usa No se usa No se usa No se usa No se usa No se usa Escribe I I I I I Contador O Contador 1 Contador 2 Control del contador CH1 byte bajo D/A CH1 byte alto D/A CH2 byte bajo D/A CH2 bvte alto D/A Limpia la solicitud de interrupción Control de la ganancia MUX Control Control de modo Disparo del software A/D Bvtebaio D/O Bvtealto D/O No se usa /* Adquiere.c f i \ I * Proyecto de ingeniería electrónica I1 I* Prof. Donaciano Jiménez I* Alumno: Adrián González Contreras I* Matricula: 89227081 i * Programa de adquisición de una señal cardiaca, mediante el uso de I * la tarjeta PCL-812PG - - \ *I / #include <graphics.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <math.h> #include <dos.h> #include <float.h> #include <string.h> /* Tipo de señal "/ #define cuadrada #define seno #define pulso 2 3 #define otra #define adquirida /* Tipos de impresión "/ #define normal #define pasa-bandas #define derivada #define integral #define FRECUEN -- / *I *I *I *I 6 10 \ Indica en que momento grafica las frecuencias / *\ #define antes #define despues #define verdadero #define falso const base=Ox300; const N=26; 3 4 8 9 *I -/ \ Variables globales -\ / int xl, yl, y2, lugar, cont, ya= O, MAX, MIN, estuvo,frec[20]; int alto= O, frecuencia, tipo, imprime, segunda= 1, graficacion= O; char buffer [50]; char el-archivo [30]; float fx[13],fy[2],fxl[33],DRV[6]; float itg,yant,vall; float INTG[27]; double maximos[4]; FILE *paradeer; -/ \ Definición de funciones -\ double factor(); float senalo; void detecta-max(); void mas-grande(); void MIN-MAX(); void portada(); void grafica(); void inic-var(); void h-proc(); void frecuencias(); void pinta-punto(); void grafica-frec(); int espera(); int IniciaGraficos(); / /\ \ Función, que mediante POLLING, espera la llegada de un dato. int espera() I int msb,z; msb= 1; z= o; while(8) { msb =inportb(base+5); z++; iymsb<= 15 && z> 15)break; 1 return(msb); I / ....................... \ . . . . . . . . . . . . . . . . . . . . . . / Función responsable de configurar los controladores de la tarjeta de adquisición (PC Lab en este caso). void activ-card() { int cntl,cnt2; int lsb,msb; cntl=Ox74; cnt2=OxB4; outportb(base+lO,l); /* Establece el canal de comunicación ”/ outportb(base+9 ,O); /* Establece la ganancia ”/ outportb(base+ll,6); /* Establece el modo de operacitn (POLLING)”/ lsb=OxDO; msb=Ox7; outportb(base+3,cnt2);/* Inicializa cuenta de contador 2 outportb(base+2,lsb); /* Parte baja del contador 2 outportb(base+2,msb); /* Parte alta del contador 2 ”/ ”/ ”/ lsb=Ox2; msb=O; outportb(base+3,cntl);/* Inicializa cuenta de contador 1 “/ outportb(base+l,lsb); /* Parte baja del contador 1 ”/ outportb(base+l,msb); /* Parte alta del contador 1 ”/ inportb(base+S); /* Esta ljnea despeja de “basura”el canal “/ 1 \ / I F Esta función es la primer proceso que se le aplica al pasa banda, que es el filtro pasa bajas. \ / float P-Bajas(float dat) I int i; float aux; fx[l2]=dat; aux=2*fy[l]-fy[O]+dat-2*fx[6]+fx[O]; for(i=O;i42;i++) fx[i]=fx[i+l]; fYto1=fY[lI; fy[l]=aux; return(aux); 1 /"""""""""""""""""""""""* \ La función del filtro pasa altas, recibe el valor generado por el filtro pasa bajas, con lo que se complementael filtro pasa bandas. \"""""""""""""""""""""""""* float P-Altas(fl0at datl) { float aux; int t; / fx1[32]=datl; aux=(32*fxl[16])-(yant+datl-fxl [O]); for(t=O;t<32;t++)fxl[t]=fxl[t+l]; yant=aux; return(aux); 1 /""""""""""""""""""""""* \ \""""""""""""""""""""""* / Esta función obtiene la derivada del dato adquirido, con lo que se van "limando" los valores de la sedal. float Deriva(float dt) { float temp; int k DRV [4]=dt; temp=((2*DRV[3])+DRV[4]-DRV[O]-(2*DRV[l]))r).125; for(i=O;i<4;i++) DRV[i]=DRV[i+l]; retum(temp); 1 /""""""""""""""""""""""""* \ \"""""""""""""""""""""""""* / Esta función integra el valor del dato, recibe el valor generado por la función deriva. float Integra(float dt) I int i; float al; INTG[N]=dt; itg=itg-INTG[O] +dt; al=itg/N; for(i=O;iCN;i++) INTG[i]=INTG[i+l]; retum(a1); 1 /””””””””””””””””* \ \””””””””””””””””* / Esta función grafica los datos adquiridos. void grafica(void) { float dato,aux,drv,integ; int x,y,i,MSB,LSB,linea=500; xl= getmaxx0-8; yl=(getmaxyO/3); y2= getmaxy()-100; x=i= O; lugar= o; estuvo= faiso; frecuencia= O; do{ if(imprime== adquirida) { MSB= espera(); LSB= inportb(base+4); dato= (MSB*256+(LSB-2048))*(0.002441); 1 else dato=senal(x,tipo); pinta-punto(normal,tipo,x,dato); /* Es esta parte se le aplica un pasabandas ”/ aux= P-Altas(P-Bajas(dat0)); drv= Deriva(aux); if(graficacion== despues) pintapunto( derivada,tipo,x,drv); drv= pow(drv,2); integ= Integra(drv)”factor(tipo); pinta-punto(integral,tipo,x,integ); if(estuvo== falso) detecta-max(integ,x); else { if(segunda== 2) frecuencia++; d(integ> MAX-20) { if(gr&cacion== antes) pinta-punto(FRECUEN,tipo, x, frecuencia); if(graficacion== despues) &&o<= 20) frecuencias(); /”/ nosound(); /”/ sound(800); delay(l0); nosound(); segunda= 2; sound@nea+=lO); 1 1 x+=l; if(x>= xl){ sound(linea); x=o; clearviewport(); 1 if(kbhit()) i= 1; delay(2); }while(+= O); nosound(); if(graficacion== despues) grafica-fret(); if(tipo== pulso) fclose(para-leer); getch0; fin_procO; void frecuencias() { if(frecuencia<= 100) return; frec[alto]= frecuencia; frecuencia= O; segunda= 1; alto+= 1; I /"""""""""""""""""""""""* \ \"""""""""""""""""""""""* / Función que permite ajustar los valores de los puntos obtenidos, para poderlos desplegar en la pantalla. double fador(tipo-sed) I switch(tipo-sed) { case pulso: return(O.00000006); default return(1); 1 I /"""""""""""""""""""""""* \ \""""""""""""""""""""""* / En esta función se pueden ir seleccionando cada que determinada cantidad de muestras se escoge un máximo, por ejemplo: cada dos muestras se escoge uno y se almacena en la función "mas_grande". void detecta-max(max-loc,cont) double max-loc; int cont; I if(cont%2== O) { if(ya== O) { maximos[lugar]= max-loc; lugar++; if(lugar== 4) ya= 1; I I else mas_grande(max-loc); if(cont== 630) MIN-MAX(); 1 ....................... \ Aquí se selecciona el rango donde puede caer un máximo, quedando los valores entre MIN y MAX, que son los valores finales. ....................... void MINMAXO / int q; MIN= maximos[3]; MAX= maximos[3]; for(q= O; q< 4; q++) [ iymaximos[q]> MAX) MAX- maximos[q]; if(maximos[q]< MIN) MIN= maximos[ql; 1 estuvo= verdadero; 1 \ . . . . . . . . . . . . . . . . . . . . . . . . . Esta función recibe los datos y almacena los que son máximos de la primera pantalla de muestras; posteriormente con estos máximos locales se puede establecer donde estar n, aproximadamente los máximos. - - \ “*/ void mas-grande(e1em) double elem; I int i; double temp; for(+ 3; i>= O; i--) [ iymaximos[i]< elem) { temp= maximos[i]; maximos[i]= elem; elem= temp; 1 1 1 /”””””””””””””””* \ \””””””””””””””* / Función que inicializa el modo gráfico. int IniciaGraficos() int gdriver=DETECT,gmode,errorcode; detectgraph(&gdriver,&gmode); initgraph(&gdriver,&gmode,””); errorcode=graphresult(); if(errorcode!= @k) { printf(”\nErroren inicializacion de gr ficos”); printf(n\n%s”,grapherrormsg(emorcode)); getch0; ~tulTl(0); 1 else return(1); 1 /"""""""""""""." \ \""""""""""""""" / Aquí se despliega la pantalla inicial. void portada() { cleardevice(); setcolor(L1GHTCYAN); rectangle(0,32,getmaxx(),getmaxy()-32); rectangle(420,4,getmaxx()-ó5,28); rectangle(l0,getmaxy( )-28,getmaxx()-389,getmaxy()-5); setfillssrle(l,4); floodfill(l,l,LIGHTCYAN); floodfill(1,getmaxy(),LIGHTCYAN); settextstyle(SMALL-FONT,HORIZ-DIR,5); outtextxy(20,getmaxy()-2O,"PULSE UNA TECLA PARA DETENERu); setcolor(2); outtextxy(430,12,"ADQUIRIENDODATOS"); setviewport(0,33,getmaxx(),getmaxy()-33,1); clearviewport(); setcolor(WH1TE); 1 \ Despliega el final del proceso de adquisición e impresión de resultados. \""""""""""""""""""""""""* void fin-proc() { settextstyle(l,O,l ); setcolor(WHlTE); rectangle(getmaxx()-410,35,getmaxx()-ZS3,19); / settextstyle(SMALL-FONT,HORIZ-DIR,5); outtextxy(getmaxx()-398,22, "PROCESO TERMINADO"); outtextxy(getmaxx()-305,40, getchar(); I "Pulse una tecla"); /""""""""""""""""""""""""* \ \""""""""""""""""""""""m""" / Procedimiento donde, en función del tipo de señal que se va a simular, se multiplica el dato adquirido por un factor que permita desplegarlo en la pantalla. Aquí se imprimen los tres distintos "procesos" a los que se someten los datos. void pinta-punto(func,clase,laX,laY) int func,clase,laX; float lay; 1 char buffy[6]; switch(func) { case normal: if(clase== pulso) putpixel(laX,5O-laY*O.O5,YELLOW); if(clase== seno) putpixel(laX,6O-laY~O,YELLOW); if(Clase== cuadrada) putpixel(laX,óO-laYY0,YELLOW); break; case pasabandas: if(clase== pulso) putpixel(laX,120-IaY*O.~l,WHITE); if(clase== seno) putpixel(laX,120-laY*O.O3,WHITE); lyclase== cuadrada) putpixel(laX,12O-laY*O.O2,WHITE); break; case derivada: if(clase== pulso) putpixel(laX,yl-laY*0.0008,RED); if(clase== seno) putpixel(laX,200-laY*o.28,FED); if(clase== cuadrada) putpixel(laX,200-1aY*O.O8,ñED); break; case integral: @clase== pulso) putpixel(laX,y2-laY,GREEN); if(cl&se==seno) putpixel(laX,390-iaY*O.007,GñEEN); @clase== cuadrada) putpixel(laX,390-laY*0.0007,GREEN); break; case FRECUEN : if(frecuencia<= 100) break; memset(buffy, '\O', sizeof(buffy)); buffy[O]= I*'; itoa(frecuencia, &buffy[l], 10); outtextxy(laX, y1,buffy); frecuencia= O; break; /"""""""""""""""""""" SIMULA SEWALES \ \"""""""""""""""""""* / Esta función permite simular las tres señales básicas: cuadrada, seno y un pulso cardiac0 obtenido de un archivo de texto. float senal(punto,tipo-send) int punto, tipo-senal; { double bien; switch(tiposenal) { case cuadrada: II if(punto<= 40 (punto> 80 && punt0<=120) I I (punto>lóO && punt0<=200) I I (punto>240 && punto<=280) I I (punto>320 && punto<=360) I I (punto>400 && punto<*o) II (punto>480 && punto<=520) I I && punto<=rn) I I (punto~560 (punto>640 && punto<=óóO)) retum(5); else return(-5); case seno: retum(sin(punto*O.O)*5); case pulso: retum(hart(punt0)); default: return(punt0); I 1 /""""""""""""""""""""""* \ \""""""""""""""""""""""" / Esta función lee un archivo donde se tiene almacenadauna seaal cardiaca, y permitiendo asi simular una adquisición real. int hart() { int bien, resultado; if(ya== O) bien= abre-arch(); if(bien) { cleardevice(); exit(0); 1 1 fscanf(para-leer, "% i", &resultado); return(resultado); 1 -/ \ -\ / Función que abre la señal cardiaca. int abredar&() { if((para-leer= fopen(e1-archivo, "rt"))== NULL) { clearviewport(); memset(buffer, '\O',sizeoybuffer)); sprintf(buffer,"Err: no se encuentra el archivo % s para ledura",el-archivo); outtextxy(15,200,buffer); outtextxy(l5,210,"E1 archivo va a ser generado"); system("a:cambia.bat"); memset(buffer, '\O', sizeof(buffer)); sprintf(buffer,"Proceso terminado, intente de nuevo",el-archivo); outtextxy(15,22O,buffer); return(-1); 1 ya= 1; \ Función donde se inicilizán los arreglos que contendrá n los resultados de cada análisis. \""""""""""""""""""""""" void inic-varo / I int i; ya= O; if(tipo== pulso) ( el-archivo[O]= '\O'; strncpy(el-archivo, "c:\\tc\\ecg.txt", 25); 1 for (i=O;i==13;i++) fx[i]=O; for (i=O;i==2 ;i+fy[i]=O; +) for (i=O;i==33 ;i++) fxl[i]=O; for(i=O;i==6 ;i++) DRV[i]=O; for (i=O;i==N+l;i++)INTG[i]=O; yant=itg=O.O; cont=O; vall=O; 1 /"""""""""""""""""""""" \ \""""""""""""""""""""" / Imprime una relación global de los datos adquiridos con sus respectivas frecuencias. void grafica_frec() { int ,i j, ana, antY, lax; char *cadena, buff[4]; lf(alto< 1) retllm; clearviewport(); setfiilstyle(1,DARKGRAY); floodfiU(l,l,LIGHTCYAN); line(35,30,35,350); line(15,350,630,350); for(i= 30; i>= O; i--) { j= i % 5; lf(J=- O) { line(27,(i~0)+50,35,(i~O)+50); /* iyx<fjoo) I itoa(x+=lOO,cadena,lO); "/ 1 1 outtextxy(5,iq0-5,cadena); else line(32,(iYO)+50,35,(ir0)+50); for(i= O; i< 60;i++) { j= i 99 5; if(j== O) { line((i90)+35,350,(i~O)+35,358); /"/ itoa(i*5,cadena,lQ); outtextxy((i~0)+35,3,cadena); /"/ 1 1 else line((iqO)+35,35O,(iqO)+35,353); j= 83; ana=antY= o; for(+ O; i<= alto I I alto<= 20; i++) { memset(buff, '\O',sizeoybuff)); iyi== alto) break; laX=irO+j; setcolor(GREEN); itoa(frec[i], buff, 10); outtextxy(laX,getmaxy()-free[i]+50, buff); outtextxy(laX,getmaxy()-frec[i]+60,"*"); if(i> O && i<= alto) { setcolor(RED); line(antX,antY,laX+2,getmaxy()-frec[i] +óó); 1 antx= lax+2; antY= getmaxy()-frec[i]+óó; I 1 j+= 40; ....................................... 1*+*+ P R I N C I P A L +*+*+*+*+*+*+*+*I ....................................... void main() { if(IniciaGraficos()) { imprime= otra; tipo= cuadrada; graficacion= despues; if(imprime== adquirida) adiv-card(); inic-varo; portada0; graficao; closegraph(); I