Pracownia Sygnałów Biologicznych/Zajecia 5 6: Różnice pomiędzy wersjami
m (→Wstęp) |
|||
Linia 46: | Linia 46: | ||
=== Ćwiczenie: zapoznanie się z sygnałami rejestrowanymi przez inwazyjne EMG=== | === Ćwiczenie: zapoznanie się z sygnałami rejestrowanymi przez inwazyjne EMG=== | ||
Proszę wczytać i przyjrzeć się sygnałom zdrowy.bin, miopatia.bin, neuropatia.bin. Sygnały są zapisane jako dtype='float64' | Proszę wczytać i przyjrzeć się sygnałom zdrowy.bin, miopatia.bin, neuropatia.bin. Sygnały są zapisane jako dtype='float64' | ||
− | Częstość próbkowania 4000Hz, amplitudy zapisane są w mV. Dane pochodzą z: | + | Częstość próbkowania 4000Hz, amplitudy zapisane są w mV. Dane pochodzą z bazy Physionet: https://physionet.org/content/emgdb/1.0.0/ |
+ | Proszę przeczytać informację o tych danych. W raporcie proszę napisać istotne informacje o tych sygnałach i wybrać charakterystyczne fragmenty typowe dla danego stanu klinicznego. | ||
=== Ćwiczenie: detekcja aktywności wybranej jednostki ruchowej=== | === Ćwiczenie: detekcja aktywności wybranej jednostki ruchowej=== |
Wersja z 19:21, 27 mar 2020
Pomiar EMG
Spis treści
- 1 Wstęp
- 2 Źródła błędu
- 3 Ćwiczenia
- 3.1 Ćwiczenie: zapoznanie się z sygnałami rejestrowanymi przez inwazyjne EMG
- 3.2 Ćwiczenie: detekcja aktywności wybranej jednostki ruchowej
- 3.3 Ćwiczenie I: Badanie zależności sygnału EMG od obciążenia
- 3.4 Ćwiczenie II: Badnanie przebiegu sygnału EMG względem trigera
- 3.5 Ćwiczenie III: Wykorzystanie pomiaru EMG do sterowania on-line
Wstęp
Filmik ilustrujący działanie mięśni
Sygnały elektro-fizjologiczne pochodzące z mięśni nazywa się elektromiogramem (EMG).
Elektromiografia jest jednym z podstawowych badań w rozpoznawaniu chorób mięśni i nerwów obwodowych. Ma ona również wiele zastosowań naukowych. Amplituda sygnału EMG wynosi od około kilkudziesięciu μV do 10 mV, zaś pasmo sygnału obejmuje zakres częstości od 2 do 5000 Hz, przy czym największa energia sygnału znajduje się w przedziale od 50 do 150 Hz.
Istnieją dwa sposoby pomiaru sygnałów EMG — badanie igłowe i powierzchniowe. W badaniu igłowym EMG, elektroda igłowa lub igła z dwoma elektrodami wbijana jest w mięsień lub w nerw ruchowy. Następnie obserwuje się aktywność elektryczną mięśni w spoczynku i podczas wysiłku.
Badanie powierzchniowe EMG wykonuje się z użyciem elektrod samoprzylepnych, umieszczonych na powierzchni skóry. Ocenie podlegają mięśnie położone powierzchownie lub grupy mięśni. Obydwie metody mają swoje wady i zalety. Metoda „igłowa” umożliwia rejestrację sygnału EMG z wybranego mięśnia, podczas gdy metoda powierzchniowa rejestruje zbiorczą aktywność wielu jednostek ruchowych. Jednakże, w przeciwieństwie do metody powierzchniowej, metoda igłowa jest badaniem inwazyjnym i czasem bolesnym, które wykonywane jest w ośrodku klinicznym.
Na zajęciach przeprowadzimy powierzchniowy pomiar EMG (w literaturze często takie badanie oznacza się skrótem sEMG, s od ang. surface — powierzchnia). W tym celu umieścimy elektrody na skórze, nad mięśniami, których aktywność chcemy zbadać.
Filmik o zastosowaniach klinicznych EMG
Lektura: Reaz MBI, Hussain MS and Mohd-Yasin F. Techniques of EMG signal analysis: detection, processing, classification and applications. Biol. Proced. Online 2006; 8(1): 11-35. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1455479/pdf/bpo_v8_p11_m115.pdf
Źródła błędu
Rejestracja sygnału EMG, podobnie jak pomiar innych sygnały bioelektrycznych podlega pewnym zakłóceniom. Są to przede wszystkim
- artefakty ruchowe,
- artefakty związane z obecnością zewnętrznych pól elektromagnetycznych.
Artefakty ruchowe
W wyniku aktywacji mięśnia, ulega on skróceniu, co powoduje przemieszczanie się względem siebie mięśnia, skóry i elektrody. Przemieszczenie to powoduje zmianę amplitudy mierzonego sygnału (np. elektroda oddala się od mięśnia), zmianę potencjału DC (potencjału powstającego na granicy skóra-elektrolit) oraz rozciągniecie skóry. Jak pamiętamy z pierwszych zajęć pomiędzy naskórkiem a skórą właściwą istnieje różnica potencjałów o amplitudzie dochodzącej do 30 mV. W trakcie rozciągania skóry, wartość to spada do 25 mV. Powstająca zmiana potencjału, o wartości około 5 mV jest w porównaniu z sygnałem EMG bardzo znacząca.
Artefakty sieciowe
Artefakty sieciowe stanowią poważny problem w przypadku rejestracji sygnału EMG. Zwykle bowiem nie obserwujemy tylko zakłócenia o jednej częstości, równej częstości zmian napięcia w gniazdku zasilającym (np. w Polsce jest to 50 Hz), lecz również wyższe harmoniczne tej częstości (w Polsce będzie to 100 Hz, 150 Hz, 200 Hz, itd). Jak można zauważyć, częstości 50 Hz, 100 Hz i 150 Hz znajdują się w paśmie, w którym sygnał EMG ma największą energię. Stosowanie filtrów pasmowo zaporowych w takim przypadku nie jest wskazane, bowiem filtry jak wiemy nie tłumią ściśle określonych częstości tylko pasma o pewnej szerokości (np. 45-55 Hz, 95-105 Hz, itd). W efekcie znaczna część interesującego nas pasma sygnału EMG zostałaby odrzucona. Aby zminimalizować przenikanie od rejestrowanego sygnału EMG sygnału sieciowego o częstości 50 Hz należy zadbać o niską impedancję pomiędzy elektrodą a skóra oraz powinno mierzyć się sygnały różnicowe.
Artefakty sieciowo-ruchowe
Podczas ruchu mięśnia ciało może ulec przemieszczeniu, co spowoduje ruch kabla w przestrzeni pomiędzy elektrodą a wzmacniaczem. W przestrzeni tej istnieje pole elektromagnetyczne, wywołane zasilaniem sieci elektrycznej. Ruch kabla w polu elektromagnetycznym może powodować zaburzenia sygnału o częstości 50 Hz. Ponadto układ elektrody-kable-wzmacniacz, tworzy pewne ramki, które w trakcie ruchu zmieniają kształt a także powierzchnię. Zgodnie z Prawem Indukcji Faraday'a zmiana strumienia magnetycznego powoduje powstawanie siły elektromotorycznej, która również może zakłócać pomiar.
Artefakty ruchowe można w większości wyeliminować przez zastosowanie filtru górnoprzepustowego, którego częstość odcięcia ustawia się w granicy od 10 do 20 Hz. Aby wyeliminować artefakty związane z ruchem kabla w polu elektromagnetycznym można zastosować tzw. elektrody aktywne. W elektrodach tych (miniaturowy) wzmacniacz znajduje się na elektrodzie. Wzmacnianie sygnału na elektrodzie zwiększa względną czułość układu na sygnał mierzony na elektrodzie w stosunku do zaburzenia związanego z ruchem kabla. Innym rozwiązaniem tego problemu jest zastosowanie kabli ekranowanych. Kable TMSI, których używamy na Pracowni są kablami ekranowanymi. W kablach tych, pomiędzy dwiema warstwami izolatora, istnieje dodatkowa osłona z przewodnika podłączona do wzmacniacza. Dzięki temu, zewnętrzne pole elektromagnetyczne nie przenika do środka kabla. Dodatkowo, aby wyeliminować indukowanie się ładunków w wyniku tarcia pomiędzy izolatorami a osłoną, jest ona częściowo pokryta warstwą węgla.
Sygnały do naszych zajęć znajdują się w tym katalogu: https://drive.google.com/drive/folders/18skluB3j2CHMXX8l1UmIvNXR1tZYGU0C?usp=sharing Proszę je pobrać.
Ćwiczenia
Ćwiczenie: zapoznanie się z sygnałami rejestrowanymi przez inwazyjne EMG
Proszę wczytać i przyjrzeć się sygnałom zdrowy.bin, miopatia.bin, neuropatia.bin. Sygnały są zapisane jako dtype='float64' Częstość próbkowania 4000Hz, amplitudy zapisane są w mV. Dane pochodzą z bazy Physionet: https://physionet.org/content/emgdb/1.0.0/
Proszę przeczytać informację o tych danych. W raporcie proszę napisać istotne informacje o tych sygnałach i wybrać charakterystyczne fragmenty typowe dla danego stanu klinicznego.
Ćwiczenie: detekcja aktywności wybranej jednostki ruchowej
Będziemy analizować sygnał:
Ćwiczenie I: Badanie zależności sygnału EMG od obciążenia
- umieść elektrodę GND na wewnętrznej części przedramienia, w połowie jego długości,
- umieść dwie elektrody do rejestracji sygnału EMG na mięśniu dwugłowym ramienia (popularnie zwanym bicepsem). Kable tych elektrod połącz z unipolarnymi wejściami wzmacniacza numer 1 i 2.
- ustaw częstość próbkowania sygnału na 1024Hz
- przygotuj odpowiedni montaż, aby sygnał można było rejestrować bipolarnie,
- dobierz odpowiednio filtry górnoprzepustowe,
- opisz obserwowany sygnał.
- zarejestruj około 1 min. sygnału spoczynnkowego i około 1 min sygnału przy obciążeniu mięśnia:
- oblicz ich średnią amplitudę (odchylenie standardowe)
- wykreśl oba sygnały
- oraz ich widma.
- Zbadaj zależność parametrów sygnału EMG od obciązenia mięśnia:
- dla kilku wartości obciążenia (np. do siatki na zakupy dokładamy kolejno 0.5 litrowe butelki z wodą) wykonaj pomiar sygnału przez 30 s
- pomiędzy pomiarami robić przerwy na odpoczynek mięśnia
- pomiar powtórzyć w odwrotnej kolejności obciązania
- sporządzić odpowiednie wykresy
- Zbadaj zależność sygnału EMG od czasu obciążania przy znacznym obciążeniu. Pytanie badawcze: czy jakieś paramtery tego sygnału ulegają zmianie wraz ze zmęczeniem mięśnia?
Ćwiczenie II: Badnanie przebiegu sygnału EMG względem trigera
Wykonaj następujące doświadczenie:
1. Elektrodę GND umieść na wewnętrznej stronie przedramienia w połowie jego długości.
2. Umieść elektrody do rejestracji sygnału EMG na kciuku lub u nasady kciuka.
3. Do wejścia trigger wzmacniacza podłącz przycisk.
4. Uruchom program Svarog, skonfiguruj go do rejestracji sygnału EMG i rozpocznij nagrywanie sygnału.
5. Naciśnij 50 razy przycisk kciukiem, przy czym zachowaj około 2 sekundowy odstęp w czasie pomiędzy kolejnymi naciśnięciami.
Naciśniecie przycisku spowoduje wysłanie na wejście trigger wzmacniacza sygnału w kształcie schodka prostokątnego. W momencie kiedy podejmiesz decyzję o naciśnięciu przycisku, upłynie pewien krótki okres czasu, zanim kciuk opadnie na przycisk, który z kolei uruchomi obwód generujące sygnał wysyłany na wejście trigger. Możemy się spodziewać, że sygnał EMG związany z wykonywanym przez kciuk ruchem będzie poprzedzał sygnał elektryczny wysłany przez układ przycisku. Po wykonaniu eksperymentu Twoim zadaniem będzie oszacowanie różnicy w czasie pomiędzy pojawieniem się sygnału na kanale trigger i sygnałem EMG. W tym celu napisz program, który:
1. Wczyta zarejestrowany sygnał.
2. Przefiltruje filtrem górnoprzepustowym sygnał EMG.
3. Wyznaczy początki wykonywanych przez kciuk ruchów, w oparciu o analizę wariancji sygnału EMG.
4. Narysuje histogram różnicy czasu [math]\Delta T = t_p - t_{emg}[/math], gdzie [math]t_p[/math] — czas wykonania ruchu kciukiem wyznaczony przy pomocy sygnału z kanału trigger, [math]t_{emg}[/math] — czas wykonania ruchu kciukiem wyznaczony na podstawie sygnału EMG.
Ćwiczenie III: Wykorzystanie pomiaru EMG do sterowania on-line
Przykładowy fragment kodu example.py umożliwiający odbieranie sygnału on line w pythonie przedstawiony jest poniżej.
from obci_cpp_amplifiers.amplifiers import TmsiCppAmplifier
import numpy as np
amps = TmsiCppAmplifier.get_available_amplifiers('usb')
amp = TmsiCppAmplifier(amps[0])
amp.sampling_rate = 512
amp.start_sampling()
gains = np.array(amp.current_description.channel_gains)
offsets = np.array(amp.current_description.channel_offsets)
def samples_to_microvolts(samples): # z jednostek wzmacniacza do mikrowoltów
return samples * gains + offsets
while True:
# 16 próbek w pakiecie, nieodebrane próbki się bufurują i można odebrać je później
packet = amp.get_samples(16)
print(samples_to_microvolts(packet.samples))
print(packet.ts[0])
print(packet.samples.shape, amp.current_description.channel_names)
Aby wykonać go w terminalu należy uruchomić polecenie, Uwaga, aby zadziałał trzeba wyłączyć SVAROGa. Proszę przetestować czy po podłączeniu wzmacniacza i uruchomieniu tego skryptu pojawiają się w terminalu wartości próbek.
/opt/braintech/bin/python3 example.py
Proszę dodać fragment analizujący sygnał on-line i wykrywający moment napięcia mięśnia. Po wykryciu w najprostszej wersji niech w terminalu pojawia się komunikat o wykryciu kliknięcia. W wersji max proszę zrobić wizualizację napięcia mięśnia albo podpiąć ten sygnał do sterowania jakimś prostym interfejsem.
Dodatek
Do działania on-line przydatne może być filtrowanie sygnału w sposób biegnący. Najlepiej zastosować do tego funkcję lfilter z ustalinymi warunkami początkowymi. Używa się tego w następujący sposób:
import scipy.signal as ss
import numpy as np
import matplotlib.pyplot as plt
Fs = 256
T = 1
t = np.arange(0,T,1/Fs)
f0 = 10
f1 = 17
f2 = 23
x = (np.sin(2*np.pi*f0*t) +
np.sin(2*np.pi*f1*t ) +
np.cos(2*np.pi*f2*t))
xn = x + np.random.randn(len(t)) * 0.08
b, a = ss.butter(3, 11/(Fs/2))
zi = ss.lfilter_zi(b, a)
z, _ = ss.lfilter(b, a, xn, zi=zi*xn[0])
plt.plot(y)
plt.plot(z)
plt.show()
Symulacja zastosowania tego sposobu on-line; filtrujemy za każdą iteracją pętli bufor buf, oraz przesuwamy jego zawartość, tak aby na końcu móc dadać nową próbkę. Jest to możliwa implementacja kolejki FIFO (first in first out):
zi = ss.lfilter_zi(b, a)
buf = np.zeros(30)
y = np.zeros(xn.shape)
for ind, s in enumerate(xn):
buf[:-1:] = buf[1:]
buf[-1] = s
y_tmp, zi = ss.lfilter(b, a, buf, zi=zi)
y[ind]=y_tmp[-1]
plt.plot(y)
plt.plot(z)
plt.plot(xn)
plt.show()
Dodatek 2
Dla zabawy detektor napięcia mięśni mógłby generować kliknięcia myszki, aby np. zagrać w:
https://www.gamesloon.com/free-sports-12/baseball-games-16/winnie-the-pooh-home-run-derby-54790.html
W tym celu trzeba doinstalować bibliotekę pynput:
pip3 install --user pynput
a potem zastosować kod:
from pynput.mouse import Button, Controller
mouse = Controller()
def click():
mouse.press(Button.left)
time.sleep(500)
mouse.release(Button.left)
# -*- coding: utf-8 -*-
#!/usr/bin/env python
# Author:
# Mateusz Kruszyński <mateusz.kruszynski@gmail.com>
#
from Xlib import X, display, Xutil, XK
import Xlib
special_X_keysyms = {
' ' : "space",
'\t' : "Tab",
'\n' : "Return", # for some reason this needs to be cr, not lf
'\r' : "Return",
'\e' : "Escape",
'!' : "exclam",
'#' : "numbersign",
'%' : "percent",
'$' : "dollar",
'&' : "ampersand",
'"' : "quotedbl",
'\'' : "apostrophe",
'(' : "parenleft",
')' : "parenright",
'*' : "asterisk",
'=' : "equal",
'+' : "plus",
',' : "comma",
'-' : "minus",
'.' : "period",
'/' : "slash",
':' : "colon",
';' : "semicolon",
'<' : "less",
'>' : "greater",
'?' : "question",
'@' : "at",
'[' : "bracketleft",
']' : "bracketright",
'\\' : "backslash",
'^' : "asciicircum",
'_' : "underscore",
'`' : "grave",
'{' : "braceleft",
'|' : "bar",
'}' : "braceright",
'~' : "asciitilde"
}
display = display.Display()
window = display.screen().root
def wait(p_keys_list):
"""Block the whole keyboard!!! And wait until some key from p_keys_list
is pressed. By now p_keys_list is a list of strings, so use single
ascii symbols.
There is a way out of this hell - hit 'Escape'.
The function returns hit button`s string representation
Eg. for p_keys_list == ['1','2','3'] the function will hand untill
1,2 or 3 key is preseed or Escape is pressed."""
ds = display
window.grab_keyboard(1, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime)
while True:
ev = ds.next_event()
if ev.type == X.KeyPress:
keysym = ds.keycode_to_keysym(ev._data['detail'], 0)
keystr = XK.keysym_to_string(keysym)
print("Got keysym/keystr: "+str(keysym)+ ' / '+str(keystr))
if keystr in p_keys_list:
ds.ungrab_keyboard(X.CurrentTime)
ds.flush()
return keystr
elif str(keysym) in p_keys_list:
ds.ungrab_keyboard(X.CurrentTime)
ds.flush()
return keysym
elif keysym == 65307:
ds.ungrab_keyboard(X.CurrentTime)
ds.flush()
return 'Escape'
def char_to_keysym(ch) :
keysym = Xlib.XK.string_to_keysym(ch)
if keysym == 0 :
# Unfortunately, although this works to get the correct keysym
# i.e. keysym for '#' is returned as "numbersign"
# the subsequent display.keysym_to_keycode("numbersign") is 0.
keysym = Xlib.XK.string_to_keysym(special_X_keysyms[ch])
return keysym
def keysym_to_keycode(keysym):
keycode = display.keysym_to_keycode(keysym)
shift_mask = 0
return keycode, shift_mask
def char_to_keycode(ch) :
keysym = char_to_keysym(ch)
keycode = display.keysym_to_keycode(keysym)
if keycode == 0 :
print "Sorry, can't map", ch
if (is_shifted(ch)) :
shift_mask = Xlib.X.ShiftMask
else :
shift_mask = 0
return keycode, shift_mask
def is_shifted(ch) :
if ch.isupper() :
return True
if "~!@#$%^&*()_+{}|:\"<>?".find(ch) >= 0 :
return True
return False
def send_string(str) :
"""I am not working. I dont know why:("""
for ch in str :
#print "sending", ch, "=",
display.keysym_to_keycode(Xlib.XK.string_to_keysym(ch))
keycode, shift_mask = char_to_keycode(ch)
event = Xlib.protocol.event.KeyPress(
time = int(time.time()),
root = display.screen().root,
window = window,
same_screen = 0, child = Xlib.X.NONE,
root_x = 0, root_y = 0, event_x = 0, event_y = 0,
state = shift_mask,
detail = keycode
)
window.send_event(event, propagate = True)
event = Xlib.protocol.event.KeyRelease(
time = int(time.time()),
root = display.screen().root,
window = window,
same_screen = 0, child = Xlib.X.NONE,
root_x = 0, root_y = 0, event_x = 0, event_y = 0,
state = shift_mask,
detail = keycode
)
window.send_event(event, propagate = True)
if __name__ == "__main__":
import sys,time
print(wait(sys.argv[1:]))
#send_string("aBcd")
#time.sleep(10)
"""Używa się tak:
import keystroke
keystroke.wait(['a','b'])
i to wisi dopóki ktoś nie wciśnie a lub b.
Z innymi klawiszam jest tak, że trzeba ich numery podać, np żeby czakać
na SPACE można zrobić
keystroke.wait(['32'])
w razie czego funkcja się 'odwiesza' jak się wciśnie ESC."""