mtf

Modulation Transfer Function (MTF) subpackage.

This subpackage provides classes for calculating the MTF of optical systems using different methods.

Kramer Harrison, 2025

class FFTMTF(optic, fields: str | list = 'all', wavelength: str | float = 'primary', num_rays=128, grid_size=None, max_freq='cutoff', strategy='chief_ray', remove_tilt=False, **kwargs)[source]

Factory class for generating either a Vectorial or Scalar FFT MTF.

This class inspects the optical system’s polarization state to determine which FFT MTF implementation to instantiate. If polarization is enabled, it returns a VectorialFFTMTF. Otherwise, it returns a ScalarFFTMTF.

Parameters:
  • optic (Optic) – The optical system object.

  • fields (str or list, optional) – The field coordinates for which to calculate the MTF. Defaults to ‘all’.

  • wavelength (str or float, optional) – The wavelength of light to use. Defaults to ‘primary’.

  • num_rays (int, optional) – The number of rays to use for the PSF calculation. Defaults to 128.

  • grid_size (int or None, optional) – The FFT grid size. Defaults to None.

  • max_freq (str or float, optional) – The maximum frequency for the MTF calculation. Defaults to ‘cutoff’.

  • strategy (str) – The wavefront calculation strategy. Defaults to “chief_ray”.

  • remove_tilt (bool) – If True, removes tilt from OPD. Defaults to False.

  • **kwargs – Additional keyword arguments passed to the strategy.

class GeometricMTF(optic: Optic, fields: str | list = 'all', wavelength: str | float = 'primary', num_rays=100, distribution: DistributionType = 'uniform', num_points=256, max_freq='cutoff', scale=True)[source]

Smith, Modern Optical Engineering 3rd edition, Section 11.9

This class represents the Geometric MTF (Modulation Transfer Function) of an optical system. It inherits from the SpotDiagram class.

Parameters:
  • optic (Optic) – The optical system for which to calculate the MTF.

  • fields (str or list, optional) – The field points at which to calculate the MTF. Defaults to ‘all’.

  • wavelength (str or float, optional) – The wavelength at which to calculate the MTF. Defaults to ‘primary’.

  • num_rays (int, optional) – The number of rays to trace for each field point. Defaults to 100.

  • distribution (str, optional) – The distribution of rays within each field point. Defaults to ‘uniform’.

  • num_points (int, optional) – The number of points to sample in the MTF curve. Defaults to 256.

  • max_freq (str or float, optional) – The maximum frequency to consider in the MTF curve. Defaults to ‘cutoff’.

  • scale (bool, optional) – Whether to scale the MTF curve using the diffraction-limited curve. Defaults to True.

num_points

The number of points to sample in the MTF curve.

Type:

int

scale

Whether to scale the MTF curve.

Type:

bool

max_freq

The maximum frequency to consider in the MTF curve.

Type:

float

freq

The frequency values for the MTF curve.

Type:

be.ndarray

mtf

The MTF data for each field point. Each element is a list containing tangential and sagittal MTF data (be.ndarray) for a field.

Type:

list

diff_limited_mtf

The diffraction-limited MTF curve.

Type:

be.ndarray

view(figsize=(12, 4), add_reference=False)[source]

Plots the MTF curve.

_generate_mtf_data()[source]

Generates the MTF data for each field point.

_compute_field_data(xi, v, scale_factor)[source]

Computes the MTF data for a given field point.

_plot_field(ax, mtf_data, field, color)[source]

Plots the MTF data for a given field point.

airy_disc_x_y(wavelength: float) tuple[list[float], list[float]]

Generates the Airy disk radii for the x and y axes for each field.

Parameters:

wavelength – The wavelength for the calculation.

Returns:

x-axis radii and y-axis radii per field.

Return type:

A tuple of two lists

airy_radius(n_w: float, wavelength: float) float

Calculates the Airy disk radius.

Parameters:
  • n_w – The physical F-number.

  • wavelength – The wavelength of light in micrometers.

Returns:

The Airy disk radius.

angle_from_cosine(a: BEArray, b: BEArray) float

Calculates the angle in radians between two direction cosine vectors.

Parameters:
  • a – The first direction cosine vector.

  • b – The second direction cosine vector.

Returns:

The angle between the vectors in radians.

centroid() list[tuple[BEArray, BEArray]]

Calculates the geometric centroid of each spot for the reference wavelength.

Returns:

A list of (x, y) centroid coordinates for each field.

f_number(n: float, theta: float) float

Calculates the physical F-number.

Parameters:
  • n – The refractive index of the medium.

  • theta – The half-angle of the cone of light in radians.

Returns:

The calculated physical F-number.

generate_chief_rays_centers(wavelength: float) BEArray

Generates the (x, y) intersection points for the chief ray of each field.

Parameters:

wavelength – The wavelength for the rays.

Returns:

An array of shape (num_fields, 2) with (x, y) coordinates.

generate_chief_rays_cosines(wavelength: float) BEArray

Generates direction cosines for the chief ray of each field.

Parameters:

wavelength – The wavelength for the rays.

Returns:

An array of shape (num_fields, 3) containing the direction cosines.

generate_marginal_rays(H_x: float, H_y: float, wavelength: float) tuple

Generates marginal rays at the four cardinal points of the pupil.

Parameters:
  • H_x – The x-field coordinate.

  • H_y – The y-field coordinate.

  • wavelength – The wavelength for the rays.

Returns:

A tuple containing the traced rays for north, south, east, and west pupil points.

generate_marginal_rays_cosines(H_x: float, H_y: float, wavelength: float) tuple

Generates direction cosines for each marginal ray of a given field.

Parameters:
  • H_x – The x-field coordinate.

  • H_y – The y-field coordinate.

  • wavelength – The wavelength for the rays.

Returns:

A tuple of direction cosine vectors for north, south, east, and west rays.

geometric_spot_radius() list[list[BEArray]]

Calculates the maximum geometric spot radius for each spot.

Returns:

A nested list of maximum radii for each field and wavelength.

rms_spot_radius() list[list[BEArray]]

Calculates the root-mean-square (RMS) spot radius for each spot.

Returns:

A nested list of RMS radii for each field and wavelength.

view(fig_to_plot_on: Figure | None = None, figsize: tuple[float, float] = (12, 4), add_reference: bool = False) tuple[Figure, Axes][source]

Plots the MTF curve.

Parameters:
  • fig_to_plot_on (plt.Figure, optional) – The figure to plot on. If provided, the existing figure is cleared and reused. Defaults to None, which creates a new figure.

  • figsize (tuple, optional) – The size of the figure. Defaults to (12, 4).

  • add_reference (bool, optional) – Whether to add the diffraction limit reference curve. Defaults to False.

Returns:

A tuple containing the matplotlib figure and axes objects.

If fig_to_plot_on is provided, the existing figure is cleared and reused; otherwise, a new figure is created.

Return type:

tuple

class HuygensMTF(optic, fields: str | list = 'all', wavelength: str | float = 'primary', num_rays=128, image_size=128, max_freq='cutoff')[source]

Factory class for generating either a Vectorial or Scalar Huygens MTF.

This class inspects the optical system’s polarization state to determine which Huygens MTF implementation to instantiate. If polarization is enabled, it returns a VectorialHuygensMTF. Otherwise, it returns a ScalarHuygensMTF.

Parameters:
  • optic (Optic) – The optical system object.

  • fields (str or list, optional) – The field coordinates for which to calculate the MTF. Defaults to ‘all’.

  • wavelength (str or float, optional) – The wavelength of light to use. Defaults to ‘primary’.

  • num_rays (int, optional) – The number of rays to use for the PSF calculation. Defaults to 128.

  • image_size (int, optional) – The size of the image grid for PSF calculation and subsequent MTF. Defaults to 128.

  • max_freq (str or float, optional) – The maximum frequency for the MTF calculation in cycles/mm. Defaults to ‘cutoff’.

class SampledMTF(optic, field, wavelength: str | float, num_rays=128, distribution='uniform', zernike_terms=37, zernike_type='fringe')[source]

Sampled Modulation Transfer Function (MTF) class.

This class calculates the MTF of an optical system from sampled wavefront data. It utilizes Zernike polynomial fitting to represent the wavefront aberrations.

Note

This class assumes that amplitude variations between the pupil and a shifted version of the pupil can be ignored.

