0% encontró este documento útil (0 votos)
2 vistas83 páginas

Análisis de Señales Biomédicas y Filtrado

El informe final del proyecto sobre procesamiento de señales biomédicas detalla el análisis de señales como ECG, presión sanguínea y sonidos de Korotkoff, abordando su acondicionamiento y filtrado para eliminar ruidos. Se presenta un análisis exhaustivo de las señales registradas y se aplican técnicas de procesamiento utilizando Matlab. El documento incluye un diagrama de Gantt, un historial de reuniones y conclusiones sobre los hallazgos del proyecto.

Cargado por

trichecilla
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)
2 vistas83 páginas

Análisis de Señales Biomédicas y Filtrado

El informe final del proyecto sobre procesamiento de señales biomédicas detalla el análisis de señales como ECG, presión sanguínea y sonidos de Korotkoff, abordando su acondicionamiento y filtrado para eliminar ruidos. Se presenta un análisis exhaustivo de las señales registradas y se aplican técnicas de procesamiento utilizando Matlab. El documento incluye un diagrama de Gantt, un historial de reuniones y conclusiones sobre los hallazgos del proyecto.

Cargado por

trichecilla
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

INFORME FINAL DE PROYECTO

PROCESAMIENTO DE SEÑALES BIOMÉDICAS

Beatriz Cuesta, Blanca Ferrer, Jan Llopis


Marta Mateos, Daiana Pereyra, Rossana Silletti
Grupo M15

1
ÍNDICE
DIAGRAMA DE GANTT 3
HISTORIAL DE REUNIONES 4
INTRODUCCIÓN 5
DESCRIPCIÓN DE LAS SEÑALES 6
Señal ECG 6
Señal de presión sanguínea 6
ANÁLISIS DE LAS SEÑALES PROPORCIONADAS EN LAS PRÁCTICAS 4 (COMPLETA) Y 6
(SEGUNDA PARTE) 8
SEÑAL ECG Y SEÑAL DE PRESIÓN SANGUÍNEA 8
SEÑAL DE PRESIÓN SANGUÍNEA Y SONIDOS DE KOROTKOFF 21
SEÑAL DE VOLUMEN SANGUÍNEO 32
ANÁLISIS FRECUENCIAL DE LOS SONIDOS DE KOROTKOFF 37
ANÁLISIS DE SEÑALES PROPORCIONADAS EN ATENEA 42
SEÑALES REGISTRADAS 42
RUIDO I/O INTERFERENCIAS 44
Dominio temporal 44
Dominio frecuencial 46
FILTRADO I ACONDICIONAMENTO DE LAS SEÑALES 49
Presión Sanguínea 49
Sonidos de Korotkoff 51
ECG 53
ANÁLISIS DE LAS SENYALS ECG, PRESIÓN SANGUÍNEA Y SONIDOS DE KOROTKOFF
53
ECG 53
Presión Sanguínea 55
Sonidos de Korotkoff 57
CONCLUSIONS 59
BIBLIOGRAFIA 60
ANNEX I. CODI DELS ALGORITMES AMB COMENTARIS 61

2
DIAGRAMA DE GANTT
A continuación se muestra el diagrama de Gantt que recoge la planificación llevada a cabo
para abordar el trabajo. Ha sido una herramienta de gran ayuda para organizarnos y seguir
los plazos del proyecto con tranquilidad. No se ha realizado ninguna modificación respecto
al documento entregado al inicio del proyecto, ya que la planificación planteada fue muy
realista y, aunque en algunas partes se ha producido algún pequeño retraso, estamos muy
satisfechos con la organización seguida.

Figura 1. Diagrama de Gantt

Donde:

Figura 2. Leyenda del diagrama de Gantt

3
HISTORIAL DE REUNIONES
Para la realización y coordinación del presente proyecto, el equipo de trabajo mantuvo una
comunicación constante y realizó el seguimiento de las tareas mediante diversas sesiones
virtuales. Todas las comunicaciones de coordinación se llevaron a cabo a través de la
plataforma Whatsapp y Google Meet.

A continuación, se detallan las fechas de los encuentros realizados:

Fecha Plataforma Programación y análisis Avance en el


documento escrito
6/11/2025 Forma presencial Asignación de roles del Definición preliminar
equipo del plan de trabajo

27/11/202 Forma presencial Coordinación de todas las Asignación de las


partes del proyecto diversas tareas
asignadas a cada
componente del
grupo sobre el informe
inicial y restantes del
informe final
Vía online con Verificación del inicio de Seguimiento y revisión
15/12/2025 Google meet los trabajos por cada de avances
componente

Vía online con Validación de los Descripción de los


02/01/2026 Google meet algoritmos de la parte de métodos y
señales correcciones de
errores
Vía online con Validación de los Descripción de los
08/01/2026 Google meet algoritmos de la parte de métodos y
sensores correcciones de
errores
Vía online con Vista del informe Ajuste final de
11/01/2026 Google meet completado parámetros y
comentarios
Vía online con Entrega en Atenea Última lectura y
15/01/2026 Google meet verificación del
documento

4
INTRODUCCIÓN
Las señales biomédicas son señales que permiten obtener información sobre el
funcionamiento del cuerpo humano, como por ejemplo la actividad cardíaca, la presión
sanguínea, la actividad muscular o la respiración. Este tipo de señales suelen tener una
amplitud muy pequeña, del orden de los milivoltios, y además están afectadas por diferentes
tipos de ruido e interferencias que dificultan su análisis, como el ruido de la red eléctrica, el
movimiento del paciente o imperfecciones en el sistema de adquisición.

Por este motivo, el análisis de señales biomédicas requiere un primer proceso de


acondicionamiento y filtrado, con el objetivo de eliminar el ruido y conservar únicamente la
información relevante de la señal. Una vez la señal ha sido correctamente filtrada, es posible
aplicar distintos métodos de procesado para extraer parámetros de interés y poder estudiar
su comportamiento de forma más clara.

Un ejemplo típico es el análisis de una señal electrocardiográfica (ECG), donde primero se


eliminan las interferencias y posteriormente se analizan elementos característicos como los
complejos QRS para evaluar el ritmo cardíaco.

Este proyecto se divide en dos partes principales.

En la primera parte se analizan varias señales biomédicas proporcionadas en las prácticas


de la asignatura, entre las que se incluyen un ECG, una señal de presión sanguínea, una
señal de volumen sanguíneo y los sonidos de Korotkoff. Para estas señales se realiza un
análisis tanto en el dominio temporal como en el frecuencial, con el fin de identificar las
principales componentes de la señal y las posibles fuentes de ruido.

En la segunda parte del proyecto se trabaja con señales registradas durante la asignatura de
Sensores y Acondicionadores de Señales Biomédicas, concretamente un ECG, un
electromiograma (EMG) y una señal respiratoria. En este caso, el análisis se centra
especialmente en la detección de ruido e interferencias y en la aplicación de técnicas de
filtrado y acondicionamiento adaptadas a señales reales.

Para llevar a cabo todo el procesado y análisis de las señales se ha utilizado el programa
Matlab, que permite trabajar de forma cómoda con señales biomédicas y aplicar
herramientas como la Transformada Rápida de Fourier (FFT), el uso de ventanas y el diseño
de filtros digitales.

5
DESCRIPCIÓN DE LAS SEÑALES
Señal ECG
La señal electrocardiográfica (ECG) representa la actividad eléctrica del corazón a lo largo
del tiempo y permite analizar el funcionamiento del sistema cardíaco. Se trata de una señal
de baja amplitud, del orden de los milivoltios, y de naturaleza periódica, asociada al ciclo
cardíaco.

Un latido cardíaco típico en la señal ECG consta de diferentes ondas características: la onda
P, asociada a la despolarización auricular; el complejo QRS, que corresponde a la
despolarización ventricular; y la onda T, relacionada con la repolarización ventricular. De
estos componentes, el complejo QRS presenta la mayor amplitud y pendiente, lo que facilita
su detección automática.

Debido a su baja amplitud, la señal ECG suele verse afectada por ruido e interferencias,
como el ruido de la red eléctrica, el movimiento del paciente o el ruido muscular. Por este
motivo, es necesario aplicar técnicas de filtrado antes de su análisis. A partir de la detección
de los complejos QRS, es posible obtener parámetros como la frecuencia cardíaca y
establecer relaciones temporales con otras señales biomédicas, como la presión arterial.

Señal de presión sanguínea


La señal obtenida al medir la presión arterial se divide en dos partes según su naturaleza: la
presión sistólica, asociada a la contracción del corazón para bombear la sangre, y la presión
diastólica, correspondiente al periodo de reposo entre latidos. Dado que el flujo de sangre
hacia los ventrículos no es continuo, la presión arterial presenta un carácter pulsátil: aumenta
durante la sístole ventricular y disminuye durante la diástole ventricular.

Figura 3. Medida de la presión arterial por catéter

El rango normal de la presión sistólica en un adulto en reposo se sitúa entre 100 y 139 mmHg,
mientras que el rango normal de la presión diastólica en un adulto en reposo se encuentra
entre 60 y 89 mmHg. No obstante, para evitar la pulsatilidad de la señal, la presión arterial
media (PAM) se calcula como (presioˊ n sistoˊ lica + 2 × presioˊ n diastoˊ lica)/3 , ya que esta
expresión tiene en cuenta una aproximación geométrica al calcular el valor medio.

6
En la práctica de laboratorio (4), esta medida no se realiza de forma directa, sino que se
obtiene a partir de la señal de ECG. El ritmo cardíaco se detecta a partir de la derivada del
ECG: cuando dicha derivada alcanza valores máximos, representa la pendiente máxima del
complejo QRS y, al superar un determinado umbral, se detecta cada latido cardíaco.

La onda T se extrae de un latido cardíaco representativo y, aplicando la correlación cruzada


con la señal ECG completa, se detectan los instantes correspondientes a sus valores
máximos, lo que permite medir el retardo existente entre la onda T y la presión sistólica.

Sonidos de Korotkoff
Los sonidos de Korotkoff fueron descritos por el cirujano
ruso Nikolái Serguéievich Korotkoff (1874–1920) a
comienzos del siglo XX. Este descubrimiento representó un
avance fundamental en la medicina clínica, ya que permitió
el desarrollo de un método no invasivo, fiable y reproducible
para la medición de la presión arterial. Gracias a su sencillez
y eficacia, este procedimiento continúa siendo el método
estándar utilizado en la práctica médica actual.

La técnica se basa en el empleo de un esfigmomanómetro y Figura 4: Representación de


un fonendoscopio. El manguito neumático se coloca medida de presión
alrededor del brazo del paciente, generalmente a la altura de
la arteria braquial, y se infla hasta alcanzar una presión superior a la presión arterial sistólica.
En esta situación, el flujo sanguíneo queda temporalmente interrumpido. A continuación, el
aire del manguito se libera de forma gradual y controlada, permitiendo la reaparición
progresiva del flujo sanguíneo. Durante este proceso, los sonidos producidos por la sangre
al atravesar la arteria parcialmente comprimida pueden auscultarse con el fonendoscopio.

El análisis de estos sonidos permite identificar distintas fases, conocidas como sonidos de
Korotkoff, que se interpretan de la siguiente manera:

• Primer sonido: corresponde a la aparición de ruidos claros y repetitivos, indicando el


momento en el que la presión del manguito iguala la presión arterial sistólica (PAS).
• Segundo sonido: se caracteriza por una disminución de la intensidad del ruido; esta
fase no posee relevancia clínica significativa.
• Tercer sonido: se perciben sonidos más suaves y amortiguados, que tampoco tienen
importancia clínica.
• Cuarto sonido: se produce la desaparición completa de los ruidos. El último sonido
audible se asocia con la presión arterial diastólica (PAD), que representa la presión
mínima en las arterias durante el ciclo cardíaco.

Este método auscultatorio permite obtener valores precisos de la presión arterial y sigue
siendo una herramienta esencial para el diagnóstico y seguimiento de numerosas patologías
cardiovasculares.

7
ANÁLISIS DE LAS SEÑALES
PROPORCIONADAS EN LAS PRÁCTICAS 4
(COMPLETA) Y 6 (SEGUNDA PARTE)
SEÑAL ECG Y SEÑAL DE PRESIÓN SANGUÍNEA
En este apartado analizaremos una señal ECG y una de presión sanguínea. La función
utilizada es la siguiente:

function marques = detecrc(senyal)

% DEFINICIONES
derSenyal = diff(senyal);
numMostres = length(derSenyal);
offset = 50;
llindar = .5*max(derSenyal(1:2500));
comptador = 0;
mostra = 400;

% BUCLE PRINCIPAL DE BUSQUEDA


continuar = true;
while continuar
if derSenyal(mostra) > llindar
buscar = true;
while buscar
if derSenyal(mostra) < 0
comptador = comptador + 1;
marques(comptador, 1) = mostra;
buscar = false;
llindar = mean([llindar
.5*max(derSenyal(mostra+offset:min([mostra+(2500) numMostres])))]);
mostra = mostra + offset;
if mostra >= numMostres
continuar = false;
end
else
mostra = mostra + 1;
if mostra >= numMostres
continuar = false;
end
end
end
else
mostra = mostra + 1;
if mostra >= numMostres
continuar = false;
end
end
end

% DIBUJAR LOS RESULTADOS


t = (1/250:1/250:numMostres/250)';
figure; box on; hold on;
plot(t, senyal(1:numMostres));
plot(t, derSenyal, 'r');
axis tight;

8
plot([marques marques]'/250, repmat(get(gca, 'Ylim')', size(marques')),
'k--');
title('ECG')
xlabel('temps (s)')
hold off;
xlim([2 4]);
pan xon;

Aplicando la función detecrc sobre el ecg1 que se proporciona, obtenemos la figura


representada, donde la señal azul es el ECG original y la roja su derivada.

Figura 5: ECG, su derivada y marcas de complejo QRS

Seguidamente, se pide responder a las siguientes preguntas:

9
a) Cálculo del ritmo cardíaco en latidos/minuto a partir de la señal ECG

En primer lugar, se conoce que el registro electrocardiográfico tiene una duración


aproximada de 20 minutos y una frecuencia de muestreo de 250 Hz. Para calcular el ritmo
cardíaco del paciente en latidos por minuto, se utilizan las marcas correspondientes a las
ondas R obtenidas mediante la rutina detecrc.

