Inteligentna stacja pogodowa z pomiarem jakości powietrza

Inteligentna stacja pogodowa z pomiarem jakości powietrza

Stacje pogodowe to zawsze wdzięczny temat na projekty elektroniczne. Zaprezentowana wersja wyróżnia się tym, że korzysta z możliwości sztucznej inteligencji do prognozowania pogody. Dodatkową funkcją jest monitorowanie poziomu ozonu, który jest szkodliwy, w atmosferze przy powierzchni Ziemi. Ten ciekawy projekt będzie jest tylko praktycznym urządzeniem, ale też doskonale nadaje się do nauki algorytmów AI.

Na przestrzeni ostatnich dekad poziom zanieczyszczenia powietrza stale się zwiększa, ale w ostatnim czasie mamy też do czynienia z okresowymi falami kumulacji zanieczyszczeń. Zależą one od pory roku, warunków pogodowych, miejsca itp. Oddychanie powietrzem o złej jakości ma wiele negatywnych następstw, zwłaszcza dla osób z problemami układu oddechowego. Monitorowanie jakości powietrza w celu podjęcia środków ostrożności, aby utrzymać zdrowy układ oddechowy, ma kluczowe znaczenie dla osób wrażliwych, takich jak chorzy na astmę i inne choroby płuc, osoby starsze, dzieci, młodzież i osoby aktywnie spędzające czas na świeżym powietrzu.

Mimo że podejmowane są międzynarodowe wysiłki na rzecz zmniejszenia zanieczyszczenia powietrza, lokalne śledzenie jakości powietrza w celu uzyskania wyprzedzających ostrzeżeń dotyczących czynników ryzyka jest cały czas ważną kwestią. Chociaż wiele czynników może prowadzić do złej jakości powietrza, dwa najczęstsze są związane z podwyższonym stężeniem ozonu w warstwie przyziemnej oraz nadmierna koncentracją cząstek stałych w powietrzu. Ozon w warstwie przyziemnej powstaje, gdy tlenki azotu (NOx) ze źródeł takich jak spaliny samochodowe i emisje przemysłowe reagują ze związkami organicznymi w obecności ciepła i światła słonecznego. Innymi słowy, ozon powstaje, gdy dwa rodzaje zanieczyszczeń (lotne związki organiczne – LZO i tlenki azotu – NOx) reagują przy udziale światła słonecznego. Zanieczyszczenia te zwykle pochodzą ze spalin pojazdów, przemysłu, elektrowni czy produktów takich jak rozpuszczalniki i farby. Ozon w warstwie przyziemnej (O3) może powodować trudności w oddychaniu, nasilać przewlekłe choroby układu oddechowego, zwiększać podatność płuc na infekcje i zwiększać częstotliwość ataków astmy. W związku z tym stężenie ozonu w powietrzu może posłużyć, jako parametr (oprócz lokalnych danych pogodowych) do prognozowania jakości powietrza. Z kolei drugi czynnik – pył zawieszony w powietrzu – składa się z cząstek stałych i ciekłych, w tym dymu, pyłu i innych aerozoli – niektóre z nich są produktami ubocznymi przemian chemicznych.

Zanieczyszczenia powietrza mogą wpływać na ludzi w różny sposób w zależności od warunków pogodowych. Ponieważ różne aspekty pogody wpływają na ilość ozonu i cząstek stałych obecnych na określonym obszarze, zmiany pogody mają realny wpływ, na jakość powietrza, jakie nas otacza. Nasłonecznienie, deszcz, wyższe temperatury, prędkość wiatru, turbulencje powietrza i głębokość mieszania zmieniają stężenie zanieczyszczeń. Dlatego lokalne śledzenie poziomów parametrów, przekładających się, na jakość powietrza jest niezbędne, aby zapobiegać ryzyku chorób układu oddechowego, zwłaszcza w przypadku grup wrażliwych, wymienianych wcześniej.

Jak zauważa autor projektu, Kutluhan Aktar, w wielu miejscach na świecie, lokalne monitory parametrów powietrza są niedostępne lub są kiepskiej jakości. Dlatego też, zdecydował się na samodzielne wykonanie niedrogiej stacji meteorologicznej, która prognozuje poziom jakości powietrza.

Zaprezentowany system bazuje na module Arduino Nano 33 z interfejsem Bluetooth Low Energy (BLE) i zestawia lokalne dane pogodowe ze zmierzonym poziomem stężenia ozonu, a następnie wysyła te informacje przez BLE do Raspberry Pi, gdzie tworzony jest zestaw danych podawanych do wcześniej wytrenowanej sieci neuronowej. Sieć bazująca na frameworku TensorFlow pozwala na predykcję poziomu jakości powietrza, a wynik jest wyświetlany na samej stacji pogodowej. Cała stacja pogodowa zamknięta jest w kompaktowej obudowie wykonanej w druku 3D, która pozwala na umieszczenie jej w dogodnym miejscu, pozwalającym monitorować warunki otoczenia.

