photoelastic_phase_estimate — OPTICS photoelastic op

• Data kinds: polsweep → table

• Call: import fullseye as fs; fs.ledger.photoelastic_phase_estimate(images, analyzers='camera4', min_modulation=0.01, sum_tolerance=0.05) (implementation को सीधे call करना हो तो import photoelastic; photoelastic.photoelastic_phase_estimate(images, analyzers='camera4', min_modulation=0.01, sum_tolerance=0.05), registry से लेना हो तो opsoptics.get("photoelastic_phase_estimate"))

• GPU: नहीं (केवल CPU reference implementation)

उपयोग

ध्रुवण छवियों से मंदन δ और मुख्य अक्ष θ का बंद रूप में व्युत्क्रम → dict।

> नीचे का विस्तृत विवरण मूल text में है — सारांश और headings का अनुवाद हो चुका है।

Inverse of photoelastic_polarization_images (right-circular illumination). With S0 = ½(I0 + I90 + I45 + I135) (the mean of the two pair sums), S1 = I0 − I90, S2 = I45 − I135:

• camera4 (4 linear analysers): sin δ = √(S1² + S2²)/S0 and δ = arcsin(·) — unique only for δ ∈ [0, π/2] (a quarter wave):

linear analysers alone cannot see the sign of cos δ.

• stokes6 (+ right/left circular): S3 = IR − IL and δ = atan2(√(S1² + S2²), S3) ∈ [0, π].

In both, θ = ½ atan2(−S1, S2) mod 180 deg, in (−90, 90] — the fast axis (for a material with C > 0, σ1 lies at θ + 90°). The pair (δ, θ) and (−δ, θ + 90°) give identical images; the estimate returns the representative with δ ≥ 0. Where the modulation √(S1²+S2²)/S0 (= |sin δ|) is at or below min_modulation (default 0.01, i.e. δ within ~0.01 rad of 0 or π, where 1 % intensity noise already turns the axis by tens of degrees) the axis is undefined: axis_valid is False and axis_deg is 0 there.

One exposure obeys I0 + I90 = I45 + I135 (and = IR + IL). Real frames do so only to the noise and the demosaic interpolation, so the check is per pixel and relative: sum_mismatch = |I45 + I135 − (I0 + I90)| / S0 (for stokes6 the larger of that and |IR + IL − S0| / S0).

Parameters

images : (K, H, W) array or list of K frames in the order of analyzers.

analyzers : "camera4" (0/45/90/135) or "stokes6" (+ right/left circular).

min_modulation : modulation at or below which the axis is not reported.

sum_tolerance : largest sum_mismatch a pixel may have and stay valid

(relative to S0, default 0.05). Measured basis: with 1 % independent

noise per frame the mismatch stays below it (99th percentile 2.9 %,

maximum 4.6 % over 40 000 pixels), and the bilinear interpolation of

optics.polarization_demosaic leaves ≤ 1.5 % on 95 % of a disc with

nine resolved fringes; pixels above it are aliased fringes, saturated

or moving pixels, or frames from another exposure. Must lie in [0, 1].

Returns delta_rad, axis_deg, axis_valid, valid (sum_mismatch ≤ sum_tolerance; delta_rad is still computed where it is False but is not a measurement there, and axis_valid is False), sum_mismatch, modulation, intensity (S0) and stokes ((4, H, W); S3 = 0 for camera4, which is a limitation, not a measurement).

Raises ValueError: wrong number of frames, non-2-D / non-finite / negative frames, a dark pixel (S0 = 0), sum_tolerance outside [0, 1], or frames whose pair sums disagree by more than sum_tolerance on more than half of the pixels (not one camera exposure, the wrong frame order, or fringes too dense for the sensor).

पूरी family का input contract (fail-closed)

optics के सभी ops गणना से पहले input की जाँच करते हैं (कुछ भी चुपचाप पास नहीं होता):

• Unit argument के नाम में ही लिखी होती है — _mm / _um / _deg / _mrad। mm और µm की गड़बड़ी crash नहीं करती, बल्कि "सही दिखने वाला पर गलत उत्तर" देती है, इसलिए नाम से इसे रोका जाता है। मान के आकार से unit का अनुमान बिल्कुल नहीं लगाया जाता।

