26  Photonische Kristalle und Bandlücken

Der Morpho-Falter aus Südamerika leuchtet in einem Blau, das kein Farbstoff der Welt hinbekommt — metallisch, fast grell, über hundert Meter sichtbar. Das Verblüffende: In seinen Flügeln steckt kein blaues Pigment. Zerreibt man eine Flügelschuppe, bleibt unscheinbares Braun zurück. Die Farbe sitzt nicht in der Chemie, sondern in der Geometrie: Die Schuppen tragen Lamellen aus Chitin, gestapelt im Abstand von etwa einem Zehntel Mikrometer. Eine Struktur, die sich im Takt der Lichtwellenlänge wiederholt, wirft eine Farbe komplett zurück und lässt die anderen passieren.

Dieselbe Idee, nur präziser gefertigt, sitzt in jedem Laser: Seine Endspiegel müssen besser reflektieren als jedes polierte Metall — und bestehen ausgerechnet aus durchsichtigen Glasschichten. In diesem Kapitel bauen wir solche Strukturen nach: erst den Schichtstapel, der zum nahezu perfekten Spiegel wird, dann den zweidimensionalen Kristall aus dielektrischen Stäbchen, der ein ganzes Frequenzband in allen Richtungen sperrt — eine photonische Bandlücke. Und zum Schluss nutzen wir das Verbot konstruktiv: Ein fehlender Stab wird zur Lichtleitung, die um eine 90°-Ecke führt, ohne dass nennenswert etwas verloren geht.

Damit eröffnet dieses Kapitel den Teil VII des Buchs: Es geht nicht mehr darum, Wellen zu erzeugen (Teil VI), sondern darum, was periodische Strukturen mit ihnen anstellen.

Lernziele

Nach diesem Kapitel kannst du …

  1. … erklären, warum viele schwache Echos einen fast perfekten Spiegel ergeben (λ/4-Bedingung: alle Echos in Phase) — und du hast es in Meep nachgemessen (\(T = 10^{-3}\) bei acht Schichtpaaren),
  2. … die Transfer-Matrix eines Schichtstapels aufstellen (eine 2×2-Matrix pro Schicht, Matrixprodukt für den Stapel) und damit \(T(f)\) exakt vorhersagen,
  3. … das Spurkriterium \(|\mathrm{Tr}\,M| \le 2\) anwenden: erlaubte Bänder und verbotene Lücken im Banddiagramm \(\omega(K)\) — und du erkennst darin die Mathematik der Stabilitätsanalyse aus Kapitel 8 wieder,
  4. … begründen, warum ein Stapel nur senkrecht sperrt, ein 2D-Kristall aber alle Richtungen — und hast die volle Bandlücke des Stäbchengitters als Schnittmenge zweier Stoppbänder gemessen (0,32–0,44 in Einheiten \(f a/c\)),
  5. … Defekte als Werkzeug einsetzen: die fehlende Stabreihe als Wellenleiter, der Licht verlustarm um die Ecke führt, und den fehlenden Einzelstab als Resonator,
  6. … Strukturfarben (Morpho, Opal) quantitativ erklären — inklusive des Schillerns beim Schrägblick.

26.1 Viele schwache Echos, ein starker Spiegel

Fangen wir bei einer alten Bekannten an: der Grenzfläche. Seit Kapitel 6 wissen wir, was eine einzelne Glasoberfläche mit einer senkrecht auftreffenden Welle macht — sie wirft den Bruchteil

\[ r = \frac{n_1 - n_2}{n_1 + n_2} \]

der Amplitude zurück. Für Luft auf Glas (\(n = 1{,}5\)) sind das \(r = -0{,}2\), also magere 4 % der Leistung — das schwache Spiegelbild im Schaufenster. Eine einzelne Grenzfläche ist ein erbärmlicher Spiegel.

Aber niemand zwingt uns, bei einer zu bleiben. Wir stapeln zwei Materialien im Wechsel — in diesem Kapitel durchgehend \(n_1 = 1{,}5\) (Glas) und \(n_2 = 2{,}5\) (ein hochbrechendes Material wie Titandioxid) — und fragen: Was machen die vielen Echos miteinander? Kapitel 14 hat die Antwort im Prinzip schon gegeben: Es kommt nicht auf die Zahl der Echos an, sondern auf ihre Phasen. Und an den Phasen können wir drehen, denn sie hängen an den Schichtdicken.

Der Trick heißt λ/4-Stapel und ist die Umkehrung eines Bausteins aus Kapitel 22: Dort haben wir mit dem λ/4-Transformator Echos gegeneinander ausgelöscht (Antireflex); jetzt schalten wir sie in Reihe. Zwei Zutaten greifen ineinander:

  • Die Vorzeichen wechseln mit. An jedem Übergang niedrig → hoch ist \(r < 0\), an jedem Übergang hoch → niedrig ist \(r > 0\). Benachbarte Grenzflächen reflektieren also gegenphasig — bevor wir den Laufweg einrechnen.
  • Der Laufweg dreht die Phase zurück. Macht jede Schicht (optisch) genau eine Viertelwellenlänge dick, \(n_j d_j = \lambda_0/4\), dann sammelt das Echo von der nächsten Grenzfläche eine Hin-und-zurück-Verzögerung von \(\lambda_0/2\) ein — eine halbe Periode, Faktor \(-1\).

Minus mal minus: Beide Effekte zusammen bringen alle Echos exakt in Phase. Jede weitere Grenzfläche zahlt auf dasselbe Konto ein. Rechnen wir das Konto kurz von Hand an: Bei \(n_1 = 1{,}5\) und \(n_2 = 2{,}5\) ist jedes Einzelecho

\[ |r| = \frac{2{,}5 - 1{,}5}{2{,}5 + 1{,}5} = \frac{1}{4}, \]

und acht Schichtpaare haben 16 Grenzflächen. Würden sich die Amplituden einfach aufsummieren, stünden \(16 \cdot 0{,}25 = 4\) auf dem Zettel — das Vierfache der einlaufenden Welle, also offensichtlicher Unsinn. Die naive Buchhaltung bricht zusammen, weil jedes Echo unterwegs an allen anderen Grenzflächen erneut gestreut wird. Was wirklich herauskommt, muss ein Experiment zeigen (und danach eine ehrliche Theorie, die alle Mehrfach-Echos mitzählt). Eines ist aber jetzt schon klar: Die Echos verstärken sich, bis der Nachschub versiegt.

WarnungNaheliegende Vermutung: „Aus durchsichtigen Zutaten kann man keinen Spiegel bauen“

Warum sie naheliegt: Glas lässt 96 % durch. Wer durchsichtige Schichten stapelt, stapelt scheinbar Durchsichtigkeit — selbst zwanzig Flächen à 4 % „sammeln” nach dieser Logik höchstens die Hälfte des Lichts ein, und real sieht man durch zwanzig Glasscheiben ja auch hindurch.

Was stattdessen stimmt: Reflexionen addieren sich nicht wie Prozente auf einer Rechnung, sondern wie Zeiger mit Phase (Kapitel 14). Zwanzig zufällig dicke Scheiben löschen sich teilweise aus — zwanzig λ/4-gestimmte Schichten ziehen am selben Strang. Wir messen gleich: Schon acht Paare aus Glas und Titandioxid reflektieren 99,9 % — besser als poliertes Silber. Der Unterschied zwischen „durchsichtig” und „Spiegel” ist keine Materialeigenschaft, sondern eine Frage der Anordnung.

26.1.1 Der Stapel im Experiment

Das Experiment dazu, zum ersten Mal in einer 1D-Zelle: Unsere Welt ist eine einzige Achse, denn Stapel und Welle hängen nur von \(z\) ab — Meep rechnet dann nur diese Achse durch (dimensions=1), und ein kompletter Frequenz-Sweep dauert Sekunden. Frage: Wie viel Leistung lässt der Stapel bei welcher Frequenz durch? Bühne: acht Schichtpaare \(n_1 = 1{,}5 / n_2 = 2{,}5\) in λ/4-Dicken, Periode \(a = d_1 + d_2 = 1\); daraus folgt die Design-Frequenz \(f_0 = 0{,}2667\) (in Meep-Einheiten \(f a/c\)). Links und rechts Luft, an beiden Enden PML. Anfangs-/Randbedingungen: ein Gauß-Puls (Kapitel 10: ein Lauf, alle Frequenzen) startet vor dem Stapel. Messgrößen: der Leistungsfluss hinter dem Stapel, geteilt durch einen Referenzlauf ohne Stapel — exakt die \(T(f)\)-Methodik der Kapitel 12/17. Erfolgskriterium: Bei \(f_0\) müssen die Echos maximal sperren; wie breit das Sperrgebiet ist, wissen wir noch nicht — das ist die Messung.

Vorhersage-Punkt (PRIMM): Die λ/4-Bedingung gilt exakt nur bei \(f_0\). Erwartest du eine scharfe Sperr-Nadel bei \(f_0\) — oder ein breites Sperr-Band? Was passiert weit unterhalb, bei \(f \to 0\), wo der ganze Stapel viel dünner ist als eine Wellenlänge?

import numpy as np
import matplotlib.pyplot as plt
import meep as mp

mp.verbosity(0)

# --- der Lambda/4-Stapel: Periode a = 1 ---
N1, N2 = 1.5, 2.5
LAM0 = 4.0 / (1.0 / N1 + 1.0 / N2)   # n1*d1 = n2*d2 = lam0/4 und d1+d2 = 1
F0 = 1.0 / LAM0                      # Design-Frequenz 0,2667
D1 = LAM0 / (4.0 * N1)               # 0,625
D2 = LAM0 / (4.0 * N2)               # 0,375
N_PAARE = 8

AUFL = 40
DPML, LUFT = 2.0, 3.0
L_STAPEL = N_PAARE * (D1 + D2)
LZ = 2 * DPML + 2 * LUFT + L_STAPEL
FCEN, DF = 0.27, 0.42                # Puls deckt 0,06 bis 0,48 ab
NFREQ = 401


def stapel_geometrie(n_paare=N_PAARE):
    """Bloecke fuer n_paare Schichtpaare, zentriert um z = 0."""
    geom = []
    z0 = -n_paare * (D1 + D2) / 2
    for i in range(n_paare):
        za = z0 + i * (D1 + D2)
        geom.append(mp.Block(size=mp.Vector3(mp.inf, mp.inf, D1),
                             center=mp.Vector3(0, 0, za + D1 / 2),
                             material=mp.Medium(index=N1)))
        geom.append(mp.Block(size=mp.Vector3(mp.inf, mp.inf, D2),
                             center=mp.Vector3(0, 0, za + D1 + D2 / 2),
                             material=mp.Medium(index=N2)))
    return geom


