Arduino könyvtár pulzusméréshez pulzoximéterrel
Az egyik megfigyelt paraméter az alvásmenedzsment projektemben
Ez a pulzus. mérni azt A hemoglobin és az oxihemoglobin különböző hullámhosszú fényekkel szembeni viselkedésén alapuló készüléket fejlesztettem ki.. Alapvetően arról van szó, hogy megmérjük, mennyi fény tud áthaladni vagy visszaverődni egy jól öntözött testterületen. A jelenség teljes ciklusának gyakorisága lehetővé teszi a mérést impulzus.A tervezési és tesztelési szakaszban a impulzusmérő készülék Kifejlesztettem néhány kis programot, amelyek segítenek ellenőrizni az összeszerelés helyességét. Először az alábbi kódot írtam le, amely időről időre (legalább minden alkalommal) vette a mért értékeket és legfeljebb mindegyik ). ) és a Python alkalmazással rendelkező számítógépről figyelhető hogy később elemezhessük őket.
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));
}
}
}
|
Az értékek beállítását követően (nagyon sűrű mérésekkel kezdve) kaptam egy értékgyűjteményt a pulzoximéter idővel, hogy grafikont készíthessek egy táblázat segítségével, LibreOffice Calc de LibreOffice, konkrét.
Az összegyűjtött adatokkal, amint az a fenti képen is látható, a következő művelet annak meghatározása volt, hogy az értékek sűrűsége lehetővé teszi-e, hogy megbízható, de "gazdaságos" módon (a szükségesnél nem több mintavétellel) kiszámítsuk a impulzus; Ahogy az alábbi grafikonon is látható, úgy tűnt, hogy a megtett intézkedések az ésszerűen elvárható eredmények elérését szolgálják.
.
Ezt követően az adatmintavételből származó információk alapján egy olyan algoritmust kellett kidolgozni, amely méri a pulzusszámot. Ragaszkodva a grafikonhoz, hogy az egyszerűség kedvéért feltételezzük, hogy a grafikonhoz hasonló elrendezést képvisel. QRS komplexum, a legegyszerűbb dolognak az tűnik, ha a legkiemelkedőbb részek közötti időt nagyobb értékekkel mérjük (ami a kamrák depolarizációs qRs zónájának felel meg), eldobva a laposabb és "zajosabb" zónát, ami ezért nehezebb. megmérni. Az elfogadott megoldás, amely megfelel az alábbi tesztkódnak, a következő eljárás szerint működik:
-
Határozza meg minden esetben a mért területet, hogy csak az értékcsúcsokat vegye figyelembe qRs és dobd el a völgyet. Ehhez egy bizonyos állandónál nagyobb értékeket is lehet mérni, de fennáll annak a veszélye, hogy az egyén és/vagy a körülmények arányosan ugyan, de növelhetik vagy csökkenthetik az értékeket. Ennek elkerülése érdekében a területen lévő értéket nagyobbnak tekintjük, mint azt, amely egy bizonyos együtthatóval meghaladja az átlagértéket. Ily módon a mérés érzékenyen önkalibrált, és az együttható finomhangolásával még tovább állítható, amit esetemben a tesztek során kísérletileg sikerült elérni.
Válassza ki a csökkenő zóna értékeit a méréshez (Rs) a csúcs qRs, a lehető legközelebb a görbe maximumához. Ha tudni szeretné, hogy a növekvő zóna feladásra kerül, elegendő ellenőrizni, hogy egy új érték kisebb-e, mint az előző, és ellenőrizze, hogy a keresett érték még nem található-e, mivel általában több érték van a csökkenőben zónája qRs a mintavételi sűrűségtől függően. Az impulzus időzítéséhez annak a pillanatnak az értéke kerül tárolásra, amikor a pontot megtalálták (ez az ezredmásodperc, amelyet millisz ()), és összehasonlítja a következővel.
Annak biztosítására, hogy a mért érték a legmagasabb görbe csökkenő zónájában legyen a legnagyobb, változót használnak logikai érték ( ebben a példában és a könyvtárban), amely a főgörbe emelkedő zónájába való belépéskor aktiválódik, és deaktiválódik, ha megtalálja az első csökkenő értéket, amely az időzített érték.
Mivel az impulzus időtartamát ütés/perc-ben (ppm) szokás megadni, a kapott impulzusok közötti idő értékét úgy korrigálják, hogy az ábrázolás teljes idejét (60000 perc, XNUMX XNUMX ezredmásodperc) elosztják a kapott intervallummal. levonva az aktuális ezredmásodpercet (az aktuális értékből) a korábban időzítettekből.
A téves mérések elkerülése érdekében (mint például a vákuumban mért készülék) ellenőrizni kell, hogy az eredmény a maximális és a minimális érték között van-e, mielőtt természetesnek tekintené. Bár átlagosnak tekinthető, hogy egy egészséges felnőtt normálértéke nyugalmi állapotban 60 és 100 ppm között van, a megengedett értékek az alábbiakban találhatók, nyugalmi sportolónál könnyű megtalálni a 40 ppm-et, 200 ppm-ig intenzív testmozgás és több. 100 ppm ülő, izgatott állapotban lévő felnőtteknél, pontosan egy érdekes tényező az alváskezelési projektben ami ennek fejlesztésére késztet impulzusmérő készülék. Emiatt ajánlatos ezeket az értékeket sokat lazítani, hogy ne vesszenek el a szélsőségek, amelyek pontosan mutathatnak releváns szempontokat.
Az új átlagértéket úgy számítják ki, hogy a mintavételezett értékek száma alapján csökkentik az aktuális átlag relevanciáját, és hozzáadják az utolsó értéket, súlyozva egy együtthatóval, amely azt csökkenti, minél több eddig mért értéket mértek. .
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;
}
}
|
Végül a korábban ismertetett algoritmus felhasználásával kifejlesztettem a könyvtárat az impulzus kiszámításához a jelenlétének detektálásával hemoglobin vagy a oxihemoglobin (a használt fény hullámhosszától függően) az alábbi kódból.
A könyvtár elvárja, hogy a mintavételi függvényt periodikusan hívják meg impulzus az alváskezelési projektemben
. Mindenesetre az általam elvégzett tesztek alapján nem tűnik szükségesnek; akár az eszköz, akár a viselkedése miatt az impulzus kiszámításához, amely a függvénnyel lekérdezhető vagy a funkcióval az átlagos pulzus. Amellett, hogy korlátozott volt az erőforrás, kizártam a megszakítások alkalmazását, mert nem azonnali értékekre volt szükségem, hanem tartós értékekre az idő múlásával a impulzus, a mintavételezés egy bizonyos gyakorisággal elegendő információt kínál, és nem sokkal több (releváns) érhető el a növelésével, és nem is nagyon lehet csökkenteni anélkül, hogy a számításhoz lényeges adatokat ne veszítsen; a kód korai verzióiban, hogy figyelemmel kísérje a kód olvasását pulzoximéter Megállapítottam, hogy nem szükséges ragaszkodni a maximális mérési időhöz, hiszen ha az egymást követő értékek változásait helyesen vettük figyelembe, az nagyon közel volt a minimumhoz.
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;
}
|
A következő példaprogram bemutatja, hogyan használhatja az előző könyvtárat a impulzus egy pulzoximéter. Az osztály példányosítása mellett szintjének nyomon követése oxihemoglobin/hemoglobin és kisebb periodicitás mellett az értéke a impulzus számított és átlag.
Annak érdekében, hogy a mérések relevánsak legyenek, a program egy várakozást programoz, mielőtt bármilyen érték megjelenik. Mivel az érték hibás lehet (például ha a felhasználó eltávolítja az eszközt), az értékek csak akkor jelennek meg, ha az érvényesnek tekintett tartományon belül vannak.
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);
}
}
}
|
Hozzászólás Comment