Arduino raamatukogu pulssoksümeetriga südame löögisageduse jälgimiseks
Üks minu unehaldusprojektis jälgitud parameetritest
See on pulss. seda mõõta Töötasin välja seadme, mis põhineb hemoglobiini ja oksühemoglobiini käitumisel valguse erinevatel lainepikkustel. Põhimõtteliselt on see mõõtmine, kui palju teatud tüüpi valgust suudab läbida või peegelduda hästi niisutatud kehapiirkonnas. Selle nähtuse täieliku tsükli toimumise sagedus võimaldab mõõta pulso.Projekteerimise ja katsetamise etapis impulsi mõõtmise seade Töötasin välja mõned väikesed programmid, mis aitavad mul kontrollida, kas kokkupanek oli õige. Kõigepealt kirjutasin alla koodi, mis võttis aeg-ajalt mõõdetud väärtused (vähemalt iga ja kõige rohkem igaüks ), kui need varieerusid miinimumi ühe ja eelmise vahel (väärtus, mis vastab ) ja jälgitakse Pythoni rakendusega arvutist et saaks neid hiljem analüüsida.
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));
}
}
}
|
Kui väärtused olid korrigeeritud (alustades väga tihedatest mõõtmistest), sain ma väärtuste kogumi impulssoksümeeter aja jooksul, et saaksin arvutustabeli abil graafiku koostada, LibreOffice'i arvutus de LibreOffice, konkreetne.
Kogutud andmetega, nagu on kujutatud ülaltoodud pildil, oli järgmiseks toiminguks kindlaks teha, kas väärtuste tihedus võimaldas meil usaldusväärsel, kuid "ökonoomsel" viisil (mitte võtta rohkem kui vajalikke andmeid) arvutada pulso; Nagu allolevalt graafikult näha, näis, et võetud meetmed aitavad saavutada tulemusi, mida on mõistlik oodata.
.
Järgmiseks oli andmete valimitest saadud teabe põhjal vaja välja töötada algoritm, mis mõõdaks pulsisagedust. Pidades kinni graafikust, eeldatakse lihtsuse huvides, et see esindab paigutust, mis sarnaneb QRS kompleks, tundub kõige lihtsam olevat mõõta kõige silmatorkavamate osade vahelisi aegu kõrgemate väärtustega (mis vastab vatsakeste depolarisatsiooni qRs tsoonile), jättes kõrvale lamedama ja "mürarikkama" tsooni, mis on seetõttu keerulisem. mõõta. Vastuvõetud lahendus, mis vastab allolevale testkoodile, töötab vastavalt järgmisele protseduurile:
-
Tuvastage igal juhul mõõdetav ala, et jälgida ainult väärtuste tippe qRs ja viska orgu minema. Selleks võib mõõta teatud konstandist suuremaid väärtusi, kuid on oht, et indiviid ja/või asjaolud võivad, kuigi proportsionaalselt, väärtusi tõsta või langetada. Selle vältimiseks loetakse piirkonna väärtus suuremaks kui see, mis ületab teatud koefitsiendi võrra keskmist väärtust. Nii on mõõtmine tundlikult isekalibreeritud ja seda saaks koefitsiendi peenhäälestusega veelgi reguleerida, mille olen enda puhul katsete käigus katseliselt saavutanud.
Valige mõõtmiseks kahaneva tsooni väärtused (Rs) tipust qRs, võimalikult lähedal kõvera maksimumile. Et teada saada, et tõusev tsoon on hüljatud, piisab, kui kontrollida, et uus väärtus on eelmisest väiksem, ja veenduda, et otsitavat väärtust pole veel leitud, kuna üldiselt on kahanevas tsoonis mitu väärtust tsoon qRs sõltuvalt proovivõtu tihedusest. Impulsi ajastamiseks salvestatakse hetke väärtus, mil punkt leiti (millisekundid, mille millis ()) ja võrdleb seda järgmisega.
Tagamaks, et mõõdetud väärtus on kõrgeima kõvera kahanevas tsoonis suurim, kasutatakse muutujat tõeväärtus ( selles näites ja teegis), mis aktiveeritakse põhikõvera tõusvasse tsooni sisenemisel ja deaktiveeritakse, kui leitakse esimene kahanev väärtus, mis on ajastatud väärtus.
Kuna tavaliselt esitatakse impulsi kestust löökidena minutis (ppm), korrigeeritakse saadud impulsside vahelise aja väärtust, jagades esituse koguaja (üks minut, 60000 XNUMX millisekundit) intervalliga, mis saadakse lahutades praegused millisekundid (praegusest väärtusest) varem ajastatud ajast.
Vale mõõtmise vältimiseks (näiteks vaakumis mõõtev seade) kontrollitakse, et tulemus oleks maksimaalse ja minimaalse väärtuse vahel, enne kui seda enesestmõistetavaks pidada. Kuigi keskmiseks loetakse, et terve täiskasvanu puhkeolekus on normaalne väärtus vahemikus 60–100 ppm, on lubatud väärtused allpool, on kerge leida puhkeolekus sportlasel 40 ppm, kuni 200 ppm. intensiivne treening ja rohkem. 100 ppm istuvatel inimestel erutusseisundis, just unehaldusprojekti jaoks huvitav tegur mis sunnib mind seda arendama impulsi mõõtmise seade. Sel põhjusel on soovitatav neid väärtusi palju lõdvestada, et ei läheks kaduma äärmused, mis võiksid täpselt näidata asjakohaseid aspekte.
Uus keskmine väärtus arvutatakse, vähendades praeguse keskmise asjakohasust valimite arvu põhjal ja lisatakse viimane väärtus, mis on samuti kaalutud koefitsiendiga, mis vähendab seda veelgi, mida rohkem väärtusi on seni mõõdetud. .
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;
}
}
|
Lõpuks, kasutades eelnevalt kirjeldatud algoritmi, töötasin välja raamatukogu impulsi arvutamiseks, tuvastades selle olemasolu hemoglobiin o la oksühemoglobiin (olenevalt kasutatud valguse lainepikkusest) allolevast koodist.
Teek eeldab, et diskreetimisfunktsiooni kutsutakse perioodiliselt välja pulso minu unehaldusprojektis
. Minu tehtud testide põhjal ei tundu see igal juhul vajalik; kas seadme või käitumise tõttu pulsi arvutamiseks, mida saab funktsiooniga vaadata või funktsiooniga keskmine pulss. Lisaks sellele, et ressurss oli piiratud, välistasin katkestuste kasutamise, sest ma ei vajanud vahetuid väärtusi, vaid pigem aja jooksul püsivaid väärtusi, et jälgida pulso, teatud sagedusega diskreetimine pakub piisavalt infot ja seda suurendades ei saa palju rohkem (asjakohast), samuti pole võimalik seda palju vähendada ilma arvutuse jaoks olulisi andmeid kaotamata; koodi varajastes versioonides, et jälgida koodi lugemist impulssoksümeeter Avastasin, et maksimaalsest mõõtmisajast ei ole vaja kinni pidada, sest kui järjestikuste väärtuste kõikumisi õigesti arvestada, oli see minimaalsele väga lähedal.
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;
}
|
Järgmine näidisprogramm näitab, kuidas kasutada eelmist teeki mõõtmiseks pulso ühe impulssoksümeeter. Lisaks klassi instantseerimisele taseme jälgimine oksühemoglobiin/hemoglobiin ja väiksema perioodilisusega väärtus pulso arvutatud ja keskmine.
Mõõtmiste asjakohasuse tagamiseks programmeeritakse enne mis tahes väärtuse kuvamist ooteaeg. Kuna väärtus võib olla vale (näiteks kui kasutaja eemaldab seadme), kuvatakse väärtused ainult siis, kui need jäävad kehtivaks peetavate väärtuste vahemikku.
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);
}
}
}
|
Postita kommentaar