Potrzebne elementy

Omawiany system zbudowany jest z szeregu gotowych, komercyjnych modułów elektronicznych, dzięki czemu samodzielne zmontowanie podobnego urządzenia nie jest problemem. Do zestawienia systemu potrzebne są:

  • moduł Arduino Nano 33 BLE,
  • komputer jednopłytkowy Raspberry Pi 3B+ lub 4,
  • sensor ozonu od DFRobot na I²C,
  • zestaw anemometru DFRobot,
  • dotykowy wyświetlacz IPS o przekątnej 8,9 cala i rozdzielczości 1920×1200 od DFRobot,
  • sensor BMP180,
  • wyświetlacz OLED z kontrolerem SSD1306,
  • płytka z przetwornicą zasilaną z USB do stabilizacji napięcia zasilania dla modułów.

Oprócz tego potrzebne są drobne elementy elektroniczne, takie jak:

  • zielona dioda LED 5 mm,
  • opornik 2,2 kΩ,
  • opornik 3,3 kΩ,
  • kable połączeniowe do modułów z goldpinami 2,54 mm.

Dodatkowo potrzebna jest płytka stykowa bądź płytka uniwersalna, aby połączyć ze sobą wszystkie elementy oraz źródło zasilania. Autor rekomenduje zastosowanie powerbanka o dużej pojemności (np. 20 000 mAh) z wyjściem USB.