def lauf_1d(geom):
    """T(f)-Messlauf: Puls rein, Fluss hinter dem Stapel."""
    sim = mp.Simulation(
        cell_size=mp.Vector3(0, 0, LZ),
        dimensions=1,                # nur die z-Achse wird gerechnet
        resolution=AUFL,
        boundary_layers=[mp.PML(DPML)],
        geometry=geom,
        sources=[mp.Source(mp.GaussianSource(FCEN, fwidth=DF),
                           component=mp.Ex,
                           center=mp.Vector3(0, 0, -LZ / 2 + DPML + 0.5))])
    z_mess = LZ / 2 - DPML - 0.5
    tr = sim.add_flux(FCEN, DF, NFREQ,
                      mp.FluxRegion(center=mp.Vector3(0, 0, z_mess)))
    sim.run(until_after_sources=mp.stop_when_fields_decayed(
        50, mp.Ex, mp.Vector3(0, 0, z_mess), 1e-9))
    return np.array(mp.get_flux_freqs(tr)), np.array(mp.get_fluxes(tr))


fs, P_ref = lauf_1d([])                       # Referenz: leere Zelle
_, P_stapel = lauf_1d(stapel_geometrie())
T_meep = P_stapel / P_ref

i0 = np.argmin(np.abs(fs - F0))
print(f"T bei f0 = {F0:.4f}:  {T_meep[i0]:.2e}")
print(f"entspricht R = {1 - T_meep[i0]:.4f}")
Using MPI version 4.1, 1 processes
T bei f0 = 0.2667:  1.14e-03
entspricht R = 0.9989

99,9 % Reflexion aus Glas und Titandioxid — und der Plot zeigt, dass die Antwort auf den Vorhersage-Punkt „Band” lautet:

# von oben: fs, T_meep, F0
fig, ax = plt.subplots(figsize=(7.0, 4.0))
ax.semilogy(fs, T_meep, "C0-", lw=1.5, label="Meep, 8 Paare")
ax.axvline(F0, color="0.4", ls="--", lw=1.2,
           label=f"Design-Frequenz $f_0$ = {F0:.3f}")
ax.set_xlim(0.05, 0.48)
ax.set_ylim(1e-4, 2)
ax.set_xlabel("Frequenz  $f\\,a/c$")
ax.set_ylabel("Transmission $T$")
ax.set_title("Die Klippe: ein verbotenes Frequenzband")
ax.legend(loc="lower right", fontsize=9)
ax.grid(alpha=0.3)
plt.show()
Abbildung 26.1: Transmission durch den 8-Paar-Stapel: kein Nadelstich, sondern eine breite Klippe rund um die Design-Frequenz (gestrichelt). Weit unterhalb ist der Stapel unsichtbar (T → 1): Dort ist er dünn gegen die Wellenlänge — die Kapitel-25-Erfahrung, von der anderen Seite gesehen.

Das ist dieselbe Sorte Klippe wie beim Hohlleiter unterhalb seiner Grenzfrequenz (Kapitel 17) — nur dass hier mitten im Spektrum ein Band ausgestanzt ist: zwischen \(f \approx 0{,}22\) und \(f \approx 0{,}31\) kommt praktisch nichts durch. Ein solches Band heißt Stoppband — und wir werden gleich verstehen, dass es der eindimensionale Vorbote einer photonischen Bandlücke ist.

Wie tief der Boden der Klippe liegt, bestimmt die Zahl der Schichtpaare. Gleicher Aufbau, gleiche Messgröße, nur \(N\) variiert — die Frage: Wie skaliert \(T(f_0)\) mit \(N\)?

Vorhersage-Punkt (PRIMM): Halbiert jedes zusätzliche Paar die Durchlässigkeit? Viertelt es sie? Tipp: Kapitel 17 — wenn in einem verbotenen Bereich „nichts laufen kann”, welche Sorte Feld lebt dann dort, und wie hängt es von der Eindringtiefe ab?

# von oben: lauf_1d(), stapel_geometrie(), fs, P_ref, F0
NS = np.array([2, 4, 6, 8, 10, 12])
T_N = []
for n in NS:
    _, P_n = lauf_1d(stapel_geometrie(n))
    T_N.append((P_n / P_ref)[np.argmin(np.abs(fs - F0))])
T_N = np.array(T_N)

for n, t in zip(NS, T_N):
    print(f"N = {n:2d} Paare:  T(f0) = {t:.3e}")
faktor_pro_paar = np.exp(np.polyfit(NS, np.log(T_N), 1)[0])
print(f"\nAbfall pro Schichtpaar: Faktor {faktor_pro_paar:.3f}")
N =  2 Paare:  T(f0) = 4.074e-01
N =  4 Paare:  T(f0) = 6.543e-02
N =  6 Paare:  T(f0) = 8.761e-03
N =  8 Paare:  T(f0) = 1.144e-03
N = 10 Paare:  T(f0) = 1.489e-04
N = 12 Paare:  T(f0) = 1.935e-05

Abfall pro Schichtpaar: Faktor 0.368

Jedes Paar drückt die Transmission um denselben Faktor 0,36 — exponentieller Abfall, das Markenzeichen evaneszenter Felder seit Kapitel 12. Im Stoppband läuft die Welle nicht durch den Stapel, sie sickert hinein und klingt von Paar zu Paar ab; was am Ende noch übrig ist, tunnelt hinaus (Kapitel 17, exakt dieselbe Physik). Merke dir die 0,36 — in Kürze sagt eine Theorie diesen Faktor ohne ein einziges Experiment voraus. Woher sie kommt, zeigt am schnellsten ein Blick auf das Feld selbst.

Der Film stellt die beiden Fälle nebeneinander — oben eine Frequenz im erlaubten Band, unten die Design-Frequenz mitten im Stoppband, beide als Dauerstrich-Läufe (der komplexe-Felder-Trick aus Kapitel 23: ein Lauf liefert das Feld zu jeder Phasenlage). Oben läuft die Welle durch den Stapel (verfolge einen Wellenberg!), unten steht vor dem Stapel eine Stehwelle aus Einfall und Echo, und im Stapel selbst bleibt nur ein atmender, exponentiell abfallender Rest — die evaneszente Welle, die pro Paar den Faktor 0,6 der Amplitude verliert (0,6² ≈ 0,36 der Leistung).

Code der Animation (nur in der HTML-Fassung)
# von oben: stapel_geometrie(), N1, N2, D1, D2, F0, N_PAARE,
#           L_STAPEL, LZ, DPML, AUFL
from matplotlib import animation
from IPython.display import HTML


def cw_feld_1d(f):
    """Eingeschwungenes komplexes Ex(z) bei Dauerstrich-Frequenz f."""
    sim = mp.Simulation(
        cell_size=mp.Vector3(0, 0, LZ), dimensions=1, resolution=AUFL,
        boundary_layers=[mp.PML(DPML)], geometry=stapel_geometrie(),
        force_complex_fields=True,
        sources=[mp.Source(mp.ContinuousSource(F0 if f is None else f),
                           component=mp.Ex,
                           center=mp.Vector3(0, 0, -LZ / 2 + DPML + 0.5))])
    sim.run(until=150)
    return sim.get_array(component=mp.Ex, center=mp.Vector3(),
                         size=mp.Vector3(0, 0, LZ - 2 * DPML))


F_BAND = 0.18
ex_band = cw_feld_1d(F_BAND)
ex_luecke = cw_feld_1d(F0)
z_film = np.linspace(-(LZ / 2 - DPML), LZ / 2 - DPML, len(ex_band))
phasen = np.linspace(0, 2 * np.pi, 16, endpoint=False)

fig, (a1, a2) = plt.subplots(2, 1, figsize=(7.2, 5.2), sharex=True)
linien = []
y_max = 1.15 * max(np.abs(ex_band).max(), np.abs(ex_luecke).max())
for a, ex, beschr in [(a1, ex_band, f"f = {F_BAND} — im erlaubten Band"),
                      (a2, ex_luecke, f"f = {F0:.3f} — im Stoppband")]:
    z0 = -L_STAPEL / 2
    for i in range(N_PAARE):           # Stapel als graue Streifen
        a.axvspan(z0 + i, z0 + i + D1, color="0.92")
        a.axvspan(z0 + i + D1, z0 + i + 1, color="0.78")
    ln, = a.plot(z_film, np.real(ex), "C0-", lw=1.5)
    linien.append(ln)
    a.set_ylim(-y_max, y_max)
    a.set_ylabel("$E_x$")
    a.text(0.02, 0.05, beschr, transform=a.transAxes, fontsize=9)
a2.set_xlabel("z (Stapel: graue Streifen, dunkel = $n_2$)")
titel = a1.set_title("", fontsize=10)
fig.subplots_adjust(top=0.9, hspace=0.15)


def bild(i):
    zeiger = np.exp(-1j * phasen[i])
    linien[0].set_ydata(np.real(ex_band * zeiger))
    linien[1].set_ydata(np.real(ex_luecke * zeiger))
    titel.set_text("Durchlaufen oder abklingen?\n"
                   f"t = {phasen[i] / (2 * np.pi):.2f} Perioden")
    return linien + [titel]


anim = animation.FuncAnimation(fig, bild, frames=len(phasen),
                               interval=140)
plt.close(fig)
HTML(anim.to_jshtml(default_mode="loop"))

26.2 Die Transfer-Matrix: alle Echos auf einmal

Die naive Echo-Summe ist vorhin an den Mehrfachreflexionen gescheitert. Die ehrliche Rechnung gibt es trotzdem — und sie ist überraschend billig. Die Idee: Wir fragen nicht „welche Echos entstehen wo?“, sondern „was macht eine Schicht mit den Feldern an ihrem Rand?“ In einer Schicht leben genau zwei Unbekannte (eine hinlaufende und eine rücklaufende Teilwelle), und \(E\) und \(H\) an der Hinterkante hängen linear an denen der Vorderkante. Lineare Abbildung von zwei Zahlen auf zwei Zahlen — das ist eine 2×2-Matrix:

\[ \begin{pmatrix} E \\ Z_0 H \end{pmatrix}_{\text{hinten}} = \underbrace{\begin{pmatrix} \cos\delta & \tfrac{\mathrm{i}}{n}\sin\delta \\[2pt] \mathrm{i}\,n\sin\delta & \cos\delta \end{pmatrix}}_{M_{\text{Schicht}}} \begin{pmatrix} E \\ Z_0 H \end{pmatrix}_{\text{vorne}}, \qquad \delta = \frac{2\pi f}{c}\, n\, d . \]

Dabei ist \(\delta\) schlicht die Phasendicke der Schicht (wie viele Radiant die Welle beim Durchqueren sammelt) und \(n\) steuert das Verhältnis von \(E\) und \(H\) — der Wellenwiderstand aus Kapitel 6, in Matrixform gegossen. Der ganze Stapel ist dann das Matrixprodukt seiner Schichten, in Laufrichtung von vorn nach hinten — dieselbe Buchhaltungs-Eleganz wie beim Update-Operator in Kapitel 7, und alle Mehrfach-Echos sind automatisch mitgezählt, weil die Matrix die vollständige Feldbeziehung transportiert. Aus der Gesamtmatrix fallen \(r\) und \(t\) mit zwei Zeilen Algebra heraus (Anschluss an die Halbräume; die Formel steht im Code).

Der Versuchsaufbau der Nagelprobe: Frage: Trifft die Transfer-Matrix die Meep-Messung — über den ganzen Sweep, parameterfrei? Bühne: dieselben acht Paare, dieselben Frequenzen; die Theorie läuft in NumPy in Millisekunden. Messgrößen: \(T_{\text{TMM}}(f)\) gegen \(T_{\text{Meep}}(f)\), als Differenzmaß der rms-Abstand. Erfolgskriterium: Abweichung im Prozentbereich (Meep diskretisiert mit 40 Punkten pro \(a\) — kleine Restfehler sind ehrlich, Kapitel 8).

# von oben: N1, N2, D1, D2, N_PAARE, fs, T_meep


def schichtmatrix(n, d, f):
    """Charakteristische 2x2-Matrix einer Schicht (senkrechter Einfall)."""
    delta = 2.0 * np.pi * f * n * d
    return np.array([[np.cos(delta), 1j * np.sin(delta) / n],
                     [1j * n * np.sin(delta), np.cos(delta)]])


def kette_rt(matrizen):
    """r und t der Schichtkette zwischen zwei Luft-Halbraeumen."""
    M = np.eye(2, dtype=complex)
    for m in matrizen:
        M = M @ m                      # Matrixprodukt: Schicht fuer Schicht
    nenner = (M[0, 0] + M[0, 1]) + (M[1, 0] + M[1, 1])
    r = ((M[0, 0] + M[0, 1]) - (M[1, 0] + M[1, 1])) / nenner
    t = 2.0 / nenner
    return r, t


def stapel_rt(f, n_paare=N_PAARE):
    mats = [m for _ in range(n_paare)
            for m in (schichtmatrix(N1, D1, f), schichtmatrix(N2, D2, f))]
    return kette_rt(mats)


T_tmm = np.array([np.abs(stapel_rt(f)[1]) ** 2 for f in fs])
R_tmm = np.array([np.abs(stapel_rt(f)[0]) ** 2 for f in fs])

print(f"Energie-Check:  max |R + T - 1| = {np.max(np.abs(R_tmm + T_tmm - 1)):.1e}")
fenster = (fs > 0.10) & (fs < 0.44)
rms = np.sqrt(np.mean((T_meep[fenster] - T_tmm[fenster]) ** 2))
print(f"Meep vs. Transfer-Matrix:  rms = {rms:.4f}")
print(f"T(f0):  Meep {T_meep[np.argmin(np.abs(fs - F0))]:.2e}, "
      f"TMM {np.abs(stapel_rt(F0)[1])**2:.2e}")
Energie-Check:  max |R + T - 1| = 2.7e-15
Meep vs. Transfer-Matrix:  rms = 0.0074
T(f0):  Meep 1.14e-03, TMM 1.13e-03
# von oben: fs, T_meep, T_tmm, F0, fenster
fig, ax = plt.subplots(figsize=(7.0, 4.0))
ax.semilogy(fs, T_tmm, "C1-", lw=1.6, label="Transfer-Matrix (Theorie)")
ax.semilogy(fs[fenster][::4], T_meep[fenster][::4], "C0o", ms=4,
            mfc="none", label="Meep (jeder 4. Messpunkt)")
ax.axvline(F0, color="0.4", ls="--", lw=1)
ax.set_xlim(0.05, 0.48)
ax.set_ylim(1e-4, 2)
ax.set_xlabel("Frequenz  $f\\,a/c$")
ax.set_ylabel("Transmission $T$")
ax.set_title("Acht Paare, zwei Rechenwege, eine Kurve")
ax.legend(loc="lower right", fontsize=9)
ax.grid(alpha=0.3)
plt.show()
Abbildung 26.2: Die Nagelprobe: Meep-Messpunkte auf der Transfer-Matrix-Linie — rms unter einem Prozent, und am Boden der Klippe (10⁻³) stimmen beide auf zwei Stellen überein. Zwei völlig verschiedene Rechenwege (Zeitschritte im Gitter gegen 2×2-Matrixalgebra), ein Ergebnis: die Validierungs-Checkliste aus Kapitel 10 in Aktion.

Mit der Transfer-Matrix ist der Stapel-Entwurf eine Sache von Millisekunden — die Spielwiese macht dich zum Spiegel-Designer. Drei Aufträge, jeweils erst vorhersagen: (1) Senke N2 von 2,5 auf 1,7 — wird die Klippe schmaler, flacher, beides? (2) Verdopple N_PAARE — was passiert mit der Breite der Klippe, was mit ihrem Boden? (3) Setze STIMMUNG = 0.7 (alle \(n_2\)-Schichten 30 % zu dünn) — und beobachte, was vom sauberen Sperrband übrig bleibt.

26.3 Das Spurkriterium: erlaubt oder verboten

Die Transfer-Matrix kann mehr, als \(T(f)\) ausrechnen — sie beantwortet die Grundsatzfrage dieses Kapitels: Für welche Frequenzen kann in einem unendlichen Stapel überhaupt eine Welle laufen? Dazu brauchen wir nur die Matrix \(M\) einer Periode (eine \(n_1\)- plus eine \(n_2\)-Schicht).

In einem perfekt periodischen Medium muss sich eine laufende Welle nach jeder Periode bis auf einen Phasenfaktor wiederholen:

\[ \begin{pmatrix} E \\ Z_0 H \end{pmatrix}_{z+a} = \mathrm{e}^{\mathrm{i} K a} \begin{pmatrix} E \\ Z_0 H \end{pmatrix}_{z} . \]

Eine solche Lösung heißt Blochwelle, und \(K\) ist ihre Wellenzahl — das periodische Gegenstück zum \(k\) der ebenen Welle. Der Vergleich mit der Periodenmatrix sagt: \(\mathrm{e}^{\mathrm{i} K a}\) muss ein Eigenwert von \(M\) sein. Für unsere 2×2-Matrix ist das eine Rechnung von drei Zeilen: Die beiden Eigenwerte \(\lambda_\pm\) erfüllen \(\lambda_+ \lambda_- = \det M = 1\) (verlustfreie Schicht: was reingeht, kommt raus) und \(\lambda_+ + \lambda_- = \mathrm{Tr}\, M\). Daraus folgt

\[ \cos(K a) = \frac{\mathrm{Tr}\, M}{2}, \]

und jetzt entscheidet eine einzige Zahl über das Schicksal der Welle:

  • \(|\mathrm{Tr}\, M| \le 2\): Es gibt ein reelles \(K\) — die Blochwelle läuft. Erlaubtes Band.
  • \(|\mathrm{Tr}\, M| > 2\): Der Kosinus müsste größer als eins sein. Das geht nur mit komplexem \(K\) — die „Welle” klingt räumlich exponentiell ab. Verbotenes Band: die Bandlücke.

Falls dir dieses Entweder-oder bekannt vorkommt: Es ist wörtlich die Mathematik aus Kapitel 8. Dort haben wir die Zickzack-Mode des Zeitschritt-Operators untersucht und gefunden: \(|\mathrm{Tr}| \le 2\) heißt stabile Schwingung, \(|\mathrm{Tr}| > 2\) heißt exponentielle Explosion — die CFL-Grenze. Hier läuft dieselbe Eigenwert-Analyse über eine Periode im Raum statt über einen Schritt in der Zeit: Statt „explodieren” heißt das Urteil nun „abklingen”. Eine Formel, zwei Physiken.

Der Versuchsaufbau: Frage: Wie sieht die Dispersionsrelation \(f(K)\) des unendlichen Stapels aus — und wo liegt die Lücke? Bühne: Theorieseite: die Spurformel, ausgewertet über ein feines Frequenzraster. Messseite: eine einzige Periode in Meep mit Bloch-periodischen Rändern — der k_point aus Kapitel 16 gibt das \(K\) vor, und Harminv (Kapitel 15) lauscht, welche Eigenfrequenzen in der Zelle leben. Fünf \(K\)-Werte, fünf Kurzläufe. Erfolgskriterium: Die Meep-Punkte liegen auf dem Spurformel-Band; am Zonenrand (\(K a/2\pi = 0{,}5\)) müssen exakt die beiden Kanten unserer gemessenen Klippe herauskommen.

# von oben: schichtmatrix(), N1, N2, D1, D2, F0


def spur_halbe(f):
    """Tr(M)/2 der Periodenmatrix — die Schicksalszahl."""
    M = schichtmatrix(N1, D1, f) @ schichtmatrix(N2, D2, f)
    return float(np.real(M[0, 0] + M[1, 1]) / 2.0)


# Band aus der Spurformel: zu jedem f das K (nan in der Luecke)
f_band = np.linspace(1e-3, 0.5, 2000)
spur = np.array([spur_halbe(f) for f in f_band])
K_band = np.where(np.abs(spur) <= 1,
                  np.arccos(np.where(np.abs(spur) <= 1, spur, 0))
                  / (2 * np.pi),
                  np.nan)

# Lueckenkanten: wo |Tr/2| die 1 kreuzt
verboten = np.abs(spur) > 1
i = np.argmin(np.abs(f_band - F0))
i_lo, i_hi = i, i
while verboten[i_lo - 1]:
    i_lo -= 1
while verboten[i_hi + 1]:
    i_hi += 1
F_LO, F_HI = f_band[i_lo], f_band[i_hi]
print(f"Spurformel: Luecke {F_LO:.4f} .. {F_HI:.4f}")
print(f"Tr/2 bei f0: {spur_halbe(F0):.4f}  "
      f"(= -(n1/n2 + n2/n1)/2 = {-(N1/N2 + N2/N1)/2:.4f})")

bw = (F_HI - F_LO) / F0
bw_formel = (4 / np.pi) * np.arcsin((N2 - N1) / (N2 + N1))
print(f"relative Lueckenbreite: {bw:.4f}  "
      f"(Lehrbuchformel (4/pi)*arcsin(dn/sn): {bw_formel:.4f})")


def meep_moden_bei_k(k):
    """Eigenfrequenzen einer Bloch-periodischen Einheitszelle."""
    geom = [mp.Block(size=mp.Vector3(mp.inf, mp.inf, D1),
                     center=mp.Vector3(0, 0, -0.5 + D1 / 2),
                     material=mp.Medium(index=N1)),
            mp.Block(size=mp.Vector3(mp.inf, mp.inf, D2),
                     center=mp.Vector3(0, 0, -0.5 + D1 + D2 / 2),
                     material=mp.Medium(index=N2))]
    sim = mp.Simulation(
        cell_size=mp.Vector3(0, 0, 1), dimensions=1, resolution=64,
        geometry=geom,
        k_point=mp.Vector3(0, 0, k),     # Bloch-Phase pro Periode
        sources=[mp.Source(mp.GaussianSource(0.3, fwidth=0.6),
                           component=mp.Ex,
                           center=mp.Vector3(0, 0, -0.5 + 0.123))])
    h = mp.Harminv(mp.Ex, mp.Vector3(0, 0, 0.171), 0.3, 0.6)
    sim.run(mp.after_sources(h), until_after_sources=300)
    return sorted(m.freq for m in h.modes if m.freq > 0.01 and abs(m.Q) > 50)


K_MESS = [0.1, 0.2, 0.3, 0.4, 0.5]
punkte = [(k, f) for k in K_MESS for f in meep_moden_bei_k(k) if f < 0.48]
print("\nMeep-Moden (k, f):",
      ", ".join(f"({k:.1f}, {f:.4f})" for k, f in punkte))
rand = meep_moden_bei_k(0.5)
print(f"Zonenrand K·a/2π = 0,5:  f = {rand[0]:.4f} und {rand[1]:.4f}  "
      f"— die Klippenkanten!")
Spurformel: Luecke 0.2239 .. 0.3095
Tr/2 bei f0: -1.1333  (= -(n1/n2 + n2/n1)/2 = -1.1333)
relative Lueckenbreite: 0.3211  (Lehrbuchformel (4/pi)*arcsin(dn/sn): 0.3217)

Meep-Moden (k, f): (0.1, 0.0516), (0.2, 0.1028), (0.2, 0.4304), (0.3, 0.1528), (0.3, 0.3804), (0.4, 0.1987), (0.4, 0.3346), (0.5, 0.2238), (0.5, 0.3095)
Zonenrand K·a/2π = 0,5:  f = 0.2238 und 0.3095  — die Klippenkanten!
# von oben: K_band, f_band, punkte, F_LO, F_HI, N1, N2, D1, D2
n_misch = np.sqrt(N1**2 * D1 + N2**2 * D2)   # gemitteltes Epsilon
K_gerade = np.linspace(0, 0.5, 50)

fig, ax = plt.subplots(figsize=(6.4, 4.6))
ax.plot(K_band, f_band, "C1.", ms=2.5, label="Spurformel  cos(Ka) = Tr/2")
ax.plot([p[0] for p in punkte], [p[1] for p in punkte], "C0o", ms=7,
        mfc="none", mew=1.6, label="Meep (k_point + Harminv)")
ax.plot(K_gerade, K_gerade / n_misch, "0.4", ls="--", lw=1.2,
        label=f"Gerade  f = K/(2π·n_eff),  n_eff = {n_misch:.2f}")
ax.axhspan(F_LO, F_HI, color="gold", alpha=0.35, label="Bandlücke")
ax.set_xlim(0, 0.52)
ax.set_ylim(0, 0.5)
ax.set_xlabel("Blochzahl  $K a / 2\\pi$")
ax.set_ylabel("Frequenz  $f\\,a/c$")
ax.set_title("$\\omega(K)$ mit Lücke: das Banddiagramm")
ax.legend(fontsize=8, loc="upper left")
ax.grid(alpha=0.3)
plt.show()
Abbildung 26.3: Das Banddiagramm des unendlichen Stapels: Die Spurformel (orange) reißt bei der Bandlücke (gold) auf, die Meep-Messpunkte (Kreise) sitzen auf den Bändern. Gestrichelt die Erwartung ohne Streuung: eine Gerade mit dem Misch-Index — unten folgt ihr das Band, am Zonenrand biegt es ab und spaltet auf. Genau wie die Gitterdispersion in Kapitel 8, nur dass dort das numerische Gitter der „Kristall“ war.

Lies das Diagramm wie die Dispersionsdiagramme aus Kapitel 16: Bei kleinen Frequenzen merkt die Welle von den Schichten nur den Durchschnitt — sie läuft mit dem Misch-Index auf der Geraden. Je näher das Band dem Zonenrand kommt, desto stärker arbeiten die Bragg-Echos dagegen: Das Band wird flach (Gruppengeschwindigkeit \(\to 0\)slow light, die stehende Welle am Rand), dann reißt die Kurve auf. In der Lücke gibt es schlicht keinen Platz im Diagramm: keine Frequenz, kein \(K\), keine laufende Welle.

Und in der Lücke selbst? Da wird \(K\) komplex, und sein Imaginärteil ist messbar — er steht schon in unserer N-Reihe. Aus \(|{\cos(Ka)}| > 1\) folgt \(\operatorname{Im}(Ka) = \operatorname{arccosh}|\mathrm{Tr}/2|\), und die Leistung fällt pro Periode um \(\mathrm{e}^{-2\operatorname{Im}(Ka)}\):

# von oben: NS, T_N, F0, spur_halbe()
im_Ka = np.arccosh(abs(spur_halbe(F0)))   # arccosh: Umkehrung von cosh
print(f"Im(Ka) = arccosh({abs(spur_halbe(F0)):.4f}) = {im_Ka:.4f}")
print(f"Leistungsfaktor pro Paar: e^(-2*{im_Ka:.4f}) = {np.exp(-2*im_Ka):.4f}")
print(f"gemessen (N-Reihe): {faktor_pro_paar:.4f}")

fig, ax = plt.subplots(figsize=(6.4, 3.8))
ax.semilogy(NS, T_N, "C0o", ms=7, label="Meep-Messung $T(f_0)$")
n_fein = np.linspace(2, 12, 50)
ax.semilogy(n_fein, T_N[0] * np.exp(-2 * im_Ka * (n_fein - NS[0])),
            "C1-", lw=1.5,
            label="Spurformel: Faktor $\\mathrm{e}^{-2\\,\\mathrm{Im}(Ka)}$ pro Paar")
ax.set_xlabel("Zahl der Schichtpaare $N$")
ax.set_ylabel("$T(f_0)$")
ax.set_title("Evaneszenter Abfall: Messung trifft Spurformel")
ax.legend(fontsize=9)
ax.grid(alpha=0.3)
plt.show()
Im(Ka) = arccosh(1.1333) = 0.5108
Leistungsfaktor pro Paar: e^(-2*0.5108) = 0.3600
gemessen (N-Reihe): 0.3675
Abbildung 26.4: Die N-Reihe aus dem ersten Experiment (Punkte), daneben die parameterfreie Vorhersage der Spurformel (Linie): T fällt pro Schichtpaar um e^(−2·arccosh|Tr/2|) = 0,36. Die Stabilitätsmathematik aus Kapitel 8 sagt die Tunneldämpfung des Spiegels exakt voraus.

Damit ist der Kreis geschlossen: Klippe, exponentieller Abfall und Banddiagramm sind drei Gesichter derselben Zahl \(\mathrm{Tr}\, M/2\).

Die zweite Spielwiese zeichnet die Schicksalszahl selbst: links \(\mathrm{Tr}/2\) über der Frequenz mit dem erlaubten „Tunnel” zwischen \(-1\) und \(+1\), rechts das daraus folgende Banddiagramm. Erst vorhersagen, dann spielen: (1) Setze N2 = N1 — was muss aus den Lücken werden, und auf welcher Kurve liegt dann das Banddiagramm? (2) Unser λ/4-Stapel hat eine Lücke um \(f_0 \approx 0{,}267\) — aber hat er auch eine um \(2 f_0\)? Schau genau hin. Die Antwort ist ein Spezialfall: Bei exakten λ/4-Dicken berühren sich dort die Bänder nur. Stelle STIMMUNG = 0.8 und sieh zu, wie die zweite Lücke aufgeht.

26.4 Vom Stapel zum Kristall

Der Stapel ist ein eindimensionaler photonischer Kristall — und er hat eine Schwachstelle, die jeder kennt, der einmal eine Seifenblase oder eben einen Morpho-Falter gedreht hat: Sein Sperrband gilt nur für eine Richtung. Bei schrägem Einfall verkürzt sich der wirksame Laufweg zwischen den Ebenen, die Bragg-Bedingung rutscht zu anderen Frequenzen — die Farbe schillert. Für einen Falter ist das eine Zierde. Wer aber Licht einsperren will (dazu gleich mehr), für den ist es ein Leck: Was die Wand senkrecht nicht passieren darf, nimmt eben den schrägen Ausgang.

Die Lösung: Periodik nicht in einer Richtung, sondern in allen. Unser Versuchsobjekt ist der Klassiker der 2D-Photonik — ein Quadratgitter aus dielektrischen Stäbchen (Aluminiumoxid, \(\varepsilon = 8{,}9\), Radius \(0{,}2\,a\)) in Luft, Gitterkonstante \(a = 1\). Die Polarisation passt von selbst: Unsere 2D-Welt rechnet seit Kapitel 9 mit \(E_z\) senkrecht zur Ebene, und genau für diese Polarisation hat das Stäbchengitter seine berühmte Lücke. Aus der Vogelperspektive von Kapitel 23 ist der Kristall übrigens ein alter Bekannter: ein Array passiver Streuer — Tausende winziger Antennen, deren Echos sich phasenrichtig sortieren, wie bei der Yagi-Direktorenkette in Kapitel 24. Nur dass hier niemand speist: Das Gitter antwortet nur.

Der Versuchsaufbau: Frage: Hat auch das Stäbchengitter ein Stoppband — und bei welchen Frequenzen? Bühne: acht Stabreihen quer zur Laufrichtung; quer dazu machen periodische Ränder (der k_point=mp.Vector3() aus Kapitel 16) das Gitter unendlich breit — wir simulieren eine einzige Gitterzeile. PML nur in Laufrichtung. Anfangsbedingungen: breiter Gauß-Puls als ebene Welle. Messgrößen: \(T(f)\) gegen einen Leerlauf, wie beim Stapel. Erfolgskriterium: eine Klippe mit sauberem Boden (\(T \ll 10^{-2}\)); die Lage vergleichen wir anschließend mit dem Literaturwert.

