four_f_filter — OPTICS wave op

• Datenarten: cimage × cimage → cimage

• Aufruf: import fullseye as fs; fs.ledger.four_f_filter(field, transfer, invert=True) (die Implementierung direkt: import optics; optics.four_f_filter(field, transfer, invert=True); aus dem Register: opsoptics.get("four_f_filter"))

Verwendung

Optischer 4f-Prozessor: Ausgabe nach Durchgang durch 2 Linsen und den Filter in der Fourier-Ebene.

Eingangsebene → Linse 1 → Fourier-Ebene (Multiplikation mit transfer) → Linse 2 → Ausgangsebene. Im idealen 4f-System der skalaren Beugung ist die Ausgabe

out(x, y) = (u * h)(-x, -y)

—— zur Faltung kommt eine Koordinateninversion hinzu. Die 2 Linsen führen jeweils eine *vorwärts gerichtete* Fourier- Transformation aus, und F{F{u}}(x) = u(-x). Hier unterscheidet sich eine Rechnung, die "nur in der Fourier-Ebene multipliziert", vom realen 4f-System, deshalb ist die Inversion per Default aktiv.

Auch diskret ist diese Inversion exakt: Sie ist die Indexabbildung n -> (-n) mod N (np.roll(a[::-1], 1)). Die Inversion selbst ist eine Indexpermutation und trägt keinen Fehler —— übrig bleibt nur der Fehler im Bereich 1e-16 aus dem FFT-Hin- und Rückweg (gemessen mit transfer gleich 1:

maximale absolute Differenz 3.4e-16).

Mit *invert* auf False entfällt die Inversion (wenn man das gefilterte Feld in Eingangskoordinaten sehen will. Es ist kein physikalisches 4f-System, daher nicht der Default).

Ground Truth (was dieser Op reproduziert):

• identity-Filter → stimmt mit der um 180 Grad gedrehten Eingabe überein (gemessen 3.4e-16).

• block-Filter → exakt null.

• derivative_x order=n → räumliche Ableitung der Ordnung *n*. Für eine Gaußfunktion (w=8, 64x64) relativer Fehler 5.8e-08 für die 1. Ordnung / 5.4e-08 für die 2. Ordnung —— 1e-16 wird nicht erreicht, weil die Gaußfunktion nicht streng bandbegrenzt ist (der abgeschnittene Anteil).

• Linearität 4f(a*u1 + b*u2) = a*4f(u1) + b*4f(u2).

• Verkettung 4f(4f(u, H1), H2) = 4f(u, H1*H2) (verschoben um die 2-mal angewandte Inversion, daher beim Testen der Verkettung *invert* auf False setzen).

• Ein Filter mit |H| = 1 erhält die Gesamtleistung (Parseval).

Raises ValueError: *field* / *transfer* nicht 2-D, unterschiedliche Form, kleiner als 2x2, mehr als MAX_FIELD_ELEMENTS, nicht endlich, maskiert.

Familienweiter Eingabevertrag (fail-closed)

Jeder optics-Operator prüft seine Eingabe vor der Berechnung (nichts rutscht stillschweigend durch):

• Einheiten stecken im Argumentnamen — _mm / _um / _deg / _mrad. Eine Verwechslung von mm und µm stürzt nicht ab, sondern liefert eine plausibel aussehende falsche Antwort; der Name verhindert das. Aus der Größenordnung wird nie auf die Einheit geschlossen.

• Strings lösen ValueError aus — float('50') gelingt, sodass ein ungeparster Konfigurationswert als Länge durchrutschen würde (gemessen: thin_lens('50', '200') lieferte plausible 66,667 mm). bool wird als implizite Hochstufung True == 1 ebenfalls abgelehnt.

• complex / Masked Arrays lösen ValueError aus (nur reelle Slots; das stille Verwerfen des Imaginärteils bzw. Abstreifen der Maske wird abgelehnt). NaN/Inf löst bei jeder Eingabe ValueError aus.

• Division durch null und Verwandtes wird namentlich abgelehnt: Brennweite 0, Krümmungsradius 0, Brechzahl <= 0, undurchlässige Blende (alles 0, die Normierung wird 0/0), PSF mit Summe <= 0, Stokes-Vektor mit S0 = 0 und ein Objekt im vorderen Brennpunkt (Bild im Unendlichen).

• Nur zwei Operatoren liefern einen nicht-endlichen Wert, und beide halten das vertraglich fest: depth_of_field liefert jenseits der hyperfokalen Distanz far_mm = inf (genau das bedeutet die hyperfokale Distanz), und gaussian_beam liefert an der Taille wavefront_radius_mm = inf (der Krümmungsradius einer ebenen Wellenfront). Beide liefern zusätzlich einen endlichen Partner (far_is_infinite / curvature_per_mm). Jedes andere stille NaN/Inf wird intern erkannt und löst ValueError aus — "float64 ist übergelaufen" und "die Antwort ist unendlich" sind verschiedene Aussagen; die erste wird nie im Gewand der zweiten geliefert.

• Größenobergrenzen: erzeugte Gitter durch optics.MAX_GRID (4096), übergebene Felder/PSFs/Blenden durch optics.MAX_FIELD_ELEMENTS (2^24), ABCD-Elementketten durch optics.MAX_SYSTEM_ELEMENTS (1024), Zernike durch MAX_ZERNIKE_TERMS (512) / MAX_ZERNIKE_ORDER (40) / MAX_ZERNIKE_BASIS (2^25). Damit werden Pfade fail-closed geschlossen, in denen ein kleines Argument eine riesige interne Allokation auslöst (gemessen: n_max=40 × 4096² braucht 108 GB).

• Physikalisch unmögliche Zustände werden ebenfalls abgelehnt: Stokes-Vektor mit Polarisationsgrad > 1, negative Transmission, negative Intensität und ungültige Zernike-Indizes wie ungerades n-|m|.

Ausführlicher Anwendungsleitfaden

• Leitfaden zur Familie optics_imaging

Referenzen (Beispieldaten, Literatur)

• Katalog der Beispieldaten (Download-URLs / Lizenzen) — 2-D nutzt skimage.data (BSD/Public Domain) plus synthetische Bilder, 3-D nennt Download-URLs echter Datenquellen (Stanford, PDS, …).

• Herkunft und Literatur der Operatoren — die Quellen der Forschung/Verfahren, auf denen diese Operatorfamilie beruht.

• Der kanonische Algorithmus (Autor, Jahr) und seine Anwendungen stehen im Familienleitfaden oben.

Ausführbare Beispiele (verifizierte Samples, die diesen Operator wirklich aufrufen)

• optics_four_f_processor — py -3.11 examples/optics_four_f_processor.py

Typkompatible Folge-Operatoren (nehmen cimage als Eingabe)

angular_spectrum_propagate · jones_apply

Gleiche Kategorie (wave)

airy_pattern · angular_spectrum_propagate · fraunhofer_pattern · fourier_plane_filter · gaussian_beam · defocus_from_shift · pupil_psf · pupil_blur


*Provenance: optics.py — OPTICS Operator-Registry. Diese Notiz wird von tools/opdocs.py md erzeugt (nicht von Hand bearbeiten).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.