Do wyprodukowania obudowy potrzebna jest oczywiście drukarka 3D oraz odpowiedni filament (autor drukował obudowę z czarnego PLA, ale nic nie stoi na przeszkodzie, aby użyć innego koloru czy materiału, (oczywiście po zmianie parametrów druku).

Sztuczna inteligencja

Ponieważ jakość powietrza zmienia się w zależności od różnych zjawisk, z których niektóre nie są jeszcze w pełni zbadane, nie można ekstrapolować i interpretować jakości powietrza przy użyciu jedynie ograniczonych lokalnych danych pogodowych o stężeniu ozonu bez utworzenia bardziej złożonych algorytmów czy uwzględniania innych danych. Dlatego też autor zdecydował się na wykorzystanie lokalnej oceny wskaźnika jakości powietrza (AQI) dostarczone przez portal IQAir, jako etykiety, aby zbudować i wytrenować model sztucznej sieci neuronowej do prognozowania poziomów jakości powietrza na podstawie lokalnych danych pogodowych o stężeniu ozonu.

Moduł Arduino Nano 33 BLE został użyty w projekcie, ponieważ może on z łatwością zbierać lokalne dane pogodowe o stężeniu ozonu i może uruchamiać wyuczoną sieć neuronową (po przeszkoleniu na zewnątrz – na wydajniejszym sprzęcie). Aby zebrać wymagane dane do trenowania modelu, do układu podłączono czujnik ozonu, anemometr i precyzyjny czujnik BMP180. Wszystko sterowane jest z poziomu Nano 33 BLE, które wyświetla informacje na ekranie OLED, co pozwala na monitorowanie zebranych danych w dowolnej sytuacji.

Ponieważ dane zbierane były lokalnie (na balkonie mieszkania autora systemu) można było przesłać je z Arduino Nano 33 do Raspberry Pi 4, które znajdowało się w domu. Dane przesyłano w czasie rzeczywistym przez Bluetooth Low Energy. Uprościło to zbieranie danych, gdyż nie trzeba było posiłkować się pośrednim magazynowaniem ich w chmurze itp.

Po skompletowaniu zestawu danych uczących, możliwe było zbudowanie modelu sztucznej sieci neuronowej (ANN) za pomocą TensorFlow, aby przewidywać poziomy (klas) jakości powietrza na podstawie lokalnych danych pogodowych o stężeniu ozonu. Aby wytrenować ANN konieczne było opisywanie danych – każdy wpis z danymi pogodowymi, zebranymi przez Arduino, musiał być w odpowiedni sposób opisany. Aby uprościć sobie ten opis, każdy pomiar został opisany klasą jakości powietrza w odniesieniu do lokalnej oceny wskaźnika jakości powietrza (AQI) dostarczonej przez IQAir. Autor zdecydował się na trzy klasy czystości powietrza:

  • dobre powietrze,
  • umiarkowana jakość powietrza,
  • powietrze szkodliwe dla zdrowia.

Po przeszkoleniu i przetestowaniu modelu sieci neuronowej został on przekonwertowany z modelu TensorFlow Keras H5 na macierz w C (plik *.h), aby uruchomić ten model na Arduino Nano 33 BLE. Dzięki temu stacja pogodowa jest w stanie estymować poziomy (klasy) jakości powietrza poprzez uruchomienie modelu w terenie na podstawie zbieranych z otoczenia danych – wszystko bez konieczności komunikacji np. z usługą w chmurze.

W dalszej części artykułu przyjrzymy się bliżej całemu opisowi zbierania danych uczących za pomocą Arduino, adnotacji ich danymi dotyczącymi jakości powietrza, treningowi sieci i implementacji wyuczonego modelu na platformie Arduino Nano.

Obudowa urządzenia

Ponieważ lokalne dane pogodowe o stężeniu ozonu itd. miały być zbierane na balkonie na zewnątrz, obudowa systemu musi zapewnić mu ochronę przed warunkami środowiskowymi, przy jednoczesnym zapewnieniu bezbłędnej pracy sensorów. Autor zaprojektował w tym celu obudowę (rysunek 1), która zabezpiecza poszczególne elementy.

Rysunek 1. Projekt obudowy układu

Obudowa została zaprojektowana w Autodesk Fusion 360. Można pobrać wynikowy plik STL ze strony z projektem. Projekt uzupełniony jest ozdobną figurką wiatraka, która powstała z elementów pobranych z Thingverse. Projekty zostały pocięte w Ultimaker Cura i wydrukowane z PLA z czarnego filamentu (obudowa) i filamentu z domieszką drewna (wiatrak). Wydrukowane elementy pokazano na fotografii 1. Wszystkie części zostały wydrukowane za pomocą drukarki 3D Creality CR-6 SE. Chociaż są to jedne z pierwszych wydruków, jakie autor wykonał, okazało się, że bez wielkiego wysiłku udało mu się osiągnąć bardzo zadowalający efekt.

Fotografia 1. Wydrukowana obudowa i ozdabiający nią model wiatraka

Połączenie modułów

Aby zbierać i wyświetlać lokalne dane pogodowe ze stężeniem ozonu do Nano 33 BLE podłączony został czujnik ozonu z interfejsem I²C, a także anemometr, precyzyjny sensor BMP180 oraz wyświetlacz OLED z kontrolerem SSD1306. Do układu dodano również zieloną diodę LED o średnicy 5 mm, która wskazuje wyniki działania funkcji oraz przycisk do uruchamiania sieci neuronowej, jak pokazano w tabeli 1.

Ponieważ anemometr wymaga napięcia zasilania w zakresie od 9 V do 24 V i generuje napięcie wyjściowe w zakresie od 0 V do 5 V (sygnał analogowy), nie można go podłączyć bezpośrednio do Nano 33 BLE pracującego przy zasilaniu 3,3 V. Dlatego do źródła zasilania w układzie (powerbanka z wyjściem USB 5 V) podłączono moduł przetwornicy buck-boost, która pozwala na wyjściu uzyskać stabilizowane napięcie 20 V. To napięcie może być użyte do zasilania anemometru. Następnie należy dobudować prosty obwód obniżający napięcie – oporniki 2,2 kΩ i 3,3 kΩ formujące dzielnik napięcia, aby przekonwertować sygnał wyjściowy anemometru (5 V) na wejście o zakresie około 3,3 V.

W zaprezentowanym systemie wszystkie sensory (oprócz anemometru, wyposażonego w wyjście analogowe) mają wyjście cyfrowe – interfejs I²C. Jest to dwuprzewodowa magistrala szeregowa zawierająca linię zegarową (SCL) i linię danych (SDA). Dzięki temu, że każde urządzenie w sieci I²C zawiera swój unikalny adres, można je wszystkie połączyć w jednej sieci. Stąd też wszystkie linie SDA i SCL połączone są ze sobą i podłączone do wyprowadzeń odpowiednio A4 i A5, modułu z mikrokontrolerem.

Gdy czujnik ozonu jest włączany po raz pierwszy, wymaga pracy przez około 24...48 godzin, aby możliwe było wygenerowanie stabilnych wyników. W przypadku opisanego prototypu, czujnik ozonu zaczął generować stabilne wyniki dopiero o po 29 godzinach pracy.

Chociaż czujnik ten wymaga tylko jednorazowej kalibracji, czas wstępnego nagrzewania po włączeniu wynosi około 3 minut. Dopiero po tym czasie jest w stanie zmierzyć poziom ozonu. Anemometr należy podłączyć do zasilania 20 V oraz do wejścia analogowego Arduino Nano 3 BLE. Sygnał analogowy z sensora wyprowadzony jest na żółtym przewodzie. Połączenia można przylutować bezpośrednio do płytki z mikrokontrolerem, można użyć przewodów połączeniowych lub zastosować płytkę stykową.

Ostatnim etapem montażu modułów, jest umieszczenie całości w wydrukowanej obudowie. Punkty styku modułów i płytki stykowej z obudową dobrze jest usztywnić za pomocą kleju na ciepło. Na koniec na wierzchu obudowy autor zamocował ozdobną figurkę wiatraka.

Konfiguracja Arduino

Ponieważ Arduino Nano 33 BLE może przesyłać pakiety danych przez Bluetooth tylko na niewielką odległość – z balkonu do domu, co daje zasięg około 3 metrów, autor zdecydował się użyć Raspberry Pi 4 do odbierania danych i rejestrowania zebranych lokalnie danych pogodowych ze stężeniem ozonu bez stosowania dodatkowych procedur. Jednak przed wykonaniem poniższych kroków należy odpowiednio skonfigurować Arduino Nano 33 BLE, a w Arduino IDE zainstalować wymagane biblioteki dla tego projektu.

Pierwszą czynnością, jaką należy wykonać, to w menu Tools należy wybrać Board → Boards Manager i wyszukać tam Arduino Mbed OS Nano. Następnie, aby wybrać Nano 33 BLE, trzeba przejść do Tools → Board i wybrać Arduino Mbed OS Nano Boards. Aby pobrać bibliotekę ArduinoBLE do Arduino IDE, należy przejść do Sketch → Include Library i finalnie Manage Libraries. Tam należy wyszukać ArduinoBLE.

Finalnie należy jeszcze doinstalować biblioteki dla czujnika ozonu, układu BMP180 i wyświetlacza OLED SSD1306: DFRobot_OzoneSensor, Adafruit-BMP085-Library, Adafruit_SSD1306 oraz Adafruit-GFX-Library.

Zbieranie danych za pomocą Raspberry Pi

Po skonfigurowaniu Arduino Nano 33 BLE można przystąpić do zbierania danych pogodowych i dotyczących koncentracji ozonu. W sieci Bluetooth Low Energy urządzenie może pełnić dwie role – centralną lub peryferyjną. Peryferium, nazywane czasami klientem, przekazuje informacje na swój temat urządzeniom dookoła siebie, a urządzenie centralne, zwane serwerem, skanuje otoczenie w poszukiwaniu tego rodzaju informacji. Aby uniknąć opóźnień lub utraty pakietów podczas przesyłania lokalnych danych pogodowych ze stężeniem ozonu przez BLE, wszystkie parametry (2 zmiennoprzecinkowe i 3 liczby całkowite) umieszczone zostały w jednej strukturze. Takie rozwiązanie pozwala na przekazywanie jednocześnie wszystkich 20 bajtów.

Ze strony z projektem można pobrać szkic Arduino ozone-enabled_weather_station_data_collect.ino, aby przetestować kod do zbierania lokalnych danych pogodowych ze stężeniem ozonu i przesyłania informacji przez BLE. Na stronie z projektem, oprócz samego kodu źródłowego, znaleźć można również dokładniejszy opis zasady działania programu krok po kroku. Z uwagi na objętość opis ten zostanie skrócony.

W pierwszej kolejności oprogramowanie w Arduino musi uruchomić usługę BLE i przygotować tzw. charakterystykę danych. Pozwala to zdalnemu urządzeniu centralnemu na zapis i odczyt danych (listing 1).

Listing 1. Uruchomienie usługi BLE i przygotowanie tzw. charakterystyki danych

BLEService air_quality_service(“19B10000-E8F2-537E-4F6C-D104768A1214”);
BLECharacteristic airDataCharacteristic(“19B10001-E8F2-537E-4F6C-D104768A1214”, BLERead | BLEWrite, 20);

Następnie definiowane są elementy potrzebne do odczytu danych z sensora ozonu – timer i interfejs I²C. Przy tym ostatnim należy pamiętać o wybraniu odpowiedniego adresu urządzenia. Następnie w analogiczny sposób definiowane są elementy dla sensora BMP180 oraz konfigurowane jest wejście analogowe do pomiaru napięcia wyjściowego z anemometru.

Kolejnym krokiem jest zdefiniowanie stałych konfigurujących ekran OLED – rozdzielczość i podłączenie pinu OLED_RESET, co potrzebne jest do inicjalizacji kontrolera SSD1306 (listing 2).

Listing 2. Inicjalizacja kontrolera SSD1306

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

Następnie definiowana jest struktura data, która wykorzystywana jest do przesyłania danych (listing 3).

Listing 3. Struktura do przesyłania danych

struct data {
 float _temperature;
 float _altitude;
 int ozoneConcentration;
 int _pressure;
 int wind_speed;
};
struct data air_Quality_Data;

Następnie system inicjalizuje i konfiguruje poszczególne elementy systemu i wyświetla na ekranie OLED (i przez interfejs szeregowy, jeśli takowy jest aktywowany w oprogramowaniu) ewentualne błędy przy rozruchu poszczególnych elementów urządzenia. Finalnie, Arduino uruchamia Bluetooth – konfigurowana jest lokalna nazwa (AirQuality) Nano 33 BLE i definiowany jest UUID usługi, jaką rozgłasza Arduino. Do usługi dodawana jest charakterystyka, a finalnie usługa łączona jest z urządzeniem. Do obsługi podłączających i odłączających się urządzeń w kodzie znajduje się odpowiednia funkcja (event handler). Po ustawieniu domyślnych/początkowych danych w systemie, układ zaczyna rozgłaszać informacje przez Bluetooth, aby nawiązać połączenie z urządzeniem centralnym (listing 4).

Listing 4. Po ustawieniu domyślnych/początkowych danych układ zaczyna rozgłaszać informacje przez Bluetooth, aby nawiązać połączenie z urządzeniem centralnym

BLE.setLocalName(“AirQuality”);
BLE.setAdvertisedService(air_quality_service);
air_quality_service.addCharacteristic(airDataCharacteristic);
BLE.addService(air_quality_service);
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
airDataCharacteristic.writeValue((byte)0);
BLE.advertise();

Funkcja update_characteristics aktualizuje dane, używając do tego zdefiniowanej wcześniej struktury, aby przesłać wszystkie dane naraz. Po uruchomieniu program przez 3 minuty czeka, aż sensor ozonu się nagrzeje. Następnie rozpoczyna transmisję danych, wysyłając co 20 sekund paczkę danych do Raspberry Pi przez Bluetooth Low Energy.

W dalszej części szkicu znaleźć można niskopoziomowe funkcje odpowiedzialne za odczyt poziomu stężenia ozonu, prędkości wiatru, temperatury itp. przez poszczególne sensory. Wszystkie mierzone wartości są również wyświetlane na ekranie OLED stacji pogodowej.

Są to:

  • stężenie ozonu (ppb),
  • prędkość wiatru,
  • temperatura (°C),
  • ciśnienie (Pa),
  • wysokość nad poziomem morza (m).

Po załadowaniu kodu i jego uruchomieniu dane pogodowe będą automatycznie zbierane przez Bluetooth i zapisywane w pamięci komputera jednopłytkowego Raspberry Pi. Po poprawnym przesłaniu pakietu danych na stacji pogodowej mruga zielona dioda LED, a na ekranie OLED pokazywany jest komunikat o powodzeniu transmisji. Ponadto stacja pogodowa drukuje zebrane lokalne dane pogodowe ze stężeniem ozonu na porcie szeregowym (jeśli jest on uruchomiony). W razie potrzeby stacja pogodowa podaje tam również informacje adresowe Nano 33 BLE (urządzenie peryferyjne) na porcie szeregowym:

MAC Address: 4c:f9:a9:9a:b2:da
Service UUID Address: 19B10000-E8F2-537E-4F6C-D104768A1214
Characteristic UUID Address: 19B10001-E8F2-537E-4F6C-D104768A1214

Po skonfigurowaniu klienta, można przystąpić do oprogramowania centralnego urządzenia – Raspberry Pi. Loguje ono dane, za pomocą skryptu napisanego w Pythonie. Wykorzystuje on moduł bluepy, który należy zainstalować przed przystąpieniem do uruchamiania skryptów poprzez wspisanie w konsoli:

sudo pip install bluepy

W repozytorium projektu znaleźć można prostą aplikację do logowania danych z Arduino w pliku CSV. Aplikacja składa się z dwóch plików:

air_quality_BLE_data_collection.py
air_quality_data_set.csv

Kluczowym elementem skryptu jest klasa air_quality. Po zainicjalizowaniu obiektu tej klasy Raspberry Pi jest gotowe do odbierania danych przez Bluetooth (__init__ konfiguruje adres MAC, UUID usługi i charakterystyki danych itd). Kluczową metodą obiektu jest obtain_characteristics (listing 5).

Listing 5. Funkcja, która odbiera dane i umieszcza je w macierzy

def obtain_characteristics(self):
self.air_data = []
for data in self.characteristics:
if(data.uuid == self.Characteristic_UUID_Address):
self.air_data.extend(unpack(‘ffiii’, data.read()))
_date = datetime.datetime.now().strftime(“%m-%d-%y_%H:%M:%S”)
self.air_data.append(_date)
sleep(1)

Funkcja ta odbiera dane i umieszcza je w macierzy (air_data). Następnie dane odebrane z Arduino do macierzy w pamięci Raspberry Pi zapisywane są w pliku CSV z użyciem metody insert_data_to_CSV w kodzie. Każdy nowy wpis – nowa macierz z pamięci Raspberry Pi to jedna transmisja danych i jedna linijka pliku CSV. Dane zapisywane są do pliku CSV co 30 sekund. Jeżeli program wykryje przerwanie z klawiatury (naciśnięty zostanie jakiś przycisk) odłącza się on od urządzenia Bluetooth.

Anotacja danych – określenie jakości powietrza

Ponieważ zjawiska i kaprysy pogody, z których niektóre nie są nawet jeszcze w pełni zbadane, mają realny wpływ, na jakość powietrza, algorytm, tworzony w tym systemie, stara się ekstrapolować i estymować poziom jakości powietrza, wykorzystując do tego jedynie ograniczone lokalne dane pogodowe o stężeniu ozonu itp. bez stosowania predefiniowanych algorytmów. Tego rodzaju zadanie może być realizowane przez sieć neuronową. Problemem jednak jest to, że aby zastosować sieć neuronową do prognozowania poziomu jakości powietrza ze stacją pogodową w terenie, należy ją najpierw wytrenować.

Do wytrenowania algorytmu potrzebny jest odpowiednio duży zbiór danych uczących. Aby dane takie nadawały się do trenowania sieci neuronowej trzeba przypisać odpowiednie etykiety do każdego rekordu danych, aby precyzyjnie prognozować poziomy jakości powietrza przy ograniczonej ilości danych. Czynność ta nazywa się anotacją.

Rysunek 2. Serwis IQAir, pokazujący jakość powietrza w wielu miejscach na świecie

Autor skorzystał z serwisu internetowego IQAir (rysunek 2), który podaje estymację wskaźnika jakości powietrza (AQI) dla danego terenu na podstawie danych satelitarnych dotyczących stężenia pyłów PM2,5 w danej lokalizacji. Dzięki temu możliwe jest automatyczne oznaczenie każdego wpisu z danymi zmierzonymi przez system etykietą pochodzącą z IQAir. Aby łatwiej synchronizować wszystkie pomiary do paczki danych, wysyłanej przez Arduino, dodawana jest data i godzina.

Dane zawierają następujące wartości:

  • temperatura,
  • wysokość,
  • stężenie ozonu,
  • ciśnienie,
  • prędkość wiatru,
  • data.

Korzystając z elementu data, dodawane są etykiety dla każdego rekordu danych wykorzystując oceny AQI dla danej lokalizacji dostarczonych przez IQAir:

  • 0 – dobra jakość powietrza,
  • 1 – umiarkowana jakość powietrza
  • 2 – powietrze szkodliwe dla zdrowia.

Po zebraniu lokalnych danych pogodowych ze stężeniem ozonu przez 15 dni, skrypt labels.py pozwolił na automatyczną adnotację w tablicy labels (kod źródłowy, dostępny w repozytorium).

Przygotowanie sieci neuronowej

Po zestawieniu danych uczących i wyprowadzeniu etykiet, autor rozpoczął pracę nad modelem sztucznej sieci neuronowej (ANN). Jako framework wybrano TensorFlow w Pythonie. W związku z tym rozpoczęto od wykonania poniższych kroków, aby lepiej zrozumieć zestaw danych i dostosować do nich budowę modelu:

  • wizualizacja danych,
  • skalowanie danych (normalizacja),
  • wstępne przetwarzanie danych,
  • dzielenie danych.

Po skalowaniu (normalizowaniu) i wstępnym przetwarzaniu danych wejściowych uzyskano pięć zmiennych wejściowych i jedną etykietę dla każdego rekordu danych w zbiorze danych. Następnie zbudowano model sztucznej sieci neuronowej za pomocą TensorFlow. Został on wytrenowany za pomocą zestawu danych treningowych, tak, aby uzyskać najlepsze możliwe wyniki i przewidywania. Sieć składa się z czterech warstw:

  1. Warstwa wejściowa, 5 neuronów,
  2. Warstwa ukryta, 128 neuronów,
  3. Warstwa ukryta, 64 neuronów,
  4. Warstwa wyjściowa, 3 neurony.
Rysunek 3. Graficzna prezentacja sieci neuronowej, zastosowanej do estymacji jakości powietrza

Model tej sieci wizualnie zaprezentowano na rysunku 3, pokazującym zrzut ekranu z aplikacji Netron, graficznego interfejsu do prezentacji sieci neuronowych różnego rodzaju. Wszystkie powyższe kroki realizowane są w skrypcie napisanym w Pythonie. Aplikacja ta składa się z trzech plików *.py i dwóch folderów. Wszystkie podstawowe operacje realizowane są w klasie Air_Quality_Level w pliku main.py.

Normalizacja wektorów danych wejściowych

Po zapoznaniu się z danymi przy pomocy prostych wizualizacji (rysunek 4), należy przygotować pięć wejść do sieci neuronowej.

Rysunek 4. Mapa korelacji koncentracji ozonu z: a) temperaturą, b) wysokością barometryczną, c) ciśnieniem i d) prędkością wiatru