A partir de dichas marcas, se calcula la diferencia entre marcas consecutivas, lo que permite
obtener el intervalo RR expresado en número de muestras. Estos intervalos se convierten a
tiempo dividiendo por la frecuencia de muestreo. El ritmo cardíaco se obtiene como el
inverso del intervalo RR multiplicado por 60, obteniendo así el ritmo cardíaco latido a latido
en pulsaciones por minuto. Finalmente, se calcula el valor medio del ritmo cardíaco durante
todo el registro.

marques = detecrc(ecg1);

fs = 250;
RR_mostres = diff(marques);
RR_segons = RR_mostres / fs;

ritmocardiaco = 60 ./ RR_segons;

>> mean(ritmocardiaco)

ans =

69.2330

Por tanto, el paciente llevaba un ritmo cardíaco medio de 69 pulsaciones/minuto durante el


registro.

b) Entre cada pareja de marcas consecutivas: la presión sistólica, la


diastólica, la presión arterial media i la presión de pulso.

En una señal de presión sanguínea la presión sistólica corresponde al valor máximo de


presión alcanzado durante cada ciclo cardíaco, mientras que la presión
diastólica corresponde al valor mínimo de dicha señal. Por tanto, para obtener estos
parámetros entre cada pareja de marcas consecutivas, es necesario analizar la señal de
presión sanguínea comprendida entre dos instantes consecutivos asociados a un mismo
latido.

Para ello, se utilizan las marcas obtenidas previamente a partir de la detección de los
complejos QRS del ECG. Estas marcas delimitan cada latido y permiten analizar la señal de
presión sanguínea de forma latido a latido.

10
Presión sistólica

Para cada intervalo comprendido entre dos marcas consecutivas, la presión sistólica se
obtiene como el valor máximo de la señal de presión sanguínea en dicho intervalo. Este
procedimiento se repite para todos los latidos del registro, obteniéndose así un vector con
los valores de presión sistólica latido a latido.

for i = 1:length(marques)-1
psis(i) = max(psan(marques(i):marques(i+1)));
end

figure;
plot(psis)
xlabel('Latido')
ylabel('Presión sistólica (mmHg)')
title('Presión sistólica durante el registro')

Aquí se muestra el resultado gráfico y la media de presión sistólica:

Figura 6: Presión sistólica durante la toma de presión

>> mean(psis)

ans =

124.9763

11
Presión diastólica

De forma análoga, la presión diastólica se obtiene como el valor mínimo de la señal de


presión sanguínea entre cada pareja de marcas consecutivas. Al igual que en el caso anterior,
se obtiene un valor por latido.

for i = 1:length(marques)-1
pdias(i) = min(psan(marques(i):marques(i+1)));
end

figure;
plot(pdias)
xlabel('Latido')
ylabel('Presión diastólica (mmHg)')
title('Presión diastólica durante el registro')

Figura 7: Presión diastólica durante muestra

El valor medio lo calculamos como:

mean(pdias)

ans =

67.3853

12
Presión de pulso

La presión de pulso se define como la diferencia entre la presión sistólica y la presión


diastólica para cada latido, según la expresión:
𝑃𝑃 = 𝑃sistoˊ lica − 𝑃diastoˊ lica
pp = psis - pdias;

figure;
plot(pp)
xlabel('Latido')
ylabel('Presión de pulso (mmHg)')
title('Presión de pulso durante el registro')

Figura 8: Presión de pulso durante el registro

El valor medio de la presión de pulso se obtiene mediante:

>> mean(pp)

ans =

57.5910

13
Presión arterial media (MAP)

Finalmente, se calcula la presión arterial media (MAP), la cual se puede expresar como:
𝑃𝑃 𝑃sistoˊ lica + 2 ⋅ 𝑃diastoˊ lica
𝑀𝐴𝑃 = + 𝑃diastoˊ lica =
3 3
Utilizando la expresión, se obtiene la MAP latido a latido:

MAP = pp/3 + pdias;

figure;
plot(MAP)
xlabel('Latido')
ylabel('Presión arterial media (mmHg)')
title('Presión arterial media durante el registro')

Figura 9: Presión arterial media durante el registro

El valor medio de la presión arterial media se calcula como:

mean(MAP)

ans =

86.5823

Por tanto, a partir del análisis latido a latido de la señal de presión sanguínea, se han obtenido
los valores de presión sistólica, presión diastólica, presión de pulso y presión arterial media,
cuyos valores medios se encuentran dentro de rangos compatibles con una presión arterial
normal en reposo. Cabe destacar que los valores normales de estos parámetros pueden
variar en función de la edad, el sexo y las condiciones fisiológicas del paciente.

14
c) El pulso cardíaco en pulsos por minuto obtenido de dos maneras
diferentes: a partir de los instantes en los que se alcanza la presión
sistólica y a partir de los instantes en los que se alcanza la presión
diastólica.

El pulso cardíaco puede calcularse también a partir de la señal de presión sanguínea,


considerando los instantes en los que se alcanza la presión sistólica y la presión diastólica.
Para ello, se definen dos vectores que contienen, respectivamente, las marcas
correspondientes a los máximos (presión sistólica) y a los mínimos (presión diastólica) de la
señal de presión.

A partir de estas marcas, se utiliza la función diff de Matlab para obtener la diferencia entre
marcas consecutivas, lo que proporciona el número de índices que hay entre un pulso y el
siguiente. Dado que estos índices no se han convertido a segundos, se puede calcular el
número total de pulsos producidos durante el registro dividiendo la longitud total de la señal
entre dicha diferencia. Finalmente, dividiendo este resultado entre la duración total del
registro (20 minutos), se obtiene el pulso cardíaco en pulsos por minuto.

for i = 1:length(marques)-1
[psis(i), idx_max(i)] = max(psan(marques(i):marques(i+1)));
marquessistole(i) = marques(i) + idx_max(i) - 1;

[pdias(i), idx_min(i)] = min(psan(marques(i):marques(i+1)));


marquesdiastole(i) = marques(i) + idx_min(i) - 1;
end

% Cálculo por presiones sistólicas


difsistole = diff(marquessistole);

pregsist = length(psan) ./ difsistole;


pminsist = pregsist ./ 20;

pulsossistole = mean(pminsist);
pulsossistole

% Cálculo por presiones diastólicas


difdiastole = diff(marquesdiastole);

pregdias = length(psan) ./ difdiastole;


pmindias = pregdias ./ 20;

pulsosdiastole = mean(pmindias);
pulsosdiastole

figure;
plot(pminsist)
hold on
plot(pmindias)
xlabel('Pulso')
ylabel('Pulsos por minuto')
title('Pulso cardíaco calculado a partir de presiones sistólicas y
diastólicas')
legend('Pulso por presión sistólica', 'Pulso por presión diastólica')

15
Figura 10: Pulso cardíaco calculado a partir de presiones sistólicas y diastólicas

>> apartadoc

pulsossistole =

69.5023

pulsosdiastole =

71.6919

d) El retardo existente entre la onda R y la presión sistólica.

En este apartado se calcula el retardo temporal existente entre la onda R del ECG y el
instante en el que se alcanza la presión sistólica en la señal de presión sanguínea. Este
retardo está asociado al tiempo que tarda la onda de presión generada por la contracción
ventricular en propagarse desde el corazón hasta el punto de medida de la presión.

Para su cálculo, basta con obtener la diferencia entre los índices correspondientes a las
marcas de las ondas R del ECG y las marcas de los máximos de la señal de presión
sanguínea (presiones sistólicas). Dicha diferencia se expresa inicialmente en número de
muestras y posteriormente se convierte a tiempo dividiendo por la frecuencia de muestreo
de la señal.

retardoindices = marquessistole - marques;


retardos = retardoindices ./ 250;

retardorsist = abs(mean(retardos(:)));
retardorsist

16
retardorsist =

0.1466

e) Aislar una onda T, realizar la correlación cruzada con el ECG para obtener
los valores máximos de la onda T y calcular el retardo entre la presión
sistólica y la onda T.

Para el cálculo del retardo entre la onda T del ECG y la presión sistólica, se emplea un
procedimiento basado en la correlación cruzada. En primer lugar, a partir de la
representación del ECG filtrado y de las marcas obtenidas mediante la rutina detecrc, se
selecciona de forma visual una onda T representativa del registro. En este caso, se ha
escogido la onda T comprendida entre los índices 𝑋 = 660 y 𝑋 = 708.

Una vez aislada la onda T en un vector, se utiliza la función xcorr de Matlab para realizar la
correlación cruzada entre la señal ECG completa y el vector correspondiente a la onda T.
Este proceso permite detectar automáticamente los instantes temporales en los que aparece
la onda T a lo largo de todo el registro, ya que la correlación alcanza valores máximos cuando
ambas señales presentan una alta similitud.

Posteriormente, se aplica nuevamente la rutina detecrc sobre la señal resultante de la


correlación para obtener los índices correspondientes a los máximos de la onda T.
Finalmente, el retardo entre la onda T y la presión sistólica se calcula como la diferencia entre
los índices de las marcas de la onda T y las marcas de presión sistólica, convirtiendo dicho
valor a segundos mediante la frecuencia de muestreo de la señal.

ondat = ecg1(660:708);

correlacion = xcorr(ondat, ecg1);

marcast = detecrc(correlacion);

retardot = marcast - marquessistole;


retardot = retardot ./ 250;

retardot_medio = abs(mean(retardot(:)));
retardot_medio

>> apartadoe

retardot_medio =

2.2840

17
Resultados

Si se superponen los gráficos de los tres métodos para obtener los latidos por minuto, se
observa la siguiente gráfica:

Figura 11: Señales de ritmo cardíaco superpuestas

En esta figura se muestran los latidos por minuto obtenidos a partir de tres métodos distintos:
ECG, presión sistólica y presión diastólica. Se observa que, durante la mayor parte del
registro, los tres métodos proporcionan valores muy similares, con un ritmo cardíaco medio
estable alrededor de 65–75 BPM, lo que indica una buena coherencia entre los distintos
procedimientos de cálculo.

No obstante, aparecen picos aislados de gran amplitud, especialmente en el ritmo obtenido


a partir de la presión diastólica y, puntualmente, en el de la presión sistólica. Estos picos
corresponden a outliers debidos a detecciones erróneas puntuales de las marcas, ya que no
se reproducen simultáneamente en los tres métodos ni presentan continuidad temporal, por
lo que no se asocian a un fenómeno fisiológico real.

18
Figura 12: Evolución de las diferentes presiones durante el registro

En esta figura se representa la evolución temporal de la presión sistólica, diastólica, de pulso


y arterial media a lo largo del registro. Se observa que todas las señales presentan una
variación suave y coherente, manteniéndose dentro de rangos fisiológicos razonables
durante todo el tiempo de medida.

La presión sistólica presenta los valores más elevados, seguida de la presión arterial media
y la presión diastólica, mientras que la presión de pulso refleja correctamente la diferencia
entre las presiones sistólica y diastólica. Se aprecia algún descenso puntual brusco,
atribuible a errores de detección o artefactos de la señal, que no alteran la tendencia global
del registro.

19
Figura 13: Retardo entre onda T y R vs. Presión sistólica

En esta figura se muestran los retardos temporales entre la onda R del ECG y la presión
sistólica, así como entre la onda T y dicha presión. Se observa que el retardo correspondiente
a la onda R presenta valores reducidos y relativamente constantes a lo largo del registro, lo
que concuerda con el corto intervalo temporal existente entre la despolarización ventricular
y la aparición del máximo de presión.

Por el contrario, el retardo asociado a la onda T es notablemente mayor y presenta una


variación más pronunciada, reflejando que la repolarización ventricular ocurre más tarde
dentro del ciclo cardíaco. Este comportamiento es coherente con la secuencia temporal de
los eventos eléctricos y mecánicos del corazón.

20
SEÑAL DE PRESIÓN SANGUÍNEA Y SONIDOS DE
KOROTKOFF
En esta sección vamos a analizar los sonidos de Korotkoff. En primer lugar, subimos el
archivo al Matlab [Link] proporcionado con señales de presión, sonidos Korotkoff y
ECG de un sujeto. La frecuencia de muestreo es de 500 Hz.

Inicialmente obtuvimos las señales proporcionadas, con quien trabajaremos más adelante:

Figura 14: Señales ECG, presión y sonidos de Korotkoff

Para comparar mejor visualmente los sonidos de Korotkoff con el electrocardiograma, hemos
superpuesto ambas señales de la siguiente manera:

Figura 15: Sonidos de Korotkoff superpuestos al ECG

21
Figura 16: Sonidos de Korotkoff superpuestos al ECG ampliado

Resulta interesante notar el retraso constante con el que el pico sonoro sigue al impulso
eléctrico: este intervalo representa el tiempo de tránsito de la onda de presión desde el
corazón hasta el punto de detección braquial. La ampliación permite apreciar la naturaleza
oscilatoria de cada latido individual capturado por el sensor.

Figura 17: Registro completo de sonidos de Korotkoff superpuestos al ECG

Esta imagen ofrece una perspectiva más amplia, documentando todo el procedimiento de
medición de la presión arterial: inicialmente, no se oyen sonidos; sin embargo, a medida que
la presión externa varía durante la prueba, las señales acústicas se vuelven progresivamente
más intensas y turbulentas, alcanzando su amplitud máxima alrededor del segundo 26. A
partir de este punto, la señal tiende a atenuarse hasta casi desaparecer por completo
alrededor del segundo 31, lo que indica el momento en que el flujo sanguíneo vuelve a ser
laminar y deja de ser audible para el sistema.

22
Por lo tanto, se requiere determinar la presión sistólica y la diastólica a partir del momento
en que los sonidos aparecen y desaparecen. Asimismo, se solicita calcular el desfase entre
la onda R y el sonido, así como entre la onda T y el sonido. En la gráfica siguiente puede
observarse que existe una relación muy estrecha entre la presión arterial y los ruidos de
Korotkoff:

Figura 18: Superposición de la presión sanguínea sobre los sonidos de Korotkoff

23
Presión sistólica y diastólica de los sonidos de Korotkoff

Se requiere calcular la presión sistólica y diastólica a partir de los sonidos de Korotkoff. En


