prysm.otf#

MTF/PTF/OTF calculations.

prysm.otf.transform_psf(psf, dx=None)#

Transform a PSF to k-space without further modification.

prysm.otf.transform_psf_adjoint(data_bar)#

Apply the adjoint of the linear FT performed by transform_psf.

transform_psf maps a real PSF to the complex k-space field fftshift(fft2(ifftshift(psf))). This is its conjugate-transpose: it maps a gradient defined on the k-space field back to the PSF plane. The df scalar returned by transform_psf is sampling metadata and carries no gradient.

Parameters:

data_bar (ndarray) – gradient at the k-space (OTF) plane

Returns:

gradient at the PSF plane

Return type:

ndarray

prysm.otf.mtf_from_psf(psf, dx=None, return_more=False)#

Compute the MTF from a given PSF.

Parameters:
  • psf (prysm.RichData or ndarray) – object with data property having 2D data containing the psf, or the array itself

  • dx (float) – sample spacing of the data

  • return_more (bool) – if True, also return the complex k-space transform of the PSF (the same array transform_psf produces). Hand it to mtf_from_psf_adjoint as data to skip recomputing the forward FT in the reverse pass.

Returns:

  • RichData – container holding the MTF, ready for plotting or slicing.

  • ndarray – the complex transform; only returned if return_more is True.

prysm.otf.ptf_from_psf(psf, dx=None, return_more=False)#

Compute the PTF from a given PSF.

Parameters:
  • psf (prysm.RichData or ndarray) – object with data property having 2D data containing the psf, or the array itself

  • dx (float) – sample spacing of the data

  • return_more (bool) – if True, also return the complex k-space transform of the PSF (the same array transform_psf produces). Hand it to ptf_from_psf_adjoint as data to skip recomputing the forward FT in the reverse pass.

Returns:

  • RichData – container holding the MTF, ready for plotting or slicing.

  • ndarray – the complex transform; only returned if return_more is True.

prysm.otf.otf_from_psf(psf, dx=None, return_more=False)#

Compute the OTF from a given PSF.

Parameters:
  • psf (ndarray) – 2D data containing the psf

  • dx (float) – sample spacing of the data

  • return_more (bool) – if True, also return the complex k-space transform of the PSF (the same array transform_psf produces, prior to the center normalization). Hand it to otf_from_psf_adjoint as data to skip recomputing the forward FT in the reverse pass.

Returns:

  • RichData – container holding the OTF, complex.

  • ndarray – the unnormalized complex transform; only returned if return_more is True.

prysm.otf.mtf_ptf_otf_from_psf(psf, dx=None, return_more=False)#

Compute the MTF, PTF, and OTF from a PSF with a single forward transform.

The three transfer functions are the modulus, argument, and complex value of the same center-normalized transform, so computing them together does the forward FT once instead of once per quantity.

Parameters:
  • psf (prysm.RichData or ndarray) – object with data property having 2D data containing the psf, or the array itself

  • dx (float) – sample spacing of the data

  • return_more (bool) – if True, also return the raw complex transform of the PSF, prior to the center normalization, as transform_psf produces it.

Returns:

  • mtf, ptf, otf (RichData) – the modulation, phase, and complex optical transfer functions

  • ndarray – the raw complex transform; only returned if return_more is True.

prysm.otf.mtf_from_psf_adjoint(mtf_bar, psf=None, dx=None, data=None)#

Apply the adjoint of mtf_from_psf.

Maps a gradient defined on the (center-normalized) MTF back to the real PSF. The forward map is mtf = abs(F[psf]) / abs(F[psf])[center]; this differentiates through both the modulus and the normalization by the central value.

Parameters:
  • mtf_bar (ndarray) – gradient at the MTF plane

  • psf (prysm.RichData or ndarray) – the PSF the MTF was computed from; used to recompute the forward FT when data is not supplied

  • dx (float) – sample spacing of the PSF; required if psf is a bare array

  • data (ndarray) – the complex transform from mtf_from_psf(…, return_more=True). When given, the forward FT is reused instead of recomputed and psf/dx are ignored.

Returns:

gradient at the PSF plane

Return type:

ndarray

prysm.otf.ptf_from_psf_adjoint(ptf_bar, psf=None, dx=None, data=None)#

Apply the adjoint of ptf_from_psf.

Maps a gradient defined on the (center-referenced) PTF back to the real PSF. The forward map is ptf = angle(F[psf]) - angle(F[psf])[center].

Parameters:
  • ptf_bar (ndarray) – gradient at the PTF plane

  • psf (prysm.RichData or ndarray) – the PSF the PTF was computed from; used to recompute the forward FT when data is not supplied

  • dx (float) – sample spacing of the PSF; required if psf is a bare array

  • data (ndarray) – the complex transform from ptf_from_psf(…, return_more=True). When given, the forward FT is reused instead of recomputed and psf/dx are ignored.

Returns:

gradient at the PSF plane

Return type:

ndarray

prysm.otf.otf_from_psf_adjoint(otf_bar, psf=None, dx=None, data=None)#