Zastosowano następujące parametry:

  • temperatura,
  • wysokość nad poziomem morza,
  • stężenie ozonu,
  • ciśnienie,
  • prędkość wiatru.
Listing 6. Funkcja zapisująca dane w pliku CSV

def insert_data_to_CSV(self, file_name):
with open(file_name, “a”, newline=””) as f:
writer(f).writerow(self.air_data)
f.close()

Następnie każda z tych wartości została przeskalowana (znormalizowana), aby podać je na neurony wejściowe CNN. W ten sposób otrzymano rekord:

  • scaled_Temperature,
  • scaled_Altitude,
  • scaled_Ozone,
  • scaled_Pressure,
  • scaled_Wind_Speed.

Za skalowanie danych odpowiada funkcja scale_data_and_define_inputs (listing 7), która dzieli każdą zmienną przez odpowiedni współczynnik tak, aby każda wartość była równa bądź mniejsza 1. Następnie dane te zostały skonwertowane do wektora NumPy, który można podać do algorytmu uczącego sieć.

Listing 7. Funkcja odpowiedzialna za skalowanie danych

def scale_data_and_define_inputs(self):
self.df[“scaled_Temperature”] = self.df[“Temperature”] / 100
self.df[“scaled_Altitude”] = self.df[“Altitude”] / 100
self.df[“scaled_Ozone”] = self.df[“Ozone_Concentration”] / 1000
self.df[“scaled_Pressure”] = self.df[“Pressure”] / 100000
self.df[“scaled_Wind_Speed”] = self.df[“Wind Speed”] / 30
for i in range(len(self.df)):
self.inputs.append(np.array([self.df[“scaled_Temperature”][i], self.df[“scaled_Altitude”]
[i],self.df[“scaled_Ozone”][i], self.df[“scaled_Pressure”][i],
self.df[“scaled_Wind_Speed” [i]]))
self.inputs = np.asarray(self.inputs)

Etykiety anotujące dane oznaczają jakość powietrza i mogą przyjmować wartość 0, 1 oraz 2. Funkcja define_and_assign_labels przypisuje każdemu wektorowi z danymi odpowiednią wartość etykiety. Tak przygotowane dane mogą być wykorzystane do treningu wcześniej przygotowanej sieci neuronowej.

Trening sieci neuronowej i ocena jej dokładności

Po przygotowaniu zbioru uczącego i jego normalizacji, dane są dzielone na zespół treningowy (95% wpisów) i zespół testowy (5%). Podział jest konieczny, gdyż w treningu sieci neuronowej wymagane są właśnie dwa zespoły – jeden do treningu, a drugi do sprawdzenia jego jakości. Następnie zbudowano sieć neuronową z użyciem Keras i przystąpiono do jej treningu przez 100 epok (tak określa się liczbę przejścia przez cały zbiór uczący).

Po przeprowadzeniu treningu sieci i zbudowaniu jej modelu (w postaci pliku w formacie TensorFlow Keras H5 – air_quality_level.h5) można było przekazać sieć do testów. Badania z wykorzystaniem przygotowanego wcześniej zestawu danych testowych, wykazały dokładność działania modelu wynoszącą 91,58%.

Implementacja modelu na Arduino

Uruchomienie modelu TensorFlow Keras H5 na Arduino Nano 33 BLE nie jest zbyt rozsądne, z uwagi na rozmiar modelu, wprowadzane opóźnienia i bardzo wysokie zużyci energii takiego systemu. Z tego powodu model musi zostać przekonwertowany z sieci neuronowej TensorFlow Keras H5 (.h5) na model TensorFlow Lite (.tflite). Następnie autor zmodyfikował otrzymany model TensorFlow Lite, aby utworzyć tablicę dla języka C (plik .h), która pozwala pomyślnie uruchomić model na Nano 33 BLE.

Listing 8. Funkcja, która konwertuje ostatnio trenowany i oceniany model na model TensorFlow Lite

def convert_TF_model(self, path):
converter = tf.lite.TFLiteConverter.from_keras_model(self.model)
tflite_model = converter.convert()
with open(path + ‘.tflite’, ‘wb’) as f:
f.write(tflite_model)
with open(“model/{}.h”.format(self.model_name), ‘w’) as file:
file.write(hex_to_c_array(tflite_model, self.model_name))

Aby zmienić model TensorFlow Lite na macierz w C, autor wykorzystał funkcję hex_to_c_array, skopiowaną z samouczka do pliku tflite_to_c_array.py. Funkcja convert_TF_model (listing 8) konwertuje ostatnio trenowany i oceniany model na model TensorFlow Lite, stosując konwerter TensorFlow Lite. Następnie wygenerowany model jest zapisywany w folderze modelu. Zapisany model jest finalnie konwertowany na macierz w C, która zapisywana jest w pliku air_quality_level.h.

Po zbudowaniu, przeszkoleniu i przekonwertowaniu modelu sieci neuronowej na tablicę C (plik .h), można ją przesłać i uruchomić model bezpośrednio na Arduino Nano 33 BLE, aby utworzyć wydajną stację pogodową, działającą bez żadnych dodatkowych elementów czy połączenia z Internetem. Skompilowanie szkicu Arduino z modelem TensorFlow wymaga użycia biblioteki TensorFlow Lite for Microcontrollers. Framework ten nie wymaga obsługi systemu operacyjnego, żadnych dodatkowych bibliotek C lub C++ ani dynamicznej alokacji pamięci, doskonale sprawdza się na platformach takich jak Arduino Nano 33 BLE. Aby pobrać oficjalną bibliotekę TensorFlow w Arduino IDE, należy w menu Sketch wybrać, Include Library, a następnie Manage Libraries… i tam wyszukać TensorFlow. Można z poziomu tego menu zainstalować potrzebną nam bibliotekę. Po jej zainstalowaniu trzeba zaimportować model sieci neuronowej (air_quality_level.h) i już można rozpocząć wnioskowanie.

Ostatnim krokiem jest zdefiniowanie wartości progowej (domyślnie jest to 0,75) dla wyjść modelu (wyników) oraz zdefiniowanie nazw poziomów (klas) jakości powietrza, np. jako:

  • dobrze,
  • umiarkowanie,
  • powietrze niezdrowe.

Oba te aspekty zaimplementowane są w szkicu Arduino (listing 9).

Listing 9. Zdefiniowanie wartości progowej dla wyjść modelu oraz zdefiniowanie nazw poziomów (klas) jakości powietrza

float threshold = 0.75;
String classes[] = {“Dobrze”, “Umiarkowanie”, “Powietrze niezdrowe”};

Implementując model w szkicu Arduino należy pamiętać o uzupełnieniu implementacji biblioteki o niezbędnej jej do działania rzeczy – przydzielenie pamięci dla sieci neuronowej oraz zdefiniowanie wskaźników, które posłużą do przekazywania danych z i do sieci. Finalnie, podając do sieci dane pomiarowe do analizy, trzeba pamiętać o ich normalizacji w taki sam sposób, jak robiono to na potrzeby danych trenujących sieć. Po zakończeniu każdej inferencji (wnioskowania) układ mignie diodą LED, co oznacza że układ działa. W programie sieć neuronowa nie jest uruchamiana cały czas, a działa na życzenie – po naciśnięciu przycisku jest ona uruchamiana, a wyniki wyświetlane są na ekranie OLED układu.

Podsumowanie

Model sieci neuronowej przewiduje klasę jakości powietrza dla każdego podanego wejścia – zmierzonych warunków pogodowych. Sieć neuronową zaprojektowano tak, aby miała trzy wyjścia, odpowiadające trzem klasom jakości powietrza. Na ich wyjściach sieć podaje prawdopodobieństwo, że warunki za oknem są właśnie tej klasy. To właśnie na podstawie tych parametrów urządzenie ocenia, jaka jest aktualna klasa jakości powietrza.

Sieć neuronowa, użyta w systemie została utworzona z zastosowaniem frameworku TensowFlow, a następnie skonwertowana do wersji nadającej się do uruchomienia na mikrokontrolerze w środowisku Arduino. Jest ono wyposażone w specjalnie doinstalowane biblioteki, pozwalające na uruchamianie TensorFlow Lite. Aby oszczędzać energię, układ działa na żądanie. Po fazie rozruchu, która trwa aż 3 minuty (tyle potrzebuje sensor ozonu, aby wykonywać poprawne pomiary), układ mierzy parametry środowiska:

  • stężenie ozonu,
  • prędkość wiatru,
  • temperaturę,
  • ciśnienie,
  • wysokość nad poziomem morza.

Jeśli przycisk modelu zostanie naciśnięty, stacja pogodowa przeprowadza wnioskowanie w sieci neuronowej, wykorzystując, jako dane wejściowe ostatnio wygenerowane lokalne dane pogodowe ze stężeniem ozonu. Następnie stacja pogodowa wyświetla dane wyjściowe, które reprezentują najdokładniejszą etykietę (klasę jakości powietrza) przewidywaną przez model. Po pomyślnym przeprowadzeniu wnioskowania, stacja pogodowa powiadamia miganiem zielonej diody LED i wyświetla informację na ekranie OLED.

Nikodem Czechowski, EP

Źródła: http://bit.ly/3sLPZui, http://bit.ly/3sK5brC

Artykuł ukazał się w
Elektronika Praktyczna
listopad 2022

Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik marzec 2024

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio marzec - kwiecień 2024

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka, Podzespoły, Aplikacje marzec 2024

Automatyka, Podzespoły, Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna marzec 2024

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich kwiecień 2024

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów