Spisu treści:
- Krok 1: Sprzęt
- Krok 2: Sygnały cyfrowe zwrócone przez MAX30102
- Krok 3: Wstępne przetwarzanie sygnału
- Krok 4: Wół roboczy: funkcja autokorelacji
- Krok 5: Określanie nasycenia tlenem
- Krok 6: Kod źródłowy
Wideo: Pulsoksymetr o znacznie zwiększonej precyzji: 6 kroków (ze zdjęciami)
2024 Autor: John Day | [email protected]. Ostatnio zmodyfikowany: 2024-01-30 11:30
Jeśli niedawno odwiedziłeś lekarza, prawdopodobnie twoje podstawowe parametry życiowe zostały zbadane przez pielęgniarkę. Waga, wzrost, ciśnienie krwi, a także częstość akcji serca (HR) i saturacja krwi obwodowej (SpO2). Być może ostatnie dwa zostały uzyskane ze świecącej na czerwono elektronicznej sondy palcowej, która w ciągu kilku minut wyświetlała odpowiednie liczby na maleńkim ekranie. Ta sonda nazywa się pulsoksymetrem i wszystkie podstawowe informacje na jej temat znajdziesz tutaj.
Bez problemu można kupić prosty pulsoksymetr, ale gdzie jest w tym zabawa? Zdecydowałem się zbudować własną, najpierw do licha, ale co ważniejsze z myślą o konkretnym zastosowaniu: nocnej oksymetrii, w której zarówno HR, jak i SpO2 dane byłyby stale gromadzone przez noc i zapisywane na karcie micro SD. Instructables zawiera już kilka projektów tego rodzaju, np. dwa dotyczące Arduino tu i tutaj, a jeden wykorzystujący Raspberry Pi. Kopalnia wykorzystuje nieco nowszy czujnik MAX30102 firmy MAXIM Integrated oraz Adafruit Feather M0 Adalogger do sterowania i rejestracji danych.
Nasz projekt nie jest więc szczególnie innowacyjny pod względem sprzętowym i jako taki nie byłby wart pisania tego Instructable, ale w trakcie jego tworzenia dokonałem istotnych postępów w oprogramowaniu, które pozwoliło mi wyodrębnić dane z MAX30102 ze znacznie większą spójnością i wieloma mniej szumów niż oprogramowanie napisane przez MAXIM dla tego czujnika. Wydajność naszego algorytmu przetwarzania sygnału jest zilustrowana na powyższym wykresie, gdzie dwa górne wykresy zawierają nocne tętno i nasycenie tlenem obliczone na podstawie surowych sygnałów naszą metodą (oznaczone jako „RF”), podczas gdy dwa dolne wykresy pokazują wyniki MAXIM uzyskane z dokładnie te same sygnały. Odchylenia standardowe dla HR wynoszą 4,7 bpm i 18,1 bpm, a dla SpO2 0,9% i 4,4%, odpowiednio dla RF i MAXIM.
(Oba wykresy RF odpowiadają minimalnemu progowi autokorelacji 0,25 i brakowi limitu korelacji R/IR; zobacz kroki 4 i 5 w celu wyjaśnienia tych terminów.)
Krok 1: Sprzęt
- Pulsoksymetr i czujnik tętna Płyta systemowa MAX30102 firmy MAXIM Integrated, Inc.
- Adalogger Feather M0 firmy Adafruit, Inc.
- Bateria litowo-jonowa firmy Adafruit, Inc.
Znajomości:
- Adalogger piny SCL i SDA do odpowiednich pinów SCL i SDA na płycie MAX30102
- Adalogger pin 10 do pinu INT na płycie MAX30102
- Adalogger GND do płyty MAX30102 GND
- Adalogger 3V do MAX30102 VIN
Krok 2: Sygnały cyfrowe zwrócone przez MAX30102
Zasady działania czujnika są bardzo proste: dwie diody LED, jedna czerwona (660 nm) i jedna podczerwona (880 nm, IR) przepuszczają światło przez ludzką skórę. Światło jest częściowo pochłaniane przez znajdujące się pod nim tkanki, w tym krew obwodową. Fotodetektor czujnika zbiera odbite światło na obu długościach fal i zwraca dwie odpowiadające im intensywności względne za pomocą protokołu I2C. Ponieważ widma absorpcji hemoglobiny utlenowanej i odtlenionej różnią się dla obu długości fal, odbite światło ma zmienną składową, ponieważ ilość krwi tętniczej obecnej pod skórą pulsuje z każdym uderzeniem serca. Ustalenie częstości akcji serca i saturacji tlenem zależy od oprogramowania do przetwarzania sygnału.
Przykłady sygnałów surowych (tylko kanał IR) są pokazane na powyższych obrazach. Można zauważyć składnik okresowy nałożony na zmienną linię bazową, która zmienia się z powodu wielu czynników wymienionych na stronie Wikipedii. Artefakty wywołane ruchem są szczególnie irytujące, ponieważ mogą maskować użyteczny sygnał HR i powodować fałszywe wyniki. Dlatego zaawansowane komercyjne oksymetry wyposażone są w akcelerometry, które pomagają zlikwidować te artefakty.
Mogę dodać akcelerometr do następnej wersji mojego pulsoksymetru, ale do nocnego HR/SpO2 nagrywanie, gdy czujnik przez większość czasu pozostaje w bezruchu, wystarczy wykryć i pominąć sygnały zniekształcone.
Sam czujnik MAX30102 jest dostarczany w niewielkiej obudowie do montażu powierzchniowego, ale MAXIM łaskawie oferuje płytkę zaciskową (płyta systemowa 6300) oraz oprogramowanie do przetwarzania sygnału dla Arduino i mbed - wszystko w referencyjnym pakiecie projektowym MAXREFDES117 #. Kupiłem go szczęśliwie, spodziewając się po prostu przylutować kilka przewodów między czujnikiem a Adaloggerem i mieć działający, dobry pulsoksymetr w jeden dzień. Zaadaptowałem wersję RD117_ARDUINO oprogramowania MAXIM do pracy na procesorze ARM Cortex M0 Adaloggera. W zasadzie wszystko, co musiałem zrobić, to zastąpić niekompatybilne funkcje SofI2C w max30102.cpp odpowiednimi wywołaniami biblioteki Wire. Kod skompilowany dobrze w Arduino IDE v1.8.5 i działał na M0 bez żadnych błędów. Wyniki netto były jednak rozczarowujące. W kroku Wstęp pokazałem już bardzo wysoką wariancję HR i SpO2. Oczywiście można powiedzieć, że zrobiłem coś złego i to też była moja pierwotna myśl. Jednak w filmie instruktażowym MAXIM możesz również zaobserwować szalenie wahające się wartości tętna wyświetlane na ekranie. Co więcej, komentarze pod filmem potwierdzają, że inni również zauważyli podobne zjawisko.
Krótko mówiąc, po kilku eksperymentach stwierdziłem, że czujnik działa poprawnie, a alternatywna metoda cyfrowego przetwarzania sygnału daje znacznie lepszą stabilność. Ta nowa metoda, oznaczona jako „RF”, jest opisana w następnych krokach.
Krok 3: Wstępne przetwarzanie sygnału
W naszej implementacji surowy sygnał jest zbierany z częstotliwością 25 Hz (tak samo jak w przypadku MAXIM) przez pełne 4 sekundy (oprogramowanie MAXIM zbiera tylko wartość 1 sekundy), co daje 100 zdigitalizowanych punktów czasowych na końcowy punkt danych. Każda 100-punktowa sekwencja musi być wstępnie przetworzona w następujący sposób:
- Centrowanie średniej (aka „usunięcie komponentu DC” dla inżynierów elektryków). Surowe dane pochodzące z czujnika to szereg czasowy liczb całkowitych w 105 zasięg. Jednak użytecznym sygnałem jest tylko część światła odbitego od krwi tętniczej, która zmienia się tylko o 102 - pierwsza cyfra. W celu uzyskania sensownego przetwarzania sygnału pożądane jest zatem odjęcie średniej od każdego punktu szeregowego. Ta część nie różni się od tego, co już robi oprogramowanie MAXIM. Różnicą jest jednak dodatkowe centrowanie średnich samych indeksów czasu. Innymi słowy, zamiast indeksowania punktów serii numerami od 0 do 99, nowe indeksy mają teraz numery -49,5, -48,5, …, 49,5. Na początku może wydawać się to dziwne, ale dzięki tej procedurze „środek ciężkości” krzywej sygnału pokrywa się z początkiem układu współrzędnych (drugi rysunek). Ten fakt staje się całkiem przydatny w następnym kroku.
- Wyrównanie linii bazowej. Kolejne spojrzenie na przebiegi pokazane w kroku 2 pokazuje, że linia bazowa rzeczywistych sygnałów pulsoksymetrycznych jest daleka od płaskiej w poziomie, ale zmienia się wraz z różnymi nachyleniami. Trzecia rycina pokazuje wyśrodkowany na środku sygnał IR (niebieska krzywa) i jego linię bazową (niebieska linia prosta). W takim przypadku nachylenie linii bazowej jest ujemne. Opisana powyżej metoda przetwarzania sygnału wymaga, aby linia bazowa była pozioma. Można to osiągnąć po prostu odejmując linię podstawową od sygnału wyśrodkowanego na średnią. Dzięki wyśrodkowaniu średniej zarówno współrzędnych Y, jak i X, punkt przecięcia linii podstawowej wynosi zero, a równanie nachylenia jest szczególnie proste, jak pokazano na czwartym rysunku. Sygnał z poziomem linii podstawowej jest przedstawiony pomarańczową krzywą na trzecim rysunku.
W ten sposób wstępnie przetworzony sygnał jest gotowy do następnego kroku.
Krok 4: Wół roboczy: funkcja autokorelacji
Wracając do zwykłego indeksowania 1, …, n, pierwszy rysunek pokazuje definicję funkcji autokorelacji rm - wielkość uznana za bardzo użyteczną w wykrywaniu okresowości oraz jakości sygnału. Jest to po prostu znormalizowany iloczyn skalarny szeregu czasowego sygnału z samym sobą przesuniętym o opóźnienie m. Jednak w naszej aplikacji wygodnie jest skalować każdą wartość autokorelacji w odniesieniu do jej wartości przy lag = 0, tj. użyć względnej autokorelacji zdefiniowanej przez rm / r0.
Wykres względnej autokorelacji typowego sygnału podczerwonego dobrej jakości pokazano na drugim rysunku. Zgodnie z oczekiwaniami, jego wartość przy lag = 0 jest przy globalnym maksimum równym 1. Następne (lokalne) maksimum występuje przy lag = 23 i wynosi 0,79. Obecność lokalnych minimów i maksimów na wykresie autokorelacji jest łatwa do zrozumienia: gdy sygnał przesuwa się w prawo, jego szczyty początkowo zakłócają się destrukcyjnie, ale w pewnym momencie interferencja staje się konstruktywna i osiąga maksimum przy opóźnieniu równym średniej okres sygnału.
Ostatnia fraza jest kluczowa: aby wyznaczyć średni czas pomiędzy szczytami, z którego można obliczyć częstotliwość sygnału (tj. tętno) wystarczy znaleźć pierwsze lokalne maksimum funkcji autokorelacji! Domyślnie MAX30102 próbkuje wejście analogowe z częstotliwością 25 punktów na sekundę, dlatego przy danym m okres w sekundach jest równy m / 25. Prowadzi to do tętna wyrażonego w uderzeniach na minutę (bpm) przez:
HR = 60*25 / m = 1500 / m
Oczywiście nie jest konieczne wykonywanie kosztownych obliczeń rm przy wszystkich wartościach opóźnień. Nasz algorytm jako pierwszy zgaduje tętno = 60 bpm, co odpowiada m = 25. Funkcja autokorelacji jest w tym momencie oceniana i porównywana z wartością u jej lewego sąsiada, m = 24. Jeśli wartość sąsiadów jest wyższa, wtedy marsz kontynuuje w lewo aż do rm-1 < rm. Tak określone końcowe m jest następnie zwracane jako maksymalne opóźnienie. Następna iteracja zaczyna się od tej wartości zamiast od 25 i cały proces się powtarza. Jeśli pierwszy sąsiad z lewej jest niżej, to powyższe rutynowe marsze lag wskazuje na prawo w podobny sposób. W większości przypadków maksymalne opóźnienie wymaga tylko kilku ocen funkcji autokorelacji. Ponadto jako wartości graniczne stosuje się maksymalne i minimalne dopuszczalne opóźnienia (odpowiadające odpowiednio minimalnemu i maksymalnemu częstości akcji serca).
Powyższe działa bardzo dobrze w przypadku sygnałów dobrej jakości, ale rzeczywisty świat jest daleki od ideału. Niektóre sygnały są zniekształcone, głównie z powodu artefaktów ruchu. Taki sygnał pokazano na trzecim rysunku. Słaba periodyczność znajduje odzwierciedlenie w postaci jej funkcji autokorelacji oraz w małej wartości 0,28 pierwszego lokalnego maksimum przy m = 11. Porównaj to z maksymalną wartością 0,79 wyznaczoną dla sygnału dobrej jakości. Wraz z wartościami granicznymi opóźnienia, zatem wartość rm / r0 co najwyżej jest dobrym wskaźnikiem jakości sygnału i wymaganie przekroczenia pewnego progu może być wykorzystane do odfiltrowania artefaktów ruchu. Przedstawione we wstępach wykresy „RF” wynikały z takiego progu równego 0,25.
Krok 5: Określanie nasycenia tlenem
Poprzedni krok wystarczył do określenia tętna. SpO2 wymaga więcej pracy. W pierwszej kolejności należy uwzględnić pomijany dotychczas sygnał w kanale czerwonym (R). Następnie oblicza się stosunek sygnałów czerwieni do podczerwieni, Z = R/IR, obydwa odbite od krwi tętniczej. Część „krew tętnicza” jest kluczowa, ponieważ większość światła jest odbijana od tkanek i krwi żylnej. Jak wybrać część sygnału odpowiadającą krwi tętniczej? Cóż, to jest pulsacyjny składnik, który zmienia się z każdym uderzeniem serca. Mówiąc słowami inżynierów elektryków, jest to „część prądu przemiennego”, podczas gdy pozostałe światło odbite to „część prądu stałego”. Ponieważ bezwzględne natężenia światła R i IR nie są współmierne, stosunek Z jest obliczany na podstawie natężeń względnych, jak pokazano na pierwszej figurze. W odniesieniu do faktycznie obliczonych wielkości, używam średniej kwadratowej (RMS) sygnału wyśrodkowanego na poziomie podstawowym, y, do znanej już średniej surowego sygnału, < Y >; patrz drugi rysunek. Jednak stosunek Z to tylko połowa pracy. Nieliniowa odpowiedź czujnika wymaga empirycznej kalibracji między Z a końcowym SpO2 wartości. Wziąłem równanie kalibracyjne z kodu MAXIM:
SpO2 = (-45,06*Z + 30,354)*Z + 94,845
Należy pamiętać, że to równanie dotyczy tylko płyty projektowej MAX30102 zakupionej w 2017 roku! Jest prawdopodobne, że MAXIM może ponownie skalibrować swoje czujniki w późniejszym terminie.
Powyższa procedura nadal generuje wiele fałszywych SpO2 odczyty. Kanał czerwony cierpi z powodu wielu artefaktów, podobnie jak kanał IR. Rozsądne jest założenie, że oba sygnały powinny być silnie skorelowane. W rzeczywistości sygnały dobrej jakości, jak na przykładzie na trzecim rysunku, bardzo dobrze korelują. Współczynnik korelacji Pearsona wynosi w tym przypadku aż 0,99. Nie zawsze tak jest, co ilustruje czwarta ilustracja. Chociaż sygnał IR przeszedłby przez filtr jakości tętna z jego rm / r0 = 0,76, zniekształcony sygnał R skutkuje słabym współczynnikiem korelacji między nimi równym tylko 0,42. Ta obserwacja oferuje drugi filtr jakości: posiadanie współczynnika korelacji między kanałami większego niż pewien próg.
Ostatnie dwie liczby ilustrują efekt netto takiego filtrowania jakości. Najpierw zmierzone nasycenie tlenem jest wykreślane z progiem jakości HR wynoszącym 0,25, ale bez SpO2 filtr. Następny wykres wynika z odfiltrowania słabego HR i SpO2 wyniki przy 0,5 rm / r0 oraz 0,8 progów współczynnika korelacji. Ogólnie rzecz biorąc, słabe punkty danych wynoszące 12% całości zostały odfiltrowane przez bardziej rygorystyczny reżim.
W naszym kodzie współczynnik korelacji cc obliczono zgodnie ze wzorem na piątym rysunku, gdzie y reprezentuje wyśrodkowany na poziomie średniej sygnał, podczas gdy r0 została zdefiniowana w poprzednim kroku.
Krok 6: Kod źródłowy
Kod źródłowy C dla tego projektu, sformatowany dla Arduino IDE, jest dostępny z naszego konta Github pod następującym linkiem:
github.com/aromring/MAX30102_by_RF
Jego strona Readme opisuje poszczególne komponenty.
Chciałabym poświęcić chwilę, aby pochwalić Adafruit za wykonanie tak doskonałego produktu, jakim jest Adalogger oparty na M0. Jego szybki procesor 48 MHz ARM Cortex M0, z dużą ilością pamięci RAM, z pewnością pomógł uczynić ten projekt opłacalnym, a bezpośrednio podłączony czytnik kart SD (plus biblioteka SD Adafruit) usunie wszystkie problemy hobbystów związane z przechowywaniem dużych ilości danych w czasie rzeczywistym.
Zalecana:
Pulsoksymetr Arduino: 35 kroków (ze zdjęciami)
Pulsoksymetr Arduino: Pulsoksymetry to standardowe przyrządy stosowane w szpitalach. Wykorzystując względną absorbancję hemoglobiny natlenionej i odtlenionej, urządzenia te określają procent krwi pacjenta, która przenosi tlen (zdrowy zakres to 94-9
Licznik kroków - Micro:Bit: 12 kroków (ze zdjęciami)
Licznik kroków - Micro:Bit: Ten projekt będzie licznikiem kroków. Do pomiaru kroków użyjemy czujnika przyspieszenia wbudowanego w Micro:Bit. Za każdym razem, gdy Micro:Bit się trzęsie, dodamy 2 do licznika i wyświetlimy go na ekranie
Bolt - DIY Wireless Charging Night Clock (6 kroków): 6 kroków (ze zdjęciami)
Bolt - DIY Wireless Charging Night Clock (6 kroków): Ładowanie indukcyjne (znane również jako ładowanie bezprzewodowe lub ładowanie bezprzewodowe) to rodzaj bezprzewodowego przesyłania energii. Wykorzystuje indukcję elektromagnetyczną do dostarczania energii elektrycznej do urządzeń przenośnych. Najpopularniejszym zastosowaniem jest stacja ładowania bezprzewodowego Qi
Pulsoksymetr mikrokontrolowany: 5 kroków
Pulsoksymetr z mikrokontrolą: W ramach tego projektu zamierzam pokazać, co zrobiłem do tej pory z moim projektem pulsoksymetru z mikrokontrolą. Moja pasja do elektroniki i fitnessu jest bardzo silna, dlatego postanowiłem stworzyć projekt, który pozwoli mi wykorzystać obie pasje
Pulsoksymetr wykorzystujący Arduino Nano, MAX30100 i Bluetooth HC06.: 5 kroków
Pulsoksymetr wykorzystujący Arduino Nano, MAX30100 i Bluetooth HC06.: Hej, dzisiaj zbudujemy urządzenie sensoryczne do odczytywania poziomu tlenu we krwi i tętna w nieinwazyjny sposób przy użyciu czujnika MAX30100. to rozwiązanie czujnika pulsoksymetrycznego i pulsometru. Łączy w sobie dwa