stokes_analyze — OPTICS polarization op

• Data kinds: stokes → table

• Call: import fullseye as fs; fs.ledger.stokes_analyze(stokes) (implementation को सीधे call करना हो तो import optics; optics.stokes_analyze(stokes), registry से लेना हो तो opsoptics.get("stokes_analyze"))

उपयोग

Stokes vector पढ़ता है: degree of polarisation, azimuth, ellipticity।

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

Returns a dict: intensity S0 · dop degree of polarisation sqrt(S1^2+S2^2+S3^2)/S0 · dolp linear part sqrt(S1^2+S2^2)/S0 · docp circular part |S3|/S0 · azimuth_deg orientation of the polarisation ellipse 0.5*atan2(S2, S1) mapped into [0, 180) · ellipticity_deg 0.5*asin(S3/|S|) in [-45, +45] · handedness one of "right" / "left" / "linear". The ellipticity is that of the polarised part (S3 over sqrt(S1^2+S2^2+S3^2)); pypolar divides by S0 instead, which for partially polarised light mixes the unpolarised part into the ellipse — the two agree only for fully polarised light (measured 2026-09-18).

azimuth_deg and ellipticity_deg are None when they are undefined — azimuth when the linear part is exactly zero (circular or unpolarised light has no orientation), ellipticity when the polarised part is zero (unpolarised light has no ellipse). Returning 0.0 there would be a fabricated angle; None says the truth and forces the caller to handle it.

Ground truth it reproduces exactly: [1,1,0,0] -> dop 1, azimuth 0, ellipticity 0, linear; [1,-1,0,0] -> azimuth 90; [1,0,1,0] -> azimuth 45; [1,0,0,1] -> docp 1, ellipticity +45, right-handed; [1,0,0,0] -> dop 0 with both angles None; [2,1,0,0] -> dop 0.5 (a partially polarised beam, which is exactly the case Jones algebra cannot express).

Raises ValueError: *stokes* is not a 1-D 4-vector, is complex / masked / non-finite, is unphysical (S0 < 0 or degree of polarisation above 1 — which is how you find out a Mueller matrix was not physical), or has S0 == 0 (no light at all: every ratio would be 0/0, and "the polarisation of darkness" is not a question with an answer).

पूरी 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।

• शून्य से भाग और उससे जुड़े मामलों को नाम लेकर अस्वीकार किया जाता है: 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 हुआ" और "उत्तर अनंत है" अलग-अलग दावे हैं, इसलिए पहले को दूसरे का चेहरा पहनाकर नहीं लौटाया जाता।

• 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 करते हैं)

• optics_imaging — py -3.11 examples/optics_imaging.py

• polarization_camera_pipeline — py -3.11 examples/polarization_camera_pipeline.py

• specular_photometric — py -3.11 examples/specular_photometric.py

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

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

इसी category के (polarization)

jones_element · jones_apply · stokes_from_jones · mueller_element · mueller_apply · polarization_demosaic · polarization_demosaic_color · mueller_from_intensities


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

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