# von oben: DPML, LUFT, FCEN/DF-Logik wie beim Stapel
EPS_STAB = 8.9          # Aluminiumoxid
R_STAB = 0.2            # Stabradius in Einheiten von a
FCEN2, DF2 = 0.35, 0.5
NFREQ2 = 401


def sweep_kristall(n_reihen=8, breite=1.0, dx=1.0, versetzt=False):
    """T(f) durch n_reihen Stabreihen; quer periodisch (Breite = Periode)."""
    tiefe = n_reihen * dx
    lx = 2 * DPML + 2 * LUFT + tiefe

    def geometrie(mit):
        if not mit:
            return []
        geom = []
        x0 = -tiefe / 2 + dx / 2
        for i in range(n_reihen):
            y0 = breite / 2 if (versetzt and i % 2 == 1) else 0.0
            geom.append(mp.Cylinder(radius=R_STAB,
                                    center=mp.Vector3(x0 + i * dx, y0),
                                    material=mp.Medium(epsilon=EPS_STAB)))
            if versetzt:
                # Periodenpartner, damit die versetzte Reihe am
                # y-Rand vollstaendig ist
                geom.append(mp.Cylinder(radius=R_STAB,
                                        center=mp.Vector3(x0 + i * dx,
                                                          y0 - breite),
                                        material=mp.Medium(epsilon=EPS_STAB)))
        return geom

    laeufe = []
    for mit in (False, True):
        sim = mp.Simulation(
            cell_size=mp.Vector3(lx, breite), resolution=24,
            boundary_layers=[mp.PML(DPML, direction=mp.X)],
            geometry=geometrie(mit),
            k_point=mp.Vector3(),        # periodische Raender in y
            sources=[mp.Source(mp.GaussianSource(FCEN2, fwidth=DF2),
                               component=mp.Ez,
                               center=mp.Vector3(-lx / 2 + DPML + 0.5, 0),
                               size=mp.Vector3(0, breite))])
        x_mess = lx / 2 - DPML - 0.5
        tr = sim.add_flux(FCEN2, DF2, NFREQ2,
                          mp.FluxRegion(center=mp.Vector3(x_mess, 0),
                                        size=mp.Vector3(0, breite)))
        sim.run(until_after_sources=mp.stop_when_fields_decayed(
            50, mp.Ez, mp.Vector3(x_mess, 0), 1e-8))
        laeufe.append((np.array(mp.get_flux_freqs(tr)),
                       np.array(mp.get_fluxes(tr))))
    (f2, p_ref), (_, p_kr) = laeufe
    return f2, p_kr / p_ref


fs_x, T_x = sweep_kristall()


def stoppband(f_arr, T_arr, schwelle=1e-2):
    drin = (f_arr > 0.15) & (f_arr < 0.55) & (T_arr < schwelle)
    return f_arr[drin][0], f_arr[drin][-1]


sb_x = stoppband(fs_x, T_x)
print(f"Stoppband senkrecht zu den Reihen: {sb_x[0]:.3f} .. {sb_x[1]:.3f}")
print(f"T am Boden: {T_x[(fs_x > 0.30) & (fs_x < 0.42)].min():.1e}")
Stoppband senkrecht zu den Reihen: 0.277 .. 0.440
T am Boden: 3.8e-06

Eine prächtige Klippe — Stoppband von 0,28 bis 0,44. Aber Vorsicht: Genau hier lauert der Denkfehler des 1D-Stapels.

Vorhersage-Punkt (PRIMM): Wir wiederholen die Messung diagonal — die Welle läuft jetzt entlang der Gitterdiagonale auf dieselben Stäbe zu. Bekommt sie dasselbe Stoppband zu spüren? Bevor du „klar, gleiches Gitter” sagst: Der Abstand der Stabreihen, die die Welle nacheinander quert, ist diagonal nicht mehr \(a\), sondern \(a/\sqrt{2}\) — und die Bragg-Frequenz hängt am Reihenabstand …

# von oben: sweep_kristall(), stoppband()
# Diagonale = um 45 Grad gedrehtes Gitter: Querperiode sqrt(2)·a,
# Reihenabstand sqrt(2)/2·a, jede zweite Reihe um die halbe
# Querperiode versetzt. 12 Reihen ≈ gleiche Kristalltiefe.
fs_m, T_m = sweep_kristall(n_reihen=12, breite=np.sqrt(2.0),
                           dx=np.sqrt(2.0) / 2, versetzt=True)
sb_m = stoppband(fs_m, T_m)
print(f"Stoppband diagonal: {sb_m[0]:.3f} .. {sb_m[1]:.3f}")

luecke = (max(sb_x[0], sb_m[0]), min(sb_x[1], sb_m[1]))
print(f"Schnittmenge beider Richtungen: {luecke[0]:.3f} .. {luecke[1]:.3f}")
print("Literatur (Joannopoulos et al.): 0.32 .. 0.44")
Stoppband diagonal: 0.323 .. 0.545
Schnittmenge beider Richtungen: 0.323 .. 0.440
Literatur (Joannopoulos et al.): 0.32 .. 0.44
# von oben: fs_x, T_x, fs_m, T_m, luecke
fig, ax = plt.subplots(figsize=(7.0, 4.2))
ax.semilogy(fs_x, np.maximum(T_x, 1e-14), "C0-", lw=1.4,
            label="senkrecht (Reihenabstand $a$)")
ax.semilogy(fs_m, np.maximum(T_m, 1e-14), "C3-", lw=1.4,
            label="diagonal (Reihenabstand $a/\\sqrt{2}$)")
ax.axvspan(luecke[0], luecke[1], color="gold", alpha=0.4,
           label="volle Bandlücke (Schnittmenge)")
ax.axvline(0.32, color="0.4", ls="--", lw=1)
ax.axvline(0.44, color="0.4", ls="--", lw=1)
ax.set_xlim(0.15, 0.55)
ax.set_ylim(1e-13, 3)
ax.set_xlabel("Frequenz  $f\\,a/c$")
ax.set_ylabel("Transmission $T$")
ax.set_title("Erst die Schnittmenge macht den Kristall")
ax.legend(fontsize=8, loc="lower left")
ax.grid(alpha=0.3)
plt.show()
Abbildung 26.5: Zwei Einfallsrichtungen, zwei verschiedene Stoppbänder: senkrecht (blau) sperrt ab 0,28, diagonal (rot) erst ab 0,32 — dafür bis weit über 0,5 hinaus. Nur die Schnittmenge (gold) ist in beiden Richtungen verboten: die echte photonische Bandlücke, 0,32 bis 0,44 — auf der Literaturlage (gestrichelte Kanten).

Die beiden Richtungen sperren verschieden — wie vom Reihenabstand-Argument vorhergesagt beginnt das diagonale Stoppband später (kürzerer Abstand → höhere Bragg-Frequenz). Aber sie überlappen: Zwischen 0,32 und 0,44 kommt die Welle weder geradeaus noch schräg durch — und eine genauere Analyse über alle Richtungen (das Kleingedruckte) bestätigt, dass dieses Fenster komplett dicht ist. Das ist der entscheidende Unterschied zwischen einem Spiegel und einem Kristall: Eine vollständige photonische Bandlücke ist ein Frequenzbereich, in dem es im Inneren des Materials überhaupt keine laufende Lichtwelle gibt. Licht dieser Frequenzen kann im Kristall schlicht nicht existieren — egal woher es kommt.

26.5 Der Defekt: Licht um die Ecke

Wozu ist ein Material gut, in dem Licht nicht existieren kann? Zum Einsperren — und das ist die eigentliche Pointe des Kapitels. Bohren wir in den perfekten Kristall einen Fehler: Wir nehmen eine komplette Stabreihe heraus. In dieser Gasse ist Platz für Licht (sie ist ja leer), aber ihre Wände sind für Lückenfrequenzen undurchdringlich — und zwar nicht wegen Reflexion an einer Grenzfläche, die bei schrägem Auftreffen schwächelt, sondern weil es im Wandmaterial keine Zustände gibt. Das Licht muss in der Gasse bleiben. Ein Wellenleiter, dessen Wände aus einem Verbot bestehen.

Der härteste Test für dieses Prinzip ist eine Kurve, an der jeder klassische Leiter scheitert: die scharfe 90°-Ecke. Eine Glasfaser (Totalreflexion, Kapitel 12) verliert ihr Licht schon bei sanften Biegungen — der Auftreffwinkel rutscht unter den Grenzwinkel. Hier kann das nicht passieren: Es gibt keinen Winkel, unter dem die Wand durchlässig würde.

Der Versuchsaufbau: Frage: Wie viel Leistung übersteht die scharfe Ecke? Bühne: ein endlicher Kristall aus 17 × 17 Stäben; einmal fehlt die mittlere Zeile (gerader Leiter, Referenz), einmal fehlen die linke halbe Zeile und die obere halbe Spalte (L-förmiger Leiter mit 90°-Knick). Anfangsbedingungen: ein Gauß-Puls bei \(f = 0{,}38\) (mitten in der Lücke), gestartet im Leiter nahe dem linken Rand. Messgrößen: der Leistungsfluss kurz vor dem Leiterende — beim geraden Leiter rechts, beim Knick oben; beide Wege sind gleich lang, das Verhältnis \(T_{\text{Knick}}/T_{\text{gerade}}\) isoliert den Preis der Ecke. Erfolgskriterium: ehrlich offen — klassische Intuition sagt „eine scharfe Ecke kostet fast alles”.

Vorhersage-Punkt (PRIMM): Dein Tipp für \(T_{\text{Knick}}/T_{\text{gerade}}\) bei \(f = 0{,}38\): eher 1 %, 10 % oder 90 %?

# von oben: EPS_STAB, R_STAB, DPML
NK = 8                    # Staebe von -NK..NK -> 17x17
L_KRIST = 2 * NK + 1
LX_WL = L_KRIST + 2 * 2.0 + 2 * DPML
F_LEIT, DF_LEIT = 0.38, 0.10


def staebe(form):
    """Kristall mit Leiter-Gasse: 'gerade' oder 'knick' (L-Form)."""
    geom = []
    for i in range(-NK, NK + 1):
        for j in range(-NK, NK + 1):
            if form == "gerade" and j == 0:
                continue
            if form == "knick" and ((j == 0 and i <= 0) or
                                    (i == 0 and j >= 0)):
                continue
            geom.append(mp.Cylinder(radius=R_STAB, center=mp.Vector3(i, j),
                                    material=mp.Medium(epsilon=EPS_STAB)))
    return geom


