पल्स ऑक्सीमीटर के साथ हृदय गति की निगरानी के लिए Arduino लाइब्रेरी
मेरे नींद प्रबंधन प्रोजेक्ट में मॉनिटर किए गए मापदंडों में से एक
यह नाड़ी है. इसे मापने के लिए मैंने प्रकाश की विभिन्न तरंग दैर्ध्य के विरुद्ध हीमोग्लोबिन और ऑक्सीहीमोग्लोबिन के व्यवहार के आधार पर एक उपकरण विकसित किया. मूल रूप से यह मापने के बारे में है कि एक निश्चित प्रकार का कितना प्रकाश शरीर के एक अच्छी तरह से सिंचित क्षेत्र से गुजरने या प्रतिबिंबित होने में सक्षम है। वह आवृत्ति जिसके साथ इस घटना का पूरा चक्र घटित होता है उसे मापने की अनुमति मिलती है pulso.के डिजाइन और परीक्षण चरण में नाड़ी मापने का उपकरण मैंने यह सत्यापित करने में मदद के लिए कुछ छोटे कार्यक्रम विकसित किए कि असेंबली सही थी। सबसे पहले मैंने नीचे कोड लिखा, जिसमें समय-समय पर (कम से कम प्रत्येक) मापा गया मान लिया गया और अधिक से अधिक प्रत्येक ) जब उनमें एक और पिछले वाले के बीच न्यूनतम अंतर होता है (वह मान जो इससे मेल खाता है ) और यह पायथन एप्लिकेशन वाले कंप्यूटर से निगरानी की जाती है ताकि बाद में उनका विश्लेषण किया जा सके।
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#define PIN_OXIMETRO 0 // Pin analógico 0
#define MEDIDA_MINIMA 10 // Cambio menor monitorizado
#define TIEMPO_MAXIMO_MEDIDA 200 // Cambio menor entre medidas (determina la resolución vertical)
#define TIEMPO_MINIMO_MEDIDA 100 // Milisegundos entre medidas (determina la resolución horizontal)
int lectura_anterior_oximetro=0;
int lectura_oximetro;
unsigned long cronometro_minimo=0;
unsigned long cronometro_maximo=0;
void setup()
{
Serial.begin(9600);
//pinMode(PIN_OXIMETRO,INPUT); // Ya es entrada por defecto
}
void loop()
{
if(millis()>cronometro_minimo)
{
lectura_oximetro=analogRead(PIN_OXIMETRO);
if(abs(lectura_oximetro–lectura_anterior_oximetro)>MEDIDA_MINIMA||millis()>cronometro_maximo)
{
cronometro_minimo=millis()+TIEMPO_MINIMO_MEDIDA;
cronometro_maximo=millis()+TIEMPO_MAXIMO_MEDIDA;
lectura_anterior_oximetro=lectura_oximetro;
Serial.println(String(millis(),DEC)+“,”+String(lectura_oximetro,DEC));
}
}
}
|
एक बार मूल्यों को समायोजित कर दिया गया (बहुत सघन माप से शुरू करके) मुझे मूल्यों का एक संग्रह मिला पल्स ऑक्सीमीटर समय के साथ मैं एक स्प्रेडशीट का उपयोग करके ग्राफ़ बना सका, लिब्रे ऑफिस Calc de लिब्रे ऑफिस, विशिष्ट।
एकत्र किए गए डेटा के साथ, जैसा कि ऊपर की छवि में दर्शाया गया है, अगला ऑपरेशन यह निर्धारित करना था कि क्या मूल्यों का घनत्व हमें विश्वसनीय लेकिन "किफायती" तरीके से गणना करने की अनुमति देता है (आवश्यक डेटा से अधिक नमूना नहीं लेना) pulso; जैसा कि नीचे दिए गए ग्राफ़ में देखा जा सकता है, किए गए उपाय ऐसे परिणाम प्राप्त करने में सहायक प्रतीत हुए जो अपेक्षा के अनुरूप थे।
.
इसके बाद, डेटा सैंपलिंग से मिली जानकारी के साथ, एक एल्गोरिदम विकसित करना आवश्यक था जो पल्स दर को माप सके। ग्राफ़ से चिपके हुए, सरलता के लिए, यह माना जाता है कि यह के समान एक लेआउट का प्रतिनिधित्व करता है क्यूआरएस कॉम्प्लेक्स, सबसे सरल बात सबसे प्रमुख भागों के बीच के समय को मापना है, उच्च मूल्यों के साथ (जो निलय के विध्रुवण के क्यूआर क्षेत्र से मेल खाती है), चापलूसी और "शोर" क्षेत्र को त्यागना, जो इसलिए अधिक कठिन है मापने के लिए। अपनाया गया समाधान, जो नीचे दिए गए परीक्षण कोड से मेल खाता है, निम्नलिखित प्रक्रिया के अनुसार काम करता है:
-
केवल मूल्य शिखर पर ध्यान देने के लिए प्रत्येक मामले में उस क्षेत्र का पता लगाएं जिसे मापा जा रहा है क्यूआर और घाटी को फेंक दो. ऐसा करने के लिए, एक निश्चित स्थिरांक से अधिक मूल्यों को मापा जा सकता है, लेकिन एक जोखिम है कि कोई व्यक्ति और/या परिस्थितियाँ, आनुपातिक रूप से, मूल्यों को बढ़ा या घटा सकती हैं। इससे बचने के लिए, क्षेत्र में एक मान उस मान से अधिक माना जाता है जो एक निश्चित गुणांक द्वारा औसत मान से अधिक होता है। इस तरह, माप संवेदनशील रूप से स्व-अंशांकित होता है और गुणांक को ठीक करके इसे और भी समायोजित किया जा सकता है, जो मेरे मामले में मैंने परीक्षणों के दौरान प्रयोगात्मक रूप से हासिल किया है।
माप के लिए अवरोही क्षेत्र के मान चुनें (Rs) शिखर का क्यूआर, जितना संभव हो वक्र के अधिकतम के करीब। यह जानने के लिए कि आरोही क्षेत्र को छोड़ दिया जा रहा है, यह सत्यापित करना पर्याप्त है कि नया मान पिछले वाले से कम है और सत्यापित करें कि खोजा गया मान अभी तक नहीं मिला है, क्योंकि सामान्य तौर पर, अवरोही क्षेत्र में कई मान होते हैं का क्षेत्र क्यूआर नमूना घनत्व के आधार पर। पल्स को समयबद्ध करने के लिए, उस क्षण का मान संग्रहीत किया जाता है जिस पर बिंदु पाया गया था (मिलीसेकंड द्वारा लौटाया गया)। मिलिस ()) और इसकी तुलना अगले से करता है।
यह सुनिश्चित करने के लिए कि मापा गया मान उच्चतम वक्र के अवरोही क्षेत्र में सबसे बड़ा है, एक चर का उपयोग किया जाता है बूलियन ( इस उदाहरण में और लाइब्रेरी में) जो प्रमुख वक्र के आरोही क्षेत्र में प्रवेश करते समय सक्रिय होता है और पहला अवरोही मान मिलने पर निष्क्रिय हो जाता है, जो कि समयबद्ध है।
चूंकि पल्स की अवधि को बीट्स प्रति मिनट (पीपीएम) के रूप में प्रस्तुत करना सामान्य है, प्राप्त पल्स के बीच के समय के मान को प्रतिनिधित्व के कुल समय (एक मिनट, 60000 मिलीसेकंड) को प्राप्त अंतराल से विभाजित करके गणना करके सही किया जाता है। पहले के समय के बीच वर्तमान मिलीसेकंड (वर्तमान मान का) घटाना।
गलत मापों से बचने के लिए (उदाहरण के लिए, वैक्यूम में मापने वाला उपकरण), यह सत्यापित किया जाता है कि परिणाम को हल्के में लेने से पहले यह अधिकतम और न्यूनतम मूल्यों के बीच है। यद्यपि यह औसत माना जाता है कि आराम के समय एक स्वस्थ वयस्क के लिए सामान्य मान 60 और 100 पीपीएम के बीच होता है, नीचे स्वीकार्य मान हैं, आराम के दौरान एक एथलीट में 40 पीपीएम खोजना आसान है, दौरान 200 पीपीएम तक। गहन व्यायाम और अधिक। उत्तेजना की स्थिति में गतिहीन वयस्कों में 100 पीपीएम, नींद प्रबंधन परियोजना के लिए एक दिलचस्प कारक है जो मुझे इसे विकसित करने के लिए प्रेरित करता है नाड़ी मापने का उपकरण. इस कारण से, इन मूल्यों को बहुत अधिक शिथिल करने की सलाह दी जाती है ताकि चरम सीमाएं खो न जाएं, जो सटीक रूप से प्रासंगिक पहलुओं को दिखा सकें।
नए औसत मूल्य की गणना नमूना किए गए मानों की संख्या के आधार पर वर्तमान औसत की प्रासंगिकता को कम करके की जाती है और अंतिम मान जोड़ा जाता है, इसे एक गुणांक के साथ भी भारित किया जाता है जो अब तक मापे गए अधिक मानों को कम कर देता है .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#define PIN_OXIMETRO 0 // Pin analógico 0
#define TIEMPO_MINIMO_MEDIDA 20 // Milisegundos entre medidas (determina la resolución horizontal)
#define COEFICIENTE_PULSO 1.25 // Coeficiente que determina la zona de valores en la que medir el pulso
#define PULSO_MENOR 30 // Ignorar valores menores (Es infrecuente un pulso más lento aún en reposo)
#define PULSO_MAYOR 180 // Ignorar valores mayores (Es infrecuente un pulso mayor en reposo)
#define MINUTO 60000.0 // Milisegundos en un minuto
float velocidad_pulso;
float lectura_media_oximetro=511.5;
unsigned long valores_contados=0;
int lectura_anterior_oximetro=0;
int lectura_oximetro;
boolean medir_pulso=false;
unsigned long cronometro_pulso=0;
unsigned long cronometro_oximetro=0;
void setup()
{
Serial.begin(9600);
//pinMode(PIN_OXIMETRO,INPUT); // Ya es entrada por defecto
}
void loop()
{
if(millis()>cronometro_oximetro)
{
cronometro_oximetro=millis()+TIEMPO_MINIMO_MEDIDA;
lectura_oximetro=analogRead(PIN_OXIMETRO);
valores_contados++;
lectura_media_oximetro=lectura_media_oximetro*(float(valores_contados–1)/valores_contados);
lectura_media_oximetro+=lectura_oximetro*(1.0/valores_contados);
if(lectura_oximetro>lectura_media_oximetro*COEFICIENTE_PULSO)
{
if(lectura_anterior_oximetro<lectura_oximetro)
{
medir_pulso=true;
}
else
{
if(medir_pulso)
{
velocidad_pulso=MINUTO/float(millis()–cronometro_pulso);
medir_pulso=false;
if(velocidad_pulso>PULSO_MENOR&&velocidad_pulso<PULSO_MAYOR)
{
Serial.println(“Pulso “+String(velocidad_pulso,DEC));
}
cronometro_pulso=millis();
}
}
}
lectura_anterior_oximetro=lectura_oximetro;
}
}
|
अंत में, पहले वर्णित एल्गोरिदम का उपयोग करके, मैंने इसकी उपस्थिति का पता लगाकर पल्स की गणना करने के लिए लाइब्रेरी विकसित की हीमोग्लोबिन ओ ला आक्सीहीमोग्लोबिन (प्रयुक्त प्रकाश की तरंग दैर्ध्य के आधार पर) नीचे दिए गए कोड से।
लाइब्रेरी को उम्मीद है कि सैंपलिंग फ़ंक्शन को समय-समय पर बुलाया जाएगा pulso मेरे नींद प्रबंधन प्रोजेक्ट में
. किसी भी मामले में, मैंने जो परीक्षण किए हैं, उससे यह आवश्यक नहीं लगता है; या तो डिवाइस द्वारा या के व्यवहार से पल्स की गणना करने के लिए, जिसे फ़ंक्शन से परामर्श लिया जा सकता है या फ़ंक्शन के साथ औसत नाड़ी. एक सीमित संसाधन होने के अलावा, मैंने रुकावटों का उपयोग करने से इंकार कर दिया क्योंकि मुझे तत्काल मूल्यों की आवश्यकता नहीं थी, बल्कि निगरानी के लिए समय के साथ निरंतर मूल्यों की आवश्यकता थी pulso, एक निश्चित आवृत्ति पर नमूनाकरण पर्याप्त जानकारी प्रदान करता है और इसे बढ़ाने से बहुत अधिक (प्रासंगिक) प्राप्त नहीं होता है, न ही गणना के लिए प्रासंगिक डेटा खोए बिना इसे बहुत कम करना संभव है; कोड के प्रारंभिक संस्करणों में पढ़ने की निगरानी करने के लिए पल्स ऑक्सीमीटर मैंने पाया कि अधिकतम माप समय पर टिके रहना आवश्यक नहीं था, क्योंकि यदि क्रमिक मूल्यों की विविधताओं पर सही ढंग से विचार किया गया, तो यह न्यूनतम के बहुत करीब था।
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
//pulso.h
#if defined(ARDUINO) && ARDUINO>=100
#include “Arduino.h”
#else
#include “WProgram.h”
#endif
#define PULSO_MINIMO 5 // Pulso mínimo. Un pulso menor se considera un error.
#define PULSO_MAXIMO 200 // Pulso máximo. Un pulso mayor se considera un error.
#define COEFICIENTE_PULSO 1.25 // Coeficiente que multiplica el pulso medio para determinar si el valor medido está en la zona que se cronometra. Puede usarse para calibra el dispositivo
#define OXIMETRIA_MEDIA 511.5 // Medida media inicial del pulso (1023/2) Puede usarse para calibrar el dispositivo
#define PULSO_MEDIO 80.0 // Pulso medio de un adulto en reposo (sólo para referencia)
class Pulso
{
private:
byte pin_oximetro; // Pin analógico al que se conecta el sensor de pulso
int lectura_oximetro; // Último valor medido en el sensor de pulso
int lectura_anterior_oximetro; // Penúltimo valor medido en el sensor de pulso para compararlo con el último y establecer la zona de valores en la que se encuentra
unsigned long numero_lecturas_oximetro; // Número de medidas del oxímetro tomadas. Usado para calcular la media
unsigned long numero_lecturas_pulso; // Número de medidas de pulso tomadas. Usado para calcular la media
float lectura_media_oximetro; // Medida media del sensor de pulso. Usado para saber si un valor se encuentra en la zona de medida (que se cronometra) del pulso
boolean medicion_de_pulso_activa; // Verdadero si se ha entrado de la zona del pulso (para no confundir si aún se encuentra en una zona ya medida)
float velocidad_pulso; // Último valor de pulso calculado
float ultima_velocidad_pulso; // Último valor de pulso correcto
float velocidad_media_pulso; // Media de los pulsos calculados durante la última sesión (creación del objeto Pulso)
unsigned long cronometro_pulso; // Tiempo entre medidas de pulso consecutivas
protected:
public:
Pulso(byte pin_oximetro_solicitado);
~Pulso();
void monitorizar_pulso(); // Se llama periódicamente (entre 10 y 50 ms) para calcular el pulso
byte ultimo_pulso(); // Devuelve el último valor correcto de pulso muestreado
byte pulso_medio(); // Devuelve el pulso medio de la sesión
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
//pulso.cpp
#include “pulso.h”
Pulso::Pulso(byte pin_oximetro_solicitado)
{
pin_oximetro=pin_oximetro_solicitado;
//pinMode(pin_oximetro,INPUT); // Ya es entrada por defecto
numero_lecturas_oximetro=0;
numero_lecturas_pulso=0;
lectura_media_oximetro=OXIMETRIA_MEDIA;
velocidad_media_pulso=PULSO_MEDIO;
medicion_de_pulso_activa=false;
lectura_anterior_oximetro=0;
ultima_velocidad_pulso=0; // Para indicar que es un valor incorrecto por el momento
cronometro_pulso=0;
}
Pulso::~Pulso()
{
}
byte Pulso::ultimo_pulso()
{
return round(ultima_velocidad_pulso);
}
byte Pulso::pulso_medio()
{
return round(velocidad_media_pulso);
}
void Pulso::monitorizar_pulso()
{
lectura_oximetro=analogRead(pin_oximetro);
numero_lecturas_oximetro++;
lectura_media_oximetro=lectura_media_oximetro*(float(numero_lecturas_oximetro–1)/numero_lecturas_oximetro); // Cambiar la representatividad de la parte actual de la media de pulso
lectura_media_oximetro+=lectura_oximetro*(1.0/numero_lecturas_oximetro); // Añadir la nueva lectura a la media
if(lectura_oximetro>lectura_media_oximetro*COEFICIENTE_PULSO)
{
if(lectura_anterior_oximetro<lectura_oximetro) // Medida de valores creciente
{
medicion_de_pulso_activa=true;
}
else
{
if(medicion_de_pulso_activa)
{
velocidad_pulso=60000.0/float(millis()–cronometro_pulso); // Cálculo de las pulsaciones por minuto (representación habitual del pulso)
medicion_de_pulso_activa=false; // Ya se ha medido el pulso, no medir hasta entrar en una nueva zona ascendente
if(velocidad_pulso>PULSO_MINIMO&&velocidad_pulso<PULSO_MAXIMO)
{
numero_lecturas_pulso++;
ultima_velocidad_pulso=velocidad_pulso;
velocidad_media_pulso=velocidad_media_pulso*(float(numero_lecturas_pulso–1)/numero_lecturas_pulso); // Calcular la representatividad de la media actual en la nueva media
velocidad_media_pulso+=velocidad_pulso*(1.0/numero_lecturas_pulso); // Añadir la nueva lectura a la media
}
cronometro_pulso=millis();
}
}
}
lectura_anterior_oximetro=lectura_oximetro;
}
|
निम्नलिखित उदाहरण प्रोग्राम दिखाता है कि मापने के लिए पिछली लाइब्रेरी का उपयोग कैसे करें pulso एक साथ पल्स ऑक्सीमीटर. कक्षा को त्वरित करने के अलावा के स्तर की निगरानी आक्सीहीमोग्लोबिन/हीमोग्लोबिन और छोटी आवधिकता के साथ का मान pulso गणना और औसत.
यह सुनिश्चित करने के लिए कि माप प्रासंगिक हैं, किसी भी मूल्य को प्रदर्शित करने से पहले प्रतीक्षा को प्रोग्राम किया जाता है। चूंकि मान गलत हो सकता है (उदाहरण के लिए यदि उपयोगकर्ता डिवाइस हटा देता है), मान केवल तभी दिखाए जाते हैं यदि वे वैध माने जाने वाले दायरे के भीतर हों।
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
#define PIN_PULSOMETRO 0
#define TIEMPO_MONITORIZACION_PULSO 20
#define TIEMPO_PRESENTACION_PULSO 5000
#include “pulso.h”
Pulso pulso(PIN_PULSOMETRO);
unsigned long cronometro_monitorizacion_pulso;
unsigned long cronometro_presentacion_pulso;
byte velocidad_pulso;
byte velocidad_media_pulso;
void setup()
{
Serial.begin(9600);
cronometro_monitorizacion_pulso=0;
cronometro_presentacion_pulso=TIEMPO_PRESENTACION_PULSO*2;
}
void loop()
{
if(millis()>cronometro_monitorizacion_pulso)
{
cronometro_monitorizacion_pulso=millis()+TIEMPO_MONITORIZACION_PULSO;
pulso.monitorizar_pulso();
}
if(millis()>cronometro_presentacion_pulso)
{
cronometro_presentacion_pulso=millis()+TIEMPO_PRESENTACION_PULSO;
velocidad_pulso=pulso.ultimo_pulso();
velocidad_media_pulso=pulso.pulso_medio();
if(velocidad_pulso)
{
Serial.print(“Pulso “);
Serial.print(velocidad_pulso,DEC);
Serial.print(” | Pulso medio “);
Serial.println(velocidad_media_pulso,DEC);
}
}
}
|
टिप्पणी पोस्ट