• String से ValueError — float('50') सफल हो जाता है, इसलिए बिना parse किया config value length के रूप में निकल जाता (मापा गया: thin_lens('50', '200') सही दिखने वाला 66.667 mm लौटा रहा था)। bool को भी True == 1 वाले implicit promotion के रूप में अस्वीकार किया जाता है।

• complex / masked array से ValueError (केवल real-valued slots; imaginary part को चुपचाप छोड़ना या mask हटाना अस्वीकार)। हर input पर NaN/Inf से ValueError। घोषित अपवाद: bottle_fit_from_pattern का u_map न मापे जा सके पिक्सेल को NaN के रूप में लेता है (अनंत अब भी अस्वीकार)।

• शून्य से भाग और उससे जुड़े मामलों को नाम लेकर अस्वीकार किया जाता है: focal length 0, radius of curvature 0, refractive index <= 0, पूरी तरह opaque aperture (सब 0, इसलिए normalisation 0/0), ऐसा PSF जिसका योग <= 0 हो, S0 = 0 वाला Stokes vector, और front focal point पर रखा object (image अनंत पर)।

• केवल 2 ops non-finite value लौटाते हैं, और वह भी contract के रूप में लिखा हुआ: depth_of_field hyperfocal distance से आगे far_mm = inf (hyperfocal distance की परिभाषा यही है) और gaussian_beam waist पर wavefront_radius_mm = inf (plane wavefront की radius of curvature)। दोनों साथ में एक finite साथी (far_is_infinite / curvature_per_mm) भी लौटाते हैं। इसके अलावा कोई भी चुपचाप आया NaN/Inf अंदर ही पकड़ा जाता है और ValueError देता है — "float64 overflow हुआ" और "उत्तर अनंत है" अलग-अलग दावे हैं, इसलिए पहले को दूसरे का चेहरा पहनाकर नहीं लौटाया जाता। घोषित अपवाद: bottle_background_map जिन पिक्सेल की किरण अनुपयोगी है (पूर्ण आंतरिक परावर्तन आदि) उनके लिए u_mm में NaN लौटाता है, साथ में valid मास्क और गिनती भी।

• Size की सीमा: generate होने वाले grid के लिए optics.MAX_GRID (4096), दिए गए field/PSF/aperture के लिए optics.MAX_FIELD_ELEMENTS (2^24), ABCD element chain के लिए optics.MAX_SYSTEM_ELEMENTS (1024), Zernike के लिए MAX_ZERNIKE_TERMS (512) / MAX_ZERNIKE_ORDER (40) / MAX_ZERNIKE_BASIS (2^25)। छोटे argument से बहुत बड़ा internal allocation होने वाले रास्तों (मापा गया: n_max=40 × 4096² पर 108 GB) को fail-closed ढंग से बंद किया गया है।

• भौतिक रूप से असंभव states भी अस्वीकार: degree of polarisation > 1 वाला Stokes vector, ऋणात्मक transmittance, ऋणात्मक intensity, और n-|m| odd जैसे अमान्य Zernike indices।

उपयोग की विस्तृत guide

• optics_imaging family guide

संदर्भ (sample data, साहित्य)

• Sample data catalog (DL URL / license) — 2-D के लिए skimage.data (BSD/public) + synthetic, 3-D के लिए real data sources (Stanford/PDS आदि) के DL URL।

• Operators का स्रोत और संदर्भ — इस op family के मूल research/methods के स्रोत।

• Algorithm का मानक स्रोत (लेखक, वर्ष) और उपयोग ऊपर की family usage guide में दिए गए हैं।

चलाए जा सकने वाले उदाहरण (verified samples जो सच में यह op call करते हैं)

• photoelastic_roundtrip — py -3.11 examples/photoelastic_roundtrip.py

• poc_photoelasticity — py -3.11 examples/poc_photoelasticity.py

वे अगले ops जिनसे type जुड़ता है (table को input के रूप में लेते हैं)

abcd_matrix · wavefront_stats · sfr_from_edge · paraxial_trace · seidel_coefficients · spot_stats · tolerance_analysis · wavefront_from_opd

इसी category के (photoelastic)

brazilian_disc_stress · kirsch_plate_stress · principal_stress · retardation_from_birefringence · photoelastic_retardation · retardation_convert · cubic_photoelastic_birefringence · silicon_piezo_optic_coefficients


*Provenance: photoelastic.py — OPTICS operator registry. यह per-op note tools/opdocs.py md से अपने-आप generate होता है (हाथ से edit न करें)।*

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