def lauf_leiter(form):
    sim = mp.Simulation(
        cell_size=mp.Vector3(LX_WL, LX_WL), resolution=16,
        boundary_layers=[mp.PML(DPML)], geometry=staebe(form),
        sources=[mp.Source(mp.GaussianSource(F_LEIT, fwidth=DF_LEIT),
                           component=mp.Ez,
                           center=mp.Vector3(-NK + 0.5, 0))])
    if form == "gerade":
        fr = mp.FluxRegion(center=mp.Vector3(NK - 0.5, 0),
                           size=mp.Vector3(0, 1))
        sonde = mp.Vector3(NK - 0.5, 0)
    else:
        fr = mp.FluxRegion(center=mp.Vector3(0, NK - 0.5),
                           size=mp.Vector3(1, 0))
        sonde = mp.Vector3(0, NK - 0.5)
    tr = sim.add_flux(F_LEIT, DF_LEIT, 201, fr)
    sim.run(until_after_sources=mp.stop_when_fields_decayed(
        50, mp.Ez, sonde, 1e-7))
    return np.array(mp.get_flux_freqs(tr)), np.array(mp.get_fluxes(tr))


fs_l, P_gerade = lauf_leiter("gerade")
_, P_knick = lauf_leiter("knick")
T_ecke = P_knick / P_gerade
print(f"T_Knick / T_gerade bei f = 0,38:  "
      f"{T_ecke[np.argmin(np.abs(fs_l - 0.38))]:.3f}")
T_Knick / T_gerade bei f = 0,38:  1.010

Die Ecke kostet nichts. Das Verhältnis liegt bei eins (die Restwelligkeit kommt von Echos an den Leiter-Enden, Fabry-Pérot lässt grüßen — Kapitel 27 nimmt sich genau solche Resonanzen vor). Zum Vergleich die klassische Welt: Ein scharfer 90°-Knick in einer Glasfaser wirft praktisch alles weg. So sieht der Sieg über die Geometrie aus:

# von oben: staebe(), LX_WL, L_KRIST, F_LEIT, NK
sim_cw = mp.Simulation(
    cell_size=mp.Vector3(LX_WL, LX_WL), resolution=16,
    boundary_layers=[mp.PML(DPML)], geometry=staebe("knick"),
    force_complex_fields=True,
    sources=[mp.Source(mp.ContinuousSource(F_LEIT),
                       component=mp.Ez, center=mp.Vector3(-NK + 0.5, 0))])
sim_cw.run(until=150)
ez_knick = sim_cw.get_array(component=mp.Ez, center=mp.Vector3(),
                            size=mp.Vector3(L_KRIST + 2, L_KRIST + 2))
print(f"Gesundheitswert: max|Ez| = {np.abs(ez_knick).max():.2f}")

seite = L_KRIST + 2
betrag = np.abs(ez_knick).T   # Transponieren: Bildzeilen = y
fig, ax = plt.subplots(figsize=(6.6, 6.2))
ax.imshow(betrag, origin="lower", cmap="inferno",
          extent=[-seite / 2, seite / 2, -seite / 2, seite / 2],
          vmax=np.percentile(betrag, 99.5))
for i in range(-NK, NK + 1):
    for j in range(-NK, NK + 1):
        if (j == 0 and i <= 0) or (i == 0 and j >= 0):
            continue
        ax.add_patch(plt.Circle((i, j), R_STAB, fill=False,
                                color="w", lw=0.4, alpha=0.55))
ax.set_xlabel("x/a")
ax.set_ylabel("y/a")
ax.set_title("Licht fährt um die Ecke")
plt.show()
Gesundheitswert: max|Ez| = 1.28
Abbildung 26.6: |E_z| im eingeschwungenen Zustand (Dauerstrich f = 0,38, helle Farbe = viel Feld; Kreise = Stäbe): Das Licht läuft von links in der Gasse, biegt scharf nach oben ab und kommt oben an — die Erwartung „T ≈ 1“ aus der Flussmessung, hier als Bild. In den Kristall dringt es nur ein bis zwei Reihen weit ein (evaneszent, wie im Stapel), und vor dem Knick steht die Stehwellen-Riffelung des leichten Echos.

Im Film läuft die Welle: derselbe Dauerstrich-Lauf, als Momentbild \(\operatorname{Re}(E_z \mathrm{e}^{-\mathrm{i}\varphi})\) über eine Periode animiert (der Zeiger-Trick aus Kapitel 15/23). Verfolge die Wellenberge: Sie laufen von links zur Ecke, biegen ab und laufen oben hinaus — nirgends leckt etwas seitlich in den Kristall.

Code der Animation (nur in der HTML-Fassung)
# von oben: ez_knick, seite, R_STAB, NK
phasen_2d = np.linspace(0, 2 * np.pi, 16, endpoint=False)
vmax_film = np.percentile(np.abs(ez_knick), 99.5)

fig, ax = plt.subplots(figsize=(6.6, 6.2))
bildobj = ax.imshow(np.real(ez_knick).T, origin="lower", cmap="RdBu_r",
                    extent=[-seite / 2, seite / 2, -seite / 2, seite / 2],
                    vmin=-vmax_film, vmax=vmax_film)
for i in range(-NK, NK + 1):
    for j in range(-NK, NK + 1):
        if (j == 0 and i <= 0) or (i == 0 and j >= 0):
            continue
        ax.add_patch(plt.Circle((i, j), R_STAB, fill=False,
                                color="0.3", lw=0.4, alpha=0.6))
ax.set_xlabel("x/a")
ax.set_ylabel("y/a")
titel2 = ax.set_title("", fontsize=10)
fig.subplots_adjust(top=0.92)


def bild2(i):
    bildobj.set_data(np.real(ez_knick * np.exp(-1j * phasen_2d[i])).T)
    titel2.set_text("Um die Ecke, ohne Leck — "
                    f"t = {phasen_2d[i] / (2 * np.pi):.2f} Perioden")
    return [bildobj, titel2]


anim2 = animation.FuncAnimation(fig, bild2, frames=len(phasen_2d),
                                interval=140)
plt.close(fig)
HTML(anim2.to_jshtml(default_mode="loop"))

Solche Knicke sind der Grund, warum photonische Kristalle als „Leiterplatten für Licht” gehandelt werden: Auf einem Chip lassen sich Lichtwege damit auf Wellenlängen-Skala falten — wo eine Glasfaser Zentimeter an Biegeradius bräuchte.

26.6 Strukturfarbe: der Falter, nachgerechnet

Zurück zum Anfang — jetzt mit Werkzeug. Die Lamellen des Morpho-Falters sind ein Bragg-Stapel aus Chitin (\(n \approx 1{,}56\)) und Luft, beide Schichten etwa 90 nm dick. Welche Farbe wirft er zurück? Die Bragg-Bedingung (alle Echos in Phase: ein Umlauf durch eine Periode = eine ganze Wellenlänge) liefert die Mitte des Sperrbands: \(\lambda_{\max} = 2(n_1 d_1 + n_2 d_2)\). Beim Schrägblick unter dem Winkel \(\theta\) zählt nur noch die Wegkomponente senkrecht zum Stapel — in jeder Schicht ersetzt \(d_j \cos\theta_j\) (mit Snellius für \(\theta_j\)) die volle Dicke, und \(\lambda_{\max}\) rutscht nach blau-violett:

# von oben: schichtmatrix(), kette_rt()
N_CHITIN, D_CHITIN = 1.56, 90e-9
N_LUFT, D_LUFT = 1.0, 90e-9
N_LAMELLEN = 8


def morpho_R(lam, theta_grad):
    """Reflexion des Chitin-Luft-Stapels bei Blickwinkel theta (s-Pol.)."""
    th = np.radians(theta_grad)
    # Snellius in jeder Schicht; bei s-Polarisation geht n*cos(theta_j)
    # als effektiver Index in die Schichtmatrix ein
    c_ch = np.sqrt(1 - (np.sin(th) / N_CHITIN) ** 2)
    c_lu = np.sqrt(1 - np.sin(th) ** 2)
    f = 1.0 / lam                      # c = 1: Frequenz in 1/m
    mats = []
    for _ in range(N_LAMELLEN):
        mats.append(schichtmatrix(N_CHITIN * c_ch, D_CHITIN, f))
        mats.append(schichtmatrix(N_LUFT * c_lu, D_LUFT, f))
    # Anschluss an Luft ebenfalls unter dem Winkel
    M = np.eye(2, dtype=complex)
    for m in mats:
        M = M @ m
    p = c_lu                            # Luft-Halbraum, s-Polarisation
    nenner = (M[0, 0] + M[0, 1] * p) * p + (M[1, 0] + M[1, 1] * p)
    r = ((M[0, 0] + M[0, 1] * p) * p - (M[1, 0] + M[1, 1] * p)) / nenner
    return np.abs(r) ** 2


lams = np.linspace(300e-9, 700e-9, 400)
fig, ax = plt.subplots(figsize=(7.0, 4.0))
for th, farbe in [(0, "C0"), (45, "C4")]:
    R_m = np.array([morpho_R(l, th) for l in lams])
    ax.plot(lams * 1e9, R_m, farbe, lw=1.6, label=f"Blickwinkel {th}°")
    th_r = np.radians(th)
    lam_bragg = 2 * (N_CHITIN * D_CHITIN
                     * np.sqrt(1 - (np.sin(th_r) / N_CHITIN) ** 2)
                     + D_LUFT * np.sqrt(1 - np.sin(th_r) ** 2))
    ax.axvline(lam_bragg * 1e9, color=farbe, ls="--", lw=1.1)
ax.axvspan(380, 490, color="royalblue", alpha=0.10)
ax.text(437, 1.04, "blau", color="royalblue", ha="center", fontsize=9)
ax.set_xlabel("Wellenlänge in nm")
ax.set_ylabel("Reflexion $R$")
ax.set_ylim(0, 1.12)
ax.set_title("Morpho-Blau: Farbe aus Geometrie")
ax.legend(fontsize=9, loc="center right")
ax.grid(alpha=0.3)
plt.show()
Abbildung 26.7: Das Reflexionsspektrum des Morpho-Modells (Transfer-Matrix, 8 Lamellen Chitin/Luft à 90 nm): senkrecht betrachtet liegt das Maximum um 460 nm (sattes Blau), bei 45°-Blick wandert es auf etwa 380 nm Richtung Violett — das Schillern. Senkrechte Striche: die Bragg-Handformel 2·Σ n·d·cosθ (461 bzw. 378 nm) sitzt jeweils im Sperrband-Maximum.

