wavefront_stats — OPTICS imaging op

• Data kinds: table → table

• Call: import fullseye as fs; fs.ledger.wavefront_stats(coeffs, radial=128, angular=192) (implementation को सीधे call करना हो तो import optics; optics.wavefront_stats(coeffs, radial=128, angular=192), registry से लेना हो तो opsoptics.get("wavefront_stats"))

उपयोग

Zernike expansion से wavefront error statistics: RMS, PV और Strehl।

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

*coeffs* is exactly the dict match3d.fit_zernike returns — {(n, m): coefficient}, coefficients in waves — and this op re-uses match3d's own basis builder, so the two cannot drift apart in normalisation or in the (n, m) convention. Fit with fit_zernike, characterise here.

The wavefront is reconstructed on a polar grid (*radial* x *angular*) over the unit pupil and reduced with the area element rho d(rho) d(theta) — an unweighted mean over a uniform-in-rho grid over-counts the centre and is a real, silent, ~10% error.

Returns a dict: rms_waves (piston removed — piston is not an aberration) · pv_waves peak-to-valley over the pupil · strehl the Marechal estimate exp(-(2*pi*rms)^2) · marechal_valid whether rms_waves <= MARECHAL_RMS_LIMIT (0.1), because past that the estimate is optimistic and reporting the number without the caveat is the dishonest option · terms and n_max of the expansion.

Ground truth it reproduces (measured at the defaults): pure defocus {(2, 0): 0.1} — for which Z = 2*rho^2 - 1 has an exact pupil RMS of 1/sqrt(3) — gives rms_waves = 0.0577422 against the exact 0.0577350, a relative error of 1.2e-4 from the discrete quadrature (3.1e-5 at radial=256), and pv_waves = 0.2 exactly; the Strehl is 0.8766676 against the exact 0.8766962. Pure astigmatism {(2, 2): 0.1} (exact RMS 1/sqrt(6)) gives 0.0408280 against 0.0408248. Piston alone ({(0, 0): c}) gives rms 0 and Strehl 1 for any c, and RMS scales exactly linearly in the coefficients (doubling them doubles the RMS to machine precision).

Raises ValueError: *coeffs* is not a dict, is empty, holds more than MAX_ZERNIKE_TERMS terms, has a key that is not an (n, m) int pair or is not a valid Zernike index (n >= 0, |m| <= n, n-|m| even), or a non-finite coefficient; a radial order above MAX_ZERNIKE_ORDER (40 — the shared basis builder's factorial recurrence breaks its own |Z| <= 1 bound at n = 46, measured, and the same bound is re-checked at runtime); *radial* / *angular* outside [8, MAX_GRID].

The radial quadrature is discrete, so its error grows with the order being

integrated: measured, the relative RMS error tracks (n_max/radial)^2 within a factor 2 — 1.2e-4 at n_max=2, 1.7e-3 at n_max=6 and 4.3e-2 at n_max=20, all at the default radial=128. Below radial >= 16*n_max a RuntimeWarning says so rather than letting a 12%-wrong Strehl look authoritative. Raising *radial* fixes it at O(1/radial^2), but note the basis is built for *all* orders up to n_max, so the working set grows as n_max^2 * radial * angular and is capped by MAX_ZERNIKE_BASIS.

Marechal is a small-aberration approximation and the RMS is over the *fitted* expansion, so it says nothing about wavefront structure finer than n_max — and fit_zernike itself discloses ~10% inter-mode crosstalk at its default sampling. Both limits compound; treat the Strehl as an indicator, not a measurement.

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

पृष्ठभूमि guides (इस op के पीछे की physics और conventions)

• measurement_uncertainty — Measurement uncertainty और calibration — 'हम माप रहे हैं' कहने के लिए क्या चाहिए

• mv_cameras — Industrial camera निर्माता (sensor mapping, line scan / TDI)

• virtual_machine_vision — Virtual machine vision — parameters की सूची और एक object model

संदर्भ (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

• poc_zernike_aberrations — py -3.11 examples/poc_zernike_aberrations.py

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

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

इसी category के (imaging)

psf_to_mtf · mtf_diffraction · edge_spread · sfr_from_edge · mtf50 · veiling_glare_index


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