Schlag eine Glocke mit einem Hammer an. Der Schlag selbst ist stumpf — ein Puls, ein „Wumms” ohne erkennbare Tonhöhe. Und doch antwortet die Glocke mit einem klaren Klang: Sie hat sich aus dem Wumms ihre eigenen Frequenzen herausgesucht und alles andere verschluckt. Der stumpfe Schlag muss diese Töne also irgendwie enthalten haben — alle auf einmal.
Genau dieses Prinzip macht aus unseren Simulationen Messgeräte: Ein einziger Puls in einen Resonator, und eine Rechnung liefert alle seine Resonanzfrequenzen gleichzeitig. Dafür fehlt uns noch das Ohr — ein Werkzeug, das aus einem Zeitsignal die enthaltenen Frequenzen liest. Wir bauen es in diesem Kapitel von Hand (es ist verblüffend wenig dahinter: multiplizieren und mitteln) und lassen es dann von np.fft schnell rechnen.
Und dann ist da noch eine Schuld, die dieses Buch seit Kapitel 5 vor sich herschiebt. Wir haben gemessen, geprüft und verglichen — aber die Grundsatzfrage nie systematisch gestellt: Warum sollte man den Zahlen einer Simulation eigentlich glauben? Mit dem Spektrum-Werkzeug in der Hand können wir sie beantworten — mit Konvergenztests, dem Vergleich gegen exakte Mathematik und einer Checkliste, die ab Teil III vor jedem Werkzeug-Einsatz steht.
Lernziele
Nach diesem Kapitel kannst du …
… einen Frequenz-Detektor selbst bauen (Signal mal Sinus, mitteln) und erklären, warum fremde Frequenzen dabei herausfallen,
… Spektren mit np.fft.rfft berechnen und lesen — und weißt, was Aufnahmedauer und Abtastschritt über Auflösung und Obergrenze entscheiden,
… erklären, warum ein kurzer Puls ein breites Spektrum hat — der „Chor aus Sinuswellen” aus Kapitel 8, jetzt messbar,
… einen Resonator mit einem einzigen Pulslauf komplett vermessen und das Ergebnis gegen die Analytik halten,
… einen Konvergenztest durchführen und mit der Validierungs-Checkliste begründen, wann eine Simulation Vertrauen verdient.
10.1 Ein Frequenz-Detektor von Hand
Gegeben ist eine Messreihe — sagen wir eine Funkantenne, deren Spannung wir 1 µs lang alle 10 ns abgetastet haben, 100 Werte. Wir bauen sie uns selbst, damit wir die Wahrheit kennen: zwei Sinustöne, 3 MHz mit Amplitude 1 und 5 MHz mit Amplitude 0,5; der 3-MHz-Ton bekommt zusätzlich eine Phasenverschiebung, denn eine echte Messung beginnt nie höflich beim Nulldurchgang. Die Frage: Wie findet man die beiden Töne wieder, wenn man die Wahrheit nicht kennt?
Die Idee ist ein Detektor zum Hineinhalten: Um zu prüfen, ob eine Testfrequenz \(f\) im Signal steckt, multipliziere das Signal Punkt für Punkt mit \(\sin(2\pi f t)\) — und mittele das Produkt über die ganze Aufnahme. Steckt ein Ton der Frequenz \(f\) im Signal, dann ist das Produkt im Gleichtakt: positiv mal positiv, negativ mal negativ — der Mittelwert bleibt stehen. Jeder fremde Ton gerät gegen den Test-Sinus mal in den Gleichtakt, mal in den Gegentakt, und mittelt sich zu null weg. Das ist keine Hoffnung, sondern Schulmathematik — das Additionstheorem verwandelt jedes Produkt zweier Sinusse in eine Differenz zweier Kosinusse:
\[\sin a \cdot \sin b
= \tfrac{1}{2}\bigl[\cos(a - b) - \cos(a + b)\bigr],\]
und ein Kosinus, der über volle Perioden gemittelt wird, ergibt null. Nur wenn \(a\) und \(b\) zur selben Frequenz gehören, wird \(\cos(a-b)\) zu \(\cos(0) = 1\) — und übrig bleibt genau die halbe Amplitude des getroffenen Tons. Die Handrechnung am konkreten Zahlenpaar, jeder Schritt einzeln:
import numpy as npimport matplotlib.pyplot as pltDT_AB =10e-9# Abtastschritt: alle 10 ns ein MesswertN_AB =100# 100 Werte → Aufnahmedauer 1 µst = np.arange(N_AB) * DT_ABsignal = (1.0* np.sin(2*np.pi *3e6* t +0.7) # 3 MHz, phasenverschoben+0.5* np.sin(2*np.pi *5e6* t)) # 5 MHzprobe_3 = np.sin(2*np.pi *3e6* t) # Test-Sinus 3 MHzprobe_4 = np.sin(2*np.pi *4e6* t) # Test-Sinus 4 MHzprint(f"Mittel über sin·sin, gleiche Frequenz : "f"{np.mean(probe_3 * probe_3):+.4f} (= 1/2)")print(f"Mittel über Signal · 3-MHz-Probe : "f"{np.mean(signal * probe_3):+.4f}")print(f"Mittel über Signal · 4-MHz-Probe : "f"{np.mean(signal * probe_4):+.4f} (fremde Frequenz)")
Mittel über sin·sin, gleiche Frequenz : +0.5000 (= 1/2)
Mittel über Signal · 3-MHz-Probe : +0.3824
Mittel über Signal · 4-MHz-Probe : +0.0000 (fremde Frequenz)
Die erste Zeile zeigt die Eichung des Detektors: Selbst der Volltreffer liefert nur \(\tfrac{1}{2}\) (das ist das gemittelte \(\sin^2\) — die Hälfte der Zeit ist der Sinus klein). Ein Treffer muss also mal 2 genommen werden. Die zweite Zeile findet vom 3-MHz-Ton nur \(0{,}38\) statt der erwarteten \(0{,}5\) — die Phasenverschiebung! Der Ton steckt zum Teil „im Kosinus”, und ein Sinus-Detektor allein übersieht diesen Anteil. Die Lösung: zweimal detektieren, einmal mit Sinus, einmal mit Kosinus, und die beiden Anteile wie die Katheten eines rechtwinkligen Dreiecks zur Gesamtamplitude zusammensetzen:
# von oben: signal, tdef detektor(sig, f, t):"""Amplitude der Frequenz f im Signal: 2·Mittel gegen sin und cos.""" a =2* np.mean(sig * np.sin(2*np.pi * f * t)) b =2* np.mean(sig * np.cos(2*np.pi * f * t))return np.hypot(a, b) # √(a² + b²), wie in Kapitel 1for f in (2e6, 3e6, 4e6, 5e6, 6e6):print(f"Detektor bei {f/1e6:.0f} MHz: {detektor(signal, f, t):.4f}")
Detektor bei 2 MHz: 0.0000
Detektor bei 3 MHz: 1.0000
Detektor bei 4 MHz: 0.0000
Detektor bei 5 MHz: 0.5000
Detektor bei 6 MHz: 0.0000
Da sind sie: \(1{,}0\) bei 3 MHz, \(0{,}5\) bei 5 MHz, praktisch null überall sonst — Amplituden und Verstecke gefunden, ohne die Wahrheit zu kennen. Lässt man den Detektor über ein ganzes Raster von Testfrequenzen laufen, entsteht das Spektrum des Signals: eine Funktion, die jeder Frequenz die in ihr steckende Amplitude zuordnet (der Ergebnistyp: ein Array über dem Frequenzraster, eine Zahl pro Testfrequenz).
10.2 np.fft: derselbe Detektor, nur schnell
Unser Detektor rechnet pro Testfrequenz das ganze Signal zweimal durch — für lange Messreihen und viele Frequenzen wird das träge. Die schnelle Fourier-Transformation (FFT, nach Jean Baptiste Fourier; der Algorithmus stammt von Cooley und Tukey, 1965) berechnet exakt dieselben Sinus- und Kosinus-Mittel für alle Frequenzen des Rasters auf einmal, durch geschicktes Wiederverwenden von Zwischenergebnissen. In NumPy heißt sie für reelle Messreihen np.fft.rfft, und es lohnt sich, die Übereinstimmung mit dem Hand-Detektor einmal nachzuprüfen:
# von oben: signal, t, detektor(), N_AB, DT_AB# np.fft.rfft: FFT für reelle Signale — liefert für jede Rasterfrequenz# das (Kosinus, Sinus)-Anteilspaar, verpackt als komplexe Zahl;# np.abs holt daraus die Gesamtamplitude (unser np.hypot(a, b))spektrum_fft = np.abs(np.fft.rfft(signal)) *2/ N_AB# np.fft.rfftfreq: das zugehörige Frequenzraster (aus N und Δt)frequenzen = np.fft.rfftfreq(N_AB, DT_AB)raster = np.arange(0, 13e6, 1e6)spektrum_hand = np.array([detektor(signal, f, t) for f in raster])fig, ax = plt.subplots(figsize=(6.6, 3.2))ax.plot(frequenzen /1e6, spektrum_fft, "o", ms=5, label="np.fft.rfft")ax.plot(raster /1e6, spektrum_hand, "+", ms=11, mew=1.6, label="Detektor von Hand")ax.set_xlim(-0.3, 12.3)ax.set_xlabel("Frequenz (MHz)"); ax.set_ylabel("Amplitude (V/m)")ax.legend()plt.tight_layout(); plt.show()vergleich = np.max(np.abs(spektrum_hand- spektrum_fft[:len(raster)]))print(f"größte Abweichung Hand-Detektor vs. rfft: {vergleich:.1e}")
Abbildung 10.1: Das Spektrum des Testsignals, zweimal berechnet: np.fft.rfft (Punkte) und der Hand-Detektor (Kreuze) liegen exakt übereinander — bis auf Rundungsrauschen unterhalb von 10⁻¹⁵. Die beiden versteckten Töne (3 MHz mit Amplitude 1, 5 MHz mit Amplitude 0,5) stehen sauber im sonst leeren Spektrum.
größte Abweichung Hand-Detektor vs. rfft: 4.7e-16
Der Faktor 2 / N_AB übersetzt die rfft-Ausgabe in unsere Detektor-Eichung (das Mitteln steckt bei NumPy nicht drin, das Mal-zwei auch nicht). Zwei Eigenschaften des Frequenzrasters solltest du auswendig kennen, denn sie entscheiden über jedes Messdesign:
Die Auflösung ist 1/Aufnahmedauer. Unsere 1 µs lange Messung hat ein Raster im Abstand \(\Delta f = 1/(1\,\text{µs}) = 1\) MHz — feiner kann diese Aufnahme Frequenzen nicht unterscheiden. Wer zwei nahe Töne trennen will, braucht länger, nicht öfter: Erst wenn die Aufnahme so lang ist, dass die beiden Töne darin spürbar verschieden oft schwingen, kann irgendein Verfahren sie auseinanderhalten (Ü 10.3 führt das vor — und räumt mit der verbreiteten Vermutung auf, schnelleres Abtasten würde helfen).
Die Obergrenze ist \(1/(2\Delta t_\text{ab})\). Mit 10 ns Abtastschritt reicht das Raster bis 50 MHz. Der Grund ist ein alter Bekannter: Die schnellste Schwingung, die eine Abtastreihe darstellen kann, ist die mit zwei Messwerten pro Periode — plus, minus, plus, minus. Das ist der Zickzack aus Kapitel 8, diesmal in der Zeit statt im Raum (sein offizieller Name ist Nyquist-Grenze; Ü 10.2 zieht die Parallele sauber durch).
Beide Regeln kannst du in dieser Live-Zelle am eigenen Messdesign erleben (editierbar, Run-Knopf oder Strg+Enter). Zwei Töne, 1,0 und 1,15 MHz, Aufnahmedauer 5 µs: ein verschmierter Buckel. Sage vorher an, ab welcher Dauer die Auflösung \(1/T\) die beiden trennt — und prüfe dann den Gegenversuch: Hilft stattdessen zehnmal schnelleres Abtasten (DT_AB = 1e-9) bei kurzer Dauer?
Dieselbe erste Regel noch einmal als geführter Film: Die Aufnahme wächst Bild für Bild von 1 auf 14 µs, sonst ändert sich nichts. Die gestrichelten Senkrechten markieren die wahren Töne. Sieh zu, wie der eine verschmierte Buckel erst breit bleibt, dann eine Taille bekommt und schließlich in zwei saubere Linien zerfällt — und behalte den Titel im Blick: Der Zerfall passiert genau dort, wo \(1/T\) unter den Tonabstand \(0{,}15\) MHz rutscht. (Dass die Buckelhöhe unterwegs atmet, ist keine Sorge wert: Je nach Dauer enden die zwei Töne mal gleich-, mal gegenphasig.)
Und die zweite Regel als Film — der Stroboskop-Effekt, der Wagenräder im Western rückwärts drehen lässt. Der graue Ton ist immer derselbe (3 MHz); was sich ändert, ist allein die Abtastrate, die Bild für Bild sinkt. Solange sie über der Nyquist-Grenze \(2f = 6\) MHz liegt, zeichnen die Punkte die wahre Welle nach. Darunter passiert das Heimtückische: Die Punkte liegen weiter brav auf dem grauen Ton — aber sie liegen genauso exakt auf der roten, viel langsameren Welle, und nur die kann eine Auswertung aus ihnen lesen. Der Titel verrät, welche Frequenz die Punkte „behaupten”.
Code der Animation (nur in der HTML-Fassung)
# von oben: np, pltfrom matplotlib import animationfrom IPython.display import HTMLF0_A =3e6# der wahre TonT_BLICK =2e-6# festes Zeitfenstert_fein = np.linspace(0, T_BLICK, 1200)FA_REIHE = np.linspace(16e6, 3.4e6, 40) # Abtastrate sinktfig_a, ax_a = plt.subplots(figsize=(6.8, 3.2))ax_a.plot(t_fein *1e6, np.sin(2* np.pi * F0_A * t_fein), color="0.75", lw=1.2, label="wahrer Ton (3 MHz)")alias_l, = ax_a.plot([], [], "--", color="tab:red", lw=1.4, label="was die Punkte behaupten")punkte, = ax_a.plot([], [], "o", color="tab:blue", ms=5, label="Abtastwerte")ax_a.set_ylim(-1.35, 1.75)ax_a.set_xlabel("t (µs)"); ax_a.set_ylabel("Signal")ax_a.legend(fontsize=7, ncol=3, loc="upper center")def zeichne(j): fa = FA_REIHE[j] ta = np.arange(0, T_BLICK, 1/ fa) punkte.set_data(ta *1e6, np.sin(2* np.pi * F0_A * ta)) k =round(F0_A / fa) # nächstes Raster-Vielfaches f_alias = F0_A - k * fa # was vom Ton übrig scheintif k >=1: # unterhalb von Nyquist: Alias! alias_l.set_data(t_fein *1e6, np.sin(2* np.pi * f_alias * t_fein)) urteil =f"Punkte behaupten {abs(f_alias) /1e6:.2f} MHz!"else: alias_l.set_data([], []) urteil ="Punkte zeigen den wahren Ton" ax_a.set_title(f"Abtastrate {fa /1e6:4.1f} MHz "f"(Nyquist-Grenze: 6 MHz) — {urteil}", fontsize=10)return [punkte, alias_l]anim = animation.FuncAnimation(fig_a, zeichne, frames=len(FA_REIHE), interval=140)plt.close(fig_a)HTML(anim.to_jshtml(default_mode="loop"))
10.3 Der Chor, sichtbar gemacht
Kapitel 8 hat behauptet, ein schmaler Puls sei „ein Chor aus vielen Sinuswellen, die exakt im Takt starten” — und die Präzisierung auf dieses Kapitel vertagt. Jetzt ist das eine Messung von drei Zeilen: Wir nehmen zwei Gauß-Pulse verschiedener Breite als Zeitsignale und halten sie in den Detektor.
WichtigVorhersage-Punkt
Zwei Gauß-Pulse, einer 50 ns breit, einer 200 ns: Welcher von beiden braucht den größeren Chor — das breitere Spektrum?
Und was wäre demnach das Extrem — welches Zeitsignal bräuchte alle Frequenzen gleich stark? Die Messung:
Abbildung 10.2: Die Spektren zweier Gauß-Pulse (auf gleiche Höhe normiert). Der viermal schmalere Puls (blau, 50 ns) braucht den viermal breiteren Chor: Sein Spektrum reicht bis über 10 MHz, das des gemütlichen 200-ns-Pulses (orange) ist schon bei 3 MHz praktisch leer. Je schärfer ein Signal in der Zeit, desto mehr Frequenzen stecken darin.
Der schmale Puls hat das breite Spektrum — Zeitschärfe wird mit Frequenzbreite bezahlt, und im Grenzfall braucht ein unendlich scharfer Knall alle Frequenzen. (Dieses Tauschgeschäft ist übrigens dasselbe, das in der Quantenmechanik als Unschärferelation Berühmtheit erlangt hat — dort zwischen Ort und Impuls. Bei uns bleibt es Handwerkszeug.) Damit ist auch die Schleppe aus Kapitel 8 vollständig erklärt: Der schmale Puls ist ein breiter Chor, das grobe Gitter lässt dessen hohe Stimmen langsamer laufen, und sie tröpfeln hinterher.
Für die Simulationspraxis ist der Chor aber vor allem eines: ein Werkzeug. Wer einen Resonator, ein Filter oder eine Antenne bei tausend Frequenzen kennenlernen will, muss nicht tausendmal simulieren — ein Puls fragt alle tausend gleichzeitig.
10.4 Ein Lauf, alle Resonanzen
Das Glocken-Experiment, jetzt elektromagnetisch. Der Versuchsaufbau: Die Bühne ist ein Resonator — die 1D-Strecke aus den Kapiteln 5–8, diesmal \(L = 1\) m lang und an beiden Enden mit PEC-Spiegeln verschlossen (die stehende Welle aus Kapitel 6 hat es vorgemacht: Zwischen zwei Spiegeln passen nur Schwingungsmuster, deren Knoten auf die Wände fallen). Die Analytik dazu ist Schulrechnung: In die Länge \(L\) passen \(m\) Halbwellen, \(\lambda_m = 2L/m\), also liegen die Resonanzen am Kamm
\[f_m = m \cdot \frac{c}{2L} \approx m \cdot 150\ \text{MHz},
\qquad m = 1, 2, 3, \dots\]
Das Gitter hat \(\Delta x = 2\) cm (51 Punkte) und läuft bewusst mit \(S = 0{,}5\) — nicht mit dem magischen Zeitschritt: Wir wollen sehen, was die Gitterdispersion aus Kapitel 8 mit den Resonanzen anstellt. Die Anregung: der Glockenschlag — eine weiche Quelle bei \(x = 0{,}32\) m gibt einen sehr kurzen Gauß-Puls ab (\(\tau = 0{,}1\) ns; nach dem Chor-Befund deckt der alle Frequenzen bis über 2,5 GHz ab). Quelle wie Sonde (bei \(x = 0{,}74\) m) sitzen absichtlich an krummen Orten: Wer auf einem Knoten einer Mode sitzt, kann sie weder anregen noch hören (Ü 10.1 macht daraus ein Experiment). Gemessen wird das E-Feld an der Sonde, jeden Zeitschritt, über \(2^{17} \approx 131\,000\) Schritte (4,4 µs — lange Aufnahme, feines Raster: \(\Delta f = 229\) kHz). Danach eine einzige FFT. Erwartung: Peaks auf dem Kamm \(m \cdot 150\) MHz — und wer Kapitel 8 ernst nimmt, erwartet die hohen Moden nicht ganz dort.
WichtigVorhersage-Punkt
Mode 15 hat \(\lambda = 13{,}3\) cm — auf dem 2-cm-Gitter sind das nur 6,7 Punkte pro Wellenlänge. Wird ihr Peak rechts oder links der Kammlinie \(15 \cdot f_1\) liegen? Und um grob wie viel Prozent? (Kapitel 8, Faustregel-Tabelle, hilft.)
# von oben: nichts Neues nötig — der Resonator wird hier gebautfrom scipy.constants import cL =1.0# Resonatorlänge (m)N_RES =51# Δx = 2 cmS =0.5# bewusst NICHT magisch (Kap. 8)DT = S * (L / (N_RES -1)) / cdef resonator_aufnahme(schritte, quellidx=16, sondenidx=37):"""Glockenschlag in den PEC-Resonator; Sonde zeichnet jeden Schritt auf.""" e, u = np.zeros(N_RES), np.zeros(N_RES -1) # u = c·B (Kap. 7-9) tau, t0 =0.1e-9, 0.6e-9# np.empty: Array OHNE Anfangswerte (schneller als zeros) — nur# benutzen, wenn ohnehin jeder Eintrag gleich beschrieben wird aufnahme = np.empty(schritte)for n inrange(schritte): u -= S * np.diff(e) e[1:-1] -= S * np.diff(u) e[quellidx] += np.exp(-((n * DT - t0) / tau)**2) aufnahme[n] = e[sondenidx]return aufnahmeSCHRITTE =2**17aufnahme = resonator_aufnahme(SCHRITTE)spektrum = np.abs(np.fft.rfft(aufnahme))fr = np.fft.rfftfreq(SCHRITTE, DT)f1 = c / (2* L)def f_dispersion(m):"""Kap.-8-Formel: die Gitterfrequenz der Mode m (kΔx = mπ/(N−1)).""" k_dx = m * np.pi / (N_RES -1)return2* np.arcsin(S * np.sin(k_dx /2)) / (2* np.pi * DT)fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(7.0, 5.2))ax1.plot(fr /1e9, spektrum, lw=0.8)for m inrange(1, 17): ax1.axvline(m * f1 /1e9, color="gray", ls=":", lw=0.7)ax1.set_xlim(0, 2.5)ax1.set_xlabel("Frequenz (GHz)"); ax1.set_ylabel("|Spektrum|")ax2.plot(fr /1e9, spektrum, lw=1.0)ax2.axvline(15* f1 /1e9, color="gray", ls=":", lw=1.2, label="Kamm: 15·c/2L")ax2.axvline(f_dispersion(15) /1e9, color="tab:red", ls="--", lw=1.2, label="Dispersionsformel (Kap. 8)")ax2.set_xlim(2.10, 2.32); ax2.set_ylim(0, 1.3* spektrum[ (fr >2.1e9) & (fr <2.32e9)].max())ax2.set_xlabel("Frequenz (GHz)"); ax2.set_ylabel("|Spektrum|")ax2.legend(fontsize=8)plt.tight_layout(); plt.show()print("Mode Peak (GHz) Kamm m·f1 Kap.-8-Formel Drift")for m in (1, 5, 10, 15): f_theo = f_dispersion(m) maske = (fr > f_theo -0.4* f1) & (fr < f_theo +0.4* f1) f_peak = fr[maske][np.argmax(spektrum[maske])]print(f" {m:2}{f_peak/1e9:.5f}{m*f1/1e9:.5f} "f"{f_theo/1e9:.5f}{100*(f_peak/(m*f1)-1):+.2f} %")
Abbildung 10.3: Oben: das Spektrum der Sonde nach einem einzigen Pulslauf — jeder Peak eine Resonanz; die gepunkteten Linien sind der analytische Kamm m·c/2L. Tiefe Moden sitzen exakt auf ihren Linien, hohe driften zunehmend nach links. Unten der Zoom auf Mode 15: Der Peak liegt 2,8 % unter der Kammlinie (gepunktet) — aber haargenau auf der Vorhersage der Dispersionsformel aus Kapitel 8 (gestrichelt): Diese Mode hat nur 6,7 Gitterpunkte pro Wellenlänge und schwingt deshalb zu langsam.
Ein einziger Lauf, und der Resonator hat sein komplettes Zeugnis abgelegt: sechzehn Resonanzen in einem Bild. Die tiefen Moden treffen den analytischen Kamm aufs Raster genau — und die hohen erzählen die Geschichte aus Kapitel 8 weiter: Mode 10 schwingt \(1{,}25\,\%\) zu tief, Mode 15 schon \(2{,}8\,\%\), denn ihre kurzen Wellen laufen auf dem groben Gitter zu langsam, und wer zu langsam läuft, schwingt zu selten. Das Bemerkenswerte steht in der Tabellenspalte daneben: Die Dispersionsformel aus Kapitel 8 sagt jeden dieser „Fehler” auf weniger als ein Hundertstel Prozent voraus. Der Fehler ist kein Rauschen — er ist berechenbar. Genau darauf baut der Rest des Kapitels.
10.5 Vertrauen ist messbar
WarnungNaheliegende Vermutung
„Die Simulation ist stabil durchgelaufen, die Bilder sehen physikalisch vernünftig aus — also kann ich den Zahlen glauben.”
Warum sie naheliegt: Instabilität macht sich unübersehbar bemerkbar (Kapitel 7–9: Explosionen um dreißig Größenordnungen), und unsere Bilder sind ja oft korrekt — Ringwellen laufen mit \(c\), Knoten sitzen im \(\lambda/2\)-Raster. Wenn das Grobe stimmt, warum nicht auch das Feine?
Was stattdessen stimmt: Stabil heißt nur „explodiert nicht” (Kapitel 7: stabil ≠ genau), und plausibel heißt nur „qualitativ richtig”. Eine Simulation kann beides sein und trotzdem quantitativ wertlos — der Resonator eben war stabil und plausibel und lag bei Mode 15 um 2,8 % daneben; wer danach ein Filter gebaut hätte, hätte Schrott gebaut. Dieses Buch verdankt einer solchen Erfahrung eine seiner Lektionen: Ein zu grob aufgelöstes 2D-Modell einer Yagi-Antenne lieferte wunderschöne, plausible Richtdiagramme — und Elementabstände, die um Dutzende Prozent unbaubar waren. Vertrauen entsteht nicht durch Anschauen, sondern durch Messen des eigenen Fehlers. Wie, zeigen die nächsten zwei Experimente.
Werkzeug 1: der Vergleich mit der Analytik. Den haben wir eben schon benutzt — der Modenkamm \(f_m = m\,c/2L\) ist exakte Mathematik, und die Abweichung der Simulation davon ist ihr gemessener Fehler. Das Schema ist allgemein: Man sucht sich einen Spezialfall des Problems, für den die exakte Antwort bekannt ist (ein Resonator, eine Kugel, ein unendlicher Draht …), und lässt das Programm gegen die Wahrheit antreten. Besteht es dort, darf man ihm auch dazwischen etwas glauben.
Werkzeug 2: der Konvergenztest. Oft gibt es keine Analytik — genau dafür simuliert man ja. Dann bleibt die Frage: Ändert sich das Ergebnis noch, wenn ich feiner rechne? Der Versuchsaufbau: Bühne ist derselbe Resonator, aber als Anfangsbedingung legen wir direkt die Mode 3 hinein (\(E = \sin(3\pi x/L)\), \(u = 0\)) — sie schwingt dann allein, ohne Chor, und die Sonde an ihrem Bauch bei \(L/2\) liefert einen reinen Sinuston. Gemessen wird dessen Frequenz, und zwar nicht per FFT (deren Raster wäre hier zu grob), sondern mit der Nulldurchgangs-Methode aus Kapitel 8 — diesmal entlang der Zeitachse: Abstand der Nulldurchgänge, gemittelt über Hunderte Perioden, ergibt die Periodendauer auf sechs Stellen. Die Leiter: Wir messen dreimal, mit \(\Delta x = 5\) cm, \(2{,}5\) cm und \(1{,}25\) cm (bei festem \(S = 0{,}5\)), und vergleichen jeweils mit dem analytischen \(f_3 = 3\,c/2L\). Erfolgskriterium (Kapitel 2 und Ü 8.3 lassen grüßen): Halbiert sich \(\Delta x\), muss der Fehler auf ein Viertel fallen — das ist die Handschrift der zweiten Ordnung, und nur ein Verfahren, das ihr folgt, ist im sauberen Konvergenz-Regime.
# von oben: L, S, f_dispersion()-Idee; c (Import)def mode3_frequenz(n_punkte, schritte=40000):"""Mode 3 schwingen lassen; Frequenz über Nulldurchgänge der Sonde.""" x = np.linspace(0, L, n_punkte) e = np.sin(3* np.pi * x / L) # die Mode als Anfangsbild u = np.zeros(n_punkte -1) dt = S * (L / (n_punkte -1)) / c sonde = np.empty(schritte)# np.argmin: der INDEX des kleinsten Werts (Gegenstück zu np.argmax,# Kap. 5) — hier: welcher Gitterpunkt liegt am nächsten an L/2? bauch = np.argmin(np.abs(x -0.5)) # Bauch der Mode 3for n inrange(schritte): u -= S * np.diff(e) e[1:-1] -= S * np.diff(u) sonde[n] = e[bauch] i = np.flatnonzero(np.sign(sonde[:-1]) * np.sign(sonde[1:]) <0) null = i - sonde[i] / (sonde[i +1] - sonde[i]) # wie in Kap. 8return1/ (2* np.mean(np.diff(null)) * dt)f3 =3* c / (2* L)print(f"Mode 3 analytisch: {f3/1e6:.3f} MHz\n")fehler, gitter = [], []for n_punkte in (21, 41, 81): f_mess = mode3_frequenz(n_punkte) dx_cm =100* L / (n_punkte -1) fehler.append(1- f_mess / f3) gitter.append(dx_cm)print(f"Δx = {dx_cm:5.2f} cm: gemessen {f_mess/1e6:.4f} MHz,"f" Fehler {100*fehler[-1]:.4f} %")print(f"\nFehler-Quotienten je Halbierung: "f"{fehler[0]/fehler[1]:.2f} und {fehler[1]/fehler[2]:.2f} (Soll: 4)")fig, ax = plt.subplots(figsize=(5.6, 3.2))ax.loglog(gitter, [100* f for f in fehler], "o-", ms=7, label="gemessener Fehler")ax.loglog(gitter, [100* fehler[0] * (g / gitter[0])**2for g in gitter],"k:", label="2. Ordnung (∝ Δx²)")ax.set_xlabel("Δx (cm)"); ax.set_ylabel("Frequenzfehler (%)")ax.legend()plt.tight_layout(); plt.show()
Abbildung 10.4: Die Konvergenzleiter: der Frequenzfehler der Mode 3 gegen die Gitterweite, doppelt-logarithmisch. Die Messpunkte fallen exakt auf die Gerade „Fehler ∝ Δx²” (gepunktet als eingezeichnete Erwartung): halbe Zelle, ein Viertel Fehler. Wer einen vierten Punkt will, weiß jetzt, wo er liegen wird — das ist der Unterschied zwischen Hoffen und Wissen.
Quotienten von \(4{,}01\) und \(4{,}00\) — das Verfahren konvergiert lehrbuchhaft mit zweiter Ordnung gegen die Analytik. Und es kommt noch besser: Die gemessenen Fehler (\(0{,}696\), \(0{,}174\), \(0{,}043\,\%\)) sind exakt die Werte, die die Dispersionsformel aus Kapitel 8 für diese drei Gitter vorhersagt — auf vier Stellen. Der Fehler dieser Simulation ist damit kein dunkler Rest, sondern eine verstandene, vorhersagbare, kontrollierbare Größe. Mehr kann man von einer numerischen Methode nicht verlangen.
Für die Praxis genügt die abgespeckte Form des Tests, und sie ist jede Rechenzeit wert: Jede wichtige Zahl zweimal rechnen — einmal normal, einmal mit halbem \(\Delta x\). Fällt der Unterschied auf etwa ein Viertel des Unterschieds zur nächstgröberen Stufe, ist man im Konvergenz-Regime und kennt obendrein die Größenordnung des Restfehlers. Ändert sich die Zahl dagegen munter weiter, ist das Ergebnis noch keine Physik, sondern Gitterkunst.
10.6 Die Checkliste
Die Vertrauensfrage, als Arbeitsprogramm vor jedem Ernstfall — jede Zeile haben wir inzwischen selbst durchexerziert:
Prüfung
Werkzeug
eingeführt
Bleibt erhalten, was erhalten bleiben muss?
Energie-Schiedsrichter
Kap. 5
Stimmt ein analytisch lösbarer Spezialfall?
z. B. Modenkamm \(m\,c/2L\)
Kap. 10
Konvergiert das Ergebnis mit 2. Ordnung?
\(\Delta x\) halbieren, Fehler vierteln
Kap. 10
Ist die kürzeste Wellenlänge aufgelöst?
10–20 Punkte pro \(\lambda\), Laufstrecke zählt
Kap. 8
Stören die Ränder?
Echo messen (Rest nach Durchgang)
Kap. 6/9
Sagt ein unabhängiges Werkzeug dasselbe?
Querrechnen (MoM vs. FDTD …)
Teil III
Die letzte Zeile ist die Königsdisziplin und der eigentliche Grund für Teil III: Wer dasselbe Problem mit zwei grundverschiedenen Methoden rechnet und zweimal dieselbe Antwort bekommt, hat mehr bewiesen als jede Einzelrechnung. Die Yagi-Antenne aus der Refutation oben wurde am Ende genau so gerettet — entworfen mit der Momentenmethode, gegengerechnet mit einem zweiten Feldlöser, und erst, als beide übereinstimmten, gebaut. Diese Geschichte erzählt Kapitel 11 zu Ende.
10.7 Das Kapitel-Programm
programme/kap10/kap10_spektren_vertrauen.py bündelt alle vier Befunde eigenständig und prüft sie mit assert-Schranken: Detektor findet \(1{,}0/0{,}5\) und schweigt bei 4 MHz (\(< 10^{-12}\)); Hand-Detektor = rfft (\(< 10^{-12}\)); Halbwertsbreiten-Verhältnis der Pulsspektren \(\approx 4\); jeder Resonanz-Peak auf der Dispersionsformel (\(< 10^{-3}\) relativ); Konvergenzquotienten in \([3{,}6,\ 4{,}4]\) und Messung = Formel (\(< 10^{-4}\)).
TippMerkkasten
Ein Spektrum ist Multiplizieren und Mitteln: \(2\langle s
\cdot \sin\rangle\) und \(2\langle s\cdot\cos\rangle\) je Testfrequenz; fremde Frequenzen mitteln sich weg (Additionstheorem). np.fft.rfft rechnet exakt das — schnell.
Auflösung = 1/Aufnahmedauer; Obergrenze = 1/(2·Abtastschritt) (Nyquist — der Zickzack in der Zeit). Länger messen trennt Frequenzen, schneller abtasten hebt nur die Decke.
Schmal in der Zeit = breit im Spektrum. Darum vermisst ein Pulslauf alle Resonanzen zugleich — das Arbeitspferd jedes FDTD-Workflows.
Stabil ≠ plausibel ≠ richtig. Vertrauen kommt aus Messung: Analytik-Vergleich, Konvergenztest (halbes \(\Delta x\) → ein Viertel Fehler), Erhaltungsgrößen, Rand-Echos, Querrechnen — die Checkliste.
Der Fehler einer guten Simulation ist berechenbar statt geheimnisvoll: Unsere Resonanz-Drifts trafen die Kapitel-8-Formel auf vier Stellen.
Roter Faden
Dieses Kapitel hat vor allem Schulden beglichen: Der Chor aus Kapitel 8 ist jetzt eine Messung, seine Dispersionsformel wurde zum Frequenz-Orakel für ganze Resonatoren, die Nulldurchgangs-Methode wanderte vom Raum in die Zeit, der Zickzack kehrte als Nyquist-Grenze wieder, und die stehende Welle aus Kapitel 6 wurde zum Messobjekt. Nach vorn ist der Weg jetzt frei für Teil III: Kapitel 11 stellt die professionellen Löser vor — in deren Inneren du DFT-Monitore, PML-Ränder und Konvergenz-Knöpfe wiedererkennen wirst, denn du hast jedes dieser Teile selbst gebaut. Kapitel 14 (Interferenz) und Kapitel 15 (Resonanz und Güte) leben dann ganz von Spektren — dort bekommen die Peaks auch endlich eine Breite, und die erzählt von Verlusten.
Übungen
Ü 10.1 (Verstehen). Im Resonator-Experiment saßen Quelle und Sonde an „krummen” Orten. Sage ohne Rechnung voraus, was im Spektrum passiert, wenn die Quelle stattdessen exakt in die Mitte des Resonators gesetzt wird — welche Moden verschwinden, und warum? Prüfe dann nach.
HinweisMusterlösung zu Ü 10.1
Die Mitte ist für jede gerade Mode ein Knoten: Mode \(m\) hat die Form \(\sin(m\pi x/L)\), und bei \(x = L/2\) ist \(\sin(m\pi/2) = 0\) für \(m = 2, 4, 6, \dots\) Eine weiche Quelle addiert ihr Signal an einem Ort — wo eine Mode einen Knoten hat, ist sie taub für jede Anregung (genau wie eine Gitarrensaite, die man am zwölften Bund anschlägt, keine Oktav-Obertöne bekommt). Die geraden Moden müssen also aus dem Spektrum verschwinden:
Die Moden 2 und 4 sind um mehr als einen Faktor 100 eingebrochen — übrig bleibt nur, was Rundungsreste anregen. Dieselbe Logik gilt für die Sonde: Sie ist blind für Moden, auf deren Knoten sie sitzt. Quelle und Sonde krumm zu platzieren ist also keine Marotte, sondern Messtechnik.
Ü 10.2 (Verstehen). Begründe die Nyquist-Grenze \(f_{\max} = 1/(2\Delta t_\text{ab})\) mit dem Zickzack-Argument aus Kapitel 8 — und erkläre dann, warum eine Abtastreihe einen Ton oberhalb dieser Grenze nicht einfach übersieht, sondern als falschen tieferen Ton meldet. (Denkhilfe: Was zeigen die Messwerte, wenn zwischen zwei Abtastungen mehr als eine halbe Schwingung vergeht?)
HinweisMusterlösung zu Ü 10.2
Das schnellste Muster, das eine Wertereihe im Abstand \(\Delta t_\text{ab}\) darstellen kann, ist der Wechsel plus–minus–plus–minus: zwei Werte pro Periode, also die Periode \(2\Delta t_\text{ab}\) und damit die Frequenz \(1/(2\Delta t_\text{ab})\) — wörtlich der Zickzack aus Kapitel 8, nur dass die „Gitterpunkte” jetzt Zeitpunkte sind. Ein schnellerer Ton verschwindet aber nicht: Die Abtastung erwischt von jeder Schwingung nur Momentaufnahmen, und wenn zwischen zwei Aufnahmen fast eine ganze Periode vergeht, sehen die Messwerte aus, als schwänge dort etwas ganz Langsames (derselbe Effekt lässt im Film Wagenräder rückwärts laufen, wenn die Bildrate nicht mitkommt). Der zu schnelle Ton wird also unter falschem Namen einsortiert — Aliasing. Darum steht vor jedem ernsthaften Abtasten ein Tiefpassfilter, das alles oberhalb der Nyquist-Grenze entfernt, bevor es lügen kann.
Ü 10.3 (Verändern). Zwei Töne, 3,0 und 3,5 MHz, sollen im Spektrum getrennt werden. Die 1-µs-Aufnahme von oben schafft das nicht (\(\Delta f = 1\) MHz). Probiere beide Auswege aus: (a) viermal schneller abtasten (gleiche Dauer), (b) viermal länger aufnehmen (gleicher Abtastschritt). Welcher hilft?
Nur das längere Aufnehmen trennt die beiden Töne (rechtes Bild: zwei saubere Spitzen im Abstand 0,5 MHz, denn jetzt ist \(\Delta f = 1/4\,\text{µs} = 0{,}25\) MHz). Das schnellere Abtasten (Mitte) liefert exakt denselben verschmierten Buckel wie das Original — es verlängert das Frequenzraster nach oben (bis 200 MHz), macht es aber kein bisschen feiner. Auflösung kauft man mit Zeit, nicht mit Abtastrate: In 1 µs schwingt der eine Ton 3-mal, der andere 3,5-mal — ein halber Schwingungsunterschied ist schlicht zu wenig Beweismaterial, egal wie dicht man hinschaut.
Ü 10.4 (Übertragen). Die Detektivaufgabe: Die Zelle unten baut eine „unbekannte” Messreihe — drei Sinustöne plus kräftiges Rauschen; im Zeitsignal ist mit bloßem Auge nichts zu erkennen. Bestimme Frequenzen und Amplituden der drei Töne.
Peak bei 2.5 MHz: Amplitude 0.787
Peak bei 7.0 MHz: Amplitude 0.428
Peak bei 11.5 MHz: Amplitude 0.222
Im Zeitsignal: Rauschteppich. Im Spektrum: drei unübersehbare Spitzen bei 2,5, 7 und 11,5 MHz, deren Höhen die wahren Amplituden (0,8/0,4/0,25) bis auf wenige Hundertstel treffen — sogar der leiseste Ton, der im Zeitsignal komplett unter dem Rauschen liegt. Der Trick ist derselbe wie im ganzen Kapitel: Der Detektor mittelt, und Rauschen, das mit keiner Testfrequenz im Takt ist, mittelt sich weg, während ein Ton Periode für Periode aufsummiert. Genau deshalb funktioniert Funkempfang unterhalb des Rauschens, GPS zum Beispiel — und genau deshalb ist die FFT das vielleicht meistbenutzte Stück Numerik der Welt.