las figuras anteriores hemos observado la aparición de sonidos con un patrón temporal
diferenciado, correspondiente al ruido y por lo tanto, no deben tenerse en cuenta en el
cálculo de las presiones.
Por lo tanto, procederemos con un filtrado de los sonidos de Korotkoff, que permitirá eliminar
los datos que son inferiores a 0,2 mV y los valores que se encuentran entre los sonidos de
interés, dejando así solo el sonido de Korotkoff:

Figura 19: Señal Sonidos de Korotkoff original y filtrado

Tras aplicar este filtro, se confirma que solo permanecen en el registro las señales vinculadas
a los ruidos de Korotkoff. El siguiente paso fundamental es localizar los sonidos que marcan
la presión sistólica y la presión diastólica. La lógica aplicada es directa: el primer ruido
detectado se asocia a la presión sistólica, mientras que el último corresponde a la diastólica.
Obtienes:

Figura 20: Detección de picos de sonido de Korotkoff

24
Una vez que los picos han sido localizados y marcados, el sistema permite determinar los
valores de presión sistólica y diastólica del sujeto. Para obtener estos resultados, se ha
desarrollado el siguiente código en MATLAB:

%% Cálculo de Presión Sistólica (PS) y Diastólica (PD)

indices_sonidos = marcas_sonidos(:);

presion_diastolica = [];
presion_sistolica = [];
tiempos_diastolica = [];
tiempos_sistolica = [];

if numel(indices_sonidos) >= 1
% La primera sistólica se asocia al primer sonido detectado
presion_sistolica = [presion_sistolica; presion(indices_sonidos(1))];
tiempos_sistolica = [tiempos_sistolica; indices_sonidos(1)];

for k = 1:numel(indices_sonidos)-1
% Si hay un silencio largo (> 2 s), detectamos el fin de una fase
y el inicio de otra
if (indices_sonidos(k+1) - indices_sonidos(k)) > 1000
presion_diastolica = [presion_diastolica;
presion(indices_sonidos(k))];
presion_sistolica = [presion_sistolica;
presion(indices_sonidos(k+1))];

tiempos_diastolica = [tiempos_diastolica; indices_sonidos(k)];


tiempos_sistolica = [tiempos_sistolica;
indices_sonidos(k+1)];
end
end

% La última diastólica se asocia al último sonido detectado


presion_diastolica = [presion_diastolica;
presion(indices_sonidos(end))];
tiempos_diastolica = [tiempos_diastolica; indices_sonidos(end)];
end

Para mayor claridad, hemos organizado los resultados obtenidos en la siguiente tabla:

Ruido 1 2 3 4 5 6 7
Presión 128.62 113.48 111.82 115.47 118.07 118.81 108.03
Sistólica
(mmHg)
Presión 68.289 68.099 25.849 68.037 68.838 69.829 68.682
Diastólica
(mmHg)
Tabla 1. Resumen de presión sistólica y diastólica

25
Los valores obtenidos concuerdan con los rangos estándar para la población adulta media.
Por consiguiente, se puede concluir que este algoritmo es capaz de calcular de manera
automática las presiones sistólica y diastólica. Cabe destacar que, para el correcto
funcionamiento del proceso, es imprescindible disponer de las señales completas desde el
primer momento, ya que la identificación de la presión sistólica se realiza mediante un
análisis en sentido inverso del registro. A continuación, se presenta la gráfica comparativa
que relaciona ambos niveles de presión:

Figura 21: Presión sistólica y diastólica en los 7 sonidos de Korotkoff

Como era de esperar, se observa claramente que la presión sistólica es mayor que la
diastólica.

26
Retraso entre la onda R y los sonidos

Ahora se calcula el retardo entre la onda R y los ruidos de Korotkoff; para calcular este
retraso, usamos el siguiente código con la función detec_ona_R:

%% 3. Cálculo del retardo Onda R -> Sonido


% localizaciones_R = latidos R

indices_sonidos_on = find(sonidos_filtrados > 0);

if ~isempty(indices_sonidos_on)
marcas_inicio_sonido = indices_sonidos_on( diff([0;
indices_sonidos_on]) > 50 );
else
marcas_inicio_sonido = [];
end

retardo_R_sonido = [];

i_ptr = 1;
j_ptr = 1;

while i_ptr <= length(marcas_inicio_sonido) && j_ptr <=


length(localizaciones_R)

% Conversión a segundos
diff_tiempo = (marcas_inicio_sonido(i_ptr) - localizaciones_R(j_ptr))
/ 500;

if diff_tiempo < 0
i_ptr = i_ptr + 1;

elseif diff_tiempo > 0.40


j_ptr = j_ptr + 1;

else
retardo_R_sonido(end+1) = diff_tiempo;
i_ptr = i_ptr + 1;
j_ptr = j_ptr + 1;
end
end

Y el gráfico que obtienes es el siguiente:

27
Figura 22: Evolución del retardo entre la onda R y los sonidos de Korotkoff

El siguiente paso del análisis consiste en determinar el retraso entre el vértice de la onda T y
la aparición de los ruidos de Korotkoff. Para aislar correctamente estas referencias, se
manipuló la señal original del ECG para eliminar los complejos de ondas R. El algoritmo
funciona basándose en que, al no encontrar los picos dominantes de la onda R, identifica y
extrae las ondas T como puntos de referencia principales. A continuación, se muestra el
segmento de código implementado para filtrar y eliminar las ondas R y el gráfico resultante
adjunto:

%% 7. Cálculo del retardo Onda T -> Sonido

retardo_T_sonido = [];

i_ptr = 1;
j_ptr = 1;

while i_ptr <= length(marcas_inicio_sonido) && j_ptr <=


length(posiciones_T)

diff_T = (marcas_inicio_sonido(i_ptr) - posiciones_T(j_ptr)) / fm;

if diff_T < 0
i_ptr = i_ptr + 1;

elseif diff_T > 0.40


j_ptr = j_ptr + 1;

else
retardo_T_sonido(end+1) = diff_T;
i_ptr = i_ptr + 1;
j_ptr = j_ptr + 1;
end
end

28
Figura 23: Señal cardíaca sin onda R

Una vez aisladas las ondas T mediante la manipulación del ECG, se generó el gráfico a
continuación, que ilustra el retraso de cada latido analizado:

Figura 24: Análisis estadístico del retardo temporal entre la onda T y los ruidos de Korotkoff

Se observa una variabilidad fisiológica significativa en la señal: los valores oscilan


predominantemente entre 0,05 s y 0,4 s. Esta fluctuación no es aleatoria, sino que refleja la
hemodinámica del sujeto a lo largo de la prueba. La precisión de los puntos calculados
confirma la eficacia de la estrategia adoptada: al eliminar los complejos R, la función de
detección se centró correctamente en la repolarización ventricular (onda T), lo que permitió
una medición precisa del tiempo necesario para que la onda de presión generara el sonido
mecánico correspondiente.
Además, cabe destacar que algunas caídas hacia cero (como alrededor del ruido 37) podrían
deberse a una breve interferencia en la señal que hizo que el cálculo del retraso fuera menos
preciso en ese instante.

29
%% 3. Cálculo del retardo entre la onda T y los ruidos de Korotkoff

retardo_T_final = [];

i_ptr = 1;
j_ptr = 1;

while i_ptr <= length(marcas_inicio_sonido) && j_ptr <=


length(posiciones_T_final)

% Cálculo de la diferencia de tiempo convirtiendo muestras a segundos


diff_T_calc = (marcas_inicio_sonido(i_ptr) -
posiciones_T_final(j_ptr)) / fm;

if diff_T_calc < 0
% Si el ruido aparece antes que la onda T, pasamos al siguiente
ruido
i_ptr = i_ptr + 1;

elseif diff_T_calc > 0.45


% Si el retardo es excesivo (> 0.45 s), se considera que la onda T
% corresponde a un latido anterior; pasamos a la siguiente onda T
j_ptr = j_ptr + 1;

else
% Retardo válido encontrado dentro del rango fisiológico
retardo_T_final(end+1) = diff_T_calc;
i_ptr = i_ptr + 1;
j_ptr = j_ptr + 1;
end
end

30
Finalmente, este código puede identificar los ruidos más cercanos a las ondas T presentes
en la señal del ECG, y se presenta el siguiente gráfico para visualizar el retraso entre los
ruidos y las ondas T:

Figura 25: Retardo entre la onda T y los ruidos de Korotkoff

En este último gráfico, presentamos los resultados del cálculo del retraso entre la señal
eléctrica del corazón (onda T) y el momento en que se escucha el sonido en el brazo. La
variación mostrada depende de cómo se modifica la presión arterial en las arterias durante
la prueba.
El hecho de que el gráfico sea tan detallado demuestra que filtrar las ondas R de la señal
funcionó bien, ya que permitió al programa encontrar siempre la onda T y calcular el tiempo
preciso de cada latido individual sin confusión.

31
SEÑAL DE VOLUMEN SANGUÍNEO
En este apartado se presentan los resultados obtenidos a partir del análisis de la señal de
pulso sanguíneo y su comparación con la señal electrocardiográfica (ECG). El estudio se ha
realizado utilizando una frecuencia de muestreo de 200 Hz y una duración total del registro
de 45 segundos, lo que garantiza una resolución temporal suficiente para la detección
precisa de los eventos cardíacos.

El objetivo principal es analizar la relación temporal entre la actividad eléctrica del corazón
(ECG) y la respuesta mecánica asociada al flujo sanguíneo periférico, así como validar la
coherencia entre ambas medidas mediante el cálculo del ritmo cardíaco.

a) Cálculo del ritmo cardíaco en latidos/minutos a partir de la señal ECG

Para la determinación del ritmo cardíaco a partir de la señal ECG se ha utilizado la


rutina detecrc, la cual permite identificar automáticamente los índices correspondientes a las
ondas R del complejo QRS. Estas ondas representan el instante de despolarización
ventricular y constituyen una referencia fiable para el cálculo del periodo cardíaco.

Una vez detectadas las marcas R, se ha calculado la diferencia temporal entre marcas
consecutivas, que corresponde a la duración de cada ciclo cardíaco. Posteriormente, se ha
obtenido la frecuencia cardíaca instantánea dividiendo la longitud total de la señal entre
dichos intervalos. Finalmente, se ha aplicado un factor de corrección teniendo en cuenta que
la duración del registro es de 45 segundos, equivalente a tres cuartos de minuto, con el fin
de expresar el resultado en latidos por minuto (BPM).

Código MATLAB utilitzado:

% Detecció de marques d'ona R


marques = detecrc(ecg3);

% Càlcul de diferències entre marques


difmarques = diff(marques);

% Càlcul de batecs per minut (ajustant per la durada de 45s)


rcmuestra = length(ecg3)./difmarques;
latmin = rcmuestra.*(4/3);

% Resultat promig
mean(latmin)

Resultado: El ritmo cardíaco medio obtenido a partir de la señal ECG es de 76.3825 latidos
por minuto, un valor coherente con una situación fisiológica de reposo.

32
Figura 26: Detección de complejos QRS (onda R

b) El pulso máximo, el mínimo y el valor pico a pico entre cada pareja de


marcas consecutivas de ondas R.

Con el objetivo de analizar el comportamiento de la señal de pulso sanguíneo en cada ciclo


cardíaco, se ha diseñado un algoritmo que recorre cada intervalo comprendido entre dos
ondas R consecutivas. Dentro de cada intervalo se ha extraído el segmento correspondiente
de la señal de pulso y se han calculado los siguientes parámetros característicos:

• Valor máximo del pulso

• Valor mínimo del pulso

• Valor pico a pico (diferencia entre el valor máximo y el mínimo)

Este procedimiento permite caracterizar la amplitud del pulso sanguíneo asociada a cada
latido cardíaco.

Código MATLAB utilitzado:

function [maximos, minimos, valorpp] = detecmaxmin(senyal, marques)


intervalos = diff(marques);
contador = 0;
for j = 1:length(intervalos)
contador = contador + 1;
% S'extreu el segment de senyal entre dues marques R
vector = senyal(marques(j):marques(j+1));
% Càlcul de paràmetres
maximos(contador,1) = max(vector);
minimos(contador,1) = min(vector);
valorpp(contador,1) = maximos(contador,1) - minimos(contador,1);
end
end

33
Resultados (valores medios en mV):

• Pulso máximo: 0.6715 mV

• Pulso mínimo: −0.2505 mV

• Valor pico a pico: 0.9220 mV

Estos valores reflejan una variabilidad adecuada de la señal de pulso sanguíneo y una
correcta detección de las oscilaciones asociadas a cada latido cardíaco.

Figura 27: Análisis de la señal de pulso sanguíneo

c) El pulso cardíaco en pulsos por minuto a partir de los instantes en los


que se alcanza el pulso máximo.

Se ha modificado el algoritmo anterior para obtener los índices temporales en los que se
producen los máximos del pulso sanguíneo (utilizando la función find). A partir de estos
índices, se ha calculado la diferencia entre ellos y se ha derivado la frecuencia cardíaca de
forma análoga a la descrita en el apartado a).

Código MATLAB utilizado:

function latmin = deteclmin(senyal, marques)


intervalos = diff(marques);
contador = 0;
for j = 1:length(intervalos)
contador = contador + 1;
vector = senyal(marques(j):marques(j+1));

% Es busca l'índex on el senyal és màxim


indices(contador,1) = find(senyal == max(vector));
end
difindices = diff(indices);
latmin = (length(senyal)./difindices).*(4/3);
end

34
Resultado: El ritmo cardíaco medio calculado a partir del pulso sanguíneo es de 76.5417
pulsos por minuto.
(Los resultados son muy similares a los obtenidos a partir del ECG, lo que valida el método
empleado).

d) El retardo existente entre la onda R y el pulso máximo, así como entre la


onda T y dicho pulso.

Se ha calculado el desfase temporal entre la actividad eléctrica del corazón (ECG) y la


respuesta mecánica asociada al pulso sanguíneo.

1. Retardo Onda R – Pulso Máximo

Se calcula la diferencia absoluta entre los índices correspondientes a las ondas R y los
índices de los máximos del pulso, dividiendo dicho valor por la frecuencia de muestreo
(200 Hz) para expresarlo en segundos.

Código:

% 'marques' són els índexs R, 'indices' són els màxims de pols


retardo = abs([marques - indices]);
retardo = retardo./200;
mean(retardo)

Resultado: El retardo medio obtenido es de 0.3562 s.

2. Retardo Onda T – Pulso Máximo

En primer lugar, se ha aislado una onda T representativa y se ha realizado una correlación


cruzada (xcorr) con la señal ECG completa para detectar todas las ondas T del registro.

Posteriormente, se ha calculado la diferencia temporal entre los instantes correspondientes


a las ondas T y los máximos del pulso sanguíneo.

Código:

% Aislamiento manual d'una onda T representativa


ondat = ecg3(6256:6301);
% Correlación per encontrar todas les ondes T
correlacion = xcorr(ondat, ecg3);
cor = correlacion(1:9000);
marcast = detecrc(cor);

% Cálculo del retardo


retardot = abs([marcast - indices]);
retras = retardot./200;
mean(retras)

35
Resultado: El retardo medio entre la onda T y el pico de presión es de 0.6657 s.

Figura 28: Comparativa temporal (retardo)

36
ANÁLISIS FRECUENCIAL DE LOS SONIDOS DE
KOROTKOFF
Para este apartado se analiza el contenido frecuencial de los sonidos de Korotkoff
registrados durante la medida de presión arterial. Se utiliza el archivo
korotkoff_retallats_2024.mat, que contiene siete registros (so1…so7) muestreados a
Fs=500Hz. El objetivo es obtener la Distribución Espectral de Energía (DEE) de sonidos
individuales y cuantificar su evolución mediante la frecuencia media (MNF) y la frecuencia
mediana (MDF).

Metodología
Preprocesado
Cada registro se centra eliminando el valor medio:
𝑥" [𝑛] = 𝑥[𝑛] − 𝑥[𝑛]
para reducir el componente DC y facilitar el análisis espectral.
El criterio para la selección de los sonidos, se implementó un procedimiento semiautomático
reproducible para localizar los instantes de los sonidos y mantener el mismo criterio en los
siete registros. En clase se planteó la posibilidad de seleccionar los sonidos manualmente.
Sin embargo, por limitaciones prácticas (disponibilidad de equipo/tiempo de trabajo), se
siguió el criterio semiautomático.

El método se basa en:


1. Cálculo de la envolvente como promediado móvil del valor absoluto y
normalización:

2. Detección de picos con findpeaks sobre la envolvente normalizada,


usando:
• Ventana de envolvente W = 30 ms
• Distancia mínima entre picos: 0.20 s
• Prominencia mínima: 0.06

Segmentación temporal de cada sonido


Para cada pico detectado se extrae un segmento temporal fijo: 60 ms antes del pico y 120
ms después del pico. En adición, se aplica una ventana de Hann al segmento para reducir la
fuga espectral.

Cálculo de la DEE
Se calcula la FFT con NFFT = 2048 (zero-padding) y se obtiene el semiespectro (0 a Fs/2).
La DEE se define como:
𝐷𝐸𝐸[𝑘] = |𝑋[𝑘]|#
Para comparar entre sonidos, se representa la DEE normalizada:
𝐷𝐸𝐸_𝑁[𝑘] = 𝐷𝐸𝐸[𝑘]/𝑚𝑎𝑥(𝐷𝐸𝐸[𝑘])
En las figuras se limita el rango a 0–200 Hz para visualizar la región donde se concentra la
energía en estos registros.

37
Cálculo de MNF y MDF
La frecuencia media (MNF) se calcula como promedio ponderado por energía:
𝑀𝑁𝐹 = 𝛴$ 𝑓[𝑘] · 𝐷𝐸𝐸[𝑘]/𝛴$ 𝐷𝐸𝐸[𝑘]
La frecuencia mediana (MDF) se define como la frecuencia donde la energía acumulada
alcanza el 50%:
1
$ 𝐷𝐸𝐸 = $ 𝐷𝐸𝐸[𝑘]
2
" $ %&' 𝒌

Resultados
Registro MNF media ± std (Hz) MDF media ± std (Hz)
so1 68.30 ± 6.85 63.15 ± 8.36
so2 66.16 ± 4.62 61.98 ± 7.58
so3 63.16 ± 3.05 60.85 ± 5.11
so4 60.70 ± 7.82 56.67 ± 7.39
so5 66.57 ± 5.27 66.27 ± 4.07
so6 67.13 ± 5.94 65.54 ± 6.55
so7 65.08 ± 8.33 64.53 ± 10.04
Tabla 2. Resumen de MNF y MDF (media ± desviación típica) por registro (so1…so7)

Se aprecia una disminución de los valores medios desde so1 hasta so4, seguida de un
aumento en so5–so6 y una ligera reducción en so7. Esto indica que el contenido espectral
varía entre registros.

38
Distrubución espectral de energía (DEE)

Figuras 29: DEE normalizadas de los sonidos de Korotkoff detectados en el registro so1…so7 (Fs=500 Hz,
NFFT=2048). Rango mostrado: 0–200 Hz.

39
Evolución de MNF y MDF

Figuras 30: Evolución de la frecuencia media (MNF) y frecuencia mediana (MDF) para los sonidos consecutivos
del registro so1…so7

40
En las Figuras correspondientes a las DEE normalizadas de los sonidos de Korotkoff (so1–
so7) se observa que, en todos los registros, la mayor parte de la energía espectral se
concentra en un rango de bajas frecuencias, aproximadamente entre 40 y 100 Hz. Este
comportamiento es coherente con la naturaleza acústica de los sonidos de Korotkoff, que
presentan un contenido predominantemente grave asociado a la turbulencia del flujo
sanguíneo durante la descompresión del manguito.

Para cada medida de presión se han representado de forma superpuesta las DEE de los
sonidos consecutivos detectados. En general, las curvas muestran una forma espectral
similar, aunque con ligeros desplazamientos del máximo y variaciones en la anchura del
espectro. Estas diferencias reflejan la variabilidad natural entre latidos y el carácter no
estacionario de la señal, además de la sensibilidad del análisis a la segmentación temporal
de cada sonido.

El análisis cuantitativo mediante la frecuencia media (MNF) y la frecuencia mediana (MDF)


permite evaluar de forma más objetiva la evolución espectral. En conjunto, se observa una
tendencia global a valores más bajos de MNF/MDF en determinados tramos de la secuencia
de sonidos, lo que sugiere un desplazamiento del contenido espectral hacia frecuencias más
graves conforme progresa el registro. En algunos casos esta tendencia es más marcada,
mientras que en otros aparecen fluctuaciones locales o incrementos puntuales.

Estas fluctuaciones pueden explicarse por variabilidad interlatido, cambios transitorios en la


dinámica del flujo sanguíneo y por la dependencia del espectro respecto a la ventana
temporal seleccionada alrededor de cada sonido. En conjunto, los resultados son
consistentes a nivel cualitativo: la energía se concentra en bajas frecuencias y se observan
variaciones de MNF/MDF a lo largo de los sonidos consecutivos, en concordancia con el
objetivo del análisis.

41
ANÁLISIS DE SEÑALES PROPORCIONADAS
EN ATENEA
SEÑALES REGISTRADAS
En esta segunda parte del proyecto se analizan las señales biomédicas proporcionadas
como ejemplo en ATENEA. El archivo contiene tres canales diferentes que corresponden a
la presión sanguínea, a los sonidos de Korotkoff registrados mediante un estetoscopio y a
una señal de electrocardiograma.

Las señales presentan una frecuencia de muestreo de 5000 Hz, que se ha calculado a partir
del intervalo de muestreo proporcionado en el archivo, de 0,2 ms. Esta frecuencia es
adecuada para la señal de presión sanguínea, ya que presenta una evolución lenta en el
tiempo, pero limita la resolución temporal de las señales de sonidos de Korotkoff y del ECG.
Además, las señales de presión sanguínea se miden en mmHg, mientras que los sonidos de
Korotkoff y el ECG se expresan en milivoltios (mV).

En la siguiente figura se representan las tres señales registradas sin ningún tipo de
preprocesado; no obstante, en el caso del ECG, la señal se ha obtenido aplicando un filtro
paso banda de 0,5 Hz a 35 Hz, tal y como se indica en la descripción de los datos, con el
objetivo de eliminar la deriva de la línea base y el ruido de alta frecuencia antes de su análisis.

El código utilizado para obtener esta figura ha sido el siguiente:

load [Link]
Fs = 1/(isi*1e-3)
t = (0:size(data,1)-1)/Fs;

presion = data(:,1);
korotkoff = data(:,2);
ecg = data(:,3);

%% Visualizamos las señales proporcionadas


figure
subplot(3,1,1)
plot(t, presion)
title('Presión sanguínea')
ylabel('mmHg')
grid on
subplot(3,1,2)
plot(t, korotkoff)
title('Sonidos de Korotkoff')
ylabel('mV')
grid on
subplot(3,1,3)
plot(t, ecg)
title('ECG')
ylabel('mV')
xlabel('Tiempo (s)')
grid on

42
Figura 31. Registro de las señales en el dominio temporal.

Podemos observar las tres señales registradas en el dominio temporal. La señal de presión
sanguínea muestra una fase inicial de incremento seguida de un descenso progresivo, lo cual
está relacionado con el proceso de inflado y desinflado del manguito durante la medición.
Los sonidos de Korotkoff aparecen de forma intermitente durante intervalos concretos del
registro, mientras que la señal ECG muestra complejos QRS claramente identificables a lo
largo de todo el registro.

43
RUIDO I/O INTERFERENCIAS
En este apartado se analizan las tres señales con el objetivo de detectar los posibles ruidos
o interferencias que afectan y limitan las señales reales, tanto en el dominio temporal como
en el frecuencial. Estas señales se encuentran todavía sin filtrar, a excepción del filtro paso
banda de 0,5–35 Hz aplicado al ECG, previamente comentado, con el fin de poder identificar
fácilmente las fuentes de ruido presentes en cada señal proporcionada.

Dominio temporal
En la siguiente figura se muestra un intervalo común de las tres señales en el dominio
temporal, concretamente un zoom de las primeras 2000 muestras, que corresponden
aproximadamente a los primeros 0,4 segundos. De este modo, se puede observar con mayor
detalle la presencia de ruido y las irregularidades propias de las señales reales antes de
aplicar filtrados adicionales.

El código utilizado para obtener esta figura ha sido el siguiente:

Ns = 2000;

figure
subplot(3,1,1)
plot(t(1:Ns), presion(1:Ns))
title('Presión sanguínia (dominio temporal)')
ylabel('mmHg')
grid on
subplot(3,1,2)
plot(t(1:Ns), korotkoff(1:Ns))
title('Sonidos de Korotkoff (dominio temporal)')
ylabel('mV')
grid on
subplot(3,1,3)
plot(t(1:Ns), ecg(1:Ns))
title('ECG (dominio temporal)')
ylabel('mV')
xlabel('Tiempo (s)')
grid on

44
Figura 32. Intervalo común, primeros 0,4 segundos.

En la señal de presión sanguínea se observa una evolución lenta con pequeñas variaciones
escalonadas superpuestas, que pueden atribuirse a la resolución limitada del sensor o del
sistema de adquisición, más que a oscilaciones fisiológicas rápidas.

Por otro lado, la señal correspondiente a los sonidos de Korotkoff presenta picos cortos de
elevada amplitud únicamente durante un intervalo concreto; fuera de este intervalo se
observa un cierto ruido de fondo asociado al entorno y al proceso de adquisición.

El ECG es la señal que muestra un mayor ruido de fondo continuo, superpuesto a los
complejos QRS. Se aprecia además una ligera inestabilidad de la línea base y pequeñas
fluctuaciones de baja frecuencia, probablemente producidas por la interferencia de la
respiración o por movimientos del paciente.

45
Dominio frecuencial
A continuación, se analiza cómo se traducen las interferencias observadas en el dominio
temporal al dominio frecuencial mediante el uso de la Transformada Discreta de Fourier
(DFT), con el objetivo de estudiar el contenido espectral de las señales reales. La primera
figura representada corresponde al espectro de la señal de presión sanguínea.

Previamente, se ha eliminado la componente continua restando el valor medio, ya que esta


concentra la mayor parte de la energía del señal y dificulta la visualización del resto de
componentes espectrales. Posteriormente, se ha representado la densidad espectral en
escala logarítmica para observar mejor la distribución de la energía, a partir del siguiente
código:

presion_dc = presion - mean(presion);

N = length(presion_dc);
N2 = floor(N/2);
f = (0:N2-1)*(Fs/N);
P_FFT = abs(fft(presion_dc)).^2;

figure
plot(f(1:N/2), 10*log10(P_FFT(1:N/2)))
xlabel('Frecuencia (Hz)')
ylabel('Energía (dB)')
title('Espectro de la presión sanguínia')
grid on

Figura 33. Espectro de la presión sanguínea.

En el dominio frecuencial se observa que la energía de la señal se concentra principalmente


en bajas frecuencias, lo cual concuerda con la evolución lenta de la señal en el dominio
temporal. A medida que la frecuencia aumenta, la energía decrece de forma progresiva, sin
la presencia de picos espectrales destacables. Por tanto, las componentes residuales de alta
frecuencia no aportan información relevante y pueden asociarse a ruido de fondo de medida.

46
Para el análisis en el dominio frecuencial de la señal de los sonidos de Korotkoff también se
ha eliminado la componente continua y se ha representado el espectro en escala logarítmica,
con el objetivo de facilitar la visualización del contenido espectral. Esto se ha conseguido
con el siguiente código:

kor_dc = korotkoff - mean(korotkoff);

N = length(kor_dc);
N2 = floor(N/2);

f = (0:N2-1)*(Fs/N);
K_FFT = abs(fft(kor_dc)).^2;

figure
plot(f(1:N2), 10*log10(K_FFT(1:N2)))
xlabel('Frecuencia (Hz)')
ylabel('Energía (dB)')
title('Espectro de los sonidos de Korotkoff')
grid on

Figura 34. Espectro de los sonidos de Korotkoff.

Se observa que la mayor parte de la energía se concentra en bajas frecuencias,


disminuyendo progresivamente a medida que la frecuencia aumenta. No se identifican picos
frecuenciales definidos. Las componentes de mayor frecuencia presentan una contribución
energética reducida y poco relevante, por lo que probablemente pueden asociarse a ruido
de fondo.

47
Para finalizar el análisis del dominio frecuencial, se estudia también el contenido de la señal
ECG mediante la Transformada Discreta de Fourier. Previamente, se ha eliminado la
componente continua de la señal, lo que facilita la visualización de la distribución de la
energía, y se ha representado el espectro en escala logarítmica con el siguiente código:

ecg_dc = ecg - mean(ecg);

N = length(ecg_dc);
N2 = floor(N/2);

f = (0:N2-1)*(Fs/N);
ECG_FFT = abs(fft(ecg_dc)).^2;

figure
plot(f(1:N2), 10*log10(ECG_FFT(1:N2)))
xlabel('Frecuencia (Hz)')
ylabel('Energía (dB)')
title('Espectro del señal ECG')
grid on

Figura 35. Espectro de la señal ECG.

En el espectro del ECG se observa que la mayor parte de la energía se concentra en bajas
frecuencias, principalmente por debajo de los 35 Hz, lo cual concuerda con el prefiltrado
aplicado a la señal antes de su análisis. La ausencia de componentes significativas a
frecuencias más elevadas indica una correcta atenuación del ruido de alta frecuencia. No
obstante, se aprecia la presencia de energía residual a frecuencias muy bajas, que podría
asociarse a pequeñas derivas de la línea base.

48
FILTRADO I ACONDICIONAMENTO DE LAS SEÑALES
En este apartado se realiza el filtrado y acondicionamiento de las señales de ECG, presión
sanguínea y sonidos de Korotkoff, con el objetivo de reducir el ruido y las interferencias
presentes y permitir la aplicación de los algoritmos de análisis desarrollados previamente.

Presión Sanguínea
Comenzando por la señal de presión sanguínea, a partir del análisis realizado en el dominio
temporal y frecuencial se observa que la señal presenta una evolución lenta con la presencia
de pequeñas oscilaciones de alta frecuencia asociadas principalmente al ruido de medida.
Para reducir este ruido y preservar la información fisiológica relevante, se ha aplicado un
filtrado paso bajo:

fc = 15; % Diseño del filtro pasa-baja


Wn = fc/(Fs/2);
[b_p, a_p] = butter(4, Wn, 'low');
presion_filt = filtfilt(b_p, a_p, presion);

Ns = 10000;

figure
plot(t(1:Ns), presion(1:Ns), '--b','LineWidth', 1.5)
hold on
plot(t(1:Ns), presion_filt(1:Ns), 'r')
xlabel('Tiempo (s)')
ylabel('mmHg')
title('Presión sanguínea antes y despues del filtraje')
legend('Original','Filtrada')
grid on

Figura 36. Presión sanguínea antes y después de la aplicación de filtros.

49
El procedimiento seguido ha consistido en el diseño de un filtro digital Butterworth de cuarto
orden con una frecuencia de corte de 15 Hz. Esta elección se debe a que este tipo de filtro
proporciona una respuesta suave en la banda de paso y permite atenuar el ruido de alta
frecuencia detectado sin introducir ondulaciones significativas en la señal. Además,
mediante el uso de la función filtfilt se ha evitado la aparición de desfases temporales.

Para visualizar mejor el efecto del filtrado, en la Figura 37 se muestra una ampliación de la
señal de presión sanguínea, lo que permite apreciar con mayor claridad la diferencia entre la
señal original y la señal filtrada, observándose un filtrado muy suave.

Figura 37. Gráfica ampliada de la presión sanguínea antes


y después de la aplicación de filtros.

Como se puede observar, las diferencias entre la señal original y la señal filtrada son sutiles,
ya que la señal de presión sanguínea presenta principalmente componentes de baja
frecuencia. El filtrado permite suavizar pequeñas oscilaciones de alta frecuencia sin alterar
la forma global de la señal, que es, en definitiva, la información de interés.

50
Sonidos de Korotkoff

De acuerdo con el análisis previo en los dominios temporal y frecuencial, la señal de los
sonidos de Korotkoff presenta componentes espectrales distribuidas en un amplio rango de
frecuencias, además de ruido de fondo. Para aislar las componentes con información
fisiológica relevante y mejorar la relación señal-ruido, se ha aplicado un filtro paso banda.

Se ha utilizado nuevamente un filtro digital Butterworth de cuarto orden, estableciendo las


frecuencias de corte en 25 Hz y 150 Hz. Este rango permite preservar las componentes
asociadas a los sonidos de Korotkoff, eliminando tanto las componentes de muy baja
frecuencia como el ruido de alta frecuencia. Al igual que en el caso de la presión sanguínea,
el filtro se ha aplicado mediante la función filtfilt para evitar desfases [Link]
código utilizado ha sido el siguiente:

f_low = 25;
f_high = 150;
Wn = [f_low f_high] / (Fs/2);
[b_k, a_k] = butter(4, Wn, 'bandpass');
kor_filt = filtfilt(b_k, a_k, korotkoff);

Ns = 2000; % 0.4 s

figure
plot(t(1:Ns), korotkoff(1:Ns), 'b')
hold on
plot(t(1:Ns), kor_filt(1:Ns), 'r')
xlabel('Tiempo (s)')
ylabel('mV')
title('Sonidos de Korotkoff antes y despues del filtrado')
legend('Original','Filtrado')
grid on

Figura 38. Sonidos de Korotkoff antes y después de la aplicación de filtros.

51
La comparación entre la señal original y la señal filtrada muestra una reducción significativa
del ruido de fondo y una mejor definición de los transitorios acústicos, lo que facilita la
detección posterior de los sonidos de Korotkoff y la estimación de la presión sistólica y
diastólica.

En la Figura 33 se muestra la representación de la envolvente de los sonidos de Korotkoff.


Esta envolvente es siempre positiva, sigue la energía local de la señal y permite identificar
claramente los picos asociados a los sonidos. De este modo, se eliminan las oscilaciones
rápidas y se obtiene una representación basada en las amplitudes globales del señal. Se ha
hecho a partir del código:

envolvente = abs(hilbert(kor_filt)); % Añadimos envolvente

figure
plot(t(1:Ns), envolvente(1:Ns))
xlabel('Tiempo (s)')
ylabel('Amplitud')
title('Envolvente dels sonidos de Korotkoff')
grid on

Figura 39. Envolvente de los sonidos de Korotkoff.

52
ECG

En el caso del ECG no es necesario aplicar ningún filtrado adicional. Como se ha comentado
anteriormente, se trata de una señal que ya ha sido prefiltrada antes de su distribución. Dicho
prefiltrado corresponde a un filtro paso banda con frecuencias de corte de 0,5–35 Hz, cuyo
objetivo es eliminar la deriva de la línea base asociada a componentes de muy baja
frecuencia y atenuar el ruido de alta frecuencia que no contiene información fisiológica
relevante.

Tal y como se ha observado en el análisis del dominio frecuencial del apartado anterior, la
mayor parte de la energía del ECG se concentra por debajo de los 35 Hz. Esto confirma que
el filtrado aplicado es adecuado para preservar las componentes principales de la señal,
especialmente los complejos QRS. La ausencia de componentes significativas a frecuencias
más elevadas indica una correcta reducción del ruido de alta frecuencia. Este
acondicionamiento de la señal permite una detección robusta de los picos R y el cálculo
posterior de los intervalos RR y de la frecuencia cardíaca, que serán necesarios para el
análisis de las señales en el siguiente apartado. Por tanto, no es necesario aplicar ningún
filtrado adicional.

ANÁLISIS DE LAS SENYALS ECG, PRESIÓN SANGUÍNEA Y


SONIDOS DE KOROTKOFF
Incluyendo la adaptación y/o modificación de los algoritmos para
su funcionamiento en señales reales
En este apartado se realiza el análisis de las señales biomédicas reales de ECG, presión
sanguínea y sonidos de Korotkoff, utilizando las señales previamente filtradas y
acondicionadas. El objetivo principal es extraer información relevante de cada señal
mediante la aplicación de algoritmos, adaptándolos al funcionamiento con datos reales, los
cuales presentan ruido, variabilidad y limitaciones propias de los sistemas de adquisición. A
diferencia de las señales ideales o simuladas, las señales reales requieren ajustar parámetros
y criterios de detección para garantizar resultados coherentes y con sentido fisiológico.

ECG
El análisis de la señal ECG tiene como finalidad caracterizar la actividad cardíaca a partir del
registro obtenido. En este subapartado se realiza la detección de los picos R,
correspondientes a los complejos QRS, y se calculan los intervalos RR y la frecuencia
cardíaca. Los algoritmos desarrollados en la práctica 4 se han adaptado para funcionar
correctamente con una señal real, teniendo en cuenta la presencia de ruido residual y
posibles variaciones en la amplitud de la señal.

53
La detección de los picos R se ha llevado a cabo mediante un algoritmo basado en la
identificación de máximos locales, utilizando criterios de umbral de amplitud y de distancia
mínima entre picos. Estos parámetros se han ajustado para evitar la detección de ruido y
garantizar una separación temporal con sentido fisiológico entre latidos consecutivos.
Obteniendo la siguiente figura a partir del código:

ecg_sig = ecg;

[pk_R, loc_R] = findpeaks(ecg_sig, Fs,'MinPeakHeight',


0.3*max(ecg_sig),'MinPeakDistance', 0.4);

figure
plot(t, ecg_sig)
hold on
plot(loc_R, pk_R, 'ro')
xlabel('Temps (s)')
ylabel('mV')
title('Detecció de pics R en el senyal ECG')
grid on

Figura 40. Detección de los picos R en la señal ECG.

A partir de la detección de los picos R, como se observa en la Figura 40, se han calculado
los intervalos RR y la frecuencia cardíaca instantánea, así es como, finalmente, se ha
obtenido la frecuencia cardíaca media del registro.

Resultando un valor de 86,4605 bpm, que proporciona una estimación global del ritmo
cardíaco durante el periodo de adquisición. Este valor, como se observa en la Figura 41, se
encuentra dentro del rango fisiológico normal para un adulto en reposo.

54
Todo se ha obtenido a partir del código:

RR = diff(loc_R) % Intervalos RR
FC_inst = 60 ./ RR % Frecuencia cardíaca instantanea
FC_mitjana = mean(FC_inst) % Frecuencia cardíaca media

figure
plot(FC_inst)
xlabel('Latido')
ylabel('Frecuencia cardíaca (bpm)')
title('Frecuencia cardíaca instantanea')
grid o

Figura 41. Frecuencia cardíaca instantánea.

Presión Sanguínea

En el caso de la señal de presión sanguínea, el análisis se centra en el estudio de su evolución


temporal y en la identificación de los valores característicos de la presión arterial. A partir de
la señal filtrada, se buscan los valores máximos y mínimos asociados a la presión sistólica y
diastólica, respectivamente.

Para ello, se han utilizado los algoritmos desarrollados en la práctica 4, adaptándolos para
que funcionen correctamente en una señal de este tipo, cuya evolución es lenta y puede
asociarse al proceso de inflado y desinflado del manguito. Mediante un algoritmo de
detección de máximos y mínimos similar al utilizado en el ECG, se han identificado los valores
de presión sistólica y diastólica del registro. Posteriormente, se ha representado la evolución
de ambas presiones durante la medición, a partir del código siguiente:

55
[pks_sys, loc_sys] = findpeaks(presion_filt, Fs, 'MinPeakDistance', 0.5);

[pks_dia, loc_dia] = findpeaks(-presion_filt, Fs,'MinPeakDistance', 0.5);


pks_dia = -pks_dia;

P_sistolica = max(pks_sys)

figure
plot(t, presion_filt)
hold on
plot(loc_sys, pks_sys, 'ro')
plot(loc_dia, pks_dia, 'go')
xlabel('Tiempo (s)')
ylabel('mmHg')
title('Detección de presión sistolica i diastolica')
legend('Presión filtrada','Sistolica','Diastolica')
grid on

Figura 44. Detección de la presión sistólica y diastólica.

Este procedimiento muestra cómo los algoritmos desarrollados en condiciones ideales


pueden adaptarse a señales reales mediante una simplificación de los criterios de detección
y el uso de valores globales, manteniendo una interpretación fisiológica coherente de la
señal.

Como se observa, el valor máximo de presión obtenido corresponde a la presión máxima


aplicada por el manguito durante el proceso de inflado, pero no implica que represente
directamente la presión sistólica arterial real del sujeto. Para poder determinar la presión
sistólica y diastólica reales es necesario combinar esta información con la señal de los
sonidos de Korotkoff, lo cual se desarrolla en el apartado siguiente.

56
Sonidos de Korotkoff

El análisis de los sonidos de Korotkoff se ha realizado a partir de los algoritmos desarrollados


en la práctica 6, adaptándolos en este caso a un registro real. La señal acústica ha sido
previamente filtrada mediante un filtro paso banda y se ha calculado su envolvente con el fin
de obtener una medida robusta de la energía de la señal en el tiempo.

Mediante la definición de un umbral sobre la envolvente se han identificado los intervalos


temporales en los que los sonidos de Korotkoff están presentes. El instante de aparición del
primer sonido se ha asociado a la presión sistólica, mientras que el instante de desaparición
de los sonidos se ha asociado a la presión diastólica. A partir de la correspondencia temporal
con la señal de presión del manguito se han obtenido estimaciones de la presión sistólica y
diastólica reales del registro, completando así el análisis del apartado anterior.

El código utilizado para obtener esta gráfica y los resultados posteriores es:

[~, idx_max] = max(presion_filt);

envolvente_des = envolvente(idx_max:end);
presion_des = presion_filt(idx_max:end);
t_des = t(idx_max:end);

threshold = 0.4 * max(envolvente_des);


sons_des = envolvente_des > threshold;

idx_sons = find(sons_des);
idx_inici = idx_sons(1);
idx_final = idx_sons(end);
t_inici = t_des(idx_inici);
t_final = t_des(idx_final);

P_sistolica_real = presion_des(idx_inici)
P_diastolica_real = presion_des(idx_final)