Kein Pigment, keine Absorption — die Farbe entsteht, weil ein Frequenzband nicht hinein darf und deshalb zurückkommt. Dasselbe Prinzip färbt Opale (dort sind es gestapelte Silikat-Kügelchen — ein 3D-Kristall, dessen Lücke je nach Blickrichtung andere Farben trifft: das Opalfeuer), Pfauenfedern und manche Käferpanzer. Und am anderen Ende der Präzisionsskala: Die Endspiegel von Laser-Resonatoren sind λ/4-Stapel mit \(R > 99{,}999\,\%\) — Werte, an die kein Metallspiegel herankommt, denn Metall absorbiert immer ein paar Prozent (Kapitel 16), während im Dielektrikum nichts verloren geht, sondern nur umgelenkt wird. Auch photonische Glasfasern gehören in diese Familie: ein Kristall aus Luftlöchern, der das Licht in einem hohlen Kern führt — Lichtleitung in Luft, wo es weder Materialdämpfung noch nennenswerte Dispersion gibt; mit Totalreflexion (Kapitel 12) wäre das unmöglich, denn die braucht innen das dichtere Medium.

Bleibt der Name: Warum „Kristall”? Weil die Mathematik geliehen ist. Elektronen in einem Halbleiter laufen als Quantenwellen (Kapitel 30) durch das periodische Potential der Atomrümpfe — und bekommen aus exakt derselben Bloch-Analyse ihre elektronische Bandlücke: den Energiebereich ohne erlaubte Zustände, der Halbleiter von Metallen unterscheidet und auf dem die gesamte Elektronik steht. Die Photonik hat sich diese fünfzig Jahre ältere Theorie ausgeliehen und „Schrödinger” durch „Maxwell” ersetzt; der photonische Kristall ist der Halbleiter des Lichts. Was dort Dotierung und Störstellen sind, waren hier unsere fehlenden Stäbe.

26.7 Das Kapitel-Programm

programme/kap26/kap26_photonische_kristalle.py bündelt alle Befunde eigenständig und mit assert-Schranken: die Transfer-Matrix-Eigenschaften (\(R + T = 1\) auf Maschinengenauigkeit, Lückenbreite auf der arcsin-Formel, \(\mathrm{Tr}/2\) bei \(f_0\) exakt \(-(n_1/n_2 + n_2/n_1)/2\)), den Meep-1D-Sweep auf der TMM-Linie (rms < 0,02), die N-Reihe auf der \(\mathrm{e}^{-2\,\mathrm{Im}(Ka)}\)-Geraden, das Banddiagramm (Meep-Punkte auf dem TMM-Band, Abweichung \(< 10^{-3}\); Zonenrand = Klippenkanten), beide 2D-Sweeps samt Schnittmengen-Lücke 0,32–0,44, den Knick (\(T \approx 1\)), die Punktdefekt-Kavität (kommt in Übung 26.4) und die Morpho-Zahlen. Läuft in wenigen Minuten.

Damit ist der Werkzeugkasten des Kapitels beisammen — Zeit für das Fazit.

TippMerkkasten
  • λ/4-Stapel: Vorzeichenwechsel der Reflexion plus λ/2-Umweg bringen alle Echos in Phase — acht Glas/Titandioxid-Paare reflektieren 99,9 %. Durchsichtig ist keine Materialeigenschaft, sondern eine Frage der Anordnung.
  • Transfer-Matrix: eine 2×2-Matrix pro Schicht, der Stapel ist ihr Produkt — alle Mehrfach-Echos inklusive. Exakt, parameterfrei, Millisekunden.
  • Spurkriterium: \(\cos(Ka) = \mathrm{Tr}\,M/2\). Bei \(|\mathrm{Tr}| \le 2\) läuft die Blochwelle (Band), bei \(|\mathrm{Tr}| > 2\) klingt sie ab (Lücke) — dieselbe Mathematik wie die CFL-Stabilität aus Kapitel 8, nur im Raum statt in der Zeit. Abfallrate: \(\operatorname{Im}(Ka) = \operatorname{arccosh}|\mathrm{Tr}/2|\).
  • Bandlücke = Schnittmenge: Ein Stapel sperrt nur senkrecht (deshalb schillert der Falter). Erst wenn die Stoppbänder aller Richtungen überlappen, ist es eine vollständige photonische Bandlücke (Stäbchengitter: 0,32–0,44 bei \(\varepsilon = 8{,}9\), \(r = 0{,}2\,a\)).
  • Defekte sind das Werkzeug: Eine fehlende Stabreihe führt Licht um die scharfe 90°-Ecke (\(T \approx 1\)), denn ihre Wände haben keine Zustände, in die etwas lecken könnte; ein fehlender Einzelstab sperrt es ein.

Roter Faden

Dieses Kapitel hat viele alte Fäden zu einem neuen Stoff verwebt: die Grenzflächen-Reflexion aus Kapitel 6 und den λ/4-Trafo aus Kapitel 22 (vom Echo-Löscher zum Echo-Sammler), die Interferenz-Buchhaltung aus Kapitel 14 (dort haben wir versprochen, dass die Gitterformel wiederkommt — als Bragg-Reflexion ganzer Kristallebenen), das Spurkriterium aus Kapitel 8 (von der Zeit in den Raum gewendet), \(k\)-Punkt und Dispersionsdiagramm aus Kapitel 16, das Harminv-Ohr aus Kapitel 15, die evaneszenten Felder aus Kapitel 12/17 (in der Lücke wohnt dieselbe Feldsorte wie hinter der Totalreflexion — und wie im Pendelfeld von Kapitel 25) und die Streuer-Arrays aus Kapitel 23/24 (der Kristall als Antennengruppe, die niemand speist). Nach vorn: Kapitel 27 holt sich die Defektidee zurück und baut aus Spiegeln Resonatoren — Fabry-Pérot, Ringresonator und der Schritt zum Laser; die Transmissionsnadel aus Übung 26.3 ist davon der Prolog.

Übungen

Ü 26.1 — Das Grün des Käfers (Verstehen). Ein Prachtkäfer erzeugt sein Grün (\(\lambda \approx 530\) nm) mit demselben Chitin/Luft-Stapel wie der Morpho (\(n = 1{,}56\), gleich dicke Schichten). (a) Wie dick müssen seine Lamellen sein? (b) Ein Regentropfen benetzt den Panzer und ersetzt die Luft in den Spalten durch Wasser (\(n = 1{,}33\)). Was passiert mit der Farbe — Lage und Stärke? Erst überlegen (zwei Effekte!), dann rechnen.

  1. Aus \(\lambda_{\max} = 2(n_1 d + n_2 d)\) folgt \(d = \lambda_{\max} / (2(n_1 + n_2))\) — die Bragg-Bedingung nach \(d\) aufgelöst:
lam_gruen = 530e-9
d_kaefer = lam_gruen / (2 * (1.56 + 1.0))
print(f"Lamellendicke: {d_kaefer*1e9:.0f} nm  (Morpho: 90 nm)")
Lamellendicke: 104 nm  (Morpho: 90 nm)

Grün braucht etwa 104 nm — nur 14 nm mehr als das Morpho-Blau. So fein arbeitet die Evolution an diesem Regler.

  1. Zwei Effekte, beide gegen die Farbe: Die optische Dicke der Spalten steigt (\(n\): 1,0 → 1,33), also rutscht \(\lambda_{\max} = 2 d (n_1 + n_2)\) nach rot; und der Kontrast \(n_2/n_1\) fällt von 1,56 auf 1,17, also wird die Lücke schmal und die Reflexion schwach (das arcsin-Argument schrumpft von 0,22 auf 0,08):
lam_nass = 2 * d_kaefer * (1.56 + 1.33)
breite_trocken = (4 / np.pi) * np.arcsin((1.56 - 1.0) / (1.56 + 1.0))
breite_nass = (4 / np.pi) * np.arcsin((1.56 - 1.33) / (1.56 + 1.33))
print(f"nass: lambda_max = {lam_nass*1e9:.0f} nm (statt 530)")
print(f"relative Lueckenbreite: {breite_trocken:.3f} -> {breite_nass:.3f}")
nass: lambda_max = 598 nm (statt 530)
relative Lueckenbreite: 0.281 -> 0.101

Der nasse Käfer wird rötlich-fahl — und genau das beobachtet man: Strukturfarben erlöschen bei Benetzung und kommen beim Trocknen wieder. Ein Pigment könnte das nicht; es ist der schnellste Feldtest auf Strukturfarbe.

Ü 26.2 — Der Kontrast-Regler (Verändern). Miss mit der Transfer-Matrix die relative Lückenbreite für \(n_2 = 1{,}7\) bis \(4{,}0\) (bei \(n_1 = 1{,}5\), jeweils λ/4-Dicken) und lege die Formel \((4/\pi)\arcsin\!\big((n_2 - n_1)/(n_2 + n_1)\big)\) darüber. Wie groß muss der Kontrast sein, damit die Lücke relativ breiter ist als die einer Oktave (Faktor 2 in der Frequenz, also Breite/Mitte = 2/3)?

# von oben: schichtmatrix(), N1


def lueckenbreite(n2):
    lam0 = 4.0 / (1.0 / N1 + 1.0 / n2)
    f0 = 1.0 / lam0
    d1 = lam0 / (4.0 * N1)
    d2 = lam0 / (4.0 * n2)

    def tr2(f):
        M = schichtmatrix(N1, d1, f) @ schichtmatrix(n2, d2, f)
        return abs(float(np.real(M[0, 0] + M[1, 1]) / 2))

    f_raster = np.linspace(0.5 * f0, 1.5 * f0, 2001)
    drin = np.array([tr2(f) > 1 for f in f_raster])
    return (f_raster[drin][-1] - f_raster[drin][0]) / f0


n2_reihe = np.linspace(1.7, 4.0, 12)
gemessen = np.array([lueckenbreite(n2) for n2 in n2_reihe])
formel = (4 / np.pi) * np.arcsin((n2_reihe - N1) / (n2_reihe + N1))

fig, ax = plt.subplots(figsize=(6.4, 3.8))
ax.plot(n2_reihe / N1, gemessen, "C0o", ms=6, label="Transfer-Matrix")
ax.plot(n2_reihe / N1, formel, "C1-", lw=1.5, label="arcsin-Formel")
ax.axhline(2 / 3, color="0.4", ls="--", lw=1, label="eine Oktave (2/3)")
ax.set_xlabel("Kontrast $n_2 / n_1$")
ax.set_ylabel("Lückenbreite / Mittenfrequenz")
ax.set_title("Die Lücke wächst mit dem Kontrast")
ax.legend(fontsize=9)
ax.grid(alpha=0.3)
plt.show()

