AKADEMIA GÓRNICZO-HUTNICZA im. St. Staszica w Krakowie WEAIiE, Katedra Automatyki Laboratorium Biocybernetyki Przedmiot: Przetwarzanie sygnałów w systemach diagnostyki medycznej Temat projektu: ARRH_DET Detekcja arytmii PR09506 Spis treści: 1. ABSTRAKT... 2 2. WSTĘP... 3 3. KONCEPCJA PROPONOWANEGO ROZWIĄZANIA... 6 3.1 SCHEMAT DZIAŁANIA PROGRAMU GŁÓWNEGO... 6 3.2 DANE WEJŚCIOWE I WYJŚCIOWE W DETEKCJI ARYTMII... 7 3.4 NASZA KONCEPCJA ROZWIĄZANIA... 11 3.5 ALGORYTM ROZWIĄZANIA POSZCZEGÓLNE FAZY I SCHEMAT... 12 4. REZULTATY I WNIOSKI... 18 5. PODSUMOWANIE... 20 6. BIBLIOGRAFIA... 21 7. DODATEK A: OPIS OPRACOWANYCH NARZĘDZI I METODY POSTĘPOWANIA... 21 8. DODATEK B. OPIS INFORMATYCZNY PROCEDUR... 22 9. DODATEK C. SPIS ZAWARTOŚCI DOŁĄCZONYCH NOŚNIKÓW (CD ROMU)... 25 Wykonali: Joanna Koza, Kamil Mucha V rok Informatyka Stosowana Konsultant: prof. dr hab. inż. Piotr Augustyniak Wersja 1.2. - raport końcowy Kraków, styczeń 2010. -1-
1. Abstrakt Celem projektu jest zaimplementowanie algorytmu detekcji podstawowych arytmii na podstawie sekwencji morfologii zespołu QRS. Projekt zakłada kompatybilność ze strukturami opisu sygnału EKG i strukturami sterującymi. Dane wejściowe i wyjściowe aplikacji przekazywane są poprzez pliki lub struktury w pamięci komputera. Jakość detekcji arytmii testowana jest za pomocą sygnałów wzorcowych EKG i bazy danych MIT-BIH (physionet.org). Na wejściu program otrzymuje z innych modułów (będących częścią większego systemu interpretacji elektrokardiogramów) dane dotyczące morfologii zespołów QRS. Na podstawie tych danych, moduł ARRH_DET dokonuje detekcji i klasyfikacji arytmii, zwracając listę typów wykrytych przypadków wraz z referencjami do danych wejściowych (sygnału / zespołów QRS).
2. Wstęp a) Cele i założenia projektu Głównym problemem do rozwiązania przy realizacji projektu jest ustalenie parametrów zespołów QRS, koniecznych i wystarczających do prawidłowej detekcji i klasyfikacji arytmii. Należy również ustalić treść i formę zwracanych przez aplikację rezultatów, pamiętając przy tym o zachowaniu wspólnego z pozostałymi modułami systemu formatu wymiany danych wejścia / wyjścia (docelowo prosty protokół oparty o pliki dyskowe). Arytmia serca stanowi sekwencję pobudzeń o ustalonych wzorcach. Dana arytmia definiowana jest poprzez specyficzną sekwencję zespołów o określonej morfologii, interwał między nimi (RR) i czasem ich liczbę. Ważnym aspektem detekcji arytmii jest możliwość zbadania przyczyn ją wywołujących poprzez analizę odcinka bezpośrednio poprzedzającego. Arytmie dzielą się na nadkomorowe (np. pauza, tachykardia lub bradykardia nadkomorowa, PSVT, nadkomorowy rytm nieregularny) oraz komorowe (np. para, czynny rytm komór, salwa, tachykardia komorowa, bigeminia, trigeminia). Wbrew potocznym rozumienia, arytmia nie oznacza niemiarowości rytmu, co definiuje metody jej detekcji jako odpowiedniej sekwencji pobudzeń w zapisie EKG. Ogólnie stosowane metody detekcji arytmii polegają na odnalezieniu początku i końca spełnienia założeń arytmii w sygnale EKG. W ten sposób wyznaczony zostaje czas trwania arytmii (ew. początek i koniec arytmii) podstawowy parametr diagnostyczny. Za początek arytmii uznaje się pierwsze wystąpienie danego zespołu pobudzeń, za koniec wystąpienie zespołu odmiennego typu morfologicznego (komorowego dla arytmii nadkomorowej i odwrotnie) lub sekwencji charakterystycznej dla innej arytmii. Detekcja obejmuje wszystkie zarejestrowane kanały jednocześnie. Często spotykanym problemem detekcji jest jednoczesne wystąpienie sekwencji charakterystycznych dla różnych arytmii wymaga to rozwiązania konfliktów diagnostycznych. Rozwiązanie opiera się na podziale arytmii na trzy klasy istotności: pierwszego rodzaju: pauza, częstoskurcz nadkomorowy, tachykardia komorowa, drugiego rodzaju: salwa, czynny rytm komór, bigeminia, trzeciego rodzaju: tachykardia (nadkomorowa), bradykardia, rytm nieregularny i pary. W przypadku konfliktu priorytetyzuje się przesłanki arytmii niższego rodzaju.
b) Zarys ogólny proponowanego rozwiązania Detekcja zespołów QRS z informatycznego punktu widzenia sprowadza się do implementacji procedury przeszukiwania bazy danych dotyczących pobudzeń występujących w sygnale EKG. Wybrane przez nas rozwiązanie polega na trzyetapowym przeglądnięciu (iteracyjna konstrukcja algorytmu) otrzymanych danych zorganizowanych w postaci listy lub tablicy. Dane dotyczyć mają morfologii zespołów QRS oraz interwałów RR między nimi. Trzyetapowy przebieg algorytmu jest konsekwencją występowania trzech rodzajów arytmii i pozwala na łatwe rozwiązywanie konfliktów diagnostycznych. Za pierwszym razem wykrywane są arytmie pierwszego rodzaju, za drugim drugiego etc, przy czym kolejne przejścia pomijają analizę danych już przypisanych do wcześniej wykrytej arytmii (oszczędność na złożoności). Ponadto, takie rozwiązanie automatycznie dokonuje selekcji wyników klasyfikacji i łatwy jednoczesny dostęp do danych dotyczących poszczególnych kategorii arytmii. Kolejne przebiegi pozwalają na ponowną analizę fragmentów sygnałów poprzedzających wykryte arytmie i ewentualną próbę zbadania ich przyczyn w sygnale. Takie podejście wydaje nam się intuicyjne i w pewien sposób odpowiadające naturalnej analizie przeprowadzanej przez człowieka (lekarza). Gotowy projekt jest w stanie poprawnie wykryć przyjęte na etapie projektowania typy arytmii (pauzę, częstoskurcz, tachykardię komorową i nadkomorową, salwę, bigeminię, bradykardię i parę) przy użyciu stosunkowo prostych pod względem złożoności i logiki budowy algorytmów, opierających się na uzyskanych wejściowo informacjach dotyczących sygnału EKG. Udało się rozwiązać problem konfliktu przynależności danego zespołu QRS do różnych typów arytmii poprzez wyszczególnienie odpowiednich etapów detekcji i przydzielenie należącym do nich typom arytmii priorytetów. Udało się zachować kompatybilność z ogólnie ustalonymi, globalnymi strukturami danych, z których pobierane są informacje o konfiguracji programu i sygnale EKG, i do których zapisywane są rezultaty detekcji. Udało się wspólnie z drugą grupą, przygotowującą projekt o tym samym temacie, ustalić wspólny typ wyliczeniowy określający rodzaje wykrywanych arytmii, przez co stworzony został współdzielony standard obowiązujący w całym systemie.
c) Dyskusja alternatywnych rozwiązań Inne podejście, być może bardziej korzystne ze względów obliczeniowych, polega na jednokrotnym przeglądnięciu kompletu danych wejściowych dla każdego pobudzenia sprawdzane są przynależności do wszystkich rozpatrywanych kategorii. W przypadku konfliktu faworyzuje się przynależność do kategorii o wyższym priorytecie. Podejście to wydaje nam się mniej intuicyjne i mniej funkcjonalne, a wszelkie korzyści natury obliczeniowej mają drugorzędne znaczenie przy obecnej wydajności sprzętu. Ponadto, alternatywne mogą być rodzaje wykrywanych arytmii. Zawęziliśmy wybór do ośmiu najczęściej występujących i najistotniejszych z diagnostycznego punktu widzenia typów arytmii. Same algorytmy detekcji poszczególnych rodzajów zostały stworzone na podstawie sugestii literaturowych [1] (parametry sygnału potrzebne do detekcji i ustalenia typów występujących w nim arytmii) oraz własnych empirycznych obserwacji na temat przebiegów EKG w odniesieniu do poszczególnych typów patologii w nich występujących. Algorytmy te skonstruować można na wiele sposobów. d) Pokazanie logicznej konstrukcji pracy W rozdziale 3 zostanie przedstawiona koncepcja proponowanego rozwiązania przez pryzmat ogólnego schematu systemu analizy EKG, którego nasz program mógłby być częścią. Na koncepcję wpływ ma również forma danych wejściowych i wyjściowych programu w postaci odgórnie i globalnie ustalonych struktur lub klas, przekazanych przez prowadzącego przedmiot. W rozdziale 3 dodatkowo opisane są typy analizowanych przez nasz program arytmii z punktu widzenia medycznego oraz informatycznego (dane potrzebne do rozróżnienia typów). Informacje te prowadzą do opisanej własnej koncepcji działania programu, popartej pseudokodem, diagramem klas oraz sekwencji. W rozdziale 4 przedstawione będą rezultaty naszej pracy oraz płynące z nich wnioski, podsumowane w rozdziale 5. Rozdział 6 zawierać będzie bibliografię. Istotne informacje dotyczące technicznej implementacji projektu znaleźć można w dodatkach do niniejszego raportu.
3. Koncepcja proponowanego rozwiązania 3.1 Schemat działania programu głównego opis ewolucji Beats sygnał EKG konfiguracja Config analiza proc. 1 analiza proc. 2 analiza proc. 3.. analiza proc. N plik rezult. Signal Status Rys. 3.1.1 Schemat działania programu głównego Etapy przetwarzania i interpretacji elektrokardiogramu: 1) QRS_DET - Detekcja i synchronizacja reprezentacji uderzenia serca (zespołu QRS) 2) QRS_CLAS - Klasyfikacja uderzeń serca 3) QRS_MORPH - Wyznaczenie morfologii uderzeń serca 4) QRS_WAVES - Określenie obecności i długości załamków EKG 5) QRS_AX - Określenie osi elektrycznej załamków, wyznaczenie sygnału oddechu z zapisu EKG 6) ARRH_DET - Detekcja arytmii 7) HRV_ANA - Detekcja zmienności rytmu serca (HRV) 8) ST_ANA - Detekcja symptomów choroby niedokrwiennej na podstawie analizy interwału ST 9) QT_DISP - Obliczenie dyspersji odcinka QT Nominalnie system składa się z N=9 odrębnych, zorganizowanych potokowo analiz proceduralnych. Realizowany przez nas etap analizy jest etapem szóstym, jego działanie oparte jest na rezultatach zapisanych w strukturach Status i Beats przez poprzednie etapy (w szczególności etapy 1-4), wyniki zwracane są do struktury Status i nie są bezpośrednio wykorzystywane przez kolejne etapy, aczkolwiek stanowią ważny i niezbędny składnik rezultatów działania programu pod względem przydatności diagnostycznej.
3.2 Dane wejściowe i wyjściowe w detekcji arytmii a) Przyjęte założenia odnośnie danych wejściowych i wyjściowych: dane wejściowe pochodzić powinny z badania EKG metodą Holtera, tj. badania trwającego przez całą dobę dla każdego z zespołów QRS, ponumerowanych zgodnie z kolejnością występowania w sygnale, następujące informacje: indeks, ID klasy, długości załamków, odległość do następnego zespołu QRS (jednocześnie odległość 0 oznaczałaby znacznik ostatniego wykrytego zespołu QRS). b) Dane wejściowe (z pliku): tablica struktur: Tabela 3.1 Dane wejściowe - tablica struktur QRS[0] QRS[1]... QRS[n] Int klasaid; Int klasaid;... Int klasaid; Int odldonast; Int odldonast;... Int odldonast = 0; Struct dlugoscizalam; Struct dlugoscizalam;... Struct dlugoscizalam;
3.3 Charakterystyka arytmii a) Charakterystyka wybranych rodzajów arytmii realizowanych w projekcie: Jak już wspomnieliśmy we wstępie naszego raportu, arytmia jest zaburzeniem pracy serca polegającym na jego przyspieszeniu, zwolnieniu lub nieregularności. Czasami bywa problemem banalnym, jednak nierzadko związana jest z poważnymi konsekwencjami, nawet zagrażającymi życiu. Arytmia może być napadowa (pojawia się okresowo) lub długotrwała (utrzymująca się przez dłuższy czas). Prawidłowo, bez wykonywania wysiłku, serce pracuje miarowo (równo) z częstością od 60 do 100 uderzeń na minutę. U osób zdrowych będzie ono wykonywać około 60 uderzeń na minutę w spoczynku, przy niewielkich wysiłkach około 100 uderzeń na minut, przy dużych wysiłkach (gimnastyka) około 130 uderzeń na minutę, a przy bardzo dużych wysiłkach (np. forsowne bieganie) nawet 180 uderzeń na minutę i więcej. U osób uprawiających sport serce może pracować wolniej i uderzać około 40-50 razy na minutę (podczas spoczynku) i jest to prawidłowe. W czasie snu serce oczywiście pracuje trochę wolniej, niż w ciągu dnia. b) Najczęstsze postacie arytmii: Migotanie komór (VF) - to forma zatrzymania akcji serca polegająca na szybkich, nieskoordynowanych pobudzeniach elektrycznych komór serca, które nie powodują ich skurczu. Migotanie komór występuje na skutek uszkodzenia mięśnia komór serca w przebiegu wielu chorób serca, ale szczególnie istotna jest choroba niedokrwienna serca, zwłaszcza zawał serca, kardiomiopatie i wrodzone kanałopatie (zaburzenia kanałów jonowych), do których należą: zespół wydłużonego QT, zespół Brugadów, katecholaminozależny różnokształtny częstoskurcz komorowy, idiopatyczny częstoskurcz komorowy i migotanie komór. Istnieje wiele innych przyczyn, wśród których ważne są choroby ogólnoustrojowe, zaburzenia hormonalne, metaboliczne i elektrolitowe. Migotanie komór może być także powodowane działaniem ubocznym niektórych leków. Migotanie komór zapoczątkowywane zwykle jest przez dodatkowe pobudzenie komorowe przypadające w określonym czasie po skurczu komory (zjawisko R na T), degenerację częstoskurczu komorowego lub migotania przedsionków. Objawem jest utrata przytomności i nagła śmierć sercowa. Wyjątkowo rzadko migotanie komór może zakończyć się samoistnie bez interwencji medycznej. Migotanie komór rozpoznaje się w zapisie EKG lub na monitorze EKG.
Migotanie przedsionków - Migotanie przedsionków to chaotyczna i szybka (350 do 700/min.) czynność elektryczna przedsionków serca. Przy tak szybkiej i nieskoordynowanej aktywacji przedsionki przestają pompować krew do komór serca, dlatego migotanie przedsionków zmniejsza rzut serca (objętość krwi przepompowywanej w ciągu minuty) nawet o 20 do 30%. Migotanie przedsionków powoduje, że komory serca pobudzane są nieregularnie z różną częstością, zależnie od stanu układu przewodzącego impulsy z przedsionków. Migotanie przedsionków powstaje na skutek zaburzenia elektrycznych mechanizmów w przeciążonych i uszkodzonych przedsionkach serca na skutek m.in. nadciśnienia tętniczego, wad serca, choroby niedokrwiennej serca, zapalenia serca, nadczynności tarczycy, infekcji, chorób płuc, toksyn (w tym alkoholu), leków, zaburzeń elektrolitowych, napięcia układu nerwowego. Migotanie przedsionków może także mieć tło genetyczne i wrodzone. Migotanie przedsionków to najczęstsza po skurczach dodatkowych arytmia serca. Migotanie przedsionków występuje coraz częściej z wiekiem i uszkodzeniem mięśnia serca. Migotanie przedsionków występuje u około 1-2% dorosłych ludzi, a po 80 roku życia aż u co dziesiątej osoby. Migotanie przedsionków dzielimy na: napadowe, które ustępuje najczęściej w ciągu doby; przetrwałe trwa >7dni i nie ustępuje samoistnie; oraz migotanie przedsionków utrwalone. Migotanie przedsionków może wystąpić jako pojedynczy epizod, jednak zwykle obserwuje się nawroty z tendencją do utrwalenia po pewnym czasie. Migotanie przedsionków rozpoznaje się w zapisie EKG. W przypadkach, gdy występuje rzadko i trwa krótko potrzebny jest długotrwały zapis - np Holter EKG. Częstoskurcz nadkomorowy - to nieprawidłowy rytm serca o częstości ponad 100/min. Częstoskurcz nadkomorowy powstaje na skutek zaburzenia elektrycznych mechanizmów w przedsionkach serca i w części układu bodźco-przewodzącego powyżej pęczka Hisa lub na skutek obecności tzw. drogi dodatkowej. Częstoskurcz nadkomorowy może występować u osób bez żadnej choroby lub na skutek m.in. nadciśnienia tętniczego, wad serca, choroby niedokrwiennej serca, zapalenia serca, nadczynności tarczycy, infekcji, chorób płuc, toksyn (w tym alkoholu), leków, zaburzeń elektrolitowych, napięcia układu nerwowego. Częstoskurcz nadkomorowy może mieć tło wrodzone (zespół WPW). Wyróżnia się trzy postacie częstoskurczu nadkomorowego: - nawrotny częstoskurcz węzłowy - który występuje zwłaszcza u młodych kobiet bez choroby serca, - częstoskurcz przedsionkowy tu często przyczyną jest uszkodzenie serca lub płuc,
- częstoskurcz przedsionkowo-komorowy obserwowany jest u chorych z zespołem WPW Częstoskurcz nadkomorowy może wystąpić jako pojedynczy epizod (zwłaszcza jeśli był skutkiem przejściowego zaburzenia), jednak zwykle obserwuje się nawroty. Częstoskurcz nadkomorowy może być napadowy lub ustawiczny (>50% czasu doby). Tachykardia komorowa - to miarowy częstoskurcz z szerokimi zespołami QRS. Salwa kilka (3-5) kolejnych pobudzeń komorowych Bigeminia - zaburzenia rytmu serca o bardzo charakterystycznym układzie pobudzeń dodatkowych w badaniu EKG: pobudzenia prawidłowe powstałe w węźle zatokowym przeplatają się z dodatkowymi pobudzeniami komorowymi w ten sposób, że po każdym pobudzeniu prawidłowym pojawia się jedno dodatkowe. Na wykresie EKG obserwujemy więc występujące na przemian dwa zespołu QRS o różnym kształcie - wąski zespół QRS jest pochodzenia zatokowego, szeroki jest pobudzeniem dodatkowym. Bradykardia - to termin określający zwolnienie pracy serca u dorosłych poniżej 50-60/minutę. Fizjologicznie bradykardia występuje w czasie snu, kiedy czynność serca może spadać nawet poniżej 40 uderzeń na minutę. Podobnie, bradykardia obserwowana jest u sportowców i jest to prawidłowe, o ile nie powoduje ona objawów. Bradykardia ma różne przyczyny. Bradykardia związana jest z zaburzeniem funkcji lub uszkodzeniem naturalnego rozrusznika, czyli węzła zatokowego (choroba węzła zatokowego), lub zaburzeniami przewodzenia elektrycznych impulsów w sercu (bloki serca). Bradykardia powodowana jest przez chorobę niedokrwienną serca, pojawia się w przebiegu wad serca, czy kardiomiopatii. Bradykardia może być także efektem nadmiernego wpływu układu nerwowego, skutkiem stosowanych leków, narkotyków i toksyn, czy zaburzeń ogólnoustrojowych tj. zaburzenia elektrolitowe, niedoczynność tarczycy czy choroby tkanki łącznej (reumatyczne). Bradykardia może występować stale jak i napadowo, może, ustępować w czasie wysiłku. Bradykardia może być bezobjawowa lub powodować mroczki przed oczami, uczucie zawrotów głowy do omdlenia i zgonu włącznie. Bradykardia może także wywoływać objawy niewydolności serca i nietolerancji wysiłku, kołatania serca.
3.4 Nasza koncepcja rozwiązania Nasze podejście zakłada 3 etapy, tj. wykrywanie arytmii pierwszego, drugiego i trzeciego rodzaju, z pominięciem w kolejnych etapach QRS już sklasyfikowanych do danej arytmii. Rys. 3.4.1 Podział arytmii z uwzględnieniem etapu jego detekcji w systemach diagnozy Poniżej znajdują się wybrane przez nas na danym etapie typy wykrywanych arytmii: I etap: 1) wykrywanie pauzy (maksimum odległości między QRS > dwukrotna średnia odległość) 2) częstoskurcz nadkomorowy (rytm serca o częstości ponad 100/min) 3) tachykardia komorowa (miarowy częstoskurcz z szerokimi zespołami QRS) II etap: 1) salwa (więcej niż 2 wystąpienia pod rząd zespołów QRS innej klasy) 2) bigeminia (naprzemienne występowanie QRS dwóch różnych klas) III etap: 1) tachykardia nadkomorowa (bardzo duże BPM, powyżej 100) 2) bradykardia (BPM poniżej 50-60/minutę) 3) para (2 wystąpienia pod rząd zespołów QRS innej klasy) Dane wynikowe to tablica wykrytych arytmii, dla każdej z których podane są informacje dotyczące jej typu, indeksów początkowego i końcowego zespołu QRS oraz częstości akcji serca w jej obrębie. Dane te wpisywane są do globalnej struktury Status.
3.5 Algorytm rozwiązania poszczególne fazy i schemat Na rysunku [3.5.1] znajduje się diagram klas aplikacji ArrhDet w notacji UML. Należy zwrócić uwagę na klasę ArrhDetector, która jest główną logiczną klasą, realizująca detekcję typów arytmii. Używa ona klasy pomocniczej Util, realizującej dodatkowe obliczenia i operacje odczytu / zapisu danych z przechowujących je struktur globalnych Config, Status, Beats. Możliwe jest rozszerzenie klasy Util o możliwości pracy z plikami dyskowymi. Do klasy Status dodany został typ wyliczeniowy określający rozróżniane typy arytmii. Klasa tester jest dodatkową klasą przeprowadzającą testy jednostkowe i nie powinna zostać wcielona do gotowego systemu analizy EKG. Diagram klas Rys. 3.5.1 Diagram klas w aplikacji ArrhDet
Diagram sekwencji Rys. 3.5.2 Diagram sekwencji w aplikacji ArrhDet
Poniżej znajduje się pseudokod najważniejszych algorytmów, powstały na etapie ich projektowania. Metody wykrywania poszczególnych arytmii, oparte na literaturze, zrealizowane są w sposób subiektywny i stanowią jedno z wielu możliwych rozwiązań. Zmienne globalne: int avgrr; int avgl; int maxrr; //sredni odstep miedzy odcinkami QRS //srednia dlugosc odcinka QRS //maksymalna odleglosc miedzy odcinkami QRS Typ wyliczeniowy: enum arytmia NONE, PAUSE, PACED, VENT_TACHY, SALVO, BIGEMINY, SUPERVENT_TACHY, BRADY, COUPLET, SINUS_ARRY, EXIT_BLOCK, ARTIAL_PRE_BEAT, ; // pauza nadkomorowa, zahamowanie zatokowe // czestoskurcz // tachykardia komorowa // salwa komorowa // bigeminia komorowa (PVC) // tachykardia nadkomorowa (PSVT) // bradykardia komorowa // para komorowa // niemiarowość zatokowa // blok zatokowo-przedsionkowy // ekstrasystolia przedsionkowa void main() for each(kanal) wylicz_statystyki(kanal); for(int etap = 1; etap <= 3; etap++) analizuj_sygnal(etap, kanal); aktualizuj_status(kanal); void analizuj_sygnal(int etap, int kanal) switch(etap) case 1: etap1(kanal); break; case 2: etap2(kanal); break; case 3: etap3(kanal); break; default: break;
void etap1(int kanal) wykryj_pauze(kanal); wykryj_czestoskurcz_lub_tachykardie_kom(kanal); void etap2(int kanal) wykryj_salwe(kanal); wykryj_bigeminie(); void etap3(int kanal) wykryj_tachykardie_nad(kanal); wykryj_bradykardie(kanal); wykryj_pare(kanal); void wylicz_statystyki(int kanal) for each(qrs in QRStab(kanal)) //licz_sredni_odstep_qrs(kanal) //licz_srednia_dlugosc_qrs(kanal) //licz_maksymaly_odstep_qrs(kanal) avgrr = sredni_odstep_qrs; avgl = srednia_dlugosc_qrs; maxrr = maksymaly_odstep_qrs; Pauza: void wykryj_pauze(int kanal) for each(qrs in QRStab(kanal)) if(qrs.typarytmii == BRAK) if(qrs.rr > 2*avgRR) QRS.typArytmii == PAUZA; Częstoskurcz / tachykardia komorowa: void wykryj_czestoskurcz_lub_tachykardie_kom(int kanal) for each(qrs in QRStab(kanal)) if(qrs.typarytmii == BRAK) if(qrs.rr < 0.5 * avg RR) if(qrs.len > 1.25 avgl) QRS.typArytmii = TACHYKARDIA_KOM; else QRS.typArytmii = CZESTOSKURCZ;
Salwa: void wykryj_salwe(int kanal) if(qrs.liczbaklas > 1) int klasa_poprzednia = QRStab(kanal)[0]; int licznik = 0; for each(qrs in QRStab(kanal)) //poczawszy od QRStab(kanal)[1] if(qrs.typarytmii == BRAK) if(qrs.klasa!= klasa_poprzednia) licznik++; if(licznik > 2) licznik = 0; QRS.typArytmii = SALWA; Bigeminia: void wykryj_bigeminie(int kanal) int klasa1, klasa2, klasa_poprzednia; if(qrs(kanal)[0].typarytmii == BRAK) klasa1 = QRS(kanal)[0]; klasa_poprzednia = klasa1; for each(qrs in QRStab(kanal)) if(qrs.typarytmii == BRAK) if(qrs.klasa!= klasa1) klasa2 = QRS.klasa; if((klasa == klasa1 klasa == klasa2) && klasa!= klasa_poprzednia) QRS.typArytmii = BIGEMINIA; else klasa1 = QRS.klasa; klasa_poprzednia = klasa1;
Tachykardia nadkomorowa: void wykryj_tachykardie_nad(int kanal) for each(qrs in QRStab(kanal)) if(qrs.typarytmii == BRAK) if(qrs.rr < 0.3 * avgrr) QRS.typArytmii = TACHYKARDIA_NAD; Bradykardia: void wykryj_bradykardie(int kanal) for each(qrs in QRStab(kanal)) if(qrs.typarytmii == BRAK) if(qrs.rr > 1.5 * avgrr) QRS.typArytmii = BRADYKARDIA; Para: void wykryj_pare(int kanal) if(qrs.liczbaklas > 1) int klasa_poprzednia = QRStab(kanal)[0]; int licznik = 0; for each(qrs in QRStab(kanal)) //poczawszy od QRStab(kanal)[1] if(qrs.typarytmii == BRAK) if(qrs.klasa!= klasa_poprzednia) licznik++; if(licznik == 2) licznik = 0; QRS.typArytmii = SALWA;
4. Rezultaty i wnioski Wyniki działania programu Działanie aplikacji ArrhDet zostało sprawdzone za pomocą odpowiednio przygotowanych testów jednostkowych. Jako moduł większego systemu analizy sygnału EKG, program ArrhDet zależny jest od wyników działania modułów realizujących wcześniejsze etapy przetwarzania i analizy sygnału wejściowego. Zależność ta dotyczy głównie wyróżnionych etapów 1,2,4, tzn. QRS_DET, QRS_CLAS i QRS_WAVES. Niestety w momencie testów działania naszej aplikacji, nie mieliśmy dostępu do modułów realizujących te etapy (pozostałe grupy nie ukończyły jeszcze prac), dlatego dane do testów uzyskane zostały z plików bazy MIT-BIH przy użyciu naszej własnej aplikacji WebDoctor, zajmującej się detekcją i klasyfikacją zespołów QRS, wraz z wyznaczaniem długości załamków. WebDoctor został przez nas stworzony na potrzeby przedmiotu Podstawy Telemedycyny, prowadzonego przez Pana prof. dr hab. inż. Piotra Augustyniaka na 8 semestrze Informatyki Stosowanej w roku akademickim 2008 / 2009. Poniżej przedstawione są wyniki testów. Zamieszczone w tabeli wizualizacje QRS, dla których poprawnie stwierdzono konkretną arytmię, pobrane zostały z własnej aplikacji WebDoctor, natomiast informacje o rekordzie pochodzą z bazy MIT-BIH na stronie [http-03].
MIT-BIH Arrhythmia Database Arytmia MIT-BIH: bigeminia komorowa (PVC) Wykryta arytmia: salwa: QRS[9-32], HR = 82 para: QRS[48-49], HR = 121 Komentarz: Warunki wystąpienia bigeminii są podzbiorem warunków salwy ponieważ salwa ma większy priorytet, zostaje wykryta zamiast bigeminii. Działanie programu uznajemy za poprawne zarówno dla salwy, jak i pary. Salwa jest nadtypem bigeminii. wzorzec salwy obecny w sygnale, wykryty przez aplikację ArrhDet
Wnioski z analiz Na podstawie wstępnie przeprowadzonych testów jednostkowych można stwierdzić poprawność działania aplikacji. Istniejące rozbieżności z danymi podanymi w rekordach MIT-BIH wynika z powtarzalności tych samych warunków dla różnych arytmii. Ze względu na przyjęte przez nas priorytety klasyfikacji arytmii i zasadę przynależności danego QRS tylko do jednego rodzaju arytmii, możemy otrzymać różne, aczkolwiek niesprzeczne z diagnostycznego punktu widzenia rezultaty. Zakresy występowania arytmii zgadzają się z wzorcowymi. Należy pamiętać, iż rzeczywiste testy (bez pośrednictwa aplikacji trzecich, takich jak WebDoctor, używanych do ekstrakcji danych z sygnału) należy przeprowadzić, mając skompletowane moduły wcześniejszych etapów analizy, mające składać się na całość systemu. Niestety prace grup projektowych nad poszczególnymi modułami przebiegały równolegle bez synchronizacji wyników i w chwili testów naszego modułu nie mieliśmy dostępu do niezbędnych dla nas danych wejściowych. 5. Podsumowanie Aplikacja ArrhDet w sposób zadowalający realizuje założone cele: detekcję arytmii oraz obsługę ustalonego standardu danych wejścia i wyjścia. Projekt zrealizowany został w całości. Wyniki są zgodne z przyjętymi na wstępie kryteriami, jednak same kryteria, chociaż oparte na badaniach literaturowych, są kryteriami po części subiektywnymi. Program taki jak ArrhDet nie może więc w pełni zastąpić decyzji lekarza, a jedynie wspomóc jego diagnozę poprzez wskazanie potencjalnie zagrożonych arytmią fragmentów sygnału EKG oraz zaproponowania najbardziej prawdopodobnego jej typu. Do lekarza należeć powinno podjęcie ostatecznej decyzji. Możliwe kierunki rozwoju aplikacji obejmują rozszerzenie zbioru wykrywanych arytmii o dodatkowe rodzaje. Przydatnym dodatkiem byłby graficzny interfejs użytkownika, dotyczący przede wszystkim prezentacji danych wejściowych oraz wyników działania programu. Dobrym pomysłem byłaby obsługa kilku formatów danych wejściowych.
6. Bibliografia [1] Augustyniak P. Przetwarzanie sygnałów elektrodiagnostycznych, Uczelniane Wydawnictwa Naukowo-Dydaktyczne, Kraków 2001. [2] Zareba W., Blanche P.M., Locati E.H Noninvasive electrocardiology in clinical practice, 2001 rozdział nr 14 Noninvasive ECG testing in management of patients with atrial arrhythmias Pierre Maison-Blanche, MD, Stephane Cosson, MD, and Bruno Cauchemez, MD. [3] Noninvasive electrocardiology: Clinical Aspects of Holter Monitoring, Saunders, 1996 - Section II Arrhythmia monitoring, introduction by Takashi Yanaga and Lee A.Biblo, Albert L. Waldo. [http-01] http://www.kardioserwis.pl - bezpłatny, specjalistyczny serwis informacyjny z zakresu kardiologii, prowadzony przez grupę lekarzy z Kliniki Kardiologii UM w Poznaniu. [http-02] http://code.assembla.com/alcgyyy9ir3q1leje5afgb/subversion/nodes [http-03] http://physionet.org 7. DODATEK A: Opis opracowanych narzędzi i metody postępowania Korzystanie z aplikacji ArrhDet ogranicza się do uruchomienia pliku ArrhDet.exe. Nie potrzebuje on żadnych dodatkowych bibliotek. Należy zwrócić uwagę na fakt, iż aplikacja projektowana była jako część większego systemu analizy EKG, dokonującego potokowego przetwarzania danych, pozbawiona jest więc interfejsu graficznego. Dane wejściowe pobierane są z klasy przeprowadzającej testy jednostkowe, docelowo powinny być przekazane przez wcześniejsze moduły systemu jako pliki dyskowe o określonej strukturze lub w postaci struktur danych przechowywanych w pamięci globalnej. Wyniki detekcji wypisywane są na standardowe wyjście, mogą być zapisywane docelowo do wspomnianych plików / struktur. Oprogramowanie testowane było na systemie operacyjnym Windows Vista 32b.
8. DODATEK B. Opis informatyczny procedur Aplikacja ArrhDet napisana została w języku C++ w środowisku Microsoft Visual Studio 2008 przy użyciu standardowych bibliotek i opcji kompilacji. Nie użyto żadnych bibliotek zewnętrznych. Kod źródłowy aplikacji znajduje się na serwerze SVN serwisu Assembla [http-02]. Najważniejsze funkcje: /***************************************************************************/ /* void main(int argc, char** argv) w pliku Main.cpp przeznaczenie: inicjalizacja struktur danych dla testów jednostkowych i wypisanie ich wyników,inicjalizacja i aktywacja obiektu detektora arytmii, oczyszczanie pamięci po wykonaniu programu argumenty funkcji: (I) int argc // liczba parametrów wywołania (I) char** argv // wektor parametrów wywołania funkcja zwraca: void uzywane funkcje: cleanup(); // zwalnia uzywana pamiec void Tester::wypalnijDaneTestowe(Config* config, Beats* beats, Status* status) // test void ArrhDetector::detect(Config* config, Beats* beats, Status* status) // glowna funkcja detektora void Tester::wypiszWyniki(Status* status) // wypisz wyniki testow uzywane zmienne: Beats* beats // kolejne ewolucje serca Config* config // struktura konfiguracyjna programu Status* status // struktura stanu/wykonania programu Tester tester // klasa testujaca dzialanie detektora ArrhDetector detector // detektor arytmii uwagi: funkcja zawiera wywolanie obiektu detektora, ktore powinno znalezc sie w wiekszym systemie analizy danych EKG: ArrhDetector detector; detector.detect(config, beats, status); autor: Joanna Koza, Kamil Mucha ostatnia modyfikcacja: 17.01.2010 /***************************************************************************/ */
/***************************************************************************/ /* void detect(config* config, Beats* beats, Status* status) w pliku ArrhDetector.cpp przeznaczenie: glowna funkcja detektora arytmii, wywoluje inicjalizacje wypelnianych struktur, wyliczanie pomocniczych statystyk sygnalu EKG, wlasciwa detekcje arytmii oraz uzupelnianie struktur wyjsciowych argumenty funkcji: (B) Config* config // konfiguracja programu (I) Beats* beats // kolejne ewolucje serca (B) Status* status // status dzialania aplikacji funkcja zwraca: void uzywane funkcje: void Util::inicjalizuj_status(Status* status, int arrhtypenumber) // inicjalizuje struktury wypelniane w klasie Status void Util::wylicz_statystyki(Beats* beats) // liczy statystyki ewolucji serca, np. sredni RR, maksymalny RR, etc. void ArrhDetector::analizuj_sygnal(int etap) // wlasciwa analiza sygnalu w celu detekcji arytmii w 3 etapach void Util::policzHR(Status *status, Config *config, Beats* beats) // liczy lokalne heart rate dla fragmentow EKG obietych arytmiami void Util::aktualizuj_status(Status* status, int errorcode) // uzupelnia struktury wyjsciowe uzywane zmienne: Beats* beats // kolejne ewolucje serca Config* config // struktura konfiguracyjna programu Status* status // struktura stanu/wykonania programu Util util // klasa pomocnicza detektora int ReadSub // numer procedury przetwarzania EKG (tutaj równy 6) int ArrhTypeNumber // ilosc rozroznianych typow arytmii (tutaj 12) uwagi: brak autor: Joanna Koza, Kamil Mucha ostatnia modyfikcacja: 17.01.2010 /***************************************************************************/ */
/***************************************************************************/ /* void etap1() w pliku ArrhDetector.cpp przeznaczenie: pierwszy z trzech etapow detekcji arytmii (wszystkie wywolywane sa przez funkcje analizuj_sygnal) argumenty funkcji: brak funkcja zwraca: void uzywane funkcje: void ArrhDetector::wykryj_pauze() // wykrycie pauzy void ArrhDetector::wykryj_czestoskurcz_lub_tachykardie_kom() // wykrycie czestoskurczu lub tachykardii komorowej uzywane zmienne: brak uwagi: analogicznie przedstawiaja się funkcje etap2() oraz etap3() w tym samym pliku / klasie, wykrywaja one odpowiednie im typy arytmii autor: Joanna Koza, Kamil Mucha ostatnia modyfikcacja: 17.01.2010 /***************************************************************************/ */ /***************************************************************************/ /* void wykryj_pauze() w pliku ArrhDetector.cpp przeznaczenie: funkcja zajmujaca się wykryciem arytmii typu pauza argumenty funkcji: brak funkcja zwraca: void uzywane funkcje: bool Util::sprawdzCzyJestArytmia(Beats* beats, Status* status) // sprawdza czy dana ewolucja serca zostala juŝ przypisana do arytmii void Util::uzupelnijArytmie(int typ, Beats* tmpbeat, Status *status) // uzupelnia status programu o informacjr o wykrytej arytmii uzywane zmienne: Beats* beats // kolejne ewolucje serca Status* status // struktura stanu/wykonania programu Util util // klasa pomocnicza detektora
uwagi: analogicznie przedstawiaja się funkcje wykryj_czestoskurcz_lub_tachykardie_kom() wykryj_salwe() wykryj_bigeminie() wykryj_tachykardie_nad() wykryj_bradykardie() wykryj_pare() w tym samym pliku / klasie, wykrywaja one odpowiednie im typy arytmii i roznia się miedzy soba algorytmem postepowania przy detekcji autor: Joanna Koza, Kamil Mucha ostatnia modyfikcacja: 17.01.2010 /******************************************************************************/ */ 9. DODATEK C. Spis zawartości dołączonych nośników (CD ROMu) SRC pliki źródłowe, pliki projektu VS 2008 EXE - postać programu gotowa do uruchomienia TEST - katalog z danymi użytymi do testów jednostkowych (pliki.dat bazy MIT-BIH ze strony [http-03]) DOC raport w postaci dokumentu MS WORD oraz PDF, prezentacja PPT oraz PDF