Signal processing in Python Zpracování signálů v jazyce

Transkript

Signal processing in Python Zpracování signálů v jazyce
XXX. ASR '2005 Seminar, Instruments and Control, Ostrava, April 29, 2005
369
Signal processing in Python
Zpracování signálů v jazyce Python
POPEK, Jiří1,& TŮMA, Jiří2
1
Ing.,
Katedra ATŘ-352, VŠB-TU Ostrava, 17. listopadu, Ostrava - Poruba, 708 33
[email protected],
http://homel.vsb.cz/~pop036
2
Prof. Ing. Csc.,
Katedra ATŘ-352, VŠB-TU Ostrava, 17. listopadu, Ostrava - Poruba,
708 33
[email protected],
http://homel.vsb.cz/~tum52
Abstrakt: příspěvek představuje zmínku o moderním programovacím jazyce Python a jeho
využití v oblasti zpracování signálů. Popsána jsou také užitečná rozšíření jazyka o projekty
SciPy a matplotlib. Těžiště práce leží v implementaci Kalmanova filtru v jazyce Python.
Klíčová slova: Python, anasig, matplotlib, SciPy, Kalmanův filtr
1
Python
Se vzrůstajícím výkonem osobních počítačů se začaly do moderních programovacích
jazyků přidávat vlastnosti, které byly kdysi spojeny s tak velkou výkonovou provizí, že tím
byla velice omezena jejich oblast použití (např. Smalltalk). Dnes je situace jiná. Projekty jsou
stále složitější, tlak ze strany zaměstnavatele a zákazníka se zdá být větší. Proto je velice
výhodné použít jazyk, který nám práci maximálně usnadní. Takovým jazykem může být
Python.
Programovací jazyky se dělí podle několika kritérií. Základním rozdělením je na jazyky
kompilované, které jsou překládány do spustitelného binárního kódu pomocí překladače
(kompilátoru) a na jazyky interpretované, které jsou překládány až během spuštění jiným
programem, kterému se říká interpret. Existují i jazyky, které mohou mít jak interpretovanou,
tak kompilovanou podobu (Basic). Interpretované jazyky se mohou dále dělit na ty, které jsou
překládány do jakéhosi mezikódu a ty které jsou interpretovány přímo ze zdrojového textu.
Skriptovací jazyky nejsou vhodné pouze pro psaní skriptů, jak by mohl jejich název
mírně zavádět. Nejsou určeny pro psaní časově kritických částí, protože rychlost interpretace
je výrazně nižší než rychlost zkompilované podoby ve strojovém kódu. Jejich síla je jinde, a
to v rychlosti návrhu vývoje, protože obsahují spoustu vlastností, které usnadňují a hlavně
urychlují vývoj aplikací. Vývojář ve skriptovacím jazyce se nemusí starat o deklarace
proměnných, správu paměti a má k dispozici vyšší datové typy (např. asociativní pole –
slovník), které usnadňují vývoj a lze pomocí nich snadno zpřehlednit kód.
Co je to Python
Python je velice jednoduchý, efektivní, interaktivní, objektově orientovaný, skriptovací
programovací jazyk. Jako takový disponuje všemi vlastnostmi, které jsou kladeny na dnešní
moderní programovací jazyky. Jeho syntaxe je založena na odsazování textu do bloků. Díky
své jednoduchosti a interaktivnosti je výhodný pro vývoj aplikací, kde jsou požadovány
výsledky v krátkém časovém intervalu.
Python je portován na všechny důležité operační systémy a platformy (Windows, Linux,
*BSD, atd.). Protože se navíc jedná o skriptovací jazyk, je přenositelnost zdrojových textů na
velmi vysoké úrovni. Skriptovací jazyk znamená, že zdrojový kód není potřeba kompilovat,
ale kód je přímo prováděn (interpretován) programem, který se nazývá interpret. Velice
XXX. ASR '2005 Seminar, Instruments and Control, Ostrava, April 29, 2005
370
jednoduché je také možné rozšíření jazyka o binární moduly napsané v jakémkoliv jiném
programovacím jazyce. Tyto moduly tak mohou urychlit kritická místa programu, ovšem
bohužel na úkor přenositelnosti. Python je velice vhodný jako jazyk pro vytváření rozšíření
aplikací (podobně jako VBA). Příkladem je použití v kancelářském balíku OpenOffice.org.
Využívá se také na straně webových serverů jako jazyk CGI skriptů. Díky rozsáhlé standardní
knihovně funkcí je velice vhodný pro veškeré aplikace. Zajímavá jsou rozšíření, které
připomínají práci v programu Matlab atd. Pro studijní účely je také velice výhodná dobrá
podpora a dostupnost zdrojových textů.
O tom, že je Python opravdu mocný nástroj mohou pomoci přesvědčit fakta, že byl využit
pro zpracování dat a kalibraci nástrojů Hubblova vesmírného teleskopu. Je také používán pro
digitální animace, modelovací skripty pro geofyzikální a elektromagnetické jevy, nástroj pro
vývoj algoritmů a vizualizaci a mnoho dalších.
OOP
Všechny moderní programovací jazyky dnes využívají objektově orientovaného přístupu.
Python samozřejmě není vyjímkou a využívá výhod tohoto řešení. Nespornou výhodou
objektově orientovaného přístupu je především zjednodušení a zpřehlednění návrhu.
Reprezentací logických celků objekty totiž vnáší do návrhů novou dávku abstrakce, kterou lze
ocenit především u složitých návrhů a větších celků.
Data jsou v počítači uložena v paměti. Platí, že datové struktury zabírají určitý souvislý
kus paměti. Takovou datovou strukturou může být i objekt, což je instance nějaké datové
struktury, která je ve zdrojovém kódu popsána třídou. Definice třídy je ve zdrojovém kódu v
jazyce Python uvedena klíčovým slovem class. Taková třída pak definuje členská data
(proměnné) a členské metody (funkce).
Python je ale vysokoúrovňový jazyk, proto je objektově orientovaný přístup částečně
zjednodušen. Nelze například definovat viditelnost dat, jako je tomu v jazyce C++ klíčovými
slovy private, public a protected. Všechny členská data i metody jsou v Pythonu
definována jako veřejná. Existuje ale dohoda, že názvy proměnných a metod, které by neměly
být volány z vně objektu jsou uvozovány podtržítkem, např. _privdata.
Moduly SciPy a matplotlib
Python už sám o sobě představuje velice interaktivní prostředí jako např. Matlab, ale
velikou výhodou tohoto prostředí je, že je založeno na plnohodnotném programovacím
jazyce. Velmi užitečné a zajímavé je použití rozšíření jazyka Python o balíky z projektů SciPy
(http://www.scipy.org) a matplotlib (http://matplotlib.sourcefoge.net).
SciPy je sada knihoven vědeckých funkcí. Tyto funkce jsou rozděleny do řady modulů
podle oblasti použití – lineární algebra, grafické funkce pro vytváření grafů, optimalizace,
numerická integrace, interpolace, zpracování signálu (obzvláště rozsáhlý je modul funkcí pro
zpracování obrazu), genetické algoritmy, statistika, atd.
Naproti tomu je balík matplotlib primárně zaměřen pro vykreslování 2D grafů a
poskytuje interaktivní uživatelské prostředí velice podobné programu Matlab. Balík
matplotlib je možné využít ve skriptech, interaktivně v příkazové řádce (shellu), vkládat do
GUI uživatelských programů nebo použít k dynamickému generování obrázků na straně
webového serveru.
Užitečné datové struktury a manipulace s nimi
V problematice zpracování signálů nejčastěji využíváme tři datové struktury. Při
zpracování dat pomocí Pythonu je velice výhodné použít funkci array() z balíku SciPy
[WSCIPY]. Tato funkce vrací objekt typu array, který byl vytvořen na základě zadaných
hodnot formátovaných v textovém řetězci nebo sekvenci dat (např. datový typ list).
XXX. ASR '2005 Seminar, Instruments and Control, Ostrava, April 29, 2005
371
Prvním ze zmíněných a používaných datových typů je skalár. Proměnná typu skalár
nemá žádný rozměr. Skalár je „pouze“ číslo které je reprezentováno svou hodnotou. Notace
přiřazení hodnoty proměnné reprezentované svým názvem je např. v=3 (pro datový typ
integer), a=-0.432 (datový typ real). Objekty třídy array mají standardní vlastnost1
zvanou shape. Tato vlastnost vrací rozměry (dimenze) objektu třídy array. Pokud jsme
objekt typu třída array vytvořili jako skalár, vlastnost shape vrátí prázdný seznam rozměrů
(dimenzí):
>>> a = array(3.33)
>>> a.shape
()
Druhým popisovaným datovým typem je vektor. Vektor má jeden rozměr, kterému se
říká délka vektoru (length). Proměnnou typu vektor můžeme vytvořit opět s využitím funkce
array() zadáním seznamu hodnot jako parametr. Tento seznam hodnot je tvořen datovým
typem list:
>>> b = array([1, -8.5, 2.3])
>>> b.shape
(3,)
Poslední řádek kódu opět představuje výstup vrácený vlastností shape.
Třetím a posledním zmiňovaným datovým typem, který lze s výhodou použít v
programech v Pythonu, které zpracovávají signály jen dvojrozměrné pole zvané matice.
Matice má dva rozměry – první z nich je počet řádků a druhým je počet sloupců:
>>> c = array([[1, 3], [4.3, -0.333], [2./3, 555]])
>>> c
array([[ 1.00000000e+00,
3.00000000e+00],
[ 4.30000000e+00, -3.33000000e-01],
[ 6.66666667e-01,
5.55000000e+02]])
>>> c.shape
(3, 2)
Při práci s objekty typu array je nutné dbát zvýšené pozornosti pořadí indexů. Je nutné se
držet konvence, kdy první index vždy označuje počet řádků a druhý index vždy počet
sloupců. Nikdy ne naopak! Chyby vzniklé nedodržením pořadí indexů jsou bohužel velice
časté a mnohdy i špatně odhalitelné.
Při používání datových typů array je dále nutné uvědomit si jednu zásadní věc. Operace
na dvou objektech třídy array není totéž jako operace na dvou maticích! Typickým příkladem
je operace násobení. Násobení dvou objektů typu array dává následující výsledek:
>>> A = array([[2, 3], [4, 5], [-1, -2]])
>>> A
array([[ 2, 3],
[ 4, 5],
[-1, -2]])
>>> A*array([2,3])
array([[ 4, 9],
[ 8, 15],
[-2, -6]])
Jak je z příkladu zřejmé, výsledek je zcela jiný, než jaký bychom čekali za předpokladu,
že objekty jsou matice. Abychom získali objekty, které se jako matice nejen tváří, ale i
chovají, použijeme funkci bmat, která je definována v modulu scipy_base.matrix_base. Tato
funkce jednoduše vytvoří objekt třídy Matrix na základě vnořené sekvence nebo předaného
objektu typu array:
F = bmat('A, B; C, D')
F = bmat([[A,B],[C,D]])
1shape je opravdu vlastnost. Vlastnosti se od metod liší tím, že pro získání hodnoty není třeba zápis se
závorkami (volací konvence). Je to v podstatě funkce, která vrací data, ale k uživateli se tváří, jakoby se jednalo
o členskou proměnnou.
XXX. ASR '2005 Seminar, Instruments and Control, Ostrava, April 29, 2005
372
F = bmat(r_[c_[A,B],c_[C,D]])
Pomocí všech těchto zápisů lze získat identický objekt třídy Matrix:
[ A
[ C
2.
B ]
D ]
Realizace Kalmanova filtru
Z mnoha důvodů je vhodné Kalmanův filtr navrhnout od začátku s využitím objektově
orientovaného přístupu. Vytvořenou třídu nazveme výstižně KalmanFilter.
Samotné jádro Kalmanova filtru bude představovat metoda s názvem tick. Tato metoda
bude představovat jeden krok (tik, step) algoritmu filtru. Funkce tick bude mít 4 parametry.
První z nich bude yv_k, což je poslední známá hodnota výstupu, u_k je poslední známá
hodnota vstupu systému a x a P aktuální (aktualizované) hodnoty stavu systému a kovarianční
matice. V prvním kroku bude algoritmus inicializován počátečními hodnotami x0 and P0.
Tyto hodnoty budou do objektu předány během jeho vytváření (inicializace), které je
reprezentováno voláním konstruktoru – v Pythonu metoda __init__(). Konstruktor třídy
KalmanFilter __init__() má rovněž jako parametry deklarovány matice systému A, B, C, D a
Q, R, což jsou kovarianční matice procesu a měření. Tyto matice jsou předány jako datový
typ list.
Zpracování dat proběhne voláním metody process. Tato metoda interně cyklicky volá
metodu tick, která představuje samotné jádro filtru (jeden krok algoritmu). Krok algoritmu je
tak volán pro všechny vstupní hodnoty (iteruje vstupním vektorem), což je programově
realizováno cyklem for.
Protože jsou v modulu filtru použity některé externí funkce, je nutno názvy těchto funkcí
naimportovat do jmenného prostoru modulu (namespace). To provedeme vložením
následujících řádků na začátek modulu s definicí třídy KalmanFilter:
from LinearAlgebra import inverse
from scipy import eye
from Numeric import transpose
Následující řádky představují samotný zdrojový kód vytvořené třídy KalmanFilter v
programovacím jazyce Python:
1 class KalmanFilter:
2
""" Kalman filter """
3
def __init__( self, A, B, C, D, Q, R, x0, P0 ):
4
self.__dict__['A'] = bmat( array(A) ) # NxN
5
self.__dict__['B'] = bmat( array(B) ) # Nxp
6
self.__dict__['C'] = bmat( array(C) ) # qxN
7
self.__dict__['D'] = bmat( array(D) ) # pxq
8
9
self.__dict__['NSTATES'] = self.A.shape[0] # N
10
self.__dict__['NINPUTS'] = self.B.shape[1] # p
11
self.__dict__['NOUTPUTS'] = self.C.shape[0] # q
12
13
# covariance matrixes
14
# Q must be NxN
15
if isscalar(Q):
16
self.__dict__['Q'] = bmat( eye(self.NSTATES) * Q )
17
else:
18
self.__dict__['Q'] = bmat( array(Q) )
19
# R must be qxq
20
if isscalar(R):
21
self.__dict__['R'] = bmat( eye(self.NOUTPUTS) * R )
22
else:
23
self.__dict__['R'] = bmat( array(R) )
24
25
# initial values
26
self.x0 = x0
XXX. ASR '2005 Seminar, Instruments and Control, Ostrava, April 29, 2005
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
373
self.P0 = P0
def __setattr__( self, attr, val ):
if attr == 'A':
self.__dict__['A'] = bmat( array(val) )
# NxN
if attr == 'B':
self.__dict__['B'] = bmat( array(val) )
# Nxp
if attr == 'C':
self.__dict__['C'] = bmat( array(val) )
# qxN
if attr == 'D':
self.__dict__['D'] = bmat( array(val) )
# pxq
elif attr == 'x0':
self.__dict__['x'] = bmat( array(val) )
# Nxp
elif attr == 'P0':
mP, nP = array(val).shape
# must be NxN
# P is not square or has bad dimension
if (mP != nP) or (mP != self.NSTATES):
self.__dict__['P'] = bmat(eye(self.NSTATES) * val)
else: self.__dict__['P'] = bmat(array(val))
else: # default - unknown param
self.__dict__[attr] = val
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def process( self, yv, u ):
# make column matrixes from vectors
if len(u.shape) == 1:
u = reshape( u, (u.shape[0], 1) )
if len(yv.shape) == 1:
yv = reshape( yv, (yv.shape[0], 1) )
77
78
79
80
81
82
83
84
85
86
def tick( self, yv_k, u_k, x, P ):
# fetch the values
A,B,C,D,R,Q = self.A,self.B,self.C,self.D,self.R,self.Q
# estimate (time update)
x_est = A*x + B*u_k
P_est = A*P*transpose(A) + Q
# data length
LEN = yv.shape[0]
x, P = self.x, self.P
# output vectors
y_est_out = array( [[0]]*LEN, Float )
x_out = []
P_out = []
x_out.append( x )
P_out.append( P )
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## loop for the entire dataset:
## Kalman filter algorithm
for i in range(1, LEN):
# fetch values
uval = bmat( array([u[i,:]]) )
yvval = bmat( array([yv[i,:]]) )
x, P, y_est_out[i] = self.tick( yvval, uval, x, P )
x_out.append( x )
P_out.append( P )
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
return x_out, P_out, y_est_out
# correction (measurement update)
K = P_est*transpose(C) * inverse( C*P_est*transpose(C) + R )
x = x_est + K*( transpose(yv_k) - C*x_est - D*u_k )
XXX. ASR '2005 Seminar, Instruments and Control, Ostrava, April 29, 2005
87
88
89
90
91
3
374
P = (eye(self.NSTATES) - K*C) * P_est
y = C*x + D*u_k
return x, P, y[0,0]
Ověření funkčnosti
Funčnost realizace Kalmanova filtru byla ověřena na základě vygenerovaných hodnot dle
následujícího schématu zapojení:
u
y
Kalmanův
filtr
u
w
x
yv
y
soustava
v
Obrázek 1 – Příklad zapojení Kalmanova filtru
Na následujícím obrázku je vidět graf, na kterém je znázorněna práce filtru. Modrou
barvou je znázorněn výstup soustavy, červeně pak odhad toho výstupu realizovaný
Kalmanovým filtrem.
Obrázek 2 – Příklad výstupu realizace vygenerovanými daty
XXX. ASR '2005 Seminar, Instruments and Control, Ostrava, April 29, 2005
4
375
Závěr
Kalmanův filtr je velice moderní nástroj. V samotné podstatě jej tvoří řada
matematických rovnic, které představují výpočetně velice výkonné (rekurzivní) řešení odhadu
stavu systému na základě metody nejmenších čtverců.
Samotnou programovou realizaci v programovacím jazyce Python usnadňuje použití
některých objektů a funkcí z balíků SciPy. Ten sám o sobě tvoří obrovskou sadu modulů
vědeckých funkcí pro použití právě v jazyce Python.
Realizovaná implementace Kalmanova filtru bude užitečná pro další použití, jelikož v
současné době taková neexistuje. Ta tvoří největší přínos této práce. Vytvořená třída, stejně
jako celá aplikace anasig, bude rovněž uvolněna pod některou z licencí svobodného softwaru.
5
Použitá literatura
TŮMA, J. 1998. Složité systémy řízení, 1.díl: Regulace soustav s náhodnými poruchami.
Ostrava, skripta katedry ATŘ, FS VŠB-TU Ostrava, 1998
KALMAN, R.E. 1960. A New Approach to Linear Filtering and Prediction Problems.
[online]. Available: http://www.cs.unc.edu/~welch/media/pdf/Kalman1960.pdf
Lu, Y.Z. 1996. Industrial Intelligent Control. West Sussex, VB, John Wiley & Sons, 1996
MAYBECK,
P.S.
Stochastic
models,
estimation,
and
control.
[online].
Available: http://www.cs.unc.edu/~welch/media/pdf/maybeck_ch1.pdf
WELCH, G. & BISHOP, G. An Introduction to the Kalman Filter. [online].
Available: http://www.cs.unc.edu/~welch/kalman/kalmanIntro.html
GOPAL, M. 1984. Modern Control System Theory.
ISBN 0 85226 321 X, Willey
Eastern Limited, New Delphi, 1984
BROWN, R.G. & HWANG P.Y.C. 1992. Introduction to Random Signals and Applied
Kalman Filtering, Second edition, ISBN 0-471-55922-9, 1983, 1992
D'AZZO, J. J. & HOUPIS, C. H. 1988. Linear Control system Analysis and Design, 3rd ed.,
New York: McGraw-Hill, 1988
HARMS, D. & MCDONALD, K. Začínáme programovat v jazyce Python, Computer press,
ISBN 80-7226-799-X, prodejní kód: K0809, 449 stran
SORENSON, H. W. 1985, Kalman filtering: Theory and Application, Computer press, IEEE
Press, 1985
PYTHON, oficiální web, http://www.python.org
SCIPY, oficiální web, http://scipy.org/
MATPLTLIB, oficiální web, http://matplotlib.sourceforge.net

Podobné dokumenty

243

243 Linux OS Implementation at the Department of Control Systems and Instrumentation Implementace OS Linux do infrastruktury katedry ATŘ POPEK, Jiří Ing.,

Více

čtvrtý - šestý týden

čtvrtý - šestý týden h1 {color:red;} /* alternativní zápis výše uvedeného */ h2 {color:red;} h3 {color:red;} ol ol {color:red;} /* 2. úroveň uspořádaného seznamu */

Více

zadání tutoriálu

zadání tutoriálu V tomto dı́le tutoriálu se podrobněji seznámı́me s jednou z nejdůležitějšı́ch vědeckých knihoven, NumPy (Numerical Python). Tato knihovna poskytuje algoritmy a datové typy (třı́dy) urče...

Více

3. týden

3. týden • CSS = Cascading Style Sheets = tabulky kaskádových stylů • na začátku byl stylesheet – soubor pravidel definující vzhled textu nezávisle na obsahu • pomocí CSS lze nadefinovat společný vzhled sou...

Více

Létající cirkus

Létající cirkus Téměř každý programátor vyzkoušel za svůj život vícero programovacích jazyků. A také téměř každý si vysnil svůj ideální. Jednoduchý, robustní, hezký, přenositelný. A poněvadž se v poslední době čím...

Více

Petr Krabica

Petr Krabica * platí pro dekory: H32,H33,H34,H35,H36,H37,H38,H39,H40,H41,H42,H43,H44,H45,H46,H47,H48,H49

Více

Untitled

Untitled /Czech Techn. Univ. Prague/ 1971; Assoc. Prof. 1964; PhD /Czechoslovak Acad. Sci./ 1959; Ing. /Czech Techn. Univ. Prague/ 1955 Born 1930 Specialized in: stability problems and limit states of thin-...

Více

offline v PDF - Mathematical Assistant on Web

offline v PDF - Mathematical Assistant on Web V následujı́cı́ch vzorcı́ch operátor “·” označuje skalárnı́ součin vektorů. Vztahy jsou uvedeny pro funkci dvou proměnných, ale úplně stejně platı́ pro funkce libovolného počtu proměn...

Více