n2_oktave = N1 * (1 + np.sin(np.pi / 6)) / (1 - np.sin(np.pi / 6))
print(f"Oktave: arcsin-Argument = sin(pi/6) = 0.5 "
      f"-> n2 = 3*n1 = {n2_oktave:.1f}")

Gemessene Lückenbreite (Punkte) auf der arcsin-Formel (Linie): Der Kontrast ist der einzige Regler — und für eine Oktave Sperrbreite braucht es n₂/n₁ ≈ 5, mehr als jedes gängige Schichtpaar hergibt.
Oktave: arcsin-Argument = sin(pi/6) = 0.5 -> n2 = 3*n1 = 4.5

Messung und Formel decken sich. Für die Oktave muss \((n_2-n_1)/(n_2+n_1) = \sin(\pi/6) = 1/2\) sein, also \(n_2 = 3 n_1 = 4{,}5\) — jenseits gängiger transparenter Materialien. Breitband-Verspiegelung löst man deshalb anders: mehrere Stapel mit gestaffelten \(f_0\) hintereinander (Chirp).

Ü 26.3 — Die Nadel im Spiegel (Verändern). Baue mit der Transfer-Matrix eine Defektschicht in den Stapel: vier λ/4-Paare, dann eine \(n_1\)-Schicht doppelter Dicke (eine λ/2-Schicht), dann vier Paare gespiegelt. Berechne \(T(f)\) innerhalb der Lücke. Vorhersage: Die Lücke war eben noch hermetisch dicht — was kann eine einzige falsche Schicht schon ausrichten? Miss dann nach: Lage, Höhe und Breite (FWHM → \(Q = f/\Delta f\), Kapitel 15) der Überraschung; wiederhole mit fünf und sechs Paaren pro Seite.

# von oben: schichtmatrix(), kette_rt(), N1, N2, D1, D2, F0, F_LO, F_HI


def kavitaet_T(f, n_spiegel):
    mats = []
    for _ in range(n_spiegel):                      # linker Spiegel
        mats += [schichtmatrix(N1, D1, f), schichtmatrix(N2, D2, f)]
    mats += [schichtmatrix(N1, 2 * D1, f)]          # lambda/2-Defekt
    for _ in range(n_spiegel):                      # rechter Spiegel
        mats += [schichtmatrix(N2, D2, f), schichtmatrix(N1, D1, f)]
    return np.abs(kette_rt(mats)[1]) ** 2


f_nadel = np.linspace(F_LO, F_HI, 8001)
fig, ax = plt.subplots(figsize=(7.0, 4.0))
for n_sp, farbe in [(4, "C0"), (5, "C1"), (6, "C3")]:
    T_kav = np.array([kavitaet_T(f, n_sp) for f in f_nadel])
    i_pk = np.argmax(T_kav)
    ueber = T_kav > T_kav[i_pk] / 2
    fwhm = f_nadel[ueber][-1] - f_nadel[ueber][0]
    ax.semilogy(f_nadel, T_kav, farbe, lw=1.3,
                label=f"{n_sp} Paare/Seite:  T = {T_kav[i_pk]:.3f}, "
                      f"Q = {f_nadel[i_pk]/fwhm:.0f}")
ax.axvline(F0, color="0.4", ls="--", lw=1)
ax.set_xlabel("Frequenz  $f\\,a/c$")
ax.set_ylabel("Transmission $T$")
ax.set_ylim(1e-6, 3)
ax.set_title("Eine λ/2-Schicht bohrt ein Loch in die Lücke")
ax.legend(fontsize=9, loc="lower right")
ax.grid(alpha=0.3)
plt.show()

Die Transmissionsnadel der λ/2-Defektschicht: mitten in der hermetischen Lücke öffnet sich ein nadelfeines Fenster mit T = 1 — ein Fabry-Pérot-Resonator, dessen Spiegel Bragg-Stapel sind. Pro zusätzlichem Spiegelpaar wird die Nadel um den Faktor 1/0,36 ≈ 3 schmaler (Q: 74 → 213 → 608).

Die „eine falsche Schicht” richtet alles aus: Bei exakt \(f_0\) steigt \(T\) auf 1,000 — der Stapel, der eben noch \(10^{-3}\) durchließ, wird für genau eine Frequenz perfekt durchsichtig. Die λ/2-Schicht ist ein Resonator zwischen zwei Bragg-Spiegeln; auf Resonanz baut sich das Feld in der Kavität so weit auf, dass die durchgelassene Welle die reflektierte exakt auslöscht (dieselbe Logik wie beim λ/4-Trafo aus Kapitel 22, nur mit gespeichertem Feld als Vermittler). Jedes weitere Spiegelpaar verdreifacht \(Q\) — der Faktor ist unser alter Bekannter \(1/0{,}36\) aus der Spurformel. Kapitel 27 beginnt genau hier.

Ü 26.4 — Wände aus Nichts (Übertragen). Entferne statt einer Reihe nur den mittleren Stab eines Stäbchen-Kristalls und miss mit Harminv (Kapitel 15), was in diesem Punktdefekt wohnt: Resonanzfrequenz und Güte für Kristalle aus 7×7 und 9×9 Stäben. Vorhersage: In welche Richtung muss \(f\) fallen (denk an die Lücke), und was erwartest du beim Schritt 7×7 → 9×9 für \(Q\) — Verdopplung oder mehr?

# von oben: EPS_STAB, R_STAB


def punktdefekt(nk):
    geom = [mp.Cylinder(radius=R_STAB, center=mp.Vector3(i, j),
                        material=mp.Medium(epsilon=EPS_STAB))
            for i in range(-nk, nk + 1) for j in range(-nk, nk + 1)
            if not (i == 0 and j == 0)]
    L = 2 * nk + 1
    sim = mp.Simulation(
        cell_size=mp.Vector3(L + 6, L + 6), resolution=16,
        boundary_layers=[mp.PML(2.0)], geometry=geom,
        sources=[mp.Source(mp.GaussianSource(0.38, fwidth=0.10),
                           component=mp.Ez,
                           center=mp.Vector3(0.123, 0.061))])
    h = mp.Harminv(mp.Ez, mp.Vector3(0.1, 0.05), 0.38, 0.10)
    sim.run(mp.after_sources(h), until_after_sources=400)
    beste = max(h.modes, key=lambda m: abs(m.Q))
    return beste.freq, abs(beste.Q)


for nk in (3, 4):
    f_def, q_def = punktdefekt(nk)
    print(f"{2*nk+1}x{2*nk+1}-Kristall:  f = {f_def:.4f},  Q = {q_def:.0f}")
7x7-Kristall:  f = 0.3945,  Q = 728
9x9-Kristall:  f = 0.3944,  Q = 4227

Die Mode liegt bei \(f = 0{,}394\)mitten in der Lücke (0,32–0,44), wie es sein muss: Nur dort sind die Wände dicht. Und \(Q\) wächst beim Schritt 7×7 → 9×9 um den Faktor sechs, nicht zwei: Der einzige Verlustkanal ist das evaneszente Durchtunneln der endlichen Kristallwand, und das fällt (wie beim Stapel) exponentiell mit jeder Stabreihe. Vergleiche Kapitel 15: Dort lebte der Resonator in Metallwänden und verlor durchs Koppel-Loch — hier sind die Wände „Nichts mit Verbot”, und man stellt die Güte ein, indem man Reihen hinzufügt. Genau solche Punktdefekt-Kavitäten (in Silizium, bei 1550 nm) erreichen \(Q > 10^6\) auf Mikrometer-Volumen — Bauteile für Filter, Sensoren und Laser auf dem Chip.

Das Kleingedruckte

Zwei Richtungen sind nicht alle. Unsere Schnittmengen-Messung hat die Γ–X- und die Γ–M-Richtung geprüft (so heißen die Wege vom Zonenzentrum zur Kante bzw. zur Ecke der Brillouin-Zone, des Einheitsquadrats im \(K\)-Raum). Dass dazwischen nichts Schlimmeres passiert, ist beim Quadratgitter Erfahrungstatsache, aber kein Naturgesetz — die saubere Methode rechnet das Eigenwertproblem für alle \(\vec K\) entlang des Zonenrands (Werkzeuge wie MPB, der Frequenzbereichs-Bruder von Meep, machen genau das; die Literaturkanten 0,32/0,44 stammen daher). Unsere Transfer-Matrix ist der 1D-Spezialfall dieser Bloch-Rechnung.

Polarisation entscheidet. Die Lücke des Stäbchengitters gilt für \(E_z\) (TM). Für die andere Polarisation (TE) hat dasselbe Gitter keine vollständige Lücke — dafür hat sie das „Negativ”: ein Lochgitter in einer dielektrischen Platte. Faustregel aus der Literatur: isolierte Dielektrikum-Inseln begünstigen TM-Lücken, verbundene Netze TE-Lücken. Wer beide will, kombiniert beides (z. B. Wabengitter) — erst dann sperrt der Kristall jedes Licht seiner Lücke.

Von 2D nach 3D. Eine vollständige 3D-Bandlücke (alle Richtungen, alle Polarisationen) ist deutlich schwerer zu bekommen: Der Opal schafft es trotz seiner hübschen Farben nicht (seine Pseudolücke ist richtungsabhängig — daher das Farbenspiel), der invertierte Opal (Luftkugeln in Titandioxid) und die „Holzstapel”-Struktur (woodpile) schaffen es. Vorgeschlagen wurde das Konzept 1987 unabhängig von Eli Yablonovitch (Ziel: spontane Emission unterdrücken — eine Lichtquelle in der Lücke kann nicht abstrahlen!) und Sajeev John (Ziel: Licht-Lokalisierung); die erste künstliche 3D-Lücke (1991, „Yablonovite”) wurde in Plexiglas gebohrt und im Mikrowellenband vermessen — Skaleninvarianz (Kapitel 11) macht Mikrowellen-Modelle zu ehrlichen Prototypen der Photonik.

Die Analogie trägt weit. Bloch entwickelte die Bandtheorie 1928 für Elektronen in Kristallen; „Bänder”, „Lücke”, „Zustandsdichte”, „Defektzustand”, „Dotierung” — das gesamte Vokabular dieses Kapitels stammt aus der Festkörperphysik. Der Unterschied: Photonen wechselwirken nicht miteinander und folgen exakt den linearen Maxwell-Gleichungen — der photonische Kristall ist insofern das sauberere Lehrbuchbeispiel der Bandtheorie als der echte Halbleiter mit seinen Elektron-Elektron-Effekten. Kapitel 30 kommt auf diese Brücke zurück, dann von der Quantenseite.