Arduino biblioteka širdies ritmo stebėjimui su pulso oksimetru
Vienas iš parametrų, stebėtų mano miego valdymo projekte
Tai pulsas. jį išmatuoti Sukūriau įrenginį, pagrįstą hemoglobino ir oksihemoglobino elgesiu prieš skirtingus šviesos bangos ilgius. Iš esmės tai yra matavimas, kiek tam tikros rūšies šviesos gali praeiti arba atsispindėti gerai drėkinamoje kūno vietoje. Dažnis, kuriuo vyksta visas šio reiškinio ciklas, leidžia išmatuoti pulsas.Projektavimo ir bandymo etape pulso matavimo prietaisas Sukūriau keletą mažų programų, kurios padėtų man patikrinti, ar surinkimas buvo teisingas. Pirmiausia parašiau žemiau esantį kodą, kuris karts nuo karto paimdavo išmatuotas vertes (bent jau kas ir daugiausia kiekviena ), kai jie skyrėsi nuo vieno iki ankstesnio minimumo (vertė, kuri atitinka ) ir stebima iš kompiuterio su Python programa kad vėliau būtų galima juos išanalizuoti.
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));
}
}
}
|
Kai vertės buvo pakoreguotos (pradedant nuo labai tankių matavimų), aš gavau verčių rinkinį iš Pulso matuoklis laikui bėgant galėčiau sudaryti diagramas naudodamas skaičiuoklę, „LibreOffice Calc“ de LibreOffice, konkretus.
Su surinktais duomenimis, kaip pavaizduota aukščiau esančiame paveikslėlyje, kita operacija buvo nustatyti, ar reikšmių tankis leido patikimai, bet „ekonomiškai“ (neatimant daugiau nei reikiamų duomenų) apskaičiuoti verčių vertę. pulsas; Kaip matyti iš toliau pateiktos diagramos, priemonės, kurių buvo imtasi, padėjo pasiekti rezultatų, kurių galima pagrįstai tikėtis.
.
Toliau, naudojant informaciją iš duomenų atrankos, reikėjo sukurti algoritmą, kuris matuotų pulso dažnį. Laikydamiesi grafiko, kad dėl paprastumo daroma prielaida, kad jis reiškia išdėstymą, panašų į QRS kompleksasAtrodo, kad paprasčiausias dalykas yra išmatuoti laiką tarp iškiliausių dalių su didesnėmis reikšmėmis (tai atitinka skilvelių depoliarizacijos qRs zoną), atmetant plokštesnę ir „triukšmingesnę“ zoną, todėl tai yra sunkiau. matuoti. Priimtas sprendimas, atitinkantis toliau pateiktą testo kodą, veikia pagal šią procedūrą:
-
Kiekvienu atveju aptikkite plotą, kuris yra matuojamas, kad atsižvelgtumėte tik į verčių smailes qRs ir išmesk slėnį. Tam galima išmatuoti didesnes už tam tikrą konstantą reikšmes, tačiau yra rizika, kad asmuo ir (arba) aplinkybės gali, nors ir proporcingai, padidinti arba sumažinti reikšmes. Siekiant to išvengti, ploto reikšmė laikoma didesne už tą, kuri tam tikru koeficientu viršija vidutinę vertę. Tokiu būdu matavimas yra jautriai savaime sukalibruojamas ir jį būtų galima dar labiau pakoreguoti tiksliai sureguliuojant koeficientą, kurį mano atveju pasiekiau eksperimentiškai per bandymus.
Matavimui pasirinkite mažėjančios zonos reikšmes (Rs) piko qRs, kuo arčiau kreivės maksimumo. Norint žinoti, kad kylanti zona yra apleista, pakanka patikrinti, ar nauja reikšmė yra mažesnė už ankstesnę, ir patikrinti, ar ieškoma reikšmė dar nerasta, nes paprastai mažėjančioje yra kelios reikšmės. zona qRs priklausomai nuo mėginių ėmimo tankio. Norint nustatyti impulso laiką, išsaugoma momento, kai taškas buvo rastas, reikšmė (milisekundės, kurias grąžina milis ()) ir lygina jį su kitu.
Siekiant užtikrinti, kad išmatuota vertė būtų didžiausia aukščiausios kreivės mažėjančioje zonoje, naudojamas kintamasis loginis ( šiame pavyzdyje ir bibliotekoje), kuris suaktyvinamas įeinant į didėjančią pagrindinės kreivės zoną ir išjungiamas, kai randama pirmoji mažėjanti reikšmė, kuri yra laiko reikšmė.
Įprasta impulso trukmę vaizduoti dūžiais per minutę (ppm), gauta laiko tarp impulsų reikšmė koreguojama skaičiuojant padalijus bendrą vaizdavimo laiką (viena minutė, 60000 XNUMX milisekundžių) iš intervalo, gauto atimant dabartines milisekundes (iš dabartinės vertės) iš tų, kurios anksčiau buvo laikomos.
Kad būtų išvengta klaidingų matavimų (pvz., prietaisas, matuojantis vakuume), prieš priimant tai savaime suprantamu dalyku, patikrinama, ar rezultatas yra tarp didžiausių ir mažiausių verčių. Nors laikoma, kad vidutinė normalioji vertė sveikam suaugusiam žmogui ramybės būsenoje yra nuo 60 iki 100 ppm, toliau pateikiamos leistinos vertės, nesunku rasti 40 ppm ramybės būsenoje, iki 200 ppm. intensyvūs pratimai ir daugiau. 100 ppm sėdintiems suaugusiems, susijaudinusiems žmonėms, būtent įdomus miego valdymo projekto veiksnys kuri mane skatina tai plėtoti pulso matavimo prietaisas. Dėl šios priežasties patartina šias vertybes labai atpalaiduoti, kad nebūtų prarasti kraštutinumai, kurie galėtų tiksliai parodyti aktualius aspektus.
Nauja vidutinė vertė apskaičiuojama sumažinant dabartinio vidurkio aktualumą, remiantis imtų verčių skaičiumi, ir pridedama paskutinė vertė, taip pat pasverta koeficientu, kuris ją dar labiau sumažina, kuo daugiau verčių iki šiol buvo išmatuota. .
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;
}
}
|
Galiausiai, naudodamas anksčiau aprašytą algoritmą, sukūriau biblioteką pulsui apskaičiuoti aptikdamas buvimą hemoglobinas arba oksihemoglobinas (priklausomai nuo naudojamos šviesos bangos ilgio) iš toliau pateikto kodo.
Biblioteka tikisi, kad atrankos funkcija bus iškviečiama periodiškai pulsas mano miego valdymo projekte
. Bet kokiu atveju iš mano atliktų testų neatrodo, kad tai būtina; arba dėl įrenginio, arba dėl jo elgesio pulsui apskaičiuoti, kurį galima peržiūrėti naudojant funkciją arba su funkcija vidutinis pulsas. Be to, kad ištekliai yra riboti, aš atmečiau pertraukų naudojimą, nes man reikėjo ne tiesioginių verčių, o nuolatinių verčių, kad galėčiau stebėti pulsas, atrinkimas tam tikru dažniu suteikia pakankamai informacijos ir ne daug daugiau (aktualu) negaunama jį didinant, taip pat negalima jo labai sumažinti neprarandant svarbių skaičiavimui duomenų; Ankstyvosiose kodo versijose, kad būtų galima stebėti skaitymą Pulso matuoklis Sužinojau, kad nebūtina laikytis maksimalaus matavimo laiko, nes, teisingai įvertinus nuoseklių verčių svyravimus, jis buvo labai artimas minimumui.
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;
}
|
Toliau pateiktame programos pavyzdyje parodyta, kaip naudoti ankstesnę biblioteką matuoti pulsas su Pulso matuoklis. Be to, instantiuoti klasę lygio stebėjimas oksihemoglobinas/hemoglobinas o mažesniu periodiškumu – vertė pulsas skaičiuojamas ir vidutinis.
Siekiant užtikrinti, kad matavimai būtų tinkami, užprogramuojamas laukimas prieš rodant bet kokią vertę. Kadangi vertė gali būti neteisinga (pavyzdžiui, jei vartotojas pašalina įrenginį), reikšmės rodomos tik tuo atveju, jei jos patenka į galiojančias.
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);
}
}
}
|
Rašyti komentarą