Parameters:
  • optic (Optic) – The optical system.

  • field (tuple) – The field point (Hx, Hy) at which to calculate the MTF.

  • wavelength (str or float) – The wavelength (in mm) at which to calculate the MTF. Can be ‘primary’ to use the optic’s primary wavelength.

  • num_rays (int, optional) – The number of rings to trace for the wavefront analysis. Defaults to 128 in each axis.

  • distribution (str, optional) – The distribution of rays in the pupil. Defaults to ‘uniform’.

  • zernike_terms (int, optional) – The number of Zernike terms to use for the wavefront fit. Defaults to 37.

  • zernike_type (str, optional) – The type of Zernike polynomials to use (‘fringe’, ‘standard’, etc.). Defaults to ‘fringe’.

optic

The optical system.

Type:

Optic

field

The field point (Hx, Hy).

Type:

tuple

wavelength

The wavelength (in mm) used for calculation.

Type:

float

num_rays

The number of rays used for wavefront analysis.

Type:

int

distribution

The ray distribution in the pupil.

Type:

str

zernike_terms

The number of Zernike terms for the fit.

Type:

int

zernike_type

The type of Zernike polynomials used.

Type:

str

x_norm

Normalized x-coordinates of pupil samples.

Type:

be.ndarray

y_norm

Normalized y-coordinates of pupil samples.

Type:

be.ndarray

opd_waves

Optical Path Difference (OPD) in waves.

Type:

be.ndarray

intensity

Intensity at each pupil sample point.

Type:

be.ndarray

zernike_fit

The Zernike fit object.

Type:

ZernikeFit

P1

The complex pupil function.

Type:

be.ndarray

otf_at_zero

The value of the Optical Transfer Function (OTF) at zero frequency, equivalent to the sum of intensities.

Type:

float

calculate_mtf(frequencies)[source]

Calculates the Modulation Transfer Function (MTF) for given spatial frequencies.

The method computes the MTF by determining the Optical Transfer Function (OTF) from the overlap integral of the pupil function with a shifted version of itself. The shift corresponds to the spatial frequency being evaluated. The MTF is the absolute value of the normalized OTF.

Parameters:

frequencies (list[tuple[float, float]] or be.ndarray) – A list or array of tuples, where each tuple (fx, fy) represents a spatial frequency pair in cycles per mm for which to calculate the MTF.

Returns:

A list of MTF values corresponding to each input frequency pair. The MTF values are dimensionless and range from 0 to 1.

Return type:

list[float]

Notes

The calculation involves: 1. Retrieving the exit pupil diameter (XPD). If XPD is near zero,

MTF is 0 for non-zero frequencies and 1 for zero frequency.

  1. Converting the wavelength to mm.

  2. For each frequency pair (fx, fy):
    1. Calculating physical shifts in the pupil based on wavelength and frequency.

    2. Normalizing these shifts using the XPD radius & exit pupil position.

    3. Determining the shifted normalized coordinates for pupil evaluation.

    4. Evaluating the Optical Path Difference (OPD) at these shifted coordinates using the Zernike polynomial fit of the wavefront.

    5. Masking points where the shifted evaluation falls outside the unit circle (i.e., outside the pupil).

    6. Computing the complex conjugate of the pupil function at the shifted coordinates (P2_conj).

    7. Calculating the OTF element as the product of the original complex pupil function (P1) and P2_conj.

    8. Summing the OTF elements over all pupil sample points to get the total OTF value for the given frequency.

    9. Normalizing the OTF value by otf_at_zero (the OTF at zero frequency).

    10. The MTF is the absolute value of this normalized OTF.

class ScalarFFTMTF(optic, fields: str | list = 'all', wavelength: str | float = 'primary', num_rays=128, grid_size=None, max_freq='cutoff', strategy='chief_ray', remove_tilt=False, **kwargs)[source]

Scalar Fast Fourier Transform Modulation Transfer Function class.

This class calculates and visualizes the Modulation Transfer Function (MTF) of an optic using the scalar FFT method. It is intended for use with unpolarized optical systems. Use the FFTMTF factory to automatically select between scalar and vectorial implementations based on the optic’s polarization state.

