Librería Arduino para monitorización de la frecuencia cardíaca con oxímetro de pulso

Librería Arduino para monitorización de la frecuencia cardíaca con oxímetro de pulso

Librería Arduino para monitorización de la frecuencia cardíaca con oxímetro de pulso

Uno de los parámetros que se monitorizan en mi proyecto de gestión del sueño

es el pulso. Para medirlo desarrollé un dispositivo basado en el comportamiento de la hemoglobina y la oxihemoglobina frente a las diferentes longitudes de onda de la luz. Básicamente se trata de medir cuánta luz de determinado tipo es capaz de atravesar o es reflejada en una zona del cuerpo bien irrigada. La frecuencia con la que ocurre un ciclo completo de este fenómeno permite medir el pulso.

Tabla de contenidos

    En la fase de diseño y prueba del dispositivo para medir el pulso desarrollé algunos pequeños programas para ayudarme a verificar que el montaje era correcto. En primer lugar escribí el código de abajo, que iba tomando los valores medidos cada cierto tiempo (como mínimo cada TIEMPO_MAXIMO_MEDIDA y como máximo cada TIEMPO_MINIMO_MEDIDA) cuando variaban un mínimo entre uno y el anterior (el valor que corresponde con MEDIDA_MINIMA) y los monitorizaba desde un ordenador con una aplicación en Python para poder analizarlos posteriormente.

    Una vez ajustados los valores (empezando en medidas muy densas) conseguí una colección de valores del oxímetro de pulso a lo largo del tiempo que podía representar gráficamente utilizando una hoja de cálculo, LibreOffice Calc de LibreOffice, en concreto.

    gráfica de las medidas del oxímetro de pulso con  de

    Con los datos recabados, como representa la imagen de arriba, la siguiente operación era determinar si la densidad de valores permitía calcular de manera fiable pero «económica» (no muestrear más de los datos necesarios) el valor del pulso; como puede verse en el gráfico de abajo, las medidas tomadas parecían servir para obtener los resultados que es razonable esperar.

    .

    medida de la presencia de oxihemoglobina a lo largo del tiempo con un oxímetro de pulso

    A continuación, con la información del muestreo de datos, quedaba elaborar un algoritmo que midiera la frecuencia del pulso. Ateniéndose a la gráfica que, por simplificar, se asume que representa un trazado similar al complejo QRS, lo más sencillo parece medir los tiempos entre las partes más destacadas, con valores mayores (que corresponde con la zona qRs de despolarización de los ventrículos) descartando la zona más plana y «ruidosa», más difícil de medir, por tanto. La solución adoptada, que corresponde con el código de prueba de abajo, funciona conforme al siguiente procedimiento:

    • Detectar la zona que se está midiendo en cada caso para atender sólo a los picos de valor qRs y desechar el valle. Para hacerlo se podrían medir valores superiores a cierta constante pero existe el riesgo de que un individuo y/o unas circunstancias que, aunque proporcionalmente, subieran o bajaran los valores. Para evitarlo, se considera un valor en la zona mayor al que supera en cierto coeficiente al valor medio. De esta forma, la medida se auto-calibra sensiblemente y se podría ajustar aún más afinando el coeficiente, que en mi caso he conseguido experimentalmente durante las pruebas.

      Elegir para la medida los valores de la zona descendente (Rs) del pico qRs, lo más cercanos posible al máximo de la curva. Para saber que se abandona la zona ascendente basta con comprobar que un nuevo valor es menor que el anterior y verificar que no se ha encontrado todavía el valor buscado puesto que, en general, hay varios valores en la zona descendente de qRs dependiendo de la densidad de muestreo. Para cronometrar el pulso se almacena el valor del instante en el que se encontró el punto (los milisegundos devueltos por millis()) y se compara con el siguiente.

      Para asegurarse de que el valor que se mide es el mayor de la zona descendente de la curva más alta se usa una variable booleana (medir_pulso en este ejemplo y medicion_de_pulso_activa en la librería) que se activa al entrar en la zona ascendente de la curva mayor y se desactiva una vez encontrado el primer valor descendente, que es el cronometrado.

      Como lo habitual es representar la duración del pulso como pulsaciones por minuto (ppm) se corrige el valor de tiempo entre pulsaciones obtenido calculando dividiendo el tiempo total de la representación (un minuto, 60000 milisegundos) entre el intervalo obtenido al restar los milisegundos actuales (del valor actual) entre los anteriormente cronometrados.

      Para evitar medidas falsas (como el dispositivo midiendo en vacío, por ejemplo) se verifica que el resultado se encuentra entre unos valores máximos y mínimos antes de darlo por cierto. Aunque se considera como media que un valor normal para un adulto sano en reposo se encuentra entre 60 y 100 ppm, hay valores admisibles por debajo, es fácil encontrar 40 ppm en un atleta en reposo, hasta 200 ppm sometido a un ejercicio intenso y más de 100 ppm en adultos sedentarios en estados de excitación, precisamente un factor interesante para el proyecto de gestión del sueño que me lleva a desarrollar este dispositivo de medición del pulso. Por esto, es recomendable relajar mucho estos valores de manera que no se pierdan los extremos, que precisamente podrían mostrar aspectos relevantes.

      El nuevo valor medio se calcula disminuyendo la relevancia de la media actual en función del número de valores muestreados y se añade el último valor, ponderado también con un coeficiente que lo reduce más cuanto más valores se hayan medido hasta el momento.

    Por último, utilizando el algoritmo descrito antes, desarrollé la librería para calcular el pulso detectando la presencia de la hemoglobina o la oxihemoglobina (según la longitud de onda de la luz usada) del código de abajo.

    La librería espera que se llame periódicamente a la función de muestreo monitorizar_pulso() para ir calculando el pulso, que puede consultarse con la función ultimo_pulso() o con la función pulso_medio() el pulso medio. Además de por ser un recurso limitado, descarté utilizar interrupciones por no necesitar valores inmediatos sino sostenidos en el tiempo para monitorizar el pulso en mi proyecto de gestión del sueño

    . En cualquier caso, por las pruebas que he hecho, no parece ser necesario; ya sea por el dispositivo o por el comportamiento del pulso, un muestreo a determinada frecuencia ofrece suficiente información y no se obtiene mucha más (relevante) por aumentarlo ni es posible disminuirla mucho sin perder datos relevantes para el cálculo; en las primeras versiones del código para monitorizar la lectura del oxímetro de pulso descubrí que no era necesario atenerse a un tiempo de medida máximo ya que, si se consideraban correctamente las variaciones de valores sucesivos, era muy cercano al mínimo.

    En el siguiente programa de ejemplo se muestra cómo utilizar la librería anterior para medir el pulso con un oxímetro de pulso. Además de instanciar la clase Pulso se llama periódicamente a la monitorización del nivel de oxihemoglobina/hemoglobina y con una periodicidad menor se muestra el valor del pulso calculado y de la media.

    Para asegurar que las medidas son relevantes se programa una espera antes de mostrar ningún valor. Como el valor puede ser incorrecto (por ejemplo si el usuario se retira el dispositivo) sólo se muestran valores si están dentro del rango de los considerados válidos.

    Puede que te hayas perdido