mueller_element — OPTICS polarization op

• Datenarten: keine → matrix (ein Operator, der allein durch seine Argumente bestimmt ist — er nimmt kein Bild und keine Daten entgegen)

• Aufruf: import fullseye as fs; fs.ledger.mueller_element(kind='polarizer', angle_deg=0.0, retardance_deg=90.0) (die Implementierung direkt: import optics; optics.mueller_element(kind='polarizer', angle_deg=0.0, retardance_deg=90.0); aus dem Register: opsoptics.get("mueller_element"))

• GPU: nein (nur CPU-Referenzimplementierung)

Verwendung

Eine reelle 4x4-Müller-Matrix für ein Polarisationselement.

> Die ausführliche Beschreibung unten ist der Originaltext — Zusammenfassung und Überschriften sind übersetzt.

*kind* is one of MUELLER_KINDS — the same five as jones_element plus "depolarizer" (ideal, diag(1, 0, 0, 0)), which has no Jones counterpart at all. That extra kind is the reason this family exists: Jones algebra can only carry fully polarised light, Mueller algebra carries partial polarisation, scattering and depolarisation — which is what a real polarisation camera sees.

Angles are doubled inside (c = cos(2a), s = sin(2a)) because the Stokes parameters live on the Poincare sphere, where a physical rotation by a is a rotation by 2a.

Returns a (4, 4) float64 matrix acting on [S0, S1, S2, S3]; apply it

with mueller_apply and compose a train as M_last @ ... @ M_first.

Ground truth it reproduces exactly: an ideal polariser transmits exactly half of unpolarised light ([1,0,0,0] -> S0 = 0.5) and fully polarises it; two polarisers at relative angle theta transmit 0.5*cos^2(theta) (Malus); a rotator by 45 degrees turns horizontal into 45-degree linear; the depolariser leaves S0 and kills S1..S3. Cross-checked against the Jones family in the tests — for every kind and a sweep of angles, the Jones path and the Mueller path return the same Stokes vector to 1e-14, which is the only construction that catches a sign slip in either one.

Raises ValueError: an unknown *kind*; non-finite *angle_deg*; or, for kind="retarder", non-finite *retardance_deg*.

Ideal, lossless (except the polariser's physical loss), normal-incidence elements; no diattenuation-plus-retardance combinations, no depolarisation other than the ideal case. A polariser with a finite extinction ratio

is mueller_partial_polarizer.

Per-pixel fields (2026-10-23). An array *angle_deg* (or, for kind="retarder", an array *retardance_deg*) returns (*shape, 4, 4), one matrix per entry of the broadcast shape — an isoclinic angle map and a retardance map of a photoelastic part give the whole field in one call, ready for mueller_apply's field form. Before this the call raised ValueError and the photoelasticity PoC had to assemble (H, W, 4, 4) by hand. Scalars take the original code path untouched (scalar results are bit-for-bit what they were; pinned by a test against a verbatim copy of the old code). Output capped at MAX_FIELD_ELEMENTS numbers.

Angle convention. *angle_deg* is measured from +x (along a row) toward +y (down the rows): clockwise on a displayed image — the sense of atan2(ny, nx) of a normal map and of 0.5 * atan2(2 txy, sxx - syy) for image-coordinate stresses. See the polarisation section comment of this module.

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. Ausnahme, ausdrücklich erklärt: Das u_map von bottle_fit_from_pattern nimmt nicht gemessene Pixel als NaN entgegen (Unendlich wird weiterhin abgelehnt).

• 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. Ausnahme, ausdrücklich erklärt: bottle_background_map liefert für Pixel mit unbrauchbarem Strahl (Totalreflexion u. Ä.) NaN in u_mm, zusammen mit einer valid-Maske und den Anzahlen.

• 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_imaging — py -3.11 examples/optics_imaging.py

• poc_mueller_dofp_observability — py -3.11 examples/poc_mueller_dofp_observability.py

• poc_photoelasticity — py -3.11 examples/poc_photoelasticity.py

• polarization_camera_pipeline — py -3.11 examples/polarization_camera_pipeline.py

Typkompatible Folge-Operatoren (nehmen matrix als Eingabe)

abcd_trace · emva_filter_distortion · mueller_apply · mueller_checks · equirect_rotate · pixel_shift_capture · pixel_shift_merge · pixel_shift_motion_mask

Gleiche Kategorie (polarization)

jones_element · jones_apply · stokes_from_jones · mueller_partial_polarizer · mueller_apply · stokes_analyze · polarization_demosaic · polarization_demosaic_color


*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.