Signal processing in Python Zpracování signálů v jazyce
Transkript
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
Linux OS Implementation at the Department of Control Systems
and Instrumentation
Implementace OS Linux do infrastruktury katedry ATŘ
POPEK, Jiří
Ing.,
č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 */
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...
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...
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...
Petr Krabica
* platí pro dekory: H32,H33,H34,H35,H36,H37,H38,H39,H40,H41,H42,H43,H44,H45,H46,H47,H48,H49
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-...
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...