Parameters:
  • optic (Optic) – The optic for which to calculate the MTF.

  • fields (str or list, optional) – The field coordinates for which to calculate the MTF. Defaults to ‘all’.

  • wavelength (str or float, optional) – The wavelength of light to use for the MTF calculation. Defaults to ‘primary’.

  • num_rays (int, optional) – The number of rays to use for the PSF calculation, which is then used for MTF. Defaults to 128.

  • grid_size (int or None, optional) – The size of the grid used for the PSF/MTF calculation. If None, the grid size will be calculated from num_rays as documented in optiland.psf.fft.ScalarFFTPSF. Defaults to None.

  • max_freq (str or float, optional) – The maximum frequency for the MTF calculation. Defaults to ‘cutoff’.

  • strategy (str) – The calculation strategy to use. Supported options are “chief_ray”, “centroid_sphere”, and “best_fit_sphere”. Defaults to “chief_ray”.

  • remove_tilt (bool) – If True, removes tilt and piston from the OPD data. Defaults to False.

  • **kwargs – Additional keyword arguments passed to the strategy.

num_rays

The number of rays used for the MTF calculation.

Type:

int

grid_size

The size of the grid used for the MTF calculation.

Type:

int

max_freq

The maximum frequency for the MTF calculation.

Type:

float

FNO

The F-number of the optic.

Type:

float

psf

List of PSF data for each field.

Type:

list

mtf

List of MTF data ([tangential, sagittal]) for each field.

Type:

list

freq

Array of frequency points for the MTF curve.

Type:

be.ndarray

view(fig_to_plot_on: Figure | None = None, figsize: tuple[float, float] = (12, 4), add_reference: bool = False) tuple[Figure, Axes]

Visualizes the Modulation Transfer Function (MTF).

This method sets up the plot and iterates through field data, calling _plot_field_mtf for each field’s specific plotting.

Subclasses must ensure self.mtf, self.freq, and self.max_freq are populated before calling this method. self.resolved_fields (from __init__) is also used.

Parameters:
  • fig_to_plot_on (plt.Figure, optional) – The figure to plot on. If None, a new figure will be created. Defaults to None.

  • figsize (tuple, optional) – The size of the figure. Defaults to (12, 4).

  • add_reference (bool, optional) – Whether to overlay the theoretical diffraction-limited MTF curve for a clear circular aperture. The reference is computed using the on-axis working F/# and the resolved wavelength. Defaults to False.

Returns:

A tuple containing the figure and axes objects.

Return type:

tuple

class ScalarHuygensMTF(optic, fields: str | list = 'all', wavelength: str | float = 'primary', num_rays=128, image_size=128, max_freq='cutoff')[source]

Scalar Huygens Modulation Transfer Function class.

This class calculates and visualizes the Modulation Transfer Function (MTF) of an optic using a Point Spread Function (PSF) derived from the Huygens-Fresnel principle. It is intended for use with unpolarized optical systems. Use the HuygensMTF factory to automatically select between scalar and vectorial implementations based on the optic’s polarization state.

Supports both the NumPy and PyTorch backends. The underlying Huygens-Fresnel summation uses Numba (NumPy) or batched tensor operations (PyTorch) transparently via the strategy pattern in ScalarHuygensPSF.

Parameters:
  • optic (Optic) – The optic for which to calculate the MTF.

  • fields (str or list, optional) – The field coordinates for which to calculate the MTF. Defaults to ‘all’.

  • wavelength (str or float, optional) – The wavelength of light to use for the MTF calculation. Defaults to ‘primary’.

  • num_rays (int, optional) – The number of rays to use for the HuygensPSF calculation along one dimension of the pupil grid. Defaults to 128.

  • image_size (int, optional) – The size of the image grid for PSF calculation and subsequent MTF. Defaults to 128.

  • max_freq (str or float, optional) – The maximum frequency for the MTF calculation in cycles/mm. If ‘cutoff’, it’s determined by the diffraction limit (1 / (lambda * FNO)). Defaults to ‘cutoff’.

num_rays

The number of rays used for the PSF calculation.

Type:

int

image_size

The size of the grid used for the PSF/MTF calculation.

Type:

int

max_freq

The maximum frequency for the MTF calculation (cycles/mm).

Type:

float

FNO

The F-number of the optic.

Type:

float

psf_data

List of 2D PSF data arrays for each field.

Type:

list

psf_instances

List of PSF instances for each field.

