Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Victor Tzorin1
1
Universidad Galileo
Guatemala, Guatemala
El complejo QRS es la onda más distintiva y1 (n) = |x(n) − 2x(n − 2) + x(n − 4)| (2)
del electrocardiograma (ECG, por sus siglas en
inglés). Dado que refleja la actividad eléctrica Por último, los dos resultados son ponde-
dentro del corazón durante la contracción ven- rados y combinados para obtener (Rangayyan,
tricular, el momento en que ocurre y su forma 2015) [3]:
proveen mucha información sobre el estado ac-
tual del corazón; también sirve como base pa- y2 (n) = 1.3y0 (n) + 1.1y1 (n) (3)
ra la determinación automática de la frecuencia
cardı́aca, como punto de entrada para los esque-
I-B. Algoritmo Murthy-Rangaraj
mas de clasificación del ciclo cardı́aco y a me-
nudo también se usa en algoritmos de compre- Método que consiste de un derivador, una
sión de datos de ECG (Kohler et. al, 2002) [1]. media móvil de orden alto y un umbral que es
1
igual a la mitad de la amplitud del pico más alto verdaderos negativos, en una población; mide el
de la señal evaluada. grado de veracidad de una prueba para evaluar
El resultado del derivador de la señal x(n), una condición en general (Zhu et. al., 2010) [4].
a su vez, es ponderado y elevado al cuadrado de
la siguiente forma (Rangayyan, 2015) [3]:
N
X
y0 (n) = |x(n−i+1)−x(n−i)|2 (N −i+1) II PROCEDIMIENTO
i=1
(4)
II-A. Materiales
I-C. Sensibilidad, especificidad y preci-
sión
Software ejecutado en computadora por-
Hay varios términos que se usan tatil Lenovo Yoga 730 (15”) con procesa-
comúnmente junto con la descripción de sen- dor Intel Core i5
sibilidad, especificidad y precisión. Estos son: Programa escrito en Python utilizando las
verdaderos positivos (VP), verdaderos negati- librerı́as PyQtGraph, Datetime, Random,
vos (VN), falsos negativos (FN) y falsos po- Numpy, Pandas, Math y Scipy.
sitivos (FP), donde las denominaciones dadas
son autodescriptivas. La sensibilidad, especifi- Datos extraı́dos de la base de datos en
cidad y precisión se describen en términos de lı́nea Physionet (Physionet, s.f.) [2].
VP, VN, FN y FP de la siguiente forma (Zhu et.
al., 2010) [4]:
VP
sensibilidad = (5)
V P + FN
II-B. Pasos del procedimiento
VN
especif icidad = (6)
V N + FP 1. Descargar archivos de Physionet.
2. Hacer un programa que:
VN +VP
precisión = (7) Grafique cada una de las señales no
V N + V P + FN + FP filtradas de los archivos.
Como lo sugieren las ecuaciones anteriores, Aplique el algoritmo de Tompkins y
la sensibilidad es la proporción de verdaderos grafique los resultados.
positivos que se identifican correctamente me- Aplique el algoritmo de Murthy-
diante una prueba; muestra cuán buena es dicha Rangaraj y grafique los resultados.
prueba para detectar positivamente una condi-
ción. La especificidad es la proporción de los Compare los resultados de los algo-
verdaderos negativos correctamente identifica- ritmos con los resultados del proce-
dos por una prueba; sugiere qué tan buena es la so de selección manual para obtener
prueba para identificar negativamente una con- sensibilidad, especificidad y preci-
dición. La precisión es la proporción de resul- sión.
tados verdaderos, ya sea verdaderos positivos o 3. Analizar los resultados.
2
III RESULTADOS utilizados por archivo
IV DISCUSIÓN/ANÁLISIS
3
cido; por esta razón, el algoritmo obtuvo una [2] PhysioNet (s.f.). Recuperado de: https:
sensibilidad de 0.985 en este caso. //physionet.org/.
Ası́ que, debido a la forma de definir el um- [3] Rangayyan, R. M. (2015). Biomedical sig-
bral a prueba y error para garantizar los mejo- nal analysis (Vol. 33). John Wiley & Sons.
res resultados, el algortimo Tompkins obtuvo el [4] Zhu, W., Zeng, N., & Wang, N. (2010).
mejor desempeño. Pero la ventaja del Murthy- Sensitivity, specificity, accuracy, associated
Rangaraj sobre el Tompkins es que hay menos confidence interval and ROC analysis with
factores que hay que ajustar y adaptar a las di- practical SAS implementations. NESUG
versas señales. Sin embargo, ambos métodos proceedings: health care and life sciences,
son funcionales y pueden identificar todos los Baltimore, Maryland, 19, 67.
complejos QRS si se ajustan de mejor mane-
ra sus parámetros. Por esta razón, cualquiera de
estos procedimientos serı́a funcional para medir
ritmos cardiacos y, por lo tanto, detectar arrit-
mias. Pero hay que recordar que no es posible
usarlos para estudios que requieran evaluar la VII ANEXOS
morfologı́a de la señal, como cuando se estu-
dian los infartos al miocardio.
VII-A. Otras imágenes
V CONCLUSIÓN
VI REFERENCIAS
Referencias
4
Figura 6: Complejos QRS identificados mediante el algoritmo
Murthy-Rangaraj del archivo apnea-ecg a10
5
VII-B. Código de programa utilizado
Código fuente de programa utilizado para analizar y filtrar los ECGs:
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 6 17:56:20 2019
#LIBRARIES
#Import of libraries
import pyqtgraph as pg
import pyqtgraph.exporters
from datetime import datetime
import random
from scipy import signal
import numpy as np
import pandas as pd
import math
#FUNCTIONS
#Function that reads a csv document with the first column being time and
#two columns of values
def csvreadert1(file_name):
#Declaration of variables
file = open(file_name+’.csv’)
tempo = 0
x = []
y = []
#Cycle that reads every line of the file and adds the values to the
#corresponding list
for i in file:
try:
y.append(float((i.split(’,’)[1])))
except:
pass
return x,y
6
#Function that extracts the signal spectrum
def espectro(x,fs):
f,sp = signal.periodogram(x,fs,scaling=’spectrum’)
amp = np.sqrt(2*sp)
return f,amp
#Variables to use
y=[]
for i in range(int(no_polos_y_ceros/4)):
#Error message
else:
print(’ERROR’)
pass
7
return y
return z
#Second derivative
y2 = []
for j in range(len(x)):
if i>=4:
y2.append(abs(x[j]-2*x[j-2]+x[j-4]))
else:
y2.append(0)
#Sum of derivatives
y3 = []
for k in range(len(x)):
y3.append((1.3*y1[k]+1.1*y2[k])/2)
return y3
8
#Function that derives the data according to Murthy & Rangaraj’s algorithm
def derMR(x,N):
y1 = []
suma = 0
for i in range(len(x)):
if i>=N:
for j in range(1,N+1):
suma = (N-j+1)*(x[i-j+1]-x[i-j])**2
y1.append(suma)
suma = 0
else:
y1.append(0)
return y1
#Function that finds all the peaks of a signal above half of its max value
def picos(x, T):
#Trigger
h = T
#Cycle that obtains the limits of the intervals above the trigger
u = []
for i in range(1,len(x)-1):
if len(u)%2==1:
del u[-1]
else:
pass
#Cycle that finds the time and values of the peaks of the intervals
y = []
for j in range(int(len(u)/2)):
y.append(int(u[2*j]+x[u[2*j]:u[2*j+1]].index(max(x[u[2*j]:u[2*j+1]]))))
9
return y
for i in range(len(x)):
tempo = cont1
for j in range(acceptance+1):
if (x[i]-j in y) or (x[i]+j in y):
cont1 = cont1 + 1
else:
pass
if cont1 == tempo:
cont2 = cont2 + 1
#Theoretical values
ideal01 = [40,128,212,295,378,466,560,657,751,844,938,1038,1140,1241,1340,1437,
1532,1630,1731,1825,1915,2001,2086,2183,2276,2369,2453,2530,2608,
2688,2769,2853,2937,3018,3101,3190,3290,3383,3471,3557,3642,3729,
3818,3909,4001,4089,4186,4286,4380,4466,4548,4632,4719,4807,4895,
4987,5077,5167,5259,5349,5439,5530,5621,5709,5797,5890,5980]
ideal10 = [80,179,276,373,473,575,672,771,874,979,1080,1178,1276,1374,1473,
1571,1668,1770,1869,1966,2064,2159,2254,2347,2439,2530,2620,2712,
2799,2886,2972,3058,3144,3229,3313,3394,3477,3562,3650,3738,3826,
3914,4003,4091,4181,4272,4363,4454,4544,4634,4724,4815,4908,4998,
5091,5184,5276,5367,5463,5560,5656,5750,5848,5946]
ideal16 = [5,83,158,232,306,381,458,535,614,694,776,859,941,1023,1104,1180,
1255,1328,1398,1468,1536,1604,1673,1743,1813,1885,1956,2029,2104,
10
2178,2252,2324,2395,2465,2533,2600,2666,2733,2802,2869,2938,3010,
3083,3157,3234,3310,3387,3464,3539,3615,3690,3765,3838,3913,3988,
4061,4135,4209,4281,4353,4426,4498,4570,4642,4715,4787,4860,4932,
5004,5074,5144,5213,5283,5353,5423,5493,5563,5634,5705,5776,5847,
5919,5991]
win4 = 0
win5 = 0
win6 = 0
windows2 = [win4,win5,win6]
#Cycle that applies the Tompkins and the Murthy & Rangaraj algorithms to each fil
for i in range(len(file_names)):
#TOMPKINS
#Creation of the window where the graphs are going to be display
windows1[i] = pg.GraphicsWindow(title=’Algoritmo Tompkins para señal ’+file_n
#Variables to use
x,y = csvreadert1(file_names[i])
Fs = 1/(x[1]-x[0])
#UNFILTERED SIGNAL
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
#Plot of unfiltered signal
plt = windows1[i].addPlot(row=1, col=1,
title = ’ECG unfiltered’)
plt.plot(x,y, pen=color)
11
f, amp = espectro(y, Fs)
plt.plot(f,amp,pen=color)
#FILTERED SIGNAL
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
#DERIVATIVE OF SIGNAL
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
#MOVING AVERAGE
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
t = picos(m, 0.75)
12
p = [m[i] for i in t]
t = [i/Fs for i in t]
plt.plot(t,p, pen=None, symbol=’o’)
#QRS IDENTIFICATION
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
print(’\n\n\nTompkins de ’+file_names[i])
print(’Sensibilidad: ’+str(round(vp/(vp+fn),3)))
print(’Especificidad: ’+str(round(vn/(vn+fp),3)))
print(’Precisión: ’+str(round((vp+vn)/(vn+vp+fn+fp),3)))
p = [y[i] for i in t]
t = [i/Fs for i in t]
plt.plot(t,p, pen=None, symbol=’o’)
13
#UNFILTERED SIGNAL
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
#Plot of unfiltered signal
plt = windows2[i].addPlot(row=1, col=1,
title = ’ECG unfiltered’)
plt.plot(x,y, pen=color)
#DERIVATIVE OF SIGNAL
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
#MOVING AVERAGE
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
t = picos(m, 0.5*max(m))
p = [m[i] for i in t]
t = [i/Fs for i in t]
plt.plot(t,p, pen=None, symbol=’o’)
14
#Plot of spectrum of moving average of signal
plt = windows2[i].addPlot(row=3, col=2,
title= ’Spectrum of moving average of ECG’)
f, amp = espectro(m, Fs)
plt.plot(f,amp,pen=color)
#QRS IDENTIFICATION
color = pg.mkPen(random.randint(0,255), random.randint(0,255),
random.randint(0,255))
p = [y[i] for i in t]
t = [i/Fs for i in t]
plt.plot(t,p, pen=None, symbol=’o’)
del i
15
pg.QtGui.QApplication.instance().exec_()
16