Если вы недавно посетили врача, скорее всего, медсестра проверила ваши основные жизненно важные функции. Это вес, рост, артериальное давление, а также частота сердечных сокращений (ЧСС) и сатурация кислорода в периферической крови (SpO2). Возможно, последние два параметра были получены с помощью светящегося красным электронным датчиком, прикрепляемым к пальцу, который отображал соответствующие числа на крошечном экране за считанные минуты. Этот датчик называется пульсоксиметром, и вы можете сделать такой самостоятельно на основе микросхемы MAX30102.
Пульсоксиметры могут приблизительно определять частоту сердечных сокращений, анализируя реакцию временного ряда отраженного красного и инфракрасного света. Здесь мы используем MAX30102 и Arduino для моздания такого устройства.
Пульсоксиметр MAX30102 – это недорогой датчик, совместимый с Arduino, который позволяет рассчитывать частоту сердечных сокращений. MAX30102 использует двухпроводную связь I2C для взаимодействия с платой Arduino. Мы используем порты I2C на выводах A4/A5 на плате Arduino. Схема подключения показана далее.
Для работы с датчиком нужна библиотека его функций. Sparkfun предоставляет библиотеку, которая обеспечивает связь между Arduino и MAX30102. В среде Arduino IDE перейдите в меню «Управление библиотеками» и введите «max30» в строку поиска. Загрузите библиотеку «Sparkfun MAX3010x Pulse and Proximity Sensor Library».
Далее представлен простой код программы Arduino. Он производит выборку данных от MAX30102 с частотой 400 Гц и выводит их через последовательный порт. При 400 Гц и последовательной скорости передачи 115200 компьютер способен без проблем читать каждую точку данных.
#include <Wire.h>
#include "MAX30105.h"
MAX30105 particleSensor;
void setup()
{
Serial.begin(115200);
while(!Serial);
delay(100);
Serial.println("");
Serial.println("MAX30102");
Serial.println("");
delay(100);
if (particleSensor.begin(Wire, I2C_SPEED_FAST) == false)
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1);
}
byte ledBrightness = 70;
byte sampleAverage = 1;
byte ledMode = 2;
int sampleRate = 400;
int pulseWidth = 69;
int adcRange = 16384;
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);
}
void loop() {
particleSensor.check();
while (particleSensor.available()) {
Serial.print(particleSensor.getFIFOIR());
Serial.print(",");
Serial.println(particleSensor.getFIFORed());
particleSensor.nextSample();
}
}
Если вплотную к MAX30102 поднести палец, вывод плоттера последовательного порта Arduino должен выглядеть следующим образом.
Нам не нужно беспокоиться о сложности отследить форму каждого графика, поскольку мы обработаем данные в Python и полностью проанализируем данные красного и ИК-диапазона от датчика MAX30102. В следующем разделе мы будем считывать данные 400 Гц в реальном времени в Python и выводить их в удобном виде. В качестве приемника данных с обработкой на Python можно использовать Raspberry Pi.
В приведенном выше коде Arduino единственное изменение, которое нам нужно сделать, это добавить функцию «micros()», чтобы прикрепить временную метку к показаниям данных значений красного и ИК-отражения. Обновленный код Arduino выглядит следующим образом.
#include <Wire.h>
#include "MAX30105.h"
MAX30105 particleSensor;
void setup()
{
Serial.begin(115200);
while(!Serial);
delay(100);
Serial.println("");
Serial.println("MAX30102");
delay(100);
if (particleSensor.begin(Wire, I2C_SPEED_FAST) == false)
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1);
}
byte ledBrightness = 70;
byte sampleAverage = 1;
byte ledMode = 2;
int sampleRate = 400;
int pulseWidth = 69;
int adcRange = 16384;
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);
}
void loop() {
particleSensor.check();
while (particleSensor.available()) {
Serial.print(micros());
Serial.print(",");
Serial.print(particleSensor.getFIFOIR());
Serial.print(",");
Serial.println(particleSensor.getFIFORed());
particleSensor.nextSample();
}
}
Алгоритм высокоскоростного последовательного считывания для Python для считывания значений последовательного вывода Arduino показан далее. Код Python получит данные и сохранит их в файл .csv для последующего анализа. Причина, по которой мы сохраняем их сразу, заключается в том, что данные поступают с такой высокой скоростью, что мы хотим минимизировать объем обработки, выполняемой между последовательными сборами.
import serial,time,csv,os
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
plt.style.use('ggplot')
ser = serial.Serial('/dev/ttyUSB0',
baudrate=115200)
datafile_name = 'test_data.csv'
if os.path.isfile(datafile_name):
os.remove(datafile_name)
all_data = []
start_word = False
while True:
try:
curr_line = ser.readline()
if start_word == False:
if curr_line[0:-2]==b'MAX30102':
start_word = True
print("Program Start")
continue
else:
continue
all_data.append(curr_line)
except KeyboardInterrupt:
break
print("Exited Loop")
t_vec,ir_vec,red_vec = [],[],[]
ir_prev,red_prev = 0.0,0.0
for ii in range(3,len(all_data)):
try:
curr_data = (all_data[ii][0:-2]).decode("utf-8").split(',')
except:
continue
if len(curr_data)==3:
if abs((float(curr_data[1])-ir_prev)/float(curr_data[1]))>1.01 or\
abs((float(curr_data[2])-red_prev)/float(curr_data[2]))>1.01:
continue
t_vec.append(float(curr_data[0])/1000000.0)
ir_vec.append(float(curr_data[1]))
red_vec.append(float(curr_data[2]))
ir_prev = float(curr_data[1])
red_prev = float(curr_data[2])
print('Sample Rate: {0:2.1f}Hz'.format(1.0/np.mean(np.abs(np.diff(t_vec)))))
with open(datafile_name,'a') as f:
writer = csv.writer(f,delimiter=',')
for t,x,y in zip(t_vec,ir_vec,red_vec):
writer.writerow([t,x,y])
fig = plt.figure(figsize=(12,8))
ax1 = fig.add_subplot(111)
ax1.set_xlabel('Time [s]',fontsize=24)
ax1.set_ylabel('IR Amplitude',fontsize=24,color='#CE445D',labelpad=10)
ax1.tick_params(axis='both',which='major',labelsize=16)
plt1 = ax1.plot(t_vec,ir_vec,label='IR',color='#CE445D',linewidth=4)
ax1_2 = plt.twinx()
ax1_2.grid('off')
ax1_2.set_ylabel('Red Amplitude',fontsize=24,color='#37A490',labelpad=10)
ax1_2.tick_params(axis='y',which='major',labelsize=16)
plt2 = ax1_2.plot(t_vec,red_vec,label='Red',color='#37A490',linewidth=4)
lns = plt1+plt2
labels = [l.get_label() for l in lns]
ax1_2.legend(lns,labels,fontsize=16)
plt.xlim([t_vec[0],t_vec[-1]])
plt.tight_layout(pad=1.2)
plt.savefig('max30102_python_example.png',dpi=300,facecolor=[252/255,252/255,252/255])
plt.show()
Окончательный график, созданный приведенным выше кодом Python, должен выглядеть следующим образом.
© digitrode.ru