Type:

list

mtf

List of MTF data ([tangential, sagittal]) for each field.

Type:

list

freq

Array of frequency points for the MTF curve (cycles/mm).

Type:

be.ndarray

view(fig_to_plot_on: Figure | None = None, figsize: tuple[float, float] = (12, 4), add_reference: bool = False) tuple[Figure, Axes]

Visualizes the Modulation Transfer Function (MTF).

This method sets up the plot and iterates through field data, calling _plot_field_mtf for each field’s specific plotting.

Subclasses must ensure self.mtf, self.freq, and self.max_freq are populated before calling this method. self.resolved_fields (from __init__) is also used.

Parameters:
  • fig_to_plot_on (plt.Figure, optional) – The figure to plot on. If None, a new figure will be created. Defaults to None.

  • figsize (tuple, optional) – The size of the figure. Defaults to (12, 4).

  • add_reference (bool, optional) – Whether to overlay the theoretical diffraction-limited MTF curve for a clear circular aperture. The reference is computed using the on-axis working F/# and the resolved wavelength. Defaults to False.

Returns:

A tuple containing the figure and axes objects.

Return type:

tuple

class VectorialFFTMTF(optic, fields: str | list = 'all', wavelength: str | float = 'primary', num_rays=128, grid_size=None, max_freq='cutoff', strategy='chief_ray', remove_tilt=False, **kwargs)[source]

Vectorial Fast Fourier Transform Modulation Transfer Function class.

This class calculates the MTF of an optical system using the vectorial FFT method. It accounts for the full 3D electric field at the exit pupil and is intended for use with polarized optical systems. Use the FFTMTF factory to automatically select between scalar and vectorial implementations based on the optic’s polarization state.

Inherits all constructor arguments and attributes from ScalarFFTMTF.

view(fig_to_plot_on: Figure | None = None, figsize: tuple[float, float] = (12, 4), add_reference: bool = False) tuple[Figure, Axes]

Visualizes the Modulation Transfer Function (MTF).

This method sets up the plot and iterates through field data, calling _plot_field_mtf for each field’s specific plotting.

Subclasses must ensure self.mtf, self.freq, and self.max_freq are populated before calling this method. self.resolved_fields (from __init__) is also used.

Parameters:
  • fig_to_plot_on (plt.Figure, optional) – The figure to plot on. If None, a new figure will be created. Defaults to None.

  • figsize (tuple, optional) – The size of the figure. Defaults to (12, 4).

  • add_reference (bool, optional) – Whether to overlay the theoretical diffraction-limited MTF curve for a clear circular aperture. The reference is computed using the on-axis working F/# and the resolved wavelength. Defaults to False.

Returns:

A tuple containing the figure and axes objects.

Return type:

tuple

class VectorialHuygensMTF(optic, fields: str | list = 'all', wavelength: str | float = 'primary', num_rays=128, image_size=128, max_freq='cutoff')[source]

Vectorial Huygens Modulation Transfer Function class.

This class calculates the MTF of an optical system using the vectorial Huygens-Fresnel method. It accounts for the full 3D electric field at the exit pupil and is intended for use with polarized optical systems. Use the HuygensMTF factory to automatically select between scalar and vectorial implementations based on the optic’s polarization state.

Inherits all constructor arguments and attributes from ScalarHuygensMTF.

view(fig_to_plot_on: Figure | None = None, figsize: tuple[float, float] = (12, 4), add_reference: bool = False) tuple[Figure, Axes]

Visualizes the Modulation Transfer Function (MTF).

This method sets up the plot and iterates through field data, calling _plot_field_mtf for each field’s specific plotting.

Subclasses must ensure self.mtf, self.freq, and self.max_freq are populated before calling this method. self.resolved_fields (from __init__) is also used.

Parameters:
  • fig_to_plot_on (plt.Figure, optional) – The figure to plot on. If None, a new figure will be created. Defaults to None.

  • figsize (tuple, optional) – The size of the figure. Defaults to (12, 4).

  • add_reference (bool, optional) – Whether to overlay the theoretical diffraction-limited MTF curve for a clear circular aperture. The reference is computed using the on-axis working F/# and the resolved wavelength. Defaults to False.

Returns:

A tuple containing the figure and axes objects.

Return type:

tuple