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.
Para evitar medidas falsas (como el dispositivo midiendo en vacío, por ejemplo) se verifica que el resultado se encuentra entre unos valores máximos y mínimos antes de darlo por cierto. Aunque se considera como media que un valor normal para un adulto sano en reposo se encuentra entre 60 y 100 ppm, hay valores admisibles por debajo, es fácil encontrar 40 ppm en un atleta en reposo, hasta 200 ppm sometido a un ejercicio intenso y más de 100 ppm en adultos sedentarios en estados de excitación, precisamente un factor interesante para el proyecto de gestión del sueño que me lleva a desarrollar este 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