Apply the adjoint of otf_from_psf.

Maps a gradient defined on the (center-normalized) complex OTF back to the real PSF. The forward map is otf = F[psf] / F[psf][center].

Parameters:
  • otf_bar (ndarray) – gradient at the OTF plane; complex

  • psf (prysm.RichData or ndarray) – the PSF the OTF was computed from; used to recompute the forward FT when data is not supplied

  • dx (float) – sample spacing of the PSF; required if psf is a bare array

  • data (ndarray) – the unnormalized complex transform from otf_from_psf(…, return_more=True). When given, the forward FT is reused instead of recomputed and psf/dx are ignored.

Returns:

gradient at the PSF plane

Return type:

ndarray

prysm.otf.encircled_energy(psf, dx, radius, return_more=False)#

Compute the encircled energy of the PSF.

Parameters:
  • psf (ndarray) – 2D array containing PSF data

  • dx (float) – sample spacing of psf

  • radius (float or iterable) – radius or radii to evaluate encircled energy at

  • return_more (bool) – if True, also return the complex k-space transform of the PSF. Hand it to encircled_energy_adjoint as data to skip recomputing the forward FT in the reverse pass.

Returns:

  • encircled energy – if radius is a float, returns a float, else returns an array.

  • ndarray – the complex transform; only returned if return_more is True.

Notes

implementation of “Simplified Method for Calculating Encircled Energy,” Baliga, J. V. and Cohn, B. D., doi: 10.1117/12.944334

prysm.otf.encircled_energy_adjoint(ee_bar, psf=None, dx=None, radius=None, data=None)#

Apply the adjoint of encircled_energy.

Encircled energy is a linear functional of the MTF (a radius-weighted sum of a Hankel kernel against the MTF), so its adjoint folds the per-radius gradients into a single MTF-plane gradient and routes that back through mtf_from_psf_adjoint to the PSF.

Parameters:
  • ee_bar (float or ndarray) – gradient of the loss with respect to the encircled energy; a scalar for a single radius, otherwise one value per radius matching radius

  • psf (prysm.RichData or ndarray) – the PSF the encircled energy was computed from; used to recompute the forward FT when data is not supplied

  • dx (float) – sample spacing of the PSF; always required, as it sets the frequency grid

  • radius (float or iterable) – the radius/radii encircled_energy was evaluated at

  • data (ndarray) – the complex transform from encircled_energy(…, return_more=True). When given, the forward FT is reused instead of recomputed.

Returns:

gradient at the PSF plane

Return type:

ndarray

prysm.otf.analytical_encircled_energy_circular_aperture(fno, wavelength, points)#

Compute the analytical encircled energy for a diffraction limited circular aperturnp.

Parameters:
  • fno (float) – F/#

  • wavelength (float) – wavelength of light

  • points (ndarray) – radii of “detector”

Returns:

encircled energy values

Return type:

ndarray

prysm.otf.diffraction_limited_mtf(fno, wavelength, frequencies=None, samples=128)#

Give the diffraction limited MTF for a circular pupil and the given parameters.

Parameters:
  • fno (float) – f/# of the lens.

  • wavelength (float) – wavelength of light, in microns.

  • frequencies (ndarray) – spatial frequencies of interest, in cy/mm if frequencies are given, samples is ignored.

  • samples (int) – number of points in the output array, if frequencies not given.

Returns:

  • if frequencies not given

    frequenciesndarray

    array of ordinate data

    mtfndarray

    array of coordinate data

  • else

    mtfndarray

    array of MTF data

Notes

If frequencies are given, just returns the MTF. If frequencies are not given, returns both the frequencies and the MTF.

prysm.otf.longexposure_otf(nu, Cn, z, f, lambdabar, h_z_by_r=2.91)#

Compute the long exposure OTF for given parameters.

Parameters:
  • nu (ndarray) – spatial frequencies, cy/mm

  • Cn (float) – atmospheric structure constant of refractive index, ranges ~ 10^-13 - 10^-17

  • z (float) – propagation distance through atmosphere, m

  • f (float) – effective focal length of the optical system, mm

  • lambdabar (float) – mean wavelength, microns

  • h_z_by_r (float, optional) – constant for h[z/r] – see Eq. 8.5-37 & 8.5-38 in Statistical Optics, J. Goodman, 2nd ed.

Returns:

the OTF

Return type:

ndarray

prysm.otf.komogorov(r, r0)#

Calculate the phase structure function D_phi in the komogorov approximation.

Parameters:
  • r (ndarray) – r, radial frequency parameter (object space)

  • r0 (float) – Fried parameter

Return type:

ndarray

prysm.otf.estimate_Cn(P=1013, T=273.15, Ct=0.0001)#

Use Weng et al to estimate Cn from meteorological data.

Parameters:
  • P (float) – atmospheric pressure in hPa

  • T (float) – temperature in Kelvin

  • Ct (float) – atmospheric struction constant of temperature, typically 10^-5 - 10^-2 near the surface

Returns:

Cn

Return type:

float