through_focus_mtf — OPTICS imaging_sim op

• Data kinds: table → table

• Call: import fullseye as fs; fs.ledger.through_focus_mtf(system, frequency_cpmm=None, defocus_mm=None, field=None, wavelength_um=None, size=None, tangential_axis='y') (to call the implementation directly, import lensimage; lensimage.through_focus_mtf(system, frequency_cpmm=None, defocus_mm=None, field=None, wavelength_um=None, size=None, tangential_axis='y'); from the registry, opsoptics.get("through_focus_mtf"))

Usage

Tangential and sagittal MTF at chosen spatial frequencies for a range of image-plane positions (table).

For each image-plane shift in *defocus_mm* (mm, added to the system's image distance; positive moves the plane away from the lens) the diffraction PSF of the real pupil is computed as in psf_from_opd (the reference sphere is re-centred on the shifted plane, so the shift appears as defocus in the OPD) and its tangential and sagittal MTF are read from the 2-D transform at each frequency of *frequency_cpmm* (cycles per millimetre; linear interpolation on the exact grid frequencies, which are spaced 1 / ((size - 1) λ F#) apart). *tangential_axis* = 'y' is the meridional plane for fields along +y, as everywhere in raytrace.

Defaults: *frequency_cpmm* = 10, 25 and 50 % of the diffraction cutoff 1 / (λ F#); *defocus_mm* = 11 points over ±2 waves of defocus W20 = δ / (8 F#² λ).

Returns {"defocus_mm" (nd,), "frequency_cpmm" (nf,), "tangential" (nd, nf), "sagittal" (nd, nf), "best_focus_mm", "cutoff_cpmm", "fno", "field"}. best_focus_mm is the shift that maximises the mean of the tangential and sagittal MTF at the first frequency (parabolic refinement through the three points around the maximum; the end of the range when the maximum is there, which means the range was too short to bracket the focus).

Ground truth it reproduces: for an aberration-free lens (an ideal paraxial surface) the in-focus MTF is the circular-pupil closed form and the defocused MTF is Hopkins' integral of the pupil overlap (tested against an independent quadrature, including the loss of contrast to zero at the first zero crossing); a rotationally symmetric on-axis system gives identical tangential and sagittal curves, and an off-axis singlet separates them (astigmatism).

The PSF grid is oversampled 2x, so its Nyquist limit equals the diffraction cutoff and the MTF at a grid frequency does not depend on the oversampling (the transform of the periodic PSF is the pupil autocorrelation).

Raises ValueError: a bad system, *field*, *wavelength_um* or *size* (see psf_from_opd); an empty or non-finite *frequency_cpmm* or *defocus_mm* (at most 64 each); a negative frequency or one above the diffraction cutoff of the PSF grid; *tangential_axis* not 'x' or 'y'.

Family-wide input contract (fail-closed)

Every optics op validates its input before computing (nothing slips through silently):

• Units are baked into the argument name — _mm / _um / _deg / _mrad. Confusing mm with µm does not crash; it yields a plausible-looking wrong answer, so the name prevents it. Nothing here guesses the unit from the magnitude.

• Strings raise ValueError — float('50') succeeds, so an unparsed configuration value would slip through as a length (measured: thin_lens('50', '200') returned a plausible 66.667 mm). bool is refused too, as the implicit promotion True == 1.

• complex / masked arrays raise ValueError (real-valued slots only; silently dropping the imaginary part or peeling off the mask is refused). NaN/Inf raises ValueError on every input.

• Division by zero and its relatives are refused by name: focal length 0, radius of curvature 0, refractive index <= 0, a fully opaque aperture (all zeros, so the normalisation is 0/0), a PSF whose sum is <= 0, a Stokes vector with S0 = 0, and an object sitting at the front focal point (the image is at infinity).

• Only two ops return a non-finite value, and both state it as a contract: depth_of_field returns far_mm = inf beyond the hyperfocal distance (that is what the hyperfocal distance means), and gaussian_beam returns wavefront_radius_mm = inf at the waist (the radius of curvature of a plane wavefront). Both also return a finite companion (far_is_infinite / curvature_per_mm). Any other silent NaN/Inf is detected internally and raises ValueError — "float64 overflowed" and "the answer is infinite" are different claims, so the first is never returned wearing the face of the second.

• Size caps: generated grids are capped by optics.MAX_GRID (4096); supplied fields/PSFs/apertures by optics.MAX_FIELD_ELEMENTS (2^24); ABCD element chains by optics.MAX_SYSTEM_ELEMENTS (1024); Zernike by MAX_ZERNIKE_TERMS (512) / MAX_ZERNIKE_ORDER (40) / MAX_ZERNIKE_BASIS (2^25). This closes, fail-closed, the paths where a small argument triggers a huge internal allocation (measured: n_max=40 × 4096² needs 108 GB).

• Physically impossible states are refused too: a Stokes vector with degree of polarisation > 1, negative transmittance, negative intensity, and invalid Zernike indices such as n-|m| odd.

Detailed usage guide

• optics_imaging family guide

Background guides (the physics and conventions behind this op)

• mv_cables — Cables (standards, speed, power delivery, robot cables)

• mv_cameras — Industrial camera makers (sensor mapping, line scan / TDI)

• mv_frame_grabbers — Frame grabber boards (not optics, but they decide whether you can capture at all)

• mv_image_sensors — Industrial image sensors (mainly current products)

• mv_standards — Camera interface standards and the bodies behind them

• virtual_machine_vision — Virtual machine vision — enumerating the parameters and an object model

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

• The canonical algorithm (author, year) and its uses are named in the family usage guide above.

Runnable examples (verified samples that actually call this op)

• optical_design_metrics — py -3.11 examples/optical_design_metrics.py

Ops the type connects to (they accept table as input)

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

Same category (imaging_sim)

psf_from_opd · distortion_map · render_through_lens · defect_dataset · calibration_views


*Provenance: lensimage.py — OPTICS operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

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