Você está na página 1de 20

UFRJ. Gómez.

Redes Neurais

DETECÇÃO E CLASSIFICAÇÃO DE ARRITMIAS DE BLOQUEIO DE RAMO


EM ECG
Johana Gómez Ceballos,
Universidade Federal de Rio de Janeiro (UFRJ), Mestrado em Engenharia Biomédica, Brasil,
Professores: Flavio Fonseca Nobre, Diogo Antonio Tschoeke.

RESUMO— É apresentado um método para classificar arritmias ventrículo direito é retardada em relação ao esquerdo, de modo
ventriculares do tipo bloqueio de ramo esquerdo (L) e direito (R) em que o complexo QRS é estendido e a derivação precordial direita
relação aos batimentos normais (N) do banco de dados de arritmia do produz uma morfologia rsR '(V1 e V2).
MIT-BIH-FACIL.
Para sua detecção, o sinal do eletrocardiograma (ECG) é analisado
Este trabalho propõe um método para classificar arritmias tipo
para obter características que podem identificar padrões normais e
anormais. Este artigo apresenta o progresso do processamento do
L e tipo R de batimentos normais de acordo com o banco de dados
sinal de ECG e o modelo de classificação de anormalidades cardíacas. de arritmia MIT-BIH-FACIL.
Para isso, foi desenvolvida uma etapa de extração de
PALAVRAS CHAVE— LBBB, RBBB, classificação, arritmias, características com base nas características morfológicas do
ECG. complexo QRS utilizando também os intervalos RR.

ABSTRACT— A method is presented to classify left (L) and right (R) Objetivo
ventricular arrhythmias in relation to the normal beats (N) of the
MIT-BIH-FACIL arrhythmia database. Classificar batimentos cardíacos em 3 possíveis classes:
For its detection, the electrocardiogram (ECG) signal is analyzed to Batimento normal (N), Bloqueio de ramo direito (RBBB) e
obtain characteristics that can identify normal and abnormal Bloqueio de ramo esquerdo (LBBB).
patterns. This article presents the progress of ECG signal processing
and the classification model of cardiac abnormalities. II. MATERIALES Y MÉTODOS
KEYWORDS— LBBB, RBBB, classification, arrhythmias, ECG.
Os métodos propostos neste trabalho compreendem as
seguintes etapas:
I. INTRODUÇÃO

O diagnóstico, o acompanhamento do tratamento e o


prognóstico das doenças cardiovasculares são geralmente
baseados em um teste rápido e confiável denominado
eletrocardiograma (ECG). Tradicionalmente, um
eletrocardiograma é um registro gráfico da atividade elétrica do
coração e fornece uma grande quantidade de informações que
podem ser armazenadas, transmitidas e processadas de várias
maneiras.

Bloqueio de ramo (BBB) é um distúrbio na condução do


impulso elétrico nos ventrículos [1]. Isso reduz a velocidade de
condução, portanto, se o bloqueio ocorrer em qualquer um dos
ramos, ocorre um prolongamento do complexo QRS, pois ele dura
enquanto a despolarização se espalha pelos ventrículos [2].
Os bloqueios de ramos também causam alterações morfológicas
no complexo QRS.

No bloqueio de ramo esquerdo (LBBB), a difusão da