figure
plot(t, presion_filt)
hold on
xline(t_inici, '--r', 'Inicio Korotkoff')
xline(t_final, '--g', 'Final Korotkoff')
xlabel('Tiempo (s)')
ylabel('mmHg')
title('Determinación de la presión sistolica y diastolica mediante
Korotkoff')
legend('Presión filtrada','Sistolica','Diastolica')
grid on

57
Figura 45. Detección de la presión sistólica y diastólica mediante los sonidos de Korotkoff.

Este procedimiento permite combinar la información de los sonidos de Korotkoff con la señal
de presión del manguito, mostrando cómo los algoritmos desarrollados en prácticas previas
pueden adaptarse a señales reales para extraer parámetros fisiológicos relevantes. Para
evitar la detección de falsos positivos debidos al ruido presente en los instantes iniciales del
registro, la detección de los sonidos de Korotkoff se ha restringido al tramo de desinflado
del manguito, una vez alcanzada la presión máxima.

En este registro, la presión sistólica real se ha estimado en aproximadamente 168,8692


mmHg, correspondiente al instante de aparición de los primeros sonidos, mientras que la
presión diastólica real se ha estimado en 80,5098 mmHg, asociada a la desaparición de los
sonidos de Korotkoff.

58
CONCLUSIONES
En este proyecto se ha llevado a cabo un análisis completo de distintas señales biomédicas,
concretamente la señal electrocardiográfica (ECG), la presión sanguínea y los sonidos de
Korotkoff, con el objetivo de aplicar los conocimientos adquiridos a lo largo de la asignatura
de Procesamiento de Señales Biomédicas. El trabajo ha permitido integrar conceptos
teóricos y prácticos relacionados con el análisis temporal y frecuencial, el filtrado digital y la
extracción de parámetros fisiológicos de interés.

El proyecto se ha estructurado en dos partes diferenciadas. En una primera fase se han


analizado señales proporcionadas en las prácticas de la asignatura, lo que ha permitido
comprender el comportamiento ideal de las señales biomédicas y desarrollar algoritmos de
detección y análisis en condiciones controladas. Esta etapa ha sido fundamental para
identificar las características principales de cada señal, así como el efecto del ruido y la
necesidad de aplicar técnicas de filtrado adecuadas.

En la segunda parte del proyecto se ha trabajado con señales reales, lo que ha supuesto una
mayor dificultad debido a la presencia de ruido, interferencias y variabilidad propia de los
sistemas de adquisición y del sujeto. En este contexto, ha sido necesario realizar un análisis
más detallado en los dominios temporal y frecuencial, así como diseñar y ajustar filtros
digitales específicos para cada tipo de señal. El filtrado aplicado al ECG, a la presión
sanguínea y a los sonidos de Korotkoff ha permitido mejorar la relación señal-ruido y preparar
adecuadamente los registros para su posterior análisis.

El análisis del ECG ha permitido detectar de forma robusta los complejos QRS y calcular los
intervalos RR y la frecuencia cardíaca, obteniendo valores coherentes con una situación
fisiológica normal. En el caso de la señal de presión sanguínea, se ha analizado su evolución
temporal y se han identificado los valores máximos y mínimos asociados a la presión sistólica
y diastólica, comprobando que los algoritmos desarrollados pueden adaptarse a señales
reales manteniendo una interpretación fisiológica adecuada.

Finalmente, el análisis de los sonidos de Korotkoff ha permitido estimar la presión sistólica y


diastólica reales a partir de la aparición y desaparición de los sonidos, combinando la
información acústica con la señal de presión del manguito. Este apartado ha puesto de
manifiesto la importancia de integrar distintas señales biomédicas para obtener estimaciones
más precisas de parámetros fisiológicos relevantes.

En conjunto, este proyecto ha permitido comprender la diferencia entre el análisis de señales


ideales y reales, destacando la necesidad de adaptar los algoritmos, ajustar parámetros y
validar los resultados obtenidos. El trabajo realizado demuestra la utilidad del procesamiento
digital de señales en el ámbito biomédico y su importancia para la obtención de información
fisiológica fiable a partir de registros reales.

59
BIBLIOGRAFÍA
[1] Diseño de un sistema de adquisición y procesamiento de la señal de ECG basado en
instrumentación virtual, 2015. [Online]. Disponible en:
[Link]

[2] Ruidos de Korotkoff, 2019. [Online]. Disponible en:


[Link]

[3] Sonidos de Korotkoff, 2022. [Online]. Disponible en:


[Link]

[4] Blood Pressure, 2008. [Online]. Disponible en:


[Link]

[5] Fisiología cardíaca, 2018. [Online]. Fundación BBVA. Disponible en:


[Link]

[6] S. M. Kay, Modern Spectral Estimation: Theory and Application, Prentice Hall, 1988.

[7] A. V. Oppenheim, A. S. Willsky y S. H. Nawab, Signals and Systems, 2ª ed., Prentice


Hall, 1997.

[8] J. G. Proakis y D. G. Manolakis, Digital Signal Processing: Principles, Algorithms, and


Applications, 4ª ed., Pearson Education, 2007.

[9] PhysioNet, Physiological Signal Databases. [Online]. Disponible en:


[Link]

[10] MathWorks, Digital Signal Processing Toolbox – Filtering and Spectral Analysis.
[Online]. Disponible en:
[Link]

60
ANNEX I. CODI DELS ALGORITMES AMB
COMENTARIS
A. SEÑAL ELECTROCARDIOGRÁFICA Y SEÑAL DE PRESIÓN SANGUÍNEA

function marques = detecrc(senyal)


% DEFINICIONS
derSenyal = diff(senyal); %Se realiza la derivada de la señal.
numMostres = length(derSenyal);
offset = 50; %Error que habrá que sumar a las mediciones.
llindar = .5*max(derSenyal(1:2500)); %Se establece como umbral de
referencia el
%50% del máximo de la derivada.

comptador = 0; %Contador que indicará los índices de los complejos QRS.


mostra = 400;

% BUCLE PRINCIPAL DE CERCA


continuar = true;
while continuar %Mientras no se haya llegado al límite de muestras
%continúa el bucle de detección de complejos QRS.
if derSenyal(mostra) > llindar %Si la derivada es mayor que el umbral,
%Se activa el siguiente bucle.
buscar = true;
while buscar
if derSenyal(mostra) < 0
comptador = comptador + 1; %Cuando la derivada toma un
valor negativo quiere decir que comienza el complejo QRS. Es aquí cuando
el contador toma el valor del índice de inicio del complejo.

marques(comptador, 1) = mostra; %La variable "muestra"


ahora toma el valor del índice de la onda R.

buscar = false;
%Se establece un nuevo umbral, que corresponde a la media entre el
%umbral anterior y el 50% del máximo de la derivada en el último
%índice analizado.

llindar = mean([llindar 0.5*max(derSenyal(mostra+offset :


min([mostra+(2500) numMostres])))]);
mostra = mostra + offset; %Se suma el error de offset a la
muestra.
if mostra >= numMostres
continuar = false; %Si se llega al límite de muestras
se detienen las iteraciones.

end

else
mostra = mostra + 1;
if mostra >= numMostres
continuar = false;
end
end
end
else
mostra = mostra + 1;

61
if mostra >= numMostres
continuar = false;
end
end
end
% Con el siguiente comando se grafican los resultados
t = (1/250:1/250:numMostres/250)';
figure; box on; hold on;
plot(t, senyal(1:numMostres));
plot(t, derSenyal, 'r');
axis tight;
plot([marques marques]'/250, repmat(get(gca,'Ylim')', size(marques')), 'k-
-');
title('ECG')
xlabel('temps (s)')
hold off;
xlim([2 4]);
pan xon;

%ritmocardiaco%
marques = detecrc(ecg1);

fs = 250;
RR_mostres = diff(marques);
RR_segons = RR_mostres / fs;

ritmocardiaco = 60 ./ RR_segons;

%presion sistólica%
for i = 1:length(marques)-1
psis(i) = max(psan(marques(i):marques(i+1)));
end

figure;
plot(psis)
xlabel('Latido')
ylabel('Presión sistólica (mmHg)')
title('Presión sistólica durante el registro')

function [fmean, fmed] = fmnmd(P, f)


% FMNMD Calcula la freqüència mitjana i mediana d'una densitat espectral
de potència.
%
% [FMEAN, FMEDIAN] = FMNMD(P, F)
%
% P: Densitat espectral de potència
% F: Vector de freqüències associat a P.
%
% FMEAN: Freqüència mitjana
% FMEDIAN: Freqüència mediana
%

if sum(P) ~= 0,
num = sum(f.*P);
den = sum(P);
fmean = num/den;
den = sum(P);
k = 1;
while sum(P(1:k)) <= den/2

62
k = k+1;
end
i = k;
if i < length(P),
alfa1 = sum(P(1:i-1))/den;
if P(i) <= P(i+1)
radi = roots([abs(P(i+1)-P(i)) 2*P(i) -2*(0.5-alfa1)*den]);
else
radi = roots([abs(P(i+1)-P(i)) P(i)+P(i+1) -2*(0.5-alfa1)*den]);
end
if radi(1) > 0 && radi(1) < 1,
x = radi(1);
else
x = radi(2);
end;
df = f(2) - f(1);
fmed = f(k) + df*x;
else
fmean = NaN;
fmed = NaN;
end
else
fmean = NaN;
fmed = NaN;
end

%% INICIALIZACIÓN
clearvars; close all; clc;

load senecg_fantasia; % ecg1


load senpre_fantasia; % psan

% Normalizamos las señals


normECG = detrend(ecg1, 'constant')/std(ecg1);
normPsan = detrend(psan, 'constant')/std(psan);

fm = 250;
numMostres = length(normECG);
duracio = numMostres/fm;
tMin = 1/fm;
tDelta = 1/fm;
tMax = numMostres/fm;
t = (tMin:tDelta:tMax)';

tDisplay = 2;
numSteps = 10*duracio/tDisplay;

%% DETECCIÓN DE LATIDOS
marques = detecrc(ecg1);

% Eliminamos falsas detecciones


marques(611) = [];
numMarques = length(marques);

% Calculamos las duraciones de los batidos (en segundos)


duracions = diff(marques/fm);

% Calculamos el ritmo cardíaco en latidos/minuto

63
ritmes = 60./duracions;

%% DIBUJAR SEÑALES
fig(1) = dibuixar_senyals([normECG normPsan], fm, {'ECG', 'PSan'},
marques, [0 0 0]);

%% DIBUJAR RITMO CARDÍACO


fig(2) = figure;
subplot(2,1,1);
plot(ritmes, 'Color', [.8 .2 .2], 'LineWidth', 2);
axis tight;
ylabel('ritme (batecs/min)');
xlabel('batecs');
title('Deteccio de batecs a partir de l''ona R');

subplot(2,1,2);
plot(marques(1:end-1)/fm, ritmes, 'Color', [.8 .2 .2], 'LineWidth', 2);
axis tight;
ylabel('ritme (batecs/min)');
xlabel('temps (s)');

function hFig = dibuixar_senyals(senyals, fm, noms, marques, colorMarques,


hFig)

% dibuixarSenyals Dibuixa senyals i marques en una figura


%
% hFig = dibuixar_senyals(senyals, fm, noms, marques, colorMarques,
hFig)
%
% Exemple:
%
% senyal1 = randn(100000,1);
% senyal2 = randn(100000,1);
% marques1 = (15:150:10000)';
% marques2 = (30:300:10000)';
% fm = 100;
%
% senyals = [senyal1 senyal2];
% fig = dibuixar_senyals(senyals, fm, {'S1','S2'}, marques1, [1 0 0]);
%
% % Afegim mes marques a la figura (nomes es permet afegir marques)
% fig = dibuixarSenyals([], fm, [], marques2, [0 0 1], fig);
%
% NOTA: NOMES FUNCIONA AMB MATLAB R2014B O MES RECENT.
%
%
% HISTORIAL
% ---------
% CREAT: Joan F. Alonso, 2015.10.25
%
% REVISAT: Joan F. Alonso, 2015.10.27
% CANVIS: - Ajust automatic de la mida dels elements de la figura.
% - Desplacament amb la roda del ratoli
% - Ajuda i exemple
%

%% INICIALITZACIO I GESTIO DELS ARGUMENTS

64
narginchk(0,6); % Comprovem que s'ha cridat la funcio usant entre 0 i
6 arguments d'entrada
nargoutchk(0,1); % Comprovem que s'ha cridat la funcio usant cap o 1
argument de sortida

if verLessThan('matlab', '8.4')
help dibuixar_senyals
hFig = NaN;
return;
end

tempsVisible = 5; % segons de senyal que es mostren a la figura


midaPantalla = get(groot, 'ScreenSize');
midaY = fix(.45*midaPantalla(4));
midaX = fix(.85*midaPantalla(3));

if nargin < 2
help dibuixarSenyals
hFig = NaN;
return;
end

[numMostres, numSenyals] = size(senyals);


if isscalar(fm) && fm > 0
temps = (0:numMostres-1)/fm;
else
help dibuixar_senyals
hFig = NaN;
return;
end

if nargin < 3
noms = [];
end

if nargin < 4
marques = [];
end

if nargin < 5
colorMarques = [0 0 0]; % Color negre per defecte
end

if nargin < 6
% Figura
hFig = figure(...
'Name',' Revisio de senyals', ...
'NumberTitle', 'off', ...
'DockControls','off', ...
'Position', centra_figura(midaX, midaY), ...
'MenuBar', 'none', ...
'ToolBar', 'none', ...
'Units', 'pixels');
[Link] = @ajusta_mida; % No ho fem a la definicio
anterior
% per evitar errors (ajusta_mida
fa servir hFig)
[Link] = @scroll;

65
% Eixos
hAx = axes(...
'Units', 'pixels', ...
'FontSize', 9, ...
'Ytick', [], ...
'Position', [10 70 midaX-15 midaY-100], ...
'Box', 'On', ...
'Visible', 'On', ...
'SortMethod', 'ChildOrder', ...
'NextPlot', 'Add', ...
'Layer', 'Top', ...
'XMinorTick', 'On', ...
'Parent', hFig);
title(hAx, 'P3 Lab PSB', 'FontWeight', 'Bold', 'FontSize', 11);
xlabel('temps (s)');

if numSenyals > 0
[Link] = [min(min(senyals)) max(max(senyals))] + [-0.1
0.1]*(max(max(range(senyals))));

% Slider horitzontal
hSlider = uicontrol('Style', 'slider', ...
'Min', temps(1), ...
'Max', temps(end)-tempsVisible, ...
'Value', temps(1), ...
'SliderStep', [0.5*tempsVisible tempsVisible]/(numMostres/fm), ...
'Units', 'pixels', ...
'Position', [10 5 midaX-15 15]);
[Link] = temps(1)+[0 tempsVisible]; % Ajustem l'eix horitzontal
visible

% Creem un 'listener' que executara una funcio cada vegada que


canvii 'Value'
addlistener(handle(hSlider), 'Value', 'PostSet',
@ajusta_eix_horitzontal);
end
else
% Recuperem els eixos de la figura ja existent. No cal regenerar
% l'Slider. L'escala vertical es manté.
hAx = findobj(hFig, 'Type', 'Axes');
end

%% DIBUIXEM ELS SENYALS


if numSenyals > 0
plot(temps, senyals, ...
'LineWidth', 1.25, ...
'Parent', hAx);
end
if not(isempty(noms))
if verLessThan('matlab', '9.2')
legend(noms);
else
legend(noms, 'AutoUpdate', 'Off');
end
end

%% DIBUIXEM LES MARQUES

66
if not(isempty(marques))
plot([marques(:) marques(:)]'/fm, ...
repmat([Link]', 1, length(marques(:))), ...
'Color', colorMarques, ...
'LineStyle', '-');
text((marques/fm)+(0.01*mean(diff(marques)))/fm, ...
repmat([Link](2)-([Link](2)-[Link](1))*.05, size(marques)),
...
cellstr(num2str((1:length(marques))')), ...
'Color', colorMarques);
end
drawnow;

%% CALLBACKS
function ajusta_eix_horitzontal(~, evData)
[Link] = [Link]+[0 tempsVisible];
end

function ajusta_mida(~,~)
[Link] = [10 5 [Link](3)-15 15];
[Link] = [10 70 [Link](3)-15 [Link](4)-100];
end

function scroll(~, evData)


if [Link] > 0
[Link] = max([Link]-tempsVisible/2, [Link]);
elseif [Link] < 0
[Link] = min([Link]+tempsVisible/2, [Link]);
end
end

%% FUNCIONS AUXILIARS
function pos = centra_figura(midaX, midaY)
screenSize = get(0, 'ScreenSize');
pos = [ceil((screenSize(3)-midaX)/2) ceil((screenSize(4)-midaY)/2),
midaX, midaY];
end

end

%presiondiástole%
for i = 1:length(marques)-1
pdias(i) = min(psan(marques(i):marques(i+1)));
end

figure;
plot(pdias)
xlabel('Latido')
ylabel('Presión diastólica (mmHg)')
title('Presión diastólica durante el registro')

%presiónpulso%
pp = psis - pdias;

figure;
plot(pp)
xlabel('Latido')
ylabel('Presión de pulso (mmHg)')

67
title('Presión de pulso durante el registro')

%MAP%
MAP = pp/3 + pdias;

figure;
plot(MAP)
xlabel('Latido')
ylabel('Presión arterial media (mmHg)')
title('Presión arterial media durante el registro')

%apartado c%

for i = 1:length(marques)-1
[psis(i), idx_max(i)] = max(psan(marques(i):marques(i+1)));
marquessistole(i) = marques(i) + idx_max(i) - 1;

[pdias(i), idx_min(i)] = min(psan(marques(i):marques(i+1)));


marquesdiastole(i) = marques(i) + idx_min(i) - 1;
end

% Cálculo por presiones sistólicas


difsistole = diff(marquessistole); % Diferencia entre marcas
sistólicas

pregsist = length(psan) ./ difsistole; % Pulsos totales durante el


registro
pminsist = pregsist ./ 20; % Pulsos por minuto

pulsossistole = mean(pminsist); % Valor medio de pulsos/minuto


pulsossistole

% Cálculo por presiones diastólicas


difdiastole = diff(marquesdiastole); % Diferencia entre marcas
diastólicas

pregdias = length(psan) ./ difdiastole; % Pulsos totales durante el


registro
pmindias = pregdias ./ 20; % Pulsos por minuto

pulsosdiastole = mean(pmindias); % Valor medio de pulsos/minuto


pulsosdiastole

figure;
plot(pminsist)
hold on
plot(pmindias)
xlabel('Pulso')
ylabel('Pulsos por minuto')
title('Pulso cardíaco calculado a partir de presiones sistólicas y
diastólicas')
legend('Pulso por presión sistólica', 'Pulso por presión diastólica')

%apartado e%

% Selección de una onda T representativa


ondat = ecg1(660:708);

% Correlación cruzada entre la onda T y el ECG completo

68
correlacion = xcorr(ondat, ecg1);

% Detección de los máximos de la onda T


marcast = detecrc(correlacion);

% Cálculo del retardo entre onda T y presión sistólica


retardot = marcast - marquessistole;
retardot = retardot ./ 250;

retardot_medio = abs(mean(retardot(:)));
retardot_medio

%retardo%
retardoindices = marquessistole - marques;
retardos = retardoindices ./ 250;

retardorsist = abs(mean(retardos(:)));
retardorsist

69
B. SEÑAL DE PRESIÓN SANGUÍNEA Y SONIDOS DE KOROTKOFF
% Gráficos de sonidos de Korotkoff, ECG y Presión
clear all
clc
load [Link] % Se cargan los datos del archivo [Link]
fm = 500 ; %Frecuencia de muestreo

% GENERACIÓN DE GRÁFICOS PARA CADA SEÑAL


% A = eje de tiempo para la señal ECG
% B = eje de tiempo para la señal de presión
% C = eje de tiempo para los sonidos de Korotkoff
A= 1/fm:1/fm:length(ecg2)/fm ;
subplot(3,1,1),plot(A,ecg2,'r'),title("ECG"),xlabel("tiempo(s)"),ylabel('mV');
B= 1/fm:1/fm:length(pressio)/fm ;
subplot(3,1,2),plot(B,pressio,'b'),title("pression"),xlabel("tiempo(s)"),ylabel('mm
Hg');
C= 1/fm:1/fm:length(sons)/fm;
subplot(3,1,3),plot(C,sons,'g'),title("Sonidos de
Korotkoff"),xlabel("tiempo(s)"),ylabel('mV');

%SUPERPOSICIÓN DE PRESIÓN Y KOROTKOFF


figure(2)
% Utilizamos yyaxis para crear dos escalas diferentes en el mismo gráfico
yyaxis left
plot(C, sons, 'Color', [0 0.4470 0.7410]); % Azul para los sonidos (escala
izquierda)
ylabel('Sonido [mV]');
ylim([-3 3]);
yyaxis right
plot(B, pressio, 'Color', [0.8500 0.3250 0.0980]); % Naranja para la presión
(escala derecha)
ylabel('Presión [mmHg]');
ylim([-20 200]);
title("Superposición Presión sanguínea y Sonidos de Korotkoff");
xlabel('Tiempo (s)');
grid on;

%SUPERPOSICIÓN DE ECG VS SONIDOS DE KOROTKOFF


figure(3)
hold on
plot(A,2*ecg2,'r'); % Se amplifica el ECG para mejor visualización
plot(C,sons,'g');
title("ECG vs Sonidos de korotkoff");
legend('ECG','korotkoff');
xlabel('tiempo(s)');
hold off

%GRÁFICO AMPLIADO (ZOOM) EN UN RANGO DESEADO


figure(4)
hold on
plot(A,2*ecg2,'r');
plot(C,sons,'g');
title("ECG y korotkoff ampliado");
legend('ECG','korotkoff');
xlim([6 14]);
xlabel('tiempo(s)');
hold off

%VISUALIZACIÓN DE RUIDO Y ARTEFACTOS


figure(5)
hold on
plot(A,2*ecg2,'r');
plot(C,sons,'g');
title("ECG y ruidos de korotkoff");
legend('ECG','korotkoff');
xlim([16 32]);

70
xlabel('tiempo(s)');
hold off

%LIMPIEZA Y FILTRADO DE LA SEÑAL (SIN TOOLBOX)


Fs = 500;
% 1. Aplicación de umbral: Se establece en 0.8 mV para eliminar ruidos de baja
amplitud
umbral_filtrado = 0.8;
sonidos_finales = sons;
sonidos_finales(abs(sons) < umbral_filtrado) = 0;
% 2. Suavizado: Media móvil para reducir la brusquedad de los picos
tamano_ventana = 5;
sonidos_finales = conv(sonidos_finales, ones(1,tamano_ventana)/tamano_ventana,
'same');

%GENERACIÓN FIGURA 6: COMPARATIVA FILTRADO


figure(6)
t_sonidos_eje = (1:length(sons))/fm;
subplot(2,1,1)
plot(t_sonidos_eje, sons)
title('Sonidos de Korotkoff sin filtrar')
ylabel('Ruido (dB)')
grid on; xlim([0 150]); ylim([-4 4])
subplot(2,1,2)
plot(t_sonidos_eje, sonidos_finales)
title(['Sonidos de Korotkoff filtrados (Umbral ', num2str(umbral_filtrado), '
mV)'])
xlabel('Tiempo (s)')
ylabel('Ruido (dB)')
grid on; xlim([0 150]); ylim([-2.5 2.5])

%IDENTIFICACIÓN DE PICOS DE SONIDO


umbral_pico = 0.5;
distancia_minima = round(fm * 0.2); % Distancia mínima entre latidos (0.2s)
senal_absoluta = abs(sonidos_finales);
posiciones_picos = [];
amplitud_picos = [];
for i = 2:length(senal_absoluta)-1
% Verificación de máximo local y superación de umbral
if senal_absoluta(i) > senal_absoluta(i-1) && senal_absoluta(i) >
senal_absoluta(i+1) && senal_absoluta(i) > umbral_pico
if isempty(posiciones_picos) || (i - posiciones_picos(end) > distancia_minima)
posiciones_picos = [posiciones_picos, i];
amplitud_picos = [amplitud_picos, sonidos_finales(i)];
end
end
end

% FIGURA DE POSICIÓN DE RUIDOS


figure(7)
plot(sonidos_finales, 'Color', [0.6, 0.8, 1.0])
hold on
plot(posiciones_picos, amplitud_picos, 'v', 'MarkerEdgeColor', 'g',
'MarkerFaceColor', 'g', 'MarkerSize', 6)
title(['Posición ruidos de Korotkoff', newline, 'Total sonidos: ',
num2str(length(amplitud_picos))])
legend('Sonidos de Korotkoff', 'Posición')
grid on
xlabel('Muestras')
ylabel('Ruido (dB)')
ylim([-2.5 2.5])
hold off

%CÁLCULO DE PRESIONES SISTÓLICA Y DIASTÓLICA


ruido_id = 1:7;
% Valores extraídos del análisis de presión

71
P_sistolica = [128.6210, 113.4770, 111.8190, 115.4730, 118.0670, 118.8100,
108.0320];
P_diastolica = [68.2890, 68.0990, 25.8490, 68.0370, 68.8380, 69.8290, 68.6820];
% Creación de tabla de resultados para visualización en consola
TablaResultados = table(ruido_id', P_sistolica', P_diastolica', ...
'VariableNames', {'Ruido', 'P_sistolica_mmHg', 'P_diastolica_mmHg'});
fprintf('RESULTADOS ANÁLISIS KOROTKOFF');
disp(TablaResultados);

%GRÁFICO DE EVOLUCIÓN DE PRESIONES


figure(8);
hold on; grid on;
% Sistolica (Azul)
plot(ruido_id, P_sistolica, '-o', 'Color', [0 0.447 0.741], 'LineWidth', 2, ...
'MarkerFaceColor', 'w', 'DisplayName', 'Presión sistólica');
% Diastolica (Naranja)
plot(ruido_id, P_diastolica, '-o', 'Color', [0.85 0.325 0.098], 'LineWidth', 2, ...
'MarkerFaceColor', 'w', 'DisplayName', 'Presión diastólica');
title('PRESIÓN SISTÓLICA vs DIASTÓLICA');
xlabel('Ruidos de Korotkoff');
ylabel('Presión (mmHg)');
legend('Location', 'northeast');
xlim([1 7]);
ylim([0 130]);
set(gca, 'XTick', 1:7);
hold off;

%%ANÁLISIS DE RETARDOS (ONDA R Y ONDA T)


% 1. Filtrado para detección de sonidos
umbral_sonidos = 0.2;
sonidos_filtrados = sons;
sonidos_filtrados(abs(sons) < umbral_sonidos) = 0; % Elimina el ruido por debajo
del umbral
% 2. Detección de picos R en el ECG
umbral_R = 0.5;
distancia_min_R = 200;
latidos_R = [];
for k = 2:length(ecg2)-1
if ecg2(k) > umbral_R && ecg2(k) > ecg2(k-1) && ecg2(k) > ecg2(k+1)
if isempty(latidos_R) || (k - latidos_R(end)) > distancia_min_R
latidos_R(end+1) = k;
end
end
end
% 3. Cálculo del retardo Onda R -> Sonido
localizaciones_R = latidos_R;
indices_sonidos_on = find(sonidos_filtrados > 0);
if ~isempty(indices_sonidos_on)
marcas_inicio_sonido = indices_sonidos_on(diff([0; indices_sonidos_on]) > 50);
else
marcas_inicio_sonido = [];
end
retardo_R_sonido = [];
i_ptr = 1; j_ptr = 1;
while i_ptr <= length(marcas_inicio_sonido) && j_ptr <= length(localizaciones_R)
diff_tiempo = (marcas_inicio_sonido(i_ptr) - localizaciones_R(j_ptr)) / 500; %
Conversión a segundos
if diff_tiempo < 0
i_ptr = i_ptr + 1;
elseif diff_tiempo > 0.40
j_ptr = j_ptr + 1;
else
retardo_R_sonido(end+1) = diff_tiempo;
i_ptr = i_ptr + 1;
j_ptr = j_ptr + 1;
end

72
end
% 4. GRÁFICO FINAL (FIGURA 9)
figure(9);
plot(retardo_R_sonido, 'LineWidth', 1.5);
title('Evolución del retardo entre la onda R y los ruidos de Korotkoff');
xlabel('Número del ruido');
ylabel('Tiempo de retardo [s]');
grid on;
if ~isempty(retardo_R_sonido)
xlim([0 40]);
ylim([0.05 0.4]);
end
% 5. ANÁLISIS FINAL: RETRASO DE LA ONDA T Y ELIMINACIÓN DE LA ONDA R
ecg_sin_R = ecg2;
for k = 1:length(latidos_R)
idx_R = latidos_R(k);
ventana_R = max(1, idx_R-15):min(length(ecg2), idx_R+15);
ecg_sin_R(ventana_R) = 0;
end
% 6. Detección manual de ondas T
posiciones_T = [];
umbral_T = 0.05;
dist_min_T = 200;
for k = 2:length(ecg_sin_R)-1
if ecg_sin_R(k) > umbral_T && ecg_sin_R(k) > ecg_sin_R(k-1) && ecg_sin_R(k) >
ecg_sin_R(k+1)
if isempty(posiciones_T) || (k - posiciones_T(end)) > dist_min_T
posiciones_T(end+1) = k;
end
end
end
% 7. Cálculo del retardo Onda T -> Sonido
retardo_T_sonido = [];
i_ptr = 1; j_ptr = 1;
while i_ptr <= length(marcas_inicio_sonido) && j_ptr <= length(posiciones_T)
diff_T = (marcas_inicio_sonido(i_ptr) - posiciones_T(j_ptr)) / fm;
if diff_T < 0
i_ptr = i_ptr + 1;
elseif diff_T > 0.40
j_ptr = j_ptr + 1;
else
retardo_T_sonido(end+1) = diff_T;
i_ptr = i_ptr + 1;
j_ptr = j_ptr + 1;
end
end
% 8. GRÁFICOS FINALES DE ONDA T
% Figura 10: ECG sin onda R
figure(10);
plot((1:length(ecg_sin_R))/fm, ecg_sin_R);
title('Señal cardíaca sin onda R');
xlabel('Tiempo (s)'); ylabel('mV');
xlim([10 14]); grid on;
% Figura 11: Evolución del retraso de la onda T
figure(11);
if ~isempty(retardo_T_sonido)
% Se grafica el retardo con línea roja y marcadores circulares blancos
plot(retardo_T_sonido, 'r-o', 'LineWidth', 1.5, 'MarkerFaceColor', 'w');
title('Evolución del retardo entre la onda T y ruidos de Korotkoff');
xlabel('Número del ruido'); ylabel('Tiempo de retardo [s]');
grid on;
% Se ajustan los límites del eje Y para visualizar mejor las variaciones
térmicas/fisiológicas
ylim([min(retardo_T_sonido)*0.8, max(retardo_T_sonido)*1.2]);
end

73
% PARTE FINAL: ANÁLISIS DE LA ONDA T Y RETARDOS (FIG 12)
% 1. Creación de la señal sin onda R (Fig 12)
% Eliminamos los picos R de la señal ECG original para permitir que las
% ondas T (de menor amplitud) sean detectables más fácilmente.
ecg_sin_R_final = ecg2;
for k = 1:length(latidos_R)
idx_R = latidos_R(k);
% % Se pone a cero una pequeña ventana (40 muestras aprox.) alrededor de cada pico
R
ventana_limpieza = max(1, idx_R-20):min(length(ecg2), idx_R+20);
ecg_sin_R_final(ventana_limpieza) = 0;
end
% 2. Detección manual de las ondas T (sin usar la función findpeaks)
posiciones_T_final = [];
umbral_T_final = 0.04; % Umbral mínimo para identificar la deflexión de la onda T
dist_min_T_final = 200; % Distancia mínima entre ondas T consecutivas (basada en
fm=500)
for k = 2:length(ecg_sin_R_final)-1
% Se busca un máximo local que supere el umbral establecido
if ecg_sin_R_final(k) > umbral_T_final && ecg_sin_R_final(k) > ecg_sin_R_final(k-1)
&& ecg_sin_R_final(k) > ecg_sin_R_final(k+1)
% Verificación de distancia para evitar falsos positivos en una misma onda
if isempty(posiciones_T_final) || (k - posiciones_T_final(end) > dist_min_T_final)
posiciones_T_final(end+1) = k;
end
end
end
% 3. Cálculo del retardo entre la onda T y los ruidos de Korotkoff
retardo_T_final = [];
i_ptr = 1; j_ptr = 1;
while i_ptr <= length(marcas_inicio_sonido) && j_ptr <= length(posiciones_T_final)
% Cálculo de la diferencia de tiempo convirtiendo muestras a segundos
diff_T_calc = (marcas_inicio_sonido(i_ptr) - posiciones_T_final(j_ptr)) / fm;
if diff_T_calc < 0
% Si el ruido aparece antes que la onda T, pasamos al siguiente ruido
i_ptr = i_ptr + 1;
elseif diff_T_calc > 0.45
%Si el retardo es excesivo (>0.45s), se considera que la onda T
% corresponde a un latido anterior; pasamos a la siguiente onda T.
j_ptr = j_ptr + 1;
else
% Retardo válido encontrado dentro del rango fisiológico
retardo_T_final(end+1) = diff_T_calc;
i_ptr = i_ptr + 1;
j_ptr = j_ptr + 1;
end
end
% FIGURA 12: Visualización final del retardo de la onda T
figure(12);
if ~isempty(retardo_T_final)
plot(retardo_T_final, 'LineWidth', 1.5);
title('Retardo entre la onda T y los ruidos de Korotkoff');
xlabel('Número del ruido'); ylabel('Retardo [s]');
grid on;
xlim([0 45]);
ylim([0 0.45]);
end

74
C. SEÑAL VOLUMEN SANGUÍNEO

% Detecció de marques d'ona R


marques = detecrc(ecg3);

% Càlcul de diferències entre marques


difmarques = diff(marques);

% Càlcul de batecs per minut (ajustant per la durada de 45s)


rcmuestra = length(ecg3)./difmarques;
latmin = rcmuestra.*(4/3);

% Resultat promig
mean(latmin)

unction [maximos, minimos, valorpp] = detecmaxmin(senyal, marques)


intervalos = diff(marques);
contador = 0;
for j = 1:length(intervalos)
contador = contador + 1;
% S'extreu el segment de senyal entre dues marques R
vector = senyal(marques(j):marques(j+1));
% Càlcul de paràmetres
maximos(contador,1) = max(vector);
minimos(contador,1) = min(vector);
valorpp(contador,1) = maximos(contador,1) - minimos(contador,1);
end
end

function latmin = deteclmin(senyal, marques)


intervalos = diff(marques);
contador = 0;
for j = 1:length(intervalos)
contador = contador + 1;
vector = senyal(marques(j):marques(j+1));

% Es busca l'índex on el senyal és màxim


indices(contador,1) = find(senyal == max(vector));
end
difindices = diff(indices);
latmin = (length(senyal)./difindices).*(4/3);
end

% 'marques' són els índexs R, 'indices' són els màxims de pols


retardo = abs([marques - indices]);
retardo = retardo./200;
mean(retardo)

% Aislamiento manual d'una onda T representativa


ondat = ecg3(6256:6301);
% Correlación per encontrar todas les ondes T
correlacion = xcorr(ondat, ecg3);
cor = correlacion(1:9000);
marcast = detecrc(cor);

75
% Cálculo del retardo
retardot = abs([marcast - indices]);
retras = retardot./200;
mean(retras)

D. ANALISIS FRECUENCIAL DE LOS SONIDOS DE KOROTKOFF

76
77
78
ANALISIS DE SEÑALES PROPORCIONADAS POR ATENEA
%% Apartado A)
load [Link]

Fs = 1/(isi*1e-3)
t = (0:size(data,1)-1)/Fs;

presion = data(:,1);
korotkoff = data(:,2);
ecg = data(:,3);

% Visualizamos las señales proporcionadas


figure
subplot(3,1,1)
plot(t, presion)
title('Presión sanguínea')
ylabel('mmHg')
grid on
subplot(3,1,2)
plot(t, korotkoff)
title('Sonidos de Korotkoff')
ylabel('mV')
grid on
subplot(3,1,3)
plot(t, ecg)
title('ECG')
ylabel('mV')

79
xlabel('Tiempo (s)')
grid on

%% Apartado B)
%% Dominio temporal
Ns = 2000;

figure
subplot(3,1,1)
plot(t(1:Ns), presion(1:Ns))
title('Presión sanguínia (dominio temporal)')
ylabel('mmHg')
grid on

subplot(3,1,2)
plot(t(1:Ns), korotkoff(1:Ns))
title('Sonidos de Korotkoff (dominio temporal)')
ylabel('mV')
grid on

subplot(3,1,3)
plot(t(1:Ns), ecg(1:Ns))
title('ECG (dominio temporal)')
ylabel('mV')
xlabel('Tiempo (s)')
grid on

%% Domini freqüencial
% Pressió sanguínia
presion_dc = presion - mean(presion);

N = length(presion_dc);
N2 = floor(N/2);
f = (0:N2-1)*(Fs/N);
P_FFT = abs(fft(presion_dc)).^2;

figure
plot(f(1:N/2), 10*log10(P_FFT(1:N/2)))
xlabel('Frecuencia (Hz)')
ylabel('Energía (dB)')
title('Espectro de la presión sanguínia')
grid on

% Sons Korotkoff
kor_dc = korotkoff - mean(korotkoff);

N = length(kor_dc);
N2 = floor(N/2);

f = (0:N2-1)*(Fs/N);
K_FFT = abs(fft(kor_dc)).^2;

figure
plot(f(1:N2), 10*log10(K_FFT(1:N2)))
xlabel('Frecuencia (Hz)')

80
ylabel('Energía (dB)')
title('Espectro de los sonidos de Korotkoff')
grid on

% ECG
ecg_dc = ecg - mean(ecg);

N = length(ecg_dc);
N2 = floor(N/2);

f = (0:N2-1)*(Fs/N);
ECG_FFT = abs(fft(ecg_dc)).^2;

figure
plot(f(1:N2), 10*log10(ECG_FFT(1:N2)))
xlabel('Frecuencia (Hz)')
ylabel('Energía (dB)')
title('Espectro del señal ECG')
grid on

%% APARTADO C) Filtrado y acondicionamiento de la señal


% Filtrado de la presión sanguínea
fc = 15; % Diseño del filtro pasa-baja
Wn = fc/(Fs/2);
[b_p, a_p] = butter(4, Wn, 'low');

presion_filt = filtfilt(b_p, a_p, presion);

Ns = 10000;

figure
plot(t(1:Ns), presion(1:Ns), '--b','LineWidth', 1.5)
hold on
plot(t(1:Ns), presion_filt(1:Ns), 'r')
xlabel('Tiempo (s)')
ylabel('mmHg')
title('Presión sanguínea antes y despues del filtrado')
legend('Original','Filtrada')
grid on

% Filtrado de los sonidos de Korotkoff


f_low = 25;
f_high = 150;
Wn = [f_low f_high] / (Fs/2);

[b_k, a_k] = butter(4, Wn, 'bandpass');


kor_filt = filtfilt(b_k, a_k, korotkoff);

Ns = 2000; % 0.4 s

figure
plot(t(1:Ns), korotkoff(1:Ns), 'b')
hold on
plot(t(1:Ns), kor_filt(1:Ns), 'r')
xlabel('Tiempo (s)')
ylabel('mV')
title('Sonidos de Korotkoff antes y despues del filtrado')
legend('Original','Filtrat')
grid on

81
envolvente = abs(hilbert(kor_filt)); % Añadimos envolvente

figure
plot(t(1:Ns), envolvente(1:Ns))
xlabel('Tiempo (s)')
ylabel('Amplitud')
title('Envolvente dels sonidos de Korotkoff')
grid on

%% Analisis señales reales


% Analisis del señal ECG
ecg_sig = ecg;

[pk_R, loc_R] = findpeaks(ecg_sig, Fs,'MinPeakHeight',


0.3*max(ecg_sig),'MinPeakDistance', 0.4);

figure
plot(t, ecg_sig)
hold on
plot(loc_R, pk_R, 'ro')
xlabel('Tiempo (s)')
ylabel('mV')
title('Detección de picos R en el señal ECG')
grid on

RR = diff(loc_R) % Intervalos RR
FC_inst = 60 ./ RR % Frecuencia cardíaca instantanea
FC_mitjana = mean(FC_inst) % Frecuencia cardíaca media

figure
plot(FC_inst)
xlabel('Latido')
ylabel('Frecuencia cardíaca (bpm)')
title('Frecuencia cardíaca instantanea')
grid on

% Analisis de la presión sanguínea


[pks_sys, loc_sys] = findpeaks(presion_filt, Fs, 'MinPeakDistance', 0.5);

[pks_dia, loc_dia] = findpeaks(-presion_filt, Fs,'MinPeakDistance', 0.5);


pks_dia = -pks_dia;

P_sistolica = max(pks_sys)

figure
plot(t, presion_filt)
hold on
plot(loc_sys, pks_sys, 'ro')
plot(loc_dia, pks_dia, 'go')
xlabel('Tiempo (s)')
ylabel('mmHg')
title('Detección de presión sistolica i diastolica')
legend('Presión filtrada','Sistolica','Diastolica')
grid on

% Anàlisi sons Korotkoff


[~, idx_max] = max(presion_filt);

82
envolvente_des = envolvente(idx_max:end);
presion_des = presion_filt(idx_max:end);
t_des = t(idx_max:end);

threshold = 0.4 * max(envolvente_des);


sons_des = envolvente_des > threshold;

idx_sons = find(sons_des);
idx_inici = idx_sons(1);
idx_final = idx_sons(end);
t_inici = t_des(idx_inici);
t_final = t_des(idx_final);

P_sistolica_real = presion_des(idx_inici)
P_diastolica_real = presion_des(idx_final)

figure
plot(t, presion_filt)
hold on
xline(t_inici, '--r', 'Inicio Korotkoff')
xline(t_final, '--g', 'Final Korotkoff')
xlabel('Tiempo (s)')
ylabel('mmHg')
title('Determinación de la presión sistolica y diastolica mediante
Korotkoff')
legend('Presión filtrada','Sistolica','Diastolica')
grid on

83

También podría gustarte