Xpert.press
Die Reihe Xpert.press vermittelt Professionals in den Bereichen Softwareentwicklung, Internettechnologie und IT-Management aktuell und kompetent relevantes Fachwissen über Technologien und Produkte zur Entwicklung und Anwendung moderner Informationstechnologien.
Oliver Kluge
Praktische Informationstechnik mit C# Anwendungen und Grundlagen Mit 115 Abbildungen und 18 Tabellen
123
Dr. Oliver Kluge 90489 Nürnberg
[email protected]
Bibliografische Information der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar.
ISSN 1439-5428 ISBN-10 3-540-20812-7 Springer Berlin Heidelberg New York ISBN-13 978-3-540-20812-9 Springer Berlin Heidelberg New York Dieses Werk ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesondere die der Übersetzung, des Nachdrucks, des Vortrags, der Entnahme von Abbildungen und Tabellen, der Funksendung, der Mikroverfilmung oder der Vervielfältigung auf anderen Wegen und der Speicherung in Datenverarbeitungsanlagen, bleiben, auch bei nur auszugsweiser Verwertung, vorbehalten. Eine Vervielfältigung dieses Werkes oder von Teilen dieses Werkes ist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des Urheberrechtsgesetzes der Bundesrepublik Deutschland vom 9. September 1965 in der jeweils geltenden Fassung zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen unterliegen den Strafbestimmungen des Urheberrechtsgesetzes. Springer ist ein Unternehmen von Springer Science+Business Media springer.de © Springer-Verlag Berlin Heidelberg 2006 Printed in Germany Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften. Text und Abbildungen wurden mit größter Sorgfalt erarbeitet. Verlag und Autor können jedoch für eventuell verbliebene fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Satz und Herstellung: LE-TEX, Jelonek, Schmidt & Vöckler GbR, Leipzig Umschlaggestaltung: KünkelLopka Werbeagentur, Heidelberg Gedruckt auf säurefreiem Papier 33/3100 YL – 5 4 3 2 1 0
Vorwort
„Scientific computing“, „computational intelligence“ und „computational engineering“ sind Schlagworte der modernen Informationstechnik. Diese Begriffe stehen für verschiedene Konzepte der digitalen Informationsverarbeitung, wie sie in Wissenschaft und Technik zum Einsatz kommen. Ob bei der Analyse von Meßwertreihen, der automatischen Schrifterkennung oder bei der Simulation von elektrischen Ausgleichsvorgängen, Kollege Computer ist immer dabei. Das vorliegende Buch gibt einen Einblick in die Funktionsweise der entsprechenden Programme. Zahlreiche Implementierungsbeispiele erleichtern das Verständnis. Aufgrund des breiten Anwendungsspektrums der Informationstechnik werden sehr unterschiedliche Schwerpunkte behandelt. Signale sind Träger von Information. Die digitale Signalverarbeitung ist daher eine Schlüsseltechnologie unserer heutigen Informationsgesellschaft. Im ersten Kapitel steht die Verarbeitung von Abtastsignalen im Zeit- und Frequenzbereich im Vordergrund. Neben der Frequenzanalyse und dem Kurzzeit-Spektrum wird ausführlich auf die Berechnung digitaler Filter eingegangen. Hieran schließen sich statistische Verfahren an. Lage-, Streuund Formparameter sind geeignete Kenngrößen, um Rauschphänomene zu beschreiben. Stochastische Abhängigkeiten in Meßreihen lassen sich mit Hilfe der Korrelationsanalyse erkennen. Zusätzlich werden Regressionsverfahren und statistische Rangordnungsfilter vorgestellt. Als Ergänzung zu den konventionellen Verfahren behandelt das dritte Kapitel Methoden der künstlichen Intelligenz. Mit neuronalen Netzen und Fuzzy-Systemen hat die Signalverarbeitung nach biologischem Vorbild bereits in vielen Anwendungen Einzug gefunden, bei denen unscharfe oder gestörte Informationen vorliegen. Das vierte Kapitel ist eine Einführung in die Simulationstechnik. Mit der numerischen Lösung von Differentialgleichungen oder Monte-Carlo-Methoden kommt man der Realität zum Greifen nahe. Doch was nützt Information, wenn sie nicht verfügbar ist? Die Kommunikation über Netzwerke ist eine weitere Säule der Informationstechnik, weshalb sich das letzte Kapitel mit der Netzwerkprogrammierung beschäftigt. Nürnberg, Januar 2006
Oliver Kluge
Inhaltsverzeichnis
1
Digitale Signalverarbeitung .............................................................1 1.1 Einführung................................................................................1 1.2 Fourier-Reihen..........................................................................2 1.3 Die Diskrete Fourier-Transformation (DFT)............................6 1.4 Arithmetiktuning – Die FFT...................................................11 1.5 Pulse und Pulsfolgen ..............................................................22 1.6 Der Abtastvorgang..................................................................26 1.7 Das Abtasttheorem .................................................................29 1.8 Leakage...................................................................................30 1.9 Nichtstationäre Signale – Die Grenzen der DFT....................33 1.10 Die Zeit-Frequenz-Analyse ....................................................35 1.11 Digitale Filter..........................................................................40 1.11.1 Frequenzselektive Eigenschaften ................................41 1.11.2 Die z-Transformation ..................................................43 1.11.3 Die Übertragungsfunktion und der Frequenzgang ......47 1.11.4 Mittelwertfilter ........................................................... 49 1.11.5 FIR-Filter.................................................................... 51 1.11.6 IIR-Filter..................................................................... 68 1.11.7 Der Phasengang.......................................................... 81 1.11.8 Vergleich zwischen FIR- und IIR-Filtern .................. 82 1.11.9 FFT-Filter ................................................................... 83 1.12 Experimentelle Systemanalyse .............................................. 84 1.12.1 Identifikation im Frequenzbereich ............................. 84 1.12.2 Identifikation im Zeitbereich...................................... 94
2
Statistische Signalverarbeitung .................................................... 97 2.1 Einführung............................................................................. 97 2.2 Zufallszahlen – Dem Rauschen auf der Spur ........................ 98 2.2.1 Gleichverteilte Zufallszahlen ..................................... 99 2.2.2 Normalverteilte Zufallszahlen.................................. 100 2.2.3 Beliebig verteilte Zufallszahlen................................ 101 2.2.4 Summen von Zufallsvariablen – Der Grenzwertsatz.................................................... 103
VIII Inhaltsverzeichnis
2.3 2.4
Die Normalverteilung .......................................................... 103 Grafische Methoden der statistischen Analyse.................... 105 2.4.1 Das Histogramm....................................................... 105 2.4.2 Das Streudiagramm .................................................. 109 2.5 Lage-, Streu- und Formparameter in der Statistik ............... 112 2.5.1 Der arithmetische Mittelwert.................................... 112 2.5.2 Der Median............................................................... 113 2.5.3 Die Spannweite ........................................................ 114 2.5.4 Die mittlere absolute Abweichung........................... 115 2.5.5 Die Standardabweichung und die Varianz ............... 115 2.5.6 Die Schiefe ............................................................... 117 2.5.7 Die Kurtosis.............................................................. 117 2.6 Stichprobe und Grundgesamtheit ........................................ 122 2.7 Standardisierte Maßzahlen – Die z-Transformation ............ 123 2.8 Die Korrelationsanalyse ...................................................... 124 2.8.1 Empirische Korrelation ............................................ 124 2.8.2 Korrelation im Streudiagramm................................. 130 2.8.3 Korrelation und Kausalität ....................................... 132 2.9 Die Regressionsanalyse ....................................................... 133 2.9.1 Lineare Regression................................................... 133 2.9.2 Regression einer allgemeinen Polynomfunktion...... 137 2.9.3 Regression einer Exponentialfunktion ..................... 143 2.9.4 Regression einer Potenzfunktion.............................. 145 2.10 Rangordnungsfilter .............................................................. 148 3
Computational Intelligence......................................................... 157 3.1 Einführung........................................................................... 157 3.2 Neuronale Netze .................................................................. 159 3.2.1 Biologische Grundlagen........................................... 159 3.2.2 Künstliche Neuronen................................................ 161 3.2.3 Netzstrukturen .......................................................... 163 3.2.4 Der Backpropagation-Lernalgorithmus.................... 166 3.2.5 Lerndatenaufbereitung ............................................. 176 3.2.6 Die Lerndatei............................................................ 177 3.2.7 Anwendungen neuronaler Netze .............................. 181 3.3 Fuzzy-Logik ........................................................................ 187 3.3.1 Die unscharfe Menge ............................................... 188 3.3.2 Unscharfes Schließen ............................................... 191 3.3.3 Die Struktur von Fuzzy-Systemen ........................... 195 3.3.4 Implementierung von Fuzzy-Systemen.................... 197 3.4 Neuronales Netz oder Fuzzy-System?................................. 213
Inhaltsverzeichnis
IX
4
Simulationstechnik....................................................................... 215 4.1 Einführung........................................................................... 215 4.2 Modellbildung ..................................................................... 215 4.3 Die analytische Lösung ....................................................... 217 4.4 Numerische Lösungsmethoden von Differentialgleichungen ................................................ 220 4.4.1 Das Polygonzug-Verfahren ...................................... 222 4.4.2 Das verbesserte Polygonzug-Verfahren ................... 223 4.4.3 Das Euler-Cauchy-Verfahren ................................... 224 4.4.4 Das Runge-Kutta-Verfahren..................................... 225 4.4.5 Das Adams-Bashforth-Verfahren............................. 227 4.4.6 Die Wahl der Methode ............................................. 229 4.4.7 Mehrdimensionale Betrachtungen............................ 230 4.4.8 Schrittweitensteuerung ............................................. 243 4.4.9 Differentialgleichungen höherer Ordnung ............... 243 4.5 Monte-Carlo-Methoden ....................................................... 245
5
Netzwerke ..................................................................................... 249 5.1 Einführung........................................................................... 249 5.2 Historische Entwicklung...................................................... 249 5.3 Physikalische Grundlagen ................................................... 252 5.3.1 Leitungsgebundene Signalübertragung .................... 253 5.3.2 Drahtlose Signalübertragung.................................... 254 5.3.3 Optische Signalübertragung ..................................... 256 5.4 Netzwerkstrukturen ............................................................. 259 5.4.1 Sternstruktur ............................................................. 259 5.4.2 Ringstruktur.............................................................. 260 5.4.3 Busstruktur ............................................................... 260 5.4.4 Vermaschte Struktur................................................. 261 5.5 Netzwerkkomponenten........................................................ 261 5.5.1 Repeater.................................................................... 262 5.5.2 Gateways .................................................................. 262 5.5.3 Router....................................................................... 262 5.6 TCP/IP und UDP/IP............................................................. 262 5.7 Sockets................................................................................. 263 5.8 Das Client-Server-Modell.................................................... 264
6
Anhang.......................................................................................... 271 6.1 Lineare Gleichungssysteme................................................. 271 6.1.1 Die Gauß-Elimination .............................................. 272
X
Inhaltsverzeichnis
6.2
Sortieren ...............................................................................288 6.2.1 Sortieren durch Vertauschen – Selectionsort ............288 6.2.2 Quicksort ...................................................................289 6.2.3 Vergleich beider Verfahren.......................................291
Literaturverzeichnis .....................................................................297 Sachverzeichnis .............................................................................301
1 Digitale Signalverarbeitung
1.1 Einführung Es besteht gar kein Zweifel, wir leben in einer Informationsgesellschaft. Ganz egal, ob wir Musik hören, mit dem Auto unterwegs sind oder mit guten Freunden telefonieren, ständig kommen wir mit Systemen der digitalen Signalverarbeitung in Berührung. Ein großer Teil der Information die uns erreicht ist bereits in mehreren vorangegangenen Schritten digital verarbeitet worden, auch wenn wir uns dessen nicht immer bewußt sind. Träger der Information sind Signale, die im mathematischen Sinne Funktionen einer oder mehrerer unabhängiger Variablen (Zeit, Raumkoordinaten) sind. Die Aufgabe der Signalverarbeitung besteht vor allem in der Manipulation, Analyse und Interpretation von Signalen. Sie kann zu Recht als eine entscheidende Schlüsseltechnologie des modernen Lebens gesehen werden. Interessanterweise wurden die mathematischen Grundlagen hierzu bereits in einer Zeit erarbeitet, als an Computer, Unterhaltungselektronik oder auch nur die Elektrifizierung der privaten Haushalte noch nicht einmal zu denken war. Einer der Wegbereiter war Jean-Baptiste Joseph Fourier (1768–1830), der im französischen Auxerre als Sohn eines Schneiders geboren wurde. Er besuchte u. A. die dortige Militärschule, wo sein mathematisches Interesse geweckt wurde. Hier machte er durch seine Studien zur Mathematik und Mechanik auf sich aufmerksam. Trotzdem entschied Fourier sich zunächst, nicht unüblich für die damalige Zeit, für das Priesteramt und begann eine entsprechende Ausbildung in der Abtei St. Benoit-sur-Loire. Er mußte sich aber bald eingestehen, daß sein Herz doch mehr für die Mathematik schlug. Zurück in Auxerre arbeitete er als Mathematiklehrer. Die Wirren der Französischen Revolution gingen auch an Fourier nicht spurlos vorüber und hätten ihm beinahe, im wahrsten Sinne des Wortes, Kopf und Kragen gekostet. 1795 zog er nach Paris und vollendete seine Studien an der École Polytechnique, an der er später auch selber lehrte. Fourier war Mitglied der Académie des Sciences und der Académie Française. Sein Ruhm gründet vor allem auf Arbeiten zur Mathematik und zur mathematischen Physik. 1822 entstand sein Hauptwerk, die „Théorie analytique de la chaleur“, in dem er den Wärmetransport und die Temperaturverteilung im
2
1 Digitale Signalverarbeitung
Abb. 1.1. Jean-Baptiste Fourier
Inneren homogener Körper mit Hilfe von partiellen Differentialgleichungen beschreibt.
1.2 Fourier-Reihen Fourier verwendete in seiner Arbeit trigonometrische Reihen, die man heute als Fourier-Reihen kennt. Er erkannte, daß sich periodische Funktionen in einfache Basisfunktionen zerlegen lassen. Die von ihm verwendeten trigonometrischen Funktionen Sinus und Cosinus bilden gerade einen hierfür geeigneten Funktionsbaukasten. Die notwendige Periodizität liegt genau dann vor, wenn für alle ganzzahligen n die folgende Bedingung erfüllt ist.
x(t ) = x(t + nT )
(1.1)
Das bedeutet, der Funktionsverlauf wiederholt sich mit der Periodendauer T, deren Kehrwert bekanntlich die Frequenz ist.
f =
1 T
(1.2)
1.2 Fourier-Reihen
3
Anstelle der Frequenz f wird jedoch für periodische Vorgänge üblicherweise die sogenannte Kreisfrequenz ω verwendet.
ω = 2π f =
2π T
(1.3)
Mit diesem Rüstzeug gelingt die Darstellung einer periodischen Funktion als unendliche Summe der trigonometrischen Basisfunktionen. ∞
x(t ) = a0 + ¦ (an cos(nω t ) + bn sin( nω t ))
(1.4)
n =1
mit
a0 =
1 x(t )dt T T³
(1.5)
an =
2 x(t ) cos(nω t ) dt T T³
(1.6)
bn =
2 x(t ) sin(nω t ) dt T T³
(1.7)
Der Koeffizient a0 ist der Mittelwert der Zeitfunktion x(t), stellt also den darin enthaltenen Gleichanteil dar. Die Amplituden an und bn repräsentieren die Gewichtung der verschiedenen Frequenzen nȦ. Wie später noch gezeigt wird, kommt ihnen bei der Signalanalyse eine ganz besondere Bedeutung zu. In der praktischen Anwendung bricht man eine solche Reihe nach endlich vielen Gliedern ab und begnügt sich mit einer genügend genauen Approximation. Als Beispiel sei an dieser Stelle die Entwicklung einer Rechteckfunktion vorgestellt.
sin((2k − 1)ω t ) (2k − 1) n =1 ∞
x(t ) = ¦
= sin(ω t ) +
sin(3ω t ) sin(5ω t ) sin(7ω t ) + + + ... 3 5 7
In diesem einfachen Beispiel sind keine Cosinus-Anteile enthalten (an = 0 für alle n) und die Amplituden der Sinus-Anteile ergeben sich zu b1 = 1, b2 = 0, b3 = 1/3, b4 = 0, b5 = 1/5, b6 = 0, b7 = 1/7, ... usw. Die gewünschte Annäherung an den idealen Funktionsverlauf gelingt aber erst mit einer sehr großen Anzahl von Reihengliedern, wie die nachfolgende Abbildung deutlich macht.
1 Digitale Signalverarbeitung 1 0,8
0,6
0,6
0,4
0,4
0,2
0,2 330
352
352
396
308
330
374
286
396
264
308
374
242
286
t
t 1
0,8
0,8
0,6
0,6
0,4
0,4
0,2
0,2
-0,4
-0,6
-0,6
-0,8
-0,8
-1
198
176
154
132
110
88
66
44
0
0 -0,2
-0,4
22
396
374
352
330
308
286
264
242
220
198
176
154
132
110
88
66
44
0
0
x(t)
1
22
x(t)
198
176
154
88
132
110
66
-1
-1
-0,2
264
-0,8
220
-0,6
-0,8
242
-0,4
-0,6
220
-0,4
44
0 -0,2
0
396
374
352
330
308
286
264
242
220
198
176
154
88
132
110
66
44
-0,2
0
0
22
x(t)
1 0,8
22
x(t)
4
-1
t
t
Abb. 1.2. Entwicklung einer Rechteckfunktion mit 1, 2, 3 und 20 Reihengliedern
Offensichtlich bereiten steile Signalflanken gewisse Probleme, denn zu beiden Seiten der Sprungstelle ist ein interessanter Effekt zu beobachten. Es zeigt sich ein deutliches Überschwingen, dessen Amplitude auch mit steigender Anzahl von Summanden nicht abnimmt. Dieses Verhalten ist als Gibbsches Phänomen bekannt. Die Ursache liegt in der letztlich doch immer nur endlichen Anzahl von Reihengliedern bei einer solchen Approximation. Auch das zweite Beispiel in Tabelle 1.1 zeigt diesen Effekt. Neben der hier vorgestellten reellen Fourier-Reihe existiert noch eine komplexe Version, die man durch Anwendung der Eulerschen Formel (ejij = cosij + j·sinij) erhält. Die resultierende Reihe kann als orthogonale Entwicklung von x(t) nach einem System komplexer Exponentialfunktionen verstanden werden.
x(t ) =
+∞
¦c e
jnω t
n
(1.8)
n = −∞
cn =
1 x(t ) e − jnω t dt ³ TT
(1.9)
Die von Fourier beschriebene Reihenentwicklung ist nun keineswegs die einzige Möglichkeit eine Funktion x(t) mit Hilfe elementarer Basisfunktionen darzustellen. Vielmehr gibt es beliebig viele solcher Funktionssysteme, die als Aufbaufunktionen dienen können, vergleichbar mit einem Vektor, der ebenfalls in verschiedenen Koordinatensystemen (rechtwinklig, schiefwinklig, Polarkoordinaten, ...) darstellbar ist. Allerdings kommt
5
1.2 Fourier-Reihen Tabelle 1.1. Beispiele für Fourier-Reihen 1,5 1 0,5
357
378
399
378
399
336
357
315
336
294
315
273
252
231
210
189
168
147
-0,5
126
84
105
0
63
0 42
n =1
sin((2n − 1)ω t ) ⋅ (2n − 1) 2
21
x(t ) = ¦ (−1)
n +1
x(t)
∞
-1 -1,5
t 7 6 5
x(t)
§ ∞ sin(nω t ) · x(t ) = π − 2¨ ¦ ¸ n © n =1 ¹
8
4 3 2 1 294
273
252
231
210
189
168
147
126
84
105
63
42
21
0
0
378
399
378
399
336 336
357
315 315
357
294
273
294
252
231
210
189
168
147
126
105
84
63
42
x(t)
1 0,8 0,6 0,4 0,2 0 -0,2 -0,4 -0,6 -0,8 -1
0
sin(2n − 1) ⋅ sin((2n − 1)ω t ) (2n − 1) 2 n =1 ∞
x(t ) = ¦
21
t
t
π2
cos(nω t ) · § ∞ − 4¨ ¦ (−1) n +1 ⋅ ¸ 3 n2 © n =1 ¹
10 8
x(t)
x(t ) =
12
6 4 2 273
252
231
210
189
168
147
126
105
84
63
42
21
0
0
t
es in einer Anwendung ganz entschieden darauf an, die jeweils günstigste Darstellung zu wählen. Das gilt auch für die Wahl des Funktionssystems bei der Approximation von x(t). Fourier verwendete für seine periodischen Funktionen die trigonometrischen Basisfunktionen Sinus und Cosinus, und er tat gut daran. Wie sich wahrscheinlich jeder leicht vorstellen kann, ist es immer günstig gerade solche Aufbaufunktionen zu wählen, die eine gewisse Ähnlichkeit mit x(t) aufweisen, da die Approximation dann besonders schnell konvergiert. Eine derartige Reihenentwicklung läßt sich ganz allgemein formulieren: ∞
x(t ) = ¦ an ϕ n (t ) n=0
(1.10)
6
1 Digitale Signalverarbeitung
Wie auch schon bei der Fourier-Reihe, ist x(t) eine Linearkombination der Aufbaufunktionen ijn(t), wobei es gilt, die Entwicklungskoeffizienten an zu bestimmen. Hierzu sind beide Seiten der Gleichung mit den konjugiert komplexen Funktionen ij*k(t) zu multiplizieren und über das Intervall T zu integrieren. Der Rechenaufwand vereinfacht sich erheblich, wenn das gewählte Funktionssystem ijn(t) die Orthogonalitätsbedingung erfüllt.
³ ϕ (t ) ⋅ ϕ n
T
∗ m
0 (t )dt = ® ¯k n
( n ≠ m) ( n = m)
(1.11)
Sind zusätzlich alle kn = 1, ist ijn(t) als orthonormal. Die Multiplikation von Gln. (1.10) mit ij*k(t) und anschließende Integration führen auf die nachfolgende Beziehung. ∞
∗ ∗ ³ x(t ) ⋅ ϕm (t )dt = ³ ¦ an ϕn (t ) ⋅ ϕm (t )dt
T
T n=0
Vorausgesetzt die Summe (1.10) ist gleichmäßig konvergent und man beachtet die Bedingung (1.11), folgt hieraus die Formel zur Berechnung der gesuchten Koeffizienten.
an =
1 x(t ) ⋅ ϕn∗ (t ) dt ³ kn T
(1.12)
Neben den trigonometrischen Aufbaufunktionen sind noch die 1923 von J. L. Walsh definierten Walsh-Funktionen und die nur ein Jahr zuvor von H. Rademacher entwickelten Rademacher-Funktionen von praktischer Bedeutung. Beide sind Erweiterungen der 1910 von A. Haar vorgestellten orthogonalen Funktionsbasis, den sogenannten Haar-Funktionen.
1.3 Die Diskrete Fourier-Transformation (DFT) Schaut man auf das bisher Gezeigte, liegt die Vermutung nahe, daß es auch eine Möglichkeit gibt, den umgekehrten Weg zu beschreiten, also eine Funktionsapproximation wieder in ihre erzeugenden Basisfunktionen zu zerlegen. Ein solches Vorgehen wäre dann geeignet, ein Signal in Bezug auf seine spektrale Zusammensetzung zu analysieren. Während man die Gleichungen (1.4) und (1.8) häufig auch als Synthesegleichungen bezeichnet, beschreiben die Gleichungen (1.5), (1.6), (1.7) und (1.9) das Signal im Frequenzbereich und werden daher entsprechend Analysegleichungen genannt. Ein Digitalrechner kann aber immer nur zeitdiskrete Werte erfassen und verarbeiten. Die zeitkontinuierlichen Signalverläufe realer
1.3 Die Diskrete Fourier-Transformation (DFT)
7
physikalischer Größen müssen infolgedessen diskretisiert werden. Möchte man eine Frequenzanalyse für ein Abtastsignal durchführen, müssen dann auch die Transformationen (1.6) und (1.7) zeitdiskret angepaßt werden. Dabei gehen die zeitkontinuierlichen Integrale der orthogonalen Komponenten, die den Realteil und den Imaginärteil des Signals repräsentieren, in zeitdiskrete Summen über.
an = bn =
2 N 2 N
N −1
k
¦ x(k ) ⋅ cos(2 π n N )
(1.13)
k =0
N −1
k
¦ x(k ) ⋅ sin(2 π n N )
(1.14)
k =0
X n = an2 + bn2 § bn · ¸¸ © an ¹
ϕ n = arctan¨¨
(1.15) (1.16)
Aus diesen Summen können dann wiederum nach Gln. (1.15) das Amplitudenspektrum, oft auch Betragsspektrum genannt, und das Phasenspektrum nach Gln. (1.16) bestimmt werden. Hierbei stellt k die diskretisierten Abtastzeitpunkte dar, N die Anzahl der Abtastwerte je Periode der Grundfrequenz und n die gerade betrachtete Frequenz. Sie sind somit die diskreten Gegenstücke zu den zeitkontinuierlichen Größen t, T und Ȧ. Insgesamt erfordert die Frequenzanalyse eines abgetasteten Signals mit Hilfe der vorgestellten reellen DFT nur einen vergleichsweise geringen Implementierungsaufwand und eignet sich damit ganz hervorragend für eigene experimentelle Untersuchungen. class Spektrum { const int Abtastwerte = 128; const double PI = 3.141592653589793; // Signalverlauf public double[] x = new double[Abtastwerte]; // Realteil und Imaginärteil public double[] Re = new double[Abtastwerte]; public double[] Im = new double[Abtastwerte]; // Amplitudenspektrum und Phasenspektrum public double[] AS = new double[Abtastwerte]; public double[] PS = new double[Abtastwerte];
8
1 Digitale Signalverarbeitung ... public void DFT() { // über alle Frequenzen for (int f=0; f
}
Die Korrektur des Gleichanteils wird vorgenommen, da in der Regel a0 nicht nach Gln. (1.5) berechnet wird, sondern nach Gln. (1.13). Man kann bei der Implementierung aber auch auf die Korrektur verzichten. In der Praxis kommt das sogar relativ häufig vor, wohlwissend, daß die Spektrallinie AS[0] dann dem doppelten Gleichanteil des Signals entspricht. In den meisten Fällen ist es völlig ausreichend, sich bei der Darstellung des Signalspektrums auf das Amplitudenspektrum zu beschränken. Es ist für jeden Signalabschnitt identisch und dadurch von eventuellen zeitlichen Verschiebungen des periodischen Signals unabhängig. Ganz anders sieht das aber beim Phasenspektrum aus, das sich aus dem Quotienten von Imaginärteil und Realteil berechnet. Wie man leicht nachvollziehen kann, ist das Phasenspektrum sehr wohl abhängig von dem gewählten zeitlichen Bezugspunkt. Aus diesem Grund ist es sehr viel weniger aussagekräftig und trägt nicht selten sogar eher zur Verwirrung bei. In den folgenden Beispielen betrachten wir daher ausschließlich das Amplitudenspektrum. Sollte es die Aufgabenstellung erfordern den zeitlichen Verlauf eines Signals aus einem vorgegebenen Spektrum zu bestimmen, ist das ebenfalls
1.3 Die Diskrete Fourier-Transformation (DFT)
9
leicht möglich und vollzieht sich in zwei Schritten. Aus dem Amplitudenspektrum ist zwar sofort erkennbar, wie stark die einzelnen Frequenzen vertreten sind, es ist aber zunächst nicht klar, ob diese als Sinus- oder als Cosinusanteil in den Signalverlauf eingehen. Wie schon bei der Signalanalyse, sind daher durch Korrelation mit den trigonometrischen Aufbaufunktionen der Realteil und der Imaginärteil des Spektrums zu ermitteln. Mit dessen orthogonalen Komponenten als Gewichtsfaktoren gelingt dann die Synthese des zeitlichen Verlaufs. Eine erste Implementierungsvariante der inversen DFT (IDFT) zeigt das folgende Code-Beispiel. class Spektrum { ... public void InverseDFT_Variante1() { // über alle Frequenzen for (int f=0; f
Wie schon bei der DFT sind auch bei der IDFT zwei geschachtelte Schleifen für die Transformation notwendig. Die Berechnung der orthogonalen Spektralkomponenten erfolgt zunächst in der äußeren Schleife, die Synthese des zeitlichen Verlaufs läuft dann in der inneren Schleife ab. Ähnlich wie bei einer mathematischen Formel kann man aber auch zweckmäßig umformen. In unserer zweiten Implementierung vereinfacht sich dadurch die Synthese zur simplen Addition.
10
1 Digitale Signalverarbeitung
class Spektrum { ... public void InverseDFT_Variante2() { for (int k=0; k
Diese zweite Variante der IDFT ähnelt der DFT doch sehr auffällig. Das ist natürlich kein Zufall, sondern liegt in der schlichten Tatsache begründet, daß die Hin- bzw. Rücktransformation einander sehr ähnlich sind. Allgemein läßt sich das an den Gleichungen (1.10) und (1.12) erkennen, speziell für die Fourier-Transformation an den Gleichungen (1.8) und (1.9). Diskretisiert man hier die Analysegleichung indem man das Integral durch die Summe ersetzt, unterscheiden sich Hin- bzw. Rücktransformation nur durch eine Normierung und verschiedene Vorzeichen in der komplexen Exponentialfunktion. Eine komplexe Exponentialfunktion ist aber nichts weiter als ein Drehzeiger in der komplexen Zahlenebene, wobei das Vorzeichen die Drehrichtung angibt. Ein Wechsel des Vorzeichen ist hier etwa vergleichbar mit der Summation von links nach rechts, oder umgekehrt. Das Ergebnis ist in jedem Fall genau dasselbe. Somit sind auch die Implementierung der DFT und der IDFT im Kern identisch. In Anwendungen, in denen tatsächlich auch beide Transformationen benötigt werden, sind diese dann üblicherweise in einer einzigen Funktion realisiert. Ein zusätzlicher Parameter beim Funktionsaufruf dient zur Unterscheidung. Aus optischen Gründen ist es dann zweckmäßig anstelle von x[] und XS[] neutrale Bezeichner wie data1[] und data2[] zu verwenden. In keinem Fall darf man jedoch vergessen, daß die Ergebnisse im Frequenz- bzw. Zeitbereich entsprechend unterschiedlich skaliert sind.
1.4 Arithmetiktuning – Die FFT
11
1.4 Arithmetiktuning – Die FFT Das Frequenzspektrum einer Folge von Abtastwerten zu berechnen, ist jetzt kein Problem mehr. Mit Hilfe der DFT können wir auf die erweiterten Möglichkeiten einer Meßwertanalyse im Frequenzbereich zurückgreifen. Doch wieviel Rechenzeit darf eine solche Analyse in Anspruch nehmen? Oft ist die DFT nur ein Glied in einer ganzen Kette von Verarbeitungsschritten. Bei zeitkritischen Anwendungen, wie z. B. der Sprachsignalverarbeitung, kommt es dann schon darauf an, den Rechenzeitbedarf insgesamt möglichst gering zu halten. Erfahrungsgemäß ist das Einsparpotential gerade dort am größten, wo auch die meiste Rechenzeit verbraucht wird. Tatsächlich ist der Rechenzeitbedarf in vielen Anwendungen der digitalen Signalverarbeitung ein latentes Problem, dem man grundsätzlich auf zwei Arten begegnen kann. Einerseits durch Optimierung der verwendeten Algorithmen, als Softwareentwickler können wir hier unmittelbar Einfluß nehmen, andererseits durch die Verwendung einer entsprechend leistungsstarken Hardwarebasis, wobei jedoch der Kostenrahmen des Projektes meist enge Grenzen setzt. Es liegt in der Natur der Sache, daß beide Ansätze das Problem immer nur kurzzeitig entschärfen, aber nicht wirklich dauerhaft lösen können, da sich mit den dann zusätzlichen Möglichkeiten auch immer komplexere Aufgabenstellungen finden, die diesen Freiraum schnell wieder aufzehren. Somit bleibt die Rechenzeitproblematik mit großer Sicherheit auch zukünftig bestehen und jeder Entwickler ist gut beraten, dies in seinem Projekt möglichst frühzeitig zu berücksichtigen. Viele Wege führen nach Rom. Und wahrscheinlich gibt es genauso viele Berechnungsvarianten für die DFT einer Abtastfolge. Eine Variante, die sogenannte Fast-Fourier-Transformation (FFT), hat sich jedoch einen ganz besonderen Stellenwert innerhalb der digitalen Signalverarbeitung erobert. Sie gehört ohne Zweifel zur „Königsklasse“ der Signalverarbeitungsalgorithmen und ist wohl auch einer ihrer kompliziertesten Vertreter. Hiervon sollte man sich aber nicht weiter beeindrucken lassen. Im Grunde ist alles doch ganz einfach. Wie wir zuvor gesehen haben, sind für die Berechnung einer DFT mit N Abtastwerten N·N = N2 komplexe Multiplikationen notwendig. Man kann sich leicht vorstellen, daß eine solche quadratische Abhängigkeit in Anwendungen mit großen Abtastraten Probleme schafft. In solchen Fällen hat sich das Prinzip Teile-und-Herrsche (divide-and-conquer) bewährt. Eine aufwendige Berechnung wird in viele kleine Teilberechnungen zerlegt und deren Teilergebnisse anschließend zu einem Gesamtergebnis zusammengeführt. Das sich dieses Vorgehen auch für eine schnellere Berechnung der DFT eignet, wurde schon frühzeitig erkannt, lange bevor es überhaupt
12
1 Digitale Signalverarbeitung
Computer gab. Aber erst die elektronische Rechentechnik hat dieser Idee zum Durchbruch verholfen. Heute werden insbesondere die Arbeiten von Danielson und Lanczos aus dem Jahre 1942, sowie von Cooley und Tukey aus dem Jahre 1965 als Wiederentdeckung der FFT gesehen. Um das Teile-und-Herrsche-Prinzip zu verdeutlichen betrachten wir zunächst die diskrete Fouriertransformation. Diese läßt sich durch Zerlegung in gerade und ungerade Abtastwerte wie folgt umschreiben: N −1
X n = ¦ x (k ) ⋅ e
−
j 2π nk N
k =0
Xn =
N / 2 −1
¦
x( 2k ) ⋅ e
−
j 2π n ( 2 k ) N
k =0
Xn =
¦
x(2k + 1) ⋅ e
−
j 2π n ( 2 k +1) N
k =0
N / 2 −1
¦
+
N / 2 −1
x( 2k ) ⋅ e
−
j 2π nk N /2
k =0
j 2π nk − § N / 2−1 + ¨¨ ¦ x(2k + 1) ⋅ e N / 2 © k =0
· − j 2Nπ n ¸⋅e ¸ ¹
Eine DFT der Länge N kann also auch aus zwei DFTs der halben Länge berechnet werden, wenn man sie anschließend phasenrichtig addiert. Was das bringt liegt auf der Hand. Anstelle einer N2 Berechnung hat man es nur noch mit 2·(N/2)·(N/2) = N2/2 Multiplikationen zu tun, was den Aufwand glatt halbiert. Aber es kommt noch besser. Dieses Vorgehen läßt sich rekursiv fortführen, solange die verbleibenden Teilintervalle durch Zwei teilbar sind. Theoretisch könnte man so weitermachen, bis man N DFTs aus N Einzelwerten zu berechnen hat. Das Ergebnis wäre dann der jeweilige Wert selbst. In der Praxis hat es sich aber durchgesetzt zwei Abtastwerte für eine Minimal-DFT zu verwenden. So eine Minimal-DFT wird dann als Butterfly bezeichnet. Natürlich ändert sich durch die fortlaufende Zerlegung in gerade und ungerade Teilfolgen auch die Reihenfolge unserer ursprünglich zeitlich geordneten Abtastwerte. Die Indizes sind nicht mehr aufsteigend sortiert, sondern werden nach einem neuen Schema umgruppiert, wie das nachstehende Beispiel mit N = 8 Abtastwerten zeigt. x(0)
x(1)
x(2)
x(3)
x(4)
x(5)
x(6)
x(7)
x(5)
x(7)
Ļ X(0)
x(2)
x(4)
x(6)
x(1)
x(3)
Ļ X(0) x(4)
x(2)
x(6)
x(1)
x(5)
x(3)
x(7)
1.4 Arithmetiktuning – Die FFT
13
Der erste Schritt zerlegt die acht Abtastwerte in zwei Teilfolgen mit jeweils vier Werten. In einem zweiten Schritt werden diese nun ihrerseits zerlegt und wir erhalten insgesamt vier Teilfolgen, bestehend aus je zwei Werten. Dieser Vorgang ist an sich nicht weiter kompliziert. Sehr viel schwieriger ist es allerdings die Gesetzmäßigkeit hinter der resultierenden Neuordnung zu erkennen, zumindest solange wir die Indizes ausschließlich als Dezimalzahlen betrachten. Im Dualsystem dagegen offenbart sich das Muster sehr schnell. Der Index 1 (binär 001) wird mit dem Index 4 (binär 100) getauscht, der Index 3 (binär 011) mit der 6 (binär 110), usw., was gerade einer Bit-Umkehr (bit reversal) entspricht. 0 1 2 3 4 5 6 7
= = = = = = = =
(000) (001) (010) (011) (100) (101) (110) (111)
ĺ ĺ ĺ ĺ ĺ ĺ ĺ ĺ
(000) (100) (010) (110) (001) (101) (011) (111)
= = = = = = = =
0 4 2 6 1 5 3 7
Mit Hilfe der Bit-Umkehr ist es also möglich, die oben beschriebene Zerlegung in gerade und ungerade Teilfolgen nicht explizit durchführen zu müssen, aber dennoch auf identisch angeordnete Abtastwerte zugreifen zu können. Wir erinnern uns, der ursprüngliche Sinn der Zerlegung war es, mehrere Teil-DFTs zu berechnen und diese dann zum richtigen Gesamtergebnis zusammenzuführen, um Aufwand zu sparen. Die Zusammenführung ist aber gerade die Umkehrung der oben vorgenommenen Zerlegung. Hierbei sind zuerst vier 2-Punkte DFTs aus den Paaren x(0) und x(4), x(2) und x(6), x(1) und x(5) und schließlich x(3) und x(7) zu bilden. Als Ergebnis erhalten wir vier 2-Punkte Spektren, die nun ihrerseits als Eingangswerte für zwei 4-Punkte DFTs dienen. Die beiden resultierenden 4-Punkte Spektren werden abschließend noch einer 8-Punkte DFT unterzogen, und schon haben wir unser Endergebnis. Zugegeben, die Interpretation der Zwischenergebnisse als Spektren ist ein wenig problematisch, schaut man aber auf den Berechnungsaufwand, dann ist das Ergebnis beeindruckend. Für unsere N = 8 Abtastwerte sind demnach nur noch 4·2 + 2·4 + 1·8 = 24 komplexe Multiplikationen nötig, was doch ein ganz ordentliches Stück besser ist als die 64 bei der DFT. Allgemein sind mit dem hier vorgestellten FFT-Algorithmus N·log2(N) Schritte erforderlich, gegenüber N2 Schritte bei der normalen DFT. Neben der Zerlegung bzw. Neuordnung der Abtastwerte ist die phasenrichtige Addition bei den Teil-DFTs die entscheidende Hürde zum Erfolg.
14
1 Digitale Signalverarbeitung
Wir wollen diese daher näher betrachten. In unserer nach geraden und ungeraden Abtastwerten zerlegten Beispielberechnung der DFT taucht ein zusätzlicher Faktor auf, der, abgesehen von der aktuellen Frequenz f, nur von der Anzahl der Abtastwerte N abhängt. Eine solche komplexe Exponentialfunktion bildet einen Drehzeiger (twiddle faktor) in der komplexen Zahlenebene. Genau dieser Zeiger ist das fehlende Glied, das für die Phasenkorrektur unserer Teil-DFT verantwortlich ist.
wN = e
−
j 2πf
(1.17)
N
Im 2
3
W8
W8
1
W8
4
0
W 8 Re
W8
5
W8
7
6
W8
W8 Abb. 1.3. Drehzeiger für N = 8
Die Zeiger liegen symmetrisch auf dem Einheitskreis (r = 1) und bilden die N Einheitswurzeln. Für die Implementierung wird es etwas einfacher, wenn man Gln. (1.17) unter Verwendung der trigonometrischen Funktionen umschreibt, wobei der Index k alle Zeiger von 0 bis N −1 durchläuft:
§ 2π k · § 2π k · wNk = cos¨ ¸ + j sin ¨ ¸ © N ¹ © N ¹
(1.18)
In dieser Form lassen sich Real- und Imaginärteil des Drehzeigers direkt berechnen. Nutzt man seine Symmetrieeigenschaft, kann man zusätzlich Berechnungsaufwand sparen.
w84 = − w80 w85 = − w81
1.4 Arithmetiktuning – Die FFT
15
w86 = − w82 w87 = − w83 Die Neuordnung der Abtastwerte und der eingeführte Drehzeiger ermöglichen schließlich das effektive Berechnungsschema der FFT. x(0)
A(0) w 02
x(4)
w 04
A(1)
w 12 w 14
x(2) w 02 x(6)
w 08
w 12
w 18 A(2)
w 24 w 28
A(3)
w 34 w 38
x(1) w 02 x(5)
w 48
A(4)
w 04
w 12
w 58
A(5)
w 14 x(3) w 02 x(7)
w 12
w 24
w 68
w 34
w 78
Abb. 1.4. Berechnungsschema für eine FFT mit 8 Abtastwerten
A(6)
A(7)
16
1 Digitale Signalverarbeitung
Bei acht Abtastwerten vollzieht sich die Berechnung in drei Stufen. Die Zusammenführung der Pfeile stellt eine Addition dar, ein beistehender Drehzeiger bedeutet eine Multiplikation mit dem entsprechenden Wert. Verständlicher wird es, wenn man einen einzelnen Butterfly betrachtet. x(0) + w 02 x(4)
x(0) w 02 x(4)
w 12
x(0) + w 12 x(4)
Abb. 1.5. Berechnungsschema eines einzelnen Butterfly
Für das Arbeiten mit komplexen Zahlen benötigt man noch einen entsprechenden Datentyp. Die Berechnungen selbst erfolgen dann jeweils getrennt nach Realteil und Imaginärteil. struct komplex { public double re; public double im; }
Echte Meßwerte aus realen Prozessen sind immer reellwertig. In der Regel werden sie auch als solche gespeichert und weiterverarbeitet (üblicherweise noch mit Zeitstempel, physikalischer Einheit, usw.). Für die FFT ist daher die vorherige Umwandlung in komplexe Daten erforderlich. Auch wenn man bis zu diesem Punkt alles verstanden hat, die wohl größte Schwierigkeit bei der Implementierung liegt ohne Zweifel darin, das Berechnungsschema der FFT über eine geeignete Indizierung tatsächlich umzusetzen. Hierzu führen wir drei Hilfsvariablen ein. Die Variable stufen bezeichnet die Anzahl der Berechnungsebenen im Schema und ergibt sich aus dem dualen Logarithmus der Zahl der Abtastwerte (8 = 23 ĺ drei Stufen). Mit sprung wird die notwendige Inkrementierung des Indexes bezeichnet, um vom ersten Zweig des Butterflys zum zweiten Zweig zu gelangen (= 4 in der ersten Ebene: 0 ĺ 4, 2 ĺ 6, 1 ĺ 5 und 3 ĺ 7). Die Variable schritt stellt das notwendige Inkrement dar, um vom ersten Zweig eines Butterflys zum ersten Zweig des nächsten Butterflys zu springen (= 2 in der ersten Ebene: 0 ĺ 2 und 1 ĺ 3).
1.4 Arithmetiktuning – Die FFT
class Spektrum { ... // komplexe Daten public komplex[] data = new komplex[Abtastwerte]; public void FFT() { double tempr = 0; double tempi = 0; double wreal = 0; double wimag = 0; double real1 = 0; double imag1 = 0; double real2 = 0; double imag2 = 0; int i = 0; int j = 0; int k = 0; int stufen = 0; int sprung = 0; int schritt = 0; int element = 0;
// // // // // // // //
für Tausch bei Bit-Umkehr für Tausch bei Bit-Umkehr Drehfaktor (Realteil) Drehfaktor (Imaginärteil) Hilfsvariable Hilfsvariable Hilfsvariable Hilfsvariable
// Bit-Umkehr for (j=0; j
17
18
1 Digitale Signalverarbeitung stufen = (int)(Math.Log10((double)Abtastwerte)/ Math.Log10((double)2)); sprung = 2; for (i=0; i<stufen; i++) { // jede Iterationsstufe startet mit dem 1. Wert element = 0; for (j=Abtastwerte/sprung; j>=1; j--) { schritt = sprung/2; for (k=0; k<schritt; k++) { // 1. Zweig des Butterfly wreal = Math.Cos(k*2.0*PI/sprung); wimag = Math.Sin(k*2.0*PI/sprung); real1 = data[element+k].re + (wreal*data[element+k+schritt].re – wimag*data[element+k+schritt].im); imag1 = data[element+k].im + (wreal*data[element+k+schritt].im + wimag*data[element+k+schritt].re); // 2. Zweig des Butterfly wreal *= -1.0; wimag *= -1.0; real2 = data[element+k].re +
(wreal*data[element+k+schritt].re – wimag*data[element+k+schritt].im); imag2 = data[element+k].im + (wreal*data[element+k+schritt].im + wimag*data[element+k+schritt].re); // Ergebnisse übernehemen data[element+k].re = real1; data[element+k].im = imag1; data[element+k+schritt].re = real2; data[element+k+schritt].im = imag2; } element += sprung; } sprung *= 2;
1.4 Arithmetiktuning – Die FFT
19
} } ... }
Wie schon bei der DFT unterscheidet sich die inverse FFT (IFFT) von der FFT lediglich durch eine andere Normierung, bzw. Skalierung des Ergebnisses. Unser ursprüngliches Anliegen war es, Rechenzeit zu sparen. Geht man allein nach der Anzahl der benötigten Programmzeilen, dann scheinen wir von diesem Ziel weiter entfernt als zuvor. Aber wer wird sich schon von Äußerlichkeiten blenden lassen, was zählt sind schließlich die inneren Werte. Führt man sich vor Augen, wie viele komplexe Multiplikationen bei DFT bzw. FFT auszuführen sind, wird schnell klar, welches Verfahren die Nase vorn hat. Ob sich die Einsparung an Rechenoperationen bei der FFT auch im gleichen Maße im Rechenzeitbedarf niederschlägt, läßt sich gut mit Hilfe eines Benchmark-Tests überprüfen. Hierbei wird die Ausführungszeit der Algorithmen miteinander verglichen. Um den relativen Fehler klein zu halten, wird pro Zeitmessung immer eine größere Anzahl von Durchläufen (z. B. 1000) ausgeführt. Wegen der Verwendung eines eigenen Datentyps, wurde bei der FFT die Zuweisung der Meßwerte mit in die Testschleife einbezogen. Genau genommen müßte man noch deren Leerlaufzeit abziehen, diese ist hier aber vernachlässigbar. Tabelle 1.2. Anzahl der komplexen Multiplikationen bei DFT und FFT N
2 4 8 16 32 64 128 256 512 1024
DFT
4 16 64 256 1024 4096 16384 65536 262144 1048576
class Spektrum { ... public void Benchmark() {
FFT
2 8 24 64 160 384 896 2048 4608 10240
20
1 Digitale Signalverarbeitung const int testzyklen = 1000; DateTime start; DateTime stop; Console.WriteLine("Benchmark DFT startet jetzt!"); start = DateTime.Now; for (int j=0; j
} ... }
Natürlich sind die gemessenen Zeiten in erster Linie von der Leistungsfähigkeit des ausführenden Computers abhängig. Eine normierte Darstellung der Werte ist in solchen Fällen hilfreich.
21
1.4 Arithmetiktuning – Die FFT Tabelle 1.3. Gemessener Zeitbedarf von DFT und FFT (normiert) N
DFT
FFT
1,3 5,7 24 94 355 1425 5703 22972 92551 371194
1 2,6 7 18 44 103 242 528 1111 2778
1200000
400000
900000
300000
t/T
M(N)
2 4 8 16 32 64 128 256 512 1024
600000
200000
100000
300000
0
0 2
4
8
16
32
64
N
128
256
512
1024
2
4
8
16
32
64
128
256
512
1024
N
Abb. 1.6. Vergleich theoretischer und gemessener Zeitbedarf von DFT und FFT
Abbildung 1.6 zeigt die gute Übereinstimmung von Theorie und Praxis beim Rechenzeitbedarf beider Verfahren. Die Kurve für die FFT schmiegt sich so dicht an die x-Achse an, daß sie kaum sichtbar wird. Für kleine Abtastraten ist der Unterschied weit weniger dramatisch. Tatsächlich gibt es dort für die DFT noch erhebliches Einsparpotential, z. B. indem man die zeitaufwendigen trigonometrischen Funktionsaufrufe für alle k direkt durch ihren jeweiligen Wert ersetzt. Für höhere Abtastraten ist das aber kaum praktikabel, so daß sich die FFT etwa für N > 16 lohnt. Vom Ansatz her produzieren DFT und FFT identische Ergebnisse. Die DFT berechnet die Frequenztransformierte einer diskreten Abtastfolge und genau das gleiche macht auch die FFT. Eigentlich ist sie ja auch nur eine (deutlich effizientere) Berechnungsvariante der DFT. Hierbei könnte man es belassen, wenn da nicht die Zahlendarstellung im Computer mit ihrem begrenzten Auflösungsvermögen wäre. Da es nicht möglich ist alle reellen Zahlenwerte in einem Rechner exakt abzubilden, geht jeder Berechnungsschritt mit einem gewissen Verlust an Präzision einher. Das Ergebnis der FFT ist aus diesem Grund zumindest theoretisch näher am „wahren Wert“, da sich mit der geringeren Anzahl von Berechnungen auch weniger Rundungsfehler aufsummieren. In der Praxis dürfte sich dieser Unterschied allerdings kaum bemerkbar machen. Wer es genauer wissen möchte, kann
22
1 Digitale Signalverarbeitung
das durch eine große Anzahl von hintereinander ausgeführten Hin- und Rücktransformationen selbst austesten (ähnlich dem Qualitätstest von Fotokopierern, wo man eine Kopie von einer Kopie von einer Kopie...).
1.5 Pulse und Pulsfolgen Um das bisher Erarbeitete auch praktisch anwenden zu können, bedarf es natürlich noch einiger Testsignale. Da echte Signale aus realen technischen Prozessen leider nicht immer zur Verfügung stehen, liegt es nahe, eigene Signalfolgen zu erstellen und diese synthetischen Daten als Basis für die weiteren Untersuchungen zu verwenden. Dabei ist es zunächst einmal egal, ob tatsächlich eine periodische Funktion vorliegt, oder ob ein Signal betrachtet wird, von dem wir lediglich annehmen, daß es periodisch ist. Natürlich könnte man einfach unter Verwendung von Gln. (1.4) ein Signal nach einer Fourier-Reihe entwickeln und anschließend mittels DFT untersuchen. Als Ergebnis bekäme man dann jedoch nur genau das heraus, was man selbst zuvor hineingesteckt hat. Von einem großen Erkenntnisgewinn kann da nun wirklich nicht die Rede sein. In der Signalverarbeitung bilden Pulse und Pulsfolgen eine besondere Klasse von Signalen, weshalb es sich lohnt, sich näher mit ihnen zu befassen. Sie haben zudem den großen Vorteil, daß sie sich softwaretechnisch sehr leicht erzeugen lassen, einige wenige Zeilen genügen. class Spektrum { ... public void ErzeugeTestsignal_1() { for (int k=0; k
Als Ergebnis erhält man den oben dargestellten Rechteckimpuls von 1/16-Periodendauer Länge. Schaut man sich anschließend das berechnete
1.5 Pulse und Pulsfolgen
23
1,2 1
x(k)
0,8 0,6 0,4 0,2 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
Abb. 1.7. Rechteckimpuls von 1/16 Länge
Amplitudenspektrum an, ist man vielleicht überrascht, welche Frequenzkomponenten schon in so einem einfachen Impuls enthalten sind. Im Allgemeinen sind deren Anteile allein durch Betrachtung des zeitlichen Signalverlaufs kaum zu erahnen. Eine Ausnahme bildet hier der Gleichanteil. Weiterhin fällt sofort die Spiegelung des Spektrums an der Stelle N/2 auf. Offensichtlich genügt es für eine reelle DFT nur N/2 + 1 Spektrallinien zu berechnen, also die Frequenz von 0..N/2 laufen zu lassen. Die Frequenz f = 0 entspricht dabei dem Gleichanteil des Signals, die Frequenz f = 1 stellt die Grundschwingung dar, die höheren Frequenzen bezeichnet man als Harmonische. Sie sind ganzzahlige Vielfache der Grundfrequenz. Natürlich bietet es sich an, die gespiegelten Frequenzen gleich ganz wegzulassen, um den Berechnungsaufwand weiter zu verringern. Zumal hiermit auch kein Informationsverlust einhergeht. In den weiteren Beispielen werden daher nur noch N/2 + 1 Spektrallinien berechnet und dargestellt. 0,14 0,12
|X(f)|
0,1 0,08 0,06 0,04 0,02 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
f
Abb. 1.8 . Amplitudenspektrum des Rechteckimpulses
24
1 Digitale Signalverarbeitung Tabelle 1.4. Amplitudenspektren verschiedener Pulsweiten Spektralbereich | X(f)| mit f = 0..64
Zeitbereich x(k) mit k = 0..127 1,2
1
1
0,8
0,8
|X(f)|
x(k)
1,2
0,6
0,6
0,4
0,4
0,2
0,2
0
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
0
8
16
24
k
32
40
48
56
64
40
48
56
64
40
48
56
64
40
48
56
64
f
1/1 Puls 1,2
0,7
1
0,6 0,5
|X(f)|
x(k)
0,8 0,6
0,4 0,3
0,4
0,2 0,2
0,1
0
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
0
8
16
24
k
32
f
1/2 Puls 1,2
0,5
1
0,4
|X(f)|
x(k)
0,8 0,6
0,3 0,2
0,4 0,1
0,2 0
0 0
8
0
16 24 32 40 48 56 64 72 80 88 96 104 112 120
8
16
24
k
32
f
1/4 Puls 1,2
0,3
1
0,25 0,2
|X(f)|
x(k)
0,8 0,6
0,15
0,4
0,1
0,2
0,05
0
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
1/8 Puls
0
8
16
24
32
f
25
1.5 Pulse und Pulsfolgen
1,2
0,14
1
0,12 0,1
|X(f)|
x(k)
0,8 0,6
0,08 0,06
0,4
0,04
0,2
0,02 0
0 0
8
0
16 24 32 40 48 56 64 72 80 88 96 104 112 120
8
16
24
32
40
48
56
64
f
k
1/16 Puls 1,2
0,07
1
0,06 0,05
|X(f)|
x(k)
0,8 0,6 0,4
0,04 0,03 0,02
0,2
0,01
0
0 0
8
0
16 24 32 40 48 56 64 72 80 88 96 104 112 120
8
16
24
k
32
40
48
56
64
40
48
56
64
40
48
56
64
f
1/32 Puls 0,035
1,2
0,03
1
0,025
|X(f)|
x(k)
0,8 0,6 0,4
0,02 0,015 0,01
0,2
0,005
0
0 0
8
0
16 24 32 40 48 56 64 72 80 88 96 104 112 120
8
16
24
k
32
f
1/64 Puls 0,018
1,2
0,016
1
0,014 0,012
|X(f)|
x(k)
0,8 0,6
0,01 0,008 0,006
0,4
0,004
0,2
0,002
0
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
0
8
16
24
32
f
1/128 Puls
Eine wichtige Erkenntnis, die aus den Amplitudenspektren dieser Pulssignale ersichtlich wird, ist die zunehmende Ausdehnung der Hülle der Frequenzamplituden bei Abnahme der relativen Pulsweite. Gleichzeitig wird
26
1 Digitale Signalverarbeitung
das Spektrum deutlich flacher mit immer kleineren Amplituden für alle Harmonischen (beachte Skalierung), weil ein schmalerer Puls auch weniger Energie besitzt. Im Grenzfall einer gegen Null strebenden Pulsdauer besitzen alle Harmonischen die gleichen Amplituden, die aber sehr klein werden und damit ebenfalls gegen Null streben. Würde im Gegenzug die Größe der Pulse entsprechend der Verringerung der Pulsdauer erhöht, so daß das Produkt aus Pulsdauer und Pulshöhe konstant bleibt (¨IJ·h = const), dann bleiben auch die Amplituden der Harmonischen konstant. Die Aufweitung des Frequenzbereiches beschränkt sich nun keineswegs nur auf Pulse, sondern gilt allgemein für zeitlich stark lokalisierte Signalanteile (z. B. steile Flanken) und läßt sich leicht interpretieren. Ursache hierfür sind die zeitlich unendlich ausgedehnten trigonometrischen Aufbaufunktionen. Sie ermöglichen die Signaldarstellung durch gegenseitige Verstärkung und Auslöschung, also durch konstruktive und destruktive Interferenz. Bei sehr scharfen zeitlichen Lokalisationen sind aber auch sehr hochfrequente Aufbaufunktionen notwendig, was schließlich zu der dargestellten spektralen Aufspreizung entlang der Frequenzachse führt. Wie am Beispiel eines immer schmaler werdenden Impulses gezeigt werden konnte, entartet das Signalspektrum auf diese Weise sogar zu einer Konstanten.
1.6 Der Abtastvorgang Bei den zuvor eingeführten Impulsen führt eine Grenzwertbetrachtung der Pulsdauer mit ¨IJĺ0 (bei gleichzeitig konstanter Impulsfläche) zur į-Funktion, die in der Literatur als Delta-Impuls oder Dirac-Impuls bekannt ist. Auf eine exakte mathematische Herleitung soll an dieser Stelle verzichtet werden. Der Delta-Impuls zeichnet sich durch die folgenden Eigenschaften aus:
1 (t = 0) ¯0 (t ≠ 0)
δ (t ) = ®
(1.19)
∞
³ δ (t )dt = 1
(1.20)
−∞ ∞
³ δ (t ) ⋅ x(t ) dt = x(0)
(1.21)
−∞
Eine besondere Bedeutung kommt vor allem der letzten Gleichung zu, welche die sogenannte Ausblendeigenschaft des Delta-Impulses beschreibt. Dank dieser Eigenschaft ist es leicht möglich, den Wert zeitkontinuierli-
1.6 Der Abtastvorgang
27
cher Funktionen zu beliebigen Zeitpunkten zu erfassen. Macht man das in regelmäßigen Abständen, erhält man im Ergebnis eine Folge verschobener Impulse, deren jeweilige Höhe gleich dem entsprechenden Funktionswert von x(t) ist (siehe auch Abb. 1.9). ∞
x(k ) = ¦ δ (t − k ⋅ Δt ) ⋅ x(t )
(1.22)
k =0
x(t)
x(k) X
(t)
Abb. 1.9. Abtastung einer zeitkontinuierlichen Funktion
Die meßtechnische Erfassung einer Zeitfunktion wird Abtastung genannt. Hierbei werden dem zeitkontinuierlichen Funktionsverlauf in üblicherweise festen zeitlichen Abständen Werte entnommen, welche in ihrer Gesamtheit die zeitdiskrete Abtastfolge bilden. Die periodische Fortsetzung von į(t) bezeichnet man als Kammfunktion ɒ(t) oder auch als DeltaKamm. Aus der Funktion x(t) wird somit durch Multiplikation mit einem solchen Delta-Kamm die abgetastete Funktion x(k). Streng genommen werden deren Werte bis zum nächsten Abtastzeitpunkt als konstant angenommen, weshalb man in diesem Fall auch von einem Haltevorgang nullter Ordnung spricht (bei einem Halteglied erster Ordnung sind die Abtastwerte durch Geraden verbunden, bei einem Halteglied zweiter Ordnung durch Parabeln, usw.). Am Ausgang eines AnalogDigital-Umsetzers (ADU), der die technische Realisierung eines solchen Abtast- und Haltegliedes darstellt, liegt tatsächlich also eine Treppenfunktion vor. Obwohl mathematisch sehr leicht möglich, tritt die Aufspaltung von Abtastvorgang und Haltevorgang in existierenden technischen Systemen meist jedoch nicht explizit in Erscheinung. Gleichwohl sollte man sich bewußt sein, daß beide Vorgänge auf das resultierende Spektrum wirken. Wir wollen solche Überlegungen aber vernachlässigen und uns im
28
1 Digitale Signalverarbeitung
weiteren Verlauf nur mit reinen Abtastfolgen (ohne Haltevorgang) beschäftigen. Das Spektrum einer Kammfunktion zeigt die nachfolgende Abbildung. 1,2
0,14
1
0,12 0,1
|X(f)|
x(k)
0,8 0,6 0,4
0,08 0,06 0,04
0,2
0,02 0
0 0
8
16 24 32
40 48 56 64 72 80 88 96 104 112 120
0
4
8
12 16 20 24 28 32 36 40 44 48 52 56 60 64
k
f
Abb. 1.10. Kammfunktion und ihr Spektrum
Interessanterweise ist das Spektrum einer Kammfunktion wiederum eine Kammfunktion, lediglich der Maßstab ändert sich. Je weiter die einzelnen Pulse im Zeitbereich auseinander liegen, desto näher rücken sie im Spektrum zusammen und umgekehrt. Dieser Umstand steht im Einklang mit den in Tabelle 1.4 dargestellten Impulsspektren, bei denen der erste Fall einem unendlich kleinen zeitlichen Abstand und der letzte Fall einem unendlich großen zeitlichen Abstand zwischen den einzelnen Pulsen entspricht. Wegen der speziellen Eigenschaften von ɒ(t) führt der Abtastvorgang eines Zeitsignals zu einer periodischen Fortsetzung seines Spektrums im Frequenzbereich. Da die Kammfunktion durch die Fouriertransformation wieder in sich selbst übergeht, bildet sie eine Eigenfunktion der Fouriertransformation. Eine Gemeinsamkeit, die sie mit der bekannten Gaußfunktion teilt. Den Haltevorgang zwischen zwei Abtastungen kann man sich am besten als Impuls vorstellen, dessen Höhe dem ersten Abtastwert entspricht und dessen Weite mit dem Abtastintervall (= Kehrwert der Abtastfrequenz fa) identisch ist. Folglich ist auch das resultierende Spektrum identisch mit den oben betrachteten Impulsspektren, abhängig von der Dauer des Haltevorgangs. Als Vorgriff auf spätere Abschnitte sei hier erwähnt, daß der Haltevorgang Tiefpaßeigenschaften besitzt. Sein Spektrum wird mathematisch durch eine Gleichung folgenden Typs beschrieben:
X ( f )=
sin(π f / f a ) π f / fa
(1.23)
Die Funktion sin(x)/x ist von grundlegender Bedeutung in der digitalen Signalverarbeitung, und auch weit darüber hinaus bekannt. In der Optik beschreibt sie die Intensitätsverteilung des Lichtes nach dem Durchtritt durch einen schmalen Spalt. Ihrem physikalischen Ursprung entsprechend
1.7 Das Abtasttheorem
29
wird sie daher Spaltfunktion genannt, manchmal auch sinc-Funktion oder einfach nur si-Funktion.
1.7 Das Abtasttheorem Obwohl der Umstand, daß die reelle DFT aus den N Abtastwerten eines Signals genau N/2 + 1 Spektrallinien bestimmt, auf den ersten Blick beinahe nebensächlich erscheint, ist er für die digitale Signalverarbeitung von fundamentaler Bedeutung. Es leuchtet unmittelbar ein, je höher die Abtastrate (d. h. die Zahl der Abtastwerte je Periode) für eine Messung gewählt wird, desto mehr Details des Signals werden auch erfaßt. Dieser eigentlich doch selbstverständliche Zusammenhang kann nun aufgrund der oben gewonnenen Erkenntnisse genauer formuliert werden. Ein abgetastetes Signal enthält demnach nur Frequenzen bis zur halben Abtastfrequenz. 1 ⋅ Abtastfrequenz 2 Abtastfrequenz ≥ 2 ⋅ höchste Signalfrequenz
höchste Signalfrequenz ≤
(1.24)
Im Umkehrschluß ergibt sich damit, daß die Abtastfrequenz bei der Meßwerterfassung mindestens doppelt so hoch gewählt werden muß, wie die höchste Signalfrequenz. Diese Bedingung ist heute ganz allgemein als Abtasttheorem bekannt und wurde 1948 von Claude Elwood Shannon (1916–2001) in seiner Arbeit „A Mathematical Theorie of Communication“ formuliert. Die höchste in einem Signal enthaltene Frequenz wird auch Nyquistfrequenz genannt. Wie bereits erwähnt, führt die Abtastung eines Signals zu einer periodischen Fortsetzung des Signalspektrums im Frequenzbereich, wobei der Abstand der einzelnen Spektren gerade durch die Abtastfrequenz gegeben ist. Wird diese nun zu klein gewählt (Unterabtastung), kommt es zu einer unerwünschten Überlappung der periodischen Signalspektren, was schließlich zu einer Signalverfälschung im Zeitbereich führt. Solche durch den Abtastvorgang selbst erzeugten Fehlfrequenzen nennt man Alias-Frequenzen, den Vorgang entsprechend Aliasing. Abbildung 1.11 verdeutlicht den Effekt. In solchen Fällen ist die ursprüngliche Information unwiederbringlich verloren und läßt sich auch nicht zurückgewinnen. Noch deutlicher wird das, wenn die Abtastfrequenz genau der Grundschwingung des abgetasteten Signals entspricht. Die Abtastfolge entartet dann zu einem konstanten Wert, abhängig von der Phasenlage des Abtastzyklus. Praktisch ist aber auch die Mindestabtastrate gemäß dem Abtasttheorem von Shannon nicht ausreichend, was an den nichtidealen Eigenschaften der digitalen Filter
30
1 Digitale Signalverarbeitung 1,5 1
x(t)
0,5 0 0,0
0,9
1,8
2,7
3,5
4,4
5,3
6,2
-0,5 -1 -1,5
t
Abb. 1.11. Scheinbarer zeitlicher Signalverlauf bei Unterabtastung
innerhalb der Signalverarbeitungskette liegt. Oft wählt man daher die tatsächliche Abtastfrequenz deutlich höher. Durch eine solche Überabtastung (oversampling) steigen dann natürlich auch die Anforderungen an die verwendete Hardware. In der Regel sind die in einem Signal enthaltenen Frequenzen vor der Messung nicht vollständig bekannt, was die Wahl einer geeigneten Abtastfrequenz natürlich erschwert. Wie soll man eine Frequenz messen, d. h. doppelt hoch abtasten, die man nicht einmal kennt? Dieses Dilemma läßt sich nur durch eine künstliche Begrenzung der Signalfrequenzen auf einen für die Messung interessanten Bereich lösen, mit Hilfe eines Anti-Alia– sing-Filters. Dessen Frequenz bestimmt dann die gewählte Abtastrate.
1.8 Leakage Obwohl nicht ausdrücklich erwähnt, wurde in den bisherigen Beispielen stets davon ausgegangen, daß der Abtastvorgang exakt auf die Periodizität des zu untersuchenden Signals abgestimmt ist. Dabei kann es in der Praxis durchaus vorkommen, daß das abgetastete periodische Signal nicht genau aus einer ganzen Anzahl von Zyklen besteht. Dies ist unmittelbar einzusehen, da ja die Frequenzanalyse eines Signals erst genauere Kenntnisse über dessen Periodendauer bzw. dessen Grundfrequenz erbringen soll. Im Ergebnis macht sich dieser Umstand als eine deutliche Abweichung vom idealen Spektrum bemerkbar und es treten bei der DFT Frequenzkomponenten auf, die im Signal eigentlich gar nicht enthalten sind. Man bezeichnet diese spektrale Spreizung als Leakage. Ein passendes Testsignal kann einfach erzeugt und mit der entsprechenden Harmonischen verglichen werden.
1.8 Leakage
31
class Spektrum { ... public void ErzeugeTestsignal_2() { for (int k = 0; k
1
1
0,5
0,8
|X(f)|
x(k)
1,5
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
0,6 0,4
-0,5
0,2
-1 0 0
-1,5
8
16
24
32
40
48
56
64
f
k
TAbtast/TSignal = 12 Abb. 1.12. Amplitudenspektrum bei ganzzahliger Zyklenzahl 1,2
1
1
0,5
0,8
|X(f)|
x(k)
1,5
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,5
0,6 0,4 0,2
-1
0 -1,5
0
k
8
16
24
32
40
48
56
64
f
TAbtast/TSignal = 11,4 Abb. 1.13. Leakage bei nicht ganzzahliger Zyklenzahl
Worin kann nun die Ursache für diesen Effekt gesehen werden? Sowohl die DFT als auch die FFT verarbeiten einen zeitlich endlichen Signalausschnitt für die Frequenzanalyse. Dessen Länge ergibt sich dabei durch das verwendete Zeitfenster von N Abtastwerten. Nach der Theorie sollte sich das unendlich fortgesetzte Zeitsignal genau dann ergeben, wenn man das betrachtete Zeitfenster mehrfach hintereinander reiht. Fällt eine ganze Zahl von Signalzyklen in das Zeitfenster, funktioniert das auch tatsächlich. Ist das jedoch nicht der Fall, entstehen an den Intervallgrenzen ungewollt
32
1 Digitale Signalverarbeitung
Signalsprünge, die es ursprünglich nicht gab. Sie sind verantwortlich für die entstehende spektrale Aufspreizung. Grundsätzlich ist bei der DFT die Zahl der Abtastwerte frei wählbar, wodurch sich Diskontinuitäten im Signalverlauf aufgrund der Fensterlänge vermeiden lassen. Vorausgesetzt man kennt die exakte Periodendauer, woher auch immer. Etwas anders sieht es bei der FFT aus, wo die Fensterlänge in der Regel eine Zweierpotenz ist. Hier müssen andere Methoden greifen, um diesen Effekt zu beseitigen oder wenigstens spürbar zu dämpfen. Da die Signalsprünge erst an den Rändern des Zeitfensters auftreten, liegt der Versuch nahe, an diesen Stellen durch geeignete Maßnahmen einen kontinuierlichen Signalverlauf zu erzwingen. Angenommen man drückt das Signal an beiden Enden langsam auf Null, unabhängig von seinem tatsächlichen Verlauf, so wären die Übergänge angepaßt und die Diskontinuität beseitigt. Am einfachsten läßt sich das erreichen, indem man das Zeitsignal zusätzlich mit einem entsprechend geformten Fenster multipliziert. Dieser Vorgang wird Fensterung genannt und verändert natürlich auch das Signalspektrum. Nicht vergessen darf man aber hierbei, daß dies selbstverständlich auch für das Rechteckfenster gilt, mit dem wir bisher immer eine Anzahl von Abtastwerten aus dem unendlich angenommenen Signalverlauf betrachtet haben. Doch hierzu später mehr. In der digitalen Signalverarbeitung sind im Laufe der Zeit eine ganze Reihe von Fensterfunktionen entwickelt worden, die auf unterschiedliche Randbedingungen hin optimiert sind. Ein typischer Vertreter ist das Hanning-Fenster (manchmal auch von-Hann-Fenster). Wir wollen mit M die gewählte Anzahl von Abtastwerten pro Signalperiode bezeichnen.
w(k ) = 0,5 − 0,5 ⋅ cos(
2π k ) M
(1.25)
1,5
1,2
1
0,8
x(k)
|X(f)|
1
0,5
0,6 0,4 0,2
0
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
0
8
16
24
32
40
48
56
64
f
Abb. 1.14. Das Hanning-Fenster und sein Linienspektrum
Die Multiplikation des Signals mit der neuen Fensterfunktion im Zeitbereich führt zu einer Faltung des Signalspektrums mit dem Spektrum des jeweils verwendeten Fensters im Frequenzbereich. Es ist üblich für die
1.9 Nichtstationäre Signale – Die Grenzen der DFT
33
Faltung, die im Abschnitt über digitale Filter noch näher erläutert wird, den symbolischen Rechenoperator * zu verwenden.
x(k ) ⋅ w(k ) ← ⎯→ X ( f ) ∗ W ( f ) 1,2
1
1
0,5
0,8
|X(f)|
x(k)
1,5
(1.26)
0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,5
0,6 0,4 0,2
-1
0 -1,5
0
k
8
16
24
32
40
48
56
64
f
Abb. 1.15. Signalverlauf und Linienspektrum nach zusätzlicher Fensterung
Tatsächlich führt die Wahl einer geeigneten Fensterfunktion zu einer deutlichen Reduzierung der spektralen Aufspreizung, wie am resultierenden Signalspektrum zu erkennen ist. Bedingt durch die Fensterform und die damit zusammenhängende Dämpfung der Signalamplitude zu den Rändern hin, kommt es auch zu einer Dämpfung der Spektrallinien, die nach der Fensterung wieder ausgeglichen werden muß. Allgemein ist die Dämpfung umgekehrt proportional zur Fläche unterhalb der Fensterfunktion. Im vorliegenden Fall (Dämpfung = 2) müssen wir die Höhen der Spektrallinien mit Zwei multiplizieren, um die ursprünglichen Verhältnisse wiederzugeben. Andere Fensterfunktionen erfordern, entsprechend ihrem Gleichanteil, auch andere Korrekturwerte. Die offensichtliche Verbesserung im Ergebnis könnte nun zu der Schlußfolgerung verleiten, es sei sinnvoll immer andere Fensterfunktionen als das gewöhnliche Rechteckfenster zu benutzen. Dies kann jedoch nicht grundsätzlich gelten. Wie der nächste Abschnitt zeigt, ist die Wahl einer optimalen Fensterfunktion nur unter Berücksichtigung der Beschaffenheit des zu untersuchenden Signals möglich.
1.9 Nichtstationäre Signale – Die Grenzen der DFT Die in den vorangegangenen Abschnitten vorgestellte DFT eignet sich zur Frequenzanalyse von zeitdiskreten Abtastsignalen. In der Praxis kann es dabei durchaus vorkommen, daß sich der Frequenzbereich eines Signals innerhalb kurzer Zeit ändert. In elektrischen Netzwerken kommt es bei Schaltvorgängen aufgrund der vorhandenen Elemente (Induktivitäten, Kapazitäten) zu Ausgleichsvorgängen. Die dabei auftretenden Transienten
34
1 Digitale Signalverarbeitung
stellen Frequenzanteile dar, die sich deutlich vom gewöhnlichen Signalverlauf abgrenzen. Sie sind mit einer normalen DFT kaum zu erfassen. Das folgende Beispiel soll die Grenzen der bisherigen Frequenzanalyse deutlich machen. Hierzu wird ein geeignetes Testsignal erzeugt. class Spektrum { ... public void ErzeugeTestsignal_3() { for (int k = 0; k= 3*Abtastwerte/4 && k < (3*Abtastwerte/4 + Abtastwerte/16)) { x[k] = Math.Sin(2*PI*23*k/Abtastwerte); } } } ... }
Zunächst besteht unser erzeugtes Testsignal aus einer hochfrequenten Sinusschwingung (52. Harmonische) über die erste halbe Abtastperiode. In der Mitte der zweiten Hälfte kommt noch eine kurze (1/16 Periode) Schwingung mit der 23-fachen Grundfrequenz hinzu. 1,5 1
x(k)
0,5 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,5 -1 -1,5
k
Abb. 1.16. Testsignal mit Frequenzanteilen unterschiedlicher Dauer
1.10 Die Zeit-Frequenz-Analyse
35
Reale Transienten treten meist in Form von exponentiell abklingenden, hochfrequenten Schwingungen auf. Unser Signal weicht hiervon deutlich ab, was jedoch nicht weiter stört. Als Ergebnis der DFT ergibt sich dann das folgende Spektrum. 0,6 0,5
|X(f)|
0,4 0,3 0,2 0,1 0 0
8
16
24
32
40
48
56
64
f
Abb. 1.17. Amplitudenspektrum des Testsignals
Deutlich zu erkennen sind die Anteile der 52. Harmonischen. Dagegen geht die kurzlebige Schwingung der 23. Harmonischen im Grundrauschen des Spektrums beinahe völlig unter, obwohl dessen Amplitude genauso groß ist, wie die der ersten Frequenz. Jedoch ist das Intervall in dem sie existiert nur sehr kurz, wodurch ihr Frequenzanteil herausgemittelt wird. Zusätzlich macht sich der Leakage-Effekt bemerkbar. Obwohl doch zeitweise vorhanden, ist im Amplitudenspektrum überhaupt nicht erkennbar, wann die jeweiligen Frequenzen auftreten oder wie lange sie wirksam sind. Gerade diese fehlende Information kann aber in bestimmten Anwendungen von erheblichem Nutzen sein.
1.10 Die Zeit-Frequenz-Analyse Wie wir bisher gesehen haben, ist die Berechnung der spektralen Zusammensetzung eines Signals ein geeignetes Verfahren zu dessen Charakterisierung. Als besonders anschaulich erweist sich hierbei die grafische Darstellung des Amplitudenspektrums. Leider geht diese Anschaulichkeit verloren, wenn sich die spektrale Zusammensetzung des Signals innerhalb des zu untersuchenden Zeitraumes ändert. In der Realität kommt das sehr häufig vor, so zum Beispiel bei Sprachsignalen. Zwar kann man auch in solchen Fällen ein Gesamtspektrum mit den bisher vorgestellten Methoden berechnen, eine gegebenenfalls erforderliche zeitliche Zuordnung einzelner
36
1 Digitale Signalverarbeitung
Frequenzanteile ist aber nicht möglich und kurzlebige Komponenten verschwinden unter Umständen ganz. Das Problem entsteht dadurch, daß die DFT und die FFT nur ein einziges Zeitfenster verwenden, welches sich immer über das gesamte Abtastintervall erstreckt. Für die Erfassung stark lokalisierter und damit hochfrequenter Signalkomponenten werden entsprechend hochfrequente Cosinusund Sinusanteile herangezogen. Deren Periodendauer T = 1/f ist aber deutlich kleiner als das Zeitfenster der DFT, wodurch es unmöglich ist, den Zeitpunkt ihres Auftretens eindeutig festzulegen (genau genommen ist die zeitliche Zuordnung auf sehr unanschauliche Weise im Phasenspektrum verschlüsselt). Es liegt daher nahe, das Problem durch eine verbesserte Lokalisierung der trigonometrischen Aufbaufunktionen zu entschärfen. In der praktischen Umsetzung sieht das folgendermaßen aus. Anstatt nur ein einziges großes Zeitfenster zu verwenden, wird das Zeitsignal in mehrere kurze Abschnitte aufgeteilt, innerhalb derer es als quasistationär angesehen werden kann. Zu jedem dieser Abschnitte wird anschließend ein separates Spektrum berechnet. Als Ergebnis erhält man auf diese Weise eine Folge von Einzelspektren, die in ihrer Gesamtheit die Dynamik des Signals widerspiegeln. Man bezeichnet dieses Vorgehen als Kurzzeit-Spektralanalyse oder kurz als STFT (Short-Time-Fourier-Transform). Eine einfache Implementierung könnte so aussehen: class Spektrum { ... const int MaxIntervalle = 32; ... public double[,] KS = new double[MaxIntervalle, Abtastwerte]; ... public void ZeitFrequenzAnalyse(int Intervalle) { // über alle Teilintervalle for (int dt=0; dt
1.10 Die Zeit-Frequenz-Analyse
37
{ Re[f] += x[k]*Math.Cos(2*PI*f*k/Abtastwerte); Im[f] += x[k]*Math.Sin(2*PI*f*k/Abtastwerte); } Re[f] *= 2.0/Abtastwerte; Im[f] *= 2.0/Abtastwerte; KS[dt, f] = Math.Sqrt(Re[f]*Re[f] + Im[f]*Im[f]); } Re[0] /= 2.0; // Korrektur Gleichanteil KS[dt, 0] = Re[0]; } } ... }
Grundsätzlich dürfen sich die aufeinanderfolgenden Signalabschnitte natürlich auch überlappen, was mit der Vorstellung korrespondiert, daß unser Zeitfenster kontinuierlich über das Signal hinweggleitet. Für unser Testsignal erhält man bei einer zeitlichen Auflösung von 16 Teilintervallen (ohne Überlappung) die nachfolgende Zeit-Frequenz-Darstellung, die auch Spektrogramm genannt wird. Um den Charakter eines Spektrums zu erhalten, wurde die Frequenz f als Abszisse und die Zeit k als Ordinate gewählt. Grundsätzlich ist aber natürlich auch die umgekehrte Darstellung möglich. Man erkennt nicht nur die im Signal enthaltenen Frequenzanteile, sondern kann diese jetzt auch eindeutig zeitlich zuordnen. Schaut man sich auch die dreidimensionale Darstellung des Spektrogramms an, erkennt man zudem sofort, daß kurzlebige Signalanteile nicht einfach rausgemittelt werden, sondern aufgrund der bei der STFT verwendeten kurzen Teilintervalle, ihrer Amplitude entsprechend, gleichfalls Berücksichtigung finden.
120 96 72
k 48 24
0
8
16
24
32
40
48
56
0 64
f
Abb. 1.18. Spektrogramm des Testsignals mit 16 Teilintervallen
38
1 Digitale Signalverarbeitung
120 0,08
96 72
0,04
48
k
24 0
0 0
8
16
24
32
40
48
56
64
f
Abb. 1.19. Spektrogramm in 3D-Ansicht
Wie schon im Zusammenhang mit dem Leakage-Effekt gezeigt, führt das bloße Ausschneiden eines Signalabschnittes, das einer Multiplikation des Signals mit einem Rechteckfenster entspricht, unter Umständen zu einem Verwischen des Frequenzspektrums, welches durch die Wahl einer anderen Fensterfunktion gemildert werden kann. Es kann sich daher auch beim Kurzzeit-Spektrum als zweckmäßig erweisen auf andere Fensterfunktionen zurückzugreifen. Hat man es mit Transienten oder anderen kurzlebigen Anteilen im Signalverlauf zu tun, ist aber Vorsicht geboten. Solche Erscheinungen können natürlich auch am Rand des betrachteten Intervalls liegen und werden bei Verwendung einer ungeeigneten Fensterfunktion unter Umständen ausgeblendet, wodurch wichtige Frequenzinformationen verloren gehen. Dies gilt übrigens auch für die normale DFT oder FFT. Verwendet man ein gleitendes Fenster, beispielsweise mit einer 50% Überlappung, läßt sich die unerwünschte Ausblendung am Rand leicht vermeiden. Signalanteile, die in einem Intervall am rechten Rand auftreten, liegen dann im nächsten Intervall genau in der Mitte und werden somit voll berücksichtigt. Es leuchtet unmittelbar ein, daß die gewählte zeitliche Rasterung bei der STFT erheblichen Einfluß auf die zeitliche Auflösung hat. Wählt man die Teilintervalle sehr klein, kann man zwar stark lokalisierte (und damit hochfrequente) Ausprägungen zeitlich gut auflösen, niedrige Frequenzanteile mit entsprechend großer Periodendauer werden dann aber nur noch ungenügend oder gar nicht mehr erfaßt. Dies läßt sich zwar durch die Verwendung größerer Teilintervalle vermeiden, worunter dann aber wieder die Auflösung zeitlich lokaler Ereignisse leidet. Ähnlich wie bei Heisenbergs Unschärfetheorie in der Physik, hat man es hier unvermeidbar mit einer Zeit-Frequenz-Unschärfe zu tun. Möchte man mehr zeitliche Details, muß man auf Frequenzinformationen verzichten und umgekehrt. Damit ist klar, daß die Wahl einer bestimmten Fensterfunktion und einer geeigneten Zeitfensterlänge unbedingt problemspezifisch erfolgen muß und immer nur auf den jeweiligen Anwendungsfall optimal abgestimmt werden kann.
1.10 Die Zeit-Frequenz-Analyse
39
Als zweites Beispiel für ein Signal mit zeitlich veränderlicher Frequenz betrachten wir den Gleitsinus, der auch als Chirp („Zwitschern“) bekannt ist. Wegen seiner linear ansteigenden Momentanfrequenz findet er unter anderem in der Meßtechnik bei der Systemanalyse, oder in der Radartechnik Anwendung. Abbildung 1.20 zeigt die besondere Charakteristik dieses Signals. Als Ton hörbar gemacht ähnelt es dem Zwitschern eines Vogels, woraus sich sein Name ableitet. class Spektrum { ... public void ErzeugeTestsignal_4() { double f = 0; for (int k=0; k
Die scheinbare Amplitudenmodulation in Abb. 1.20 resultiert aus ungünstig verteilten AbtastpunktenWie nicht anders zu erwarten war, zeigt sich die stetig wachsende Signalfrequenz als steigende Gerade im Spektrogramm. Wählt man jedoch die Anzahl der Teilintervalle ungünstig, wie in Abb. 1.22, dann bleiben unter Umständen wesentliche Signaleigenschaften verborgen. Ein Rückschluß auf die tatsächliche Zeit-Frequenz-Charakteristik ist dann oft nur noch sehr schwer (oder überhaupt nicht mehr) möglich. 1,5 1
x(k)
0,5 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,5 -1 -1,5
k
Abb. 1.20. Zeitverlauf des Chirp mit linear ansteigender Frequenz
40
1 Digitale Signalverarbeitung 120 96 72
k 48 24
0
8
16
24
32
40
48
56
0 64
f
Abb. 1.21. Spektrogramm des Chirp mit 16 Teilintervallen
96
64 k
32
0
8
16
24
32
40
48
56
0 64
f
Abb. 1.22. Spektrogramm des Chirp mit 4 Teilintervallen
1.11 Digitale Filter In der Signalverarbeitung setzt man digitale Filter hauptsächlich für die Rekonstruktion verrauschter Eingangssignale oder für die Trennung verschiedener Frequenzanteile ein. Grundsätzlich sind für beide Anwendungen auch analoge Filter in Form von elektronischen Schaltungen geeignet. Allerdings streuen die elektrischen Kenngrößen analoger Bauelemente sehr stark. Zusätzlich unterliegen sie einem Alterungsprozeß, der die Charakteristik analoger Filter im Laufe mehrere Betriebsjahre merklich verändert. Dagegen werden digitale Filter in der Regel als Softwareimplementierung eines entsprechenden Algorithmus realisiert, wodurch die Stabilität ihrer Eigenschaften immer gewährleistet ist, auch über viele Jahre hinweg. Um den Umfang dieses Kapitels nicht zu sprengen, werden ausschließlich lineare Filter betrachtet.
1.11 Digitale Filter
41
1.11.1 Frequenzselektive Eigenschaften Digitale Filter haben die Aufgabe bestimmte Signalfrequenzen entweder zu verstärken oder zu dämpfen. Mit ihrer Eigenschaft auf verschiedene Frequenzen in unterschiedlicher Weise einzuwirken, sind sie leicht zu beschreiben. Es ist daher gängige Praxis, frequenzselektive Filter über ihr Frequenzverhalten zu klassifizieren. Der Durchlaßbereich ist derjenige Bereich, der von Frequenzen passiert werden kann, wogegen der Sperrbereich die blockierten Frequenzanteile kennzeichnet. Beide Bereiche sind durch einen sogenannten Übergangsbereich voneinander getrennt. Für eine saubere Trennung der Frequenzen, sollte dieser so schmal wie möglich ausfallen, seine Breite also gegen Null gehen. In der Realität ist dieses angestrebte Ideal ist aber nicht zu erreichen, weshalb man sich beim Filterentwurf gezwungenermaßen mit einem mehr oder weniger guten Kompromiß begnügt. Weitere Kenngrößen sind die Bandbreite eines Filters, sowie seine Grenzfrequenz. Beide Größen sind eng miteinander verknüpft und beschreiben den Frequenzbereich, der weitestgehend unverändert das Filter durchlaufen kann. Tatsächlich wird auch im Durchlaßbereich eine gewisse Dämpfung der Signalamplitude akzeptiert, die bei der Grenzfrequenz auf 1 / 2 (dies entspricht 70,7%) ihres ursprünglichen Wertes abgesunken ist. Die Amplitude des Frequenzganges wird auch Verstärkung genannt und stellt ebenfalls eine wichtige Kenngröße digitaler Filter dar. Sie ergibt sich aus dem Verhältnis der Ausgangsamplitude zur Eingangsamplitude des Filtersignals. Ist die Verstärkung größer als Eins, dann ist die Ausgangsamplitude größer als die Eingangsamplitude. Im umgekehrten Fall ist sie kleiner als Eins. In den meisten Anwendungen ist die Verstärkung im Sperrbereich erheblich kleiner als im Durchlaßbereich, typischerweise um mehrere Zehnerpotenzen. Um dennoch beide Bereiche auf einer Skala grafisch vernünftig darstellen zu können, wird oft die zunächst lineare Verstärkung in Dezibel (dB) umgerechnet.
Verstärkung dB = 20 ⋅ log(Verstärkung )
(1.27)
Für den täglichen Gebrauch ist es zweckmäßig einige Umrechnungen zwischen dem linearen Amplitudenverhältnis und den entsprechenden Werten in Dezibel im Kopf zu haben. Eine Zusammenstellung der wichtigsten Wertepaare ist aus diesem Grund hier aufgelistet.
42
1 Digitale Signalverarbeitung Tabelle 1.5. Logarithmisches (dB) und lineares Amplitudenverhältnis −60 dB −40 dB −20 dB −6 dB −3 dB 0 dB 3 dB 6 dB 20 dB 40 dB 60 dB
0,001 0,01 0,1 0,5 0,707 1 1,414 2 10 100 1000
Die erwähnte Unterteilung frequenzselektiver Filter in funktionelle Gruppen orientiert sich am jeweils wirksamen Frequenzbereich, woraus sich schließlich auch die Benennung der verschiedenen Filtertypen ableitet. Es könne vier Grundtypen unterschieden werden, von denen jedoch zum Teil noch Varianten existieren. Tiefpaß-Filter werden eingesetzt, um die tiefen Frequenzanteile eines Signals zu übertragen, wogegen die hohen Frequenzen oberhalb der Grenzfrequenz fg gedämpft werden. Ihr Durchlaßbereich erstreckt sich von f = 0Hz bis f = fg. Mit ihnen gelingt es hochfrequentes Rauschen vom Nutzsignal zu trennen. Die sehr häufig angewendete Mittelwertbildung von Meßwerten stellt eine einfache Tiefpaß-Filterung dar. Hochpaß-Filter sind notwendig, um die hohen Frequenzanteile eines Signals zu übertragen. Tiefe Frequenzen unterhalb der Grenzfrequenz und auch der Gleichanteil werden dagegen gedämpft. Ihr Durchlaßbereich erstreckt sich von f = fg bis f = ∞. Die oft angewendete Differenzbildung von Meßwerten, zum Beispiel zur Erkennung von Änderungen im Signalverlauf, stellt eine einfache Hochpaß-Filterung dar. Bandpaß-Filter sind in der Lage einen mittleren Frequenzbereich zu übertragen. Tiefe Frequenzen unterhalb der unteren Grenzfrequenz und hohe Frequenzen oberhalb der oberen Grenzfrequenz werden dagegen blockiert. Hierdurch bedingt, besitzen sie auch zwei Sperrbereiche. Verengt sich der Durchlaßbereich auf eine Frequenz, spricht man auch von einem Resonanz-Filter. Bandsperren bzw. Sperr-Filter dämpfen einen mittleren Frequenzbereich, wogegen tiefere und höhere Frequenzen übertragen werden. Sie besitzen also zwei Durchlaßbereiche. Verengt sich der Sperrbereich auf eine Frequenz, spricht man auch von einem Notch-Filter, manchmal auch Lochoder Kerb-Filter.
43
1.11 Digitale Filter |H(f)|
|H(f)|
f |H(f)|
f |H(f)|
f
f
Abb. 1.23. Tiefpaß, Hochpaß, Bandpaß und Bandsperre (unten rechts)
1.11.2 Die z-Transformation Lineare Filter lassen sich wahlweise durch ihr Verhalten im Zeitbereich oder im Frequenzbereich beschreiben. Beide Bereiche sind gleichermaßen geeignet, ein lineares Filter vollständig zu charakterisieren. Es sind nur jeweils verschiedene Betrachtungsweisen des selben Sachverhalts. Sind erst einmal durch die innerhalb einer Anwendung herrschenden Randbedingungen die Eigenschaften im Zeitbereich vorgegeben, ist damit auch das Verhalten im Frequenzbereich eindeutig festgelegt und kann berechnet werden (gilt auch umgekehrt). Um diese Zusammenhänge besser beschreiben und auch verstehen zu können, kommt man spätestens an dieser Stelle leider nicht umhin, sich zumindest ein wenig mit dem mathematischen Fundament der digitalen Signalverarbeitung zu beschäftigen. Wie wir gesehen haben, führt die alleinige Betrachtung von Signalen im Zeitbereich zu einer unvollständigen Sicht der Dinge. Die Tatsache, daß so manche Signaleigenschaft erst im Frequenzbereich sichtbar wird, rechtfertigt den Einsatz von Frequenztransformationen. Als bekanntes und weit verbreitetes Werkzeug für zeitkontinuierliche Signale hat sich die Fourier-Transformation bewährt, die ein Sonderfall der Laplace-Transformation (abgekürzt L) ist. Für abgetastete Signale wurde die DFT vorgestellt. Sie kann ohne viel Aufwand als Algorithmus auf einem Computer implementiert werden, stellt aber, entsprechend ihrem kontinuierlichen Gegenstück, nur einen Sonderfall der allgemeineren z-Transformation (Z) dar. Somit bildet die z-Transformation das zeitdiskrete Pendant zur zeitkontinuierlichen Laplace-Transformation.
44
1 Digitale Signalverarbeitung Frequenzbereich L x(t)
X(s) −1
L
diskret
Abtastung
kontinuierlich
Zeitbereich
=
z −1 X ( s) ⋅ Z( ) z s
Z
x(k)
X(z) Z −1
Abb. 1.24. Transformation zwischen Zeitbereich und Frequenzbereich
Die vorgestellten Verfahren wurden bisher ausschließlich auf Signale angewendet. Es ist nun an der Zeit, diese Selbstbeschränkung zugunsten des Begriffs System endlich aufzugeben. Als System kann eine beliebige Anzahl von Elementen gesehen werde, die miteinander in Wechselwirkung stehen. Üblicherweise lassen sich diese Beziehungen mit Hilfe von Signalen mathematisch beschreiben. Ein Digitalfilter stellt ein einfaches Signalverarbeitungssystem dar, welches in der Regel Teil eines größeren Gesamtsystems ist. Das Bild verdeutlicht die Zusammenhänge zwischen Signalen im Zeitbereich und im Frequenzbereich bzw. den Übergang von den zeitkontinuierlichen Signalen hin zu zeitdiskreten Signalen. Es mag ein wenig überraschen, daß keine Umkehrung der Abtastung existiert. Dies steht scheinbar im Widerspruch zur allgemeinen Vorstellung, wonach Abtastfolgen natürlich auch wieder in zeitkontinuierliche Signale umgewandelt werden können. Schließlich gibt es Digital-Analog-Umsetzer (DAU), kleine elektronische Bausteine, die genau hierzu in der Lage sind. Allerdings handelt es sich bei einer solchen Rekonstruktion immer nur um eine mehr oder weniger gelungene Interpolation. Wie man sich leicht vorstellen kann, ist es immer möglich, durch die Stützstellen einer Abtastfolge unendlich viele kontinuierliche Signalverläufe zu legen. Ausgangspunkt für die weiteren Betrachtungen ist aber zunächst die Laplace-Transformation.
X (s) =
+∞
³ x(t ) ⋅ e
t = −∞
− st
dt
(1.28)
1.11 Digitale Filter
45
Mit Hilfe der Substitution z = esT wird daraus schließlich die zweiseitige z-Transformation.
X ( z) =
+∞
¦ x(k ) ⋅ z
−k
(1.29)
k = −∞
X(z) ist somit eine Funktion der komplexen Variablen z und kann in der komplexen Ebene dargestellt werden. Weiterhin gilt s = σ + jω.
z = e sT z = eσ ⋅ e jωT z = r ⋅ e jωT
(1.30)
Die hier aufgeführten Gleichungen ermöglichen die Transformation von Signalen aus der komplexen s-Ebene in die komplexe z-Ebene. Berücksichtigt man die verschiedenen möglichen Werte von σ = Re(s), ergeben sich grundsätzlich drei unterschiedliche Bereiche. • ı = 0 entspricht in der s-Ebene der Imaginärachse. Als Radius erhält man r = e0 = 1. Die Imaginärachse der s-Ebene wird auf den Einheitskreis der z-Ebene abgebildet. Dies entspricht gerade der schon mehrfach verwendeten DFT. • ı > 0 beschreibt die rechte offene s-Halbebene, was im z-Bereich einem Radius r > 1 entspricht. Damit wird die rechte s-Ebene also auf den außerhalb des Einheitskreises liegenden Bereich transformiert. • ı < 0 ergibt einen Radius r < 1, was gleichbedeutend ist mit einer Abbildung der linken s-Halbebene in das innere des Einheitskreises der z-Ebene. Eine ganz besondere Bedeutung kommt der s-Ebene in der Regelungstechnik bei Untersuchungen zur Stabilität zeitkontinuierlicher Systeme zu. Sie lassen sich im Zeitbereich mathematisch durch Differentialgleichungen beschreiben. Als Lösung dieser Differentialgleichungen ergeben sich für gewöhnlich Exponentialfunktionen. Es leuchtet unmittelbar ein, daß diese Exponentialfunktionen, und damit natürlich auch das System selbst, nur für negative Exponenten stabil sind. Somit gewährleisten die negativen Exponenten in den Lösungen der systembeschreibenden Differentialgleichung die Stabilität eines zeitkontinuierlichen Systems. In die s-Ebene transformiert, bilden sie die dann ebenfalls negativen Polstellen (Pole = Nullstellen des Nennerpolynoms) der gebrochen rationalen Übertragungsfunktion des Systems. Für zeitkontinuierliche Systeme kann daher festgehalten werden, daß diese genau dann stabil sind, wenn ihre Übertragungsfunktion
46
1 Digitale Signalverarbeitung Im(s)
Im(z)
Re(z)
Re(s)
s-Ebene
z-Ebene
Abb. 1.25. Ebenentransformation
nur Polstellen in der linken offenen s-Halbebene aufweist. Entsprechendes gilt für die z-Ebene im zeitdiskreten Fall. Aufgrund der zuvor beschriebenen Ebenentransformation bildet hier das innere des Einheitskreises den stabilen Bereich. Wegen der Periodizität von z = r·ejȦT ist die Abbildung aus dem s-Bereich in die z-Ebene aber nur in Streifen von jeweils ȦT = 2ʌ Breite eindeutig, die inverse z-Transformation demzufolge im allgemeinen mehrdeutig. Weiterhin soll nicht unerwähnt bleiben, daß es neben der hier angegebenen zweiseitigen z-Transformation auch eine einseitige Form gibt, bei welcher der Summationsindex k von 0.. ∞ läuft. Offensichtlich genügt diese Variante zur Transformation kausaler Signale, bei denen die Werte für negative Zeitpunkte (k < 0) sämtlich verschwinden. Tabelle 1.6. Ausgewählte Eigenschaften der z-Transformation Zeitbereich
z-Bereich
a ⋅ X ( z) + b ⋅ G( z)
Zeitverschiebung
a ⋅ x (k ) + b ⋅ g ( k ) x ( k − n)
Zeitverschiebung (2)
x( k + n)
z n ⋅ X ( z ) − ¦ x(i ) ⋅ z n − i
k ⋅ x(k )
dX ( z ) − z⋅ dz −1 X (z )
Linearität
Differentiation Zeitumkehr
n −1 i =0
x (− k ) k
Faltung
z −n ⋅ X ( z)
x (k ) ∗ g ( k ) = ¦ x (i ) ⋅ g ( k − i ) i=0
X ( z) ⋅ G( z)
1.11 Digitale Filter
47
Die für uns wichtigste Anwendung der z-Transformation liegt natürlich in der Beschreibung digitaler Abtastsysteme, also auch digitaler Filter. Ihr Verhalten im Zeitbereich wird durch Differenzengleichungen charakterisiert. Nach einer Transformation in den z-Bereich erhält man im allgemeinen gebrochen rationale Systemfunktionen, die uns helfen das Frequenzverhalten anschaulich zu verstehen. Auf diesen Punkt wird in den nächsten Abschnitten noch näher eingegangen. An dieser Stelle soll es genügen einige wichtige Eigenschaften der z-Transformation aufzuzeigen. 1.11.3 Die Übertragungsfunktion und der Frequenzgang
Physikalisch betrachtet, beschreibt die Übertragungsfunktion die Antwort eines Systems bei verschiedenen Eingangssignalen, oder genauer ausgedrückt, aufgrund unterschiedlicher (komplexer) Eingangsfrequenzen. In der Meß- und Regelungstechnik wird dieser Umstand häufig genutzt, um die dynamischen Eigenschaften eines unbekannten Systems meßtechnisch zu analysieren (siehe hierzu auch Abschn. 1.12). Filtereingang
Filterantwort
H(z)
X(z)
Y(z)=H(z)·X(z)
Abb. 1.26. Übertragungsfunktion in Frequenzbereich
Im Frequenzbereich sind das Eingangssignal X(z), die Übertragungsfunktion H(z) und die resultierende Systemantwort Y(z) multiplikativ miteinander verknüpft. Aus diesem Grund ist der Rückschluß auf H(z) durch Umformung leicht möglich.
H ( z) =
Y ( z) X ( z)
(1.31)
Prinzipiell kann aufgrund dieser Gleichung das Übertragungsverhalten durch Messung am Objekt direkt bestimmt werden. In der Praxis bewährt hat sich die Bestimmung des Frequenzganges H(f), ein Sonderfall der komplexen Übertragungsfunktion. Um H(f) zu messen, speist man am Eingang ein sinusförmiges Testsignal ein und erhöht dessen Frequenz kontinuierlich. Hat man es mit einem linearen System zu tun, dann wird die Frequenz des Ausgangssignals der Eingangsfrequenz folgen, lediglich die Amplitude und die Phase ändern sich. Diese typische Charakteristik stellt
48
1 Digitale Signalverarbeitung
Filtereingang
Filterantwort
h(k)
x(k)
y(k)=h(k)*x(k)
Abb. 1.27. Übertragungsfunktion im Zeitbereich
dann den Frequenzgang des untersuchten Systems dar, spiegelt also seine dynamischen Eigenschaften wider. Aber natürlich können digitale Systeme nicht nur im Frequenzbereich, sondern auch im Zeitbereich beschrieben werden. Leider sind manche Dinge im Zeitbereich ein wenig komplizierter als im Frequenzbereich. Das elementarste Abtastsignal ist der schon bekannte Einheitsimpuls. Ihn kann man sich als einen unendlichen Datenstrom vorstellen, bei dem genau ein Abtastwert den Wert Eins hat und alle übrigen Werte Null sind. Hat diese spezielle Abtastfolge das System vollständig durchlaufen, dann erhält man an seinem Ausgang die Einheitsimpulsantwort h(k), manchmal auch Gewichtsfunktion genannt. Alle Abtastsignale lassen sich nun als Linearkombination gewichteter und verschobener Einheitsimpulse darstellen.
x(k ) =
+∞
¦ x (i ) ⋅ δ ( k − i )
(1.32)
i = −∞
Durchläuft eine solche Impulsfolge unser lineares System, erhalten wir am Ausgang ein Signal, welches sich aus der Überlagerung aller entsprechend gewichteten und verschobenen Impulsantworten ergibt. Mathematisch stellt dies eine Faltungssumme dar.
y(k ) =
+∞
¦ x (i ) ⋅ h ( k − i )
(1.33)
i = −∞
Die Kenntnis von h(k) reicht also aus, um die Systemantwort auf beliebige Eingangssignale zu bestimmen. Somit beschreibt die Impulsantwort ein lineares System ebenfalls vollständig. Allerdings sind hier x(k), h(k) und y(k) durch eine Faltung miteinander verknüpft, weshalb im Zeitbereich ein so einfacher Zusammenhang wie Gln. (1.31) leider nicht existiert. Da die Übertragungsfunktion H(z) die Frequenztransformierte der Einheitsimpulsantwort h(k) ist, läßt sich das Frequenzverhalten eines digitalen Filters mittels z-Transformation auch direkt aus seiner Impulsantwort berechnen. Hier endlich schließt sich der Kreis. Mit der folgenden Gleichung wird die enge Beziehung zwischen Zeit- und Frequenzbereich deutlich, die
1.11 Digitale Filter
49
untrennbar miteinander verbunden sind. Sie bildet daher einen fundamentalen Grundsatz der digitalen Signalverarbeitung.
H ( z) =
+∞
¦ h( k ) ⋅ z
−k
(1.34)
k = −∞
Den Frequenzgang H(f) des Filters als Sonderfall der Übertragungsfunktion H(z) erhält man schließlich mit z = e j 2π f Ta durch Variation der Frequenz f. Ta stellt die gewählte Abtastzeit dar, für die das Filter eingesetzt werden soll. Der Frequenzgang durchläuft alle Werte der Übertragungsfunktion entlang des Einheitskreises in der z-Ebene und wird wegen der besseren Anschauung in Betragsgang und Phasengang zerlegt.
H ( f ) = H ( z = e j 2 π f Ta )
(1.35)
H ( f ) = H ( f ) ⋅ e jϕ ( f )
(1.36)
H ( f ) = ℜ2 ( H ( f )) + ℑ2 ( H ( f ))
(1.37)
§ ℑ ( H ( f )) · ¸¸ © ℜ ( H ( f )) ¹
ϕ ( f ) = arctan¨¨
(1.38)
Leider ist die Definition des Phasenganges ij(f) in der Literatur nicht ganz einheitlich. Während in der Regelungstechnik meist die vorliegende Form verwendet wird, ist es in der Nachrichtentechnik üblich, den Phasengang zusätzlich mit einem negativen Vorzeichen zu versehen. Da die digitale Signalverarbeitung gleichermaßen in beiden Disziplinen verwurzelt ist, sind in den Lehrbüchern auch beide Definitionen vorzufinden. Insbesondere in der deutschsprachigen Literatur wird für die Übertragungsfunktion auch häufig G(z) statt H(z) verwendet, entsprechend g(k) anstelle von h(k). Hiervon sollte man sich aber nicht beirren lassen. 1.11.4 Mittelwertfilter
Das wohl am häufigsten benutzte digitale Filter ist das Moving-AverageFilter (MA-Filter), welches einfach den Mittelwert aus einer Anzahl von Meßwerten berechnet. Es ist so simpel, daß man bei seiner Verwendung fast ein schlechtes Gewissen hat, wegen der scheinbar mangelnden Wissenschaftlichkeit eines solchen Ansatzes. Hierzu besteht jedoch kein Grund, ganz im Gegenteil. Wegen seiner einfachen Handhabung und verständlichen Wirkungsweise ist es leicht zu implementieren und eignet sich
50
1 Digitale Signalverarbeitung
damit besonders zur Reduzierung von zufälligen Störungen, wie sie bei der Meßwerterfassung eigentlich immer auftreten.
y (k ) =
1 M
M −1
¦ x (k − i )
(1.39)
i=0
Hierbei sind x(k) die Abtastwerte des Eingangssignals, M die Anzahl der einbezogenen Abtastwerte und y(k) das gefilterte Ausgangssignal. Bei Online-Anwendungen kann für eine Filterung nur auf den aktuellen Meßwert x(k) und zeitlich zurückliegende Eingangswerte zugegriffen werden. Ein solches Filter ist kausal. Liegen die Eingangsdaten zum Zeitpunkt der Verarbeitung schon vor, zum Beispiel abgespeichert in einer Meßwertdatei, dann ist grundsätzlich auch die Verwendung nichtkausaler Filter denkbar. Bei ihnen werden zur Berechnung des aktuellen Ausgangswertes neben dem aktuellen Abtastwert auch vergangene und zukünftige Werte einbezogen, meist symmetrisch angeordnet.
y (k ) =
x(k − 2) + x(k − 1) + x(k ) + x(k + 1) + x(k + 2) 5
In der hier vorgestellten nichtrekursiven Form hängt der Ausgangswert ausschließlich von den Eingangswerten ab. Möchte man den Mittelwert aus einer Anzahl von Meßwerten bestimmen, muß man warten, bis tatsächlich genügend Werte aus der Messung vorliegen. Dabei wächst die Antwortzeit des Filters mit der Breite seines Datenfensters, d. h. mit der Anzahl der einbezogenen Meßwerte. Auch wenn für eine Mittelwertbildung nach Gln. (1.39) sehr viele Meßwerte herangezogen werden, sind es doch immer nur endlich (also abzählbar) viele, weshalb auch die Filterantwort immer nach einer endlichen Zeit vorliegt. Da sie in jedem Fall endlich ist, gehören nichtrekursive Filter zur Klasse der FIR-Filter (Finite Impulse Response). Bekanntermaßen gehen beim Mittelwertfilter alle Abtastwerte mit dem gleichen Gewicht 1/M ein. Die identischen Filterkoeffizienten bilden im Zeitbereich ein Rechteckfenster, welches die Eigenschaften und das Verhalten des Filters im Frequenzbereich bestimmt. Neben den nichtrekursiven FIR-Filtern, bei denen die Filterantwort zu jedem Zeitpunkt ausschließlich von den anliegenden Eingangswerten abhängt, gibt es auch rekursive Filter. Aufgrund ihrer besonderen Struktur gehen bei diesem Filtertyp die Ausgangswerte zurückliegender Zeitpunkte
1.11 Digitale Filter
51
ebenfalls in die aktuelle Filterantwort ein. Wie die folgende Beispielrechnung belegt, kann man ein nichtrekursives Mittelwertfilter ohne großen Aufwand in eine rekursive Form bringen.
y (58) =
x(56) + x (57) + x(58) + x (59) + x (60) 5
y (59) =
x(57) + x (58) + x (59) + x (60) + x (61) 5
y (58) − y (59) =
x (56) − x (61) 5
y (59) = y (58) +
x(61) − x(56) 5
Wie sich zeigt, hängt der Ausgangswert y(59) von den Eingangswerten x(56), x(61) und dem alten Ausgangswert y(58) ab. Man kann sich nun leicht überlegen, daß es in einem nächsten Schritt durchaus möglich wäre, den Ausgangswert y(58) ebenfalls rekursiv durch seinen Vorgänger y(57) zu ersetzen, mit dem man dann wiederum so verfahren könnte. Da somit beliebig viele alte Ausgangswerte in die aktuelle Filterantwort eingehen, ist folglich auch die Filterantwort selbst beliebig lang. Rekursive Filter zählen daher zur Klasse der IIR-Filter (Infinite Impulse Response). Schaut man sich das obige Beispiel an, wird schnell klar, daß ein wesentlicher Vorteil rekursiver Filter in der schnelleren Berechenbarkeit durch einen Computer zu sehen ist, da in dieser kompakten Form erheblich weniger Adreßaufrufe und Rechenoperationen notwendig sind. 1.11.5 FIR-Filter
FIR-Filter bilden im Zeitbereich nichtrekursive Differenzengleichungen mit konstanten Koeffizienten. Als Beispiel dient uns erneut die schon bekannte Mittelwertbildung aus fünf Meßwerten.
y (k ) =
1 ⋅ ( x(k ) + x(k − 1) + x(k − 2) + x(k − 3) + x(k − 4)) 5
Mit Hilfe der z-Transformation ist die Transformation dieser Gleichung und ihre Betrachtung im Frequenzbereich möglich.
Y (z) =
1 ⋅ ( X ( z ) + z −1 ⋅ X ( z ) + z − 2 ⋅ X ( z ) + z − 3 ⋅ X ( z ) + z − 4 ⋅ X ( z )) 5
52
1 Digitale Signalverarbeitung
1 ⋅ X ( z ) ⋅ (1 + z −1 + z − 2 + z − 3 + z − 4 ) 5 Y (z) 1 H ( z) = = ⋅ (1 + z −1 + z − 2 + z − 3 + z − 4 ) X ( z) 5
Y (z) =
Als Ergebnis unserer Berechnung erhalten wir die Übertragungsfunktion H(z). Genau wie die Differenzengleichung im Zeitbereich, charakterisiert die Übertragungsfunktion im Frequenzbereich das Filters vollständig. Bei linearen Systemen bildet die Übertragungsfunktion eine sehr anschauliche Eingangs-/Ausgangsbeziehung. Eine solche Interpretation ist jedoch nur im Frequenzbereich möglich, was eindeutig für die Verwendung der zTransformation spricht. Differenzengleichung und Übertragungsfunktion lassen sich ganz allgemein formulieren:
y (k ) = a0 ⋅ x(k ) + a1 ⋅ x(k − 1) + a2 ⋅ x(k − 2) + ... + aN ⋅ x(k − N ) (1.40) N
H ( z ) = ¦ ai ⋅ z − i = a0 + a1 ⋅ z −1 + a2 ⋅ z − 2 + ... + aN ⋅ z − N (1.41) i =0
Auch wenn es nicht auf den ersten Blick erkennbar ist, stellt der letzte Ausdruck eine gebrochen rationale Funktion der komplexen Variable z dar. Wir formen Gln. (1.41) um, indem wir mit zN erweitern.
a0 ⋅ z N + a1 ⋅ z N −1 + a2 ⋅ z N − 2 + ... + aN H ( z) = zN Man erkennt jetzt den N-fachen Pol der Übertragungsfunktion bei z = 0, der aber auf die Stabilität des Filters keinen Einfluß hat, da er innerhalb des Einheitskreises liegt (mit z = esT entspricht das der komplexen Frequenz s = -). Dieser Umstand ist typisch für FIR-Filter, die immer stabil sind, da ihre Polstellen ausschließlich im Koordinatenursprung der z-Ebene liegen. Möchte man die Übertragungsfunktion bzw. den Frequenzgang eines FIR-Filters bestimmen, dann ist das nach Gln. (1.34) mit Hilfe der z-Transformation auch unmittelbar aus der Impulsantwort möglich. Hierzu ist es aber notwendig, die Impulsantwort des Filters zu kennen. Sollte das nicht der Fall sein, kommt man nicht umhin sie zu bestimmen. Wie das funktioniert ist klar. Zunächst ist am Filtereingang ein Einheitsimpuls anzulegen, der das Filter vollständig zu durchlaufen hat. Am Filterausgang erhält man dann die gesuchte Impulsantwort. Glücklicherweise ist das bei FIR-Filtern ganz besonders einfach. Als Ergebnis erhält man am Filterausgang gerade die einzelnen Filterkoeffizienten ai selbst. Das durch sie gebildete Signalfenster stellt also die
1.11 Digitale Filter
53
x(k) … 0,
0,
1,
0,
0,
0,
1/5
1/5
1/5
1/5
1/5
0, ...
y(k) = 1/5
Abb. 1.28. Nichtrekursives Mittelwertfilter mit Einheitsimpuls am Eingang
Einheitsimpulsantwort des FIR-Filters im Zeitbereich dar. Komplizierte Berechnungen sind somit überflüssig.
Entwurf und Analyse von FIR-Filtern Frequenzselektive Filter werden eingesetzt, um bestimmte Frequenzanteile aus einem Signal herauszufiltern. Ganz gleichgültig, welcher Filtertyp in einer konkreten Anwendung zum Einsatz kommen soll, in jedem Fall ist es für den Filterentwurf zwingend notwendig, eine möglichst exakte Vorstellung von dem gewünschten Frequenzverhalten des Filters zu haben. Nur so lassen sich, entsprechend der Aufgabenstellung, die Anforderungen an das Filter genau spezifizieren. Somit erfolgt die Wahl der Filterkoeffizienten immer problemabhängig. Unter dem Entwurf eines Filters wollen wir daher die Bestimmung geeigneter Koeffizienten verstehen. Die Theorie des Filterentwurfs ist ein sehr weitläufiges Thema und kann an dieser Stelle nicht einmal annähernd vollständig behandelt werden. Aus diesem Grund stehen auch eine Reihe kommerzieller Entwurfsprogramme zur Verfügung, die den Entwickler bei seiner Arbeit unterstützen. Die hier vorgestellten Methoden ermöglichen ein tieferes Verständnis für die Probleme dieser Thematik und versetzen den Leser in die Lage, die Funktionsweise softwaregestützter Entwurfsverfahren besser zu verstehen.
54
1 Digitale Signalverarbeitung
Die Fenstermethode Beim Entwurf von FIR-Filtern ist ein Verfahren gebräuchlich, für das die bisher erarbeiteten Grundlagen eine ausgezeichnete Basis bieten. Die nachfolgend vorgestellte Fenstermethode zeichnet sich besonders durch ihr unkompliziertes und intuitives Vorgehen aus. Man muß sich lediglich in Erinnerung rufen, daß die inverse Fouriertransformierte des Frequenzganges H(f) die Impulsantwort h(k) des Filters ergibt. Diese ist aber bei FIRFiltern gerade mit den Filterkoeffizienten identisch. Somit beschränkt sich der Entwurf nach der Fenstermethode darauf, den gewünschten Filterfrequenzgang vorzugeben und die gesuchten Filterkoeffizienten zu berechnen, beispielsweise mit der schon bekannten IDFT. Wenn doch nur alles im Leben so einfach wäre, oder doch nicht? Die Anforderungen an ein Filter sind schnell formuliert. Neben der angestrebten Grenzfrequenz, stehen ein glatter Frequenzverlauf im Durchlaßbereich, ein möglichst steiler Übergang und schließlich eine gute Dämpfung im Sperrbereich im Vordergrund. Gleichzeitig strebt man einen kleinen Filtergrad an, um die Reaktionszeit des Filters und den Berechnungsaufwand bei der Faltung mit einem Signal niedrig zu halten. Alle diese typischen Forderungen gemeinsam unter einen Hut zu bekommen ist aber schwieriger als es zunächst den Anschein hat. Tatsächlich widersprechen sie sich sogar zum Teil, wie wir am Beispiel eines Tiefpaßfilters mit fg = 1/16 fa sehen werden. Das angestrebte Übertragungsverhalten ist in Abb. 1.29 dargestellt und dient als Ausgangspunkt für den weiteren Entwurf. Wie wir schon im Abschnitt über Pulse und Pulsfolgen gesehen haben, berechnet die DFT (und damit natürlich auch die FFT) immer ein bei der halben Abtastfrequenz gespiegeltes Spektrum. Gibt man nun umgekehrt einen Frequenzgang vor, um mit Hilfe der IDFT die Impulsantwort des Filters zu berechnen, darf man diese periodische Fortsetzung im Frequenzbereich nicht vergessen. Wird ein solcher idealer Wunschfrequenzgang
1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0 0
0,063
0,125
0,188
0,25
0,313
0,375
0,438
0,5
f/fa
Abb. 1.29. Wunschfrequenzgang eines Tiefpaßfilters mit fg = 1/16 fa
1.11 Digitale Filter
55
20
h(k)
15 10 5 0 -64 -56 -48 -40 -32 -24 -16 -8
0
8
16 24 32 40 48 56
-5
k
Abb. 1.30. Impulsantwort des Tiefpaßfilters
gewählt, erhält man als Ergebnis der IDFT die schon bekannte Spaltfunktion, deren Abtastwerte h(k) schließlich die gesuchten Filterkoeffizienten bilden. Zumindest theoretisch stimmt das so. Nimmt man aber einen auf diese Weise erzeugten Satz von Filterkoeffizienten und schaut auf die hieraus resultierende Übertragungsfunktion (wie das geht, sehen wir im nächsten Abschnitt), dann erlebt man eine unangenehme Überraschung. Der tatsächliche Verlauf des Amplitudenfrequenzganges weicht ganz erheblich von der angestrebten Idealform ab. Ein Blick zurück auf die berechnete Impulsantwort unseres Tiefpaßfilters in Abb. 1.30 legt es nahe, als Ursache die Verwendung von nur endlich vielen Filterkoeffizienten aus der doch eigentlich nach beiden Seiten unendlich ausgedehnten Spaltfunktion zu vermuten. Eine solche Begrenzung der Impulsantwort kommt der Multiplikation mit einem Rechteckfenster gleich und ist für reelle Anwendungen durchaus sinnvoll, schließlich sind in der Praxis Filter unendlicher Länge nicht zu gebrauchen. Unvermeidlich bringt das Abschneiden der Filterkoeffizienten dann aber auch eine ganze Reihe unerwünschter Nebenwirkungen im Frequenzbereich mit sich. • Es entsteht im Durchlaßbereich eine deutliche Welligkeit, deren Amplitude zur Grenzfrequenz hin sogar noch zunimmt (Gibbsches Phänomen). • Im Sperrbereich des Filters sind mehrere Nebenmaxima erkennbar, die nur langsam mit zunehmender Frequenz abklingen. • Der Übergangsbereich ist erheblich aufgeweitet, die Filterflanke demzufolge keineswegs ideal steil. Alle diese Nachteile könnten durch eine Vergrößerung der Filterlänge grundsätzlich behoben werden, wenn diese denn beliebig groß wählbar wäre. Insbesondere die Breite des Übergangsgebietes ist unmittelbar mit der Filterlänge verknüpft und ließe sich auf diese Weise leicht dem angestrebten
56
1 Digitale Signalverarbeitung 1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,12
0,12
0,1
0,11
0,09
0,08
0,07
0,06
0,05
0,04
0,04
0,03
0,02
0
0,01
0
f/fa
Abb. 1.31. Tatsächlicher Frequenzgang des Filters (geänderte Skalierung!)
Ideal annähern. Mit zunehmender Filterlänge wächst dann allerdings auch die Anzahl der erforderlichen Rechenoperationen, was mit einem entsprechend hohem Rechenzeitbedarf verbunden ist, egal ob eine Softwareimplementierung oder eine Hardwarerealisierung des Filter vorliegt. Der bisher erzielte Filterfrequenzgang in Abb. 1.31 ist jedoch für viele Anwendungen nicht akzeptabel, weshalb wir unseren prinzipiell richtigen Ansatz noch ein wenig verfeinern müssen. Schon im Abschn. 1.8 haben wir festgestellt, daß die Verwendung von Rechteckfenstern keineswegs immer zu optimalen Ergebnissen führt. Es konnte gezeigt werden, daß sich die in bestimmten Anwendungsfällen auftretenden spektralen Unschärfen durch die Wahl geeigneterer Fenstertypen deutlich mildern lassen. Das trifft auch auf den von uns angestrebten Filterfrequenzgang zu. Bevor wir jedoch diese Zusammenhänge näher untersuchen, ist es zweckmäßig einige der bekanntesten Fenstertypen hier kurz einmal vorzustellen. In den folgenden Beispielen ist M die Anzahl der Abtastwerte je Signalperiode, also die Fensterlänge. Hanning:
w(k ) = 0,5 − 0,5 ⋅ cos(
2π k ) M
Hamming:
w(k ) = 0,54 − 0,46 ⋅ cos(
2π k ) M
Blackman:
w(k ) = 0,42 − 0,5 ⋅ cos(
2π k 4π k ) + 0,08 ⋅ cos( ) M M
1.11 Digitale Filter
57
Blackman (exakt):
w(k ) = 0,42659071 − 0,49656062 ⋅ cos(
2π k 4π k ) + 0,07684867 ⋅ cos( ) M M
Blackman-Harris:
w(k ) = 0,42323 − 0,49755 ⋅ cos(
2π k 4π k ) + 0,07922 ⋅ cos( ) M M
Flat Top:
w(k ) = 0,2810639 − 0,5208972 ⋅ cos(
2π k 4π k ) + 0,1980399 ⋅ cos( ) M M
Bartlett:
w(k ) = 1 −
k − M /2 M /2
Welch:
k − M /2 w(k ) = 1 − M /2
2
Mit dem Aufkommen der digitalen Rechentechnik in der Signalverarbeitung, etwa ab 1950, wurden die geschilderten Probleme bei der Benutzung von Rechteckfenstern sehr schnell erkannt. Die Cosinus-Funktion bietet sich in diesem Fall als naheliegende Lösung der durch das abrupte
1,2 1
w(k)
0,8 0,6 0,4 0,2 0 -0,2 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
Hanning Blackman Blackman-Harris Bartlett
k
Hamming Blackman (exakt) Flat-Top Welch
Abb. 1.32. Hüllkurven der verschiedenen Fensterfunktionen
58
1 Digitale Signalverarbeitung 20
h(k)
15 10 5 0 -64 -56 -48 -40 -32 -24 -16 -8
0
8
16 24 32 40 48 56
-5
k
Abb. 1.33. Impulsantwort nach Multiplikation mit einem Hanning-Fenster
Abschneiden verursachten Abweichungen vom Ideal an. Tatsächlich ist sie der Urahn der allermeisten Fenstertypen. Hieraus sind dann im Laufe der Zeit zahlreiche Varianten entstanden, die häufig nach ihrem Entwickler benannt wurden. Trotz der Vielfalt sei aber darauf hingewiesen, daß die häufigste Fensterfunktion immer noch das Rechteckfenster selbst ist. Alle aufgeführten Fenster liegen symmetrisch um einen mittleren Abtastzeitpunkt. Mit ihnen gelingt es, die Filterkoeffizienten zum Rand hin kontrolliert gegen einen vernachlässigbaren Wert zu zwingen. Hierfür ist es erforderlich die in Abb. 1.30 dargestellten Rohwerte punktweise mit w(k) zu multiplizieren. Genau genommen kann der Filterentwurf bis zu diesem Punkt sogar noch verkürzt werden. Das unsere ideale Vorgabe im Frequenzbereich als Impulsantwort eine Spaltfunktion besitzt, ist ja ohnehin klar. Warum sollte es dann noch notwendig sein, dieses doch eigentlich schon bekannte Ergebnis über eine IDFT zu erzeugen? Das kann man auch schneller und einfacher haben, Zeit ist schließlich Geld. Die Tatsache, daß die angestrebte Grenzfrequenz fg und die Zahl der Abtastwerte M den Verlauf von h(k) eindeutig festlegen, wollen wir für unsere Zwecke nutzen.
h(k ) = K ⋅
sin(2π f g (k − M / 2)) (2π f g (k − M / 2))
⋅ w(k )
(1.42)
Nimmt man für w(k) eine der zuvor aufgelisteten Fensterfunktionen, dann kann die gefensterte Impulsantwort mit Hilfe dieser Gleichung direkt berechnet werden. Die Konstante K dient zur Einstellung der gewünschten Gleichspannungsverstärkung |H(0)|. Bei der Implementierung ist zu beachten, daß an der Stelle k = M/2 ein „Division durch Null“-Fehler auftritt, wenn k über alle Abtastwerte läuft. Natürlich wollen wir das vermeiden, die Addition einer kleinen Konstanten (zum Beispiel 0,00001) im Argument des Sinus und im Nenner wäre eine Möglichkeit hierzu. Unabhängig
1.11 Digitale Filter
59
1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,12
0,12
0,11
0,1
0,09
0,08
0,07
0,06
0,05
0,04
0,04
0,03
0,02
0,01
0
0
f/fa
Abb. 1.34. Amplitudengang nach Hanning-Fensterung der Impulsantwort
davon, ob wir uns für die IDFT oder Gln. (1.42) entscheiden, zeigt die zusätzliche Fensterung der Impulsantwort eine deutliche Verbesserung im resultierenden Frequenzgang. Auf den ersten Blick ist zu erkennen, daß die störende Welligkeit im Durchlaßbereich weitgehend verschwunden ist und auch die Sperrdämpfung sich deutlich erhöht hat. Beides hängt natürlich vom konkret verwendeten Fenstertyp ab. Interessanterweise ist die Verstärkung unseres Filters, entgegen der Vorgabe, ein wenig kleiner als Eins. Das war übrigens auch in Abb. 1.31 schon so, wenngleich es dort wegen der ausgeprägten Welligkeit nicht sofort auffällt. Ursache ist erneut die nur endliche Anzahl von Filterkoeffizienten aus der doch eigentlich unendlich ausgedehnten Spaltfunktion. Hier macht sich die Vernachlässigung kleiner und scheinbar unbedeutender Amplituden bemerkbar. In den meisten Fällen ist jedoch eine Gleichspannungsverstärkung von genau Eins erwünscht, weshalb wir die Koeffizienten noch entsprechend normieren müssen. Dazu dividiert man jeden einzelnen Filterkoeffizienten durch die Summe aller Koeffizienten. Weiterhin besitzt unser Filter noch nicht die gewünschte Grenzfrequenz. Für einen Tiefpaß ist sie definiert als
H TP ( f g ) =
1 ⋅ H TP (0) 2
(1.43)
Abhängig von der Fensterfunktion ist die tatsächlich resultierende Grenzfrequenz ein wenig kleiner als die Vorgabe, was es notwendig macht, den angestrebten Wert zum Ausgleich entsprechend anzuheben. Somit ist der gesamte Entwurfsprozeß mit der modifizierten Grenzfrequenz fg zu wiederholen. Dies führt zu einem Iterationsvorgang, der unter Umständen mehrmals durchlaufen werden muß. Auch wenn das zunächst kompliziert erscheint, kommt man in der praktischen Anwendung recht schnell zu einem akzeptablen Ergebnis.
60
1 Digitale Signalverarbeitung
Betrachtet man das bisher gezeigte Vorgehen, kommt zwangsläufig die Frage auf, für welche der zahlreichen Fensterfunktion man sich denn nun entscheiden soll. Leider kann dies nicht eindeutig beantwortet werden, sondern hängt von den jeweiligen Anforderungen ab. Wie nicht anders zu erwarten, beeinflussen die verschiedenen Fenster den resultierenden Frequenzgang in unterschiedlicher Weise. Die Wahl einer geeigneten Funktion ist aus diesem Grund immer nur anwendungsspezifisch möglich. In den meisten Fällen sind jedoch das Hanning-, Hamming- oder das BlackmanFenster eine gute Wahl. Sie haben sich zu Recht als echte Arbeitspferde in der digitalen Signalverarbeitung etabliert. Nun gut, aber was ist, wenn kein Tiefpaßfilter benötigt wird, sondern ein Hochpaß, ein Bandpaß oder eine Bandsperre? Gibt es für diese Fälle auch eine Formel, mit deren Hilfe man die Filterkoeffizienten ohne großen Aufwand berechnen kann, oder bleibt hier nur die IDFT? Tatsächlich gibt es noch einen dritten Weg, nicht ganz so einfach wie die Benutzung von Gln. (1.42), viel komplizierter aber auch nicht. Dieser neue Weg nutzt den Umstand, daß sich aus einem Tiefpaß auch die anderen Filtertypen entwickeln lassen. Alles was wir dafür noch benötigen, ist ein Allpaßfilter, also ein Filter, dessen Durchlaßbereich von f = 0 bis f = reicht, d. h. es gilt |HAP(f)| = 1 für sämtliche Frequenzen. Schauen wir noch einmal auf Abb. 1.23 und führen uns dabei das Übertragungsverhalten eines Allpaßfilters vor Augen, dann kann man leicht nachvollziehen, daß sich z. B. ein Hochpaß aus der Differenz von Allpaß und Tiefpaß ergibt. Mit Allpaß, Tiefpaß und Hochpaß lassen sich dann durch Addition bzw. Subtraktion auch Bandpaß und Bandsperre konstruieren. Für normierte Frequenzgänge, also solche mit einem Verstärkungsfaktor = 1, gelten dann die folgenden Zusammenhänge. Hochpaß:
H HP ( f ) = H AP ( f ) − H TP ( f ) H HP ( f ) = 1 − H TP ( f )
(1.44)
Bandpaß:
H BP ( f ) = H TP ( f ) + H HP ( f ) − H AP ( f ) H BP ( f ) = H TP ( f ) + H HP ( f ) − 1 mit
f g TP > f g HP
(1.45)
1.11 Digitale Filter
61
Bandsperre:
H BS ( f ) = H AP ( f ) − H BP ( f ) H BS ( f ) = 1 − H BP ( f )
(1.46)
Die Gleichungen dienen eigentlich nur dem Zweck, die Richtigkeit unseres Entwurfsverfahrens zu veranschaulichen. Wirklich anwenderfreundlich wird es durch die Tatsache, daß die exakt gleichen Beziehungen auch für die Filterkoeffizienten h(k) im Zeitbereich gelten, d. h. wir müssen diese nur in geeigneter Weise addieren und subtrahieren, um den jeweils gewünschten Filtertyp zu erhalten. Bleibt eigentlich nur noch zu klären, wie denn die Koeffizienten eines Allpaßfilters aussehen könnten. Hier hilft erneut ein Blick auf Tabelle 1.4 weiter. Ein Allpaß hat genau einen Filterkoeffizienten, da wir normierte Filter betrachten, hat dieser den Wert Eins. Damit der Entwurf funktioniert, ist der AP-Koeffizient mit dem jeweils zentralen Koeffizienten unserer TP/HP/BP/BS-Filter zu addieren bzw. zu subtrahieren. class Filter { const int Abtastwerte = 128; const double PI = 3.141592653589793; // Filterkoeffizienten public double[] x = new double[Abtastwerte]; public int filterlaenge; ... public void TPKoeffizienten(double fg) { double sum = 0; for (int k=0; k
62
1 Digitale Signalverarbeitung } // Normierung der Koeffizienten for (int k=0; k
} } 0,4
h(k)
0,3 0,2 0,1 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,1
k
Abb. 1.35. Koeffizienten eines Tiefpaßfilters mit fg/fa = 0,15 1,2 1
|H(f)|
0,8 0,6 0,4 0,2
f/fa
Abb. 1.36. TP-Amplitudengang mit fg/fa = 0,15
class Filter { ... public void HPKoeffizienten(double fg) { // Basis für den Entwurf ist ein Tiefpass TPKoeffizienten(fg); // Tiefpass invertieren
0,5
0,46
0,43
0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0
0,04
0
1.11 Digitale Filter
for (int k=0; k
h(k)
0,2 0,1 0 -0,1
0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,2 -0,3
k
Abb. 1.37. Koeffizienten eines Hochpaßfilters mit fg/fa = 0,35 1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,5
0,46
0,43
0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0 -0,2
0,04
0
f/fa
Abb. 1.38. HP-Amplitudengang mit fg/fa = 0,35
class Filter { ... public void BPKoeffizienten(double fg1, double fg2) { // lokale Kopien double[] htp = new double[filterlaenge]; double[] hhp = new double[filterlaenge];
63
64
1 Digitale Signalverarbeitung TPKoeffizienten(fg2); for (int k=0; k
} } 0,5 0,4 0,3
h(k)
0,2 0,1 0 -0,1 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,2 -0,3 -0,4
k
Abb. 1.39. Koeffizienten eines Bandpaßfilters mit fg1/fa = 0,15 und fg2/fa = 0,35
1.11 Digitale Filter 1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,5
0,46
0,43
0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0
0,04
0 -0,2
f/fa
Abb. 1.40. BP-Amplitudengang mit fg1/fa = 0,15 und fg2/fa = 0,35
class Filter { ... public void BSKoeffizienten(double fg1, double fg2) { // Basis für den Entwurf ist ein Bandpass BPKoeffizienten(fg1, fg2); // Bandpass invertieren for (int k=0; k
h(k)
0,4 0,3 0,2 0,1 0 -0,1 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-0,2
k
Abb. 1.41. Koeffizienten eines Bandsperrefilters mit fg1/fa = 0,15 und fg2/fa = 0,35
65
66
1 Digitale Signalverarbeitung 1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,5
0,46
0,43
0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0
0,04
0
f/fa
Abb. 1.42. BS-Amplitudengang mit fg1/fa = 0,15 und fg2/fa = 0,35
Von den FIR-Koeffizienten zum Frequenzgang Bei der Fenstermethode wird ein Frequenzgang vorgegeben, um daraus die gesuchten Filterkoeffizienten zu ermitteln. Besonders für die Filteranalyse ist aber auch der umgekehrte Weg von Nutzen. Hier kommt es darauf an, aus den bekannten Koeffizienten auf das Übertragungsverhalten zu schließen. Denkbar ist aber auch, daß die Koeffizienten zu modifizieren sind, um den Frequenzgang des Filters an veränderte Randbedingungen anzupassen. Wir wollen daher in diesem Abschnitt den unmittelbaren Zusammenhang zwischen Filterkoeffizienten und Frequenzgang näher untersuchen. Wie schon aus Gln. (1.34) bekannt, ergibt sich die Übertragungsfunktion eines Filters durch z-Transformation der Impulsantwort und kann somit direkt aus den Filterkoeffizienten berechnet werden. Glücklicherweise ist das genauso einfach, wie es auf den ersten Blick erscheint, Computer sei Dank. Die DFT als Sonderfall der z-Transformation ist hierfür hervorragend geeignet und steht uns auch schon als Implementierung zur Verfügung. Von einigen kleinen Änderungen einmal abgesehen, kann auf den alten Quellcode zurückgegriffen werden. Notwendige Anpassungen ergeben sich aus dem Umstand, daß bei der Bestimmung des Übertragungsverhaltens der interessierende Frequenzbereich manchmal kleiner ist als bei der Spektralanalyse und die betrachteten Frequenzen dementsprechend nicht nur ganzzahlige Vielfache der Grundschwingung sind. Auf die bei der DFT vorgenommene Korrektur des Gleichanteils und die Normierung auf die Abtastwerte kann verzichtet werden. Als Testsignal sind dann einfach die Filterkoeffizienten selbst zu nehmen. class Filter { ... public void ErzeugeTestsignal_1()
1.11 Digitale Filter
67
{ int M = 10; for (int k=0; k
68
1 Digitale Signalverarbeitung 1,2 1 3 Punkte
|H(f)|
0,8 0,6 0,4
10 Punkte
0,2 0,5
0,46
0,43
0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0
0,04
0
f/fa
Abb. 1.43. Amplitudenfrequenzgang eines Mittelwertfilters mit 3 und 10 Werten
Verwendet man die Koeffizienten eines Mittelwertfilters, dann zeigt der resultierende Amplitudenfrequenzgang dessen typische Tiefpaßeigenschaft. Wegen der geringen Flankensteilheit im Übergangsbereich und der ausgeprägten Welligkeit im Sperrbereich eignen sich Mittelwertfilter nicht besonders gut zur Trennung verschiedener Signalfrequenzen. Vielmehr werden sie meist zur Reduktion zufälliger Störungen in Meßsignalen eingesetzt. Dabei wächst die Störgrößenunterdrückung des Mittelwertfilters erwartungsgemäß mit der Anzahl der einbezogenen Meßwerte. Je mehr Werte man verwendet, desto zuverlässiger werden die überwiegend hochfrequenten Störungen auch tatsächlich herausgefiltert. Abhängig von der Filterbreite M und der Abtastfrequenz fa werden bestimmte Frequenzanteile sogar vollständig unterdrückt.
H( f =
n ⋅ fa ) = 0 für n ganzzahlig M
Letztlich sind FIR-Filter ein Spezialfall der allgemeineren IIR-Filter. Nur haben bei ihnen sämtliche Koeffizienten des Rückkopplungszweiges den Wert Null. Bezüglich der Entwurfs- und der Analysemöglichkeiten von FIR-Filtern im Frequenzbereich (basierend auf deren Nullstellen in der z-Ebene) sei deshalb auf die nächsten Abschnitte verwiesen.
1.11 Digitale Filter
69
1.11.6 IIR-Filter
IIR-Filter bilden im Zeitbereich rekursive Differenzengleichungen mit konstanten Koeffizienten. Als Beispiel soll an dieser Stelle die rekursive Variante unserer schon bekannten Mittelwertbildung aus fünf Meßwerten dienen.
y (k ) = y (k − 1) +
x(k ) x(k − 5) − 5 5
1 1 Y ( z ) = z −1 ⋅ Y ( z ) + ⋅ X ( z ) − ⋅ z − 5 ⋅ X ( z ) 5 5 Y (z) Y ( z ) 1 1 −5 = z −1 ⋅ + − ⋅z X ( z) X ( z) 5 5 H ( z ) = z −1 ⋅ H ( z ) + H ( z ) ⋅ (1 − z −1 ) =
1 1 −5 − ⋅z 5 5
1 1 −5 − ⋅z 5 5
1 5 − 1 5 ⋅ z −5 1 − z −1
H ( z) =
Natürlich kann auch hier allgemeiner formuliert werden und man erhält die rekursive Differenzengleichung und die daraus resultierende Übertragungsfunktion im z-Bereich.
y (k ) = a0 ⋅ x(k ) + a1 ⋅ x(k − 1) + a2 ⋅ x(k − 2) + ... + aM ⋅ x(k − M ) + b1 ⋅ y (k − 1) + b2 ⋅ y (k − 2) + ... + bN ⋅ y (k − N ) M
¦a
k
H ( z) =
k =0 N
⋅ z−k
1 − ¦ bk ⋅ z − k
a0 + a1 ⋅ z −1 + a2 ⋅ z − 2 + ... + aM ⋅ z − M (1.47) = 1 − b1 ⋅ z −1 + b2 ⋅ z − 2 + ... + bN ⋅ z − N
k =1
Die Übertragungsfunktion H(z) bildet eine gebrochen rationale Funktion in Abhängigkeit von den konstanten Koeffizienten ak und bk. Sie bestimmen das Filterverhalten im Zeit- und Frequenzbereich. Hierbei sind die Koeffizienten bk die Gewichtungen der vorhandenen Rückkopplungszweige. Genau diese Rückkopplungen sind es aber, die rekursive Filter potentiell instabil machen. Es entspricht der gängigen Vorstellung, daß ein stabiles
70
1 Digitale Signalverarbeitung
System, wenn es kurzzeitig angeregt wird, nach einer gewissen Zeit immer wieder in eine stabile Ruhelage zurückkehrt. Sind jedoch Rückkopplungen vorhanden, kann es im ungünstigsten Fall vorkommen, daß die auf den Eingang rückwirkende Systemantwort zu einem unerwünschten Aufschaukeln des Systems führt. Jeder von uns kennt wohl das Phänomen der akustischen Rückkopplung bei einer Verstärkeranlage. Kommt man hier mit dem Mikrophon zu nahe an den Lautsprecher, dann macht sich die resultierende Instabilität als unangenehmes Pfeifen bemerkbar. Instabilitäten entstehen immer dann, wenn das Rückkopplungssignal das externe Eingangssignal positiv verstärkt. Für Untersuchungen bezüglich der Stabilität eines Filters im Frequenzbereich ist es notwendig, das Nennerpolynom der Übertragungsfunktion näher zu betrachten. Wird der Nenner Null, dann geht H(z) gegen Unendlich. Die Nullstellen des Nenners, Polstellen genannt, kennzeichnen also den Stabilitätsbereich des Filters und sind daher von besonderem Interesse. Allerdings sind sie in der Darstellung von Gln. 1.47 nur sehr schwer zu erkennen, weshalb wir eine geeignete Umformung wählen. Zunächst definieren wir g = max{M,N} und erweitern anschließend Zähler und Nenner mit zg.
H ( z) =
a0 ⋅ z g + a1 ⋅ z g −1 + a2 ⋅ z g − 2 + ... + aM ⋅ z g − M z g − b1 ⋅ z g −1 + b2 ⋅ z g − 2 + ... + bN ⋅ z g − N
Mit diesem Schritt ist eigentlich noch nichts gewonnen. Die Exponenten sind jetzt alle positiv und man erkennt, daß Zähler und Nenner gewöhnliche Polynome sind, mit einer dem Polynomgrad entsprechenden Anzahl von Nullstellen. Bestimmt man diese Nullstellen, läßt sich H(z) auch in Produktform darstellen.
H ( z) =
a0 ⋅ ( z − z01 ) ⋅ ( z − z02 )...( z − z0 M ) ( z − z X 1 ) ⋅ ( z − z X 2 )...( z − z XN )
(1.48)
In dieser Darstellung sind z0k die Nullstellen und zXk die Polstellen des Filters. Aufgrund der reellen Filterkoeffizienten sind sie entweder auch reell oder liegen paarweise konjugiert komplex vor. Dabei kann es durchaus vorkommen, daß Pol- und Nullstellen gleich sind und sich gegenseitig herauskürzen. Sie sind zudem durch die Filterkoeffizienten eindeutig festgelegt, weshalb die Vermutung nahe liegt, daß der Frequenzgang auch direkt aus ihnen bestimmt werden kann. Tatsächlich ist dem so.
1.11 Digitale Filter
71
Entwurf und Analyse von IIR-Filtern Man kann sich leicht vorstellen, daß es mehrere Vorgehensweisen gibt, IIR-Filter mit definierten Eigenschaften zu entwerfen. Der klassische Weg besteht bekanntlich darin, daß man sich das gewünschte Übertragungsverhalten vorgibt und hieraus ein Filter entwirft, das dieser Charakteristik möglichst nahe kommt. Speziell für rekursive Filter seien an dieser Stelle die Impulsinvarianzmethode und die Bilineartransformation erwähnt. Beide Verfahren lassen sich aber nicht annähernd so leicht implementieren, wie die nachfolgend vorgestellten Methoden. Der Pol-Nullstellen-Plan Eine besonders anschauliche geometrische Interpretation des komplexen Frequenzganges nach Gln. (1.48) erhält man, wenn man die Lage der Pole und Nullstellen in der z-Ebene betrachtet und dabei die Frequenz entlang des Einheitskreises laufen läßt. Für ein Filter zweiter Ordnung mit zwei Pol- und Nullstellen ist dies hier einmal aufgezeigt. Im(z)
L 01
P
L X1
Re(z) L 02
L X2
Nullstelle Polstelle
Abb. 1.44. Interpretation des Frequenzganges aus dem Pol-Nullstellen-Plan
Die einzelnen Faktoren der Zähler- und Nennerprodukte in der Produktform von H(z) lassen sich als Differenzzeiger auffassen, die jeweils von den ortsfesten Polstellen bzw. Nullstellen zu dem veränderlichen Punkt P führen. Mit zunehmender Frequenz läuft dieser Punkt entgegen dem Uhrzeigersinn auf dem Einheitskreis entlang, wobei die Zeiger ihre Länge und Richtung ähnlich einem Gummiband verändern. Den Amplitudengang des Filters gewinnt man einfach durch Betragsbildung und Multiplikation der
72
1 Digitale Signalverarbeitung
einzelnen Zeiger. Aus der Summation der Zeigerwinkel, von der reellen Achse aus gesehen im mathematisch positiven Sinn, kann anschließend noch der Phasengang bestimmt werden. Amplitudengang und Phasengang bilden zusammen schließlich den komplexen Frequenzgang des Filters. Um das hier beschriebene Verfahren als Algorithmus zu realisieren, ist nur noch ein wenig elementare Vektorrechnung notwendig. Der Verlauf des frequenzabhängigen Punktes P ergibt sich mit Hilfe der Parameterdarstellung des Kreises. An dieser Stelle kommt die Abtastfrequenz fa ins Spiel. Sie dient lediglich zur Normierung und sorgt dafür, daß unsere Frequenz den Halbkreis von 0..ʌ durchläuft.
§ cos(2π f f a ) · f ¸¸ mit 0 ≤ f ≤ a P( f ) = ¨¨ 2 © sin(2π f f a ) ¹
Li = PZ i = (ℜ ( P) − ℜ ( Z i )) 2 + (ℑ ( P) − ℑ ( Z i )) 2 Ausgangspunkt der Implementierung ist aber zunächst die Schaffung einer geeigneten Struktur für die Datenhaltung, einmal für die Darstellung komplexer Zahlen und hierauf aufbauend eine Klasse für die Pol- und Nullstellen (auch Wurzeln genannt). struct komplex // für komplexe Zahlen { public double re; public double im; } class wurzel // für Pol- und Nullstellen { public int anzahl; public komplex[] z; public wurzel(int dim) { this.anzahl = 0; this.z = new komplex[dim]; } } class Filter { ... const int MaxPole = 10; // max. Zahl Polstellen const int MaxZero = 10; // max. Zahl Nullstellen
1.11 Digitale Filter
73
public wurzel Null = new wurzel(MaxZero); public wurzel Pol = new wurzel(MaxPole); ... public void PolNullFrequenzgang() { double[] Lo = new double[Null.anzahl]; double[] Lx = new double[Pol.anzahl]; double Lre = 0; // Zeiger-Realteil double Lim = 0; // Zeiger-Imaginärteil double Po = 0; // Produkt der Nullstellenzeiger double Px = 0; // Produkt der Polstellenzeiger double fa = 1.0; // normierte Abtastfrequenz double startf = 0.0; // Startfrequenz double stopf = 0.5; // Stopfrequenz double deltaf = (stopf-startf)/(Abtastwerte-1); double freq = startf; for (int i=0; i
74
1 Digitale Signalverarbeitung PS[i] -= Math.Atan2(Lim, Lre); } AS[i] = Po/Px; freq += deltaf; }
} ... }
Auf der Basis manuell eingegebener Pol- und Nullstellen kann somit der resultierende Frequenzgang berechnet werden, wobei leichte Variationen in der Eingabe sich entsprechend im Frequenzgang niederschlagen. Die gezielte und iterative Umsetzung dieses Sachverhaltes erlaubt es einem Anwender, ein wenig Erfahrung ist hier natürlich sehr hilfreich, ein Filter mit den gewünschten Eigenschaften zu entwerfen. Hält man sich noch zusätzlich an ein paar einfache Grundregeln, erleichtert das die Arbeit ganz erheblich. • Für den Entwurf stabiler Filter ist es notwendig, daß ausnahmslos alle Polstellen im inneren des Einheitskreises liegen. Ein außerhalb des Einheitskreises liegender Pol hat eine exponentiell ansteigende Impulsantwort (und damit Instabilität) zur Folge. • Polstellen und Nullstellen sind immer entweder reell oder treten konjugiert komplex auf. Diese Einschränkung resultiert aus den reellen Koeffizienten, die für ein realisierbares Filter zwingend sind. • Je näher die Nullstellen am Einheitskreis liegen, desto kleiner ist deren Abstand zum frequenzabhängigen Punkt P und desto mehr tragen sie zur Bedämpfung der jeweiligen Frequenz bei. • Polstellen in der Nähe des Einheitskreises führen dagegen zu einer Anhebung des Amplitudenganges, da das Nennerprodukt bei der betreffenden Frequenz dann sehr klein wird. Einer Überprüfung dieser Regeln steht nun nichts mehr im Wege. Ausgangspunkt für die weiteren Untersuchungen sollen Filter zweiter Ordnung sein, wie sie als Grundbausteine beim Filterentwurf typisch sind. In den folgenden Beispielen sollte man sich nicht mehr über die doppelte Nullstelle im Koordinatenursprung wundern. Sie resultiert aus der Erweiterung von Zähler und Nenner von H(z) mit z2. Ist nur der Amplitudenfrequenzgang von Interesse, könnte man sie eigentlich auch weggelassen. Tatsächlich haben Pol- und Nullstellen im Koordinatenursprung keinen Einfluß auf den Amplitudenfrequenzgang, sondern wirken sich nur auf den Phasenfrequenzgang aus, wie man sich leicht mit Hilfe von Abb. 1.44 überlegen kann.
75
1.11 Digitale Filter Tabelle 1.7. Einfluß der Polstellen auf das Übertragungsverhalten
Im(z)
5
|H(f)|
4
Re(z)
3 2 1
0,5
0,46
0,43
0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z) =
1 1 − z + 0.25 ⋅ z − 2 −1
Im(z)
4
|H(f)|
3 2 1
Re(z)
0,28
0,32
0,35
0,39
0,43
0,46
0,5
0,28
0,32
0,35
0,39
0,43
0,46
0,5
0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z) =
1 1 − z + 0 .5 ⋅ z − 2 −1
Im(z) |H(f)|
2
1
Re(z) 0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z) =
1 1 + 0.25 ⋅ z − 2
76
1 Digitale Signalverarbeitung
Im(z)
4
|H(f)|
3 2 1
Re(z)
0,28
0,32
0,35
0,39
0,43
0,46
0,5
0,32
0,35
0,39
0,43
0,46
0,5
0,25
0,28
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z) =
1 1 + z + 0 .5 ⋅ z − 2 −1
Im(z)
5
|H(f)|
4
Re(z)
3 2 1
0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z) =
1 1 + z + 0.25 ⋅ z − 2 −1
Selbstverständlich können wir FIR-Filter als Sonderfall der allgemeineren IIR-Filter ebenfalls mit dieser Methode entwerfen. Wir erinnern uns, daß FIR-Filter zwar auch Polstellen besitzen, diese aber alle im Koordinatenursprung der z-Ebene liegen. Nachfolgend dargestellt ist daher ihr Übertragungsverhalten bei Variation der Nullstellen. Die unten aufgeführten Beispiele entstehen durch Vertauschen von Polstellen und Nullstellen in Tabelle 1.7. Im Ergebnis erhält man den jeweils komplementären Filtertyp. Aus einem Tiefpaß wird somit ein Hochpaß, aus einem Bandpaß wird eine Bandsperre und umgekehrt.
77
1.11 Digitale Filter Tabelle 1.8. Einfluß der Nullstellen auf das Übertragungsverhalten
Im(z)
3
|H(f)|
2
1
Re(z) 0,5
0,46
0,43
0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z ) = 1 − z −1 + 0.25 ⋅ z −2 Im(z)
3
|H(f)|
2
1
Re(z) 0,28
0,32
0,35
0,39
0,43
0,46
0,5
0,28
0,32
0,35
0,39
0,43
0,46
0,5
0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z ) = 1 − z −1 + 0.5 ⋅ z −2 Im(z) |H(f)|
2
1
Re(z) 0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z ) = 1 + 0.25 ⋅ z −2
78
1 Digitale Signalverarbeitung
Im(z)
3
|H(f)|
2
1
Re(z) 0,28
0,32
0,35
0,39
0,43
0,46
0,5
0,32
0,35
0,39
0,43
0,46
0,5
0,25
0,28
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z ) = 1 + z −1 + 0.5 ⋅ z −2 Im(z)
3
|H(f)|
2
1
Re(z) 0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
H ( z ) = 1 + z −1 + 0.25 ⋅ z −2 Von den IIR-Koeffizienten zum Frequenzgang Mit dem vorigen Abschnitt beschriebenen Verfahren verfügt man über ein für den Filterentwurf und die Filteranalyse gleichermaßen geeignetes Werkzeug. Trotzdem ist der Gedanke, daß dies nur über die Polstellen und Nullstellen der komplexen Übertragungsfunktion möglich sein soll, doch irgendwie unbefriedigend. Vielmehr wird man völlig zu recht erwarten, den Frequenzgang von IIR-Filtern auch direkt aus ihren Filterkoeffizienten berechnen zu können. Das hat schließlich auch schon bei den FIR-Filtern funktioniert. IIR-Filter bestehen aus zwei Signalzweigen, die sich völlig unabhängig voneinander betrachten lassen. Zum einen der Vorwärtszweig (Zähler von H(z)), der den FIR-Anteil repräsentiert, zum anderen der Rückkopplungszweig (Nenner von H(z)). Was für den Vorwärtszweig schon möglich war, sollte doch auch für den Rückkopplungsteil gehen. Natürlich sind beide Zweige nicht ganz gleichberechtigt, da es schließlich reine Vorwärtsfilter gibt, wogegen jedoch ein reines Rückkopplungsfilter aufgrund der dann fehlenden Eingangswerte keinen Sinn macht. Trotz dieser Einschränkung
1.11 Digitale Filter
79
kann die Übertragungsfunktion von IIR-Filtern als Quotient zweier eigenständiger Filterfunktionen HZ(z) und HN(z) gesehen werden. M
H ( z) =
H Z ( z) = H N ( z)
¦a
⋅ z −k
¦b
⋅ z−k
k
k =0 M
k
k =0
Wird auf b0 normiert und läßt man auch noch unterschiedliche Filterordnungen für Zähler und Nenner zu, dann entspricht dieser Ausdruck der allgemeinen Übertragungsfunktion, wie wir sie schon in Gln. 1.47 definiert haben. Die Abweichung an dieser Stelle bedeutet aber keine Beschränkung der Allgemeinheit. Selbstverständlich läßt sich jetzt separat für beide Zweige durch z-Transformation der Impulsantwort (sie ist identisch mit den jeweiligen Koeffizienten ak, bk) das gesuchte Übertragungsverhalten berechnen. Das sich schließlich der Frequenzgang H(f) des Gesamtsystems durch Quotientenbildung der Teilfrequenzgänge ergibt, entspricht wohl der allgemeinen Erwartung. Genau wie schon bei den FIR-Filtern, werden wir jedoch anstelle der z-Transformation die viel leichter zu implementierende DFT verwenden.
H( f ) =
HZ ( f ) HN ( f )
=
DFT (ak ) DFT (bk )
ϕ ( f ) = ϕZ ( f ) − ϕ N ( f ) class Filter { ... // Filterkoeffizienten des Vorwärtszweiges public double[] a = new double[Abtastwerte]; // Filterkoeffizienten des Rückkopplungszweiges public double[] b = new double[Abtastwerte]; // Amplitudengang des Zählers von H(z) public double[] Az = new double[Abtastwerte]; // Amplitudengang des Nenners von H(z) public double[] An = new double[Abtastwerte]; // Phasengang des Zählers von H(z) public double[] Pz = new double[Abtastwerte]; // Phasengang des Nenners von H(z) public double[] Pn = new double[Abtastwerte]; // Amplitudengang von H(z) public double[] AS = new double[Abtastwerte];
(1.49) (1.50)
80
1 Digitale Signalverarbeitung
// Phasengang von H(z) public double[] PS = new double[Abtastwerte]; ... public void ErzeugeTestsignal_2() { // Filterkoeffizienten des Vorwärtszweiges a[0] = 1; a[1] = 0; a[2] = 0; // Filterkoeffizienten des Rückkopplungszweiges b[0] = 1; b[1] = -1; b[2] = 0.5; for (int k=3; k Zähler von H(z) Az[i] = Math.Sqrt(real*real + imag*imag); Pz[i] = Math.Atan2(imag, real);
1.11 Digitale Filter
81
real = 0; imag = 0; // über alle Rückkopplungskoeffizienten b[k] for (int k=0; k Nenner von H(z) An[i] = Math.Sqrt(real*real + imag*imag); Pn[i] = Math.Atan2(imag, real); // Gesamtsystem -> H(z)= Hz(z)/Hn(z) if (An[i] > 0) { // IIR-Filter AS[i] = Az[i]/An[i]; } else { // FIR-Filter AS[i] = Az[i]; } PS[i] = Pz[i]-Pn[i]; freq += deltaf; } } ... }
1.11.7 Der Phasengang
In unseren Betrachtungen digitaler Systeme stand bisher ausschließlich der Amplitudengang im Vordergrund. Aber erst Amplitudengang und Phasengang gemeinsam beschreiben die Frequenzabhängigkeit eines Systems vollständig, bilden also den Frequenzgang H(f) entsprechend Gln. (1.36). Üblicherweise verändern Signale beim Durchlaufen digitaler Systeme nicht nur ihre spektrale Zusammensetzung, sie werden zusätzlich auch mehr oder weniger stark verzögert, d. h. das Signal am Systemausgang eilt dem am Eingang anliegenden Signal nach. Die Verschiebung des (sinusförmigen) Ausgangssignals gegenüber dem (sinusförmigen) Eingangssignal wird gerade durch den Phasengang beschrieben.
82
1 Digitale Signalverarbeitung
Neben der gezielten spektralen Veränderungen eines Signals durch frequenzselektive Filter, also die Verstärkung oder Unterdrückung bestimmter Frequenzanteile, wirkt auch dessen Phasengang auf den Signalverlauf. Eine solche zusätzliche Abhängigkeit, die sich als laufzeitbedingte Verzerrung bemerkbar macht, ist in den meisten Anwendungen aber unerwünscht. Man greift daher bevorzugt auf solche Filter zurück, deren Phasengang keinen Einfluß auf die Signalform hat. Allgemein bezeichnet man Filter mit dieser Eigenschaft als linearphasig. FIR-Filter, mit beidseitig um ein Zentralelement symmetrischen Filterkoeffizienten, besitzen gerade die Eigenschaft der Linearphasigkeit. IIR-Filter dagegen haben meist einen nichtlinearen Phasengang, was bei der Übertragung von Pulsen zu einer asymmetrischen Verschiebung des ursprünglich symmetrischen Signals führt. 1.11.8 Vergleich zwischen FIR- und IIR-Filtern
Nachdem wir uns in den vorangegangenen Abschnitten ausführlich mit FIR- und IIR-Filtern beschäftigt haben, ist deutlich geworden, daß sich beide Filterarten in vielerlei Hinsicht unterscheiden. FIR-Filter besitzen keinen Rückkopplungszweig und sind aus diesem Grund auch für beliebige Koeffizienten immer stabil. Da ihre Impulsantwort grundsätzlich frei wählbar ist, haben sie unter Umständen einen Frequenzgang, für den kein entsprechendes analoges Filter existiert. Möchte man einen vorgegebenen Frequenzgang mit einem FIR-Filter nachbilden, ist das oft nur mit sehr langen Filtern hoher Ordnung möglich. Als Softwareimplementierung beansprucht es dann auch viel Speicherplatz und verursacht relativ lange Rechenzeiten. Ein wesentlicher Vorteil von FIRFiltern (neben ihrer Stabilität) ist der Umstand, daß es mit ihnen leicht möglich ist einen linearen Phasengang und eine konstante Gruppenlaufzeit zu realisieren, was sie unter anderem für Anwendungen im Audio-Bereich sehr attraktiv macht. IIR-Filter haben in den meisten Fällen ein analoges Gegenstück, lassen sich also auch mit Hilfe von Operationsverstärkern, Widerständen und Kondensatoren als elektronische Schaltung realisieren. Sie kommen daher vorzugsweise dann zum Einsatz, wenn es darum geht die Eigenschaften eines bekannten Analogfilters durch ein Digitalfilter nachzubilden. Die notwendige Filterordnung ist zudem, bei vergleichbarer Selektivität, deutlich geringer als bei einem FIR-Filter, was den Speicherbedarf und die erforderliche Rechenzeit stark reduziert. Ein latentes Problem bei IIR-Filtern ist deren Stabilität, insbesondere dann, wenn ihre Polstellen in der z-Ebene nahe am Einheitskreis liegen. Selbst wenn das entworfene Filter im Einsatz stabil ist, kann es doch vorkommen, daß das tatsächliche Übertragungsverhalten nach
1.11 Digitale Filter
83
der Implementierung durch Rundungs- oder Abschneidefehler der Koeffizienten vom ursprünglichen Entwurf abweicht. 1.11.9 FFT-Filter
Egal ob wir bisher mit FIR-Filtern oder mit IIR-Filtern gearbeitet haben, eines war immer klar, die Filterung ist eine mathematische Operation, die auf die Eingangswerte x(k) im Zeitbereich angewendet wird. Betrachtungen im Frequenzbereich waren dagegen nur ein zusätzliches Hilfsmittel, um die erforderlichen Eigenschaften zu definieren oder unbekannte Eigenschaften zu analysieren. Mit dem jetzt vorgestellten FFT-Filter kehren sich die Verhältnisse um. In der Regel definieren sich Filter über ihr Verhalten im Frequenzbereich. Konsequenterweise gibt es deshalb auch Entwurfsverfahren, z. B. die Fenstermethode, bei denen man einen gewünschten Frequenzgang einfach vorgeben kann. Leider kränkelte die Umsetzung dieses an sich doch richtigen Ansatzes bisher an der Notwendigkeit die Eigenschaften aus dem Frequenzbereich in den Zeitbereich übertragen zu müssen. Und damit geht der Ärger los. Das gewünschte Frequenzverhalten in reale Filterkoeffizienten abzubilden ist nämlich gar nicht so einfach, wie wir gesehen haben. Man fängt sich eine Reihe von nichtidealen Effekten ein, die sich nur mit sehr viel Aufwand wieder unterdrücken lassen. Da wäre es doch viel günstiger die Filterung ebenfalls im Frequenzbereich ausführen zu können, um diese Schwierigkeiten zu umgehen. Genau das ist mit FFT-Filtern möglich. Zunächst werden die Eingangswerte mittels FFT in den Frequenzbereich transformiert. Anschließend wird das resultierende Spektrum mit dem gewünschten Frequenzgang multipliziert. Dabei kann der Anwender grundsätzlich, ähnlich wie bei einem Equalizer, beliebige Verläufe wählen. In einem letzten Schritt ist das Ergebnis dann wieder mit Hilfe der IFFT in den Zeitbereich zu transformieren. Mit diesem Vorgehen lassen sich Übergangsbereich und Sperrdämpfungen realisieren, wie das mit gewöhnlichen FIR- oder IIR-Filtern kaum möglich wäre. Aus diesem Grund sind FFTFilter besonders in der Audio-Signalverarbeitung weit verbreitet. Tabelle 1.9. Vergleich zwischen FIR-Filtern und IIR-Filtern Merkmal Selektivität Erforderliche Ordnung Speicherbedarf Rechenzeitbedarf Lineare Phase Stabilität Genauigkeit der Koeffizienten
FIR-Filter gering hoch hoch hoch leicht möglich immer mäßig
IIR-Filter hoch gering gering gering kaum möglich bedingt hoch
84
1 Digitale Signalverarbeitung
x(k)
FFT
X(f)
Y(f)
IFFT
y(k)
Abb. 1.45. Funktionsprinzip eines FFT-Filters
1.12 Experimentelle Systemanalyse Schon bei der Einführung der Übertragungsfunktion und des Frequenzganges im Abschn. 1.11.3 wurde darauf hingewiesen, daß es in der Meßund Regelungstechnik üblich ist, ein unbekanntes Übertragungssystem mit geeigneten Testfunktionen zu beaufschlagen, um aus der Systemantwort auf dessen dynamische Eigenschaften zu schließen. Mit unseren jetzt erweiterten Kenntnissen können wir endlich die Möglichkeiten der experimentellen Systemanalyse nutzen. Die Bestimmung der Systemparameter wird auch Identifikation genannt. Als typische Übertragungssysteme in der Signalverarbeitung sind digitale Filter geeignete Testobjekte. Wir sind also nun in der Lage, digitale Filter auf der Basis ihrer Koeffizienten oder ihrer Pol- und Nullstellen zu berechnen. Damit sind sowohl der Zeit-, als auch der Frequenzbereich abgedeckt. Allerdings ist es in beiden Fällen zwingend notwendig, die Koeffizienten oder die Pol- und Nullstellen auch tatsächlich zu kennen, also Zugriff auf die „Innereien“ des Filters zu haben. Es sind aber durchaus Anwendungen denkbar, bei denen das nicht sichergestellt ist, zum Beispiel in verteilten Systemen oder bei der Verwendung von eingekauften Fremdkomponenten. Das Filter ist dann beispielsweise nur über Schnittstellen zugänglich, bildet also eine BlackBox. Sich in solchen Fällen blind auf zugesagte Eigenschaften zu verlassen könnte jedoch sehr teuer werden. 1.12.1 Identifikation im Frequenzbereich
In der Praxis kann es also durchaus zweckmäßig sein, die Eigenschaften eines Systems (oder von Teilen des Systems) von außen zu bestimmen. Aber welche systembeschreibenden Größen stehen hierfür zur Verfügung, wenn doch der direkte Zugriff auf das Innenleben nicht möglich ist? Ein Rückblick auf die Abb. 1.26 und 1.27 sollte die Antwort geben. Natürlich steckt die notwendige Information in dem zugeführten Eingangssignal x(k) und dem resultierenden Ausgangssignal y(k), der Systemantwort. Beide
1.12 Experimentelle Systemanalyse
85
zusammen beschreiben das Übertragungsverhalten eines unbekannten (linearen) Systems vollständig. y ( k ) = h( k ) ∗ x ( k ) Y ( z) = H ( z) ⋅ X ( z) DFT ( y (k )) H (z) = DFT ( x(k )) class Identifikation { const int Abtastwerte = 512; const double PI = 3.141592653589793; ... // Eingangssignal im Zeitbereich public double[] x = new double[Abtastwerte]; // Ausgangssignal im Zeitbereich public double[] y = new double[Abtastwerte]; // Eingangssignal im Frequenzbereich public double[] XA = new double[Abtastwerte]; public double[] XP = new double[Abtastwerte]; // Ausgangssignal im Frequenzbereich public double[] YA = new double[Abtastwerte]; public double[] YP = new double[Abtastwerte]; // Amplitudengang und Phasengang des Testsystems public double[] HA = new double[Abtastwerte]; public double[] HP = new double[Abtastwerte]; ... public void Frequenzgang(double StartFreq, double StopFreq) { double deltaf = (StopFreq-StartFreq)/ (Abtastwerte-1); double freq = StartFreq; double real = 0; double imag = 0; // über alle Frequenzen for (int i=0; i
86
1 Digitale Signalverarbeitung real += x[k]*Math.Cos(2*PI*freq*k/Abtastwerte); imag += x[k]*Math.Sin(2*PI*freq*k/Abtastwerte); } real /= imag /= XA[i] = XP[i] =
Abtastwerte; Abtastwerte; Math.Sqrt(real*real + imag*imag); Math.Atan2(imag, real);
real = 0; imag = 0; // DFT des Ausgangssignals for (int k=0; k
Als „unbekanntes“ Testsystem nehmen wir einfach ein Mittelwertfilter mit M=10 Abtastwerten. Da dessen Amplitudenfrequenzgang aus den bisherigen Betrachtungen schon bekannt sein sollte (Abb. 1.43), lassen sich die Ergebnisse unserer experimentellen Analyse leicht verifizieren. class Identifikation { ... public void Filterung() { int M = 10; double[] a = new double[M];
1.12 Experimentelle Systemanalyse
87
// Mittelwertfilter als Übertragungssystem for (int k=0; k<M; k++) { a[k] = 1.0/(double)M; } // Filterung im Zeitbereich (= Faltung) for (int k=M-1; k
Bis hierhin ist alles klar, man nimmt ein Eingangssignal x(k), legt es an sein unbekanntes Testsystem an und zeichnet die Systemantwort y(k) auf. Aus den Frequenztransformierten X(f), Y(f) beider Signale läßt sich dann der Frequenzgang H(f) unseres Testsystems bestimmen, das dann nicht mehr ganz so unbekannt ist. Wie man sich aber denken kann, sind für das hier beschriebene Verfahren der Systemidentifikation nicht alle Eingangssignale gleichermaßen geeignet. Selbstverständlich ist ein Gleichsignal x(k) = const am Eingang nicht in der Lage eine frequenzabhängige Systemantwort zu provozieren. Die Dynamik eines auf diese Art angeregten Systems bliebe also weiterhin verborgen. Aus diesem Grund greift man zur Messung des Übertragungsverhaltens auf bewährte und standardisierte Testsignale zurück.
Der Einheitsimpuls Grundsätzlich sollte der Einheitsimpuls schon aus früheren Abschnitten bekannt sein. Regt man ein System mit dem Einheitsimpuls an, ergibt sich am Ausgang die Impulsantwort. Warum dieses eigentlich recht unscheinbare Testsignal so besonders aussagekräftig ist, wird sofort klar, wenn man sich erinnert, daß ein idealer Impuls Sinusschwingungen aller Frequenzen mit identischen Amplituden enthält. Das zu untersuchende System wird demzufolge mit allen Frequenzen gleichzeitig angeregt, allein durch eine einzige Messung. In der Analogtechnik ist der mittels Funktionsgenerator erzeugte Impuls als Testfunktion nicht ganz unproblematisch. Wegen seiner nur geringen Signalenergie bleibt die Impulsantwort oft unterhalb der
88
1 Digitale Signalverarbeitung
Nachweisgrenze. Erhöht man zum Ausgleich die Amplitude, läuft man Gefahr das Testsystem zu übersteuern. In der digitalen Signalverarbeitung spielen derartige Probleme dagegen keine Rolle. Wir können ein entsprechendes Testsignal leicht erzeugen und beliebig verschieben.
1 (k = 0) ¯0 (k ≠ 0)
δ (k ) = ®
(1.51)
class Identifikation { ... public void ErzeugeTestsignal_1() { for (int k=0; k
Unser so erzeugter Einheitsimpuls wird nun durch Aufruf der Methode Filterung() auf unser Testsystem geschaltet. Als Ergebnis erhalten wir
die Systemantwort y(k). Mit dem zugeführten Eingangssignal und dem daraus resultierenden Ausgangssignal verfügen wir im Zeitbereich über alle notwendigen systembeschreibenden Informationen. Jetzt sind lediglich noch beide Folgen einer DFT zu unterziehen, um das gesuchte Übertragungsverhalten im Frequenzbereich zu ermitteln.
x(k ) = δ (k ) y ( k ) = h( k ) ∗ δ ( k )
| H( f ) | =
DFT (h(k ) ∗ δ (k )) DFT (δ (k ))
89
1.12 Experimentelle Systemanalyse
0,0025
1,2 1
0,002
|X(f)|
x(k)
0,8 0,6
0,0015 0,001
0,4
0,0005
0,2
0,49
0,46
0,42
0,39
0,35
0,32
0,28
f/fa
k
0,12
0,0025
0,1
0,002
|Y(f)|
0,08
y(k)
0,25
0,21
0,18
0,14
0,11
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
0,07
0 0
0,04
0
0
0,06
0,0015 0,001
0,04 0,0005
0,02
0,42
0,46
0,49
0,46
0,49
0,39
0,35
0,32
0,28
0,42
k
0,25
0,21
0,18
0,14
0,11
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
0,07
0 0
0,04
0
0
f/fa
1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,39
0,35
0,32
0,28
0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
Abb. 1.46. Bestimmung der Übertragungsfunktion |H(f)| mit Hilfe des Einheitsimpulses als Testsignal
Das erzielte Ergebnis kann eigentlich niemanden mehr überraschen. Ein Einheitsimpuls am Eingang unseres FIR-Filters ergibt als Filterantwort die Filterkoeffizienten selbst. Das durch sie gebildete Rechtecksignal hat als Spektrum eine Spaltfunktion, welche der Pulsweite entsprechend aufgefächert ist. Bei unserem unendlich schmalen Eingangspuls entartet diese Spaltfunktion zu X(f) = const. Somit läßt sich im vorliegenden Fall der Verlauf von H(f) = Y(f)/X(f) durch einige kurze Überlegungen verifizieren. In den nachfolgenden Beispielen ist das leider nicht mehr ganz so einfach.
Der Einheitssprung Die in der Regelungstechnik am häufigsten benutzte Testfunktion ist der Einheitssprung ı(t). Mathematisch gesehen handelt es sich hierbei um das Integral des Einheitsimpulses. Ein großer Vorteil der Sprungfunktion besteht darin, daß das Testsystem nur mit einer einzigen Zustandsänderung, von Null auf Eins, beaufschlagt wird (anders als beim Impuls, bei dem es zwei direkt aufeinanderfolgende Zustandsänderungen sind). Aus diesem
90
1 Digitale Signalverarbeitung
Grund läßt sich eine Sprungfunktion durch einen analogen Funktionsgenerator auch leichter erzeugen, als ein Impuls. Die resultierende Systemantwort wird als Sprungantwort oder Übergangsfunktion bezeichnet.
0 (k ≤ 0) ¯1 (k > 0)
σ (k ) = ®
(1.52)
Ganz frei von Problemen ist auch die digitale Signalverarbeitung nicht. Schauen wir doch einmal genauer auf die Definition der Sprungfunktion. Zunächst ist sie Null, bis sie zu einem bestimmten Zeitpunkt auf den Wert Eins springt und diesen beibehält. Auf den ersten Blick nicht weiter spektakulär, denkt man aber länger darüber nach, stellt sich die Frage, was kommt eigentlich nach dem Sprung? Oder noch viel wichtiger, wie interpretiert die DFT das Ende des Abtastintervalls? Die DFT geht implizit von periodischen Signalen aus, somit würde am Intervallende ein Rücksprung von Eins auf Null stehen. Unser Testsignal wäre dann ein Rechteck, dessen Länge von der ansteigenden Flanke (Zeitpunkt frei wählbar) bis zum Intervallende reicht. Unterschiedlich weite Rechtecke oder Pulse besitzen aber
1,2
0,3
1
0,25
|X(f)|
0,6
0,2 0,15
0
0,49
0,46
0,42
0,39
0,35
0,32
0,28
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
k
f/fa
1,2
0,3
1
0,25 0,2
|Y(f)|
0,8 0,6
0,15
0,4
0,1
0,2
0,05 0,28
0,32
0,35
0,39
0,42
0,46
0,49
0,28
0,32
0,35
0,39
0,42
0,46
0,49
k
0,25
0,21
0,18
0,14
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
0,11
0
0
0,07
0
0
0,04
y(k)
0,25
0,21
0,18
0,14
0
0
0,11
0,2
0,07
0,05 0,04
0,1
0,4
0
x(k)
0,8
f/fa
1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
Abb. 1.47. Bestimmung der Übertragungsfunktion |H(f)| mit Hilfe des Einheitssprungs als Testsignal
1.12 Experimentelle Systemanalyse
91
auch unterschiedliche Spektren, wie Abschn. 1.5 gezeigt hat. Für Untersuchungen im Frequenzbereich ist das jedoch ungünstig. Besser wäre es, den scheinbaren Rücksprung für die DFT irgendwie auszublenden. Abhilfe schafft auch hier wieder, wie sollte es auch anders sein, eine Fensterung. Wird die Dauer der Sprungfunktion durch ein zusätzliches Zeitfenster künstlich begrenzt, ist die Anwendung der DFT problemlos möglich. Wir schalten unserem Testsignal daher noch ein Hanning-Fenster nach. Für Untersuchungen im Zeitbereich sind solche Maßnahmen nicht notwendig. Dort reicht es aus, wenn die Eins nur lange genug ansteht, bis sich das Testsystem eingeschwungen hat. Was danach kommt interessiert nicht weiter. class Identifikation { ... public void ErzeugeTestsignal_2() { for (int k=0; k
x(k ) = σ (k ) ⋅ w(k ) y ( k ) = h(k ) ∗ (σ (k ) ⋅ w(k ))
| H( f ) | =
DFT (h(k ) ∗ (σ (k ) ⋅ w(k ))) DFT (σ (k ) ⋅ w(k ))
92
1 Digitale Signalverarbeitung
Der Gleitsinus Den Gleitsinus, auch Chirp genannt, haben wir schon in Abschn. 1.10 kennengelernt. Mit seiner kontinuierlich anwachsenden Frequenz erscheint es als Testsignal wie geschaffen für unsere Zwecke. class Identifikation { ... public void ErzeugeTestsignal_3() { double f = 0; for (int k=0; k
x(k ) = chirp (k ) y (k ) = h(k ) ∗ chirp (k ) | H( f ) | =
DFT (h(k ) ∗ chirp (k )) DFT (chirp ( k ))
Das Spektrum des Gleitsinus kann durchaus auch anders aussehen, denn es hängt von der Schnelligkeit ab, mit der die Frequenz im Abtastintervall anwächst. Hiervon sollte man sich aber nicht beirren lassen. Wählt man den abgedeckten Frequenzbereich günstig, kann man den Frequenzgang des Systems sogar schon im Zeitbereich ablesen. Die gute Übereinstimmung von y(k) mit |H(f)| ist deutlich zu erkennen. Jedem Punkt im Zeitbereich kann die jeweilige Frequenz exakt zugeordnet werden. Durch diese besondere Anschaulichkeit unterscheidet sich der Gleitsinus von allen anderen Testsignalen.
93
1.12 Experimentelle Systemanalyse 0,035
1,2
0,03
0,8
0,025
|X(f)|
0
0,02 0,015
-0,4
0,01
-0,8
0,005 0,46
0,49 0,49 0,49
0,42
0,46 0,46
0,39
0,42 0,42
0,35
0,39 0,39
0,32
0,35 0,35
0,28
0,32 0,32
f/fa
k 1,2
0,03
0,8
0,025 0,02
|Y(f)|
0,4 0
0,015
-0,4
0,01
-0,8
0,005
k
0,28
0,25
0,21
0,18
0,14
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
0,11
0 0
0,07
0
-1,2
0,04
y(k)
0,25
0,21
0,18
0,14
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
0,11
0 0
0,07
0
-1,2
0,04
x(k)
0,4
f/fa 1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,28
0,25
0,21
0,18
0,14
0,11
0,07
0,04
0
0
f/fa
Abb. 1.48. Bestimmung der Übertragungsfunktion |H(f)| mit Hilfe des Gleitsinus als Testsignal
Rauschen Zugegeben, die Verwendung von stochastischem Rauschen als Testsignal klingt zunächst wie ein Widerspruch. Rauschen zeigt bekanntlich keine Erhaltungstendenz, d. h. es ist nicht möglich aus der Betrachtung eines beliebigen Intervalls auf vorherige oder nachfolgende Intervalle zu schließen. Der zeitliche Verlauf ist rein zufällig und unvorhersehbar. Sowenig es uns auch gefällt, Rauschen ist allgegenwärtig und macht sich in der Signalverarbeitung als dem Nutzsignal überlagerte Störung bemerkbar. Trotzdem hat es auch seine guten Seiten, zumindest als Testsignal. Ideales weißes Rauschen als Signal trägt zwar selbst keinerlei Information, enthält dafür aber alle Frequenzen. Durchläuft es unser Testsystem (wird also mit einem Tiefpaß gefiltert), dann entsteht zunächst sogenanntes farbiges Rauschen. Seine fehlenden bzw. verbleibenden Frequenzanteile sind es, die schließlich die Dynamik des Testsystems preisgeben. An dieser Stelle ist mit der im Beispielcode verwendeten Klasse Zufall ein kleiner Vorgriff auf das nächste Kapitel notwendig, da natürlich die Standardsprachelemente von C# (und auch jeder anderen Programmiersprache) die Erzeugung von Rauschsignalen nicht unmittelbar unterstützen.
94
1 Digitale Signalverarbeitung
Pronblematisch ist hier lediglich die Auflösung. Bei normalverteiltem Rauschen ist die Streuung umgekehrt proportional zur Wurzel aus der Zahl der Abtastwerte. Für eine Verdopplung der Genauigkeit (bzw. halbierte Streuung), ist demnach die vierfache Auflösung notwendig. class Identifikation { ... public void ErzeugeTestsignal_4() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k
0,14
5 4 3 2 1 0 -1 -2 -3 -4 -5
0,12 0,1
|X(f)|
0,08 0,06 0,04 0,02 0,35
0,39
0,42
0,46
0,49
0,39
0,42
0,46
0,49
0,39
0,42
0,46
0,49
0,32
0,35 0,35
0,28
0,32 0,32
0,25
f/fa
1,5
0,12
1
0,1
0,5
0,08
|Y(f)|
0
0,06
-0,5
0,04
-1
0,02
k
0,25
0,21
0,18
0,14
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
0,11
0 0
0,07
0
-1,5
0,04
y(k)
0,28
k
0,28
0,21
0,18
0,14
0,11
32 64 96 128 160 192 224 256 288 320 352 384 416 448 480
0,07
0
0 0
0,04
x(k)
}
f/fa
1,2 1
|H(f)|
0,8 0,6 0,4 0,2 0,25
0,21
0,18
0,14
0,11
0,07
0
0,04
0
f/fa
Abb. 1.49. Bestimmung der Übertragungsfunktion |H(f)| mit Hilfe von Rauschen als Testsignal
1.12 Experimentelle Systemanalyse
95
x(k ) = r (k ) y ( k ) = h( k ) ∗ r ( k ) | H( f ) | =
DFT (h(k ) ∗ r (k )) DFT (r (k ))
1.12.2 Identifikation im Zeitbereich
Möchte man die komplette Übertragungsfunktion bestimmen, dann kommt man um die zuvor beschriebene Frequenzanalyse nicht herum. Ist man dagegen z. B. nur an der Grenzfrequenz fg interessiert, genügt schon eine Betrachtung im Zeitbereich. Zunächst machen wir aber einen kurzen Ausflug in die Analogtechnik. Wir stellen uns einen einfachen RC-Tiefpaß erster Ordnung vor, auf dessen Eingang wir einen Spannungssprung geben. Die Ausgangsspannung hat dann den folgenden Verlauf: −
t
ua (t ) = u0 (1 − e ) τ
Die Zeitkonstante IJ = R·C beschreibt, wie schnell die Ausgangsspannung ihren stationären Endwert erreicht, ist also ein Maß für die Dynamik des Systems. Systeme mit großen Zeitkonstanten reagieren recht träge, haben also eine geringe Dynamik. Umgekehrt stehen kleine Zeitkonstanten für kurze Reaktionszeiten, also eine hohe Dynamik. Allgemein sind die Zeitkonstanten von Übertragungssystemen umgekehrt proportional zum Frequenzbereich den diese verarbeiten können. Eine wesentliche Kenngröße zur Beschreibung von Tiefpässen im Zeitbereich ist deren Anstiegszeit ta. Sie gibt an, in welcher Zeit das Ausgangssignal von 10% auf 90% des Endwertes ansteigt, wenn man eine Sprungfunktion an den Eingang legt.
ta = t90% − t10% = τ (ln(0,9) − ln(0,1) ≈ 2,2τ
(1.53)
Somit ist die Anstiegszeit ta etwas mehr als doppelt so groß, wie die Zeitkonstante IJ unseres RC-Tiefpasses. Für die Grenzfrequenz fg = 1/2ʌIJ folgt daraus:
fg ≈
1 3ta
(1.54)
Diese einfache Beziehung gestattet es, die Grenzfrequenz eines Übertragungssystems aus der Anstiegszeit des Ausgangssignals zu schätzen. Gln. (1.54) gilt näherungsweise auch für Systeme höherer Ordnung. Wir
96
1 Digitale Signalverarbeitung
wollen diese Erkenntnis nutzen, um die Grenzfrequenz eines rekursiven Tiefpaßfilters erster Ordnung zu bestimmen.
y (k ) = x(k ) + 0,5 ⋅ y (k − 1) Bei der Implementierung rekursiver Systeme ist unbedingt der Rückgriff auf die alten Ausgangswerte zu berücksichtigen. Will man einen Absturz seines Computers vermeiden, dann muß die Schleife zur Berechnung, entsprechend der Filterordnung, mit einem Wert k > 0 starten. class Identifikation { ... public void Filterung() { // IIR-Tiefpassfilter 1. Ordnung for (int k=1; k
Da unseren synthetischen Daten, anders als die aufgezeichneten Daten aus einem echten Prozeß, natürlich keine reale Zeitbasis haben, ist es notwendig die einzelnen Zeitschritte auf die gewählte Abtastrate (im Beispiel N = 128) zu beziehen. Die Werte für t90% und t10% können aus der Grafik abgelesen werden. Bequemer wäre es aber, eine deutlich höhere Abtastrate vorausgesetzt, sie direkt den tabellierten Ausgangswerten zu entnehmen. Im vorliegenden 2,5
y(k)
2 1,5 1 0,5 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
Abb. 1.50. Sprungantwort des Testsystems
1.12 Experimentelle Systemanalyse
97
Fall ergibt sich eine normierte Anstiegszeit von etwa ta = 3/128. Eingesetzt in Gln. (1.54) erhalten wir damit eine auf die Grundschwingung bezogene Grenzfrequenz von fg = 14,2. Dieser Wert steht in recht guter Übereinstimmung mit dem nach einer Frequenztransformation (Fensterung nicht vergessen!) aus |H(f)| abgelesenen Wert von 14,6.
2 Statistische Signalverarbeitung
2.1 Einführung In der Praxis hat man es sehr häufig mit Signalen zu tun, für deren Verlauf nur mit sehr viel Aufwand ein Bildungsgesetz gefunden werden kann, wenn dies überhaupt möglich ist. Eine wesentliche Ursache hierfür ist der Umstand, daß alle realen Systeme in mehr oder weniger enger Wechselwirkung mit ihrer Umgebung stehen. Oft besteht diese Wechselwirkung aus einer Vielzahl von kleinen Effekten, jeder einzelne für sich fast immer vernachlässigbar. In der Summe sieht das aber schon anders aus, was eine detaillierte Modellbildung erschwert. In solchen Fällen ist die Beschreibung mit Hilfe von statistischen Methoden oft die bessere Lösung. Dies trifft nun keineswegs nur auf den Bereich der Meßtechnik zu, sondern gilt allgemein für die Verarbeitung größerer Datenmengen, ganz egal welchen Ursprung sie haben. Hier stellt die mathematische Statistik geeignete Verfahren zur Verfügung, um Datensätze darzustellen und zu analysieren. In der Regel lassen sich aus ihnen Gesetzmäßigkeiten ableiten, die in den Einzelwerten nicht erkennbar sind. Die verschiedenen Kenngrößen der Statistik ermöglichen somit Schlußfolgerungen, helfen bei Entscheidungen und Prognosen für die Zukunft. Auch wenn wir uns in den gewählten Beispielen sehr eng an Problemstellungen der physikalischen Meßtechnik anlehnen, sind die vorgestellten Verfahren allgemeiner Natur und lassen sich ohne Probleme auf anderen Gebieten anwenden. Grundsätzlich stimmt der bei einer Messung ermittelte Wert nicht exakt mit dem wahren Wert überein. Hierfür gibt es zwei wesentliche Ursachen. Ein Grund sind systematische Fehler in der Meßmethode selbst. Solche Fehler beeinflussen das Ergebnis einer Messung stets in gleicher Weise, die Werte sind dann entweder immer zu groß oder immer zu klein. Eine kritische Betrachtung der Ergebnisse hilft systematische Fehler zu erkennen. Man kann dann versuchen die Fehlerquelle zu beseitigen, oder, falls das nicht gelingt, wenigstens die Größenordnung des Fehlers abschätzen und bei der Interpretation des Ergebnisses berücksichtigen. Nicht weniger schwierig ist der Umgang mit den unvermeidlich zufälligen Fehlern einer Messung. Typischerweise ist bei der Meßwerterfassung dem eigentlichen Nutzsignal ein gewisser Rauschanteil überlagert, der sich als zufällige
100 2 Statistische Signalverarbeitung
Schwankung in den gemessenen Werten bemerkbar macht. Rauschen ist ein Zufallsprozeß, der grundsätzlich bei allen Messungen auftritt. Ein bekanntes Beispiel ist thermisches Rauschen, welches aus der Brownschen Molekularbewegung resultiert. Die Elektronen in einem elektrischen Leiter ändern ständig ihre Position und Geschwindigkeit aufgrund zufälliger thermischer Fluktuationen. Durch das Anlegen einer äußeren Spannung erhält ihre Bewegung eine Vorzugsrichtung. Natürlich unterliegt damit auch der gemessene elektrische Strom statistischen Schwankungen. Besonders bei kleinen Strömen macht sich das störend bemerkbar, weshalb Rauschen durch den weiter anhaltenden Trend zur Miniaturisierung in der Sensorik und Mikroelektronik zunehmend ein Problem wird. Eines der Hauptanliegen der Statistik ist es, die Unsicherheit in der Information, wie sie durch zufällige Schwankungen im Datenmaterial entsteht, entweder zu beseitigen, oder doch wenigstens abzuschätzen und die ursprünglichen Rohdaten auf ihre Kernaussage zu reduzieren. Bevor wir uns in diesem Kapitel den dazu geeigneten Methoden zuwenden, wollen wir noch einen kurzen Blick auf das Wesen zufälliger Ereignisse und deren Nachbildung mit dem Computer werfen.
2.2 Zufallszahlen – Dem Rauschen auf der Spur Rauschen ist das Ergebnis stochastischer physikalischer Vorgänge. Echte Zufallszahlen lassen sich daher durch die Nutzung physikalischer Effekte relativ leicht erzeugen, beispielsweise mit Hilfe des oben beschriebenen thermischen Rauschens in elektronischen Bauelementen. Eine so erzeugte Folge von Zufallswerten ist weder reproduzierbar noch vorhersagbar. Obwohl eine Hardwarerealisierung technisch also durchaus möglich wäre, sind Zufallsgenerator-Chips in heutigen Rechnern nicht üblich. Bei der Simulation technischer Systeme oder Prozesse ist man jedoch sehr häufig auf die Verwendung von Zufallszahlen angewiesen und greift dann notgedrungen auf eine Softwarerealisierung zurück. Allerdings ist das nicht ganz unproblematisch. Ein Computer ist schließlich eine deterministische Maschine, was bedeutet, daß jeder implementierte Algorithmus bei identischen Startbedingungen auch die immer selben Ergebnisse produziert. Von Zufall also keine Spur. Bestenfalls liefert er mehr oder weniger gute Pseudo-Zufallszahlen, was jedoch für die meisten Zwecke völlig ausreichend ist. Gerade die Reproduzierbarkeit der erzielten Ergebnisse ist in vielen Bereichen für Kontrollrechnungen enorm wichtig und deshalb sogar erwünscht. Die Anforderungen an eine gute Pseudo-Zufallsfolge sind schnell formuliert:
2.2 Zufallszahlen – Dem Rauschen auf der Spur 101
• Zwischen beliebigen Teilfolgen darf keine Beziehung bestehen, schließlich stellt jeder Zufallswert ein unabhängiges Einzelereignis dar. • Die Periodizität der erzeugten Folge muß möglichst groß sein, um für jeden denkbaren Anwendungsfall eine ausreichend große Anzahl von Werten generieren zu können. • Die erzeugten Zahlen sollen eine bestimmte Verteilung aufweisen. Wie wir noch sehen werden, genügt es hierfür in einem ersten Schritt gleichverteilte Zufallswerte zu erzeugen, die sich dann gegebenenfalls transformieren lassen. Auch wenn die aufgelisteten Kriterien auf den ersten Blick harmlos erscheinen, ist der Entwurf eines guten Zufallsgenerators durchaus eine Kunst für sich und nimmt in der Literatur einen entsprechend breiten Raum ein. Es lohnt daher allemal, sich ein wenig mit dieser Thematik zu beschäftigen, trotz der wohl in allen Programmiersprachen verfügbaren Systemfunktionen rand(), random(), ..., bei deren Benutzung aber Vorsicht geboten ist. Der Grund hierfür ist vor allem in den ausgeprägten Systemabhängigkeiten und den unbekannten statistischen Eigenschaften zu sehen. Ein eigener Zufallsgenerator kann dagegen ohne große Probleme auf verschiedene Plattformen portiert werden und produziert dann auch miteinander vergleichbare Resultate. So ganz nebenbei bietet der Entwurf eines Zufallsgenerators auch eine gute Gelegenheit seine Eigenschaften mit Hilfe statistischer Methoden näher zu untersuchen. 2.2.1 Gleichverteilte Zufallszahlen
Eine Anzahl gleichverteilter Zufallszahlen erhält man zum Beispiel durch den mehrfachen Wurf eines idealen Würfels. Das Ergebnis jedes einzelnen Wurfes ist eine Zahl zwischen Eins und Sechs, wobei die Reihenfolge völlig zufällig ist. Allerdings wäre es nicht besonders effektiv, längere Zufallsfolgen auf diese Art zu erzeugen, insbesondere für computergestützte Anwendungen. Doch zum Glück gibt es geeignetere Methoden. Eines der bekanntesten Verfahren zur Erzeugung von PseudoZufallszahlen ist die 1951 von D. Lehmer vorgestellte Methode der linearen Kongruenz, auch Restmethode genannt, die später von D. E. Knuth verfeinert wurde. Ausgehend von einem Keim z0 als Startinitialisierung der Folge, entsteht jede neue Zufallszahl nach einem festen Bildungsgesetz aus ihrem Vorgänger.
zn +1 = (a ⋅ zn + c) mod m
(2.1)
102 2 Statistische Signalverarbeitung
Der nächste Wert ergibt sich hierbei durch Multiplikation mit einem Faktor a und Addition einer Konstanten c, als Rest der Division durch m. Natürlich hat die Wahl von a, c, und m einen ganz entscheidenden Einfluß auf die Güte des Generators. Zusammen mit dem gewählten Startwert bestimmen sie die resultierende Folge. Für die ganzzahlige Version des ModuloOperators ist das Ergebnis stets eine Zahl zwischen 0 und m−1, womit klar ist, daß für m ein sehr großer Wert gewählt werden muß, am besten eine Primzahl, um eine genügend große Periodizität der Folge zu erreichen. Günstige Werte für a wählt man aus dem Bereich [2, m−1]. Die Normierung un = zn / m erzeugt Zahlen im Intervall [0, 1). So simpel diese Methode auch zunächst erscheint, in ungünstigen Fällen kann die Periode erheblich kleiner als m−1 sein. Unter Umständen ist dann die Anzahl der verfügbaren Zufallszahlen nicht ausreichend groß. Wie man sich denken kann, werden die Ergebnisse einer hierauf aufbauenden Simulation oder sonstigen Anwendung nicht unbedingt besser. Es ist deshalb ratsam, seinen eigenen Generator vor der dem ersten Einsatz ausgiebig zu testen. Häufig werden ohnehin Zufallszahlen im Gleitkommaformat benötigt und man greift dann lieber gleich auf die Gleitkommaversion des Modulo-Operators zurück. Den gleichen Zweck erfüllt eine vereinfachte Variante der Restmethode, die trotz ihrer simplen Struktur über bemerkenswerte Eigenschaften verfügt.
zn +1 = FRAC (b ⋅ zn + d )
(2.2)
Wie zuvor, wird auch hier zuerst mit einem Faktor multipliziert und anschließend eine Konstante addiert. Der sich ergebende Nachkommateil bildet den neuen Zufallswert. Steht für die Rückgabe des Nachkommateils keine Funktion zur Verfügung, muß man eben selbst den Ganzzahlteil abziehen. Gute Werte erhält man z. B. mit b = 201 und d = 100000/3. Wahrscheinlich spielt hier jeder mit dem Gedanken, seiner Zufallsfolge durch den Gebrauch komplizierter Faktoren (ʌ·e·...) ein besonders hohes Maß an „Zufälligkeit“ zu verleihen, diesen Aufwand kann man sich jedoch getrost sparen. Wie schon beim Generator zuvor, ist ein Startwert für die Initialisierung erforderlich. Die erzeugten Zahlen liegen gleichverteilt im Bereich [0, 1). Benutzt man als Datentyp eine 64-bit-Gleitkommazahl (double) ist die Periodizität der Folge größer als 100.000.000.000, was wohl für die meisten Anwendungen ausreichen dürfte. 2.2.2 Normalverteilte Zufallszahlen
Die beiden oben vorgestellten Generatoren erzeugen gleichverteilte Zufallszahlen, bei denen jeder Wert idealerweise mit der gleichen Wahrscheinlichkeit auftritt. Möchte man Rauschphänomene simulieren, wie sie
2.2 Zufallszahlen – Dem Rauschen auf der Spur 103
in der Meßwerterfassung vorkommen, genügt das noch nicht. Dort macht sich Rauschen typischerweise als normalverteilte Unschärfe bemerkbar, die dem tatsächlichen Wert überlagert ist. Um solche Zufallsprozesse nachbilden zu können, bedarf es dann auch normalverteilter Zufallszahlen. Diese lassen sich aus zwei gleichverteilten Zufallswerten zG1, zG2 wie folgt erzeugen:
z = σ ⋅ − 2 ⋅ ln( zG1 ) ⋅ sin(2π zG 2 ) + μ
(2.3)
Der Parameter μ stellt den gewünschten Erwartungswert dar, also den Schwerpunkt der Verteilung, der Parameter ı ist die Standardabweichung, manchmal auch Streuung genannt, und bestimmt die Breite der Verteilung (siehe auch Abschn. 2.3). 2.2.3 Beliebig verteilte Zufallszahlen
Die Anforderungen an einen Zufallsgenerator können unterschiedlicher Natur sein, abhängig vom Prozeß, den man nachbilden möchte. So ist es durchaus denkbar, daß in einer Anwendung weder eine Gleichverteilung noch eine Normalverteilung benötigt wird, sondern Zufallszahlen erforderlich sind, die einem anderen Verteilungsgesetz unterliegen. Man braucht dann ein Verfahren, um beliebige Verteilungsdichten f(x) erzeugen zu können. Typischerweise geht man dabei in zwei Schritten vor. Zuerst werden gleichverteilte Zufallszahlen zn im Bereich [0, 1) generiert, die dann in einem zweiten Schritt noch geeignet zu transformieren sind. Hierzu ist die Umkehrfunktion der angestrebten Verteilung auf die ursprünglichen zn anzuwenden. Wir probieren das am Beispiel einer Exponentialverteilung aus, wie sie z. B. für die Lebensdauer technischer Geräte in guter Näherung gilt.
f ( x) = e − λ ⋅ x e−λ ⋅ x = z − λ ⋅ x = ln(z ) x=−
1
λ
⋅ ln( z )
Die neue Zufallszahlenfolge xn = f −1(zn) entsteht also durch Inversion der gewünschten Verteilung. Bei der Implementierung müssen wir noch den Fall z = 0 ausschließen, weil der natürliche Logarithmus nur für Werte größer Null definiert ist. Am einfachsten gelingt das durch Addition einer vernachlässigbar kleinen Konstanten.
104 2 Statistische Signalverarbeitung
So anschaulich das hier beschriebene Transformationsverfahren auch ist, muß an dieser Stelle erwähnt werden, daß leider nicht für alle theoretisch denkbaren Verteilungen eine Umkehrfunktion auch wirklich existiert. Ein Beispiel hierfür ist die zuvor eingeführte Normalverteilung. In solchen (hoffentlich seltenen) Fällen bleibt einem dann nichts anderes übrig, als auf Näherungsverfahren zurückzugreifen. class Zufall { const double PI = 3.141592653589793; private private private private
double double double double
gz1; // gz2; // nz; // ez; //
gleichverteilte Zufallszahl gleichverteilte Zufallszahl normalverteilte Zufallszahl exponentialverteilte ...
// Konstruktor für Startinitialisierung public Zufall(double initgz1, double initgz2) { gz1 = initgz1; gz2 = initgz2; nz = 0; ez = 0; } public double Gleich1() { gz1 = (201.0*gz1+100000/3.0) – (int)(201.0*gz1+100000/3.0); return gz1; } public double Gleich2() { gz2 = (171.0*gz1+100000/3.0) – (int)(171.0*gz1+100000/3.0); return gz2; } public double Normal(double mw, double streu) { nz = streu * Math.Sqrt(-2*Math.Log(Gleich1(), 2)) * Math.Sin(2*PI*Gleich2()) + mw; return nz; }
2.2 Zufallszahlen – Dem Rauschen auf der Spur 105
public double Exponent(double lambda) { ez = -(1/lambda)*Math.Log(Gleich1()+1E-12, 2); return ez; } }
Sollte für jeden Programmdurchlauf eine andere Zufallsfolge erforderlich sein, dann wird der Startwert zur Initialisierung üblicherweise über die Systemzeit des Rechners gebildet. Zufallszahlen, die nicht softwaregestützt erzeugt werden, finden sich übrigens auch auf verschiedenen Seiten im WWW. Als Quelle dient dort z. B. das Rauschen von Radioempfängern oder CCD-Sensoren. In der Regel findet man auf solchen Seiten weitere Informationen über Zufallsprozesse und deren technische Nutzung. Reinschauen lohnt sich daher in jedem Fall. 2.2.4 Summen von Zufallsvariablen – Der Grenzwertsatz
In der Praxis hat man es häufig nicht nur mit genau einer Rauschquelle (oder Zufallsvariablen) zu tun, sondern mit einer Verknüpfung mehrerer Rauschquellen. Aus diesem Grund ist man gut beraten, sich auch einmal die Verkettung mehrerer Zufallsvariablen anzuschauen. Im einfachsten Fall ist das die Summe zweier gleichverteilter Zufallszahlen. Bewegt sich jede einzelne im Bereich 0..1, dann kann die Summe Werte von 0..2 annehmen. Es treten jedoch jetzt in der Summe nicht mehr alle Werte mit der gleichen Wahrscheinlichkeit auf, da es für die Werte in der Intervallmitte mehr kombinatorische Möglichkeiten gibt, als für die Randwerte. Die neue Verteilungsdichtefunktion ergibt sich als Faltung der ursprünglichen Verteilungsdichtefunktionen. Summiert man nun sehr viele Zufallsvariablen auf, dann nähert sich die resultierende Verteilungsdichte immer mehr einer Standard-Normalverteilung an. Aus diesem zentralen Grenzwertsatz folgt auch der besondere Stellenwert der Normalverteilung, die sich für eine Vielzahl physikalischer Phänomene als korrekte statistische Beschreibung bestätigt hat. Immer, wenn sich eine Beobachtungsgröße als Summe vieler unabhängiger Teilgrößen darstellt, ergibt sich somit eine Normalverteilung. Weshalb nun ausgerechnet die Normalverteilung als Grenzwert auftritt, erklärt sich aus ihrer Invarianz gegenüber der Faltung, was bedeutet, daß die Faltung zweier Normalverteilungen selbst eine Normalverteilung ergibt.
106 2 Statistische Signalverarbeitung
2.3 Die Normalverteilung Eine Zufallsvariable x ist genau dann normalverteilt, kurz N(μ,ı)-verteilt, wenn sich ihre Dichtefunktion f(x) durch den nachfolgenden funktionalen Zusammenhang beschreiben läßt: − 1 f ( x) = ⋅e σ 2π
( x−μ )2 2σ 2
(2.4)
Die Normalverteilung wurde zuerst von dem Mathematiker Abraham de Moivre (1667–1754) in seiner Schrift „Doctrine of Chances“ im Jahre 1718 eingeführt. Ihre besondere Bedeutung für allgemeine Streuprozesse hat aber erst der Mathematiker Carl-Friedrich Gauß (1777–1855) im Rahmen seiner Untersuchungen zur Fehler- und Ausgleichsrechnung erkannt, weshalb man heute auch oft von einer Gauß-Verteilung spricht. Als Graph der Dichtefunktion erhalten wir die bekannte Glockenkurve. Man bezeichnet μ als Erwartungswert und ı als Standardabweichung (oder Streuung). Für verschiedene Werte dieser beiden Parameter ergeben sich unterschiedliche Kurven, die jeweils symmetrisch um ein Maximum bei x = μ liegen. Die Punkte x = μ-ı und x = μ + ı bilden die Wendepunkte der Kurve. Mit steigendem ı wird deren Verlauf flacher und dafür breiter, da die Gesamtfläche unter dem Graphen konstant (= 1) ist. 0,5
f(x)
0,4 0,3 0,2 0,1 0 -5
-4
-3
-2
-1
0
1
2
3
4
5
x
Abb. 2.1. Normalverteilungsdichte für verschiedene Werte von ı
Aus dem zentralen Grenzwertsatz folgt die besondere Bedeutung der Normalverteilung für viele physikalische Vorgänge. Trotzdem sind natürlich in der Praxis nicht alle Streuprozesse normalverteilt. Es hat sich aber gezeigt, daß die Annahme einer Normalverteilung auch in den Fällen, in denen das nicht exakt zutrifft, oft zu brauchbaren Ergebnissen führt. Zudem können viele andere Verteilungen zur Vereinfachung durch eine Normalverteilung angenähert werden. Geht man bei einer Meßwertreihe
2.4 Grafische Methoden der statistischen Analyse 107
von einer Normalverteilung mit dem Erwartungswert μ und Streuung ı aus, dann gelten die folgenden Vertrauensbereiche:
P( μ − σ ≤ x ≤ μ + σ ) =
μ +σ
f ( x)dx ≈ 68,3% ³ μ σ −
P( μ − 2σ ≤ x ≤ μ + 2σ ) =
μ + 2σ
³ f ( x)dx ≈ 95,4%
μ − 2σ
P( μ − 3σ ≤ x ≤ μ + 3σ ) =
μ + 3σ
³ f ( x)dx ≈ 99,7%
μ − 3σ
Unter der oben genannten Voraussetzung kann man also davon ausgehen, daß jeder zusätzlich aufgenommene Meßwert mit etwa 68% Wahrscheinlichkeit im Bereich ± ı um den Erwartungswert liegen wird. Mit Hilfe des Integrals über die Verteilungsdichte f(x) können wir auch eine Aussage darüber machen, wie groß die Wahrscheinlichkeit für das Auftreten eines exakt angegebenen Wertes x(k) = c ist. c
P(c ≤ x ≤ c) = P( x = c) = ³ f ( x)dx = 0 c
Die Wahrscheinlichkeit einen bestimmten Wert exakt zu messen ist Null. Dies ist auch leicht nachvollziehbar. Weil Messungen immer fehlerbehaftet sind, ist es unmöglich einen Meßwert mit absoluter Genauigkeit zu ermitteln.
2.4 Grafische Methoden der statistischen Analyse Die Statistik stellt für die Untersuchung von Daten eine Vielzahl von Kenngrößen bereit, die eine Beschreibung der wesentlichen Eigenschaften ermöglichen. Wer aber glaubt, daß hierfür immer umfangreiches und kompliziertes Formelwerk notwendig ist, der irrt sich. Eine Reihe interessanter Merkmale läßt sich ohne großen Aufwand sogar schon aus der richtigen grafischen Darstellung ablesen.
108 2 Statistische Signalverarbeitung
2.4.1 Das Histogramm
Möchte man wissen, wie sich die gemessenen Daten über ihren gesamten Wertebereich verteilen, also wie häufig einzelne Werte auftreten, dann kann man dies sehr anschaulich in einem Histogramm grafisch wiedergeben. Histogramme lassen sich denkbar einfach erstellen. Man bildet mehrere Teilintervalle, Klassen genannt, entsprechend den vorliegenden Datenwerten und bestimmt die Anzahl von Werten, die innerhalb einer solchen Klasse liegen. In den allermeisten Fällen ist die Klassenbreite konstant. Sie sollte so gewählt werden, daß keine Werte genau auf die Klassengrenzen fallen. Läßt sich das jedoch mit vertretbarem Aufwand nicht vermeiden, dann wird ein solcher Wert jeweils zur Hälfte beiden Klassen zugeordnet. Typische Werte für die Klassenzahl liegen zwischen 5 und 20, abhängig vom Umfang der Daten. Wählt man die Anzahl der Klassen im Histogramm ungerade, wird auch eine symmetrische Verteilungsdichte gut wiedergegeben. Zur Vereinfachung werden innerhalb einer Klasse alle Werte als gleichverteilt angenommen. Aus diesem Grund hängt der Charakter der Verteilung in hohem Maße von der richtigen Wahl der Klassenbreite (und damit von der Klassenzahl) ab. Die Darstellung der Verteilungsdichte ist eine sehr einfache Methode, um einen ersten Eindruck von der Beschaffenheit des vorliegenden Datenmaterials oder des erzeugenden Prozesses zu bekommen. Für eine aussagekräftige Darstellung sollten jedoch mindestens 30 Werte vorliegen, da bei einer zu kleinen Datenmenge die resultierende Verteilung häufig nicht repräsentativ ist. Es leuchtet unmittelbar ein, daß ein Histogramm keinerlei Rückschlüsse mehr auf den ursprünglichen Verlauf der Daten zuläßt, da die Verteilung sich ausschließlich an den jeweiligen Werten orientiert, losgelöst von ihrem zeitlichen (oder räumlichen) Auftreten. class GrafischeAnalyse { const int Abtastwerte = 5000; // Stichprobenumfang const int Klassenzahl = 15; public double[] x = new double[Abtastwerte]; public double[] histo = new double[Klassenzahl]; private double klassenbreite; // Konstruktor public GrafischeAnalyse() { klassenbreite = 0; }
2.4 Grafische Methoden der statistischen Analyse 109
public void Histogramm(double von, double bis) { klassenbreite = (bis - von) / Klassenzahl; // alte Einträge im Histogramm löschen for (int k=0; k= (von + i*klassenbreite) && x[k] < (von + (i+1)*klassenbreite)) { histo[i]++; } } } // Normierung der Klassenhäufigkeit for (int k=0; k
Die obere und untere Grenze des Histogramms müssen natürlich auf den Wertebereich der darzustellenden Daten abgestimmt werden. Liegt eine Normalverteilung vor, dann ist beispielsweise von = μ − 4·ı und bis = μ + 4·ı ein günstiges Intervall, wogegen man bei einer Exponentialverteilung mit von = 0 und bis = 5.0 / lambda etwa 99,3% aller Werte erfaßt. Ob das Weglassen statistischer Ausreißer das Ergebnis in unerwünschter Weise verfälscht oder nicht, ist im jeweiligen Einzelfall zu entscheiden. Maßgeblich hierfür ist die Frage, ob sich ein Ausreißer plausibel begründen läßt. Mit dem vorgestellten Verfahren verfügen wir nun über das notwendige Rüstzeug für die ersten statistischen Gehversuche, alles was noch fehlt, sind ein paar geeignete Stichproben. Was liegt näher, als auf selbst erzeugte Daten zurückzugreifen. Verwenden wir hierfür unseren eigenen Zufallsgenerator,
110 2 Statistische Signalverarbeitung
dann bietet sich eine gute Gelegenheit die Qualität der mit ihm erstellten Zufallszahlen zu untersuchen. class GrafischeAnalyse { ... public Zufall Rauschen = new Zufall(0.71036,0.23906); public void ErzeugeTestsignal_1() { for (int k=0; k
2.4 Grafische Methoden der statistischen Analyse 111
Häufigkeit
1
x(k)
0,8 0,6 0,4 0,2
0
8
0, 03 3 0, 1 0, 16 7 0, 23 3 0, 3 0, 36 7 0, 43 3 0, 5 0, 56 7 0, 63 3
0
100000 90000 80000 70000 60000 50000 40000 30000 20000 10000 0
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
0, 7 0, 76 7 0, 83 3 0, 9 0, 96 7
1,2
Wert
Gleichverteilung mit z aus [0, 1) 2,5
140000 120000
Häufigkeit
x(k)
2 1,5 1
100000 80000 60000 40000 20000
0,5
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
1, 4 1, 53 3 1, 66 7 1, 8 1, 93 3
8
0, 06 7 0, 2 0, 33 3 0, 46 7 0, 6 0, 73 3 0, 86 7
0
1 1, 13 3 1, 26 7
0 0
Werte
Dreiecksverteilung z = z1 + z2 mit z1, z2 gleichverteilt aus [0, 1) 250000
3
200000
2
0 -1 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
150000 100000 50000
-2
3, 2 3, 73 3
-3 ,7 33 -3 , -2 2 ,6 6 -2 7 ,1 33 -1 , -1 6 ,0 6 -0 7 ,5 33
-4
1, 6 2, 13 3 2, 66 7
0
-3
0 0, 53 3 1, 06 7
x(k)
1
Häufigkeit
4
Werte
k
Normalverteilung mit μ = 0 und ı = 1 250000
8 7
200000
Häufigkeit
6 4 3
150000 100000 50000
2 1 0
8
16
24 32
40 48
56
64 72
80 88
96 104 112 120
k
67 0, 5 0, 83 3 1, 16 7 1, 5 1, 83 3 2, 16 7 2, 5 2, 83 3 3, 16 7 3, 5 3, 83 3 4, 16 7 4, 5 4, 83 3
0
0
0, 1
x(k)
5
Werte
Exponentialverteilung mit Ȝ = 1 Abb. 2.2. Zeitliche Verläufe und Histogramme von Rauschsignalen mit unterschiedlichen Verteilungsdichten
2.4.2 Das Streudiagramm
Aber die Verteilungsdichte ist nur ein Merkmal und charakterisiert eine Stichprobe nicht vollständig. So macht das Histogramm keine Aussage über eventuell vorhandene Abhängigkeiten in den Daten. Für eine genaue Auswertung ist aber gerade diese Information von besonderem Interesse. Zunächst gilt es daher herauszufinden, ob eine stochastische Abhängigkeit
112 2 Statistische Signalverarbeitung
in den Meßdaten vorhanden ist, die anschließend in einem zweiten Schritt, falls notwendig, noch genauer untersucht werden kann (siehe Abschn. 2.8). Eine solche Abhängigkeit kann entweder zwischen verschiedenen Beobachtungsreihen existieren oder auch innerhalb einer einzelnen Meßwertreihe. Dem Streudiagramm liegt die Idee zugrunde, Abhängigkeiten in Datenreihen grafisch zu erkennen. Hierzu sind die einzelnen Werte als Koordinaten eines Punktes zu betrachten. Zwei Meßwerte xj, xk markieren dann einen Punkt in der Ebene, wogegen drei Meßwerte xi, xj, xk einen Raumpunkt bilden. Auf diese Weise erhält man eine zwei- oder mehrdimensionale Punktwolke, Streudiagramm genannt, deren Form bzw. Muster die Daten (und damit den erzeugenden Prozeß) ebenfalls charakterisiert. class GrafischeAnalyse { // Streudiagramm public double[,] streu = new double[Abtastwerte, 2]; ... public void Streudiagramm() { for (int k=0; k
Das Streudiagramm sollte auch für die Untersuchung unserer Zufallsfolgen geeignet sein, denn schließlich ist die Unabhängigkeit jedes einzelnen Zufallswertes eine wesentliche Forderung an einen guten Generator. Wir begnügen uns mit einer zweidimensionalen Darstellung P(x,y) und bilden die x-Koordinaten aus den Folgegliedern mit geradem Index, die yKoordinaten entsprechend aus den Folgegliedern mit ungeradem Index.
2.4 Grafische Methoden der statistischen Analyse 113 1
z(k), k ungerade
0,75
0,5
0,25
0 0
0,25
0,5
0,75
1
z(k) , k gerade
Abb. 2.3. Streudiagramm mit 5000 Zufallswerten
Der verfügbare Raum wird von den 5000 Zufallszahlen relativ gleichmäßig aufgefüllt, ohne daß es zu auffälligen Anhäufungen von Punkten in einzelnen Bereichen kommt. Keine Region wird vom Generator bevorzugt oder benachteiligt. Die Verteilung in der Ebene ist rein zufällig. Zumindest scheint das auf den ersten Blick so zu sein. Betrachtet man aber einen vergrößerten Ausschnitt, zeigt sich ein generelles Problem, mit dem alle linear kongruenten Generatoren behaftet sind. Die erzeugten Zufallszahlen füllen den Raum keineswegs gleichmäßig aus, sondern liegen immer auf (n−1)dimensionalen Hyperflächen. Wie viele Hyperebenen sich ausbilden, hängt von den jeweiligen Parametern ab, in Gln. (2.1) vom Modul m und in Gln. (2.2) vom Parameter b. Im vergrößerten Ausschnitt von Abb. 2.4 sind sie als fast senkrecht stehende Streifen zu erkennen. Für b = 201 sind es rund 20 auf 1/10-Intervall. Erhöhen wir in unserem Beispiel den Wert von b auf 2001, bilden sich entsprechend mehr Hyperebenen aus, wodurch die Verteilung wieder zufällig wirkt, zumindest bis zur nächsten Zoomstufe. Um die hier beschriebene (und natürlich unerwünschte) Abhängigkeit innerhalb einer Zufallsfolge aufzubrechen, greift man zu einer Methode, die sich Reshuffling nennt. Dabei gibt man nicht alle generierten Werte der Folge auch tatsächlich aus, sondern verwirft immer eine bestimmte Anzahl, um die Ordnung hintereinander folgender Werte zu stören. Die zuletzt ausgegebene Zufallszahl selbst, z. B. deren erste Nachkommastelle, bestimmt, wie viele weitere Zahlen bis zur nächsten Ausgabe zu verwerfen sind. Im Einzelfall kann es durchaus vorkommen, daß eine zweidimensionale Darstellung noch nicht ausreicht, um eventuell vorhandene Abhängigkeiten im Datenmaterial zu erkennen. Möchte man die Unabhängigkeit eines
114 2 Statistische Signalverarbeitung 1
z(k), k ungerade
0,75
0,5
0,25
0 0,5
0,55
0,6
z(k) , k gerade
Abb. 2.4. Detailansicht mit erkennbarer Streifenbildung (Hyperebenen)
dritten Wertes von zwei vorangegangenen Werten testen, ist schon ein dreidimensionaler Kubus erforderlich. Bei Tests noch höherer Dimension ist leider die bildliche Darstellung nicht mehr ganz so einfach, was dann auch die Erkennung sich ausbildender Muster erheblich erschwert. Bis hierher sind wir mit erstaunlich wenig Mathematik ausgekommen. Sieht man einmal von der Erzeugung der synthetischen Daten ab, mußte eigentlich noch gar nichts berechnet werden. Schon allein durch eine geschickte grafische Aufbereitung ist man in der Lage, seinen Daten einige interessante Geheimnisse zu entlocken. Der große Vorteil der Datenvisualisierung beruht auf der bemerkenswerten Eigenschaft des menschlichen Gehirns Muster oder Strukturen zu erkennen und hieraus Zusammenhänge abzuleiten. Eine solche grafische Analyse wird üblicherweise durch verschiedene statistische Untersuchungen mit mathematischen Methoden ergänzt. Nicht selten schließt sich hieran eine erneute grafische Darstellung der modifizierten Daten an.
2.5 Lage-, Streu- und Formparameter in der Statistik Wie man sich wohl denken kann, sind mit der grafischen Darstellung von Histogramm und Streudiagramm unsere Möglichkeiten noch lange nicht ausgeschöpft. Die Statistik stellt eine Reihe von Maßzahlen zur Verfügung, die eine Stichprobe nach ihrer äußeren Form beschreiben. Mit ihnen gelingt es, auch sehr umfangreiches Datenmaterial auf einige wesentliche
2.5 Lage-, Streu- und Formparameter in der Statistik 115
Kenngrößen zu reduzieren und unterschiedliche Datensätze miteinander zu vergleichen. 2.5.1 Der arithmetische Mittelwert
Der arithmetische Mittelwert ist wahrscheinlich die bekannteste statistische Kenngröße und auch die am häufigsten benutzte. Beinahe immer, wenn wir im Alltag mit Durchschnitts- oder Mittelwerten konfrontiert werden („Durchschnittseinkommen“, „mittlere Temperatur“), ist dieser Lageparameter gemeint. Ihm liegt die Idee zugrunde, eine Anzahl von Datenpunkten durch eine einzige Kennziffer zu beschreiben, etwa im Sinne eines Ausgleichswertes. Er berechnet sich einfach als Summe aller Einzelwerte, dividiert durch deren Anzahl.
x=
1 N ¦ xk N k =1
(2.5)
Liegen zum Zeitpunkt der Berechnung bereits alle Daten vollständig vor, dann kann man ruhig so vorgehen. Etwas anders sieht es aber aus, wenn es notwendig ist, den Mittelwert (online) mit jedem neu eintreffenden Einzelwert zu aktualisieren. Die Berechnung nach Gln. (2.5) wird dann durch die Summenbildung mit einer wachsenden Anzahl von Werten immer zeitaufwendiger. Das ist bei wirklich großen Datenmengen jedoch nicht akzeptabel. Abhilfe schafft hier eine Rekursion.
x=
1 § N −1 · ⋅ ¨ ¦ xk + xN ¸ N © k =1 ¹
xN =
1 ⋅ ( ( N − 1) ⋅ xN −1 + xN ) N
(2.6)
In der rekursiven Form berechnet sich der aktuelle Mittelwert mit Hilfe des neuen Meßwertes xN und der aktuellen Gesamtzahl N direkt aus dem vorherigen Mittelwert. Wie wir schon im Kapitel über digitale Signalverarbeitung gesehen hatten, stellt die Mittelwertbildung aus einer Anzahl von Meßwerten eine Filterung dar. Dabei wird die Folge x(k) in die gefilterte Folge y(k) überführt. An dieser Stelle sei aber darauf hingewiesen, daß die oben vorgestellte rekursive Form als Mittelwertfilter ungeeignet ist. Dies hängt mit der wachsenden Fensterlänge und der damit unvermeidbaren Veränderung im Frequenzgang zusammen. Sie ist allerdings eine ausgezeichnete Wahl, wenn es wirklich darum geht, aus einer Anzahl von Einzelwerten den Mittelwert zu bestimmen. Da stört es auch überhaupt nicht,
116 2 Statistische Signalverarbeitung
daß für den ersten Mittelwert noch gar kein Vorgänger existiert, weil er ja ohnehin mit N−1 (= 0) zu multiplizieren ist. Bei der Verwendung des arithmetischen Mittelwertes sollte man sich immer bewußt sein, daß diese Kenngröße relativ empfindlich gegenüber Extremwerten ist. Insbesondere bei kleinen Stichproben kann schon ein einzelner Ausreißer das Gesamtbild unter Umständen stark verfälschen. In der Regel kommt der arithmetische Mittelwert auch nicht tatsächlich als Wert in der Datenmenge vor. Man bezeichnet den Mittelwert auch als das gewöhnliche Moment erster Ordnung. 2.5.2 Der Median
Als Median (manchmal auch Zentralwert) wird derjenige Wert bezeichnet, der genau in der Mitte einer nach Größe der Einzelwerte geordneten Datenmenge liegt. Somit teilt er die Datenmenge in zwei gleich große Hälften, wobei jeweils 50% der Einzelwerte kleiner sind als der Median und 50% größer. Anders als der arithmetische Mittelwert, der ausschließlich für quantitative (skalare) Merkmale berechnet werden kann, ist der Zentralwert auch für qualitative Rangmerkmale möglich. Betrachten wir eine geordnete Folge {x1, x2, x3, ..., xN} mit x1 x2 x3 ... xN , dann ist der Median definiert durch
( xN / 2 + xN / 2 +1 ) / 2 x50% = ® ¯ x( N +1) / 2
N gerade N ungerade
(2.7)
Bei Rangmerkmalen, wo eine Addition natürlich nicht definiert ist, kann man bei einer geraden Anzahl von Werten entweder xN/2 oder x(N/2)+1 als Median wählen. Seine starke Resistenz gegenüber Extremwerten macht ihn besonders für die Beseitigung von einzelnen Ausreißern in Datenreihen interessant. Hierzu mehr im Abschn. 2.10. So verschieden arithmetischer Mittelwert und Median auch sind, besteht zwischen beiden Lageparametern doch auch eine gewisse Affinität. Daher mag zunächst die Entscheidung schwerfallen, welcher Kenngröße der Vorzug zu geben ist. Wie man sich wohl denken kann, hängt die Beantwortung dieser Frage vom jeweiligen Sachzusammenhang ab. Bei symmetrischen Verteilungen fallen beide Größen ohnehin zusammen, wogegen bei schiefen Verteilungen (viele kleine Werte und nur wenige große, oder umgekehrt) der Median den Schwerpunkt oft besser beschreibt. Die beiden Lageparameter reichen jedoch nicht aus, um die Verteilung von Daten statistisch vollständig zu beschreiben, da sie keinerlei Aussage darüber machen, wie diese Daten angeordnet bzw. verteilt sind. So haben
2.5 Lage-, Streu- und Formparameter in der Statistik 117
die Stichproben (49, 50, 51) und (1, 50, 99) zwar den gleichen Mittelwert und auch den gleichen Median, es ist aber wohl für jeden sofort offensichtlich, daß sie unterschiedlich stark um diesen Bezugspunkt streuen. Um unsere Daten noch genauer beschreiben zu können, benötigen wir daher ein Streumaß. 2.5.3 Die Spannweite
Das einfachste Streumaß ist die Spannweite w, die sich aus der Differenz des größten und des kleinsten Einzelwertes einer Stichprobe ergibt. Ein wesentlicher Nachteil der Spannweite ist, daß man sich bei ihrer Berechnung ausschließlich auf zwei Extremwerte stützt, wogegen alle übrigen Werte völlig unberücksichtigt bleiben.
w = xmax − xmin
(2.8)
Nimmt durch Hinzunahme von weiteren Meßwerten der Stichprobenumfang zu, kann auch die Spannweite offensichtlich immer nur größer werden. Sie ist daher nicht besonders charakteristisch, sondern eignet sich nur für eine erste, sehr grobe Beschreibung. Der Berechnungsaufwand steckt vor allem im Auffinden der beiden Extremwerte. Liegen die Daten bereits als geordnete Folge vor, beispielsweise weil zuvor der Median berechnet worden ist, dann sind sie identisch mit den Gliedern x1 und xN dieser Folge. 2.5.4 Die mittlere absolute Abweichung
Betrachten wir nun für jeden einzelnen unserer Meßwerte den absoluten Abstand zum Mittelwert. Die Addition dieser Abstände, dividiert durch die Anzahl der Meßwerte, ergibt die mittlere absolute Abweichung.
dx =
1 N ⋅ ¦ xk − x N k =1
(2.9)
Die Betragsbildung stellt sicher, daß sich in der Summe die positiven und die negativen Differenzen nicht gegenseitig aufheben. Als Ergebnis dieser einfachen Berechnung erhält man den mittleren Abstand aller Meßwerte von ihrem gemeinsamen Mittelwert. Analog hierzu kann die durchschnittliche Abweichung der einzelnen Werte auch mit dem Median als Bezugspunkt gebildet werden, sofern sie skalar sind. Tatsächlich ist dieses Streumaß in Verbindung mit dem Mittelwert eher selten und wird vorzugsweise mit dem Median angewendet.
118 2 Statistische Signalverarbeitung
2.5.5 Die Standardabweichung und die Varianz
Aus dem zentralen Grenzwertsatz folgt die besondere Stellung der Normalverteilung für die Fehlerbehandlung in der physikalischen Meßtechnik. Die Standardabweichung oder Streuung stellt dabei die Breite der Wahrscheinlichkeitsdichtefunktion (Glockenkurve) dar. Sie kann auch als mittlere quadratische Abweichung vom Mittelwert aufgefaßt werden und berechnet sich für eine Stichprobe aus N Werten:
s=
N 1 ⋅ ¦ ( xk − x ) 2 N − 1 k =1
(2.10)
Wie man sieht, ist der Berechnungsaufwand durch die Quadratur der Abweichung und die abschließende Bildung der Wurzel vergleichsweise groß. Anders als beim Mittelwert, läßt sich hier jedoch für Online-Anwendungen nicht auf eine einfache rekursive Formel zur Berechnung zurückgreifen, da sich der Mittelwert im Allgemeinen mit jedem neuen Meßwert ändert. Anstelle der Standardabweichung wird häufig auch ihr Quadrat verwendet, die Varianz. Es ist üblich, die Varianz s2 und die Standardabweichung s mit demselben Formelbuchstaben zu bezeichnen, was die Gleichwertigkeit beider Streumaße unterstreicht. Aufgrund der Wurzel unterscheiden sie sich aber in ihrer Dimension. Hier hat die Standardabweichung einen klaren Vorteil, da sie dieselbe physikalische Einheit (Volt, cm, ...) hat, wie die Einzelwerte der Stichprobe und der aus ihnen gebildete Mittelwert. Man bezeichnet die Varianz s2 auch als das zweite zentrale Moment.
s2 =
N 1 ⋅ ¦ ( xk − x ) 2 N − 1 k =1
(2.11)
Durch die Bildung der Differenz aus aktuellem Wert und Mittelwert ist die Berechnung der Standardabweichung nach Gln. (2.10) numerisch ungünstig. Sind beide ungefähr gleich groß, dann entstehen sehr kleine Differenzen, die anschließend auch noch quadriert werden. Wegen der Zahlendarstellung im Computer kommt es hierbei zu einem unerwünschten Genauigkeitsverlust. Man findet deshalb auch Berechnungen, die diese Differenz vermeiden.
s=
N 1 ⋅ ¦ ( xk2 − 2 ⋅ xk ⋅ x + x 2 ) N − 1 k =1
s=
N N 1 ⋅ (¦ xk2 − 2 ⋅ x ⋅ ¦ xk + N ⋅ x 2 ) N − 1 k =1 k =1
2.5 Lage-, Streu- und Formparameter in der Statistik 119
s=
N 1 ⋅ (¦ xk2 − 2 ⋅ x ⋅ N ⋅ x + N ⋅ x 2 ) N − 1 k =1
s=
N 1 ⋅ (¦ xk2 − N ⋅ x 2 ) N − 1 k =1
(2.12)
Neben den bisher beschriebenen Lage- und Streuparametern gibt es schließlich auch noch Formparameter, welche die Stichprobe mit der Normalverteilung vergleichen. In der Realität sind Stichproben natürlich selten exakt normalverteilt. Sehr häufig sind sie flacher oder steiler als eine Normalverteilung und zudem oft auch unsymmetrisch. Die nachfolgenden Kennwerte beschreiben solche Abweichungen und lassen sich daher auch zur Prüfung einer Stichprobe auf Normalverteilung einsetzen. 2.5.6 Die Schiefe
Mit der Schiefe (engl. skewness) wird die Symmetrie einer Verteilung bezüglich ihres Mittelwertes bestimmt. Sie bildet das zentrale Moment dritter Ordnung.
γ =
N 1 ⋅ ¦ ( xk − x )3 N ⋅ s 3 k =1
(2.13)
Liegt eine ideal normalverteilte Stichprobe vor, dann ist deren Schiefe Null, wie übrigens auch bei allen anderen symmetrischen Verteilungen (Gleichverteilung, Dreiecksverteilung, ...). Ein negativer Wert weist auf eine linksschiefe bzw. rechtssteile Verteilungsdichte hin. Hier gibt es sehr viele große Werte und nur wenige kleine Werte. Ein positiver Wert weist dagegen auf eine rechtsschiefe bzw. linkssteile Verteilungsdichte. Eine solche Stichprobe enthält nur wenige große Werte, aber viele kleine Werte. Weicht also die Schiefe einer Stichprobe signifikant von Null ab, dann
Ȗ>0
0,8
0,8
0,6
0,6
f(x)
f(x)
Ȗ<0
0,4 0,2
0,4 0,2
0
0 -5
-4
-3
-2
-1
0
1
2
3
4
5
-5
-4
-3
-2
-1
x
Abb. 2.5. Schiefe Verteilungsdichtefunktionen
0
x
1
2
3
4
5
120 2 Statistische Signalverarbeitung
kann man die Hypothese, es handele sich hierbei um eine Normalverteilung, mit Sicherheit verwerfen. Ist eine Verteilung nicht symmetrisch, ist sie eben auch nicht normalverteilt. Da die Umkehrung nicht gilt, verfügen wir somit zumindest über ein Ausschlußkriterium. 2.5.7 Die Kurtosis
Die Kurtosis, manchmal auch Exzeß genannt, bildet das zentrale Moment vierter Ordnung und ist ein Maß für die Wölbung einer Verteilung, verglichen mit der Normalverteilung. Sie beschreibt, wie stark oder wie schwach der zentrale Bereich und die Randbereiche besetzt sind.
c=
N 1 ⋅ ( xk − x ) 4 4 ¦ N ⋅ s k =1
(2.14)
Die Kurtosis einer ideal normalverteilten Stichprobe hat den Wert c = 3. Manchmal findet man aber auch Berechnungsformeln, bei denen Drei subtrahiert wird, damit sich im Idealfall der Wert Null ergibt. Ein Wert kleiner als Drei (bzw. Null) deutet auf eine flachere Verteilung als die Normalverteilung hin, wogegen eine steilere Verteilung entsprechend einen Wert größer als Drei (bzw. Null) ergibt. c>3 0,8
0,6
0,6
f(x)
f(x)
c<3 0,8
0,4 0,2
0,4 0,2
0
0 -5
-4
-3
-2
-1
0
x
1
2
3
4
5
-5
-4
-3
-2
-1
0
1
2
3
4
5
x
Abb. 2.6. Verteilungsdichtefunktionen unterschiedlicher Wölbung
Bei der Verwendung dieser beiden Formparameter muß man allerdings immer im Hinterkopf behalten, daß sie nur bei genügend großen Stichproben auch wirklich aussagekräftig sind, also einen Rückschluß auf die Form der Grundgesamtheit zulassen. In der nachfolgenden Tabelle sind sie, auf der Basis unseres Zufallsgenerators aus Abschn. 2.2, für unterschiedliche Verteilungsdichten (siehe Abb. 2.2) berechnet. Deutlich erkennbar, können sie auch beim gewählten Stichprobenumfang von N = 10000 noch vom jeweiligen Idealwert abweichen.
2.5 Lage-, Streu- und Formparameter in der Statistik 121 Tabelle 2.1. Schiefe und Kurtosis für unterschiedliche Stichproben Verteilungsdichte der Stichprobe
Gleichverteilung Dreiecksverteilung Normalverteilung Exponentialverteilung
Formparameter Ȗ = 0,005 c = 1,827 Ȗ = 0,007 c = 2,426 Ȗ = −0,028 c = 2,983 Ȗ = 2,129 c = 10,364
Die Berechnung der statistischen Kennwerte zu implementieren sollte jetzt kein Problem mehr sein. Zu beachten ist lediglich, daß Varianz und Streuung durch N−1 dividiert werden, weshalb diese erst für N > 1 existieren. Wie könnte eine aus nur einem einzigen Wert bestehende Stichprobe auch streuen? Konsequenterweise gilt das dann auch für die Schiefe und die Kurtosis. class Statistik { // Stichprobenumfang const int Abtastwerte = 512; // Stichprobe public double[] x = new double[Abtastwerte]; public void BerechneStatistik() { int anzahl = 0; // Aktueller Stichprobenumfang double miwert1 = 0; // Mittelwert double miwert2 = 0; // rekursiver Mittelwert double median = 0; // Median double spannw = 0; // Spannweite double delta = 0; // Mittlere absolute Abweichung double streu1 = 0; // Streuung double streu2 = 0; // Streuung (2. Variante) double varianz1 = 0; // Varianz double varianz2 = 0; // Varianz (2. Variante) double schiefe = 0; // Schiefe double kurtosis = 0; // Kurtosis for (int k=0; k
122 2 Statistische Signalverarbeitung
// Mittelwert miwert1 = 0; for (int i=0; i 1) // wegen Division durch N-1 { varianz1 = 0; for (int i=0; i 1) // wegen Division durch N-1 { varianz2 = 0; for (int i=0; i
2.5 Lage-, Streu- und Formparameter in der Statistik 123
} // Streuung streu1 = Math.Sqrt(varianz1); // Streuung (2. Variante) streu2 = Math.Sqrt(varianz2); // Schiefe if (anzahl > 1) // wegen Streuung=0 bei N=1 { schiefe = 0; for (int i=0; i 1) // wegen Streuung=0 bei N=1 { kurtosis = 0; for (int i=0; i
Um den Median zu bestimmen, ist außerdem noch ein Sortieralgorithmus notwendig. Leider wird es jetzt richtig kompliziert. Wohl kaum ein Gebiet innerhalb der Informatik wurde so gründlich untersucht, wie die verschiedenen Sortierverfahren. Von Quicksort, Bubblesort, Heapsort oder den sonstigen Algorithmen hat wahrscheinlich jeder schon einmal gehört. Sie unterscheiden sich in der Hauptsache durch die notwendige Anzahl von Operationen, um eine Menge von Elementen zu sortieren. Insbesondere bei großen Mengen, etwa bei mehr als 1000 Elementen, macht sich die Leistungsfähigkeit des gewählten Verfahrens im Rechenzeitbedarf deutlich
124 2 Statistische Signalverarbeitung
bemerkbar. Wir wollen uns an dieser Stelle aber nicht weiter in diese sehr komplexe Thematik vertiefen. Für Interessierte sei darum auf den Anhang verwiesen, wo näher auf Sortierverfahren eingegangen wird. class Statistik { ... public double[] sort = new double[Abtastwerte]; ... public double Median(int k) { double median = 0; // Arbeitskopie der Stichprobe anlegen for (int i=0; i
Die Abweichung von Gln. (2.7) sollte nicht weiter irritieren. Sie resultiert aus der in C# und auch in vielen anderen Programmiersprachen üblichen Feldindizierung von 0..N−1.
2.6 Stichprobe und Grundgesamtheit Betrachtet man eine Anzahl von Einzelwerten, um diese statistisch zu untersuchen, dann stellt eine solche Stichprobe meist nur einen relativ kleinen
2.6 Stichprobe und Grundgesamtheit 125
Ausschnitt aus der Grundgesamtheit dar. Aus Kostengründen versucht man aus einer möglichst kleinen Untermenge auf die Eigenschaften der Grundmenge zu schließen: • Vor Wahlen möchte man mit Hilfe von repräsentativen Umfragen die politische Stimmungslage der Bevölkerung prognostizieren. • Bei einer physikalischen Messung werden in festen zeitlichen Abständen Einzelwerte aus dem üblicherweise kontinuierlichen Signalverlauf entnommen. Für beide Beispiele leuchtet unmittelbar ein, je größer die verfügbare Datenmenge ist, um so besser stimmt sie mit der Realität überein. Vergrößert man eine Stichprobe immer weiter, bis sie schließlich mit der Grundgesamtheit identisch ist, dann nähern sich die statistischen Kenngrößen der beiden Mengen im gleichen Maße an. Man bezeichnet diesen Zusammenhang in der Statistik als das Gesetz der großen Zahlen. Selbst wenn sich die statistischen Kennwerte beider Mengen annähern, sollte man sich immer vor Augen halten, daß dies genau genommen nur für den Grenzübergang N ĺ gilt. In der Realität unterscheiden sich Stichprobe und Grundgesamtheit daher mehr oder weniger stark. Während der Erwartungswert μ und die Standardabweichung ı für einen stationären Prozeß konstant sind, ändern sich die Kenngrößen für das durch diesen Prozeß erzeugte Signal, also die Stichprobe, normalerweise mit jedem neuen Wert. Man bezeichnet Mittelwert und Standardabweichung der Stichprobe auch als Schätzung von μ und ı der Grundgesamtheit, die sich, zumindest theoretisch, auch berechnen lassen. Der Erwartungswert μ ergibt sich (wie auch der Mittelwert) nach Gln. (2.5), wogegen für ı Gln. (2.15) gilt.
σ =
1 N ⋅ ¦ ( xk − μ ) 2 N k =1
(2.15)
Abweichend von Gln. (2.10) wird hier durch N dividiert. Früher war dies auch für die Standardabweichung der Stichprobe üblich. Es hat sich aber gezeigt, daß man dadurch im Mittel etwas zu kleine Werte erhält, verglichen mit der Grundgesamtheit. Zum Ausgleich wird bei der Stichprobe jetzt durch N−1 dividiert. Tatsächlich entspricht es wohl der allgemeinen Erwartung, daß kleine Stichproben mit einer größeren Unsicherheit behaftet sind als große Stichproben. Vergrößert man nun die Stichprobe immer weiter, wird folglich auch die verbleibende Unsicherheit in den Daten immer kleiner, was schließlich die kleinere Streuung der Grundgesamtheit erklärt. Man kann diesen Unterschied auch mit dem Verlust eines Freiheitsgrades begründen. Er resultiert aus dem Umstand, daß in die
126 2 Statistische Signalverarbeitung
Standardabweichung der Stichprobe der Mittelwert eingeht, der ja ebenfalls aus den N vorliegenden Einzeldaten berechnet wurde. Letztlich sollte man sich jedoch um die Verwendung der richtigen Formel nicht allzuviel Gedanken machen, da man für große N den Unterschied zwischen N und N−1 ohnehin vernachlässigen kann. Da die aus einer Stichprobe ermittelten Kenngrößen Mittelwert und Standardabweichung nur Schätzungen für die Grundgesamtheit sind, stellt sich die Frage, mit welcher Unsicherheit diese nun selbst behaftet sind. Es ist also durchaus von Interesse, wie weit der Mittelwert der Stichprobe vom Erwartungswert der Grundgesamtheit abweicht. Liegen keine extremen Abweichungen einzelner Stichprobenwerte von der Normalverteilung vor, dann darf man zu Recht annehmen, daß auch die Mittelwerte verschiedener Stichproben gleichmäßig um den Erwartungswert der Grundgesamtheit streuen. Man bezeichnet diese Abweichung allgemein als Standardfehler. Er läßt sich mit Hilfe der Standardabweichung s bestimmen.
sx =
s N
(2.16)
Tatsächlich bestätigt diese Formel unsere bereits zuvor getroffene Feststellung. Je größer man eine Stichprobe wählt, desto genauer wird die Schätzung für die Grundgesamtheit. Der Standardfehler verkleinert sich mit zunehmender Anzahl N und der Mittelwert strebt gegen den Erwartungswert.
2.7 Standardisierte Maßzahlen – Die z-Transformation Möchte man die Ausprägungen verschiedener Stichproben miteinander vergleichen, z. B. in einer gemeinsamen Grafik, dann stören die meist stark unterschiedlichen Merkmalsdimensionen erheblich. Abhilfe schafft hier die Anwendung der z-Transformation, mit der die Daten so standardisiert werden, daß sie anschließend den Mittelwert Null und die Standardabweichung Eins haben. Da es sich um eine lineare Transformation handelt, verändert sie nicht den grundsätzlichen Charakter der Verteilung, so daß eine transformierte Stichprobe die selben Schlußfolgerungen erlaubt, wie die ursprünglichen Daten.
zk =
xk − x s
(2.17)
Für Meßwerte xk kleiner als der Mittelwert ergeben sich negative zk, für Meßwerte größer als der Mittelwert positive zk. Die Differenzbildung aus
2.8 Die Korrelationsanalyse 127
ursprünglichem Einzelwert und Mittelwert dividiert durch die Standardabweichung sorgt dafür, daß zk dimensionslos ist. Aber, auch nach einer zTransformation ist es nur dann sinnvoll zwei Meßwertreihen miteinander zu vergleichen, wenn dies inhaltlich begründet ist.
2.8 Die Korrelationsanalyse Das man es immer nur mit genau einer Meßwertreihe zu tun hat, ist wohl eher selten der Fall. Sehr oft liegen dagegen mehrere Meßreihen vor, und es stellt sich dann die Frage, ob eventuell ein Zusammenhang zwischen den Beobachtungsreihen besteht. Eine Möglichkeit dies zu erkennen, ist das in Abschn. 2.4.2 vorgestellte Streudiagramm, anhand der sich dort ausbildenden Muster. Es macht aber nur eine qualitative Aussage. Was noch fehlt ist eine Maßzahl, um die lineare Abhängigkeit zwischen Meßreihen auch zu quantifizieren. Aus diesem Bedürfnis heraus hat sich die Korrelationsanalyse entwickelt. 2.8.1 Empirische Korrelation
Da eine solche Maßzahl nicht von der Dimension der Merkmale abhängen soll, betrachten wir standardisierte Daten.
x −x ~ xk = k sx
y −y ~ yk = k sy Unser Ziel ist es, Wechselwirkungen in den Daten zu erkennen. Da uns aber der genaue funktionale Zusammenhang nicht bekannt ist, gehen wir vom einfachsten Fall aus und vermuten eine lineare Abhängigkeit. Wir erinnern uns an die Bedeutung des Vorzeichens bei der im vorherigen Abschnitt vorgestellten z-Transformation. Unabhängig vom ursprünglichen Wertebereich sind die standardisierten Daten positiv oder negativ, je nachdem, ob die Originaldaten größer oder kleiner als der jeweilige Mittelwert sind. Eine gleichläufige oder gegenläufige Abhängigkeit unserer Meßreihen ist daher am Vorzeichen des Produkts beider Reihen erkennbar. Wir wollen dieses Produkt mit rxy bezeichnen. Um von der Anzahl der Daten
128 2 Statistische Signalverarbeitung
unabhängig zu sein, wird zusätzlich normiert (weil sich das später als günstig erweist mit N−1, statt mit N).
rxy =
N 1 ⋅¦~ xk ⋅ ~ yk N − 1 k =1
(2.18)
Somit können wir rxy immerhin schon in Bezug auf sein Vorzeichen interpretieren. Ein positives Vorzeichen bedeutet, daß vorwiegend die überdurchschnittlichen Werte von xk mit den überdurchschnittlichen Werten yk gepaart sind, wie auch die unterdurchschnittlichen Werte von xk jeweils mit den unterdurchschnittlichen Werten yk. Umgekehrt zeigt ein negatives Vorzeichen an, daß vorwiegend die überdurchschnittlichen Werte von xk mit den unterdurchschnittlichen Werten yk gepaart sind, ebenso die unterdurchschnittlichen Werte von xk mit den überdurchschnittlichen Werten yk. Leider ist Gln. (2.18) wenig transparent, weshalb wir umformen.
rxy =
1 ¦ ( xk − x ) ⋅ ( yk − y ) ⋅ N −1 sx ⋅ s y
rxy =
1 ⋅ N −1
− x ) ⋅ ( yk − y )
¦(x
k
1 1 ⋅ ¦ ( xk − x ) 2 ⋅ ⋅ ¦ ( yk − y ) 2 N −1 N −1 ¦ ( xk − x ) ⋅ ( yk − y )
rxy =
¦ ( xk − x )2 ⋅
¦ ( yk − y ) 2
(2.19)
Man nennt rxy den empirischen Korrelationskoeffizienten oder auch den Pearson-Korrelationskoeffizienten. Er entspricht dem Cosinus des Winkels zwischen den Vektoren x und y, im Sinne eines Skalarproduktes. In der oberen Momenten-Form ergeben sich aber die gleichen Nachteile bei der Berechnung, wie wir sie schon bei der Standardabweichung festgestellt haben. Durch Ausmultiplizieren und Umformung kommen wir zu einer numerisch günstigeren Form. Hierzu eine kurze Zwischenrechnung:
¦ (x − x) ⋅ ( y − y) = ¦ (x y − x y − x y = ¦x y − y ⋅¦x − x ⋅¦ y + Nxy 1 1 = ¦x y − ⋅¦ y ¦x − ⋅¦x ¦ y N N k
k
k
k
k
k
= ¦ xk y k −
=
k
k
k
k
k
+ x y)
k
+
k
k
k
1 ⋅ ¦ xk ¦ yk N
1 ⋅ ( N ⋅ ¦ xk yk − ¦ xk ¦ yk ) N
k
1 ⋅ ¦ xk ¦ y k N
2.8 Die Korrelationsanalyse 129
Ersetzen wir in Gln. (2.19) den Zähler durch unsere Umformung (im Nenner entsprechend), stützt sich die Berechnung nur noch auf die Einzelwerte.
rxy =
N ⋅ ¦ xk yk − ¦ xk ¦ yk N ⋅ ¦ xk2 − (¦ xk ) 2 ⋅ N ⋅ ¦ yk2 − (¦ yk ) 2
(2.20)
class Daten { const int Abtastwerte = 128; // Signale x(k) und y(k) public double[] x = new double[Abtastwerte]; public double[] y = new double[Abtastwerte]; // Korrelationskoeffizient public double rxy; // Konstruktor public Daten() { rxy = 0; } public void Korrelation() { double sumx = 0; double sumy = 0; double sumxx = 0; double sumyy = 0; double sumxy = 0; for (int k=0; k
130 2 Statistische Signalverarbeitung (Abtastwerte*sumyy - sumy*sumy))); } ... }
Wie wir gesehen haben, basiert die lineare Korrelation nach Pearson auf eine z-Transformation der ursprünglichen Meßwerte. Die z-Transformation selbst berechnet sich über den Mittelwert und die Standardabweichung, die aber ihrerseits nur bei normalverteilten Meßreihen sinnvoll sind. Somit ist strenggenommen auch die beschriebene Korrelation nur auf Meßreihen anwendbar, die einer Normalverteilung unterliegen. Der Korrelationskoeffizient rxy nimmt Werte zwischen –1 und +1 an. Dabei bedeutet rxy = 0, daß zwischen den Meßreihen x und y überhaupt kein Zusammenhang besteht, wogegen die Werte +1 bzw. –1 eine direkte Proportionalität bzw. einen umgekehrt proportionalen Zusammenhang implizieren. Welche Werte nun einen „besonders starken“ oder „weniger starken“ Zusammenhang anzeigen, läßt sich natürlich nicht exakt festlegen. Trotzdem wird man im täglichen Gebrauch dazu neigen, die Korrelation von Meßreihen (und damit einzelne Werten von rxy) verbal zu beschreiben. 0,0 < |rxy| 0,2 0,2 < |rxy| 0,5 0,5 < |rxy| 0,7 0,7 < |rxy| 0,9 0,9 < |rxy| 1,0
„sehr geringe Korrelation“ „geringe Korrelation“ „mittelstarke Korrelation“ „starke Korrelation“ „sehr starke Korrelation“
Bei der Herleitung von Gln. (2.19) hatten wir schon erwähnt, daß rxy dem Skalarprodukt der beiden Meßwertvektoren x = {x0 x1 x2 ... xN−1} und y = {y0 y1 y2 ... yN−1} entspricht. Das Skalarprodukt berechnet sich aus der Summe der einzelnen Koordinatenprodukte oder, in unserem Fall, aus der Summe aller Meßwertprodukte. x·y = x0·y0 + x1·y1 + x2·y2 + ... + xN−1·yN−1
In dieser Form ist das Skalarprodukt auch von der Anzahl N der einbezogenen Meßwerte abhängig, weshalb wir zweckmäßigerweise durch N dividieren. Durch einen zeitlichen Versatz m zwischen beiden Reihen, der zunächst frei wählbar sei, erhalten wir eine Vielzahl von verschiedenen Korrelationsmaßen.
rxy (m) =
1 N −1 ⋅ ¦ xk ⋅ yk − m N k =0
(2.21)
2.8 Die Korrelationsanalyse 131
Es fällt nicht sofort auf, aber für die Implementierung ist Gln. (2.21) ungeeignet. Bei einem unendlichen Strom von Meßdaten würde die Indexverschiebung k-m keine Probleme bereiten, in der Realität hat man es jedoch immer nur mit einer begrenzten Anzahl von Werten zu tun. Dementsprechend lassen sich N-m Produktpaare bilden.
rxy (m) =
N −1 1 ⋅ ¦ xk ⋅ yk − m N − m k =0
(2.22)
Dabei unterscheidet sich rxy(0) so wenig vom Pearson-Koeffizienten nach Gln. (2.20), daß man für alle praktischen Anwendungen von identischen Werten ausgehen kann (die relative Abweichung beträgt etwa 1%). Allerdings ändert sich das sehr schnell mit zunehmendem m, wie man sich leicht denken kann. Der immer größere Versatz beider Meßreihen wirkt natürlich auch auf das Ergebnis der Korrelation. Man verwendet die Kreuzkorrelation rxy, um Wechselwirkungen zwischen zwei verschiedenen Zeitreihen zu erkennen. Es gibt aber auch Anwendungen, in denen es sinnvoll ist, die Ähnlichkeit eines Signals mit sich selbst zu untersuchen. Man spricht dann von Autokorrelation und drückt das mit dem Koeffizienten rxx aus. Anders als bei der Kreuzkorrelation, interessiert bei der Autokorrelation zumeist die Abhängigkeit von der zeitlichen Verschiebung, d. h. man berechnet rxx(m) tatsächlich als Funktion von m und stellt das Ergebnis rxx = f(m) entsprechend dar. Gerade hierdurch werden Signaleigenschaften sichtbar, die im zeitlichen Verlauf des Signals nicht zu erkennen sind, durchaus vergleichbar mit den Betrachtungen von Zeitbereich und Frequenzbereich in der digitalen Signalverarbeitung. Wegen der funktionalen Abhängigkeit bezeichnet man rxx(m) auch als Autokorrelationsfunktion (AKF). Für die praktische Anwendung sei noch auf einen kleinen Randeffekt hingewiesen. Nähert sich die zeitliche Verschiebung m der Anzahl der Abtastwerte N an, dann stützt sich rxx(m) nur auf wenige Werte. Gleichzeitig wird der Normierungsfaktor (N-m) vom Betrag sehr klein. Um den verfälschenden Einfluß von Ausreißern klein zu halten, nehmen wir das Intervallende von der Berechnung aus, indem wir m statt von 0 bis N−1 nur von 0 bis N/2−1 laufen lassen. class Daten { public double[] korrxx = new double[Abtastwerte]; ... public void Autokorrelation() {
132 2 Statistische Signalverarbeitung // Korrelation als Skalarprodukt, // abhängig von der zeitlichen Verschiebung m for (int m=0; m
Als erstes Beispiel betrachten wir eine N(0,1)-normalverteilte Folge von Zufallswerten. Da deren Werte im Idealfall als unabhängige Einzelereignisse anzusehen sind, sollte auch nur rxx(m = 0) einen Beitrag leisten, wogegen für alle anderen m die AKF verschwindet. Als Bild der AKF ergibt sich somit ein Dirac-Impuls. Zumindest gilt das, wenn die Anzahl der Abtastwerte unendlich ist. In der Praxis hat man es aber wohl eher mit einer beschränkten Anzahl von Meßwerten zu tun, was dazu führt, daß rxx(m > 0) dann zwar deutlich kleiner ist als rxx(0) = 1, aber eben nicht genau Null, höchstens einmal zufällig. 1
3
0,8
2
0,6 0,4
0 0
16
32
48
64
-1
80
96
112
rxx(m)
x(k)
1
0,2 0 -0,2 0
16
32
48
64
80
96
112
-0,4 -0,6
-2
-0,8 -1
-3
k
m
Abb. 2.7. Weißes Rauschen und Autokorrelationsfunktion
Als zweites Beispiel wollen wir die AKF eines periodischen Signals bestimmen. Zu diesem Zweck überlagern wir ein Sinussignal mit N(0,1)verteiltem Rauschen. Interessanterweise ist die AKF eines periodischen Signals wiederum periodisch und das auch noch mit der selben Frequenz. Somit eignet sich die AKF zur Bestimmung der Periodizität von Signalen, bei denen das aufgrund von Rauschen oder anderen Störungen sonst nicht möglich wäre.
2.8 Die Korrelationsanalyse 133 3
1 0,8
2
0,6 0,4
rxx(m)
x(k)
1 0 0
16
32
48
64
80
96
112
-1
0,2 0 -0,2 0 -0,4
16
32
48
64
80
96
112
-0,6 -0,8
-2 -3
-1
k
m
Abb. 2.8. Verrauschter Sinus und Autokorrelationsfunktion
2.8.2 Korrelation im Streudiagramm
Ein sehr nützliches Hilfsmittel zur grafischen Analyse von Abhängigkeiten zwischen zwei Datenreihen haben wir mit dem Streudiagramm bereits in Abschn. 2.4.2 kennengelernt. Um zu prüfen, ob zwischen zwei Datenreihen ein Zusammenhang besteht, werden alle Meßwerte x(k), y(k) jeweils paarweise als Punkte eines 2-dimensionalen x-y-Koordinatensystems aufgetragen. Abhängigkeiten in den Daten lassen sich dann leicht an der Ausbildung charakteristischer Muster erkennen. Nachfolgend einige Beispiele in standardisierter Form. Tabelle 2.2. Lineare Korrelation im Streudiagramm 2
rxy = 0,99 „sehr starke Korrelation“
y(k)
1
0 -3
-2
-1
0
1
2
3
1
2
3
-1
-2
x(k)
2
rxy = 0,74 „starke Korrelation“
y(k)
1
0 -3
-2
-1
0 -1
-2
x(k)
134 2 Statistische Signalverarbeitung 2
rxy = 0 „keine Korrelation“
y(k)
1
0 -3
-2
-1
0
1
2
3
1
2
3
-1
-2
x(k) 2
rxy = −0,99 „sehr starke Korrelation“
y(k)
1
0 -3
-2
-1
0 -1
-2
x(k)
Bei der Herleitung von rxy haben wir eine lineare Abhängigkeit zwischen den Datenreihen x(k) und y(k) vorausgesetzt. Diese resultiert aus dem Produktansatz in Gln. (2.18). Das bedeutet aber keineswegs, daß die Korrelationsanalyse nur bei Meßwerten anwendbar ist, die einem linearen Bildungsgesetz folgen. Eine solche Forderung würde den Nutzen doch erheblich einschränken. Vielmehr können die beiden Datenreihen x(k) und y(k) beliebig nichtlinear sein, lediglich die funktionale Abhängigkeit y(k) = f(x(k)) zwischen ihnen muß diese Voraussetzung erfüllen, damit wir das Ergebnis richtig interpretieren können. Letztlich ist Gln. (2.20) nur eine Formel, deren richtige Benutzung in der Verantwortung des Anwenders liegt. Ist also die Art der Abhängigkeit nicht bekannt oder wird ein linearer Zusammenhang lediglich vermutet, dann ist man gut beraten, neben dem berechneten Wert von rxy zusätzlich das Streudiagramm heranzuziehen. Tabelle 2.3 zeigt einige Beispiele nichtlinearer Abhängigkeiten in standardisierter Form. Im ersten Fall würde man wohl zu recht einen quadratischen Zusammenhang vermuten. Das zweite Beispiel zeigt ebenfalls eine quadratische Abhängigkeit, allerdings sind hier alle x(k) > 0. Die gleichläufige Zunahme beider Meßreihen hat einen entsprechend hohen (linearen) Korrelationskoeffizienten zur Folge, obwohl doch eigentlich ein nichtlinearer Zusammenhang besteht. Im letzten Beispiel sind x(k) = sin(2ʌk/N) und y(k) = cos(2ʌk/N). Die Korrelation der beiden Signale zeigt sich deutlich an der charakteristischen Musterbildung im Streudiagramm, nicht jedoch in rxy. Somit lassen sich Ähnlichkeiten in Meßreihen allein mit dem Korrelationskoeffizienten nicht immer sicher erfassen.
2.8 Die Korrelationsanalyse 135 Tabelle 2.3. Nichtlineare Korrelation im Streudiagramm 2
y(k)
1
rxy = 0 „keine Korrelation“ ĺ falsch
0 -3
-2
-1
0
1
2
3
1
2
3
1
2
3
-1
-2
x(k)
2
y(k)
1
rxy = 0,94 „sehr starke Korrelation“ ĺ richtig
0 -3
-2
-1
0 -1
-2
x(k)
2
y(k)
1
rxy = 0 „keine Korrelation“ ĺ falsch
0 -3
-2
-1
0 -1
-2
x(k)
2.8.3 Korrelation und Kausalität
Wir wollen einmal annehmen, es lägen zwei Beobachtungsreihen vor, die deutlich korrelieren (gleichläufig rxy § 1 oder gegenläufig rxy § −1). Kann man aus dieser Korrelation auf eine innere Beziehung zwischen beiden Reihen schließen? Wirkt eine Größe auf die andere (oder umgekehrt), weil beide parallel verlaufen? Eine solche Schlußfolgerung ist sehr verlockend, gehört aber zu den großen Irrtümern im Umgang mit statistischen Methoden. Besteht zwischen zwei Meßreihen ein kausaler Zusammenhang, dann korrelieren sie auch. Der Umkehrschluß ist dagegen nicht zulässig. Somit ist die Korrelationsanalyse zum Nachweis einer kausalen Abhängigkeit nicht geeignet. Sie zeigt lediglich auf, daß ein rein mathematischer Zusammenhang zwischen den betrachteten Größen besteht, auch dann, wenn diese in der Realität gar nichts miteinander zu tun haben (man spricht dann von Scheinkorrelation). Aus diesem Grund empfiehlt es sich dringend, rxy immer kritisch zu bewerten.
136 2 Statistische Signalverarbeitung
mathematisches Modell
Realität
Problem 1
zulässig
Kausalität
Größe 1 Korrelation
nicht zulässig Problem 2
Größe 2
Abb. 2.9. Zusammenhang von Kausalität und Korrelation
2.9 Die Regressionsanalyse Die Regression ist eng verwand mit der Korrelation, geht aber noch einen Schritt weiter. Sie fragt nicht nur danach, ob ein statistischer Zusammenhang zwischen den Merkmalen einer Stichprobe besteht, sondern ermöglicht es, diesen Zusammenhang mathematisch zu modellieren. In der Meßtechnik kommt es sehr häufig vor, daß eine gemessene Größe y (abhängige Variable) eine Funktion einer zweiten veränderlichen Größe x (unabhängige Variable) ist. Beispiele hierfür sind z. B. der elektrische Widerstand eines Leiters in Abhängigkeit von seiner Temperatur oder der Durchlaßstrom einer Diode in Abhängigkeit von der angelegten Spannung. Ist also bekannt, daß zwischen x und y eine Abhängigkeit besteht, dann erscheint die Frage nach dem funktionalen Zusammenhang y = f(x), also dem Bildungsgesetz, naheliegend. Da die meßtechnisch ermittelten Wertepaare {xk, yk} in der Regel fehlerbehaftet sind, werden sie der gesuchten Abhängigkeit y = f(x) nicht exakt folgen. Vielmehr werden die Meßdaten um den wahren Wert streuen. Das Ziel der Regressionsanalyse ist es, diejenigen Modellparameter zu finden, die den wahren funktionalen Zusammenhang am besten beschreiben. Hierfür ist es sehr hilfreich bereits zu Beginn der Analyse eine sehr konkrete Vermutung über die Art des Zusammenhangs zu haben, um eine geeignete Funktionsklasse als Modell zu wählen. 2.9.1 Lineare Regression
Im einfachsten Fall existiert zwischen den Größen x und y eine lineare Abhängigkeit. Tatsächlich kommt das in der Realität sehr oft vor. Der
2.9 Die Regressionsanalyse 137
gesuchte funktionale Zusammenhang kann somit durch eine Geradengleichung modelliert werden. Die Parameter dieser Gleichung sind dann derart zu bestimmen, daß die einzelnen Meßpunkte von der Geraden möglichst wenig abweichen. Man bezeichnet eine solche Gerade auch als Ausgleichsgerade (oder Regressionsgerade). Für eine Geradengleichung benötigen wir genau zwei Parameter. Einerseits die Steigung, die angibt, um wieviele Einheiten die abhängige Variable y steigt oder fällt, wenn sich die unabhängige Variable x um eine Einheit ändert. Andererseits der Achsenabschnitt, der das Basisniveau der abhängigen Variablen angibt, wenn die unabhängige Variable den Wert Null annimmt. Steigung und Achsenabschnitt der Geraden bilden die Regressionskoeffizienten dieses Ansatzes. Für unsere Meßwerte erhalten wir das folgende lineare Modell:
y ( x) = a0 + a1 ⋅ xk
(2.23)
Natürlich werden unsere so modellierten Werte y(xk) von den tatsächlichen Meßwerten yk aufgrund der Meßunsicherheit ein wenig abweichen. Wir wollen den Fehler zwischen beiden mit ek bezeichnen.
ek = y ( xk ) − yk = (a0 + a1 ⋅ xk ) − yk
(2.24)
Entsprechend der Methode der kleinsten Fehlerquadrate ist die Summe aller Fehlerquadrate, d. h. die Abweichungen über alle N aufgenommenen Meßwertpaare, zu minimieren (die Quadratur verhindert, daß sich positive und negative Fehler gegenseitig aufheben). N
¦e
2 k
= min
(2.25)
k =1
Natürlich hängt unser Fehler e von den Geradenparametern a0 und a1 ab. Somit können wir diese Extremalwertaufgabe mit Hilfe von zwei partiellen Ableitungen lösen.
∂ ¦ ek2 ∂ a0
=
∂ ¦ ek2 ∂ a1
=0
(2.26)
Weil im gesuchten Minimum alle anliegenden Tangenten gerade die Steigung Null haben (gilt natürlich auch für ein Maximum), verschwinden auch sämtliche partiellen Ableitungen. Wir berechnen zunächst e2/a1.
∂ ¦ ek2 ∂ a1
=
∂ ¦ (a0 + a1 ⋅ xk − yk ) 2 ∂ a1
(2.27)
138 2 Statistische Signalverarbeitung
Mit Hilfe der Kettenregel („...äußere Ableitung multipliziert mit der inneren Ableitung...“) läßt sich die rechte Seite auflösen.
2 ⋅ ¦ (a0 + a1 ⋅ xk − yk ) ⋅ xk = 0
(2.28)
Indem wir xk in die Klammer ziehen und die entstehende gemischte Summe auf die rechte Seite bringen, erhalten wir die erste Bestimmungsgleichung für die beiden unbekannten Regressionskoeffizienten.
a0 ⋅ ¦ xk + a1 ⋅ ¦ xk2 = ¦ xk ⋅ yk
(2.29)
Für die notwendige zweite Bestimmungsgleichung gehen wir ebenso vor, berechnen also zunächst e2/a0.
∂ ¦ ek2 ∂ a0
=
∂ ¦ (a0 + a1 ⋅ xk − yk )
2
(2.30)
∂ a0
Auch hier wird die Kettenregel angewendet. Die innere Ableitung ist Eins, was die weitere Rechnung ein wenig vereinfacht.
2 ⋅ ¦ (a0 + a1 ⋅ xk − yk ) = 0
(2.31)
Nach kurzer Umformung ergibt sich:
N ⋅ a0 + a1 ⋅ ¦ xk = ¦ yk
(2.32)
Mit den unabhängigen Gleichungen (2.29), (2.32) können wir endlich nach a0 und a1 auflösen. Hierfür stellen wir Gln. (2.32) nach a0 um.
a0 =
¦y
k
− a1 ⋅ ¦ xk
(2.33)
N
und setzen diesen Ausdruck anschließend in Gln. (2.29) ein. Was jetzt folgt, ist eine etwas langwierige, aber im Grunde doch simple Zwischenrechnung, um nach a1 aufzulösen.
§ ¦ yk − a1 ⋅ ¦ xk a1 ⋅ ¦ xk2 + ¨¨ N ©
a1 ⋅ ¦ xk2 +
¦ y ⋅¦x k
k
· ¸ ⋅ ¦ xk = ¦ xk ⋅ yk ¸ ¹
− a1 ⋅ (¦ xk ) 2 N
= ¦ xk ⋅ yk
N ⋅ a1 ⋅ ¦ xk2 − a1 ⋅ (¦ xk ) 2 = N ⋅ ¦ xk ⋅ yk − ¦ yk ⋅ ¦ xk
2.9 Die Regressionsanalyse 139
a1 ⋅ ( N ⋅ ¦ xk2 − (¦ xk ) 2 ) = N ⋅ ¦ xk ⋅ yk − ¦ yk ⋅ ¦ xk a1 =
N ⋅ ¦ xk ⋅ yk − ¦ yk ⋅ ¦ xk N ⋅ ¦ xk2 − (¦ xk ) 2
(2.34)
Mit den Gleichungen (2.33) und (2.34) können wir a0 und a1 nun endgültig berechnen. Dabei lassen sich bei der Implementierung die einzelnen Summen elegant in einer einzigen Schleife unterbringen, wenn man ein paar zusätzliche Hilfsvariablen einführt. An dieser Stelle weichen wir von unserer bisher üblichen Bezeichnung für Abtastfolgen ab, um bei der Notation y = f(x) bleiben zu können. class DatenModell { const int Abtastwerte = 16; // idealer Signalverlauf public double[] y = new double[Abtastwerte]; // gemessener Signalverlauf public double[] yi = new double[Abtastwerte]; // lineare Regressionskoeffizienten public double a0; public double a1; // Konstruktor public DatenModell() { a0 = 0; a1 = 0; } ... public void LineareRegression() { double sumx = 0; double sumy = 0; double sumxx = 0; double sumxy = 0; for (int { sumx sumy sumxx sumxy }
k=0; k
k; yi[k]; k*k; k*yi[k];
140 2 Statistische Signalverarbeitung // Geradensteigung a1 = (Abtastwerte*sumxy-sumx*sumy)/ (Abtastwerte*sumxx-sumx*sumx); // Achsenabschnitt a0 = (sumy-a1*sumx)/Abtastwerte; } ... }
Trotz der langen Herleitung ist die Implementierung erfreulich kompakt. Auch die Testdatengenerierung ist mit Hilfe normalverteilter Zufallszahlen denkbar einfach. class DatenModell { ... public void ErzeugeTestsignal_1() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k
f(x)
40 30 20 10 0 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
x
Abb. 2.10. Datenpunkte mit linearer Ausgleichsfunktion
2.9 Die Regressionsanalyse 141
2.9.2 Regression einer allgemeinen Polynomfunktion
Aber natürlich folgen nicht alle Meßreihen einer streng linearen Abhängigkeit. Sehr oft sind auch nichtlineare Anteile vorhanden. Dann macht sich neben einem linearen Term z. B. auch eine quadratische Abhängigkeit bemerkbar, oder es wirken sogar Glieder noch höherer Ordnung mit. Im allgemeinen Fall lassen sich solche Zusammenhänge mit einem Polynom n-ter Ordnung modellieren.
y ( x) = a0 + a1 ⋅ x + a2 ⋅ x 2 + a3 ⋅ x 3 + ... + an ⋅ x n
(2.35)
Grundsätzlich lassen sich in diesem Fall die Regressionsparameter auf die gleiche Weise bestimmen, wie beim linearen Modell. Wir wollen dies zumindest für ein Polynom zweiter Ordnung, also eine Parabel, noch einmal durchrechnen. Der Fehler zwischen den gemessenen Werten und unserem Modell ist dann:
ek = y ( xk ) − yk = (a0 + a1 ⋅ xk + a2 ⋅ xk2 ) − yk Die Minimierung der Fehlerquadrate führt, analog zu den Gleichungen (2.26) und (2.27), zu drei Bestimmungsgleichungen, die nach den unbekannten Parametern aufzulösen sind.
a0 ⋅ ¦ xk2 + a1 ⋅ ¦ xk3 + a2 ⋅ ¦ xk4 = ¦ yk ⋅ xk2
(2.36)
a0 ⋅ ¦ xk + a1 ⋅ ¦ xk2 + a2 ⋅ ¦ xk3 = ¦ yk ⋅ xk
(2.37)
a0 ⋅ N + a1 ⋅ ¦ xk + a 2 ⋅ ¦ xk2 = ¦ y k
(2.38)
Die letzte Gleichung läßt sich sehr einfach nach a0 umformen und man erhält:
a0 =
¦y
k
− a1 ⋅ ¦ xk − a2 ⋅ ¦ xk2 N
(2.39)
In die beiden oberen Gleichungen eingesetzt können wir nun Gln. (2.36) nach a1 auflösen.
§ ¦ yk ⋅ xk2 ¦ yk · § x4 x2 · ¸ − a2 ⋅ ¨ ¦ k − ¦ k ¸ ¨ − ¨ ¦x ¨ ¦ x2 N ¸¹ N ¸¹ k k © © a1 = ¦ xk3 − ¦ xk ¦ xk2 N
(2.40)
142 2 Statistische Signalverarbeitung
Mit diesen beiden Gleichungen, eingesetzt in Gln. (2.37), können wir schließlich a2 bestimmen.
§ ¦ yk ⋅ xk ¦ yk · § ¦ xk3 ¦ xk · ¸− ¸⋅¨ ¨ − − ¸ ¸ ¨ ¦ x2 ¨ ¦ xk N N k ¹ ¹ © © § ¦ yk ⋅ xk2 ¦ yk · § ¦ xk2 ¦ xk · ¸ ¸⋅¨ ¨ − − ¸ ¸ ¨¦x ¨ ¦ x2 N N k k ¹ ¹ © a2 = © § ¦ xk3 ¦ xk2 · § ¦ xk3 ¦ xk · ¸− ¸⋅¨ ¨ − − ¸ ¸ ¨ ¦ x2 ¨¦x N N k k ¹ ¹ © © § ¦ xk4 ¦ xk2 · § ¦ xk2 ¦ xk · ¸ ¸⋅¨ ¨ − − ¸ ¸ ¨¦x ¨ ¦ x2 N N k k ¹ ¹ © ©
(2.41)
Die Implementierung folgt exakt dem gleichen Schema, wie zuvor bei der linearen Regression. class DatenModell { ... public void ParabelRegression() { double sumx = 0; double sumxx = 0; double sumxxx = 0; double sumxxxx = 0; double sumy = 0; double sumyx = 0; double sumyxx = 0; double n = (double)Abtastwerte; for (int { sumx sumxx sumxxx sumxxxx sumy sumyx sumyxx }
k=0; k
k; k*k; k*k*k; k*k*k*k; yi[k]; yi[k]*k; yi[k]*k*k;
2.9 Die Regressionsanalyse 143
a2 = ((sumyx/sumx-sumy/n)*(sumxxx/sumxx-sumx/n) (sumyxx/sumxx-sumy/n)*(sumxx/sumx-sumx/n) ) / ((sumxxx/sumx-sumxx/n)*(sumxxx/sumxx-sumx/n) (sumxxxx/sumxx-sumxx/n)*(sumxx/sumx-sumx/n) ); a1 = ((sumyxx/sumxx - sumy/n) – a2*(sumxxxx/sumxx - sumxx/n)) / (sumxxx/sumxx-sumx/n); a0 = (sumy – a1*sumx – a2*sumxx) / n; } ... }
Für Polynome höherer Ordnung ist dieses Vorgehen jedoch nicht mehr akzeptabel. Damit ist weniger die Art der Implementierung gemeint, sondern vielmehr die zuvor notwendige Berechnung der Regressionskoeffizienten entsprechend den Gleichungen (2.39), (2.40) und (2.41). Vergleicht man diese (für ein Polynom zweiter Ordnung) mit denen der linearen Regression (Polynom erster Ordnung), dann erkennt man, daß die entstehenden Terme immer unhandlicher werden. Schaut man sich für beide Fälle auch noch einmal die Bestimmungsgleichungen (2.29) und (2.32), sowie (2.36), (2.37) und (2.38) an, stellt man fest, daß sich diese nach einem sehr einfachen Schema aufstellen lassen. Besonders leicht ist das zu erkennen, wenn wir für deren Darstellung die Matrixform wählen. Für ein Modell dritter Ordnung (y(x) = a0 + a1x + a2x2 + a3x3) erhalten wir:
§ N ¨ ¨ ¦ xk ¨ 2 ¨ ¦ xk ¨ x3 ©¦ k
¦x ¦x ¦x ¦x
k 2 k 3 k 4 k
¦x ¦x ¦x ¦x
2 k 3 k 4 k 5 k
¦x ¦x ¦x ¦x
3 k 4 k 5 k 6 k
· § a0 · § ¦ yk · ¸ ¨ ¸ ¨ ¸ ¸ ¨ a1 ¸ ¨ ¦ yk xk ¸ ¸ ⋅ ¨ a ¸ = ¨ y x2 ¸ ¸ ¨ 2 ¸ ¨¦ k k ¸ ¸ ¨ a ¸ ¨ ¦ y x3 ¸ k k ¹ ¹ © 3¹ ©
(2.42)
Das hier aufgestellte Gleichungssystem ist zwar nichtlinear bezüglich der unabhängigen Variablen x, aber linear in bezug auf unsere gesuchten Regressionskoeffizienten. Zur Lösung können wir daher das Eliminationsverfahren von Gauß anwenden (siehe letztes Kapitel). Üblicherweise wird ein lineares System in der folgenden Form dargestellt:
A⋅ x = b
(2.43)
144 2 Statistische Signalverarbeitung
In unserem Fall bilden die Summen der Abtastwerte (bzw. die Summen ihrer Potenzen) die Koeffizientenmatrix A und die unbekannten Regressionskoeffizienten den Lösungsvektor x. Die gemischten Terme der rechten Seite sind die Absolutglieder b des linearen Gleichungssystems. class DatenModell { ... public void Polynom3Regression() { double sumx = 0; double sumxx = 0; double sumxxx = 0; double sumxxxx = 0; double sumxxxxx = 0; double sumxxxxxx = 0; double sumy = 0; double sumyx = 0; double sumyxx = 0; double sumyxxx = 0; double n = (double)Abtastwerte; // Objekt für Lösung des Gleichungssystems LGleichung linear = new LGleichung(4); // Berechnung for (int k=0; { sumx += sumxx += sumxxx += sumxxxx += sumxxxxx += sumxxxxxx += sumy += sumyx += sumyxx += sumyxxx += }
der Summen k
// Zuweisung derKoeffizientenmatrix linear.A[0,0] = n; linear.A[0,1] = sumx; linear.A[0,2] = sumxx; linear.A[0,3] = sumxxx;
2.9 Die Regressionsanalyse 145
linear.A[1,0] linear.A[1,1] linear.A[1,2] linear.A[1,3]
= = = =
sumx; sumxx; sumxxx; sumxxxx;
linear.A[2,0] linear.A[2,1] linear.A[2,2] linear.A[2,3]
= = = =
sumxx; sumxxx; sumxxxx; sumxxxxx;
linear.A[3,0] linear.A[3,1] linear.A[3,2] linear.A[3,3]
= = = =
sumxxx; sumxxxx; sumxxxxx; sumxxxxxx;
// Zuweisung der Absolutglieder linear.b[0] = sumy; linear.b[1] = sumyx; linear.b[2] = sumyxx; linear.b[3] = sumyxxx; linear.GaussElimination(); // a0 a1 a2 a3
Regressionskoeffizienten = Lösungsvektor = linear.x[0]; = linear.x[1]; = linear.x[2]; = linear.x[3];
} ... }
Natürlich wollen wir auch dieses Programm sofort testen. Allerdings sollte man bei der Erzeugung synthetischer Testdaten bedenken, daß die hohen Potenzen den Funktionsverlauf für Werte größer Null sehr schnell dominieren, bei Werten kleiner Null dagegen kaum ins Gewicht fallen. class DatenModell { ... public void ErzeugeTestsignal_2() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k
146 2 Statistische Signalverarbeitung { // idealer Signalverlauf y[k] = -0.4*k*k*k + 7*k*k - 20*k + 82.0; // "gemessener" Signalverlauf yi[k] = y[k] + Rauschen.Normal(0, 4); } } ... }
Grundsätzlich ist das hier beschriebene Vorgehen durchaus auch für Regressionspolynome höherer Ordnung anwendbar, wegen der mit der Ordnung zunehmenden Schwingungsneigung von Polynomen macht man hiervon jedoch nur sehr vorsichtig Gebrauch. 200 175 150
f(x)
125 100 75 50 25 0 0
1
2
3
4
5
6
7
8
9
10 11
12 13
14 15
x
Abb. 2.11. Datenpunkte mit polynomaler Ausgleichsfunktion dritter Ordnung
2.9.3 Regression einer Exponentialfunktion
Viele physikalische Prozesse folgen einer exponentiellen Abhängigkeit. Ein Beispiel hierfür ist der Kollektorstrom IC eines bipolaren npnTransistors bei positiver Basis-Emitter-Spannung UBE: U BE
IC = I0 ⋅ e UT Wie schon zuvor, lassen sich Zusammenhänge dieser Art durch einen allgemeinen Ansatz modellieren.
y ( x) = a 0 ⋅ e a1 ⋅ x
(2.44)
2.9 Die Regressionsanalyse 147
Anders als vorher, wollen wir die Regressionsparameter a0 und a1 diesmal jedoch nicht durch die analytische Lösung einer Extremalwertaufgabe bestimmen, sondern linearisieren unser Modell durch eine logarithmische Transformation. Unter der Voraussetzung yk > 0 für alle gemessenen Werte läßt sich Gln. (2.44) in geeigneter Weise umformen.
ln( y ( x)) = ln(a 0 ⋅ e a1 ⋅ xk ) ln( y ( x)) = ln(a 0 ) + ln(e a1 ⋅ xk )
ln( y ( x)) = ln(a 0 ) + a1 ⋅ x k yT ( x) = a 0T + a1 ⋅ x k
(2.45)
Es gelingt also, unseren ursprünglich nichtlinearen Modellansatz durch die Transformation yT(x) = ln(y(x)) und a0T = ln(a0) in eine lineare Gleichung zu überführen. Was liegt da näher, als zur Lösung die bereits implementierte lineare Regression zu verwenden? Natürlich darf man zum Schluß die Rücktransformation nicht vergessen.
y ( x ) = e yT ( x )
(2.46)
a 0 = e a0 T
(2.47)
class DatenModell { ... public void ExponentielleRegression() { // Transformation von {x,y} nach {x,ln(y)} for (int k=0; k
148 2 Statistische Signalverarbeitung a0 = Math.Exp(a0); } ... }
Die Nutzung bewährter Programmkomponenten reduziert nicht nur den Programmieraufwand, sondern trägt auch erheblich zur Vermeidung von Fehlern bei. class DatenModell { ... public void ErzeugeTestsignal_3() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k
f(x)
200 150 100 50 0 0
1
2
3
4
5
6
7
8
9
10
11
12 13 14 15
x
Abb. 2.12. Datenpunkte mit exponentieller Ausgleichsfunktion (a1 > 0)
2.9 Die Regressionsanalyse 149 14 12
f(x)
10 8 6 4 2 0 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
x
Abb. 2.13. Datenpunkte mit exponentieller Ausgleichsfunktion (a1 < 0)
2.9.4 Regression einer Potenzfunktion
Eine weitere wichtige Funktionsklasse in der nichtlinearen Ausgleichsrechnung sind Potenzfunktionen mit dem allgemeinen Ansatz:
y ( x) = a 0 ⋅ x a1
(2.48)
Unter der Voraussetzung yk > 0 und xk > 0 für alle gemessenen Werte, läßt sich auch dieses Datenmodell durch eine logarithmische Transformation linearisieren.
ln( y ( x)) = ln(a 0 ⋅ x ka1 ) ln( y ( x)) = ln(a 0 ) + ln( x ka1 )
ln( y ( x)) = ln(a0 ) + a1 ⋅ ln( x k ) yT ( x) = a 0T + a1 ⋅ x kT
(2.49)
Wie schon bei der exponentiellen Regression, gelingt es auch hier, den ursprünglichen Modellansatz durch die Transformationen yT(x) = ln(y(x)), a0T = ln(a0) und xT = ln(x) in eine lineare Gleichung zu überführen. Und erneut werden unsere Bemühungen durch die nun mögliche Verwendung der linearen Regression belohnt. Auch hier gilt abschließend: Rücktransformation nicht vergessen!
x = e xT
(2.50)
y ( x) = e yT ( x )
(2.51)
a 0 = e a0 T
(2.52)
150 2 Statistische Signalverarbeitung class DatenModell { ... public void PotenzRegression() { // Transformation von {x,y} nach {ln(x),ln(y)} for (int k=0; k
Wie zuvor beim exponentiellen Ansatz, kann auch die Potenz positiv oder negativ sein. Beide Fälle lassen sich aber auch hier gleichermaßen problemlos linearisieren. class DatenModell { ... public void ErzeugeTestsignal_4() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k
2.10 Rangordnungsfilter 151
y[k] = 3*Math.Pow((double)k, 2.0); // "gemessener" Signalverlauf yi[k] = y[k] + Rauschen.Normal(0, 2); } } ... } 800 700 600
f(x)
500 400 300 200 100 0 0
1
2
3
4
5
6
7
8
9
10 11 12 13
14 15
x
Abb. 2.14. Datenpunkte mit potenzförmiger Ausgleichsfunktion (a1 > 1) 14 12
f(x)
10 8 6 4 2 0 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
x
Abb. 2.15. Datenpunkte mit potenzförmiger Ausgleichsfunktion (a1 < 1)
2.10 Rangordnungsfilter In der digitalen Signalverarbeitung setzt man lineare Filter ein, um bestimmte Frequenzanteile eines Signals auszublenden oder zu verstärken. Dabei sind die Frequenzeigenschaften des Filters durch die Koeffizienten eindeutig festgelegt, deren Faltung mit den Abtastwerten des Signals schließlich die Filterung selbst darstellt. Hat man es dagegen mit Rangordnungsfiltern zu tun, betritt man ein Gebiet, das weit weniger wohlgeordnet ist. Für Rangordnungsfilter existiert weder ein Faltungsoperator,
152 2 Statistische Signalverarbeitung
noch eine Frequenztransformation. Sie gehören zur Gruppe der nichtlinearen Filter und definieren sich ausschließlich über ihre statistischen Eigenschaften. Genau wie ihre linearen Verwandten, berechnen sie aus einer Anzahl von Abtastwerten xk mit Hilfe einer Verknüpfungsfunktion f(x) einen Ausgangswert y = f(xk). Allerdings ergibt sich dieser Ausgangswert aus der Rangordnung der Abtastwerte. Hierfür werden die Werte innerhalb des Filterfensters zunächst sortiert und anschließend, abhängig vom Typ des Rangordnungsfilters, das Maximum, das Minimum oder der Median ausgegeben. Letzterer ist wegen seiner guten Störreduktion von besonderem Interesse. Bei der Erfassung von Daten, egal ob aus einer Messung oder aus einer statistischen Erhebung, läßt sich Rauschen nie ganz vermeiden. Es ist die Aufgabe einer guten Rauschunterdrückung, möglichst alle Störungen zu beseitigen, ohne die signifikanten Eigenschaften der ursprünglichen Nutzdaten zu verändern. Eine Aufgabe, die alles andere als einfach ist. Schuld daran ist die Tatsache, daß Störungen sehr vielfältiger Natur sein können. Neben dem schon bekannten normalverteilten Rauschen treten häufig auch einzelne Ausreißer, auch Spikes genannt, in den Daten auf. Um solche zeitlich stark lokalisierten Störungen zu beseitigen, sind Medianfilter eine gute Wahl. Als statistischen Lageparameter einer Stichprobe haben wir den Median bereits im Abschn. 2.5.2 kennengelernt. Ein Medianfilter ist nun nichts weiter, als die Berechnung des Medians für ein Teilintervall, welches schrittweise über die Stichprobe gleitet. Die Filterlänge ist hierbei üblicherweise ungeradzahlig und liegt symmetrisch zum betrachteten Abtastzeitpunkt. Damit ist klar, daß Medianfilter bevorzugt offline eingesetzt werden, also auf bereits vollständig vorliegende Datensätze. Diesem Schema folgt auch die nachfolgende Implementierung. class Median { const double PI = 3.141592653589793; const int Abtastwerte = 128; // Stichprobenumfang // Signalverlauf public double[] x = new double[Abtastwerte]; // aktuelle Filterlänge (immer ungerade: 3,5,7,...) public int filterlaenge; // Konstruktor public Median() { filterlaenge = 3;
2.10 Rangordnungsfilter 153
} // Berechne den Median des Filterfensters // zum Zeitpunkt k der Stichprobe public double BerechneMedian(int k) { double[] sort = new double[filterlaenge]; double median = 0; int von = 0; int bis = 0; von = k-(filterlaenge-1)/2; bis = k+(filterlaenge-1)/2; // Arbeitskopie der Stichprobe anlegen for (int i=von; i sort() beachten! QuickSort(von-von, bis-von, sort); median = sort[(bis-von)/2]; return median; } ... }
Eine wesentliche Eigenschaft des Medianfilters ist die Kantenerhaltung bei Signalsprüngen. Für einen ersten Test generieren wir daher einen durch Spikes gestörten Signalsprung und vergleichen anschließend das Ergebnis des Medianfilters mit dem eines Mittelwertfilters gleicher Länge. class Median { ... public void ErzeugeTestsignal_1() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k
154 2 Statistische Signalverarbeitung { // Signalsprung mit Spikes if (k < Abtastwerte/2) { x[k] = 5; } else { x[k] = 10; } if (k % 12 == 0 && k > 0) { x[k] += 3*Rauschen.Normal(0, 1); } } } ... } 14 12
x(k)
10 8 6 4 2 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
Abb. 2.16. Signalsprung mit Spikes als Testsignal 14 12
x(k)
10 8 6 4 2 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
Abb. 2.17. Testsignal nach Medianfilterung (Filterlänge = 3)
2.10 Rangordnungsfilter 155
Wie auch schon bei den linearen Filtern, besteht die Ausgangsfolge aus N-(Filterlänge−1) Werten. Interessant ist die Wirkung der Medianfilterung auf die Spikes, deren Beseitigung in diesem Beispiel ideal gelingt. Warum das so ist, wird deutlich, wenn man die einzelnen Filtersequenzen näher betrachtet (xSpike = 11). {..., 5, 5, 11, ...} ĺ {5, 5, 11} ĺ 5 {..., 5, 11, 5, ...} ĺ {5, 5, 11} ĺ 5 {..., 11, 5, 5, ...} ĺ {5, 5, 11} ĺ 5 Ein Mittelwertfilter ist für diese Aufgabe offensichtlich ungeeignet, wie Abb. 2.18 zeigt. Ein Blick auf die Filtersequenzen macht auch klar weshalb. {..., 5, 5, 11, ...} ĺ (5 + 5 + 11) / 3 = 7 {..., 5, 11, 5, ...} ĺ (5 + 11 + 5) / 3 = 7 {..., 11, 5, 5, ...} ĺ (11 + 5 + 5) / 3 = 7 Das Mittelwertfilter ist nicht nur außerstande den konstanten Signalanteil zu rekonstruieren, es verschleift auch den ursprünglich idealen Signalsprung zu einer Rampe, deren Weite von der Filterlänge abhängt. Eine an dieser Stelle unerwünschte Eigenschaft, die alle digitalen Filter mit Tiefpaßcharakter zeigen. 14 12
x(k)
10 8 6 4 2 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
Abb. 2.18. Testsignal nach Mittelwertfilterung (Filterlänge = 3)
Signalsprünge bereiten dem Medianfilter offensichtlich keine Probleme. Leider gelingt die Rekonstruktion nicht bei allen Signalformen so ideal, wie hier. In der Meßtechnik treten sehr häufig periodische Signale auf, weshalb wir als zweites Testsignal einen Sinus mit Spikes betrachten.
156 2 Statistische Signalverarbeitung class Median { ... public void ErzeugeTestsignal_2() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k 0) { x[k] += 3*Rauschen.Normal(0, 1); } } } ... } 12 8
x(k)
4 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-4 -8 -12
k
Abb. 2.19. Sinus mit Spikes als Testsignal 12 8
x(k)
4 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-4 -8 -12
k
Abb. 2.20. Testsignal nach Medianfilterung (Filterlänge = 3)
2.10 Rangordnungsfilter 157
Auch in diesem Beispiel liefert der Medianfilter zwar das eindeutig bessere Ergebnis, es verbleibt aber eine gewisse Rauhigkeit im Signalverlauf, die sich leicht nachvollziehen läßt, wenn man sich die Filtersequenzen einmal anschaut. Zur Vereinfachung wird der sinusförmige Verlauf durch eine ansteigende Gerade {..., 3, 4, 5, 6, 7, ...} mit einem Spike (xSpike = 11) anstelle des Wertes 5 angenähert. {..., 3, 4, 11, ...} ĺ {3, 4, 11} ĺ 4 {..., 4, 11, 6, ...} ĺ {4, 6, 11} ĺ 6 {..., 11, 6, 7, ...} ĺ {6, 7, 11} ĺ 7 Es zeigt sich, daß der Medianfilter den jeweils größten ungestörten Wert ausgibt, was schließlich zu dem etwas rauhen Verlauf führt. Der Vergleich mit Abb. 2.21 macht klar, daß die Mittelwertfilterung dagegen nur unbrauchbare Ergebnisse liefert. Erheblich genauer und aussagekräftiger als ein rein visueller Vergleich der Kurvenverläufe wäre natürlich eine Frequenzanalyse mittels DFT bzw. FFT. Bestimmt man das Verhältnis der jeweils enthaltenen Harmonischen in Bezug auf die Grundschwingung, ergibt sich ein geeignetes Gütemaß. 12 8
x(k)
4 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
-4 -8 -12
k
Abb. 2.21. Testsignal nach Mittelwertfilterung (Filterlänge = 3)
Um eine lokale Störung von n Abtastwerten Länge beseitigen zu können, muß das Medianfilter selbst 2n + 1 Werte lang sein. Nachfolgend das Beispiel einer Störung von vier Abtastwerten. Entsprechend der obigen Beziehung ist für die Filterung dann eine Fensterlänge von neun Abtastwerten erforderlich. class Median { ... public void ErzeugeTestsignal_3()
158 2 Statistische Signalverarbeitung { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k= (Abtastwerte/2) && k < (Abtastwerte/2) + 4 ) { x[k] = 5 + 3*Rauschen.Normal(0, 1); } else { x[k] = 5; } } } ... } 14 12
x(k)
10 8 6 4 2 0 48
56
64
72
80
k
Abb. 2.22. Lokale Störung über vier Abtastwerte als Testsignal 14 12
x(k)
10 8 6 4 2 0 48
56
64
72
80
k
Abb. 2.23. Testsignal nach Medianfilterung (Filterlänge = 9)
2.10 Rangordnungsfilter 159 14 12
x(k)
10 8 6 4 2 0 48
56
64
72
80
k
Abb. 2.24. Testsignal nach Mittelwertfilterung (Filterlänge = 9)
In den betrachteten Beispielen hat sich das Medianfilter bei der Signalaufbereitung durchaus bewährt, da es den ungestörten Signalverlauf beinahe ideal rekonstruiert. Trotzdem stellen Medianfilter kein Allheilmittel im Kampf gegen Signalstörungen allgemeiner Art dar, da sie normalverteiltes bzw. weißes Rauschen nur sehr schlecht unterdrücken (schlechter als z. B. ein Mittelwertfilter). Hier zeigt sich ein Grundprinzip: Die Natur verschenkt nichts. Vorteile in einem Bereich müssen immer durch Nachteile in anderen Bereichen erkauft werden, auch in der statistischen Signalverarbeitung. class Median { ... public void ErzeugeTestsignal_4() { Zufall Rauschen = new Zufall(0.71036, 0.23906); for (int k=0; k
160 2 Statistische Signalverarbeitung 14 12
x(k)
10 8 6 4 2 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
Abb. 2.25. Signalsprung mit N(0,1)-Rauschen als Testsignal 14 12
x(k)
10 8 6 4 2 0 1
9
17 25 33 41 49 57 65 73 81 89 97 105 113 121
k
Abb. 2.26. Testsignal nach Medianfilterung (Filterlänge = 9) 14 12
x(k)
10 8 6 4 2 0 0
8
16 24 32 40 48 56 64 72 80 88 96 104 112 120
k
Abb. 2.27. Testsignal nach Mittelwertfilterung (Filterlänge = 9)
3 Computational Intelligence
3.1 Einführung Was ist Intelligenz? Eine Antwort auf diese Frage zu finden ist gar nicht so leicht. Irgendwie hat es mit Verständnis zu tun, mit der Fähigkeit Probleme zu erkennen und zu lösen. Eine schnelle Auffassungsgabe, räumliches Denken und logisches Schlußfolgern gehören wohl auch dazu. Ganz offensichtlich umreißt der Begriff verschiedene geistige Leistungen. Ohne Zweifel ist der Mensch ein intelligentes Wesen, dem es gelingt, sich in seiner komplexen Umwelt erfolgreich zu behaupten. Hierfür sind jeden Tag, auf der Basis persönlicher Erfahrungen, eine Vielzahl von Entscheidungen zu treffen. Das Ziel der Forschung auf dem Gebiet der Künstlichen Intelligenz ist es, menschliche Handlungsweisen auf Maschinen zu übertragen, also Methoden zu entwickeln, um Denk- und Entscheidungsprozesse berechenbar (computational) zu machen. Kann eine Maschine überhaupt intelligent handeln oder sogar denken? Um das herauszufinden, bräuchte man ein Kriterium, das es möglich macht maschinelle Intelligenz zu messen. Der britische Mathematiker Alan Turing (1912–1953) hat ein Testverfahren entwickelt, das ihm hierfür geeignet erschien. Nach seiner Definition gilt eine Maschine als intelligent, wenn sie den sogenannten Turing-Test besteht. Zu diesem Zweck sitzt eine Person vor einem Terminal und kommuniziert mit einem Partner. Ziel ist es, durch Dialog herauszufinden, ob dieser Partner ein Mensch oder eine Maschine ist. Ist die Person nach einer gewissen Zeit überzeugt mit einem Menschen zu kommunizieren, gilt der Test als bestanden, das Testobjekt somit als intelligent. Computerprogrammen wird diese Fähigkeit wohl am ehesten zugetraut. Sie sind schon heute in der Lage unterschiedliche Aspekte der menschlichen Intelligenz zu simulieren. Ein bekanntes Beispiel hierfür ist das Dialogsystem ELIZA, welches von Joseph Weizenbaum 1966 am MIT (Massachusetts Institute of Technology) entwickelt wurde. Es simuliert einen Psychiater und generiert immer neue Fragen aus den Schlüsselwörtern der zuletzt gegebenen Antwort. Obwohl es nie als ernsthafte Anwendung geplant war, glaubten viele Zeitgenossen wirklich an eine Revolution in der Psychoanalyse. Genau genommen ist ELIZA aber ein Programm zur Sprachanalyse. Weizenbaum wollte nur zeigen, wie es
162 3 Computational Intelligence
schon mit vergleichsweise einfachen Regeln möglich ist, den Eindruck scheinbarer Intelligenz zu vermitteln. Tatsächlich kann man z. B. auf „Ich bin heute ...“ immer mit „Warum bist du heute ...?“ antworten, völlig unabhängig von „...“. Programme dieser Art sind echter Intelligenz so nahe, wie eine Kraftwerkssimulation auf dem PC in der Lage ist Strom zu erzeugen. Trotzdem geht von solchen Chatbots eine gewisse Faszination aus, der man sich nur schwer entziehen kann. Inzwischen setzen viele Firmen auf ihren Internetseiten weiterentwickelte Chatbots ein, die als erste Anlaufstelle Kundenanfragen beantworten, sehr oft in Verbindung mit einer künstlichen Figur (Avatar) als virtuellen Gesprächspartner. Sitz der menschlichen Intelligenz ist bekanntlich das Gehirn. Es ist der Ort, an dem unsere Ideen entstehen, sich unsere Gefühle entwickeln und unsere Gedanken kreisen. Allerdings sind Vorgänge dieser Art und die zugrundeliegenden Mechanismen noch nicht genügend erforscht und verstanden, um sie in Algorithmen nachbilden zu können. Eines steht jedoch mit Sicherheit fest, die Abläufe in unserem Gehirn, und seien sie auch noch so kompliziert, unterliegen den Gesetzen der Physik. Somit ist ihre Entschlüsselung doch zumindest grundsätzlich möglich. Eine Garantie ist das jedoch nicht, denn bis zum heutigen Tag ist völlig unklar, ob wir mit unseren geistigen Fähigkeiten hierzu überhaupt in der Lage sind. Verfügt unser Gehirn über genügend Kapazität, um sich selbst zu begreifen? Die Zukunft wird es zeigen. Bis dahin müssen wir uns damit begnügen, die bisher verstandenen Mechanismen, so gut es eben geht, in nutzbringende Anwendungen umzusetzen. In unseren Gedanken entstehen vor unserem geistigen Auge Einzelbilder oder Szenen von Personen oder Gegenständen. Dabei handelt es sich nicht zwingend um Erinnerungen, also die Wiedergabe von realen Erlebnissen, sondern wir sind in der Lage solche Bilder nach Belieben entstehen zu lassen. Handelt es sich aber nicht um eine im Gedächtnis gespeicherte Aufzeichnung, dann entstehen diese Bilder in Echtzeit durch eine Abfolge von Nervenimpulsen in unserem Gehirn. Nervenimpulse bzw. Bild stellen somit unterschiedliche Formen der selben Information dar. Entsprechend unterscheidet man zwei Arten der Wissensrepräsentation. Einerseits die symbolische Repräsentation auf der Basis konkreter Objekte und Regeln, die über umgangssprachliche Bezeichner „greifbar“ sind (z. B. in der Fuzzy-Logik), andererseits die subsymbolische Repräsentation, die sich zur Darstellung und Wissensverarbeitung auf schwer verständliche Elementarstrukturen stützt (z. B. in neuronalen Netzen). Wir wollen beide Ansätze näher untersuchen, die auf unterschiedlichen Abstraktionsebenen arbeiten, etwa vergleichbar mit dem objektorientierten Klassenmodell eines Programms und seinem Maschinencode.
3.2 Neuronale Netze 163
3.2 Neuronale Netze Für viele Probleme hat die Natur vorbildliche Lösungen gefunden, die in vielerlei Hinsicht den von Menschen entwickelten Konzepten überlegen sind. Das ist eigentlich auch gar nicht verwunderlich, denn schließlich verfügt die Natur über einen Technologievorsprung aus einigen Jahrmillionen der Evolution, den sich der Mensch in zunehmendem Maße zunutze macht. In ganz besonderer Weise trifft das auf einige Gebiete der Informationsverarbeitung zu, z. B. auf die Mustererkennung. Der Umstand, daß hier biologische Gehirne als informationsverarbeitende Systeme konventionellen Computern weit voraus sind, hat zur Entwicklung der Neuroinformatik geführt. Sie vereint Spezialisten der unterschiedlichsten Disziplinen, Biologen, Informatiker, Psychologen, Physiker, Mathematiker und Ingenieure. Ihr gemeinsames Ziel ist es, die Arbeitsweise biologischer Gehirne zu erforschen und zu modellieren, um die Stärken menschlicher Informationsverarbeitung in die Entwicklung neuer und leistungsfähigerer Algorithmen einfließen zu lassen. Die Grundlagen für das Arbeiten mit künstlichen neuronalen Netzen wurden bereits in den 40er und 50er Jahren des vergangenen Jahrhunderts von Forschern wie Norbert Wiener, Warren McCulloch, Walter Pitts und Frank Rosenblatt geschaffen. Aber erst in den 80er Jahren, angeregt durch die Entwicklungen von Teuvo Kohonen, John Hopfield und David Rumelhart, wurden ihre Ideen neu aufgegriffen. Auch wenn die Entwicklung heute noch lange nicht abgeschlossen ist, sondern immer noch erheblicher Forschungsbedarf besteht, haben sich neuronale Netze in vielen technischen Anwendungen fest etabliert. 3.2.1 Biologische Grundlagen
Mit künstlichen neuronalen Netzen wird versucht, biologische neuronale Netze als informationsverarbeitende Systeme nachzuahmen. Vorbild hierfür ist die Leistungsfähigkeit des menschlichen Gehirns, dem wohl komplexesten Gebilde, daß die Natur jemals hervorgebracht hat. Es besteht aus etwa 100 Milliarden Nervenzellen, Neuronen genannt, von denen jede einzelne bis zu 10 000 andere Nervenzellen direkt kontaktiert. Auf diese Art entsteht ein Netzwerk unglaublicher Komplexität mit insgesamt mehreren hundert Billionen Verbindungen. Diese astronomische Zahl macht sehr schnell klar, warum sich die Hirnforschung auf die Untersuchung einzelner Regionen konzentrieren muß. Auch für uns ist zunächst die Funktion der Grundbausteine von Interesse. Die kleinste informationsverarbeitende Einheit ist gerade die einzelne Nervenzelle. Bei näherer Betrachtung einer
164 3 Computational Intelligence
solchen Zelle erkennt man den Zellkörper mit seinem Kern im Inneren und die vom Zellkörper ausgehenden Fortsätze, Dendriten ([griech.]: Verästelung) genannt. Diese Dendriten nehmen über chemische Kontaktstellen, den Synapsen ([griech.]: Verbindung), die Ausgangssignale der umliegenden Nervenzellen auf, summieren sie und führen sie dem Zellkörper zu. Überschreitet dieser Reiz einen bestimmten Schwellwert, dann erzeugt der Zellkörper seinerseits ein Ausgabesignal, welches vom sogenannten Axon ([griech.]: Achse) zu den Zielneuronen weitergeleitet wird.
Dendriten
Zellkörper
Axon
Abb. 3.1. Darstellung einer biologischen Nervenzelle
Synapsen, Dendriten, Zellkörper und Axon bilden gemeinsam die Grundstruktur einer Nervenzelle. Man kann ihnen grob die Aufgaben der Signalaufnahme, Signalverarbeitung und Signalausgabe zuordnen. Und obwohl die biologische Signalverarbeitung sehr viel langsamer ist als ihr elektronisches Pendant (typischerweise 10−3 s gegenüber 10−9 s), lösen biologische Gehirne viele Probleme erheblich besser als moderne Computer. Ein wesentlicher Grund hierfür ist die massiv parallele Vernetzung der Nervenzellen, das allein kann aber noch nicht die Lösung sein. Zusätzlich sind die Verbindungen zwischen ihnen adaptiv, d. h. sie sind in der Lage sich mit der Zeit zu verändern. Gerade auf solchen Anpassungsmechanismen beruht eine der bemerkenswertesten Eigenschaften unseres Gehirns, die Fähigkeit zu lernen.
3.2 Neuronale Netze 165
3.2.2 Künstliche Neuronen
Mit der Entwicklung künstlicher Neuronen versucht man die Struktur und das Verhalten des biologischen Vorbilds für technische Anwendungen nutzbar zu machen. Das einzelne Neuron kann dabei durchaus als signalverarbeitender Elementarprozessor angesehen werden, mit dem sich durch eine entsprechende Verschaltung auch komplexe hierarchische Strukturen bilden lassen. Bei der Verwendung künstlicher Neuronen beschränkt man sich darauf, mit einem stark vereinfachten Modell zu arbeiten. Abbildung 3.2 zeigt eine gängige Variante.
bias input 1 input 2
input j
w1 w2 net
f(net)
output
wj Abb. 3.2. Modell eines technischen Neurons
Die gewichteten Verbindungsleitungen nehmen die Ausgangssignale der anderen Neuronen auf. Man bezeichnet die Summe der Eingangssignale zusammen mit dem Bias als den Nettoinput des Neurons.
net = ¦ input j ⋅w j + bias
(3.1)
j
Der Bias hat die Aufgabe, den Schwellwert der nachfolgenden Aktivierungsfunktion festzulegen. Als Aktivierung verwendet man bevorzugt Funktionen mit ausgeprägtem Sättigungscharakter, wie z. B. die SigmoidFunktion oder den hyperbolische Tangens.
166 3 Computational Intelligence Tabelle 3.1. Beispiele von Transferfunktionen f(x) 1 0,5
Sigmoid-Funktion
f ( x) =
1 1 + e −x
0 -3
-1,5
0
1,5
3
x
-0,5
-1
f(x) 1 0,5
Hyperbolischer Tangens
f ( x) = tanh( x)
0 -3
-1,5
0
1,5
3
x
-0,5
-1
f(x) 1
Hard-Limiter
0,5
1 x ≥ 0 f ( x) = ® ¯0 x < 0
0 -3
-1,5
0
1,5
3
x
-0,5
-1
f(x) 1
Lineare Funktion mit Begrenzung
+ 1 ° f ( x) = ® x °− 1 ¯
x >1 sonst x < −1
0,5
0 -3
-1,5
0 -0,5
1,5
3
x
-1
Am Ausgang unseres Modellneurons erhalten wir somit die folgende Aktivierung:
output = f (net )
(3.2)
Die bisher gemachten Ausführungen beziehen sich aber lediglich auf ein einzelnes Neuron. Ein neuronales Netz entsteht nämlich erst durch die Verschaltung mehrerer solcher Modellneuronen zu einer größeren Einheit, wobei die Leistungsfähigkeit des Netzes wesentlich durch die Art der Verknüpfung bestimmt wird.
3.2 Neuronale Netze 167
3.2.3 Netzstrukturen
Biologische Informationsverarbeitung ist häufig identisch mit der Abbildung von Mustern aufeinander. Was zunächst sehr abstrakt klingt, ist aber in jedem Augenblick so allgegenwärtig, daß es von uns kaum noch bewußt wahrgenommen wird. So lösen verschiedene visuelle Eingangssignale auf unserer Netzhaut (input) ganz unterschiedliche Reaktionen (output) aus, z. B. das Anhalten vor einer roten Ampel. Mathematisch gesehen stellt eine solche Eingangs-/Ausgangsbeziehung von Signalen eine Abbildung dar. Neuronale Netze sind daher nichts weiter als Abbildungsmaschinen, mit denen sich verschiedene Abbildungsfunktionen durch gezieltes Training realisieren lassen.
input 1 input 2
output 1 F:R
n
R
m
output 2
input n
output m
Abb. 3.3. Neuronales Netz als Abbildungsmaschine
Üblicherweise sind neuronale Netze in Schichten angeordnet, wobei zwischen der Eingabeschicht und der Ausgabeschicht eine oder mehrere Verarbeitungsschichten liegen. Da diese inneren Schichten von außen nicht zugänglich sind, werden sie als verdeckte Schichten (hidden-layer) bezeichnet. Die Verbindung der einzelnen Neuronen erfolgt über Gewichtsfaktoren, die in ihrer Gesamtheit das antrainierte Wissen darstellen. Grundsätzlich gibt es rein vorwärts gerichtete Netze (feedforward-), bei
input 1
input 2
output 1
input 3
output 2
input 4 Abb. 3.4. MLP-Netz aus mehreren Neuronen
168 3 Computational Intelligence
denen der Signalfluß immer vom Eingang zum Ausgang hin verläuft, und rückgekoppelte Netzwerke (feedbackward-), bei denen das Ausgangssignal dem Eingang wieder zugeführt wird. Letztere können aber zu Instabilitäten neigen und werden hier nicht weiter behandelt. Grundlage der weiteren Betrachtungen ist das Multi-Layer-Perzeptron (MLP), welches als Generalist unter den neuronalen Netzen weit verbreitet ist. In der praktischen Anwendung stellt sich die Frage, wie ein neuronales Netz zu dimensionieren ist, um ein Problem nach Möglichkeit optimal zu lösen. Hierzu betrachten wir zunächst wieder nur ein einzelnes Neuron. Ausgehend von zwei Merkmalen am Netzeingang erhalten wir den folgenden Nettoinput:
net = w1 ⋅ input1 + w2 ⋅ input2 + bias
(3.3)
Soll das Neuron beide Merkmale durch Null bzw. Eins klassifizieren, dann muß das Argument der Aktivierungsfunktion an der Klassengrenze Null sein. Damit läßt sich der obige Ausdruck in eine Geradengleichung umformen.
input2 = −
bias w1 ⋅ input1 − w2 w2
(3.4)
Die so definierte Gerade trennt hier den 2-dimensionalen Merkmalraum. Verallgemeinert läßt sich sagen, daß jedes einzelne Neuron den n-dimensionalen Merkmalraum durch eine (n−1)-dimensionale Hyperebene linear separiert. Eine nachfolgende Neuronenlage bildet dann aus den einzelnen Geraden bzw. Hyperebenen ein konvexes Gebilde im Merkmalraum, entsprechend einer UND-Verknüpfung. Folgt noch eine weitere Neuronenlage, werden die bisher entstandenen Gebiete schließlich ODER-verknüpft, wobei beliebig geformte Teilgebiete entstehen, deren Komplexität sich durch die Anzahl der verwendeten Neuronen bestimmt. Dies läßt die Schlußfolgerung zu, daß mit drei Neuronenlagen jedes Problem klassifizierbar ist, die Eingangslage nicht mitgezählt. Leider hilft uns diese Erkenntnis nur sehr wenig, wenn es darum geht, die für ein konkretes Problem optimale Netzstruktur zu finden. Die Anzahl der Eingangs- und Ausgangsneuronen ist ja meist durch die zu verarbeitenden Eingangsmerkmale bzw. die benötigten Ausgangswerte vorgegeben. Hier hat man dann keinen Spielraum. Das Optimierungspotential liegt daher in den verdeckten Lagen. Ist erst einmal klar, ob eine oder mit zwei verdeckten Lagen erforderlich sind, dann weiß man immer noch nicht, wie viele Neuronen in der/den verdeckten Lage(n) eine Aufgabe optimal lösen. Man könnte nun auf die Idee kommen, alle Kombinationen einer Netztopologie vollständig zu trainieren und anschließend die Qualität der einzelnen
3.2 Neuronale Netze 169
keine Zwischenschicht Durch Hyperebene begrenzter Halbraum
1 Zwischenschicht Konvexe offene oder geschlossene Gebiete
2 Zwischenschichten Beliebige Gebiete, deren Komplexität durch die Anzahl der Neuronen limitiert ist
Abb. 3.5. Zusammenhang von Netzstruktur und Klassifizierungsmöglichkeiten
Netze aufgrund des verbleibenden Restfehlers zu bewerten. Jedoch macht der enorme Zeitaufwand für die gesamte Trainingsphase dieses Vorgehen praktisch unmöglich. Es besteht aber die Möglichkeit die Netze zunächst nur über eine geringe Anzahl von Lernzyklen zu trainieren, z. B. 20% der vorgesehenen Zyklenzahl, und dann aus der Tendenz des Lernfortschritts eine Auswahl für das weitere Training zu treffen. Tatsächlich erhält man so brauchbare Hinweise auf geeignete Kandidaten. Allerdings ist auch dieses Vorgehen nicht frei von Schwächen. Modifiziert man einige Parameter des Lernverfahrens, dann ergeben sich meistens auch andere Favoriten. Man steht hier unausweichlich vor dem Dilemma, die Lernparameter und die Netzstruktur möglichst gut aufeinander abstimmen zu müssen, bzw. beide Faktoren zu optimieren, jeweils in Abhängigkeit von der anderen Größe. Zugegeben, das klingt ein bißchen wie die Quadratur des Kreises. Umgehen läßt sich
170 3 Computational Intelligence
dieses Problem aber nur durch Erfahrung oder Ausdauer. Letztere benötigt viel Rechenleistung und Zeit, aber glücklicherweise läßt sich die Suche nach der besten Konfiguration relativ leicht automatisieren. Ohnehin gibt es meistens mehrere brauchbare Netzstrukturen. Hat man erst einmal eine solche gefunden, d. h. ein Netz mit einem ausreichend kleinen Restfehler, kann man die weitere Suche einstellen. 3.2.4 Der Backpropagation-Lernalgorithmus
Das Multi-Layer-Perzeptron wird mit einem Algorithmus trainiert, der zur Klasse der überwachten Lernverfahren gehört. Hierbei werden dem Netz Eingangsmuster vorgelegt, die dieses durchlaufen. Die resultierende Abweichung von der erwünschten Netzausgabe (Zielmuster) wird dann für die Korrektur der Netzgewichte verwendet, so daß künftige Abweichungen geringer ausfallen. Im Idealfall führt die iterative Anwendung dieses Prozesses zur Lösung des Lernproblems. Was zunächst so einfach klingt, wirft jedoch bei näherer Betrachtung eine Reihe von Fragen auf. Grundsätzlich stellt sich das Problem, nach wie vielen Iterationen man den Lernvorgang beenden kann. Die Antwort ist keineswegs trivial, sind doch zwei völlig entgegengesetzte Anforderungen zu beachten. Einerseits soll das neuronale Netz in der Trainingsphase die Eingangsmuster möglichst exakt auf die Zielmuster abbilden. Andererseits muß es auch in der Lage sein, eingebunden in einen realen Prozeß,
Lehrer
erwünschte Ausgabe
Eingangsmuster
neuronales Netz
Abb. 3.6. Überwachtes Lernen
tatsächliche Ausgabe
+ -
3.2 Neuronale Netze 171
unbekannte Eingangsmuster richtig zu verarbeiten, d. h. in geeigneter Weise zu interpolieren. Gerade diese Generalisierungsfähigkeit ist es schließlich, die neuronale Netze für technische Anwendungen so interessant macht. Läßt man nun das Netz zu lange lernen, wird zwar der verbleibende Fehler der Lerndatei immer kleiner, jedoch verliert das Netz ab einem bestimmten Punkt seine Verallgemeinerungsfähigkeit. Man bezeichnet diesen äußerst unerwünschten Effekt als Überanpassung (overlearning). Um nun den optimalen Zeitpunkt für das Ende der Lernphase zu erkennen, läßt man einfach eine sogenannte Validationsdatei mitlaufen. Hierbei handelt es sich um einen Datensatz, der ebenfalls aus einer Anzahl von Eingangsund Ausgangsmustern besteht, die jedoch nicht schon im Lerndatensatz enthalten sein dürfen. Während des Trainings wird dann auch laufend der Fehler dieser Validationsdatei bestimmt, er fließt jedoch nicht in die Korrektur der Netzgewichte ein. Overlearning setzt ein, wenn der Validationsfehler ansteigt, obwohl der Lernfehler noch weiter abnimmt. Marvin Minsky und Seymour Papert konnten 1969 anhand des XORProblems aufzeigen, daß einlagige Netze nur bedingt zur Klassifikation geeignet sind. Zwar war damit die Notwendigkeit mehrlagiger Netze für allgemeinere Probleme klar, es gab jedoch zu diesem Zeitpunkt noch keinen Algorithmus, mit dem es möglich war, auch die verdeckten Schichten eines neuronalen Netzes zu trainieren. Erst nachdem Rummelhart, Hinton und Williams 1986 ein schon im Jahre 1974 von Werbos beschriebenes Lernverfahren wiederentdeckten, konnte diese Einschränkung überwunden werden. Heute zählt der Backpropagation-Algorithmus zu den leistungsstärksten Lernverfahren und hat dem Multi-Layer-Perzeptron ein breites Spektrum von Anwendungen eröffnet.
F(w) Validationsfehler
Lernfehler
Zyklen Abb. 3.7. Erkennung der optimalen Lerndauer mittels Validation
172 3 Computational Intelligence
Das Backpropagation-Verfahren minimiert die aufgrund der Netzgewichte determinierte Fehlerfunktion durch Gradientenabstieg, d. h. es läuft entlang des stärksten Gefälles in Richtung Minimum. Hierfür ist es zwingend erforderlich, daß der Gradient tatsächlich für alle Punkte des Fehlerraumes existiert. Verwenden wir als Aktivierung die Sigmoidfunktion, ist das gewährleistet.
s( x) =
1 1 + e −x
(3.5)
Gleichung (3.5) ist für alle Werte von x differenzierbar. Das gilt dann auch für jede durch mehrlagige Netze gebildete Funktionskomposition, wodurch auch die Fehlerfunktion selbst diese Eigenschaft hat. Nach der Initialisierung der Netzgewichte mit Zufallswerten kann das Backpropagation-Verfahren starten. Es besteht aus fünf Schritten, die solange zu wiederholen sind, bis die Fehlerfunktion einen vom Anwender gewählten Grenzwert unterschritten hat (damit ist das Lernziel erreicht) oder eine maximale Anzahl von Iterationen durchlaufen wurden. 1. Berechnung der Netzausgabe aufgrund des angelegten Lernmusters 2. Ermittlung der jeweiligen Abweichung vom Zielmuster 3. Rückwärtsberechnung für die Korrektur der Ausgabeschicht 4. Rückwärtsberechnung für die Korrektur der verdeckten Schichten 5. Korrektur der Netzgewichte. Der lokale Fehler Em aufgrund des aktuell anliegenden Musters m ergibt sich durch Summation des quadratischen Fehlers über alle Neuronen k der Ausgabeschicht i.
Em =
1 ⋅ ¦ (t m,k − output i ,k ) 2 2 k
(3.6)
Hierbei ist tm,k das vorgegebene Zielmuster und outputi,k die tatsächliche Netzausgabe. Den globalen Fehler erhalten wir durch Summation der lokalen Fehler über alle Lernmuster.
E = ¦ Em
(3.7)
m
Mit Hilfe des globalen Fehlers erfolgt dann die Korrektur der Netzgewichte in Richtung des negativen Gradienten, d. h. es ist das Ziel des Lernverfahrens E zu minimieren. Hierzu berechnen wir den jeweiligen Abstieg über die partielle Ableitung.
Δwi , j ,k = −γ ⋅
∂E ∂wi , j ,k
(3.8)
3.2 Neuronale Netze 173
Der Proportionalitätsfaktor Ȗ ist die Lernrate des Verfahrens. Er dient als Schrittweitensteuerung und erlaubt es dem Anwender den Lernvorgang problemspezifisch anzupassen. Um die partielle Ableitung weiter auflösen zu können, wird die Kettenregel angewendet.
∂output i ,k ∂net i ,k ∂E ∂E = ⋅ ⋅ ∂wi , j ,k ∂output i ,k ∂net i ,k ∂wi , j ,k
∂E = (t m, k − output i , k ) ⋅ s (net i , k ) ⋅ (1 − s (net i ,k )) ⋅ output i −1, j ∂wi , j , k ∂E = −δ i ,k ⋅ output i −1, j ∂wi , j , k
(3.9)
(3.10)
(3.11)
Hierbei ist s(neti,k) = outputi,k die Aktivität des Neurons k der Schicht i und outputi−1,j das am Eingang j anliegende Signal, d. h. die Ausgangsaktivität eines vorgeschalteten Neurons. Für die Korrektur der Netzgewichte erhält man somit:
Δwi , j ,k = γ ⋅ δ i ,k ⋅ output i −1, j
(3.12)
Allerdings sind die bisherigen Gleichungen nur auf Neuronen der Ausgabeschicht anwendbar, da für die Neuronen der inneren Schichten kein Zielwert tm,k vorgegeben ist. Für diese muß daher der Lernfehler nach Gln. (3.6) durch einen äquivalenten Faktor ersetzt werden. Durch Anwendung der Kettenregel ist es möglich, den Lernfehler eines inneren Neurons rekursiv aus dem Produkt des Fehlersignals nachgeschalteter Neuronen und den entsprechenden Netzgewichten abzuleiten. Dabei gilt für die Neuronen der verdeckten Schichten:
δ i ,k = s ′(net i ,k ) ⋅ ¦ wi +1,k ,l ⋅ δ i +1,l
(3.13)
l
δ i ,k = output i ,k ⋅ (1 − output i , k ) ⋅ ¦ wi +1,k ,l ⋅ δ i +1,l
(3.14)
l
Mit der Bestimmung des Fehlers innerer Neuronen sind nun endlich alle notwendigen Terme zur Korrektur der Netzgewichte gegeben. alt Δwineu , j , k = γ ⋅ δ i , k ⋅ output i −1, j + μ ⋅ Δwi , j , k
(3.15)
Der Faktor μ, Momentum genannt, stellt einen Erinnerungswert dar und bewirkt, daß die jeweils letzte Gewichtsänderung ebenfalls noch in die neue Korrektur mit einfließt. Liegt das gesuchte Minimum unserer Fehlerfunktion beispielsweise in einem schmalen Tal, so kann es vorkommen,
174 3 Computational Intelligence
daß der Algorithmus über dieses Minimum hinwegläuft und im nächsten Lernzyklus eine Veränderung der Netzgewichte in die genau entgegengesetzte Richtung stattfindet. Tritt dieser Effekt nun mehrmals hintereinander auf, kommt es zu einer unerwünschten Oszillation um das Minimum. Ein entsprechend großes Momentum wirkt dieser Schwingung entgegen und beschleunigt somit den Suchvorgang. Um den Lernvorgang des Backpropagation-Algorithmus weiter zu verbessern, wird zusätzlich eine dynamische Anpassung der Lernrate vorgenommen. Hierzu ist diese nach jedem Lernzyklus in geeigneter Weise zu verkleinern. Dieses Vorgehen korrespondiert mit der Erwartung, daß die Abweichung vom Zielmuster zu Beginn des Trainings naturgemäß sehr groß ist und im weiteren Verlauf, mit zunehmender Annäherung an das globale Minimum der Fehlerfunktion, eine immer kleinere Gewichtskorrektur erforderlich ist.
γ z = α ⋅ γ z −1
(3.16)
Günstige Werte für Į liegen etwa im Bereich 0,999..0,9995, abhängig von der Zahl der Lernzyklen. Ein zu kleiner Wert kann den Lernfortschritt aber auch schnell abwürgen, so verringert sich die Lernrate bei Ȗ = 0,99 nach nur hundert Lernzyklen auf ein Drittel des ursprünglichen Wertes (0,99100 § 0,36). Mit Į = 1 findet dagegen keine Anpassung statt. Das hier beschriebene Vorgehen empfiehlt sich auch beim Momentum μ. Grundsätzlich kann die Korrektur der Netzgewichte nach jedem vorgelegten Muster erfolgen, man spricht dann von musterweisem Lernen, oder aber auch erst nach einem kompletten Durchlauf aller Lernmuster, dem epochenweisen Lernen. Beim Letztgenannten werden die berechneten Gewichtsänderungen aller Lernmuster zunächst aufsummiert und am Ende des jeweiligen Durchlaufs tatsächlich mit den Netzgewichten verrechnet. In der Literatur ist manchmal zu lesen dieses Vorgehen wäre weniger zeitaufwendig, der Algorithmus demzufolge schneller. Dies ist aber nur bedingt richtig. Bei realen Problemstellungen liegt der größere numerische Aufwand in jedem Fall in der zwingend musterweisen Berechnung der Gewichtsänderung, wogegen die Gewichtskorrektur, also die wirkliche Ausführung, hier kaum noch eine Rolle spielt. Demgegenüber birgt die epochenweise Korrektur ein gewisses Risiko bei der Konvergenz des Lernvorgangs. An dieser Stelle sei daher die musterweise Korrektur der Netzgewichte ausdrücklich empfohlen. Doch genug der grauen Theorie. Mit den bisher erarbeiteten Kenntnissen sollten wir nun endlich selbst in der Lage sein, ein neuronales Netz zu trainieren. Ausgangspunkt für unsere weiteren Aktivitäten auf diesem neu eroberten Terrain ist aber erst einmal die Schaffung einer geeigneten Klasse für die Datenhaltung.
3.2 Neuronale Netze 175
class MLPerceptron { const int maxlayer = 3; // 2 hiddenlayer + output const int maxneuron = 50; // öffentliche Strukturparameter des MLP public int layers; // Anzahl Schichten public int inputs; // Anzahl Eingangsneuronen public int outputs; // Anzahl Ausgangsneuronen // Neuronen je Lage, Netzgewichte und Bias public int[] number = new int[maxlayer]; public double[,,] wght = new double[maxlayer, maxneuron, maxneuron]; public double[,] bias = new double[maxlayer, maxneuron]; // öffentliche Parameter für die Ein-/Ausgabe des MLP public double[] input = new double[maxneuron]; public double[] target = new double[maxneuron]; public double[,] output = new double[maxlayer, maxneuron]; // private Parameter für die Ein-/Ausgabe des MLP private double[,] net = new double[maxlayer, maxneuron]; // private Parameter für die Lerndatei private StreamReader dat; private int musterzahl; // Parameter für den Backprop-Lernalgorithmus public String lerndatei; // Name der Lerndatei public int maxzyklen; // max. Anzahl der Lernzyklen public double sigma; // Lernrate public double dynsig; // dynamische Anpassung public double moment; // Momentum public double dynmom; // dynamische Anpassung public double fehlergrenze; public double fehlerquadsumme; ... }
176 3 Computational Intelligence
Den Signalfluß von den Eingangsneuronen (über die verdeckten Lagen) bis zu den Ausgangsneuronen nennt man Vorwärts-Propagation oder einfach nur Propagation. Weil die Eingangsneuronen das Eingangssignal nur weiterleiten bzw. verteilen, beginnt die Verarbeitung (entsprechend unserem technischen Modellneuron aus Abb. 3.2) mit den Neuronen der ersten verdeckten Lage. Deren Anzahl ist in number[0] hinterlegt, während inputs die Zahl der Netzeingänge (= Eingangsneuronen) ist. Die Ausgaben output[,] jeder Schicht bilden die Eingänge der nachfolgenden Neuronenlage. class MLPerceptron { ... public void Propagation() { // für alle k Neuronen der 1. (verdeckten) Schicht for (int k=0; k
3.2 Neuronale Netze 177
Ein wenig komplizierter ist die Implementierung des BackpropagationLernverfahrens. Die äußere while-Schleife überwacht das Abbruchkriterium, innerhalb derer die Lernmuster mehrmals durchlaufen werden. Hierfür gibt es eine innere for-Schleife, die alle weiteren Schritte enthält. Für jedes Lernmuster wird die Netzausgabe ermittelt und die resultierende Abweichung berechnet. Sie bestimmt dann rückwärts die erforderliche Gewichtsänderung, die anschließend auch tatsächlich ausgeführt wird (der Einfachheit halber allerdings wieder in Vorwärtsrichtung). Sind alle Lernmuster durchlaufen, erfolgt noch die Anpassung der Lernparameter, bevor es dann mit dem nächsten Zyklus weitergeht. class MLPerceptron { ... public void Backpropagation() { double[,,] dw = new double[maxlayer, maxneuron, maxneuron]; double[,] db = new double[maxlayer, maxneuron]; double[,] delta = new double[maxlayer, maxneuron]; int zyklus = 0; double fehler = 0; fehlerquadsumme = 999999;
// damit > fehlergrenze
// Lerndatei öffnen und Kompatibilität prüfen if (OeffneLerndatei(lerndatei) < 0) return; // Schleifendurchlauf bis maxzyklen erreicht // oder bis fehlergrenze unterschritten while (zyklus < maxzyklen && fehlerquadsumme > fehlergrenze) { // Neuinitialisierung in jeder Epoche fehlerquadsumme = 0; for (int i=0; i
178 3 Computational Intelligence for (int k=0; k0; i--) {
3.2 Neuronale Netze 179
for (int k=0; k
180 3 Computational Intelligence for (int j=0; j
3.2.5 Lerndatenaufbereitung
Entscheidend für den Erfolg neuronaler Netze ist die Qualität der zugrunde liegenden Trainingsdaten. Das MLP lernt aus Beispielen. In einen realen Prozeß eingebunden wird es seine Aufgabe daher nur dann erfüllen können, wenn die Trainingsdaten ein charakteristisches Abbild des Problems sind. In der Praxis hat man es meistens mit mehreren kontinuierlichen Eingangsgrößen zu tun. Zur Gewinnung von Trainingsmustern sind hieraus eine Anzahl typischer Daten zu entnehmen, wobei die Komplexität der Aufgabe die notwendige Rasterung bestimmt. Die extrahierten Eingangsdaten bilden zusammen mit den zugehörigen Zielwerten die Rohwerte für die Lerndatei.
3.2 Neuronale Netze 181
Wie man sich wohl leicht denken kann, ist es bei den vielfältigen Einsatzmöglichkeiten neuronaler Netze und der daraus resultierenden Varianz der Daten, nicht immer möglich im natürlichen Wertebereich zu arbeiten. Tatsächlich ist der verfügbare Wertebereich durch die verwendete Transferfunktion vorgegeben. Beim MLP ist das normalerweise die Sigmoidfunktion. Wegen ihres begrenzten Ausgabebereiches ist eine Normierung der Zielwerte unumgänglich. Dabei muß der theoretisch verfügbare Bereich 0..1 sogar noch weiter eingeschränkt werden. Betrachten wir hierzu noch einmal den Graphen der Sigmoidfunktion in Tabelle 3.1. Der Ausgangswert f(x) = 0 wird erst für x =- erreicht, f(x) = 1 erst für x = + . Zudem ist der Verlauf der Kurve in beiden Extremfällen sehr flach, d. h. die Ableitung df(x)/dx ist beinahe Null. Selbst relativ große Änderungen der Eingangswerte hätten hier nur minimale Ausgangsänderungen zur Folge. Eine solche Lernvorgabe würde das System in die Sättigung treiben, wo es träge verharrt. Mit einem weiteren Lernfortschritt ist dann nicht mehr zu rechnen. Um es erst gar nicht soweit kommen zu lassen, muß die Zielvorgabe, und damit auch der spätere Arbeitsbereich des MLP, auf einen sinnvollen Bereich eingeschränkt werden. Hier bietet sich z. B. das Intervall 0,2..0,8 an. Später im Betrieb sind die Ausgangswerte y = f(x) dann wieder zu entnormieren, also in den Originalbereich umzurechnen. In der folgenden Transformation ist y der Originalwert mit den Grenzwerten yoben, yunten und yMLP der für das neuronale Netz transformierten Wert.
y MLP =
0,8 − 0,2 ⋅ y + 0,5 y oben − y unten
(3.17)
Für die Rücktransformation in den Originalbereich gilt dann natürlich die Umkehrung.
y = ( y MLP − 0,5) ⋅
y oben − y unten 0,8 − 0,2
(3.18)
Etwas weniger restriktiv verhält es sich mit den Eingangswerten, da die Sigmoidfunktion für alle reellen Argumente definiert ist. Trotzdem ist auch hier eine Normierung sinnvoll, z. B. auf den Bereich –1,0..+1,0. Mit dieser Maßnahme wird einerseits der lineare Bereich der Sigmoiden gut ausgenutzt, andererseits steigt die Wahrscheinlichkeit, daß die Netzgewichte während der Trainingsphase innerhalb gewisser Grenzen bleiben. Wie bereits angedeutet, ist diese Einschränkung bei den Eingangsdaten aber nicht so absolut zu verstehen, wie zuvor bei der Lernvorgabe. Sollten in der Anwendung unter extremen Bedingungen auch vereinzelt Eingangsdaten außerhalb des normierten Bereiches auftreten, dann macht das gar nichts, unser MLP wird damit schon fertig.
182 3 Computational Intelligence
3.2.6 Die Lerndatei
Da wir für das Arbeiten mit dem MLP eine eigene Implementierung nutzen, sind wir völlig frei in Bezug auf den Aufbau der Lerndatei. Um die Handhabung zu erleichtern, entscheiden wir uns dafür, am Dateianfang Informationen über die Anzahl der enthaltenen Lernmuster und die Zahl der Eingangswerte bzw. der Zielwerte zu hinterlegen. Weiterhin ist es durchaus sinnvoll, die Lernmuster zeilenweise in einer lesbaren Textdatei anzuordnen, um eine Sichtprüfung zu ermöglichen. Da reale Lerndateien auch mehrere tausend Muster enthalten können, erleichtert eine Markierung der Zeilen die Orientierung (z. B. „i“ für input und „o“ für output). Ob man zusätzlich noch Leerzeilen zur Strukturierung nutzt, bleibt dem eigenen Geschmack überlassen. Die Lerndatei für das XOR-Problem könnte dann z. B. so aussehen: Muster 4 Inputs 2 Outputs 1 i 0.00000 o 0.20000 i 0.00000 o 0.80000 i 1.00000 o 0.20000 i 1.00000 o 0.80000
0.00000 1.00000 1.00000 0.00000
Im Programm ist zunächst einmal zu prüfen, ob die Lerndatei überhaupt vorhanden ist. Nach dem Öffnen der Datei wird der Dateikopf gelesen und über die Zahl der Ein- und Ausgänge die Lerndaten auf Kompatibilität mit der zu trainierenden Netzstruktur geprüft. Im Falle der Inkompatibilität ist ein entsprechender Errorcode zurückzugeben und eine Fehlermeldung abzusetzen. class MLPerceptron { ... private int OeffneLerndatei(String lerndatei) { int lrnin = 0; int lrnout = 0; String line = ""; String[] txt = null; String delimStr = " "; // Leerzeichen als Trenner
3.2 Neuronale Netze 183
char[] delimiter = delimStr.ToCharArray(); if (!File.Exists(lerndatei)) { Console.WriteLine("Lerndatei {0} nicht gefunden!", lerndatei); return -1; } dat = File.OpenText(lerndatei); // Lerndatei auf Kompatibilität prüfen line = dat.ReadLine(); txt = line.Split(delimiter, 2); musterzahl = Convert.ToInt32(txt[1]); line = dat.ReadLine(); txt = line.Split(delimiter, 2); lrnin = Convert.ToInt32(txt[1]); line = dat.ReadLine(); txt = line.Split(delimiter, 2); lrnout = Convert.ToInt32(txt[1]); if (lrnin != inputs || lrnout != outputs) { Console.WriteLine("Netzstruktur und Lerndatei sind nicht kompatibel!"); return -1; } return 1; } ... }
Beim Auslesen der Lernmuster das Überspringen der Markierungen („i“ bzw. „o“) nicht vergessen, sonst gibt es Probleme bei der Zuordnung. class MLPerceptron { ... private void LeseLernmuster() { String line = ""; String[] txt = null; String delimStr = " "; // Leerzeichen als Trenner char[] delimiter = delimStr.ToCharArray();
184 3 Computational Intelligence // aktuelles Lernmuster lesen // (zuerst die Eingabewerte... line = dat.ReadLine(); txt = line.Split(delimiter, inputs+1); for (int i=0; i
Da unsere Lerndatei während der Trainingsphase mehrmals vollständig durchlaufen wird, erfolgt jeweils am Dateiende ein Rücksprung auf das erste Lernmuster. Hierzu kann man den Dateikopf einfach überspringen. Erst nach Beendigung des Lernvorgangs wird die Lerndatei dann wieder geschlossen. class MLPerceptron { ... private void ResetLerndatei() { // zurück zum Dateianfang dat.BaseStream.Seek(0, SeekOrigin.Begin); // Dateikopf überspringen dat.ReadLine(); dat.ReadLine(); dat.ReadLine(); } private void SchliesseLerndatei() { dat.Close(); } ... }
3.2 Neuronale Netze 185
Abschließend noch eine kurze Betrachtung zur Reihenfolge der Muster innerhalb der Lerndatei. In den wahrscheinlich meisten Fällen werden die Lernmuster für die jeweils unterschiedlichen Prozeßparameter in ihrer natürlichen zeitlichen Abfolge erzeugt. Sie auch in genau dieser Reihenfolge als Lerndatei anzulegen ist jedoch ungünstig, da für den Backpropagation-Algorithmus die Reihenfolge der Präsentation sehr wichtig ist. Um hier ein optimales Ergebnis zu erzielen, ist dafür zu sorgen, daß aufeinanderfolgende Muster möglichst wenig korrelieren. Es kommt somit nicht nur auf den Inhalt der Lernmuster an, sondern auch auf deren Anordnung. Üblicherweise bilden die Trainingsmuster eine repräsentative Datenauswahl aus dem Wertebereich der Eingangsmerkmale und den zugehörigen Zieldaten. In der Regel besitzen ähnliche Eingangsdaten auch ähnliche Sollvorgaben, wodurch sich viele der Lernmuster kaum, oder nur sehr wenig voneinander unterscheiden. Wie wirkt sich das auf den Lernvorgang aus, wenn diese nun unmittelbar hintereinander liegen? Mit einem kleinen Experiment wollen wir die Auswirkungen einer ungünstig gewählten Reihenfolge, bei ansonsten identischen Randbedingungen, untersuchen. Ausgangspunkt ist das XOR-Problem mit seinen vier Lernmustern. unkorrelierte Lerndaten:
korrelierte Lerndaten:
i 0.000 o 0.200 i 0.000 o 0.800 i 1.000 o 0.200 i 1.000 o 0.800
i 0.000 o 0.200 i 0.000 o 0.800 i 1.000 o 0.800 i 1.000 o 0.200
0.000 1.000 1.000 0.000
0.000 1.000 0.000 1.000
Wie deutlich zu erkennen ist, steigert ein unkorrelierter Trainingsdatensatz die Lerngeschwindigkeit ganz erheblich. Für diesen Effekt ist das Momentum μ verantwortlich, welches grundsätzlich konvergenzbeschleunigend wirkt. Offensichtlich sind für den Algorithmus die Lerndaten optimal angeordnet, wenn aufeinanderfolgende Muster auch eine signifikante Änderung der Sollausgabe aufweisen bzw. wenn der Abstand zwischen ähnlichen Mustern möglichst groß ist.
186 3 Computational Intelligence 0,2
Fehler
0,15
0,1
0,05
0 1
50
100
150
200
250
300
350
400
450
500
Lernzyklen
Abb. 3.8. Lernfortschritt bei unkorrelierten und korrelierten (gestrichelt) Mustern
3.2.7 Anwendungen neuronaler Netze
Das MLP ist in der Lage, beliebige Beziehungen zwischen Eingangs- und Ausgangsdaten aus Beispielen zu erlernen, sofern denn zwischen beiden ein erlernbarer Zusammenhang besteht. Mit dieser Fähigkeit eignet es sich für solche Anwendungen, für die zwar kein vollständiges Prozeßmodell gefunden werden kann, es aber sehr wohl möglich ist aus gemessenen Daten ausreichend viele (repräsentative) Trainingsmuster zu generieren. Und das ist erstaunlich oft der Fall. Zeichenerkennung
Der Mensch kann Gesichter, Sprache oder Schrift mühelos erkennen. Dagegen stellt eine robuste maschinelle Erkennung, die sich auch nur annähernd mit der menschlichen Leistungsfähigkeit messen kann, immer noch eine große technische Herausforderung dar. Dabei sind die Erkennung von Sprache (eindimensionales Signal) und Gesichtern bzw. Schrift (zweidimensionale Signale) im Ansatz sehr ähnlich. Alle drei Anwendungen sind klassische Beispiele der Mustererkennung, einem Bereich, der ganz ohne Zweifel zu den besonderen Stärken biologischer Gehirne zählt. Anwendungen dieser Art eignen sich daher ideal als Prüfsteine für intelligente Verfahren. Als stellvertretendes Beispiel für eine Mustererkennung wollen wir die Zeichenerkennung näher betrachten. Sie kommt zum Einsatz z. B. in der Postautomatisierung, beim maschinellen Sortieren der Briefe, oder auch im Bankwesen, bei der automatischen Bearbeitung von Überweisungsaufträgen. Zur Vereinfachung wird die in der Regel recht aufwendige Vorverarbeitung an dieser Stelle nur kurz beschrieben. In einem ersten Schritt muß
3.2 Neuronale Netze 187
der gedruckte oder geschriebene Text digitalisiert werden, um ihn mit dem Computer weiter verarbeiten zu können. Bei der Post geschieht das natürlich nicht mit handelsüblichen Scannern, wie wir sie kennen. Hier kommen sehr viel leistungsfähigere und vollautomatisierte Systeme zum Einsatz. Doch auch deren Auflösung beträgt nur selten mehr als 300dpi, was sich als guter Kompromiß aus den widersprüchlichen Anforderungen nach geringer Datenmenge und guter Detailtreue erwiesen hat. Der eingescannte Text ist wegen verschiedener Störquellen sehr häufig nur von dürftiger Qualität. Die Ursache hierfür können störende Muster im Hintergrund, ein schwacher Kontrast, anhaftende Verschmutzungen oder eine Schieflage bei der Aufnahme sein. Solche Fehler lassen sich aber mit geeigneten Verfahren weitestgehend rausrechnen. Als nächstes ist es notwendig den digitalisierten Text zu segmentieren, d. h. die einzelnen Zeichen voneinander zu trennen. Hierzu wertet man das vertikale Projektionsprofil eines Schriftzuges aus, d. h. die Anzahl der vertikal übereinander liegenden Pixel beim horizontalen Durchlauf über den Schriftzug. Das Profil hat hohe Werte im Bereich der Buchstaben und verschwindet im Bereich der Lücken zwischen den einzelnen Buchstaben. Eine Trennung ist so möglich, vorausgesetzt die Buchstaben überlappen sich nicht. Wie man sich leicht denken kann, ist das bei Druckschrift sehr viel weniger ein Problem, als bei kursiver Fließschrift. Letztere ist auch beim derzeitigen Stand der Technik nicht ohne Probleme maschinell lesbar. Die Trennung handgeschriebener Druckbuchstaben ist jedoch auch nicht immer einfach. So bereitet z. B. die Unterscheidung von „rn“ und „m“ einem Menschen beim Lesen durchaus Schwierigkeiten. Uns ist in solchen Fällen unser Verständnis für den Gesamtzusammenhang eine große Hilfe. Der Computer hat dagegen nur sehr eingeschränkte Möglichkeiten sich hier richtig zu entscheiden, etwa die Identifikation legaler Zeichenketten durch den Vergleich mit einem Wörterbuch. Ein solches Wörterbuch bildet das verfügbare Expertenwissen des Computers auf der Wortebene. Sind die Wörter bzw. Buchstaben und Zahlen getrennt, dann sind die einzelnen Zeichen noch zu normieren, also auf einen einheitlichen Maßstab zu verkleinern bzw. zu vergrößern. Das Ergebnis der Vorverarbeitung sind segmentierte Zeichen mit fester Auflösung (z. B. 10 × 12 Pixel), die man schließlich einem neuronalen Netz zur Erkennung zuführen kann. Jeder Bildpunkt stellt ein Eingangsmerkmal dar und ist einem Eingangsneuron direkt zugeordnet. Eine ausreichend hohe Varianz der Trainingsdaten vorausgesetzt, ist das neuronale Netz in der Lage das Zeichen richtig zu klassifizieren und dies an seinem Ausgang anzuzeigen.
188 3 Computational Intelligence
0 1 2 3
9 Abb. 3.9. Neuronale Ziffernerkennung
Verständlicherweise ist man bemüht, die Anzahl der notwendigen Eingangsmerkmale so gering wie möglich zu halten. Sind wirklich 10 × 12 = 120 Merkmale notwendig, um zehn verschiedene Objekte zu klassifizieren? Oder, noch viel wichtiger, benötigt man wirklich ein Netz mit 120 Eingängen, um diese Merkmale zu verarbeiten? Erfahrungsgemäß hat eine hohe Zahl von Netzeingängen auch eine hohe Neuronenzahl in den verdeckten Lagen zur Folge. Eine Reduktion der Eingangsmerkmale sollte daher im Umkehrschluß auch zu einer kleineren Netztopologie führen, was wiederum die Trainingsphase erheblich verkürzt (kleines Netz ĺ kleine Laufzeit). Da jeder Bildpunkt ein Eingangsneuron benötigt, läßt sich deren
2x2
Abb. 3.10. Reduktion der Eingangsmerkmale durch Downsampling
3.2 Neuronale Netze 189
Anzahl reduzieren, indem man die Anzahl der Bildpunkte reduziert. Das ist genauso einfach, wie es sich anhört, da hierfür lediglich eine Anzahl von benachbarten Bildpunkten zu einem neuen Bildpunkt zusammengefaßt wird. Dessen Farbe bzw. Intensität ergibt sich dann durch Mittelwertbildung aller einbezogenen Punkte. Bildet man Blöcke von z. B. 2 × 2 Pixeln, reduziert sich das Bild auf ein Viertel seiner ursprünglichen Größe. Die Zusammenfassung größerer Blöcke führt zu einer entsprechend höheren Reduktion. Das funktioniert aber natürlich nur dann, wenn die anschließend verbleibenden Merkmale noch genügend repräsentativ sind, um eine eindeutige Klassifizierung vornehmen zu können. Diese gezielte Reduktion der Signalauflösung wird auch Downsampling genannt. Zeitreihenanalyse
Eine ebenfalls häufige Anwendung stellt die Zeitreihenanalyse dar. Jede zeitlich geordnete Menge von Einzelwerten x(k) stellt eine sogenannte Zeitreihe dar. Ein wohl bekanntes Beispiel für Zeitreihen sind die Aufzeichnungen der örtlichen Tageshöchsttemperatur, des Luftdrucks und der Niederschlagsmenge durch die Wetterdienste. Das Sammeln solcher Daten ist dabei keineswegs Selbstzweck, sondern hilft den Meteorologen Trends zu erkennen und bessere Modelle für ihre Vorhersagen zu entwickeln. Das Erkennen von Trends zur Abschätzung des zukünftigen Verlaufs ist dann auch eine der Hauptaufgaben der Zeitreihenanalyse (-prognose). Exakte Vorhersagen zukünftiger Ereignisse sind nur in elementar deterministischen Systemen (z. B. der Mechanik) möglich. Hierzu ist eine vollständige mathematische Beschreibung des Systems notwendig. Ausgehend von einem bekannten Anfangszustand kann dann unter Berücksichtigung aller äußeren Einflüsse der Folgezustand zu jedem beliebigen Zeitpunkt berechnet werden. Das hört sich einfach an, scheitert in der Praxis aber an der Komplexität realer Problemstellungen. Alle realen Systeme wechselwirken mit ihrer Umwelt auf vielfache und oft unbekannte Weise, was eine vollständige mathematische Beschreibung nahezu ausschließt. Für Prognosen ist man daher auf andere Methoden angewiesen. Anstatt das System mittels Zustandsgleichungen zu beschreiben, betrachtet man sein Ausgangssignal (eine Zeitreihe), dessen zeitlicher Verlauf den Systemzustand mit allen Einflüssen repräsentiert. Im einfachsten Fall wird man für eine Vorhersage den jüngsten Verlauf dieser Zeitreihe auch für die nächste Zukunft fortschreiben. Eine Methode, die jeder von uns anwendet, wenn er morgens aus dem Fenster schaut und das Wetter betrachtet („Gestern hat es den ganzen Tag geregnet, da nehme ich heute wohl lieber einen Schirm mit“). Eine sichere Prognose, insbesondere über längere Zeiträume, ist mit so einem simplen Ansatz aber kaum zu erwarten. Besser ist es da schon,
190 3 Computational Intelligence
man berücksichtigt auch weiter zurückliegende Daten („Gestern hat es nicht mehr so stark geregnet wie Vorgestern, wahrscheinlich kann ich heute ohne Schirm gehen“). Die Verfeinerung des zweiten Ansatzes besteht darin, nicht nur den letzen Wert der Zeitreihe zu berücksichtigen, sondern auch deren zeitliche Änderung ǻx/ǻt. Vom Standpunkt der Mathematik betrachtet, ist so eine Vorhersage nichts weiter als eine Extrapolation, d. h. es geht um die Bestimmung von Werten außerhalb eines vorgegebenen Stützintervalls. Als konventionelle Lösung dieses Problems bietet sich ein Polynomansatz an. Zwei Punkte definieren eine Gerade, drei Punkte eine quadratische Parabel, n + 1 Punkte ein Polynom n-ter Ordnung. Allerdings eignen sich Polynome nur für relativ kurze Intervalle, da sie mit zunehmender Ordnung zu Oszillationen neigen. Sie gelten zudem immer nur stückweise und müssen somit für jeden neu hinzukommenden Wert erneut bestimmt werden. Um die komplexen Zusammenhänge längerer Zeitreihen zu prognostizieren, bieten sich daher neuronale Netze an. Aber nicht nur die Meteorologie lebt von guten Prognosen, noch viel mehr als dort ist in anderen Branchen das frühzeitige Erkennen eines Trends bares Geld wert, wie zwei weitere Beispiele zeigen. Aufgabe der Energieversorgungsunternehmen ist die sichere Versorgung der Verbraucher mit elektrischer Energie. Die Kraftwerke können den Strom jedoch nicht auf Vorrat produzieren. Damit es durch plötzliche Verbrauchsspitzen trotzdem nicht zu Engpässen in der Versorgung kommt, ist es notwendig den Energiebedarf, abhängig von der jeweiligen Tages- und Jahreszeit, möglichst genau zu prognostizieren. Nicht weniger interessant ist die Entwicklung der Börsenkurse. Glücklich kann sich derjenige schätzen, der hier in die Zukunft zu schauen vermag. Planungssicherheit und wirtschaftliche Vorteile waren schon immer gute Gründe, sich neuen Technologien zu öffnen. Völlig unabhängig von der konkreten Anwendung läuft die neuronale Zeitreihenanalyse nach dem immer gleichen Schema ab. Das Netz wird angelernt aus einer Anzahl vergangener Werte x(k-n), x(k-n + 1), ..., x(k−1) und dem aktuellen Wert x(k) einer Zeitreihe den zukünftigen Wert x(k + 1) zu bestimmen. Als Grundlage für das Training dienen die bisher aufgezeichneten Werte der Zeitreihe. Hierbei nutzt man den Umstand, daß jeder alte Wert in der Zukunft liegt, wenn man ihn von einer noch weiter zurückliegenden Vergangenheit aus betrachtet. Liegt eine Anzahl n von Werten vor, dann lassen sich daraus Trainingsmuster erstellen. Mit m bezeichnen wir die Anzahl der verwendeten Eingangsmuster (n > m). x(k-n), x(k-n + 1), ..., x(k-n + m−1) ĺ x(k-n + m) ĺ x(k-n + m + 1) x(k-n + 1), x(k-n + 2), ..., x(k-n + m) x(k-n + 2), x(k-n + 3), ..., x(k-n + m + 1) ĺ x(k-n + m + 2) ...
3.3 Fuzzy-Logik 191
x(k-3)
x(k-2) x(k+1) x(k-1)
x(k) Abb. 3.11. Neuronale Prognose einer Zeitreihe
Natürlich erhalten wir somit nur Rohwerte, die für eine Lerndatei noch entsprechend aufzubereiten sind. Wie das funktioniert, wurde im Abschn. 3.2.5 gezeigt. Das Ergebnis unserer Bemühungen ist ein Netz, das einen kleinen Blick in die Zukunft erlaubt. Werden dem MLP die einzelnen Werte einer Zeitreihe als Eingangsvektor gleichzeitig zugeführt, bildet es ein sogenanntes Time-Delay neuronales Netzwerk (TDNN). Beim TDNN durchlaufen die Abtastwerte das Netz wie ein Schieberegister und rutschen mit jedem Zeittakt eine Position weiter. Zum Abschluß sei noch eine kurze akademische Betrachtung gestattet. Bei der Prognose von Börsenkursen werden neuronale Netze darauf trainiert, sich in einem durch überwiegend menschliche Handlungsweisen bestimmten Metier zu bewähren. Neben dem rein konjunkturellen Umfeld spielen am Aktienmarkt Erwartungen, Bauchgefühl und Emotionen eine nicht zu unterschätzende Rolle. Stützen sich zukünftig die Entscheidung über Kauf oder Verkauf mehr und mehr auf die Vorhersage neuronaler Netze, dann bestimmen diese zunehmend allein das Marktgeschehen, losgelöst von menschlichen Einflüssen. Wie gut ist dann noch deren Prognose unter diesen veränderten Bedingungen?
3.3 Fuzzy-Logik Ständig treffen wir Entscheidungen. Dabei wird unser Handeln in jeder Situation durch die verarbeiteten Sinneseindrücke, unsere persönlichen Erfahrungen und unsere augenblickliche Zielstellung bestimmt. Wir wägen ab und reagieren, mal mehr, mal weniger. Dies ist um so erstaunlicher, da ein Großteil der Informationen die wir verarbeiten sehr unpräzise ist. Doch
192 3 Computational Intelligence
auch mit ungenauen Informationen können wir erstaunlich oft richtige Schlußfolgerungen ziehen. Aus dem Bemühen Vorgänge dieser Art in einer Theorie zu bündeln, ist die Fuzzy-Logik (unscharfe Logik) entstanden, als deren geistiger Vater Lotfi A. Zadeh von der Berkeley Universität in Kalifornien gilt. Die Vorteile, mit einem Formalismus menschliche Entscheidungsprozesse nachbilden zu können, liegen auf der Hand. Viele Vorgänge lassen sich nur sehr schwer oder sogar überhaupt nicht mathematisch beschreiben. Die Ursache hierfür sind unbekannte Störeinflüsse, zahlreiche Wechselwirkungen mit der Umgebung oder starke Nichtlinearitäten. Wenn es aber nicht gelingt einen Vorgang mathematisch zu modellieren, dann ist es mit den klassischen Methoden auch nicht möglich ihn technisch zu beherrschen, also ihn zu steuern oder zu regeln. Alle gängigen Verfahren der Prozeßautomatisierung stützen sich auf ein mathematisches Modell. Andererseits zeigt die Erfahrung, daß auch sehr komplexe Abläufe von menschlichen Bedienern vergleichsweise einfach beherrscht werden. Sie sind nicht nur Experten für bestimmte Abläufe, sondern können ihr Wissen auch problemlos an andere Personen weitergeben. Offensichtlich gibt es eine Form der nichtmathematischen Modellbildung, die komplexe Zusammenhänge ausreichend genau beschreibt. Aber wie setzt ein menschlicher Bediener sein Expertenwissen um? Hier genügen bereits wenige Punkte zur Charakterisierung. • Anders als in der digitalen Logik trifft ein Mensch nicht nur Ja/Nein Entscheidungen, sondern ist aufgrund seiner Erfahrung in der Lage, auf verschiedenen Situationen angemessen zu reagieren. • Viele komplizierte Vorgänge lassen sich umgangssprachlich relativ leicht beschreiben und zwar in Form von „Wenn..., dann...“ Regeln. • Die konsequente Anwendung dieser Regeln macht einen Menschen (oder eine Maschine) zum Experten. • Typischerweise verwendet man für eine solche verbale Beschreibung Begriffe, wie „sehr hoch“ oder „etwas weniger“ usw., die aber hochgradig unbestimmt bzw. unscharf sind. Mit der Möglichkeit menschliche Informationsverarbeitung in maschinell ausführbare Algorithmen abzubilden eröffnen sich neue technische Anwendungen, die bisher nur schwer in den Griff zu bekommen waren. Ein Beispiel hierfür sind Fahrassistenzsysteme. Immer wieder kommt es auf unseren Straßen aus Unachtsamkeit zu Auffahrunfällen, die jedes Jahr Schäden in Millionenhöhe verursachen. Taucht ein Hindernis auf der Straße auf und erfordert das Betätigen der Bremse, dann läßt sich das Verhalten eines aufmerksamen Autofahrers etwa folgendermaßen modellieren:
3.3 Fuzzy-Logik 193
1. Wenn die Geschwindigkeit hoch ist und der Abstand klein ist, dann sei der notwendige Bremsdruck sehr groß. 2. Wenn die Geschwindigkeit mittel ist und der Abstand mittel ist, dann sei der notwendige Bremsdruck mittel. 3. Wenn die Geschwindigkeit niedrig ist und der Abstand groß ist, dann sei der notwendige Bremsdruck klein. 4. Wenn… Man kann sich leicht vorstellen, daß ein solcher Satz von Regeln, trotz seines irgendwie vagen Inhalts, die Reaktion in einer Gefahrensituation gut beschreibt. Für die Umsetzung als ausführbarer Algorithmus ist es in einem ersten Schritt erforderlich, die unpräzisen Aussagen in eine Form zu bringen, die uns diese zugänglich macht. Als Erweiterung der bekannten zweiwertigen Logik wurde hierfür die sogenannte unscharfe Menge entwickelt. 3.3.1 Die unscharfe Menge
Die tägliche Erfahrung lehrt uns: Dinge sind nicht nur schwarz oder weiß, es gibt auch viele Zwischentöne. Eine unscharfe Menge beschreibt die graduelle Zugehörigkeit μM(x) eines Objektes x zu einer Menge M. Dabei bedeutet μM(x) = 1 das Objekt x gehört voll und ganz zu M bzw. μM(x) = 0 es gehört überhaupt nicht dazu (das war übrigens auch in der digitalen Logik schon so). Darüber hinaus sind bei unscharfen Mengen sämtliche Zwischenwerte erlaubt. Bleiben wir beim automatischen Fahrassistenten, dann lassen sich die unterschiedlichen Geschwindigkeiten mit Hilfe verschiedener unscharfer Ausprägungen beschreiben. μ niedrig
mittel
hoch
1
0 25
50
75
Geschwindigkeit in km/h
Abb. 3.12. Unscharfe Zugehörigkeitsfunktionen
194 3 Computational Intelligence
In diesem Beispiel bildet „Geschwindigkeit“ eine linguistische Variable, die Bezeichner „niedrig“, „mittel“ und „hoch“ werden linguistische Terme genannt. Wie man sieht, hat jeder Wert der Grundmenge nicht nur genau eine Eigenschaft, ist entweder „hoch“ oder „niedrig“, sondern vereinigt mehrere dieser Eigenschaften in unterschiedlichem Maße auf sich.
μ mittel (40 km / h) = 0,85 μ niedrig (40 km / h) = 0,15 Tabelle 3.2. Für technische Anwendungen vereinfachte Zugehörigkeitsfunktionen
z-Typ x0 = x1 < x2 < x3
μ(x)
1
0
Ȝ-Typ x0 < x1 = x2 < x3
x μ(x)
1
x
0
ʌ-Typ x0 < x1 < x2 < x3
μ(x)
1
x
0
s-Typ x0 < x1 < x2 = x3
μ(x)
1
0
x
3.3 Fuzzy-Logik 195
Natürlich ist die gewählte Verteilung der Zugehörigkeitsfunktionen sehr stark kontextabhängig. Auf der Autobahn gelten schließlich nicht die gleichen Maßstäbe, wie in einer verkehrsberuhigten Zone. Aber wohl jeder wird die gaußförmigen Zugehörigkeitsfunktionen zur Beschreibung der fließenden Übergänge, intuitiv als richtig ansehen. Dennoch sind sie für technische Anwendungen ungeeignet. Weil Gauß-Funktionen ungleich Null für alle Werte aus dem Grundbereich sind, ist der Berechnungsaufwand für μ(x) sehr hoch. Aus diesem Grund nähert man die Verläufe durch Polygone mit vier Stützstellen an. Damit lassen sich vier Grundtypen unscharfer Zugehörigkeiten darstellen, deren Bezeichnungen sich aus ihrer äußeren Form ableiten. Für alle Typen gilt μ(x0) = 0, μ(x1) = 1, μ(x2) = 1 und μ(x3) = 0. Damit ist die Berechnung der Zugehörigkeit nicht nur denkbar einfach, sondern auch besonders effizient, denn man muß lediglich drei Fälle unterscheiden. 1. Ist x x0 oder x x3, dann ist μ(x) = 0 (ohne weitere Berechnung), 2. ist x x1 und x x2, dann ist μ(x) = 1 (ohne weitere Berechnung), 3. ansonsten berechnet sich μ(x) über eine einfache Geradengleichung. 3.3.2 Unscharfes Schließen
Nun möchte man unscharfe Informationen natürlich nicht nur darstellen, sondern auch sinnvoll verarbeiten. Hierzu sind verschiedene logische Operatoren erforderlich, die es dem Anwender gestatten, unscharfe Mengen miteinander zu verknüpfen. In dem einleitenden Beispiel wurden zwei Voraussetzungen, z. B. eine „hohe“ Geschwindigkeit und ein „kleiner“ Abstand miteinander gekoppelt, um daraus eine Schlußfolgerung abzuleiten. Offenbar stellt das Bindewort „und“ bereits eine umgangssprachliche Verknüpfung im Sinne eines mathematischen Operators dar. Unser Regelwerk in seiner Gesamtheit beschreibt das Abbremsen eines Autos. Abhängig von der durch Geschwindigkeit und Abstand gegebenen Situation, werden verschiedene Regeln aktiviert. Es wirkt dann entweder die erste Regel oder die zweite Regel oder ..., eventuell auch mehrere Regeln gleichzeitig. Ohne es ausdrücklich zu erwähnen, sind die einzelnen Regeln durch den Begriff „oder“ miteinander verbunden, der somit ebenfalls einen Operator darstellt. Daneben gibt es noch weitere Operatoren, z. B. die Negation.
196 3 Computational Intelligence Tabelle 3.3. Fuzzy-Operatoren μ(x) A
Der Durchschnitt zweier Mengen ' entspricht dem sprachlichen „und“: μ(x) = Minimum(μA(x), μB(x))
B
C
1
0
x μ(x) A
Die Vereinigung zweier Mengen entspricht dem sprachlichen „oder“: μ(x) = Maximum(μA(x), μB(x))
B
C
1
x
0 μ(x) A
Die einstellige Negation entspricht dem sprachlichen „nicht“: μ(x) = 1 – μB(x)
B
C
1
0
x
Weitere Operatoren ergeben sich z. B. durch die Addition der Zugehörigkeitswerte bzw. durch deren Multiplikation. Im ersten Fall erhält man ein optimistischeres Ergebnis als bei der Vereinigung, im zweiten Fall ein etwas pessimistischeres als beim Durchschnitt. In der Praxis finden diese Varianten aber kaum Anwendung. Zusammen mit den unscharfen Mengen kann man nun auf Grundlage der vorgestellten Operatoren prozeßbeschreibende Regeln definieren, deren Anwendung dann den Experten nachbildet. Die unscharfe Entscheidungsfindung durchläuft typischerweise drei Phasen: • In der ersten Phase, Fuzzifizierung genannt, werden die Eingangsdaten auf die linguistischen Terme abgebildet, d. h. man bestimmt für jeden Eingangswert seine Zugehörigkeit zu den unscharfen Mengen „klein“, „mittel“ oder „hoch“. • Die anschließende Regelauswertung bezeichnet man als Inferenz. Da in unseren Beispiel-Regeln beide Voraussetzungen durch „und“ miteinander verknüpft sind, ergibt sich die Aktivierung der Schlußfolgerung einer Regel aus dem Minimum beider Zugehörigkeitswerte. Weil sich die
3.3 Fuzzy-Logik 197
unscharfen Mengen normalerweise um 50% überlappen, sind zudem immer zwei Regeln gleichzeitig wirksam, wobei die einzelnen Regeln implizit durch „oder“ verbunden sind. Die Schlußfolgerung beider Regeln ergibt sich somit aus dem Maximum beider Minima. • Im letzten Schritt, Defuzzifizierung genannt, ist das Ergebnis der Inferenz wieder in eine scharfe Ausgangsgröße (also in eine konkrete Stellhandlung) umzuwandeln. Zur besseren Anschauung der hier beschriebenen Phasen dient Abb. 3.13. Die Pfeile auf den linguistischen Eingangsvariablen G und A markieren die scharfen Augenblickswerte von Geschwindigkeit und Abstand. Wenn G=hoch
und
A=klein
G
dann B=hoch
A
B
MIN Wenn
G=mittel
und
G
A=mittel
dann
B=mittel
A
B MAX
B Abb. 3.13. Unscharfe Regelauswertung
198 3 Computational Intelligence μ(x)
1
B
0
Abb. 3.14. Die Lage des Flächenschwerpunktes bildet den Ausgangswert
Als Ergebnis erhalten wir ein etwas eigenwillig anmutendes Flächenstück, aus dem wieder ein scharfer Ausgangswert, in unserem Beispiel der Bremsdruck, zu bilden ist. Benutzt man hierfür die COG-Methode (center of gravity), dann bestimmt er sich aus der Lage des Flächenschwerpunktes über der Grundmenge.
xCOG =
³ x ⋅ μ ( x)dx ³ μ ( x)dx
(3.19)
Auch wenn bisher alles sehr einleuchtend klingt, so ist dieses Vorgehen doch mit einigen unerwünschten Nebeneffekten verbunden. Es ist unmittelbar einsichtig, daß der Schwerpunkt einer solchen Fläche niemals am Rand dieser Fläche liegt. Demzufolge wäre es aber unmöglich die Randwerte des Stellbereiches anzusprechen. Durch Überlegung stellt man schnell fest, daß sich der Schwerpunkt in dem durch die Schwerpunkte der Teilflächen begrenzten Bereich bewegt. Um also den gesamten Stellbereich nutzen zu können, müssten die Randwerte die Schwerpunkte der äußeren Zugehörigkeitsfunktionen bilden. Das gelingt genau dann, wenn man diese durch Spiegelung erweitert. Ein weiterer Effekt ergibt sich durch das Abschneiden der Zugehörigkeitsfunktionen je nach Erfüllungsgrad der Voraussetzung. Weil die hierdurch entstehenden Flächenstücke nicht direkt proportional zur Höhe sind, gehen kleine Aktivierungsgrade überproportional in die Schwerpunktbildung ein. Indem man die Zugehörigkeitsfunktion durch Multiplikation mit dem Erfüllungsgrad linear verkleinert, läßt sich diese Nichtlinearität vermeiden. Weiterhin könnte man den sich überlappenden Bereich beider Zugehörigkeitsfunktionen bei der Schwerpunktbildung zusätzlich bewerten. Alle diese Effekte lassen sich jedoch sehr elegant umgehen, wenn man am Ausgang anstelle der unscharfen Zugehörigkeitsfunktionen scharfe
3.3 Fuzzy-Logik 199 μ(x)
1
0
B
Abb. 3.15. Lage des Schwerpunktes bei Verwendung von Singletons
Stellwerte verwendet, sogenannte Singletons. Nebenbei vereinfacht sich hierdurch die Berechnung des Schwerpunktes ganz erheblich, weshalb die meisten Entwicklungstools dem Benutzer für Ausgangsvariablen überhaupt nur Singletons zur Verfügung stellen.
¦x ⋅μ = ¦μ k
xCOG
k
k
(3.20)
k
k
Die Schwerpunktbildung erfolgt hier ähnlich wie bei einer Waage, bei der das Produkt aus Hebelarm und Masse beidseitig ins Gleichgewicht zu bringen ist. Dabei gehen in die Berechnung nur diejenigen Singletons ein, die (als Resultat der Eingangswerte und dadurch wirksamen Regeln) auch tatsächlich angesprochen worden sind. 3.3.3 Die Struktur von Fuzzy-Systemen
Ganz allgemein sind Fuzzy-Systeme nichts anderes, als nichtlineare, mehrdimensionale Übertragungsfunktionen F:RnĺRm. Den n Eingangswerten xk werden m Ausgangswerte yk zugeordnet, eine Eigenschaft, die wir grundsätzlich schon von den neuronalen Netzen kennen, wie Abschn. 3.2.3 gezeigt hat. Ebenso wie diese, stellen Fuzzy-System Abbildungsmaschinen dar, obwohl sich die Art der Wissensrepräsentation völlig von der beim MLP unterscheidet. Vergleichbar etwa mit der Datenhaltung eines Computers auf Bitebene und einem objektorientierten Klassenmodell. In Anlehnung an Abb. 3.3 ergibt sich die nachfolgende Struktur. Eine solche abstrakte Darstellung hilft zwar dem Verständnis, für die praktische Anwendung ist es aber mindestens ebenso wichtig unscharfes Wissen irgendwie greifbar zu machen. Die notwendigen Voraussetzungen
200 3 Computational Intelligence
x1
x2
xn
Fuzzifizierung Expertenwissen
Inferenz
Defuzzifizierung
y1
y2
ym
Abb. 3.16. Struktur eines Fuzzy-Systems
hierfür sind jedenfalls geschaffen. Mit Hilfe von unscharfen Variablen und „Wenn..., dann...“-Regeln gelingt es, Expertenwissen zu modellieren und als Datei abzuspeichern. Ein solches „Expertenextrakt“ in Dateiform bildet dann die Basis für das Einbinden in einen realen Prozeß. Wie eine solche Datei aussehen könnte, ist nachfolgend aufgezeigt. Neben dem Projektnamen enthält sie Informationen über die Anzahl der Eingänge, Ausgänge und Regeln. Für jede unscharfe Variable ist ebenfalls der Name, die physikalische Einheit sowie die Anzahl der Terme vermerkt. Die Terme selbst definieren sich über vier Stützstellen (entsprechend Tabelle 3.2) aus der jeweiligen Grundmenge. Bremsassistent
2
1
9
Geschwindigkeit km/h 3 niedrig 0.0 0.0 0.2 0.5 mittel 0.2 0.5 0.5 0.8 hoch 0.5 0.8 1.0 1.0 Abstand m 3 klein 0.0 mittel 0.2
0.0 0.5
0.2 0.5
0.5 0.8
3.3 Fuzzy-Logik 201
gross
0.5
0.8
Bremsdruck bar klein 0.0 mittel 0.5 gross 1.0
1.0
1.0
3
Wenn Geschwindigkeit = niedrig und Abstand = gross dann Bremsdruck = klein Wenn Geschwindigkeit = niedrig und Abstand = mittel dann Bremsdruck = klein Wenn Geschwindigkeit = niedrig und Abstand = klein dann Bremsdruck = mittel Wenn Geschwindigkeit = mittel und Abstand = gross dann Bremsdruck = klein Wenn Geschwindigkeit = mittel und Abstand = mittel dann Bremsdruck = mittel Wenn Geschwindigkeit = mittel und Abstand = klein dann Bremsdruck = gross Wenn Geschwindigkeit = hoch und Abstand = gross dann Bremsdruck = mittel Wenn Geschwindigkeit = hoch und Abstand = mittel dann Bremsdruck = gross Wenn Geschwindigkeit = hoch und Abstand = klein dann Bremsdruck = gross
Für ein System mit einem Eingang und einem Ausgang läßt sich die Übertragungscharakteristik als Kennlinie darstellen, für zwei Eingänge (wie im vorliegenden Fall) ergibt sich ein sogenanntes Kennfeld. Das vorgestellte Beispiel kommt mit jeweils drei linguistischen Termen für die Geschwindigkeit und den Abstand aus. Hieraus resultieren dann neun unscharfe Regeln. Damit ist unser Bremsassistent zwar überschaubar
202 3 Computational Intelligence 1
B 0,5 0 0,5 A
0 1
0,5
1 0
G Abb. 3.17. Bremsdruck-Kennfeld aus Geschwindigkeit G und Abstand A
und transparent, man kann sich aber leicht vorstellen, daß Fuzzy-Systeme für reale Probleme sehr viel differenzierter reagieren müssen. Sie haben z. B. fünf, sieben oder neun linguistische Terme je Variable. Da der Eingangsraum normalerweise vollständig abzudecken ist, ergibt sich die Anzahl der Regeln aus allen kombinatorischen Verknüpfungen der Eingangsterme (bei drei Eingängen je fünf Termen sind das 53 = 125 Regeln). Bleibt noch zu klären, warum so oft eine ungerade Anzahl von Termen zur Beschreibung der linguistischen Variablen verwendet wird. Sehr häufig hat man es mit Problemen zu tun, bei denen sich der Wertebereich symmetrisch um eine Ruhelage oder einen Nullpunkt erstreckt. Der mittlere Term, oft deutlich schmaler definiert (d. h. steilflankiger), markiert dann genau diesen Punkt. Entsprechend der 50%-Überlappungsregel sind die zugewandten Flanken der benachbarten Terme ebenso steil definiert, diese selbst entsprechend unsymmetrisch. Im Ergebnis führt diese Maßnahme zu einem empfindlicheren Ansprechverhalten des Systems im Bereich der Ruhelage. 3.3.4 Implementierung von Fuzzy-Systemen
Ist die Wissensbasis erstellt, hat man zwar die erste Hürde erfolgreich genommen, steht dann aber immer noch vor dem Problem, diese irgendwie in den Prozeß einzubinden bzw. zu integrieren. Am einfachsten gelingt das als Softwarerealisierung. Wenn man einen Codegenerator hätte, der die Wissensbasis quasi auf Knopfdruck direkt in Programmcode umwandelt, dann wäre das sehr hilfreich. Ein solcher Codegenerator erleichtert das Arbeiten insbesondere bei der immer notwendigen Justierung von Fuzzy-Systemen. Üblicherweise gelingt mit dem ersten Entwurf nur eine recht grobe Annäherung an das gewünschte Verhalten, was eine iterative Feinabstimmung notwendig macht. Es ist leicht einzusehen, daß dies innerhalb der Wissensbasis leichter möglich ist, als auf Codeebene. Die Implementierung eines
3.3 Fuzzy-Logik 203
Codegenerators benötigt natürlich Datenstrukturen oder Klassen für die Terme, Variablen und Regeln. Nach der „Bottom-Up“ Methode beginnen wir daher ganz unten mit den linguistischen Termen. Hierfür sind jeweils vier Stützstellen notwendig. Bleibt eigentlich nur noch die Frage, ob man die Terme lieber als Klasse oder als Struktur anlegt. Wegen der eleganten Instanziierbarkeit von Klassen über deren Konstruktor, ziehen wir diese den Strukturen vor. class fuzzyterm { public String name; public double x0; public double x1; public double x2; public double x3;
// // // // //
z. B. "hoch" 1. Stützstelle 2. Stützstelle 3. Stützstelle 4. Stützstelle
// Konstruktor public fuzzyterm() { name = ""; x0 = 0; x1 = 0; x2 = 0; x3 = 0; } }
Für die Ausgangsvariablen werden nur Singletons unterstützt, d. h. es genügt eine einzige Stützstelle. class singleterm { public String name; // z. B. "hoch" public double x; // Stützstelle // Konstruktor public singleterm() { name = ""; x = 0; } }
204 3 Computational Intelligence
Eine unscharfe Variable besteht aus einer Anordnung mehrerer linguistischer Terme, hat aber neben dem Variablennamen (z. B. „Geschwindigkeit“, „Abstand“) noch eine physikalische Einheit (km/h, m, ...). Die Anzahl der Terme kann natürlich für alle Variablen unterschiedlich sein, weshalb deren Festlegung zweckmäßigerweise über den Konstruktor erfolgt. class fuzzyvar { public String name; // Name der Variablen public String einheit; // Einheit der Variablen public fuzzyterm[] term; // Fuzzy-Terme der Variablen // Konstruktor public fuzzyvar(int termzahl) { name = ""; einheit = ""; term = new fuzzyterm[termzahl]; } }
Für die Ausgänge gilt entsprechendes, unter Verwendung der zuvor erstellten Singleton-Klasse. class singlevar { public String name; // Name der Variablen public String einheit; // Einheit der Variablen public singleterm[] term; // Singletons der Variablen // Konstruktor public singlevar(int termzahl) { name = ""; einheit = ""; term = new singleterm[termzahl]; } }
Kaum zu glauben, aber mit den vier gerade erzeugten Klassen ist der schwierigste Teil der Arbeit bereits getan. Also, zurücklehnen und kurz durchatmen. Was jetzt noch fehlt, ist eine Klasse für die verbalen Regeln. Sie liegen in Form von „Wenn..., dann...“-Regeln vor. Da diese grundsätzliche
3.3 Fuzzy-Logik 205
Struktur für alle Regeln gilt, ist es nur notwendig die Anzahl der Eingangs/Ausgangsvariablen je Regel festzuhalten und sich den Index des jeweiligen Terms einer Variablen zu merken. Wir setzen die Anzahl der Variablen für alle Regeln der Wissensbasis als gleich voraus, was keine allzu große Einschränkung darstellt, womit nur noch die Indexe verbleiben. In unserem Beispiel wären das die Werte {0, 2, 0} für die erste Regel (entsprechend den Eingangstermen „niedrig“ bzw. „gross“ und dem Ausgangsterm „klein“) oder {0, 1, 0} für die zweite Regel. Eine solche Indexfolge bildet dann genau eine verbale Regel. class verbal { public int[] para; // Konstruktor public verbal(int parazahl) { para = new int[parazahl]; } }
Die Klassen fuzzyvar, singlevar und verbal bilden dann die Komponenten der Klasse Wissensbasis. Wie bereits erwähnt, hängt die Anzahl der Regeln von der Anzahl der Terme je Eingangsvariable ab. Da die Eingänge aber erst später definiert werden, ist es nicht möglich die Regeln zusammen mit den anderen Variablen im Konstruktor anzulegen. class Wissensbasis { public fuzzyvar[] eingang; public singlevar[] ausgang; public verbal[] regel; private String dateiname; private String projektname; // Konstruktor public Wissensbasis(int einzahl, int auszahl) { // Anzahl der Variable festlegen eingang = new fuzzyvar[einzahl]; ausgang = new singlevar[auszahl]; // Dimension von regel wird später festgelegt, // da diese von der Anzahl der Terme abhängig ist
206 3 Computational Intelligence
dateiname = ""; projektname = ""; } ... }
Die gerade erstellten Klassen bilden das Fundament, auf das wir aufbauen wollen. Sind Struktur und Syntax der Wissensbasis erst einmal festgelegt (z. B. wie im Abschn. 3.3.3), läßt sie sich mit jedem beliebigen Editor erstellen und als Datei speichern. Natürlich benötigt man dann auch eine Methode, um sie wieder einzulesen. Damit die Implementierung nicht unnötig kompliziert wird, machen wir an dieser Stelle ein paar Einschränkungen: • Bei der Regelauswertung werden die Variablen in der gleichen Reihenfolge erwartet, wie bei der Variablendefinition (die Wissensbasis im Abschn. 3.3.3 erfüllt diese Bedingung). • Für jede Regel ist genau eine Zeile zu verwenden. Diese folgen unmittelbar hintereinander, ohne Leerzeile (abweichend vom Beispiel in Abschn. 3.3.3). • Hat eine Regel mehrere Ausgangsvariablen, dann folgen diese aufeinander, jeweils durch ein Leerzeichen getrennt. class Wissensbasis { ... public int LeseWissensbasis(String quelldatei) { StreamReader dat = null; String line = ""; String[] txt = null; String delimStr = " "; // Leerzeichen als Trenner char[] delimiter = delimStr.ToCharArray(); int einzahl = 0; int auszahl = 0; int regelzahl = 0; int termzahl = 0; int wortzahl = 0; String substr = ""; int position = 0; dateiname = quelldatei;
3.3 Fuzzy-Logik 207
if (!File.Exists(quelldatei)) { Console.WriteLine("Wissensbasis nicht gefunden!"); return -1; } dat = File.OpenText(quelldatei); // Dateikopf lesen line = dat.ReadLine(); txt = line.Split(delimiter, 4); projektname = txt[0]; einzahl = Convert.ToInt32(txt[1]); auszahl = Convert.ToInt32(txt[2]); regelzahl = Convert.ToInt32(txt[3]); line = dat.ReadLine(); // Kompatibilitätstest if (einzahl != eingang.Length || auszahl != ausgang.Length) { Console.WriteLine("Fuzzystruktur und Wissensbasis sind nicht kompatibel!"); dat.Close(); return -1; } // alle Eingangsvariablen einlesen for (int j=0; j<einzahl; j++) { line = dat.ReadLine(); txt = line.Split(delimiter, 3); termzahl = Convert.ToInt32(txt[2]); // Anzahl der linguistischen Terme festlegen eingang[j] = new fuzzyvar(termzahl); // Terme tatsächlich anlegen for (int k=0; k
208 3 Computational Intelligence line = dat.ReadLine(); txt = line.Split(delimiter, 5); eingang[j].term[k].name = txt[0]; eingang[j].term[k].x0 = Convert.ToDouble(txt[1]); eingang[j].term[k].x1 = Convert.ToDouble(txt[2]); eingang[j].term[k].x2 = Convert.ToDouble(txt[3]); eingang[j].term[k].x3 = Convert.ToDouble(txt[4]); } // Leerzeile line = dat.ReadLine(); } // alle Ausgangsvariablen einlesen for (int j=0; j
3.3 Fuzzy-Logik 209
{ // für jede Regel werden die Indexe // der Terme/Singletons erfasst regel[k] = new verbal(einzahl+auszahl); } // Länge der Fuzzy-Regeln bestimmen wortzahl = 1 + // "Wenn" eingang.Length + // Zahl der Eingänge eingang.Length - 1 + // Zahl "und" 1 + // "dann" ausgang.Length; // Zahl der Ausgänge // Regeln einlesen for (int i=0; i
210 3 Computational Intelligence // Variable und Term trennen, // Variablenname verwerfen, weil Reihenfolge klar substr = substr.Remove(0, position+1); // mit Variablendefinition vergleichen for (int k=0; k
Nach dem Einlesen der Wissensbasis sind unsere Variablen/Objekte mit den entsprechenden Informationen gefüllt. Immerhin ist damit ist der erste Schritt getan. Es fehlt aber immer noch eine Möglichkeit, das mühsam erstellte Fuzzy-System in ein reales Projekt einbinden zu können. Am einfachsten gelingt das mit einem Codegenerator, der die Wissensbasis direkt in compilierbaren Quellcode umsetzt, z. B. als eigene Klasse in einer eigenen Datei. class Wissensbasis { ... public void CodeGenerator() { StreamWriter dat = File.CreateText(dateiname+".cs"); dat.WriteLine("class Fuzzy{0}", projektname); dat.WriteLine("{"); dat.WriteLine(" public double[] indata;"); dat.WriteLine(" public double[] outdata;"); dat.WriteLine(); dat.WriteLine(" private double[] my;"); dat.WriteLine(" private double min;"); dat.WriteLine(" private double[] max;");
3.3 Fuzzy-Logik 211
dat.WriteLine(" private double[] nenner;"); dat.WriteLine(); dat.WriteLine(" // Konstruktor"); dat.WriteLine(" public Fuzzy{0}()", projektname); dat.WriteLine(" {"); dat.WriteLine(" indata = new double[{0}];", eingang.Length); dat.WriteLine(" outdata = new double[{0}];", ausgang.Length); dat.WriteLine(" my = new double[{0}];", eingang.Length); dat.WriteLine(" min = 0;"); dat.WriteLine(" max = new double[{0}];", ausgang[0].term.Length); dat.WriteLine(" nenner = new double[{0}];", ausgang.Length); dat.WriteLine(" }"); dat.WriteLine(); dat.WriteLine(" // Zugehörigkeitsfunktion"); dat.WriteLine(" private double ZGF(double x0,"); dat.WriteLine(" double x1,"); dat.WriteLine(" double x2,"); dat.WriteLine(" double x3,"); dat.WriteLine(" double input)"); dat.WriteLine(" {"); dat.WriteLine(" if (x0 <= input && input < x1)"); dat.WriteLine(" {"); dat.WriteLine(" return ((input-x0)/(x1-x0));"); dat.WriteLine(" }"); dat.WriteLine(" if (x1 <= input && input <= x2)"); dat.WriteLine(" {"); dat.WriteLine(" return 1.0;"); dat.WriteLine(" }"); dat.WriteLine(" if (x2 < input && input <= x3)"); dat.WriteLine(" {"); dat.WriteLine(" return ((x3-input)/(x3-x2));"); dat.WriteLine(" }"); dat.WriteLine(" return 0.0;"); dat.WriteLine(" }"); dat.WriteLine(); dat.WriteLine(" public void Inferenz()"); dat.WriteLine(" {"); // Ausgabedaten neu initialisieren
212 3 Computational Intelligence dat.WriteLine(" outdata[0] = 0;"); for (int i=0; i 1) { dat.Write(" &&"); dat.WriteLine(); dat.Write(" "); } else { dat.Write(")"); dat.WriteLine(); } } dat.WriteLine(" {"); // if... Begin der Regel for (int j=0; j<eingang.Length; j++) { dat.Write(" my[{0}] = ZGF(", j); dat.Write("{0}, {1}, {2}, {3},", eingang[j].term[regel[i].para[j]].x0, eingang[j].term[regel[i].para[j]].x1, eingang[j].term[regel[i].para[j]].x2, eingang[j].term[regel[i].para[j]].x3); dat.Write(" indata[{0}]);", j); dat.WriteLine(); } dat.WriteLine(); // Minimum der Regel bilden
3.3 Fuzzy-Logik 213
if (eingang.Length == 1) { dat.WriteLine(" min = my[0];"); } if (eingang.Length >= 2) { dat.WriteLine(" if (my[0] < my[1])"); dat.WriteLine(" {"); dat.WriteLine(" min = my[0];"); dat.WriteLine(" }"); dat.WriteLine(" else"); dat.WriteLine(" {"); dat.WriteLine(" min = my[1];"); dat.WriteLine(" }"); } if (eingang.Length > 2) { for (int j=2; j<eingang.Length; j++) { dat.WriteLine(" if (my[{0}] < min)", j); dat.WriteLine(" {"); dat.WriteLine(" min = my[{0}];", j); dat.WriteLine(" }"); } } dat.WriteLine(); // Maximum über alle Regeln bilden dat.WriteLine(" if (min > max[{0}])", regel[i].para[eingang.Length]); dat.WriteLine(" {"); dat.WriteLine(" max[{0}] = min;", regel[i].para[eingang.Length]); dat.WriteLine(" }"); dat.WriteLine(" }"); // if... Ende der Regel dat.WriteLine(); } dat.WriteLine(" // Defuzzifizierung mit COG"); dat.Write(" nenner[0] = "); for (int i=0; i 1) { dat.Write(" + "); }
214 3 Computational Intelligence else { dat.Write(";"); dat.WriteLine(); } } dat.WriteLine(" if (nenner[0] > 0)"); dat.WriteLine(" {"); dat.Write(" outdata[0] = ("); for (int i=0; i 1) { dat.Write(" + "); } else { dat.Write(")"); dat.WriteLine(); dat.Write(" / nenner[0];"); dat.WriteLine(); } } dat.WriteLine(" }"); dat.WriteLine(" }"); dat.WriteLine("}"); dat.Close();
// Inferenz()... Ende // class... Ende
} ... }
Zugegeben, die Implementierung des Codegenerators ist nicht unbedingt leicht zu verstehen (hierbei leistet auch die beschränkte Zeilenlänge ihren Beitrag). Der Vergleich mit dem nachfolgenden Ergebnis sollte aber das Verständnis für die Umsetzung der Wissensbasis in compilierbaren Quellcode wesentlich erleichtern. class FuzzyBremsassistent { public double[] indata; public double[] outdata; private double[] my;
3.3 Fuzzy-Logik 215
private double min; private double[] max; private double[] nenner; // Konstruktor public FuzzyBremsassistent() { indata = new double[2]; outdata = new double[1]; my = new double[2]; min = 0; max = new double[3]; nenner = new double[1]; } // Zugehörigkeitsfunktion private double ZGF(double x0, double x1, double x2, double x3, double input) { if (x0 <= input && input < x1) { return ((input-x0)/(x1-x0)); } if (x1 <= input && input <= x2) { return 1.0; } if (x2 < input && input <= x3) { return ((x3-input)/(x3-x2)); } return 0.0; } public void Inferenz() { outdata[0] = 0; max[0] = 0; max[1] = 0; max[2] = 0; // 1. Regel if (0 <= indata[0] && indata[0] <= 0.5 && 0.5 <= indata[1] && indata[1] <= 1) {
216 3 Computational Intelligence my[0] = ZGF(0, 0, 0.2, 0.5, indata[0]); my[1] = ZGF(0.5, 0.8, 1, 1, indata[1]); if (my[0] < my[1]) { min = my[0]; } else { min = my[1]; } if (min > max[0]) { max[0] = min; } } // 2. Regel if (0 <= indata[0] && indata[0] <= 0.5 && 0.2 <= indata[1] && indata[1] <= 0.8) { my[0] = ZGF(0, 0, 0.2, 0.5, indata[0]); my[1] = ZGF(0.2, 0.5, 0.5, 0.8, indata[1]); if (my[0] < my[1]) { min = my[0]; } else { min = my[1]; } if (min > max[0]) { max[0] = min; } } // 3. Regel if (0 <= indata[0] 0 <= indata[1] { my[0] = ZGF(0, 0, my[1] = ZGF(0, 0,
&& indata[0] <= 0.5 && && indata[1] <= 0.5)
if (my[0] < my[1])
0.2, 0.5, indata[0]); 0.2, 0.5, indata[1]);
3.3 Fuzzy-Logik 217
{ min = my[0]; } else { min = my[1]; } if (min > max[1]) { max[1] = min; } } // 4. Regel if (0.2 <= indata[0] && indata[0] <= 0.8 && 0.5 <= indata[1] && indata[1] <= 1) { my[0] = ZGF(0.2, 0.5, 0.5, 0.8, indata[0]); my[1] = ZGF(0.5, 0.8, 1, 1, indata[1]); if (my[0] < my[1]) { min = my[0]; } else { min = my[1]; } if (min > max[0]) { max[0] = min; } } // 5. Regel if (0.2 <= indata[0] && indata[0] <= 0.8 && 0.2 <= indata[1] && indata[1] <= 0.8) { my[0] = ZGF(0.2, 0.5, 0.5, 0.8, indata[0]); my[1] = ZGF(0.2, 0.5, 0.5, 0.8, indata[1]); if (my[0] < my[1]) { min = my[0]; } else
218 3 Computational Intelligence { min = my[1]; } if (min > max[1]) { max[1] = min; } } // 6. Regel if (0.2 <= indata[0] && indata[0] <= 0.8 && 0 <= indata[1] && indata[1] <= 0.5) { my[0] = ZGF(0.2, 0.5, 0.5, 0.8, indata[0]); my[1] = ZGF(0, 0, 0.2, 0.5, indata[1]); if (my[0] < my[1]) { min = my[0]; } else { min = my[1]; } if (min > max[2]) { max[2] = min; } } // 7. Regel if (0.5 <= indata[0] && indata[0] <= 1 && 0.5 <= indata[1] && indata[1] <= 1) { my[0] = ZGF(0.5, 0.8, 1, 1, indata[0]); my[1] = ZGF(0.5, 0.8, 1, 1, indata[1]); if (my[0] < my[1]) { min = my[0]; } else { min = my[1]; } if (min > max[1])
3.3 Fuzzy-Logik 219
{ max[1] = min; } } // 8. Regel if (0.5 <= indata[0] && indata[0] <= 1 && 0.2 <= indata[1] && indata[1] <= 0.8) { my[0] = ZGF(0.5, 0.8, 1, 1, indata[0]); my[1] = ZGF(0.2, 0.5, 0.5, 0.8, indata[1]); if (my[0] < my[1]) { min = my[0]; } else { min = my[1]; } if (min > max[2]) { max[2] = min; } } // 9. Regel if (0.5 <= indata[0] && indata[0] <= 1 && 0 <= indata[1] && indata[1] <= 0.5) { my[0] = ZGF(0.5, 0.8, 1, 1, indata[0]); my[1] = ZGF(0, 0, 0.2, 0.5, indata[1]); if (my[0] < my[1]) { min = my[0]; } else { min = my[1]; } if (min > max[2]) { max[2] = min; } }
220 3 Computational Intelligence
// Defuzzifizierung mit COG nenner[0] = max[0] + max[1] + max[2]; if (nenner[0] > 0) { outdata[0] = (0*max[0] + 0.5*max[1] + 1*max[2]) / nenner[0]; } } }
3.4 Neuronales Netz oder Fuzzy-System? Das antrainierte Wissen neuronaler Netze ist in deren Gewichtsmatrix kodiert und damit einer Interpretation kaum zugänglich, wogegen FuzzySysteme mit ihrer klar lesbaren Wissensbasis, bestehend aus Variablen und Regeln, unmittelbar verständlich sind. Schon aus diesem Gegensatz ergibt sich fast zwangsläufig, daß beide auf völlig unterschiedliche Weise erstellt werden. Neuronale Netze lernen aus Beispielen, d. h. die ihnen in der Trainingsphase vorgelegten Eingangs-/Ausgangsmuster müssen das Lernproblem genügend genau repräsentieren. Das Erstellen der Lerndaten ist dabei ein nicht zu unterschätzendes Problem. Demgegenüber modellieren FuzzySysteme den Entscheidungsprozeß eines menschlichen Bedieners. Sie eignen sich daher in erster Linie für Probleme mit vergleichsweise wenigen Eingangs- und Ausgangswerten. In der Regel haben Fuzzy-Systeme nur drei oder vier Eingangsvariablen. So eine Beschränkung ist bei neuronalen Netzen nicht nötig, ganz im Gegenteil. Sie haben oft sogar hundert oder noch mehr Eingänge und zumeist auch mehrere Ausgänge, werden also bevorzugt für höherdimensionale Aufgaben eingesetzt. Ein großer Vorteil von Fuzzy-Systemen ist der Umstand, daß ihr Wertebereich, sieht man einmal von Beschränkungen durch die Hardwarebasis ab, grundsätzlich nicht eingeschränkt ist, was das Arbeiten im natürlichen Wertebereich der Prozeßgrößen ermöglicht. Die Beschränkungen der Transferfunktion eines neuronalen Netzes erfordern dagegen immer eine zusätzliche Normierung. Ganz egal, ob neuronales Netz oder Fuzzy-System, beiden gemein ist ihr robustes und fehlertolerantes Verhalten in bezug auf Störungen.
3.4 Neuronales Netz oder Fuzzy-System? 221 Tabelle 3.4. Merkmale von neuronalen Netzen und Fuzzy-Systemen μ(x)
input 1
input 2
output 1
input 3
output 2
input 4
Black-Box Lernfähig Nichtlineares Übertragungsverhalten hoher Dimension Subsymbolische Informationsverarbeitung nach Dem Vorbild biologischer Gehirne
1
0
B
Transparent Nicht lernfähig Nichtlineares Übertragungsverhalten geringer Dimension Symbolische Informationsverarbeitung nach dem Vorbild menschlicher Entscheidungsprozesse Beschränkter Wertebereich, daher NorArbeiten im natürlichen mierung der Prozeßgrößen notwendig Wertebereich der Prozeßgrößen ist möglich Fehlertolerant und robust
4 Simulationstechnik
4.1 Einführung „Da steh’ ich nun, ich armer Thor! Und bin so klug als wie zuvor…“. Das Streben nach Erkenntnis treibt den Menschen um, schon Johann Wolfgang Goethe wußte das. Von Kindesbeinen an, zwingt uns unsere angeborene Neugier Dinge zu erforschen und auszuprobieren. Mit zunehmendem Alter verfeinert sich zwar die Methodik, unser Wissensdurst wird dadurch aber kaum gestillt. Das Computerzeitalter gibt uns mit der Simulationstechnik (simulare [lat.]: vortäuschen) ein weiteres Werkzeug in die Hand, zu erkennen, was die Welt im Innersten zusammenhält. Neben Theorie und Experiment hat sie sich inzwischen längst als drittes Standbein in der Wissenschaft etabliert. Die Simulationstechnik stellt Methoden zur Nachbildung dynamischer Systeme zur Verfügung, mit dem Ziel Erkenntnisse zu gewinnen, die auf die Realität übertragbar sind. In der Regel sind digitale Simulationen kostengünstiger, schneller und ihre Durchführung weit weniger gefährlich oder umweltschädlich als reale Experimente.
4.2 Modellbildung Ein System besteht aus einer beliebigen Anzahl von Elementen, die miteinander in Wechselwirkung stehen. Jedes Element hat einen Eingang und einen Ausgang, weshalb sich die Beziehungen zwischen den einzelnen Elementen mit Hilfe von Signalen mathematisch beschreiben lassen. Bei technischen Systemen erfolgt diese Beschreibung üblicherweise über die Anwendung physikalischer Gesetze. So entsteht eine Anzahl von Systemgleichungen, deren Formulierung man als Modellbildung bezeichnet. Aufgrund der Komplexität realer Probleme ist es meistens notwendig geeignet zu abstrahieren, weshalb ein solches Modell dann auch kein Abbild der Realität ist, sondern nur eine Annäherung mit eingeschränkter Gültigkeit darstellt. Entsprechend kritisch sind die Simulationsergebnisse in Bezug auf das ursprünglich reale Problem zu bewerten.
224 4 Simulationstechnik
Abstraktion Realität
reale Lösung
Interpretation
mathematisches Modell
mathematische Lösung
Abb. 4.1. Modellbildungsprozeß
Die mathematische Modellierung realer Systeme, unabhängig davon ob physikalisch-technischen, biologischen oder ökonomischen Ursprungs, führt in der Regel auf eine Differentialgleichung (DGL), die es zu lösen gilt. Da Differentialgleichungen eine gesuchte Lösungsfunktion und ihre Ableitung(en) miteinander verknüpfen, gelingt die analytische Lösung nur in wenigen einfachen Fällen. Unser erstes Beispiel ist ein solcher Fall. Eine Spule L mit einem in Reihe geschalteten Widerstand R wird zum Zeitpunkt t = 0 durch Schließen des Schalters mit der Gleichspannung U0 beaufschlagt. Unmittelbar danach beginnt für t > 0 der Strom für zu fließen. Aufgrund der Selbstinduktion der Spule kann er sich aber nicht sprunghaft ändern, sondern nähert sich seinem stationären Endwert asymptotisch an.
Abb. 4.2. Einschaltvorgang einer Spule
4.3 Die analytische Lösung 225
Die Berechnung des Einschaltstromes führt auf eine lineare, gewöhnliche (= nur von einer Variablen abhängig) Differentialgleichung erster Ordnung (= enthält nur die erste Ableitung).
U0 = U R + UL U0 = i ⋅ R + L ⋅
(4.1)
di dt
(4.2)
Gleichung (4.2) enthält neben dem Strom auch seine zeitliche Änderung di/dt, bildet also die systembeschreibende DGL. Es ist üblich, die Gleichung auf den Koeffizienten der höchsten Ableitung zu normieren.
R U di +i⋅ = 0 L L dt
(4.3)
4.3 Die analytische Lösung In der Regel läßt sich die Lösung einer Differentialgleichung nicht eindeutig allein durch die Gleichung selbst bestimmen, sondern man benötigt noch einen Startwert als zusätzliche Bedingung. Genügt für die eindeutige Lösung ein solcher Startwert, spricht man von einem Anfangswertproblem, mehrere Startwerte an den Rändern des Lösungsintervalls definieren ein Randwertproblem. Für den vorliegenden Gleichungstyp berechnet sich die analytische Lösung nach einem festen Schema. Zuerst ist die homogene Lösung unserer DGL (4.3) zu bestimmen, d. h. die Teillösung für U0/L = 0. Verschwindet die rechte Seite, sieht man sofort, daß die Ableitung des Stromes, bis auf den Faktor R/L, gleich dem negativen Strom selbst ist. In diesem Fall bietet sich eine Exponentialfunktion als Lösungsansatz an.
i (t ) = C1 ⋅ eλt
(4.4)
Wir bilden die erste Ableitung und setzen anschließend beide Terme in die homogene DGL ein.
di (t ) = C1 ⋅ λ ⋅ e λt dt C1 ⋅ λ ⋅ eλt +
R ⋅ C1 ⋅ eλt = 0 L
226 4 Simulationstechnik
Durch Umformung (mit ein bißchen Übung genügt auch scharfes Hinschauen) erkennt man:
λ=−
R L
Der Koeffizient L/R bildet die Zeitkonstante IJ, woraus schließlich die homogene Lösung folgt.
i (t ) = C1 ⋅ e
−
t
τ
(4.5)
Als nächstes ist die inhomogene Lösung der DGL mit U0/L0 durch ein Verfahren zu bestimmen, das sich Variation der Konstanten nennt. Hierfür wird C = C(t) angesetzt, d. h. wir nehmen an, die Konstante C der homogenen Lösung sei nun selbst eine Funktion der Zeit.
i (t ) = C (t ) ⋅ e
−
t
τ
(4.6)
Um die Ableitung von i(t) zu bilden, wenden wir die Produktregel an. t
t
di (t ) dC (t ) −τ C (t ) −τ = ⋅e − ⋅e τ dt dt
Setzt man beiden Gleichungen in die DGL (4.3) ein und berücksichtigt weiterhin R/L = 1/IJ, dann folgt: t
t
t
dC (t ) − τ C (t ) −τ C (t ) − τ U 0 ⋅e − ⋅e + ⋅e = τ τ L dt t
dC (t ) − τ U 0 ⋅e = L dt t
dC (t ) U 0 τ = ⋅e dt L
C(t) ergibt sich durch Integration dieser Ableitung.
C (t ) = ³
dC (t ) dt dt t
U C (t ) = ³ 0 ⋅ eτ dt L
4.3 Die analytische Lösung 227 t
U C (t ) = 0 ⋅ ³ e τ dt L t
C (t ) =
U0 ⋅τ ⋅ e τ + K L
Die zusätzliche Integrationskonstante K können wir in den weiteren Berechnungen vernachlässigen. Setzen wir C(t) in unseren Ansatz (4.6) ein, erhalten wir die inhomogene Lösung unserer Differentialgleichung. t
t
− U i (t ) = 0 ⋅ τ ⋅ e τ ⋅ e τ L
Im vorliegenden Fall läßt sich diese noch ein Stück vereinfachen, da das Produkt der beiden Exponentialfunktionen gerade Eins ergibt. Mit IJ = L/R erhalten wir:
i (t ) =
U0 R
(4.7)
Somit sind die homogene und die inhomogene Lösung bestimmt. Die Gesamtlösung folgt schließlich aus der Addition der beiden Teillösungen (4.5) und (4.7).
i (t ) = C1 ⋅ e
−
t
τ
+
U0 R
(4.8)
Mit Gln. (4.8) liegt die vollständige Lösung für i(t) vor, zunächst allerdings noch mit einem kleinen Schönheitsfehler. Um den Verlauf des Stromes grafisch oder numerisch darstellen zu können, ist nämlich noch die Unbekannte C1 zu bestimmen. Hierfür benötigen wir eine weitere Gleichung, die sich z. B. aus einer zusätzlichen Randbedingung herleiten läßt. Weil der Strom erst nach dem Schließen des Schalters, also für t > 0, zu fließen beginnt, bildet der Einschaltvorgang selbst eine solche Randbedingung, d. h. zum Zeitpunkt t = 0 haben wir einen Anfangswert i(t) = 0.
i (0) = 0 = C1 +
U0 R
(4.9)
Da dieser eine Anfangswert ausreicht, um eine eindeutige Lösung zu finden, bildet unser Einschaltvorgang ein Anfangswertproblem.
C1 = −
U0 R
228 4 Simulationstechnik
Eingesetzt in Gln. (4.8) erhalten wir mit I0 = U0/R die endgültige Lösung unserer Differentialgleichung. −
t
i (t ) = I 0 ⋅ (1 − e ) τ
(4.10)
Zugegeben, der hier gefundene funktionale Zusammenhang für den Einschaltstrom ist ohnehin bekannt oder läßt sich doch zumindest erahnen. Um so mehr überrascht es, daß die Berechnung, selbst für dieses relativ einfache Beispiel, so aufwendig und kompliziert ist. Für Differentialgleichungen existiert leider keine geschlossene mathematische Theorie, es ist daher auch nicht möglich, ausgehend von einem beliebigen Gleichungstyp, die Lösung nach einem festen Schema zu bestimmen. Das gelingt nur für lineare Differentialgleichungen. Für alle anderen Typen gibt es zwar verschiedene Ansätze, die das Auffinden einer Lösung erleichtern (Erfahrung ist hierbei sehr hilfreich), aber eben nicht garantieren.
4.4 Numerische Lösungsmethoden von Differentialgleichungen Weil es aber nicht möglich ist jede DGL analytisch zu lösen, ist man entsprechend häufig auf numerische Verfahren angewiesen, die, wenn auch keine exakte Lösung, doch zumindest eine ausreichend genaue Näherung liefern. Wie sich zeigen wird, lassen sich die numerischen Lösungsverfahren sehr anschaulich geometrisch bzw. grafisch interpretieren. Diese Anschaulichkeit bleibt allerdings weitestgehend verborgen, solange man die Differentialgleichungen in ihrer „natürlichen“ Form betrachtet. Eine geeignete Normierung wandelt die dimensionsbehafteten Größen von Gln. (4.3) in x-y-Koordinaten. Hierzu erweitern wir in einem ersten Schritt mit (I0/IJ) · ( IJ/I0) = 1. § I 0 τ · di U 0 R ¨¨ ⋅ ¸¸ ⋅ = − ⋅i L L © τ I 0 ¹ dt § i · d ¨¨ ¸¸ I0 © I0 ¹ U 0 R ⋅ = − ⋅i τ L L §t· d¨ ¸ ©τ ¹ § i · d ¨¨ ¸¸ © I0 ¹ = U0 ⋅ τ − R ⋅ τ ⋅ i §t· L I0 L I0 d¨ ¸ ©τ ¹
4.4 Numerische Lösungsmethoden von Differentialgleichungen 229
Berücksichtigt man IJ = L/R bzw. I0 = U0/R und ersetzt y = i/I0 bzw. x = t/IJ, dann führt dies zur normierten Form unserer ursprünglichen DGL.
dy = 1− y dx
(4.11)
Das in unserem speziellen Beispiel die Steigung dy/dx nur von der Variablen y abhängt ist schon ein Sonderfall. Im Allgemeinen ist dy/dx eine Funktion sowohl von y als auch von x.
dy = f ( x, y ) dx
(4.12)
Damit ist die geometrische Interpretation von Differentialgleichungen aber besonders einfach. In jedem Punkt des durch die Koordinaten x und y aufgespannten Gebietes ist die Steigung der Lösungskurve (bzw. die Tangente an ihr) durch den funktionalen Zusammenhang von f(x,y) definiert. Zeichnet man viele solcher Tangenten für verschiedene Werte von x und y in ein Koordinatensystem ein, dann entsteht ein sogenanntes Richtungsfeld. Wir sind somit in der Lage die Lösungskurven einer DGL grafisch zu bestimmen, ohne auf komplizierte mathematische Methoden zurückgreifen zu müssen. Bevor wir zu den numerischen Lösungsmethoden kommen, benötigen wir einen Klassenrumpf, der uns die wichtigsten Komponenten für die Implementierung zur Verfügung stellt. Neben zwei Arrays für die x-yKennlinie sind das die Anfangswerte, die Schrittweite und natürlich noch unsere Beispiel-DGL (4.11). class Simulation { const int Schrittzahl = 100; // eine einzelne x-y-Kennlinie public double[] x; public double[] y; // Anfangswerte public double xstart; public double ystart; // Schrittweite public double h; // Konstruktor
230 4 Simulationstechnik public Simulation() { x = new double[Schrittzahl]; y = new double[Schrittzahl]; xstart = 0; ystart = 0; h = 0.1; } public double DGL(double x, double y) { double dydx = 0; // Steigung dy/dx dydx = 1 - y; return dydx; } … }
4.4.1 Das Polygonzug-Verfahren
Die einfachste numerische Lösungsmethode besteht darin, ausgehend von einem Anfangswert f(x0,y0), den Funktionswert des nachfolgenden Stützpunktes abzuschätzen, indem man der durch die DGL gegebenen Steigung dy/dx ein Stück weit folgt. Auf diese Weise gelangt man zu einem neuen Stützpunkt. Hier wird die Steigung erneut bestimmt, um die Richtung zu korrigieren. Fährt man so fort, ergibt sich ein geschlossener Kurvenzug, der die gesuchte Lösung approximiert.
xk +1 = xk + h
(4.13)
yk +1 = yk + h ⋅ f ( xk , yk )
(4.14)
Das Polygonzug-Verfahren führt zu akzeptablen Ergebnissen, solange die durch die gewählte Schrittweite h gegebene Abweichung von der jeweiligen Steigung dy/dx = f(x,y) genügend klein bleibt. Es ist besonders anschaulich, läßt sich intuitiv herleiten und problemlos implementieren. Sein großer Nachteil ist die geringe Genauigkeit. Gleichung (4.14) entspricht einer nach dem ersten Ableitungsglied abgebrochenen Taylorreihe, schätzt man den verbleibenden Fehler mit dem nächsten Glied ab, dann liegt er in der Größenordnung h2.
4.4 Numerische Lösungsmethoden von Differentialgleichungen 231
class Simulation { … public void EinfachPolygon(double[] x, double[] y, double startx, double starty) { double dydx = 0; // Steigung dy/dx x[0] = startx; y[0] = starty; for (int k=0; k<Schrittzahl-1; k++) { // Berechnung der Steigung dydx = DGL(x[k], y[k]); // Extrapolation des nächsten Punktes x[k+1] = x[k] + h; y[k+1] = y[k] + h*dydx; } } … }
4.4.2 Das verbesserte Polygonzug-Verfahren
Die mangelnde Genauigkeit des vorherigen Verfahrens resultiert aus der am Intervallanfang berechneten Steigung, die bis zum Intervallende als konstant angenommen wird. Man kann aber davon ausgehen, daß sich die Steigung innerhalb der Schrittweite h ändert. Möchte man eine höhere Genauigkeit erzielen, muß man daher einen Steigungswert nehmen, der die stetige Änderung von dy/dx besser berücksichtigt. Wie man sich leicht vorstellen kann, liegt dieser Wert in der Mitte des Intervalls. Das verbesserte Polygonzug-Verfahren berechnet in einem Zwischenschritt die Steigung in der Intervallmitte und verwendet diesen genaueren Zwischenwert zur Bestimmung des nächsten Stützpunktes.
xk +1 / 2 = xk +
h 2
yk +1 / 2 = yk + h ⋅ f ( xk , yk )
(4.15) (4.16)
232 4 Simulationstechnik
xk +1 = xk + h
(4.17)
yk +1 = yk + h ⋅ f ( xk +1 / 2 , yk +1 / 2 )
(4.18)
Der erhöhte Berechnungsaufwand wird mit einer höheren Genauigkeit belohnt, d. h. der Fehler dieses Verfahrens ist proportional zu h3. class Simulation { … public void VerbessertPolygon(double[] x, double[] y, double startx, double starty) { double dydx = 0; // Steigung dy/dx double x2 = 0; // Zwischenwert double y2 = 0; // Zwischenwert x[0] = startx; y[0] = starty; for (int k=0; k<Schrittzahl-1; k++) { // Berechnung der Steigung dydx = DGL(x[k], y[k]); // Extrapolation der Zwischenwerte x2 = x[k] + h/2; y2 = y[k] + (h/2)*dydx; // Verbesserte Steigung bei den Zwischenwerten dydx = DGL(x2, y2); // Extrapolation mit verbesserter Steigung x[k+1] = x[k] + h; y[k+1] = y[k] + h*dydx; } } … }
4.4 Numerische Lösungsmethoden von Differentialgleichungen 233
4.4.3 Das Euler-Cauchy-Verfahren
Die Änderung von dy/dx zu berücksichtigen ist eine Idee, die auch dem Euler-Cauchy-Verfahren zugrunde liegt. Anstatt die Steigung aus der Intervallmitte zu nehmen, wird hier aber der Mittelwert der Steigungen vom Intervallanfang und vom Intervallende gebildet. Zu diesem Zweck ist in einem Zwischenschritt ein „vorläufiger“ Endwert zu extrapolieren, der anschließend in die Berechnung des tatsächlichen Endwertes einfließt.
xk +1 = xk + h ~ yk +1 = yk + h ⋅ f ( xk , yk ) yk +1 ) · § f ( xk , yk ) + f ( xk +1 , ~ yk +1 = yk + h ⋅ ¨ ¸ 2 © ¹
(4.19) (4.20) (4.21)
Der Fehler dieses Verfahrens ist, genau wie beim verbesserten Polygonzug, proportional zu h3, was sich leicht durch die Ähnlichkeit der beiden Ansätze erklärt. Auch der Berechnungsaufwand ist etwa gleich hoch. class Simulation { … public void EulerCauchy(double[] x, double[] y, double startx, double starty) { double dydx = 0; // Steigung dy/dx double dydx2 = 0; // Steigung am Intervallende double y2 = 0; // Zwischenwert x[0] = startx; y[0] = starty; for (int k=0; k<Schrittzahl-1; k++) { // Berechnung der Steigung dydx = DGL(x[k], y[k]); x[k+1] = x[k] + h; // vorläufige Extrapolation für y y2 = y[k] + h*dydx; // Steigung am Endpunkt dydx2 = DGL(x[k], y2);
234 4 Simulationstechnik
// endgültige Extrapolation für y y[k+1] = y[k] + h*(dydx+dydx2)/2; } } … }
4.4.4 Das Runge-Kutta-Verfahren
Für eine noch höhere Genauigkeit muß man die Ableitung zwischen zwei benachbarten Stützstellen besser abschätzen. Wenn man eine noch größere Anzahl von Zwischenwerten aus dem Intervall h für die Schätzung heranzieht, ist das sehr leicht möglich. Mit seinen vier Werten stellt das Runge-Kutta-Verfahren einen guten Kompromiß zwischen Genauigkeit und Berechnungsaufwand dar (entwickelt um 1900 als noch mühsam „von Hand“ gerechnet wurde, ein besonders wichtiger Aspekt). Neben dem hier vorgestellten Algorithmus existieren noch weitere Berechnungsvarianten sowie Versionen mit zwei oder sechs Zwischenwerten. xk +1 = xk + h (4.22)
k1 = h ⋅ f ( xk , yk ) h k k2 = h ⋅ f ( xk + , yk + 1 ) 2 2 h k k3 = h ⋅ f ( xk + , yk + 2 ) 2 2 k4 = h ⋅ f ( xk + h, yk + k3 ) yk +1 = yk +
1 ⋅ ( k1 + 2 ⋅ k2 + 2 ⋅ k3 + k 4 ) 6
(4.23) (4.24) (4.25) (4.26) (4.27)
Mit einem Restfehler in der Größenordnung h5 liefert das Runge-KuttaVerfahren für viele Differentialgleichungen eine gute Näherungslösung. Für viele Anwender ist es daher die erste Wahl, wogegen auch gar nichts einzuwenden ist, solange es nicht die einzige bleibt. Leider ist das RungeKutta-Verfahren relativ empfindlich bezüglich der gewählten Schrittweite und nicht immer absolut stabil. Es kann daher durchaus passieren, daß in bestimmten Fällen Runge-Kutta versagt, in denen einfachere Verfahren (z. B. Euler-Cauchy) noch brauchbare Resultate liefern.
4.4 Numerische Lösungsmethoden von Differentialgleichungen 235
class Simulation { … public void RungeKutta(double[] x, double[] y, double startx, double starty) { double k1 = 0; // 1. Zwischenwert double k2 = 0; // 2. Zwischenwert double k3 = 0; // 3. Zwischenwert double k4 = 0; // 4. Zwischenwert double dy = 0; // Zuwachs in y x[0] = startx; y[0] = starty; for { // k1 k2 k3 k4
(int k=0; k<Schrittzahl-1; k++) Berechnung der Zwischenwerte = h*DGL(x[k], y[k]); = h*DGL(x[k]+h/2, y[k]+k1/2); = h*DGL(x[k]+h/2, y[k]+k2/2); = h*DGL(x[k]+h, y[k]+k3);
// Berechnung des Zuwachses dy = (k1 + 2*k2 + 2*k3 + k4)/6; // Extrapolation des nächsten Punktes x[k+1] = x[k] + h; y[k+1] = y[k] + dy; } } … }
Die Anzahl der Zwischenwerte immer weiter zu erhöhen, um durch eine genauere Mittelung der Ableitung den Restfehler zu verringern, ist also nur bedingt möglich. Außerdem nimmt die Anzahl der notwendigen Funktionsaufrufe von f(x,y) ebenfalls mit jedem Zwischenschritt weiter zu, was mit entsprechend erhöhtem Berechnungsaufwand verbunden ist. Doch es gibt noch einen anderen Weg. Die bisher vorgestellten Verfahren greifen bei der Approximation einer neuen Stützstelle xk+1,yk+1 ausschließlich auf den vorangegangenen Wert xk,yk zurück, d. h. jeder neue Punk bestimmt sich allein aus den Informationen des zurückliegenden Intervalls. Man
236 4 Simulationstechnik
bezeichnet sie daher auch als Einschrittverfahren. Es ist aber auch möglich, die Mittelung von dy/dx über die Einbeziehung weiter zurückliegender Stützpunkte zu verbessern. Speichert man diese zuvor berechneten Stützpunkte in Variablen ab, kann man sie ohne weiteren Aufwand noch für den aktuellen Berechnungsschritt verwenden. Nutzt man zur Approximation mehrere zurückliegende Stützpunkte, spricht man von einem Mehrschrittverfahren. 4.4.5 Das Adams-Bashforth-Verfahren
Zuvor berechnete Funktionswerte in die aktuelle Berechnung mit einzubeziehen scheint ein guter Ansatz zu sein, wirft allerdings die Frage auf, wie ein solches Verfahren überhaupt anlaufen soll, wenn doch zu Beginn noch keine alten Werte vorliegen. Hier leisten Einschrittverfahren als Starthelfer gute Dienste. Ausgehend von den Anfangswerten x0, y0 werden mit ihrer Hilfe so viele Stützpunkte berechnet, bis es genügend alte Werte für das Mehrschrittverfahren gibt, um starten zu können.
xk +1 = xk + h yk +1 = yk +
h ⋅ (3 f ( xk , yk ) − f ( xk −1 , yk −1 )) 2
class Simulation { … public void AdamsBashforth2(double[] x, double[] y, double startx, double starty) { double dydx = 0; // Steigung dy/dx double dglvz0 = 0; // f(x,y) unverzögert double dglvz1 = 0; // 1 Zeitschritt verzögert x[0] = startx; y[0] = starty; // Mit dglvz0 x[1] y[1]
Einschrittverfahren beginnen... = DGL(x[0], y[0]); = x[0] + h; = y[0] + h*dglvz0;
for (int k=1; k<Schrittzahl-1; k++)
(4.28) (4.29)
4.4 Numerische Lösungsmethoden von Differentialgleichungen 237
{ dglvz1 = dglvz0; dglvz0 = DGL(x[k], y[k]); // ...dann Steigung über 2 Stützpunkte dydx = (3*dglvz0 - dglvz1) / 2; // Extrapolation des nächsten Punktes x[k+1] = x[k] + h; y[k+1] = y[k] + h*dydx; } } … }
Natürlich gibt es auch Varianten höherer Ordnung, die entsprechend mehr alte Stützpunkte für die Extrapolation nutzen, z. B. das AdamsBashforth-Verfahren dritter Ordnung.
xk +1 = xk + h yk +1 = yk +
(4.30)
h ⋅ (23 f ( xk , yk ) − 16 f ( xk −1 , yk −1 )+ 5 f ( xk − 2 , yk − 2 )) (4.31) 12
class Simulation { … public void AdamsBashforth3(double[] x, double[] y, double startx, double starty) { double dydx = 0; // Steigung dy/dx double dglvz0 = 0; // f(x,y) unverzögert double dglvz1 = 0; // 1 Zeitschritt verzögert double dglvz2 = 0; // 2 Zeitschritte verzögert x[0] = startx; y[0] = starty; // Mit Einschrittverfahren beginnen... // Anfangswert = 1. Stützstelle dglvz1 = DGL(x[0], y[0]); x[1] = x[0] + h; y[1] = y[0] + h*dglvz1; // 2. Stützstelle
238 4 Simulationstechnik dglvz0 = DGL(x[1], y[1]); x[2] = x[1] + h; y[2] = y[1] + h*dglvz0; for (int k=2; k<Schrittzahl-1; k++) { dglvz2 = dglvz1; dglvz1 = dglvz0; dglvz0 = DGL(x[k], y[k]); // ...dann Steigung über 3 Stützpunkte dydx = (23*dglvz0 - 16*dglvz1 + 5*dglvz2) / 12; // Extrapolation des nächsten Punktes x[k+1] = x[k] + h; y[k+1] = y[k] + h*dydx; } } … }
4.4.6 Die Wahl der Methode
Wie so oft im Leben fällt die Entscheidung schwer, wenn man die Wahl hat. Neben den hier vorgestellten Verfahren gibt es noch weitere Methoden und Varianten, jeweils mit spezifischen Vor- und Nachteilen. Das kein Verfahren für alle Aufgabenstellungen optimal ist, leuchtet unmittelbar ein, dann gäbe es nur dieses eine. Vielmehr verlangt jedes Problem nach einer passenden Lösungsmethode. Mehrschrittverfahren sind vorzugsweise dann zu verwenden, wenn die Berechnung von f(x,y) sehr aufwendig ist. Ist das nicht der Fall, bietet sich das Runge-Kutta-Verfahren an. Für Differentialgleichungen, bei denen die Lösungskurve genügend „glatt“ verläuft (wie bei unserem Einschaltvorgang), kann man aber auch das verbesserte Polygonzug-Verfahren oder Euler-Cauchy einsetzen. Hat man es dagegen mit einer oszillierenden Lösungsfunktion zu tun, läßt sich der methodische Fehler der einfachen Verfahren mit einer sehr kleinen Schrittweite niedrig halten, was aber entsprechend mehr Rechenschritte erfordert und damit zu einem Anstieg des aufsummierten Rundungsfehlers führt. Für einfache Aufgaben spielen Überlegungen dieser Art eine untergeordnete Rolle. Sind ohnehin nur einige hundert oder tausend Stützpunkte zu berechnen, dann fällt der Rechenzeitbedarf kaum ins Gewicht. Abbildung 4.3 zeigt die berechneten Lösungskurven unseres Einschaltstromes für verschiedene Anfangswerte.
4.4 Numerische Lösungsmethoden von Differentialgleichungen 239
y
2
1
0 0
1
2
3
4
5
6
x Abb. 4.3. Lösungsfunktionen von dy/dx = 1–y für verschiedene Anfangswerte
4.4.7 Mehrdimensionale Betrachtungen
Etwas aufwendiger ist da schon die numerische Berechnung von Differentialgleichungen, deren Lösungen mehrdimensionale Funktionen sind. Wie lassen sich das Runge-Kutta-Verfahren oder die anderen Methoden hierfür erweitern? Bei eindimensionalen Lösungsfunktionen die nur von der Zeit abhängen ist alles noch ganz einfach, schließlich kennt die Zeit nur eine Richtung: von der Vergangenheit in die Zukunft. Diese strenge Monotonie kann man bei mehrdimensionalen Lösungen, die z. B. Funktionen der drei Raumkoordinaten sein könnten, nicht mehr voraussetzen. Ein Beispiel aus der numerischen Feldberechnung soll das deutlich machen. Hierfür ist zunächst aber ein kleiner Ausflug in die weite Welt der Elektrostatik notwendig. Feldlinien vermitteln ein anschauliches Bild vom Verlauf eines elektrischen Feldes. Sie folgen seiner Richtung in jedem Punkt des Raumes und markieren damit Bahnen (Kraftlinien), auf denen sich eine Probeladung unter dem alleinigen Einfluß dieses Feldes bewegen würde. Für die elektrische Feldstärke E einer Punktladung Q im Abstand r gilt:
E (r ) =
Q r ⋅ 4πε r 3
(4.32)
240 4 Simulationstechnik
Nimmt man eine beliebige räumliche Anordnung mehrerer Punktladungen Qi an, dann ergibt sich nach dem Superpositionsprinzip die resultierende Feldstärke in jedem Punkt des Raumes p(x,y,z) durch Überlagerung der durch jede einzelne Ladung verursachten Feldstärke.
E ( p) =
Q r Q1 r1 Q r ⋅ 3 + 2 ⋅ 23 + ... + n ⋅ n3 4πε r1 4πε r2 4πε rn
(4.33)
Wir bezeichnen mit ri den Ortsvektor von der Ladung Qi zu unserem Aufpunkt p(x,y,z). Hierbei sind xi, yi und zi die Raumkoordinaten dieser Ladung.
ri3 = ( ( xi − x) 2 + ( yi − y ) 2 + ( zi − z ) 2 )3 Grundsätzlich läßt sich die elektrische Feldstärke in drei unabhängige Raumkomponenten zerlegen.
E ( x, y , z ) = E x ⋅ e x + E y ⋅ e y + E z ⋅ e z
(4.34)
Unter der vereinfachten Annahme, daß alle Ladungen gleich sind, d. h. Qi = Q für alle i, erhalten wir Ex, Ey und Ez entsprechend Gln. (4.33).
Ex =
Q 4πε
§ ( x − x) ( x − x) ( x − x) ( x − x) · ⋅ ¨¨ 1 3 + 2 3 + 3 3 + ... + n 3 ¸¸ r2 r3 rn © r1 ¹
Ey =
Q 4πε
§ ( y − y) ( y − y) ( y3 − y) ( yn − y) · ¸¸ ⋅ ¨¨ 1 3 + 2 3 + + ... + 3 3 r r r r 1 3 2 n © ¹
Ez =
Q 4πε
§ ( z − z) ( z − z) ( z − z) ( z − z) · ⋅ ¨¨ 1 3 + 2 3 + 3 3 + ... + n 3 ¸¸ r2 r3 rn © r1 ¹
Wir sind zwar nun in der Lage die Feldstärke einer beliebigen räumlichen Anordnung von Punktladungen zu bestimmen, für die Berechnung einer (durch diese Feldstärke gebildeten) Kraft- bzw. Feldlinie, die den Einsatz numerischer Methoden erfordert, fehlt aber noch eine feldbeschreibende Differentialgleichung. Diese ergibt sich aus dem Umstand, daß der Feldvektor E immer tangential an einer Feldlinie liegt, wodurch das Kreuzprodukt aus Feldstärke E und dem Wegelement ds der Kraftwirkung des Feldes verschwindet.
E ×ds = 0
(4.35)
4.4 Numerische Lösungsmethoden von Differentialgleichungen 241
ex
ey
ez
Ex dx
Ey dy
Ez = 0 dz
(4.36)
( E y ⋅ dz − E z ⋅ dy ) ⋅ ex − ( Ex ⋅ dz − Ez ⋅ dx) ⋅ e y + ( Ex ⋅ dy − E y ⋅ dx) ⋅ ez = 0 Dies gilt dann auch für jede der drei voneinander unabhängigen Raumkomponenten, woraus unmittelbar die drei systembeschreibenden Differentialgleichungen folgen.
E y ⋅ dz = E z ⋅ dy
E x ⋅ dz = E z ⋅ dx E x ⋅ dy = E y ⋅ dx
dz Ez = dy E y
(4.37)
dz Ez = dx Ex
(4.38)
dy E y = dx Ex
(4.39)
Weil sich jede Gleichung aus den beiden anderen ableiten läßt, bilden (4.37), (4.38) und (4.39) ein System gekoppelter Differentialgleichungen. Gleichwohl sind alle zusammen die Basis für unsere numerische Feldberechnung. Der Algorithmus hierfür ist glücklicherweise relativ einfach. Ausgehend von einem Anfangswert (-punkt) x0, y0, z0 wird die elektrische Feldstärke berechnet. Die größte der drei Raumkomponenten Ex, Ey oder Ez bestimmt dann die Richtung, in die mit der Schrittweite h weitergegangen wird. Der Zuwachs in die beiden anderen Raumrichtungen berechnet sich aus den DGLn. Für jeden Schritt sind somit drei Fälle zu unterscheiden: Ex = Maximum(|Ex|, |Ey|, |Ez|)ĺ dx = h, dy und dz aus DGL Ey = Maximum(|Ex|, |Ey|, |Ez|)ĺ dy = h, dx und dz aus DGL Ez = Maximum(|Ex|, |Ey|, |Ez|) ĺ dz = h, dx und dy aus DGL
242 4 Simulationstechnik
Der Verlauf der Feldlinien ergibt sich eindeutig durch die Anordnung der Punktladungen. Für ihre Definition benötigen wir daher eine Klasse mit entsprechenden Variablen für den Betrag der Ladung, das Vorzeichen (beide zusammen in einer Variablen) und die räumliche Lage. class Ladung { public double public double public double public double
wert; x; y; z;
// Konstruktor public Ladung(double double double double { wert = q; x = xq; y = yq; z = zq; }
q, xq, yq, zq)
}
Weil die Feldlinien eine Schar von Werten im dreidimensionalen Raum bilden, benötigen wir neben der Schrittweite h auch noch Variablen für den Zuwachs in x-, y- und z-Richtung, sowie die räumliche Begrenzung. class Feldlinien { const double PI const int Schrittzahl const int Scharzahl const int Qzahl
= = = =
Math.PI; 100; 24; // Anzahl Feldlinien 4;
// elektrische Feldkonstante const double epsilon = 8.854E-12; // A*s/(V*m) // Quelle des elektrischen Feldes sind die Ladungen Ladung[] Q; // Feldlinien als Schar der Raumkomponenten x, y, z public double[,] x; public double[,] y;
4.4 Numerische Lösungsmethoden von Differentialgleichungen 243
public double[,] z; // Schrittweite public double h; // Zuwachs in Raumrichtung public double deltax; public double deltay; public double deltaz; // räumliche Begrenzung public double xmin; public double xmax; public double ymin; public double ymax; public double zmin; public double zmax; … }
Die Instanziierung unserer Komponenten erfolgt im Konstruktor. Hier werden auch die Punktladungen verteilt. Diese liegen alle in der x-y-Ebene bei z=0, was die grafische Darstellung der Feldlinien ein wenig einfacher macht. Die Festlegung der Anfangswerte erfolgt ebenfalls im Konstruktor (auch wenn das nicht unbedingt sehr anwenderfreundlich ist). class Feldlinien { … // Konstruktor public Feldlinien() { // die elektrischen Ladungen anlegen Q = new Ladung[Qzahl]; // ihre räumliche Anordnung über den Konstruktor // festlegen (alternativ: komponentenweise) Q[0] = new Ladung(1.0, +1.0, +1.0, 0); Q[1] = new Ladung(1.0, -1.0, +1.0, 0); Q[2] = new Ladung(1.0, -1.0, -1.0, 0); Q[3] = new Ladung(1.0, +1.0, -1.0, 0); // die Kennlinien anlegen x = new double[Scharzahl, Schrittzahl]; y = new double[Scharzahl, Schrittzahl]; z = new double[Scharzahl, Schrittzahl];
244 4 Simulationstechnik // Initialisierung h = 0.05; deltax = 0; deltay = 0; deltaz = 0; xmin = -4.0; xmax = +4.0; ymin = -4.0; ymax = +4.0; zmin = 0; zmax = 0; // Anfangswerte festlegen // 1. Quadrant x[0,0] = 1.3; y[0,0] = 0.7; z[0,0] = 0; x[1,0] = 1.3; y[1,0] = 1.0; z[1,0] = 0; x[2,0] = 1.3; y[2,0] = 1.3; z[2,0] = 0; x[3,0] = 1.0; y[3,0] = 1.3; z[3,0] = 0; x[4,0] = 0.7; y[4,0] = 1.3; z[4,0] = 0; x[5,0] = 0.3; y[5,0] = 0.3; z[5,0] = 0; // 2. Quadrant x[6,0] = -0.7; y[6,0] = 1.3; z[6,0] = 0; x[7,0] = -1.0; y[7,0] = 1.3; z[7,0] = 0; x[8,0] = -1.29; y[8,0] = 1.3; z[8,0] = 0; x[9,0] = -4.0; y[9,0] = 1.9; z[9,0] = 0; x[10,0] = -4.0; y[10,0] = 0.6; z[10,0] = 0; x[11,0] = -0.3; y[11,0] = 0.29; z[11,0] = 0; // 3. Quadrant x[12,0] = -4.0; y[12,0] = -0.6; z[12,0] = 0; x[13,0] = -4.0; y[13,0] = -1.9; z[13,0] = 0; x[14,0] = -4.0; y[14,0] = -4.0; z[14,0] = 0; x[15,0] = -1.9; y[15,0] = -4.0; z[15,0] = 0; x[16,0] = -0.6; y[16,0] = -4.0; z[16,0] = 0; x[17,0] = -0.7; y[17,0] = -0.7; z[17,0] = 0; // 4. Quadrant x[18,0] = 0.6; y[18,0] = -4.0; z[18,0] = 0; x[19,0] = 1.9; y[19,0] = -4.0; z[19,0] = 0; x[20,0] = 1.3; y[20,0] = -1.29; z[20,0] = 0; x[21,0] = 1.3; y[21,0] = -1.0; z[21,0] = 0; x[22,0] = 1.3; y[22,0] = -0.6; z[22,0] = 0; x[23,0] = 0.29; y[23,0] = -0.3; z[23,0] = 0; } … }
4.4 Numerische Lösungsmethoden von Differentialgleichungen 245
Weil h immer positiv ist (anders als die aus den DGLn berechneten Zuwächse) und zugleich für die Richtung der größten Feldstärkekomponente benutzt wird, haben die Feldlinien eine räumliche Vorzugsrichtung. Das ist bei der Wahl der Anfangswerte unbedingt zu berücksichtigen. So wächst Ex von –x nach +x, wobei die Zuwächse in y und z beliebig sein können, aber eben nicht von +x nach –x. Entsprechendes gilt auch für die anderen beiden Raumkomponenten. Das hat zur Folge, daß nicht alle berechneten Feldlinien bei den Punktladungen beginnen können, um von dort nach außen zu laufen, sondern einige Linien außen beginnen müssen und an den Ladungen enden, was in der grafischen Darstellung jedoch keinen Unterschied macht (ein Blick auf Abb. 4.4 hilft hier weiter). Hätten wir es dagegen mit drei Gleichungen dx/dt, dy/dt und dz/dt zu tun, dann würde die unabhängige Variable t mit der Schrittweite h wachsen und die drei Lösungen x(t), y(t), z(t) bildeten eine frei bewegliche Raumkurve. Grundlage für das weitere Vorgehen sind zunächst aber die elektrischen Feldstärkekomponenten Ex, Ey, Ez. class Feldlinien { … public double Ex(double x, double y, double z) { double feldx = 0; double dist = 0; // über alle vorhandenen Ladungen Qi for (int i=0; i
246 4 Simulationstechnik double dist
= 0;
// über alle vorhandenen Ladungen Qi for (int i=0; i
Die Implementierung der Differentialgleichungen erfolgt entsprechend den Gleichungen (4.37), (4.38) und (4.39). Auch wenn im nachfolgenden Beispielcode darauf verzichtet wurde, ist vor der Quotientenbildung noch zu prüfen, ob der Divisor ungleich Null ist.
4.4 Numerische Lösungsmethoden von Differentialgleichungen 247
class Feldlinien { … public double DGL1(double x, double y, double z) { double dydx = 0; // Steigung dy/dx dydx = Ey(x,y,z) / Ex(x,y,z); return dydx; } public double DGL2(double x, double y, double z) { double dzdx = 0; // Steigung dz/dx dzdx = Ez(x,y,z) / Ex(x,y,z); return dzdx; } public double DGL3(double x, double y, double z) { double dzdy = 0; // Steigung dz/dy dzdy = Ez(x,y,z) / Ey(x,y,z); return dzdy; } … }
Nachdem das mathematische Modell implementiert ist, können wir uns wieder mehr der Numerik widmen. Gleichung (4.27) zeigt, daß sich das Runge-Kutta-Verfahren bei seiner Approximation auf vier Zwischenwerte stützt. Natürlich gilt das auch im mehrdimensionalen Fall, dann allerdings für jede Dimension. In unserem Beispiel sind die Differentialgleichungen miteinander gekoppelt, d. h. sie lassen sich nicht unabhängig voneinander berechnen. Hier zeigt sich ein wesentlicher Vorteil des Runge-KuttaVerfahrens, welches sich sehr einfach auf solche DifferentialgleichungsSysteme anwenden läßt. Während die größte Feldstärkekomponente mit der Schrittweite h wächst, lassen sich die beiden anderen Zuwächse gleichzeitig numerisch bestimmen, Runge-Kutta macht’s möglich. Wie das funktioniert, zeigt der folgende Beispiel-Code.
248 4 Simulationstechnik class Feldlinien { … public void RungeKuttaYZ(double x, double y, double z) { double j1 = 0; // 1. Stützstelle double j2 = 0; // 2. Stützstelle double j3 = 0; // 3. Stützstelle double j4 = 0; // 4. Stützstelle double k1 = 0; // 1. Stützstelle double k2 = 0; // 2. Stützstelle double k3 = 0; // 3. Stützstelle double k4 = 0; // 4. Stützstelle // // j1 k1 j2 k2 j3 k3 j4 k4
Ex > Ey, Ez -> deltax=h deltax und deltaz aus DGL = h * DGL1(x, y, z); = h * DGL2(x, y, z); = h * DGL1(x+h/2, y+j1/2, z+k1/2); = h * DGL2(x+h/2, y+j1/2, z+k1/2); = h * DGL1(x+h/2, y+j2/2, z+k2/2); = h * DGL2(x+h/2, y+j2/2, z+k2/2); = h * DGL1(x+h, y+j3, z+k3); = h * DGL2(x+h, y+j3, z+k3);
deltay = (j1 + 2*j2 + 2*j3 + j4) / 6.0; deltaz = (k1 + 2*k2 + 2*k3 + k4) / 6.0; } public void RungeKuttaXZ(double x, double y, double z) { double j1 = 0; // 1. Stützstelle double j2 = 0; // 2. Stützstelle double j3 = 0; // 3. Stützstelle double j4 = 0; // 4. Stützstelle double k1 = 0; // 1. Stützstelle double k2 = 0; // 2. Stützstelle double k3 = 0; // 3. Stützstelle double k4 = 0; // 4. Stützstelle // // j1 k1
Ey > Ex, Ez -> deltay=h deltax und deltaz aus DGL = h * (1.0 / DGL1(x, y, z)); // dx/dy = 1/dy/dx = h * DGL3(x, y, z);
4.4 Numerische Lösungsmethoden von Differentialgleichungen 249
j2 k2 j3 k3 j4 k4
= = = = = =
h h h h h h
* * * * * *
(1.0 / DGL1(x+j1/2, y+h/2, z+k1/2)); DGL3(x+j1/2, y+h/2, z+k1/2); (1.0 / DGL1(x+j2/2, y+h/2, z+k2/2)); DGL3(x+j2/2, y+h/2, z+k2/2); (1.0 / DGL1(x+j3, y+h, z+k3)); DGL3(x+j3, y+h, z+k3);
deltax = (j1 + 2*j2 + 2*j3 + j4) / 6.0; deltaz = (k1 + 2*k2 + 2*k3 + k4) / 6.0; } public void RungeKuttaXY(double x, double y, double z) { double j1 = 0; // 1. Stützstelle double j2 = 0; // 2. Stützstelle double j3 = 0; // 3. Stützstelle double j4 = 0; // 4. Stützstelle double k1 = 0; // 1. Stützstelle double k2 = 0; // 2. Stützstelle double k3 = 0; // 3. Stützstelle double k4 = 0; // 4. Stützstelle // // j1 k1 j2 k2 j3 k3 j4 k4
Ez > Ex, Ey -> deltaz=h deltax und deltay aus DGL = h * (1.0 / DGL2(x, y, z)); // dx/dz = 1/dz/dx = h * (1.0 / DGL3(x, y, z)); // dy/dz = 1/dz/dy = h * (1.0 / DGL2(x+j1/2, y+k1/2, z+h/2)); = h * (1.0 / DGL3(x+j1/2, y+k1/2, z+h/2)); = h * (1.0 / DGL2(x+j2/2, y+k2/2, z+h/2)); = h * (1.0 / DGL3(x+j2/2, y+k2/2, z+h/2)); = h * (1.0 / DGL2(x+j3, y+k3, z+h)); = h * (1.0 / DGL3(x+j3, y+k3, z+h));
deltax = (j1 + 2*j2 + 2*j3 + j4) / 6.0; deltay = (k1 + 2*k2 + 2*k3 + k4) / 6.0; } … }
Weil die Bestimmung der elektrischen Feldstärke am Ort einer Ladung zu einem „Division durch Null“-Fehler führt, müssen wir noch verhindern, daß die Feldlinien den Ladungen zu nahe kommen. Wir berechnen daher für jeden Rechenschritt den minimalen Abstand der aktuellen Position von den Punktladungen und nutzen diesen Abstand als Abbruchkriterium.
250 4 Simulationstechnik class Feldlinien { … double MinAbstand(double x, double y, double z) { double abstand = 9.9E99; double temp = 0; // kleinsten Abstand der Feldlinie zu // einer der Ladungen Qi bestimmen for (int k=0; k
Was noch bleibt, ist die Berechnung der Feldlinien selbst. Eine whileSchleife überwacht für jede einzelne Lösungskurve den gültigen Bereich, den Mindestabstand zu den Raumladungen und die Anzahl der Rechenschritte. Die weitere Berechnung wird dann durch die größte Feldstärkekomponente bestimmt. class Feldlinien { … public void Berechne() { double feldx = 0; double feldy = 0; double feldz = 0; int k = 0; // Schrittzahlindex; // über alle Feldlinien for (int linie=0; linie<Scharzahl; linie++) { k = 0;
4.4 Numerische Lösungsmethoden von Differentialgleichungen 251
// Berechnung einer Feldlinie while (x[linie,k]>=xmin && x[linie,k]<=xmax && y[linie,k]>=ymin && y[linie,k]<=ymax && z[linie,k]>=zmin && z[linie,k]<=zmax && MinAbstand(x[linie,k], y[linie,k], z[linie,k])>2*h && k<(Schrittzahl-1) ) { feldx = Ex(x[linie,k], y[linie,k], z[linie,k]); feldy = Ey(x[linie,k], y[linie,k], z[linie,k]); feldz = Ez(x[linie,k], y[linie,k], z[linie,k]); if (Math.Abs(feldx) >= Math.Abs(feldy) && Math.Abs(feldx) >= Math.Abs(feldz) ) { RungeKuttaYZ(x[linie,k],y[linie,k],z[linie,k]); x[linie,k+1] = x[linie,k] + h; y[linie,k+1] = y[linie,k] + deltay; z[linie,k+1] = z[linie,k] + deltaz; } if (Math.Abs(feldy) >= Math.Abs(feldx) && Math.Abs(feldy) >= Math.Abs(feldz) ) { RungeKuttaXZ(x[linie,k],y[linie,k],z[linie,k]); x[linie,k+1] = x[linie,k] + deltax; y[linie,k+1] = y[linie,k] + h; z[linie,k+1] = z[linie,k] + deltaz; } if (Math.Abs(feldz) >= Math.Abs(feldx) && Math.Abs(feldz) >= Math.Abs(feldy) ) { RungeKuttaXY(x[linie,k],y[linie,k],z[linie,k]); x[linie,k+1] = x[linie,k] + deltax; y[linie,k+1] = y[linie,k] + deltay; z[linie,k+1] = z[linie,k] + h; } k++; } } } … }
252 4 Simulationstechnik 4 3 2
y
1 0 -1 -2 -3 -4 -4
-3
-2
-1
0
1
2
3
4
x
Abb. 4.4. 2d-Feldlinienbild einer Anordnung von 4 Ladungen Q1 = Q2 = Q3 = Q4
4.4.8 Schrittweitensteuerung
Eine kleine Schrittweite h minimiert zwar den verfahrensbedingten Fehler, erhöht aber zwangsläufig auch die Anzahl der notwendigen Berechnungsschritte, was nicht nur zu einer längeren Rechendauer führt, sondern auch die Summe der Rundungsfehler erhöht. Was zunächst nach unvereinbaren Gegensätzen ausschaut, läßt sich durch eine Schrittweitensteuerung leicht auflösen. Ändert sich die Lösungskurve in einem Bereich sehr stark, dann wählt man eine kleine Schrittweite, für Bereiche mit wenig Veränderung genügt dagegen eine große Schrittweite. Anstatt mit einer konstanten Schrittweite zu arbeiten, paßt sich ein solches Verfahren den jeweiligen Erfordernissen selbständig an, wodurch es gelingt, gleichzeitig schnell und genau zu rechnen. Grundsätzlich kann die Steuerung der Schrittweite auf sehr unterschiedliche Weise realisiert werden. Allen Methoden gemeinsam ist der Ansatz, den Fehler des aktuellen Simulationsschrittes zu schätzen und daraus eine Vergrößerung, Verkleinerung oder ggf. Beibehaltung der Schrittweite abzuleiten. Die Schätzung des Fehlers bedeutet zunächst aber immer zusätzlichen Berechnungsaufwand, der nicht zu vernachlässigen ist. Ein einfacher Ansatz besteht darin, ein zweites Lösungsverfahren mitrechnen zu lassen und die Ergebnisse beider Verfahren laufend zu vergleichen, z. B. Runge-Kutta zur Extrapolation und Euler-Cauchy als Schätzer. Ist die Differenz beider Verfahren kleiner als eine selbst gewählte untere Schranke, dann kann man die Schrittweite vergrößern (z. B. verdoppeln),
4.4 Numerische Lösungsmethoden von Differentialgleichungen 253
ist sie dagegen größer als eine obere Schranke, muß man die Schrittweite verkleinern (z. B. halbieren), zwischen den Schranken bleibt h konstant. Allerdings ist es ratsam die Schrittweite nach oben und nach unten zu begrenzen, damit sich das Verfahren nicht totläuft. Anstatt zwei unterschiedliche Verfahren mit der selben Schrittweite zu vergleichen, kann man auch ein Verfahren mit zwei unterschiedlichen Schrittweiten (z. B. h/2 und h) für die Steuerung verwenden. Hierbei wird die in zwei Halbschritten berechnete Schätzung mit der weniger genauen Approximation verglichen. Genau wie zuvor, bestimmt deren Differenz den Wert von h für den nächsten Berechnungsschritt. 4.4.9 Differentialgleichungen höherer Ordnung
Was passiert eigentlich, wenn wir in den Schaltkreis von Abb. 4.2, parallel zu Spule und Widerstand, zusätzlich einen Kondensator einbauen? Ebenso wie im ersten Beispiel, wird zum Zeitpunkt t = 0 durch Schließen des Schalters das neue System mit der Spannung U0 beaufschlagt. t=0
R U0
C L
Abb. 4.5. Einschaltvorgang einer Parallelschaltung aus Kondensator und Spule
In der vorliegenden Parallelschaltung, bestehend aus Kondensator und Spule, führt der Energieaustausch zwischen beiden Komponenten zu einem schwingungsfähigen System. Die Systemgleichung ergibt sich durch Anwendung der Maschenregel.
UC +U L +U R = 0
(4.40)
di 1 ⋅ ³ idt + L ⋅ + R ⋅ i = 0 C dt
(4.41)
254 4 Simulationstechnik
Das Ergebnis ist eine Integral-Differentialgleichung. Wir leiten diese Gleichung nach der Zeit ab und erhalten eine DGL zweiter Ordnung. Die Terme werden entsprechend ihrer Ordnung sortiert, zusätzlich normieren wir noch mit 1/L.
d 2 i R di 1 + ⋅ + ⋅i = 0 2 L dt L ⋅ C dt
(4.42)
Wie man sieht, läßt sich ein System mit zwei Energiespeichern durch eine Differentialgleichung zweiter Ordnung modellieren. Natürlich können in der Praxis auch Systeme höherer Ordnung auftreten. Allerdings lösen die bisher gezeigten numerischen Verfahren nur Gleichungen erster Ordnung, was ein ziemliches Problem wäre, wenn es nicht die Möglichkeit der Ordnungsreduktion gäbe. Zu diesem Zweck führen wir zwei zusätzliche Variablen u und v ein.
u=i v=
di dt
Wir ersetzen die Terme in Gln. (4.42) durch die neuen Variablen und erhalten zwei Differentialgleichungen.
dv R 1 + ⋅v + ⋅u = 0 dt L L⋅C
(4.43)
du =v dt
(4.44)
Die Substitution hat aus der ursprünglichen DGL zweiter Ordnung zwei DGLn erster Ordnung gemacht. Für Gleichungen höherer Ordnung kann man entsprechend verfahren, d. h. jede Differentialgleichung n-ter Ordnung läßt sich in ein System von n gekoppelten Differentialgleichungen erster Ordnung umformen. Deren Lösung ist dann mit den bekannten Methoden kein Problem.
4.5 Monte-Carlo-Methoden Als Monte-Carlo-Methode bezeichnet man eine Simulationstechnik, bei der mathematische oder physikalische Prozesse durch Zufallsexperimente nachgebildet werden. Viele Anwendungen lassen sich jedoch erst durch eine geschickte Formulierung als Zufallsexperiment modellieren. Genau
4.5 Monte-Carlo-Methoden 255
diese künstliche Randomisierung ist es, die das Wesen der Monte-CarloMethode ausmacht. Sie ermöglicht damit die Simulation von Prozessen, die ursprünglich nicht der Wahrscheinlichkeitstheorie entstammen. Die Idee, Berechnungsmodelle auf der Basis von Zufallszahlen zu entwickeln, ist nicht neu. Ansätze hierzu hat es bereits im 18.Jahrhundert gegeben. Aber erst in den 40er Jahren des vergangenen Jahrhunderts wurden die theoretischen Grundlagen systematisch ausgearbeitet. Stanislaw Ulam, Nicholas Metropolis und John von Neumann waren zu dieser Zeit in Los Alamos an der Entwicklung der Atombombe beteiligt, wo sie die MonteCarlo-Methode zur Berechnung komplizierter Integrale nutzten. Die Berechnung der Kreiszahl ʌ ist wohl das bekannteste Beispiel für die Lösung von Integralen mit Hilfe der Monte-Carlo-Methode. Zwei gleichverteilte Zufallszahlen z1 und z2 bilden Punkte P(x,y) in dem quadratischen Bereich [−1..1), dessen Fläche gerade 4 beträgt. Die Fläche des innen liegenden Einheitskreises beträgt ʌ·r2 = ʌ (wegen r = 1). Werden nun sehr viele Zufallswerte (-punkte) erzeugt, dann nähert sich das Verhältnis von Kreistreffern zur Gesamtzahl N der erzeugten Punkte immer mehr dem Wert
Kreisfläche π = Quadratfläche 4 Hieraus ergibt sich die gesuchte Kreiszahl ʌ (oder zumindest eine mehr oder weniger gute Näherung). Weil die Qualität des Ergebnisses mit der Anzahl der verwendeten Zufallswerte wächst, wollen wir kurz abschätzen, wie groß N mindestens sein muß, um ʌ auf zwei Nachkommastellen genau zu bestimmen. Aus 3,14:4 = 0,785 folgt N1000, d. h. frühestens nach 1000 Zufallspunkten wird die angestrebte Genauigkeit erreicht. Allerdings nur, wenn sich die Punkte im Verhältnis 785:1000 auf der Fläche verteilen. Ob uns gleich die ersten 1000 Punkte diesen Gefallen tun, darauf haben wir aber keinen Einfluß, weshalb es in der Praxis wohl erheblich länger dauern wird, bis sich das gewünschte Verhältnis einstellt. class MonteCarlo { public Zufall Rauschen; public double z1; public double z2; // Konstruktor public MonteCarlo() { Rauschen = new Zufall(0.71036, 0.23906);
256 4 Simulationstechnik z1 = 0; z2 = 0; } public double BerechnePI(long anzahl) { long imkreis = 0; for { // z1 z2
(long k=0; k [-1, 1) = 2.0*Rauschen.Gleich1() - 1; = 2.0*Rauschen.Gleich2() - 1;
if (Math.Sqrt(z1*z1 + z2*z2) <= 1.0) { imkreis++; } } return 4.0*((double)imkreis)/((double)anzahl); } } Tabelle 4.1. Annäherung an die Kreiszahl ʌ mit wachsendem N N
10 100 1000 10000 100000 1000000 10000000 100000000 1000000000 10000000000 100000000000
ʌ
2,8 3,32 3,240 3,1888 3,14772 3,143468 3,1428352 3,14175664 3,141539646 3,1415654768 3,14159979556
|İ| in % 10,8 5,67 3,13 1,50 0,195 0,0596 0,0395 0,00521 0,00168 0,000865 0,000227
Wie bereits vermutet, läßt sich das Ergebnis allein durch den Einsatz von mehr Rechenleistung verbessern. Die Monte-Carlo-Methode gehört damit zu den Brute-Force-Algorithmen, bei denen die erhöhte Genauigkeit einfach durch „Brachialgewalt“ erzwungen wird, ohne jede Verfeinerung
4.5 Monte-Carlo-Methoden 257
der Methodik selbst. Für den relativen Fehler İ der Monte-Carlo-Methode gilt dabei:
1
ε~
(4.45)
N
Die simulierten Werte aus Tabelle 4.1 stehen in guter Übereinstimmung mit Gln. (4.45), was auch ein Beleg für die Qualität des verwendeten Zufallsgenerators ist. 12
rel. Fehler in %
10 8 6 4 2 0 1,0E+01
1,0E+03
1,0E+05
1,0E+07
1,0E+09
N
Abb. 4.6. Abnahme des relativen Fehlers İ mit wachsendem N
5 Netzwerke
5.1 Einführung Der Austausch von Informationen gehört zu den Grundbedürfnissen des Menschen. Im direkten Miteinander benutzen wir üblicherweise unsere natürliche Sprache zur Kommunikation, sind aber größere Entfernungen zu überwinden, dann benötigen wir Boten oder technische Hilfsmittel zur Nachrichtenübertragung. Bereits in der Antike hat man daher angefangen ausgedehnte Kommunikationssysteme zu entwickeln und aufzubauen. Ausgehend von Rauch- und Feuerzeichen hat man frühzeitig begonnen, die Verfügbarkeit, Zuverlässigkeit und Übertragungsgeschwindigkeit der Informationskanäle stetig zu verbessern. An diesem Grundsatz hat sich bis heute nichts geändert.
5.2 Historische Entwicklung Im September 490 v. Chr. stellten sich die griechischen Streitkräfte unter ihrem Feldherrn Miltiades in der Ebene bei Marathon dem zahlenmäßig überlegenen Heer der Perser. Trotz ihrer Unterzahl gewannen die Griechen die Schlacht und man schickte einen Boten ins etwa 40 Kilometer entfernte Athen, um die frohe Botschaft vom Sieg zu verkünden. Ein Läufer namens Pheidippides machte sich auf den Weg. Ausgelaugt von der Strecke und der Hitze kam dieser schließlich völlig erschöpft in Athen an, wo er noch „Nenikekamen“ (Wir haben gesiegt) rief und verstarb. Während die Schlacht selbst eine unbestrittene historische Tatsache ist, gehört die Geschichte vom armen Pheidippides wahrscheinlich ins Reich der Legenden. Aber, in jeder Legende steckt auch ein Körnchen Wahrheit, denn tatsächlich verfügte man in den Staaten der Antike über ein gut ausgebautes Netz von Boten und Kurieren. Unwegsames Gelände, die Notwendigkeit Flüsse überqueren oder regelmäßig Pferde bzw. Läufer wechseln zu müssen und nicht zuletzt deren begrenzte Geschwindigkeit führten dann aber zum Ausbau der optischen Nachrichtenübertragung. So wurden besonders wichtige Orte durch eine Reihe von in Sichtweite errichteten Stationen
260 5 Netzwerke
(z. B. Fackeltürme) miteinander verbunden. An diesem Prinzip hat man bis in die Neuzeit hinein festgehalten. Der französische Ingenieur Claude Chappe de Vert (1763−1805) entwickelte einen optischen Telegraphen, der sich wegen seiner vielfältigen Signalstellungen auch zur Übermittlung komplexer Nachrichten eignete. Insgesamt konnte er 196 verschiedene Zeichen darstellen. Mit diesem Zeichenvorrat ließ sich nicht nur das ganze Alphabet, sondern zusätzlich auch eine Reihe von Wörtern und Sätzen fest kodieren. 1794 wurde die etwa 212 Kilometer lange Strecke von Paris nach Lille mit 23 Zwischenstationen in Betrieb genommen. Die Übermittlung eines Zeichens über die gesamte Strecke dauerte nur noch wenige Minuten, eine längere Botschaft etwa eine Stunde (zum Vergleich: Ein berittener Kurier hätte dagegen etwa 24 Stunden gebraucht). Ein offensichtlicher Nachteil der optischen Telegraphie ist der Umstand, daß Dunkelheit, Nebel oder Schneetreiben eine Übertragung praktisch verhindern. Mit der Entdeckung der Elektrizität wurden deren Möglichkeiten für die Nachrichtentechnik schnell erkannt. Bereits im 18. Jahrhundert gab es eine Reihe von Versuchen auf diesem Gebiet. Anfänglich stellten aber der hohe Spannungsabfall entlang der Leitungen, deren schlechte Isolierung und die hohe Störanfälligkeit der Apparaturen kaum zu überwindende Hindernisse dar. Ein weiteres Problem war die Signalisierung selbst, d. h. die Anzeige des Wechsels zwischen „Signal“ und „kein Signal“. Es gab sogar ernsthafte Vorschläge, hierfür unter Stromeinfluß zuckende Froschschenkel zu verwenden, eine Erkenntnis, die auf den italienischen Arzt Luigi Galvani (1737−1798) zurückzuführen ist. Eine praktikable Lösung dieses Problems war da schon der Nadeltelegraph von Carl-Friedrich Gauß (1777−1855) und Wilhelm Weber (1804−1891) aus dem Jahr 1833, der das physikalische Institut der Universität Göttingen mit der Sternwarte verband. Eigens zu diesem Zweck wurde eine doppelte Drahtleitung über die Häuser der Stadt geführt. Die Anzeigeeinheit war eine durch Spulen abgelenkte Magnetnadel. Als entscheidender Durchbruch in der elektrischen Telegraphie müssen aber wohl die Entwicklungen des amerikanischen Erfinders Samuel Finley Breese Morse (1791−1872) gesehen werden, der mit seinem elektromagnetischen Taster nicht nur die gerätetechnische Ausführung entscheidend verbesserte, sondern auch eine an den Informationskanal angepaßte Signalkodierung (Morse-Alphabet) einführte. Im Mai 1844 wurde die 60 Kilometer lange Leitung von Baltimore nach Washington D.C. in Betrieb genommen. Das von Morse geschaffene System setzte sich schnell durch und bildete den ersten internationalen Standard. In der zweiten Hälfte des 19. Jahrhunderts stand daher der Ausbau der Telegraphennetze im Vordergrund. 1858 wurde das erste transatlantische Kabel verlegt, um die neue Welt mit Europa zu verbinden. Allerdings versagte es
5.2 Historische Entwicklung 261
seinen Dienst bereits nach wenigen Wochen, wohl aufgrund von Isolationsproblemen. 1876 leitete Alexander Graham Bell (1847−1922) mit seiner Patentanmeldung eines Fernsprechapparates das Zeitalter der Individualkommunikation ein. Damit war erstmals (sieht man einmal von Telegrammdiensten ab) Fernkommunikation für jedermann möglich und nicht mehr vorrangig ein Privileg der Militärs, staatlichen Institutionen und Börsen. Etwa zeitgleich entwickelte sich die Fernschreibtechnik, bei der die Nachricht in lesbarer Schrift auf der Empfangsseite ausgegeben wurde. Von grundlegender Bedeutung für die Kommunikationstechnik aber waren (und sind es bis heute) die Arbeiten des schottischen Physikers James Clerk Maxwell (1831−1879), der 1864 bzw. 1873 in seinem Werk „A Treatise on Electricity and Magnetism“ mit vier Gleichungen die Theorie der elektromagnetischen Wellen begründete. Leider war es ihm nicht vergönnt, den experimentellen Nachweis dieser Wellen durch den Physiker Heinrich Hertz (1857−1894) im Jahre 1884 noch mitzuerleben. Hertz war jedoch viel zu sehr Theoretiker, um sich für eine praktische Anwendung dieser Technologie zu interessieren. Ganz anders der italienische Ingenieur Guglielmo Marconi (1874−1937), der schon frühzeitig begonnen hat, sich mit drahtloser Telegraphie zu beschäftigen und deren Weiterentwicklung konsequent vorantrieb. Am 12. Dezember 1901 gelang ihm mit der ersten transatlantischen Funkübertragung das bis dahin Unvorstellbare. Seine Nachricht „• • •“ (Morse-Code für „S“, wie „success“) überwand die 3520 Kilometer von der Südwestspitze Englands bis nach St. John’s in Neufundland mit Lichtgeschwindigkeit. Mit der Funktechnik rückte die Welt ein Stück enger zusammen, Entfernungen waren nun kein Hindernis mehr. In den folgenden vier Jahrzehnten entwickelte sich die Rundfunktechnik, die aktuelle Informationen in den letzten Winkel der Erde trug. Mit dem Aufkommen der digitalen Rechentechnik, etwa in den 50er Jahren des vergangenen Jahrhunderts, wuchs auch schnell die Einsicht, daß der Datenaustausch über den Transport physikalischer Datenträger (Lochkarten bzw. Magnetbänder) sehr mühsam und zeitraubend ist. Es war die Zeit des Kalten Krieges zwischen den USA und der UdSSR, als das USVerteidigungsministerium 1958 die Advanced Research Projects Agency (ARPA) ins Leben rief, eine wissenschaftliche Forschungseinrichtung mit dem Auftrag, die Landesverteidigung durch die Förderung innovativer Technologien zu unterstützen. Ein Projekt (von vielen anderen) war die Entwicklung eines dezentralen Computernetzes, das durch seine redundanten Verbindungen auch nach einem nuklearen Angriff funktionsfähig bleiben sollte. Wirklich neu war allerdings die Idee, die Daten für die Übertragung in diesem Netz in kleine Datenpakete zu zerlegen. Jedes der Pakete sollte mit der Zieladresse versehen von allen Rechnern entgegengenommen
262 5 Netzwerke
bzw. weitergeleitet werden können. Je nach Auslastung der einzelnen Verbindungsleitungen, wäre es den einzelnen Paketen möglich unterschiedliche Wege zum Ziel zu nehmen. An ihrem Bestimmungsort angekommen würden sie dann wieder entsprechend zusammengesetzt. Die Vernetzung der im Land verstreuten ARPA-eignen Rechenzentren auf der Basis dieser neuen Pakettechnik wurde 1966 beschlossen und 1969 umgesetzt. Die Entstehung des ARPA-Netzes kann man auch als Geburtsstunde des Internets betrachten. Innerhalb weniger Jahre schlossen sich mehr und mehr Universitäten und andere Forschungseinrichtungen an. Die Notwendigkeit verschiedene Hardwareplattformen mit unterschiedlichen Betriebssystemen in einem gemeinsamen Netz zu integrieren, führte etwa Mitte der 70er Jahre zur Entwicklung des einheitlichen Übertragungsstandards TCP/IP. Bereits zu dieser Zeit nutzte das ARPA-Netz Teile des öffentlichen Kommunikationsnetzes (Telefonleitungen, Satellitenverbindungen). In Europa verlief die Entwicklung etwas zeitverzögert. Zudem baute man hier zunächst auf einen eigenen Standard (X.25), der sich aber nicht durchsetzen konnte. Mit der Übernahme des TCP/IP-Protokolls stand aber der Verbindung des europäischen Verbundnetzes mit dem ARPA-Netz nichts mehr im Wege. Gegen Ende der 80er Jahre hat sich der Name „Internet“ etabliert, das also in Wirklichkeit ein Zusammenschluß vieler kleiner, organisatorisch selbständiger Computernetze ist. Mit dem Aufkommen der Internettelefonie (VoiceOverIP) verschwimmt die Trennung der Begriffe Kommunikationsnetz, Computernetzwerk und Internet vollends.
5.3 Physikalische Grundlagen Ganz egal wie ein Kommunikationsnetz aufgebaut ist, die Übertragung von Signalen unterliegt immer den Gesetzen der Physik. Dabei spielt es zunächst auch keine Rolle, ob es sich um analoge oder digitale Signale handelt. Die Weitergabe von Informationen über große Entfernungen erfolgt mit Hilfe elektromagnetischer Wellen. Diese haben, anders als Schwingungen, eine zeitliche und eine räumliche Ausdehnung. Mit der sich fortpflanzenden Welle geht immer auch ein Energietransport einher. Zwischen der Wellenlänge Ȝ, der Frequenz f und der Lichtgeschwindigkeit c besteht ein unmittelbarer Zusammenhang.
c =λ⋅ f
(5.1)
Der Frequenzbereich elektromagnetischer Wellen reicht von einigen Hertz bis zu 1024 Hz. Die Signalübertragung mit ihnen kann leitungsgebunden, drahtlos oder optisch erfolgen.
5.3 Physikalische Grundlagen 263
5.3.1 Leitungsgebundene Signalübertragung
Bei der Signalübertragung spielen Leitungen (Koaxialkabel, Twisted-Pair) eine wichtige Rolle. Diese sind in der Regel als Doppelleitungen ausgeführt. Ist die Signalfrequenz entsprechend hoch (> 100MHz), dann wird die Geometrie und Beschaffenheit der Leitung zur bestimmenden Größe. Um die Übertragungseigenschaften einer Leitung zu beschreiben, stellt man sich diese aus vielen differentiellen Leitungselementen zusammengesetzt vor. Jedes dieser Leitungselemente wird über seinen Widerstandsbelag R‘ = R/dx, seinen Induktivitätsbelag L‘ = L/dx, seinen Kapazitätsbelag C‘ = C/dx und seinen Ableitungsbelag G‘ = G/dx definiert. R’
L’
C’
G’
Abb. 5.1. Ersatzschaltung eines Leitungselementes der Länge dx
Am Eingang eines solchen Leitungselementes liegt die Spannung u(t, x) an, an seinem Ausgang u(t, x + dx). Entsprechend fließt ein Eingangsstrom i(t, x) und ein Ausgangsstrom i(t, x + dx). Für die Ausgangsgrößen gilt:
u (t , x + dx) = u (t , x) + i (t , x + dx) = i (t , x) +
∂u ⋅ dx ∂x
∂i ⋅ dx ∂x
(5.2) (5.3)
Entlang des Leitungselementes dx ergibt sich ein Spannungsabfall aufgrund des Widerstandsbelages und des Induktivitätsbelages.
∂u ∂i = − R′ ⋅ i − L′ ⋅ ∂x ∂t
(5.4)
Der Kapazitätsbelag und der Ableitungsbelag verursachen dagegen eine Stromänderung (Verschiebungsstrom) entlang dx.
∂i ∂u = −G′ ⋅ u − C ′ ⋅ ∂x ∂t
(5.5)
264 5 Netzwerke
Wir erhalten zwei Differentialgleichungen, welche die zeitliche und räumliche Änderung von Strom und Spannung miteinander verknüpfen. Differenziert man beide Gleichungen nach x und ersetzt noch u/x mit Gln. (5.4) und i/x mit Gln. (5.5), führt das auf zwei partielle Differentialgleichungen zweiter Ordnung, die jetzt aber nur noch jeweils eine Veränderliche enthalten.
∂ 2u ∂ 2u ∂u ′ ′ = L C ⋅ 2 + (C ′R′ + L′G′) ⋅ + G′R′ ⋅ u 2 ∂x ∂t ∂t
(5.6)
∂ 2i ∂ 2i ∂i ′ ′ = ⋅ L C + (C ′R′ + L′G′) ⋅ + G′R′ ⋅ i 2 2 ∂x ∂t ∂t
(5.7)
Die Gleichungen (5.6) und (5.7) sind als Telegraphengleichungen bekannt. Für die Praxis relevant sind ihre periodischen Lösungen.
u (t , x) = U 0 ⋅ e jωt −γx
(5.8)
i (t , x) = I 0 ⋅ e jωt −γx
(5.9)
Man bezeichnet Ȗ als Fortpflanzungsfaktor, Z ist die Wellenimpedanz der verlustbehafteten Leitung. Für eine verlustfreie Leitung ist R‘ = G‘ = 0, der Wellenwiderstand Z dann real.
γ = ( R ′ + jωL ′) ⋅ (G ′ + jωC ′) Z=
R ′ + jω L ′ G ′ + jωC ′
(5.10) (5.11)
Strom und Spannung an jedem Punkt x der Leitung ergeben sich durch Überlagerung der hinlaufenden Welle und der durch Reflexion am Leitungsende entstehenden rücklaufenden Welle (ggf. wird diese erneut am Leitungsanfang reflektiert, usw.). 5.3.2 Drahtlose Signalübertragung
Betrachten wir es einmal genau, ob beim Datenaustausch zwischen Handy und PC, mit dem Notebook per WLAN ins Internet oder eine interkontinentale Datenübertragung via Satellit, die drahtlose Kommunikation hat in den vergangenen Jahren erheblich an Bedeutung gewonnen. Den verschiedenen Anwendungen entsprechend lassen sich dabei ganz unterschiedliche Entfernungen (von ca. 1 m bis > 1000 km) überbrücken. Das zugrundeliegende Prinzip ist simpel, das Nutzsignal wird vom Signalgenerator über eine
5.3 Physikalische Grundlagen 265
AC
C
Abb. 5.2. Wechselstromkreis mit Kondensator C
Leitung an die Antenne weitergeführt und dort in den freien Raum abgestrahlt. Tatsächlich ist das fast so einfach, wie es hier klingt. Der Umstand, daß eine Antenne eigentlich nichts weiter ist, als ein Stück offener Leitung, führt oft zu Verständnisproblemen, denn haben wir nicht alle einmal gelernt, daß ein Stromkreis geschlossen sein muß? Nun, das stimmt auch, allerdings nur solange man als Spannungsquelle eine Gleichspannung (z. B. Batterie) verwendet. Liegt dagegen eine Wechselspannung an, sieht das aber schon anders aus. Ein solcher Wechselstromkreis nutzt die kapazitive Wirkung der Leitungsanordnung bzw. spezieller Bauelemente (Kondensator), um durch die Ausbildung eines elektromagnetischen Feldes auch isolierte Wegstrecken (z. B. Luft) zu überwinden. Abbildung 5.2 verdeutlicht das Prinzip. Die Funktion einer Sendeantenne läßt sich sehr anschaulich durch das Aufbiegen einer Zweidrahtleitung erläutern. Hierfür sei eine solche Leitung an eine Signalquelle (Sender) angeschlossen. Da die beiden Drähte der Leitung wie ein Kondensator kapazitiv wirken, bildet sich zwischen ihnen ein pulsierendes elektrisches Feld. Biegt man die Leitungsenden ein Stück weit auseinander, dann verlängern sich die Feldlinien zwar, aber sie können sich zunächst nicht von der Leitung lösen. Werden die Drähte noch weiter aufgebogen, dann erreichen die senkrecht auf dem Leiter stehenden Feldlinien schließlich eine Länge, die eine Ablösung des Feldes erlaubt. Eine Freiraumwelle ist entstanden. Man bezeichnet Antennen daher auch als Wellentypwandler, da sie Leitungswellen in Freiraumwellen umwandeln. Die sich ausbreitende Welle hat eine elektrische Komponente E, deren Ursache die Spannung u(t) ist, und eine magnetische Komponente H, die aus dem Strom i(t) resultiert. Für die Funktechnik besonders interessant ist der Teil des Feldes, der in großer Entfernung von der Antenne wirkt. Man bezeichnet diesen Bereich (r >> Ȝ) als Fernfeld. Hier erscheint die Antenne nur noch als Punktstrahler, womit die von ihr ausgehende Wellenfront als ebene Welle betrachtet werden kann. In diesem Bereich stehen elektrische Feldstärke E und magnetischen Feldstärke H senkrecht aufeinander, senkrecht zur Ausbreitungsrichtung
266 5 Netzwerke
Sender
Sender
Sender
Abb. 5.3. Grundprinzip einer Sendeantenne
und sind zeitlich in Phase. Der Quotient aus beiden Größen bildet den Feldwellenwiderstand ZF0 des freien Raumes.
ZF0
G E = G = 120π Ω H
(5.12)
Hierbei handelt es sich um eine konstante Größe. Damit die Abstrahlung der elektromagnetischen Welle ohne Reflexion erfolgen kann, muß die Antenne den Leitungswellenwiderstand der Zuleitung an den Feldwellenwiderstand des freien Raumes anpassen. Man erreicht das über die Form und Größe der Sendeantenne. Das Prinzip der Antenne läßt sich umkehren, weshalb jede Sendeantenne auch für den Empfang geeignet ist (Reziprozitätsprinzip). 5.3.3 Optische Signalübertragung
Für Netzwerkleitungen werden auch häufig Lichtwellenleiter verwendet. Hierfür ist das elektrische Signal über spezielle LEDs oder Laserdioden als
5.3 Physikalische Grundlagen 267
Licht in ein Glasfaserkabel einzuspeisen, wo es durch Totalreflexion weitergeleitet wird. Der Vorteil von Lichtwellenleitern (LWL) liegt in ihrer sehr hohen Übertragungskapazität. Zudem ist diese Form der Signalübertragung fast unempfindlich gegenüber elektromagnetischen Störungen, weshalb sich der Einsatz besonders in einem entsprechend belasteten Umfeld (z. B. einer Maschinenhalle) lohnt. Glasfaserkabel haben einen Kern aus Glas (dem eigentlichen Leiter), der von einer weiteren Glasschicht umgeben ist. Aufgrund unterschiedlicher optischer Eigenschaften beider Gläser kommt es an deren Grenzschicht zur Reflexion. Reflexionen treten immer dann auf, wenn elektromagnetische Wellen auf ein anderes Medium treffen. Was schon bei Leitungen und Antennen galt, behält somit auch beim Lichtwellenleiter seine Gültigkeit. Dabei hängt der Reflexionsgrad vom Einfallswinkel des Lichtes und von der Verschiedenheit beider optischer Medien (Kern und Mantel) ab. Die hierfür bestimmende Größe ist der Brechungsindex n, manchmal auch Brechzahl genannt. Er kennzeichnet das Verhältnis der Lichtgeschwindigkeit im Vakuum c0 zur Ausbreitungsgeschwindigkeit c des Lichtes im jeweils betrachteten Medium.
n=
c0 c
(5.13)
In einem optisch dichten Medium breitet sich Licht langsamer aus, als in einem optisch dünnen Medium. Genau diese unterschiedlichen Lichtgeschwindigkeiten bzw. Brechzahlen sind verantwortlich für die Reflexion des Lichtes an der Grenzschicht. Bei einem Lichtwellenleiter ist der Mantel das optisch dünnere Medium (hat die kleinere Brechzahl n1) und der Kern das optisch dichtere Medium (hat die größere Brechzahl n2). Speist man am Eingang Licht ein, dann bewegt es sich nicht nur entlang der optischen Achse, sondern versucht, sich nach allen Seiten auszubreiten. Die Lichtstrahlen fallen daher in unterschiedlichen Winkeln in die Faser ein und werden auf ihrem Weg entsprechend unterschiedlich oft reflektiert. Dies führt dazu, daß Lichtstrahlen des selben Signalimpulses verschieden
n1
n2
n1
Abb. 5.4. Lichtwellenleiter mit Stufenprofil
268 5 Netzwerke
lange Wege zurücklegen, was am Ausgang schließlich zu einer Aufweitung des Pulses führt. Ein unerwünschter Effekt, der die mögliche Übertragungsrate deutlich beschränkt. Abhilfe schafft ein Kern mit Gradientenprofil, bei dem die optische Dichte nach außen hin stetig abnimmt, d. h. die Brechzahl n2 = f(r) wird in radialer Richtung kleiner. Die stetige Änderung von n2 = f(r) erzwingt auch eine stetige Reflexion der Lichtstrahlen. Diejenigen Strahlen, die schräg einstreuen, legen zwar immer noch einen insgesamt längeren Weg in der Faser zurück, weil sie sich aber dabei in optisch dünneren Bereichen bewegen und dort entsprechend schneller vorankommen, kompensiert der resultierende Geschwindigkeitsvorteil den Wegnachteil. n1
n2(r)
n1
Abb. 5.5. Lichtwellenleiter mit Gradientenprofil
Die laufzeitbedingte Aufweitung von Signalimpulsen läßt sich aber auch mit einer Stufenfaser vermeiden. Wie in Abb. 5.4 dargestellt, werden die einzelnen Lichtstrahlen, je nach Einstreuwinkel, unterschiedlich oft an der Grenzschicht reflektiert. Häufig reflektierte Strahlen bezeichnet man als Licht hohen Modes, selten reflektierte Strahlen nennt man entsprechend Licht niedrigen Modes. Verringert man nun den Kerndurchmesser soweit, daß sich das Licht nur noch entlang der optischen Achse ausbreiten kann, hat man eine Monomode-Faser. Mit Monomode-Fasern lassen sich die größten Übertragungsraten erzielen. n1
n2
n1
Abb. 5.6. Lichtwellenleiter mit Monomode-Stufenprofil
5.4 Netzwerkstrukturen 269
5.4 Netzwerkstrukturen Die Verbindung mehrerer Computer ermöglicht die Nutzung gemeinsamer Ressourcen (z. B. Dateien, Drucker, Programme) und ermöglicht den schnellen Datenaustausch. Im einfachsten Fall sind zwei Rechner miteinander verbunden, in größeren Firmen können das aber auch einige hundert oder tausend Rechner sein. Netze innerhalb eines Gebäudes bzw. Firmengeländes bezeichnet man als LAN (Local Area Network). Ein solches LAN besteht in der Regel aus betriebseigenen Leitungen und muß auch selbst administriert werden. Für größere Entfernungen, z. B. zwischen verschiedenen Städten, nutzt man Weitverkehrsnetze, die man WAN (Wide Area Network) nennt. Die Leitungen hierfür werden entweder von öffentlichen oder privaten Anbietern (kostenpflichtig) zur Verfügung gestellt. Es gibt mehrere Möglichkeiten, die Rechner eines Netzes miteinander zu verbinden, wodurch unterschiedliche Netzstrukturen mit spezifischen Vor- und Nachteilen entstehen. 5.4.1 Sternstruktur
Bei einer Sternstruktur sind alle Teilnehmer über eine Punkt-zu-PunktVerbindung an einen zentralen Knoten angeschlossen, der die gesamte Kommunikation steuert. Fällt die Zentrale aus, führt das zum Zusammenbruch des kompletten Netzes. Bei Ausfall eines Teilnehmers kann das Netz dagegen weiterarbeiten. Losgelöst von der physikalischen Verkabelung kann ein Stern aber auch als logische Struktur auftreten, z. B. bei Datenbankanwendungen.
Abb. 5.7. Sternstruktur
270 5 Netzwerke
5.4.2 Ringstruktur
In einem Netzwerk mit Ringstruktur sind alle Rechner gleichberechtigt mit jeweils zwei Nachbarn verbunden. Trifft eine Nachricht bei einem Teilnehmer ein, prüft dieser die Zieladresse und leitet sie gegebenenfalls zum nächsten Teilnehmer weiter. Nachrichten werden so vom Sender bis zum Empfänger durchgereicht. Fällt ein Teilnehmer im Ring aus, ist die Kommunikation im Netz unterbrochen.
Abb. 5.8. Ringstruktur
5.4.3 Busstruktur
Die Busstruktur kommt ebenfalls ohne Zentrale aus. Sie ist die einfachste und auch die am häufigsten verwendete Netzstruktur. Alle Teilnehmer sind über eine gemeinsame Hauptleitung, auch Backbone genannt, verbunden. Eine Nachricht auf der Leitung wird zwar von allen Teilnehmern registriert, aber nur von dem bzw. den Zieladressaten entgegengenommen. Fällt
Abb. 5.9. Busstruktur
5.5 Netzwerkkomponenten 271
ein Teilnehmer aus, ist das restliche Netz weiter funktionsfähig. Um Reflexionen zu vermeiden (diese könnten zu falschen Signalpegeln führen), sind die beiden Enden des Busses jeweils mit dem Wellenwiderstand der Leitung abzuschließen. 5.4.4 Vermaschte Struktur
Aber es gibt auch Computernetze, die nicht der reinen Lehre folgen und keiner der oberen Strukturen entsprechen. Zum Beispiel gibt es vermaschte Netze, bei denen mehrere unabhängige Verbindungen zwischen den Rechnern existieren, teilweise auch ohne Direktverbindung. Wegen der vielen redundanten Leitungen tritt ein Totalausfall des Netzes erst dann ein, wenn wirklich jeder einzelne Pfad ausgefallen ist. Häufig findet man auch unterschiedliche Strukturen miteinander kombiniert, z. B. ein Bus mit angeschlossenen Sternen. WANs sind in der Regel vermaschte Netze, wogegen LANs nach einem der ersten drei Konzepte aufgebaut sind.
Abb. 5.10. Vermaschte Struktur
5.5 Netzwerkkomponenten Was wir heute als Internet kennen, ist keineswegs ein homogenes Netz, sondern ein Verbund zahlreicher eigenständiger Teilnetze, in denen unterschiedliche Hardwareplattformen, Betriebssysteme und Übertragungsprotokolle nebeneinander existieren. Als Anwender erwartet man natürlich, daß der Zugriff auf einen Zielrechner problemlos funktioniert, unabhängig davon, wo dieser tatsächlich steht oder was für ein System darauf läuft. Um dies zu gewährleisten, bedarf es einiger Zusatzkomponenten im Netz.
272 5 Netzwerke
5.5.1 Repeater
Räumlich weit ausgedehnte Netze nutzen Repeater als Signalverstärker. Repeater empfangen die eingehenden Signale, regenerieren sie und geben diese dann wieder weiter. Weil jede Signalverstärkung im Netz auch zwangsläufig zu einer Verzögerung der Signallaufzeit führt, ist die Anzahl der hintereinander geschalteten Repeater auf vier beschränkt. Sie operieren auf der untersten Signalebene, ohne Informationen über den Dateninhalt. 5.5.2 Gateways
Gateways sind in der Lage verschiedene heterogene Netze, die nicht den TCP/IP-Standard verwenden, miteinander zu koppeln. Sie extrahieren die Nutzdaten aus den Datenpaketen und konvertieren diese in das jeweils andere Protokoll. Gegebenenfalls passen sie auch die Paketgröße an, spalten z. B. ein großes Datenpaket in kleinere Pakete auf. Weiterhin erkennen Gateways, ob ein Netz leistungsfähiger als das andere ist und bremsen das schnellere Netz entsprechend aus. 5.5.3 Router
Die Datenpakete werden bei ihrer Reise durch die verschiedenen Teilnetze von einem Router zum nächsten weitergegeben, bis sie schließlich ihre Zieladresse erreicht haben. Router sind Wegplaner, sie analysieren die eintreffenden Datenpakete, lesen die Zieladresse und bestimmen dann den weiteren Weg durch das Netz. Zur Ermittlung des günstigsten Weges verwenden sie interne Routingtabellen. Diese enthalten aber nicht etwa alle möglichen Zieladressen, sondern nur die Adressen der nächsten Station auf dem Weg dorthin. Das kann entweder ein weiterer Router sein oder der Zielrechner selbst.
5.6 TCP/IP und UDP/IP Die TCP/IP-Protokollfamilie dient Anwendungen zur Datenübertragung im weltweiten Rechnerverbund Internet. Dabei ist die Kommunikation in verschiedenen Ausführungsebenen bzw. Schichten organisiert, was sich in der geschachtelten Struktur der Protokolle widerspiegelt. Die Vermittlungsschicht IP (Internet Protocol) stellt Mechanismen zur Verfügung (z. B. Routing), um Datenpakete von einer Absenderadresse zu einer Zieladresse zu transportieren. Solch eine IP-Adresse besteht aus vier
5.7 Sockets 273
natürlichen Zahlen (0..255), die wegen der besseren Lesbarkeit jeweils durch einen Punkt getrennt sind (z. B. 149.123.12.34). Die Datenpakete werden versendet, ohne explizit einen Kommunikationskanal zu öffnen („verbindungslos“). Ihr Transport erfolgt unabhängig voneinander, unter Umständen auf verschiedenen Wegen durchs Netz und ohne auf eine Bestätigung durch den Empfänger zu warten. Somit kann IP nicht garantieren, daß auch alle Pakete ihr Ziel erreichen („nicht zuverlässig“). Es ist die Aufgabe der Transportschicht TCP dies sicherzustellen. TCP (Transmission Control Protocol) zerlegt die zur Übertragung anstehenden Daten in Pakete einheitlicher Größe. Ein solches Paket enthält neben den Nutzdaten zusätzliche Informationen, wie die Paketnummer, den Absender-Port und den Empfänger-Port. Die Ports bilden die Endpunkte einer TCP-Verbindung (Punkt-zu-Punkt). Sie sind durchnumeriert und auf dem jeweiligen Computer eindeutig. Die Datenpakete werden anschließend an IP zur weiteren Übertragung übergeben, da der Zielrechner nur auf dieser Ebene bekannt ist. Dort angekommen, setzt dieser die Pakete entsprechend ihrer Numerierung wieder zusammen. Sollten auf dem Weg durchs Netz Pakete verloren gegangen sein, werden sie erneut angefordert. IP-Adresse und Port-Nummer von Absender und Empfänger definieren eine TCP/IP-Verbindung vollständig. Neben TCP ist auch UDP (User Datagram Protocol) gebräuchlich, ein verbindungsloser und unzuverlässiger Übertragungsdienst. Wie bei IP werden die Daten einfach versendet, ohne auf eine Empfangsbestätigung zu warten. Der Vorteil von UDP gegenüber TCP liegt dann auch in der größeren Übertragungsgeschwindigkeit. Es wird vorzugsweise in solchen Anwendungen benutzt, bei denen Geschwindigkeit wichtiger ist als Zuverlässigkeit (z. B. Sprachübertragung).
5.7 Sockets Die Implementierung eines Netzwerkprotokolls ist mit Sicherheit keine triviale Aufgabe. Kann oder möchte man in seinem Programm aber nicht auf Netzwerkkommunikation verzichten, dann ist es zum Glück trotzdem nicht zwingend notwendig, sich in diese schwierige Materie vertieft einzuarbeiten, der Socket-Schnittstelle sei Dank. Sockets (Steckdose) sind abstrakte Kommunikationsendpunkte in einer Netzwerkumgebung. Sie wurden Anfang der 80er Jahre an der University of California in Berkeley implementiert und stellen dem Programmierer eine Reihe von Funktionen für die TCP/IP- bzw. UDP/IP-Kommunikation zur Verfügung. Ursprünglich für die UNIX-Welt entwickelt, wurden sie später auch auf andere
274 5 Netzwerke
Plattformen übertragen. Und obwohl die Socket-Programmierschnittstellen der verschiedenen Systeme nicht 100% kompatibel sind, man Programmzeilen in der Regel nicht einfach per „Copy“ und „Paste“ übernehmen kann, sind sie ihrem Grundprinzip immer treu geblieben. Daher läuft die Kommunikation über Sockets stets wie ein Dateizugriff ab, folgt also dem Schema „öffnen“, „lesen/schreiben“ (ggf. auch mehrfach) und wieder „schließen“. Entsprechend dem unterstützten Protokoll unterscheidet man Stream-Sockets für TCP und Datagram-Sockets für UDP (darüber hinaus gibt es noch Raw-Sockets, die aber kaum Anwendung finden). Tabelle 5.1. Die wichtigsten Funktionen der Socket-Schnittstelle für TCP/IP Aufruf (vereinfacht) Socket() Connect() Bind() Listen()
Accept() Send() Receive() Close()
Funktion Erzeugt ein Socket und initialisiert es Stellt eine TCP/IP-Verbindung zu einem Host her Weist einem Socket einen lokalen Endpunkt zu Versetzt ein Socket in Bereitschaft für eine Verbindungsaufnahme Wartefunktion für Verbindungsanforderung Sendet bzw. schreibt Daten raus Empfängt bzw. liest Daten ein Schließt ein Socket nach beendeter Datenübertragung
5.8 Das Client-Server-Modell In einem Computernetzwerk muß der Zugriff auf die Ressourcen (z. B. Dateien, Drucker, Programme) organisiert werden, um Zugriffskonflikte zu vermeiden. Eine Methode, die sich hierbei bewährt hat, beruht auf dem Client-Server-Modell. Allgemein betrachtet ist ein Server ein Prozeß, der gestartet wird, sich initialisiert und anschließend in einen Wartezustand geht, um Anfragen bzw. Aufträge von Clients zu bedienen. Oft starten Server-Prozesse bereits beim Hochfahren des Systems. Erst danach kann ein Anwender einen Client-Prozeß starten, um die Dienste des Servers zu nutzen (z. B. Daten abfragen). Hat der Server den Auftrag des Clients abgearbeitet, geht er wieder in den Wartezustand, bis der nächste Auftrag kommt. Soweit die Theorie. Client-Server-Netzwerkanwendungen lassen sich mit den zuvor beschriebenen Sockets leicht selbst implementieren. Dafür braucht man noch nicht einmal ein „echtes“ Netz, wenn man den Localhost 127.0.0.1 (das ist immer der eigene Rechner) verwendet. Als Port wird z. B. 1234 gewählt. Client und Server können dann als eigenständige Anwendungen über diesen Kanal miteinander kommuniziere.
5.8 Das Client-Server-Modell 275
Das folgende Beispiel zeigt den Transfer einer Datei. Der Client fordert eine Datei an, indem er den Dateinamen an den Server sendet. Der Server prüft, ob die angeforderte Datei überhaupt existiert. Ist das der Fall, dann liest er die Datei byteweise ein und übersendet sie ebenso an den Client. Der speichert sie in seinem Applikationsverzeichnis. Ist die Datei komplett übertragen, beendet sich der Client und der Server ist bereit für den nächsten Auftrag. Die nachstehende Implementierung folgt dem üblichen Schema einer Client-Server-Kommunikation mittels TCP/IP. Zunächst legt der Client ein Server-Socket an und verknüpft es mit der Zieladresse, bestehend aus IPAdresse und Port des Servers. Anschließend versucht der Client durch Aufruf von Connect() eine Verbindung mit dieser Zieladresse aufzubauen. Ist die Verbindung zustande gekommen, wird der Name der angeforderten Datei mit Send() übergeben. Der Verbindungsaufbau und die Anforderung eines Dienstes waren notwendige Formalismen, seine eigentliche Arbeit erledigt unser Client innerhalb der while-Schleife. Hier empfängt er die vom Server gesandten Daten mit Receive() und speichert sie als lokale Datei. Nach dem Übertragungsende schließt Close() den Server-Socket wieder. class TcpClient { public void Run(String dateiname) { int pufferlaenge = 256; byte[] sendepuffer = new byte[pufferlaenge]; byte[] empfangspuffer = new byte[pufferlaenge]; int anzahl = 0; int gesamt = 0; String adresse = "127.0.0.1"; int port = 1234; IPAddress serverIP = IPAddress.Parse(adresse); IPEndPoint zielpunkt = new IPEndPoint(serverIP, port); Socket serversocket = new Socket(AddressFamily. InterNetwork, SocketType.Stream, ProtocolType.Tcp); if (serversocket == null) { Console.WriteLine("Server-Socket nicht erstellt!"); return;
276 5 Netzwerke } try { // Verbindung zum Server aufnehmen serversocket.Connect(zielpunkt); } catch (Exception e) { Console.WriteLine("{0} Exception caught.", e); Console.WriteLine("Verbindung nicht aufgebaut!"); return; } if (serversocket.Connected) { Console.WriteLine("Verbindung mit Server!"); } // Dateinamen konvertieren String -> byte sendepuffer = Encoding.ASCII.GetBytes(dateiname); // ...und an den Server senden serversocket.Send(sendepuffer); // Filestream für die angeforderte Datei öffnen FileStream datei = new FileStream(dateiname, FileMode.Create, FileAccess.Write); do { // Empfange Daten vom Server anzahl = serversocket.Receive(empfangspuffer); // Die vom Server empfangene Datei lokal schreiben datei.Write(empfangspuffer, 0, anzahl); // Summation der empfangenen Daten gesamt += anzahl; // Fortschrittsanzeige Console.Write("."); } while(anzahl > 0); datei.Close(); // Verbindung zum Server wieder schließen serversocket.Close();
5.8 Das Client-Server-Modell 277
Console.WriteLine(); Console.WriteLine("{0} Byte empfangen!", gesamt); Console.WriteLine("Ende...<ENTER>"); Console.ReadLine(); } }
Im Gegensatz zum Client läuft der Server endlos in einer for(;;)Schleife. Zunächst muß auch hier ein Server-Socket angelegt werden, diesmal allerdings mit einem lokalen Endpunkt (d. h. der Verknüpfung der eigenen IP-Adresse und Port-Nummer). Die Zuweisung erfolgt durch den Aufruf von Bind(). Innerhalb der Endlosschleife wird dann ein ClientSocket angelegt. Mit Accept() wartet dieser bis ein Client versucht Verbindung zum Server aufzunehmen. Liegt aktuell keine Verbindungsanforderung vor, ist der weitere Ablauf blockiert. Meldet sich ein Client, wird im Programm fortgefahren und mit Receive() der Name der angeforderten Datei entgegengenommen. Ist die Datei vorhanden, wird sie gelesen und mit Send() an den Client gesendet. Nach Abschluß der Übertragung schließt Close() den Client-Socket wieder. Der Server gibt noch die Anzahl der übersendeten Bytes aus und springt dann erneut an den Anfang seiner Endlosschleife. class TcpServer { public void Run() { FileStream datei String dateiname int pufferlaenge byte[] sendepuffer byte[] empfangspuffer int anzahl int gesamt String adresse int port IPAddress serverIP IPEndPoint lokalerpunkt
= = = = = = = = = = =
null; ""; 256; new byte[pufferlaenge]; new byte[pufferlaenge]; 0; 0; "127.0.0.1"; 1234; IPAddress.Parse(adresse); new IPEndPoint(serverIP, port); Socket serversocket = new Socket(AddressFamily. InterNetwork, SocketType.Stream, ProtocolType.Tcp);
278 5 Netzwerke if (serversocket == null) { Console.WriteLine("Server-Socket nicht erstellt!"); return; } try { // Adresse und Port zuweisen serversocket.Bind(lokalerpunkt); } catch (Exception e) { Console.WriteLine("{0} Exception caught.", e); Console.WriteLine("Server-Socket und Adresse nicht verknüpft!"); return; } try { // Server in Bereitschaft setzen serversocket.Listen(1); } catch (Exception e) { Console.WriteLine("{0} Exception caught.", e); Console.WriteLine("Server ist nicht bereit!"); return; } for (;;) { Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Server ist bereit!"); // Objekt ClientSocket anlegen Socket clientsocket = new Socket(AddressFamily. InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Warte auf Verbindungsaufnahme durch einen Client clientsocket = serversocket.Accept(); if (clientsocket == null) {
5.8 Das Client-Server-Modell 279
Console.WriteLine("Fehler bei Verbindung!"); continue; } else { Console.WriteLine("Verbindung aufgenommen!"); } // Empfange Dateinamen vom Client anzahl = clientsocket.Receive(empfangspuffer); // ...und konvertiere byte -> String dateiname =Encoding.ASCII.GetString(empfangspuffer, 0, anzahl); Console.WriteLine("Anfrage von Client: {0}", dateiname); if (File.Exists(dateiname) == true) { // Datei existiert -> öffnen datei = new FileStream(dateiname, FileMode.Open, FileAccess.Read); } gesamt = 0; do { if (File.Exists(dateiname) == true) { // angeforderte Datei in Sendepuffer einlesen anzahl = datei.Read(sendepuffer, 0, pufferlaenge); } else { anzahl = 0; } // ...und zum Client schicken clientsocket.Send(sendepuffer, 0, anzahl, SocketFlags.None);
280 5 Netzwerke // Summation der gesendeten Daten gesamt += anzahl; // Fortschrittsanzeige Console.Write("."); } while(anzahl > 0); if (File.Exists(dateiname) == true) { datei.Close(); } // Verbindung zum Client wieder schließen clientsocket.Close(); Console.WriteLine(); Console.WriteLine("{0} Byte gesendet!", gesamt); } // Server wieder schließen -> wird nie erreicht! // serversocket.Close(); } }
6 Anhang
6.1 Lineare Gleichungssysteme Viele technische und naturwissenschaftliche Probleme lassen sich auf das Lösen eines Systems linearer Gleichungen zurückführen (z. B. polynomiale Regression von Meßreihen in Kapitel 2). Ein solches Gleichungssystem hat die folgende Gestalt:
a11 ⋅ x1 + a12 ⋅ x2 + a13 ⋅ x3 = b1 a21 ⋅ x1 + a22 ⋅ x2 + a23 ⋅ x3 = b2 a31 ⋅ x1 + a32 ⋅ x2 + a33 ⋅ x3 = b3
(6.1)
Mit Hilfe der Matrixschreibweise läßt sich das System in eine sehr kompakte und übersichtliche Form bringen.
§ a11 a12 ¨ ¨ a21 a22 ¨a © 31 a32 A⋅ x = b
a13 · § x1 · § b1 · ¸ ¨ ¸ ¨ ¸ a23 ¸ ⋅ ¨ x2 ¸ = ¨ b2 ¸ a33 ¸¹ ¨© x3 ¸¹ ¨© b3 ¸¹
(6.2)
(6.3)
Man bezeichnet A als Koeffizientenmatrix und x als Lösungsvektor. Die Absolutglieder b bilden die rechte Seite der Gleichung. Sind diese alle Null, dann liegt ein homogenes lineares Gleichungssystem vor, andernfalls ein inhomogenes System. Für inhomogene Systeme lassen sich grundsätzlich drei Fälle unterscheiden. Übersteigt die Anzahl m der Gleichungen die Anzahl n der Unbekannten, dann ist das System überbestimmt, die Lösung mithin nicht eindeutig. Gibt es dagegen weniger Gleichungen als Unbekannte, dann ist das System nicht lösbar. Für m=n ist das System lösbar, wenn die Gleichungen linear unabhängig sind. Wir wollen ausschließlich solche quadratischen Matrizen betrachten.
282 6 Anhang
6.1.1 Die Gauß-Elimination
Beim Lösen eines linearen Gleichungssystems versucht man das gegebene System durch äquivalente Umformung in eine Form zu bringen, die leichter zu lösen ist als das ursprüngliche System. Dies ist möglich, weil man Zeilen problemlos vertauschen kann oder Linearkombinationen aus ihnen bilden kann, ohne die Lösungsmenge der Gleichungen zu verändern. Eine Methode, die diese Eigenschaften konsequent ausnutzt, ist das Verfahren der Gauß-Elimination. Hierbei wird durch fortlaufende Normierung und Subtraktion die Ordnung des Gleichungssystems systematisch reduziert, bis die Koeffizientenmatrix in Dreiecksform gebracht ist. Aus deren letzter Zeile ergibt sich dann die erste Lösung. Setzt man diese nun rückwärts ein, lassen sich auch die restlichen Lösungen bestimmen. Das Verfahren beginnt mit der Normierung des Gleichungssystems (6.1), wobei jede Zeile durch ihren jeweils ersten Koeffizienten ai1 dividiert wird.
x1 +
a12 a b ⋅ x2 + 13 ⋅ x3 = 1 a11 a11 a11
(6.4)
x1 +
a22 a b ⋅ x2 + 23 ⋅ x3 = 2 a21 a21 a21
(6.5)
x1 +
a32 a b ⋅ x2 + 33 ⋅ x3 = 3 a31 a31 a31
(6.6)
Die Reduktion der Ordnung erfolgt durch Subtraktion einer beliebigen Gleichung von den beiden anderen Gleichungen, wobei x1 eliminiert wird. Um die angestrebte Dreiecksform zu erreichen, dient üblicherweise die erste Gln. (6.4) als Subtrahend. Sie bildet unsere Bezugszeile und bleibt dabei selbst unverändert. Dann ist im vorliegenden Fall Gln. (6.7) die Differenz aus den Gleichungen (6.5) und (6.4), entsprechend Gln. (6.8) die Differenz aus den Gleichungen (6.6) und (6.4).
§ a22 a12 · §a a · b b ¨¨ ¸¸ ⋅ x2 + ¨¨ 23 − 13 ¸¸ ⋅ x3 = 2 − 1 − a21 a11 © a21 a11 ¹ © a21 a11 ¹
(6.7)
§ a32 a12 · §a a · b b ¨¨ ¸¸ ⋅ x2 + ¨¨ 33 − 13 ¸¸ ⋅ x3 = 3 − 1 − a31 a11 © a31 a11 ¹ © a31 a11 ¹
(6.8)
Nach der Elimination von x1 verbleiben noch zwei Gleichungen mit zwei Unbekannten. Da dieses neue Gleichungssystem aus dem ursprünglichen System allein durch Anwendung linearer Operatoren hervorgegangen
6.1 Lineare Gleichungssysteme 283
ist, sind seine Lösungen auch Teil der ursprünglichen Lösungsmenge. Mit dem reduzierten Gleichungssystem wird ebenso verfahren, d. h. zunächst wird erneut normiert:
§ a23 a13 · § b2 b · ¨¨ ¸¸ ¨¨ − − 1 ¸¸ a a11 ¹ a a11 ¹ ⋅ x3 = © 21 x2 + © 21 § a22 a12 · § a22 a12 · ¨¨ ¸¸ ¨¨ ¸¸ − − a a a a © 21 © 21 11 ¹ 11 ¹
(6.9)
§ a33 a13 · § b3 b · ¨¨ ¸¸ ¨¨ − − 1 ¸¸ a11 ¹ a a a11 ¹ ⋅ x3 = © 31 x2 + © 31 § a32 a12 · § a32 a12 · ¨¨ ¸¸ ¨¨ ¸¸ − − a a a a 11 ¹ 11 ¹ © 31 © 31
(6.10)
Die Differenz der beiden Gleichungen (6.9), (6.10) führt schließlich zur Elimination von x2 und es bleibt nur eine Gleichung mit der Unbekannten x3 übrig.
§ § a33 a13 · § a23 a13 · · § b3 b · §b b · ¨¨ ¸¸ ¨¨ ¨¨ ¸¸ ¸ − − 1 ¸¸ ¨¨ 2 − 1 ¸¸ − ¨ ¨ © a31 a11 ¹ © a21 a11 ¹ ¸ © a31 a11 ¹ − © a21 a11 ¹ − ¨ ¸ ⋅ x3 = § a32 a12 · § a22 a12 · ¨ §¨ a32 − a12 ·¸ §¨ a22 − a12 ·¸ ¸ ¸¸ ¸¸ ¨¨ ¨¨ − − ¸ ¨ ¸ ¨¨ a ¸ © a31 a11 ¹ © a21 a11 ¹ © © 31 a11 ¹ © a21 a11 ¹ ¹
(6.11)
Im letzten Schritt ist noch nach x3 umzustellen, womit die erste Lösung gefunden ist.
§ b3 b · §b ¨¨ − 1 ¸¸ ¨¨ 2 © a 31 a11 ¹ − © a 21 § a32 a12 · § a 22 ¨¨ ¸ ¨ − a 31 a11 ¸¹ ¨© a 21 © x3 = § a33 a13 · § a 23 ¨¨ ¸¸ ¨¨ − © a 31 a11 ¹ − © a 21 § a32 a12 · § a 22 ¨¨ ¸¸ ¨¨ − © a 31 a11 ¹ © a 21
−
b1 · ¸ a11 ¸¹
−
a12 · ¸ a11 ¸¹
a · − 13 ¸¸ a11 ¹ −
a12 · ¸ a11 ¸¹
(6.12)
284 6 Anhang
Was jetzt folgt, ist die Berechnung der übrigen Lösungen. Hierzu setzt man Lösung (6.12) in die Gleichungen (6.9) oder (6.10) ein und erhält somit x2. Die Lösung für x1 ergibt sich entsprechend aus der Gln. (6.4), (6.5) oder (6.6). Wie man sieht, folgt der Gauß-Algorithmus einem sehr starren Schema und eignet sich daher ideal für eine Softwareimplementierung. Allerdings haben wir bisher ein Problem ignoriert. Es ist nicht auszuschließen, daß im Verlauf der Berechnung ein Normelement den Wert Null hat. Da wir einen „Division durch Null“-Fehler vermeiden wollen, müssen wir entsprechend vorsorgen. Man verwirft in diesem Fall die betroffene Zeile als Bezugszeile und wählt eine andere Zeile aus. Weil es aber numerisch ohnehin günstiger ist immer die Zeile mit dem betragsmäßig größten Koeffizienten als Referenzzeile zu wählen, sortieren wir entsprechend um. Aber auch das neue Normelement könnte Null sein (weil alle Koeffizienten der jeweiligen Spalte Null sind), weshalb wir dann den Wert Null durch einen vernachlässigbar kleinen Wert (z. B. 10−20) ersetzen und mit der Elimination fortfahren. class LGleichung { public double[,] A; public double[] b; public double[] x;
// Koeffizientenmatrix // Absolutglieder // Lösungsvektor
public int dimension; // Konstruktor public LGleichung(int dim) { dimension = dim; A = new double[dimension, dimension]; b = new double[dimension]; x = new double[dimension]; } public void FindeReferenzZeile(int zeile) { int spalte = zeile; int refzeile = zeile; double refelement = A[zeile,zeile]; double temp = 0; // Alle folgenden Elemente dieser Spalte // nach größtem Element durchsuchen
6.1 Lineare Gleichungssysteme 285
for (int k=zeile+1; k Math.Abs(refelement)) { refelement = A[k,spalte]; refzeile = k; } } // Neue Referenzzeile gefunden? // Falls ja, dann Zeilen tauschen if (refzeile > zeile) { // Erst die Koeffizientenmatrix for (int k=0; k
286 6 Anhang } // Über alle verbleibenden Elemente der Zeile for (int k=i; k=0; j--) { // Ausser Pivotelement alles durch Subtraktion // auf die rechte Seite bringen for (int k=dimension-1; k>j; k--) { b[j] -= x[k]*A[j,k]; } // Unbekannte entspricht dann dem Absolutglied x[j] = b[j]; } } }
Ein Blick auf Gln. (6.12) macht klar, daß für Systeme höherer Ordnung Rundungsfehler ein latentes Problem darstellen. Im Einzelfall können sie sogar zu falschen Ergebnissen führen. Ein gründlicher Test des Eliminations-Verfahrens schadet daher nicht. Man könnte nun die Koeffizientenmatrix A und die Absolutglieder b durch Zufallswerte vorgeben und den Lösungsvektor x berechnen. Allerdings wäre es dann notwendig die Richtigkeit des Ergebnisses mühsam zu verifizieren. Das ist zwar für ein System
6.1 Lineare Gleichungssysteme 287
vierter oder fünfter Ordnung eine gute Übung, bei Systemen höherer Ordnung hört der Spaß allerdings auf. Wir lassen lieber den Rechner für uns arbeiten und beschreiten den umgekehrten Weg, ein automatischer Matrixgenerator ist schließlich schnell implementiert. Er generiert ebenfalls zuerst eine Koeffizientenmatrix beliebiger Dimension (im folgenden Beispiel mit ganzzahligen Koeffizienten), erzeugt anschließend einen beliebigen Lösungsvektor und berechnet zu guter Letzt die resultierende rechte Seite des Systems. Mit der generierten Koeffizientenmatrix und den berechneten Absolutgliedern startet dann das Gauß-Verfahren. Der Test ist bestanden, wenn die berechnete Lösung mit der vorgegebenen Lösung identisch ist. class LGleichung { ... public void AutoGenerierung() { Zufall Rauschen = new Zufall(0.71036, 0.23906); double wert = 0; double summ = 0; // Koeffizientenmatrix for (int j=0; j
288 6 Anhang { summ += A[j,k]*x[k]; } b[j] = summ; } } }
§ − 8 2 − 1 5 − 2 · § x1 · § 4 · § 5 · ¨ ¸ ¨ ¸ ¨ ¸ ¨ ¸ ¨ − 1 8 − 7 10 − 5 ¸ ¨ x2 ¸ ¨ 94 ¸ ¨ 8 ¸ ¨ − 2 10 8 − 3 1 ¸ ⋅ ¨ x ¸ = ¨ 91 ¸ → x = ¨ 5 ¸ ¨ ¸ ¨ 3¸ ¨ ¸ ¨ ¸ ¨ − 4 − 9 0 − 9 − 2 ¸ ¨ x4 ¸ ¨ − 129 ¸ ¨ 5 ¸ ¨ ¸ ¨ ¨ 8 ¸ ¸ ¨ − 4¸ 4 −6 1 3 ¹ © x5 ¹ © 35 ¹ © © ¹ 6.2 Sortieren Das Sortieren von Daten gehört zu den Standardproblemen der Informatik und nimmt dort einen entsprechend breiten Raum ein. Eine Anwendung ist z. B. die Bestimmung des Medians, wie im zweiten Kapitel vorgestellt. Im Laufe der Zeit sind verschiedenen Sortierverfahren entwickelt worden, die sich hauptsächlich durch ihr Laufzeitverhalten unterscheiden. Viele dieser Algorithmen haben allerdings nur akademischen Wert und kommen in der Praxis kaum zum Einsatz, weshalb wir an dieser Stelle nur auf die beiden gängigsten Verfahren näher eingehen wollen. 6.2.1 Sortieren durch Vertauschen – Selectionsort
Es ist immer von Vorteil, wenn ein Algorithmus simpel genug ist, um ihn bei Bedarf selbst herleiten zu können. Das Verfahren Sortieren durch Vertauschen fällt genau in diese Kategorie. Ausgehend vom ersten Element einer Datenreihe wird dieses zunächst mit allen nachfolgenden Elementen verglichen und jedesmal getauscht, wenn man ein kleineres Element findet. Ist man am Ende des Datenfeldes angekommen, dann steht das kleinste Element garantiert an erster Stelle. Im nächsten Durchlauf beginnt man beim zweiten Element und verfährt mit diesem ebenso, wodurch schließlich das zweitkleinste Element an zweiter Stelle steht. Auf diese Weise fährt man fort, bis sämtliche Elemente des Feldes sortiert sind.
6.2 Sortieren 289
class Sortieren { public const int Abtastwerte = 128; // Stichprobe public double[] x = new double[Abtastwerte]; // Arbeitskopie der Stichprobe public double[] sort = new double[Abtastwerte]; public void SelectionSort() { double min = 0; // Alle Abtastwerte x() aufsteigend sortieren for (int i=0; i
Die Implementierung benötigt zwei geschachtelte Schleifen, wobei die äußere Schleife (Index i) auf das aktuelle Element zeigt und die innere Schleife (Index j) von diesem jeweils bis zum Ende des Datenfeldes läuft. Alle bereits durchlaufenen Elemente i sind sortiert und werden nicht mehr bewegt. Insgesamt sind N−1 + N−2 + N−3 + ... + 1 = N·(N−1)/2 Vergleiche nötig, womit Selectionsort zu den N2-proportionalen Algorithmen gehört. 6.2.2 Quicksort
Auch wenn das zuvor beschriebene Verfahren im Prinzip funktioniert, ist es für große Datensätze ungeeignet, da sein hoher Berechnungsaufwand
290 6 Anhang
dann relativ schnell zu nicht akzeptablen Ausführungszeiten führt. 1961 stellte C. A. R. Hoare einen Algorithmus vor, der nach dem Prinzip Teileund-Herrsche die Daten in zwei Teile zerlegt und sortiert. Führt man den Ansatz rekursiv fort, genügen durchschnittlich N·log2(N) Schritte. Dieser Algorithmus wurde als Quicksort bekannt und ist heute das wahrscheinlich am häufigsten verwendete Sortierverfahren. Der Quicksort-Algorithmus beginnt mit einem Pivotelement als Vergleichswert, z. B. entnommen aus der Mitte des Datenfeldes. Notwendige Bedingung für ein aufsteigend sortiertes Datenfeld ist, daß alle Elemente links vom Pivot kleiner (oder gleich) dem Vergleichswert sind und alle Elemente rechts vom Pivot größer (oder gleich) dem Vergleichswert. Diese Bedingung beschreibt nur eine grobe Ordnung der Daten, ist daher im Sinne der mathematischen Logik noch nicht hinreichend, d. h. auch wenn eine solche Ordnung vorliegt, ist der Rückschluß auf bereits vollständig sortierte Daten unzulässig. Daher läuft ein Index vom Anfang des Datenfeldes nach rechts los, bis zum ersten Element, welches größer als der Vergleichswert ist, ein zweiter Index läuft vom Ende des Datenfeldes nach links, bis zum ersten Element, das kleiner ist als der Vergleichswert. Haben sich beide Indexe noch nicht getroffen, dann liegt also das größere Element links vom Vergleichswert und das kleinere Element rechts davon. Sie verletzen somit in jedem Fall die notwendige Bedingung (befinden sich also auf der falschen Seite) und werden getauscht. So wird fortgefahren, bis beide Indexe zusammentreffen. Das Vergleichselement hat dann seinen endgültigen Platz im Datenfeld gefunden, d. h. alle Elemente links sind kleiner (oder gleich) und alle Elemente rechts größer (oder gleich). Mit den beiden entstandenen (Teil-) Datenfeldern wird dann ebenso verfahren. Führt man diesen Vorgang rekursiv fort, wird schließlich das gesamte Datenfeld sortiert. class Sortieren { ... public void QuickSort(int start, int stop, double[] sort) { int von = 0; int bis = 0; double wert = 0; // Pivotelement double temp = 0; von = start; bis = stop;
6.2 Sortieren 291
// Vergleichswert aus der Intervallmitte wert = sort[(int)((von+bis)/2.0)]; do { while (sort[von] < wert) von++; while (sort[bis] > wert) bis--; if (von <= bis) { temp = sort[von]; sort[von] = sort[bis]; sort[bis] = temp; von++; bis--; } } while (von <= bis); if (start < bis) QuickSort(start, bis, sort); if (stop > von) QuickSort(von, stop, sort); } ... }
6.2.3 Vergleich beider Verfahren
Der wesentliche Unterschied zwischen den beiden Verfahren ist natürlich ihr Rechenzeitbedarf. Um zu überprüfen, ob der Quicksort-Algorithmus seinen Namen zu recht trägt, bestimmen wir seine Laufzeit und vergleichen diese mit Selectionsort. Damit der relative Fehler möglichst klein bleibt, wird für jede Messung eine größere Anzahl von Durchläufen ausgeführt. Streng genommen benötigt natürlich auch eine leere Programmschleife Rechenzeit, deren Zeitbedarf aber gegenüber den Sortierverfahren nicht ins Gewicht fällt und darum vernachlässigbar ist. class Sortieren { ... public void Benchmark() { const int testzyklen = 1000; DateTime start; DateTime stop;
292 6 Anhang Console.WriteLine("SelectionSort startet jetzt!"); start = DateTime.Now; for (int j=0; j
Wie man sich leicht vorstellen kann, hängt die Laufzeit eines Sortierverfahrens nicht unwesentlich von der „Unordnung“ der betrachteten Stichprobe ab. Tatsächlich kommt es beim Sortieren ganz entscheidend darauf an, wie häufig Elemente zu tauschen sind bis die Reihenfolge stimmt (und
6.2 Sortieren 293 1
x(k)
x(k)
1
0,5
0
0,5
0 0
4
8
12
16
20
24
28
32
36
40
44
48
0
4
8
12
k
16
20
24
28
32
36
40
44
48
k
Abb. 6.1. Sortieren einer zufällig verteilten Stichprobe
nicht nur auf die Anzahl der Vergleiche). Für unsere Laufzeitmessung verwenden wir daher eine unsortierte, eine aufsteigend vorsortierte und eine absteigend vorsortierte Stichprobe. Am Beispiel einer zufällig angeordneten Stichprobe erkennt man sofort die gute Übereinstimmung von Theorie und Praxis. Ähnlich wie beim Laufzeitvergleich von DFT und FFT, laufen beide Kurven sehr schnell auseinander. Für kleine Datenmengen ist der Unterschied allerdings weit weniger dramatisch und macht sich bis N§20 kaum bemerkbar. 180
Rechenzeit
150 120 90 60 30 0 0
250
500
750
1000
N
Abb. 6.2. Laufzeit von Selectionsort und Quicksort bei zufälliger Stichprobe
Auf den ersten Blick scheinen zufällig verteilte Stichproben das Paradebeispiel schlechthin zu sein, wenn es ums Sortieren geht. Dem ist aber nicht so. In der Meßtechnik zeigen Signale sehr häufig eine deutliche Tendenz, d. h. sie steigen bzw. fallen monoton für einige Zeit oder sie sind sogar periodisch. Zusätzlich ist ihnen ein zufälliger Rauschanteil überlagert. Man hat es also in der Regel mit einer Mischung aus ungeordneten und teilweise geordneten Werten zu tun. Um dieser Realität möglichst nahe zu kommen, vergleichen wir schließlich auch die Laufzeit der Algorithmen bei vorsortierten Stichproben.
294 6 Anhang 1
x(k)
x(k)
1
0,5
0
0,5
0 0
4
8
12
16
20
24
28
32
36
40
44
48
0
4
8
12
k
16
20
24
28
32
36
40
44
48
k
Abb. 6.3. Sortieren einer aufsteigend vorsortierten Stichprobe
Im Falle einer aufsteigend vorsortierten Stichprobe braucht Selectionsort die Elemente nur zu vergleichen, ohne daß es auch nur einmal zum Tausch kommt. Im Resultat macht sich das durch eine erheblich kleinere Ausführungszeit als im vorigen Beispiel bemerkbar. Ähnliches gilt auch für den Quicksort-Algorithmus. Da sich jedes Pivotelement an der richtigen Stelle befindet, links alle kleineren und rechts alle größeren Elemente liegen, sollte die Notwendigkeit zum Tausch eigentlich entfallen. Ein Blick auf die hier vorgestellte Implementierungsvariante zeigt aber, daß immer dann getauscht wird, wenn die Bedingung (von<=bis) erfüllt ist. Schnell ist man geneigt das Gleichheitszeichen zu entfernen, welchen Sinn soll es schließlich haben zwei gleichwertige Elemente zu tauschen? Nicht übersehen sollte man aber auch das Rauf- bzw. Runterzählen der beiden Laufvariablen nach dem Tausch. Geschieht dies nicht auch für von=bis, wird die Abbruchbedingung der while-Schleife nie erfüllt. Als Folge kommt es zu etwa N/2 Tauschvorgängen, allesamt bei Gleichheit der Laufvariablen. Trotzdem ist der Quicksort-Algorithmus auch bei einer aufsteigend vorsortierten Stichprobe noch erheblich schneller als Selectionsort. 60
Rechenzeit
50 40 30 20 10 0 0
250
500
750
1000
N
Abb. 6.4. Laufzeit von Selectionsort und Quicksort bei aufsteigender Anordnung
6.2 Sortieren 295 1
x(k)
x(k)
1
0,5
0
0,5
0 0
4
8
12
16
20
24
28
32
36
40
44
48
0
4
8
12
k
16
20
24
28
32
36
40
44
48
k
Abb. 6.5. Sortieren einer absteigend vorsortierten Stichprobe
270
Rechenzeit
225 180 135 90 45 0 0
250
500
750
1000
N
Abb. 6.6. Laufzeit von Selectionsort und Quicksort bei absteigender Anordnung
Liegt eine absteigend vorsortierte Stichprobe vor, ist die Interpretation des Laufzeitverhaltens für Selectionsort wieder relativ einfach. Im ersten Durchlauf wird (N−1)-mal getauscht, im zweiten Durchlauf (N−2)-mal, im dritten Durchlauf noch (N−3)-mal, usw., in der Addition ergeben sich somit N·(N−1)/2 Tauschvorgänge, also mehr als bei einem zufällig angeordneten Datenfeld. Hieraus resultiert schließlich die deutlich höhere Laufzeit. Quicksort ist da erheblich genügsamer und tauscht nur etwa N Elemente.
Literaturverzeichnis
Allgemeine Themen [1] Gunnerson, E.: C#. Galileo Press 2000 [2] Knuth, D. E.: The Art of Computer Programming. Addison-Wesley 1997 [3] Meyer, B.: Objektorientierte Softwareentwicklung. Carl Hanser Verlag 1990 [4] Sedgewick, R.: Algorithmen in C. Addison-Wesley 2003 [5] Petzold, C.: Windows-Programmierung mit C#. Microsoft Press 2003 [6] Press, W. H.; Flannery, B. P.; Teukolsky, S. A.; Vetterling, W. T.: Numerical Recipes in C. Cambridge University Press 1992 [7] Wirth, N.: Algorithmen und Datenstrukturen. Teubner–Verlag 1983
Digitale Signalverarbeitung (Kapitel 1) [8] Hoffmann, R.: Signalanalyse und –erkennung. Eine Einführung für Informationstechniker. Springer 1998
298 Literaturverzeichnis
[9] Lüke, H. D.: Signalübertragung. Grundlagen der digitalen und analogen Nachrichtenübertragungssysteme. Springer 2000 [10] Kronmüller, H.: Digitale Signalverarbeitung. Grundlagen, Theorie, Anwendungen in der Automatisierungstechnik. Springer 1991 [11] Oppenheim, A. V.; Willsky, A. S.: Signale und Systeme. VCH-Verlag 1989 [12] Tietze, U.; Schenk, C.: Halbleiter-Schaltungstechnik. Springer 1989 [13] Unbehauen, R.: Systemtheorie 1. Allgemeine Grundlagen, Signale und lineare Systeme im Zeit- und Frequenzbereich. Oldenbourg-Verlag 2002
Statistische Signalverarbeitung (Kapitel 2) [14] Burkschat, M.; Cramer, E.; Kamps, U.: Beschreibende Statistik. Grundlegende Methoden. Springer 2004 [15] Hänsler, E.: Statistische Signale. Grundlagen und Anwendungen. Springer 2001 [16] Hartung, J.: Statistik: Lehr- und Handbuch der angewandten Statistik. Oldenbourg-Verlag 1993 [17] Gränicher, W. H.: Messung beendet-was nun? Teubner-Verlag 1996
Literaturverzeichnis 299
Computational Intelligence (Kapitel 3) [18] Bandemer, H.; Gottwald, S.: Einführung in Fuzzy-Methoden. Akademie-Verlag 1990 [19] Bothe, H.-H.: Neuro-Fuzzy-Methoden. Springer 1998 [20] Haykin, S.: Neural Networks. Prentice Hall 1998 [21] Kurzweil, R.: Das Zeitalter der Künstlichen Intelligenz. Carl Hanser Verlag 1993 [22] Nauck, D.; Klawonn, F.; Kruse, R.: Neuronale Netze und Fuzzy-Systeme. Vieweg 1994 [23] Pao, Y.-H.: Adaptive Pattern Recognition and Neural Networks. Addison-Wesley 1989 [24] Rojas, R.: Theorie der neuronalen Netze. Eine systematische Einführung. Springer 1993
Simulationstechnik (Kapitel 4) [25] Föllinger, O.; Franke, D.: Einführung in die Zustandsbeschreibung dynamischer Systeme. Oldenbourg-Verlag 1982 [26] Hoffmann, J.: MATLAB und SIMULINK. Beispielorientierte Einführung in die Simulation dynamischer Systeme. Addison-Wesley 1998 [27] Möller, D.: Modellbildung, Simulation und Identifikation dynamischer Systeme. Springer 1992
300 Literaturverzeichnis
Netzwerke (Kapitel 5) [28] Furrer, F. J.: Ethernet-TCP/IP für die Industrieautomation: Grundlagen und Praxis. Hüthig-Verlag 2000 [29] Tanenbaum, A. S.: Computernetzwerke. Prentice Hall 2003
Sachverzeichnis
A
C
Absolutglieder 281 Abtasttheorem 29 Abtastung 27 Adams-Bashforth-Verfahren 237 AKF 131 Aktivierungsfunktion 165 Alias-Frequenzen 29 Aliasing 29 Allpaßfilter 60 Amplitudenspektrum 7 Analysegleichungen 6 Anfangswertproblem 225 Antenne 265 arithmetischer Mittelwert 115 ARPA 261 Aufbaufunktionen 4 Ausblendeigenschaft 26 Ausgleichsgerade 137 Ausreißer 152 Autokorrelation 131 Avatar 162 Axon 164
Chatbots 162 Chirp 39 Client-Server-Modell 274 COG-Methode 198 Cosinus 2
B Backbone 270 Backpropagation-Algorithmus 171 Bandbreite 41 Bandpaß-Filter 42 Bandsperren 42 Bias 165 Bit-Umkehr 13 Brechungsindex 267 Brute-Force-Algorithmen 256 Busstruktur 270 Butterfly 12
D Datagram-Sockets 274 Defuzzifizierung 197 Delta-Impuls 26 Delta-Kamm 27 Dendriten 164 DFT 7 Differentialgleichung 224 digitale Filter 40 Dirac-Impuls 26 Downsampling 189 drahtlose Kommunikation 264 Drehzeiger 14 Durchlaßbereich 41
E Einheitsimpuls 87 Einheitssprung 89 Einschrittverfahren 236 Eliminationsverfahren von Gauß 143 empirischer Korrelationskoeffizienten 128 Erwartungswert 106 Euler-Cauchy-Verfahren 233 experimentelle Systemanalyse 84 Exzeß 120
F Faltung 32 Faltungssumme 48
302 Sachverzeichnis farbiges Rauschen 93 Feldwellenwiderstand 266 Fenstermethode 54 Fensterung 32 Fernfeld 265 FFT 11 FFT-Filter 83 FIR-Filter 50 Fortpflanzungsfaktor 264 Fourier-Reihen 2 Freiraumwelle 265 Frequenzgang 47 Fuzzifizierung 196 Fuzzy-Logik 192
G Gateways 272 Gauß-Elimination 282 Gauß-Verteilung 106 Gesetz der großen Zahlen 125 Gewichtsfaktoren 167 Gewichtsfunktion 48 Gibbsches Phänomen 4 Gleichungssystem 281 Gleitsinus 39 Grenzfrequenz 41 Grundgesamtheit 125 Grundschwingung 23
H Haar-Funktionen 6 Haltevorgang 27 Hanning-Fenster 32 Harmonische 23 Histogramm 108 Hochpaß-Filter 42 homogene Lösung 225
K Kammfunktion 27 kausal 50 Koeffizientenmatrix 281 Korrelationsanalyse 127 Kreuzkorrelation 131 künstliche Randomisierung 255 Kurtosis 120 Kurzzeit-Spektralanalyse 36
L LAN 269 Laplace-Transformation 43 Leakage 30 Lernrate 173 Lichtwellenleiter 266 lineare Kongruenz 101 linearphasig 82 linguistische Terme 194 linguistische Variable 194 Localhost 274 Lösungsvektor 281
M Median 116 Medianfilter 152 Mehrschrittverfahren 236 Methode der kleinsten Fehlerquadrate 137 mittlere absolute Abweichung 117 Modellbildung 223 Momentum 173 Monte-Carlo-Methode 254 Moving-Average-Filter 49 Multi-Layer-Perzeptron 168
I Identifikation 84 IDFT 9 IIR-Filter 51 Inferenz 196 inhomogene Lösung 226 Instabilität 70 IP 272
N Nettoinput 165 neuronale Netze 163 Neuronen 163 Normalverteilung 106 Notch-Filter 42 Nyquistfrequenz 29
Sachverzeichnis 303
O Ordnungsreduktion 254 Orthogonalitätsbedingung 6 overlearning 171 oversampling 30
P Pearson-Korrelationskoeffizienten 128 Phasengang 81 Phasenspektrum 7 Polstellen 70 Polygonzug-Verfahren 230 Propagation 176
Q Quicksort 290
R Rademacher-Funktionen 6 Randwertproblem 225 Rangordnungsfilter 151 Rauschen 93 Reflexionen 267 Regression 136 rekursive Filter 50 Repeater 272 Reshuffling 113 Resonanz-Filter 42 Restmethode 101 Reziprozitätsprinzip 266 Richtungsfeld 229 Ringstruktur 270 Router 272 Runge-Kutta-Verfahren 234
S Scheinkorrelation 135 Schiefe 119 Schrittweitensteuerung 252 Sigmoid-Funktion 165 Simulationstechnik 223 Singletons 199 Sinus 2 skewness 119
Sockets 273 Sortieren durch Vertauschen 288 Spaltfunktion 29 Spannweite 117 Spektrogramm 37 Sperrbereich 41 Sperr-Filter 42 Spikes 152 Sprungantwort 90 stabiles System 70 Stabilität 45 Standardabweichung 106, 118 Standardfehler 126 Sternstruktur 269 STFT 36 Stichprobe 124 Stream-Sockets 274 Streudiagramm 112 Streumaß 117 Streuung 106, 118 subsymbolische Repräsentation 162 symbolische Repräsentation 162 Synapsen 164 Synthesegleichung 6 System 44 Systemgleichungen 223
T TCP 273 Teile-und-Herrsche 11 Telegraphengleichung 264 Testsignale 87 Tiefpaß-Filter 42 Time-Delay neuronales Netzwerk 191 Transienten 33 Treppenfunktion 27 Turing-Test 161
U Überabtastung 30 Übergangsbereich 41 Übergangsfunktion 90 Übertragungsfunktion 45 überwachtes Lernverfahren 170 UDP 273
304 Sachverzeichnis unscharfe Menge 193 Unterabtastung 29
weißes Rauschen 93 Wellenimpedanz 264 Wellentypwandler 265
V Validationsdatei 171 Varianz 118 Variation der Konstanten 226 verbessertes Polygonzug-Verfahren 231 vermaschte Netze 271 Verstärkung 41
W Walsh-Funktionen 6 WAN 269
Z Zeichenerkennung 186 Zeit-Frequenz-Unschärfe 38 Zeitreihenanalyse 189 zentraler Grenzwertsatz 105 Zentralwert 116 Zielmuster 170 z-Transformation 43 Zufallszahlen 100 Zugehörigkeitsfunktionen 195