despolarização do coração pelo ventrículo direito é muito mais
rápida do que a difusão pelo ventrículo esquerdo. Portanto, o
ventrículo esquerdo permanece polarizado por mais tempo que
o ventrículo direito. Isso se reflete no alongamento e nas Figura 1. Diagrama de blocos do método proposto.
alterações morfológicas (RR ') do complexo QRS nas
derivações precordiais esquerdas (V5 e V6). Por outro lado, no
bloqueio de ramo direito (RBBB), a condução do impulso pelo
1
UFRJ. Gómez. Redes Neurais

A. Dados
Neste trabalho foi utilizado o banco de dados de Arritmia
MIT-BIH-FACIL (MARK e MOODY, 1997), que contém
gravações de sinais de 48 participantes de duas derivações de
ECG com duração de 30 minutos cada. Os arquivos foram salvos
em formato .wav e contém os sinais com frequência de
amostragem de 360 Hz e uma resolução de 12 bits.

B. Pré-processamento
No pré-processamento do sinal, um filtro passa-baixa de
segunda ordem com uma frequência de corte de 20 Hz é usado
para atenuar o ruído de alta frequência no sinal. Além disso, dois
filtros de média móvel são usados para eliminar a linha de base,
ou o primeiro filtro com uma janela de 200 ms para remover o
QRS complexo na onda P e o segundo filtro com uma janela de
600 ms para remover as ondas T.

Figura-3. Um batimento tipo LBBB paciente 118.


(3)

O sinal foi obtido após passar pelo filtro passa-baixos e pelos


filtros de média móvel.

C. Extração de características
A extração do complexo QRS foi realizada a partir da
posição das anotações feitas no pico R de cada batimento no banco
de dados do MIT. Considerando a largura do complexo QRS.

Figura 4. Um batimento tipo normal paciente 212.

Os batimentos foram classificados usando a seguinte


sequência:
1. Extração de 6 características de tipo contínuo de cada
ECG que são valores de intervalos da onda R
normalizados antes e depois de cada batimento.
2. Extração de 2 características morfológicas de cada
batimento em cada derivação usando a transformada
Wavelet discreta.
3. Para não haver efeito de fibrilação e outras ocorrências
nos intervalos RR obtidos, o intervalo RR foi obtido
antes e após cada batimento.
4. Os intervalos foram normalizados pela média dos dois
Figura 2. Um batimento tipo RBBB paciente 207. intervalos em cada participante.
5. As características morfológicas foram obtidas por meio
de Wavelet discreto de 4ª escala do tipo Derivativo
Gaussiano de 1ª ordem.
6. Foi calculada a auto correlação dos sinais após a
Wavelet, para obter as posições do primeiro cruzamento
em zero e também a posição do ponto de valor mínimo.
Dessa forma, foram obtidas as 6 características
utilizadas para classificação.

2
UFRJ. Gómez. Redes Neurais

Variável Descrição
RRant Intervalo RR anterior ao
batimento
RRpost Intervalo RR posterior ao
batimento
Cross1 Primeiro cruzamento de 0
da derivação 1 na função
de auto correlação da 4a
escala da transformada de
wavelets discreta
Cross2 Primeiro cruzamento de 0
da derivação 2 na função
de auto correlação da 4a
escala da transformada de Figura 5- Analise dos valores ausentes.
wavelets discreta
Mind1 Posição do valor máximo As estatísticas descritivas mais comuns são obtidas, como
da derivação 1 na função mínimo, primeiro quartil, média, mediana, terceiro quartil e
de auto correlação da 4a máximo, mas também o número de zeros, valores negativos e até
escala da transformada de mesmo o número de outliers potenciais para cada variável numérica
wavelets discreta
Mind2 Posição do valor máximo
da derivação 2 na função
de auto correlação da 4a
escala da transformada de
wavelets discreta
Tabela 1 - Características extraídas dos sinais de ECG
.
Tipo Quantidade de amostras
Normal 3159
LBBB 5998
RBBB 8068
Total 17,225
Tabela 2 - Distribuição das amostras em cada tipo.

D. Análise Exploratória dos Dados


Figura 6- Analise estatística descritiva dos batimentos.
Após o tratamento dos sinais e extração de características,
os dados obtidos foram analisados na linguagem de Cálculo da média de cada variável com outliers, sem outliers e
programação R. a média dos próprios outliers.

Os dados brutos devem ser diagnosticados para problemas


existentes, explorados para novas hipóteses e reparados a fim
de aumentar a qualidade e a produção dos dados. O pacote
{dlookr} torna essas etapas rápidas.

Diagnóstico geral

Análise de qual variável tem valores ausentes e quantos. Este


procedimento permite ver quantos valores únicos temos em cada
variável, o que é particularmente útil para variáveis categóricas,
por exemplo, podemos ver imediatamente se alguns dos valores
foram digitados incorretamente e agora estão em múltiplos em vez
de uma única categoria. Figura 7- Análise das variáveis em relação aos outliers.

3
UFRJ. Gómez. Redes Neurais

4
UFRJ. Gómez. Redes Neurais

saber, a transformação logarítmica e a raiz quadrada, caso a


suposição de normalidade não seja atendida.

Figura 8 – Analise sobre influência dos outliers na


distribuição das variáveis.
Para as varáveis acima, a remoção dos seus outliers
traria benefícios quanto suas distribuições, trazendo uma
distribuição mais próxima de uma normal. Figura 10- Teste de normalidade no tipo.
Correlação
Exploração de dados A relação entre as variáveis numéricas é estimada, a forma
de cada subparcela mostra a força da correlação, enquanto a cor
Estatísticas descritivas mostra a direção, onde o azul é positivo e o vermelho é
Estatísticas descritivas de todas as variáveis numéricas negativo.
entre elas são a média, desvio padrão, erro padrão, intervalo O intervalo RR anterior apresenta correlação mais alta com
interquartil, viés e muitos quantis. as características morfológicas do que o intervalo RR posterior,
Teste de normalidade o que se justifica pelo fato de que os batimentos anormais
Um teste de normalidade Shapiro-Wilk é realizado em possuem um intervalo RR anterior encurtado. Já as
todas as variáveis numéricas ao mesmo tempo. Além disso, características morfológicas apresentam alta correlação já que
com a função plot_normality () exibe a normalidade dos dados são extraídas de duas derivações do mesmo sinal
numéricos e mais duas transformações de dados comuns, a

Figura 9- Teste de normalidade no paciente.

Figura 11- Matriz de correlação de banco de dados.

Esse tratamento de dados tem forte potencial para trazer


benefícios para o resultado do modelo.

5
UFRJ. Gómez. Redes Neurais

E. Classificação dos batimentos III. RESULTADOS


Resultados de cada modelo
Para classificar os batimentos cardíacos do banco de
dados em uma das três classes possíveis (N, LBBB e RBBB), dois Cada modelo foi treinado e testado. Para avaliar os resultados
tipos de classificadores são aplicados. O primeiro deles foi o de cada um, foram obtidas as matrizes de confusão e também
Classificador MLP, que é uma rede neural com uma única camada, calculadas as métricas de acurácia e PPV, sensibilidade e medida-
é um classificador linear, ou seja, vai separar as classes por meio F. O primeiro classificador testado foi o SVM e seus resultados
de hiperplanos. O segundo classificador SVM é outro tipo de estão dispostos na Figura 12 e na Figura 13.
classificadores que pode separar classes não linearmente
separáveis são o SVM. Com este classificador, uma hipersuperfície
não linear não é obtida, mas o espaço de caracteristicas é
transformado em um espaço com mais dimensões, de modo que as
características são linearmente separáveis.

Todos os modelos foram implementados em python. Antes


da aplicação dos classificadores, os dados foram normalizados
para que cada preditor tivesse média 0 e variância 1. Após isso foi
implementado o primeiro classificador SVM.

Os dados são divididos em conjuntos de treinamento e teste Figura 12 - Matriz de Confusão obtida no teste do
e, em seguida, ou SVM foi treinado. Ou o Scikit-Learn contém a modelo SVM
biblioteca svm, que contém classes integradas para diferentes
algoritmos SVM. Como a intenção era realizar uma classificação,
foi utilizada uma classe classificadora de vetores de suporte, escrita
como SVC na biblioteca svm do Scikit-Learn. Essa classe recebe
um parâmetro, que é o tipo de kernel. Isto é muito importante.
Neste caso de SVMs simples, esse parâmetro foi definido
simplesmente como “linear”, uma vez que SVMs simples só
podem classificar os dados de forma separada e linear.

O método (fit) de ajuste da classe SVC é chamado para treinar Figura 13 - Métricas calculadas no teste do modelo SVM
o algoritmo nos dados de treinamento, que são passados como
parâmetro para o método de ajuste (fit).
O segundo classificador treinado e testado foi o
Depois o segundo classificador MLP foi implementado MLP e seus resultados estão dispostos na Figura 14 e na Figura
usando o pacote Scikit -Learn, MLPRegressor é implementado no 15.
módulo neural_network. Os outros módulos foram importados
como "train_test_split" para dividir o conjunto de dados em
treinamento e conjunto de teste para testar o modelo e
"StandardScaler" para dimensionar os dados, uma vez que
características diferentes (variáveis independentes) têm um valor
grande, era muito importante dimensionar os dados usados para
treinar o modelo. Além disso, foi necessário definir uma função de
ativação para os neurônios é a função sigmóide (logística ).

 Número de camadas da rede (neste caso, são 3)


 Número de neurônios em cada rede (2 entradas, 2 na Figura 14 - Matriz de Confusão obtida no teste do modelo
camada oculta e 1 saída) MLP

Após a construção dos modelos, para cumprir o objetivo de


compará-los, a acurácia é considerada como uma métrica e uma
matriz de confusão foi implementada em cada um dos modelos.

Figura 15 - Métricas calculadas no teste do modelo MLP

6
UFRJ. Gómez. Redes Neurais

Figura 17 - Matriz de Confusão obtida no teste do modelo


SVM

IV. CONCLUSÃO

O classificador MLP atinge uma boa porcentagem de sucesso


no reconhecimento e também é muito rápido. No entanto, o
processo de treinamento pode ser muito lento, especialmente
quando os conjuntos de treinamento são muito grandes, também é
muito importante ter dados equilibrados.

O classificador SVM tem uma taxa de acerto ligeiramente


maior do que o classificador MLP e o processo de treinamento é
mais rápido, especialmente para grandes conjuntos de treinamento.
Figura 16 - Matriz de Confusão obtida no teste do modelo No entanto, o processo de classificação é mais lento (levou cerca
MLP de 25 minutos) do que em um classificador MLP e requer muito
mais memória.

Com base na acurácia, inicialmente foi obtida uma acurácia


menor no MLP, mas foi devido ao fato dos dados estarem
desbalanceados, também como o número de neurônios foi
aumentado, melhorou consideravelmente, finalmente obtendo uma
acurácia igual à do SVM.
V. REFERÊNCIAS
[1] E. Braunwald, Tratado de cadiología, Mc. Graw Hill, Vol.
1, cuarta edición, Chp. 24., 1993
[2]A. Guyton, J. E. Hall, Tratado de fisiología médica, Mc.
Graw Hill Interamericana, décima edición, Page. 154, 2000.
[3] R. Mark e G. Moody. “MIT-BIH Arrhythmia
Database”,1997, http://ecg.mit.edu/dbinfo.html.

7
UFRJ. Gómez. Redes Neurais

ANEXOS

8
UFRJ. Gómez. Redes Neurais

ANEXO 1
Código elaborado em python para a implementação dos modelos (SVM e MLP)
In [2]: # Import libraries
#Johana Gómez Ceballos
#SVM #MLP
import pandas
import joblib
import pandas as pd # for data manipulation import
numpy as np
import matplotlib.pyplot as plt
import sklearn.model_selection
import sklearn.metrics import
sklearn.neural_network
from sklearn.model_selection import train_test_split # for splitting the data into trai
from sklearn.metrics import plot_confusion_matrix
from sklearn.metrics import classification_report,confusion_matrix

In [3]: # Read in the csv


#Lê o banco de dados com todas as características
df=pd.read_csv('C:/Users/Usuario/Desktop/MIT-BIH-FACIL/Sinais
filtrados/Banco_Dados.csv X= df.drop(['Paciente','Tipo','Posicao'],axis=1)
Y = df['Tipo']

Após a separação, os dados passaram por uma normalização a fim de retirar a média e fazer com
que a variância dos dados seja unitária:

In [4]: from sklearn.preprocessing import StandardScaler scaler


= StandardScaler()
scaler.fit(df.drop(['Paciente','Tipo','Posicao'],axis=1))

Out[4]: StandardScaler()
In [5]: scaled_X = scaler.transform(df.drop(['Paciente','Tipo','Posicao'],axis=1))
s_X = pd.DataFrame(scaled_X,columns=X.columns) s_X

Out[5]: RR_Anterior RR_Posterior Cross_Zero_Der1 CrossZero_Der2 Min_Der1 Min_Der2

0 -0.271054 -0.053959 -1.129052 -1.126766 -1.216024 -1.212791

1 -0.282605 -0.208102 -1.511136 -1.126766 -1.425972 -1.212791

2 -0.375016 -0.188834 -1.129052 -1.126766 -1.216024 -1.212791

3 -0.363465 -0.208102 -1.511136 -1.554486 -1.425972 -1.447218

4 -0.375016 -0.015424 -1.511136 -1.554486 -1.425972 -1.447218

... ... ... ... ... ... ...

9
UFRJ. Gómez. Redes Neurais

6660 0.909817 -1.781908 -1.129052 0.156392 -1.006077 1.600325

6661 6.480691 2.977584 -0.746969 0.156392 -1.006077 1.131472

6662 1.534842 -1.887675 -0.746969 0.156392 -1.006077 1.600325

6663 2.150809 -1.887675 -1.129052 0.156392 -1.216024 2.069177

6664 1.933409 -1.872565 -1.129052 0.156392 -1.006077 1.834751

6665 rows × 6 columns

Quantidade de batimentos de cada tipo


1 -> Batimento normal

2 -> LBBB

3 -> RBBB

SVM
In [6]: #Divide the data as Train/ Test dataset

X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3,


random_state=4

In [7]: #Import svm model from


sklearn import svm

#Create a svm Classifier


classif = svm.SVC(kernel='linear') # Linear Kernel

#Train the model using the training sets classif.fit(X_train,


Y_train)

#Predict the response for test dataset


Y_pred = classif.predict(X_test) Y_pred

Out[7]: array([1, 2, 1, ..., 2, 2, 1], dtype=int64)

In [8]: #Import scikit-learn metrics module for accuracy


calculation from sklearn import metrics

# Model Accuracy: how often is the classifier correct?


print("Accuracy:",metrics.accuracy_score(Y_test, Y_pred))

Accuracy: 0.999
10
UFRJ. Gómez. Redes Neurais

In [9]: aux = classification_report(Y_test,Y_pred,target_names=['Normal','LBBB','RBBB'],digits=

classRep = ' VPP Sensibilidade Medida-F N\n\n Norm


classRep = classRep + '{:.4f} {}\n LBBB {:.4f} {:.4f}
classRep = classRep + '{:.4f} {:.4f} {:.4f} {}\n\n Acurácia
classRep = classRep + ' {}' classRep =
classRep.format(aux['Normal']['precision'],
aux['Normal']['recall'],aux['Normal']['f1-score'],aux['Normal']['support'],aux
aux['LBBB']['recall'],aux['LBBB']['f1-score'],aux['LBBB']['support'],aux['RBBB
aux['RBBB']['f1-score'],aux['RBBB']['support'],aux['accuracy'],aux['macro avg'
print(classRep)

VPP Sensibilidade Medida-F N

Normal 0.9985 0.9985 0.9985 687


LBBB 1.0000 0.9991 0.9996 1156
RBBB 0.9937 1.0000 0.9968 157

Acurácia 0.9990 2000

In [12]: con_mat = confusion_matrix(Y_test,Y_pred)

conMat = ' Classes Preditas\n\n N


conMat = conMat + ' Normal {} {} {}\nVerdadeiras LBBB
conMat = conMat + 'RBBB {} {} {}'
conMat = conMat.format(con_mat[0,0],con_mat[0,1],con_mat[0,2],con_mat[1,0],con_mat[1,1]
con_mat[2,1],con_mat[2,2])
print(conMat)

Classes Preditas

Normal LBBB RBBB

Classes Normal 686 0 1


Verdadeiras LBBB 1 1155 0
RBBB 0 0 157

In [11]: class_names = [1,2,3]


titles_options = [("Confusion matrix, without normalization", None),
("Normalized confusion matrix", 'true')] for
title, normalize in titles_options:
disp = plot_confusion_matrix(classif, X_test, Y_test,
display_labels=class_names,
cmap=plt.cm.Oranges, normalize=normalize)
disp.ax_.set_title(title)

print(title)
print(disp.confusion_matrix)

Confusion matrix, without normalization


[[ 686 0 1]
[ 1 1155 0]
[ 0 0 157]]
Normalized confusion matrix
[[9.98544396e-01 0.00000000e+00 1.45560408e-03]

11
UFRJ. Gómez. Redes Neurais

[8.65051903e-04 9.99134948e-01 0.00000000e+00]


[0.00000000e+00 0.00000000e+00 1.00000000e+00]]

MLP
In [43]: from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import
train_test_split from sklearn.metrics import
accuracy_score from sklearn.metrics import
confusion_matrix

In [66]: # Fit the model and display results


X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=4
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

from sklearn.neural_network import MLPClassifier

12
UFRJ. Gómez. Redes Neurais

clf= MLPClassifier(hidden_layer_sizes=(2,4,1), activation='logistic', solver='adam', ma


clf.fit(X_train,Y_train)

Out[66]: MLPClassifier(activation='logistic', hidden_layer_sizes=(2, 4, 1),


max_iter=50000)

In [67]: clf.fit(X_train, Y_train)


Y_pred = clf.predict(X_test)

In [68]: accuracy_score(Y_test, Y_pred)


Out[68]: 0.999
In [72]: aux = classification_report(Y_test,Y_pred,target_names=['Normal','LBBB','RBBB'],digits=

classRep = ' VPP Sensibilidade Medida-F N\n\n Norm


classRep = classRep + '{:.4f} {}\n LBBB {:.4f} {:.4f}
classRep = classRep + '{:.4f} {:.4f} {:.4f} {}\n\n Acurácia
classRep = classRep + ' {}' classRep =
classRep.format(aux['Normal']['precision'],
aux['Normal']['recall'],aux['Normal']['f1-
score'],aux['Normal']['support'],aux aux['LBBB']['recall'],aux['LBBB']['f1-
score'],aux['LBBB']['support'],aux['RBBB aux['RBBB']['f1-
score'],aux['RBBB']['support'],aux['accuracy'],aux['macro avg'

print(classRep
)

VPP Sensibilidade Medida-F N

Normal 1.0000 0.9985 0.9993 687


LBBB 0.9983 1.0000 0.9991 1156
RBBB 1.0000 0.9936 0.9968 157

Acurácia 0.9990 2000

In [69]: cm = confusion_matrix(Y_test, Y_pred) cm

Out[69]: array([[ 686, 1, 0],


[ 0, 1156, 0],
[ 0, 1, 156]], dtype=int64)

In [70]: con_mat = confusion_matrix(Y_test,Y_pred)

conMat = ' Classes Preditas\n\n N


conMat = conMat + ' Normal {} {} {}\nVerdadeiras LBBB
conMat = conMat + 'RBBB {} {} {}'
conMat = conMat.format(con_mat[0,0],con_mat[0,1],con_mat[0,2],con_mat[1,0],con_mat[1,1]
con_mat[2,1],con_mat[2,2])
print(conMat)

Classes Preditas

Normal LBBB RBBB

Classes Normal 686 1 0


Verdadeiras LBBB 0 1156 0

13
UFRJ. Gómez. Redes Neurais

RBBB 0 1 156

In [71]: class_names = [1,2,3]


titles_options = [("Confusion matrix, without normalization", None),
("Normalized confusion matrix", 'true')] for
title, normalize in titles_options:
disp = plot_confusion_matrix(clf, X_test, Y_test,
display_labels=class_names,
cmap=plt.cm.Greens, normalize=normalize)
disp.ax_.set_title(title)

print(title)
print(disp.confusion_matrix)

Confusion matrix, without normalization


[[ 686 1 0]
[ 0 1156 0]
[ 0 1 156]]
Normalized confusion matrix
[[0.9985444 0.0014556 0. ]
[0. 1. 0. ]
[0. 0.00636943 0.99363057]]

14
UFRJ. Gómez. Redes Neurais

In [92]: print('Accuracy: %.2f' % accuracy_score(Y_test, Y_pred)) print('Accuracy:


%.5f' % accuracy_score(Y_test, Y_pred))

Accuracy: 0.92
Accuracy: 0.92100

In [ ]:

15
UFRJ. Gómez. Redes Neurais

ANEXO 2
Código elaborado em MATLAB para o pré-processamento dos sinais de ECG

clear all close all


clc

addpath C:\Users\Usuario\Desktop\MIT-BIH-FACIL %
Identificação dos pacientes analisados
Paciente = [100 109 207 232 ];

for i = 1:length(Paciente) %
Leitura do sinal
% y é é uma matriz com duas coluna contendo os dois canais de
ECG
% fs é a frequência de amostragem
Sinal_Paciente = sprintf('%s\\%d.wav','sinais',Paciente(i));
[y,fs] = audioread(Sinal_Paciente,'native');

% Converter escala do sinal para mV

y_mV = double(y-1024)/200;

Der1 = y_mV(:,1); % Derivação 1


Der2 = y_mV(:,2); % Derivação 2

% Leitura das anotações

Anot_Paciente = sprintf('%s\\%d.ant','anotações_mod',Paciente(i));

fid = fopen(Anot_Paciente,'r');

A = fscanf(fid,'%d',[2,inf])'; % Lê o arquivo de anotações

fclose(fid);

% Filtra a matriz de anotações deixando apenas as anotações


% correspondentes a complexos QRS e transforma em tabela
AnotF = filtraqrs(A);
Anot = array2table(AnotF, 'VariableNames',{'Tipo', 'Posicao'}); %
Transforma a matriz em tabela

Sinal_csv = sprintf('Sinais filtrados\\Anot_ %d.csv',Paciente(i)); %


Formata o local e nome do arquivo writetable(Anot,Sinal_csv); % Escreve
a tabela em um arquivo .csv no formato definido

% Filtro passa-baixas

b = [1 0 0 0 0 0 -2 0 0 0 0 0 1];

a = [36 -72 36];

16
UFRJ. Gómez. Redes Neurais

Der1 = filter(b,a,Der1);
Der2 = filter(b,a,Der2);

% Definição dos tamanhos das janelas para os filtros de mediana móvel


if mod(round(fs*0.2),2) == 0
Janela1 = round(fs*0.2) - 1;

else
Janela1 = round(fs*0.2); end
if mod(round(fs*0.6),2) == 0
Janela2 = round(fs*0.6) - 1; else
Janela2 = round(fs*0.6); end

% Filtros de mediana móvel

aux1 = medfilt1(Der1,Janela1);

aux1 = medfilt1(aux1,Janela2);

Der1 = Der1 - aux1;

aux2 = medfilt1(Der2,Janela1);

aux2 = medfilt1(aux2,Janela2);

Der2 = Der2 - aux2;

% Sinal filtrado em formato .csv


ECG = [Der1 Der2];
ECG = array2table(ECG, 'VariableNames',{'Der1' 'Der2'}); %
Transforma a matriz em tabela

ECG_csv = sprintf('Sinais filtrados\\%d.csv',Paciente(i)); % Formata o


local e nome do arquivo writetable(ECG,ECG_csv); % Escreve a tabela em
um arquivo .csv no formato definidoplt.figure(figsize=(16,10))

end

17
UFRJ. Gómez. Redes Neurais

ANEXO 3

Código elaborado em MATLAB para a extração de características dos sinais de ECG


clear all close all clc

addpath C:\Users\Usuario\Desktop\MIT-BIH-FACIL

Nome = [100 109 207 232];


Fs = 360; % Frequência de
amostragem
Features_Total = [];
for ii =
1:length(Nome)
Paciente = Nome(ii);
Anot_Paciente = sprintf('Sinais
filtrados\\Anot_%d.csv',Paciente);
Anot = importdata(Anot_Paciente);

% Cálculo da média dos intervalos RR

media_RR = 0;

cont = 0;

for jj = 2:(length(Anot.data)-1) media_RR = media_RR +


Anot.data(jj,2) - Anot.data(jj-1,2);

cont = cont + 1;

end

clear jj

media_RR = media_RR/cont;

media_RR = media_RR/Fs;

% Cálculo da quantidade de batimentos cont_B = 0;


for jj = 2:(length(Anot.data)-1) if (Anot.data(jj,1)
== 1) || (Anot.data(jj,1) == 2) || (Anot.data(jj,1) == 3)
cont_B = cont_B + 1; end end clear jj

% Inicialização de vetores
RR_ant = zeros(length(cont_B),1);
RR_post = zeros(length(cont_B),1);
Tipo_B = zeros(length(cont_B),1);
Posicao_B = zeros(length(cont_B),1);
list_Paciente = zeros(length(cont_B),1);

for jj = 1:(cont_B) list_Paciente =


[list_Paciente; Paciente]; end clear jj
% Cálculo dos intervalos RR normalizados

pos = 1;

for jj = 2:(length(Anot.data)-1)
18
UFRJ. Gómez. Redes Neurais

if ((Anot.data(jj,1) == 1) || (Anot.data(jj,1) == 2) ||
(Anot.data(jj,1) == 3)) pos = pos + 1;

Tipo_B(pos,1) = Anot.data(jj,1);
Posicao_B(pos,1) = Anot.data(jj,2);
RR_ant(pos,1) = (Anot.data(jj,2)-Anot.data(jj-1,2))/Fs;
RR_ant(pos,1) = RR_ant(pos,1)/media_RR;
RR_post(pos,1) = (Anot.data(jj+1,2)-
Anot.data(jj,2))/Fs; RR_post(pos,1) =
RR_post(pos,1)/media_RR;

end

end

clear jj

Features = [list_Paciente Tipo_B Posicao_B RR_ant RR_post];

% Eliminação dos dados


faltantes for jj =
1:(length(Features)-1) if
Features(jj,4) == 0
Features(jj,:) = []; end
end clear jj

% Sinal de cada paciente


Sinal_Paciente = sprintf('Sinais filtrados\\%d.csv',Paciente)
ECG = importdata(Sinal_Paciente);
Der1 = ECG.data(:,1);
Der2 = ECG.data(:,2);

% Extração das características morfológicas


CZero_der1 = zeros(length(Features),1);
CZero_der2 = zeros(length(Features),1);
Min_der1 = zeros(length(Features),1);
Min_der2 = zeros(length(Features),1);

aux = 1; for jj = 1:(length(Features)) % Cálculo


da janela wavelet com 130 ms antes do batimento até 200 ms depois
pos = Features(jj,3); inicio = floor(pos - 0.13*Fs);
fim = ceil(pos + 0.2*Fs);

% Seleciona o sinal do batimento


Sinal_1 = Der1((inicio+1):fim);
Sinal_2 = Der2((inicio+1):fim);

% Transformada wavelet Gaussiana derivativa


Escala = 1:4;
Sinal_W1 = cwt(Sinal_1,Escala,'gaus1');
Sinal_W2 = cwt(Sinal_2,Escala,'gaus1');

% Autocorrelação da escala 4 do sinal


Wave_1 = xcorr(Sinal_W1(4,:),Sinal_W1(4,:));
Wave_1 = Wave_1((floor(numel(Wave_1)/2)+1):end);
Wave_2 = xcorr(Sinal_W2(4,:),Sinal_W2(4,:));
Wave_2 = Wave_2((floor(numel(Wave_2)/2)+1):end);

19
UFRJ. Gómez. Redes Neurais

% Encontra os cruzamentos em zero


Zero_crossings_1 = find(diff(sign(Wave_1)));
Zero_crossings_2 = find(diff(sign(Wave_2)));

% Extração das características morfológicas do sinal


if (length(Zero_crossings_1) > 0) && (length(Zero_crossings_2) >
0)
CZero_der1(aux,1) = Zero_crossings_1(1);
CZero_der2(aux,1) = Zero_crossings_2(1);
[Min_Der1,Ind_Der1] = min(Wave_1);
Min_der1(aux,1) = Ind_Der1;
[Min_Der2,Ind_Der2] =
min(Wave_2); Min_der2(aux,1) =
Ind_Der2; else
CZero_der1(aux,1) = NaN;
CZero_der2(aux,1) = NaN;
Min_der1(aux,1) = NaN;

Min_der2(aux,1) = NaN;

end

aux = aux + 1;

end

clear jj

Features1 = [CZero_der1 CZero_der2 Min_der1


Min_der2];

% Eliminação dos dados


faltantes

for jj = 1:(length(Features1)-1)

if Features1(jj,:) == NaN
Features1(jj,:) = [];

end

end clear jj

% Matriz com as características encontradas

Features_Total = [Features_Total; Features Features1];


end

% Transformação da matriz de caracteristicas em tabela e escreve em .csv

FeaturesF = array2table(Features_Total, 'VariableNames', {'Paciente', 'Tipo',


'Posicao', 'RR_Anterior', 'RR_Posterior', 'Cross_Zero_Der1',
writetable(FeaturesF,'Sinais filtrados\\Banco_Dados.csv'); % Escreve a tabela
em um arquivo .csv no formato definido

20

Você também pode gostar