Lens MTF Model

In this tutorial, we will show how to use prysm to model the MTF of a lens based on a polynomial model of its aberrations. We will utilize the concepts from the First Diffraction Model tutorial in constructing the forward model.

MTF is defined as the magnitude of the Fourier transform of the Point Spread Function (PSF), normalized by its value at the origin. Without writing the normalization, that is simply:

\[\text{MTF}\left(\nu_x,\nu_y\right) = \left| \mathfrak{F}\left[\text{PSF}\left(x,y\right)\right] \right|\]

To make this tutorial a bit more interesting, we will use an N-sided aperture, as if our lens were stopped down and has a finite number of aperture blades. We will also assume no vignetting. Instead of Hopkins’ polynomials as used previously, we will use Zernike polynomials which are orthogonal over the unit disk. Everything scales with F/#, but we’ll assume its 8 and the focal length is 50 mm as reasonable photographic examples.

The first step in this model is to form the aperture:

[1]:
from prysm.coordinates import make_xy_grid, cart_to_polar
from prysm.geometry import regular_polygon

from matplotlib import pyplot as plt
[2]:
efl = 50
fno = 8

x, y = make_xy_grid(256, diameter=efl/fno)
dx = x[0,1]-x[0,0]
r, t = cart_to_polar(x, y)
radius = efl/fno/2
rho = r / radius
n_sides = 14

aperture = regular_polygon(n_sides, radius, x, y)

plt.imshow(aperture, origin='lower')
[2]:
<matplotlib.image.AxesImage at 0x7f30e5ac5550>
../_images/tutorials_Lens-MTF-Model_2_1.png

Once we have our model of the aperture, we can model its phase error and compute the PSF. We will assume for the moment that the illumination is monochromatic, as a separate tutorial deals with polychromatic propagation. We’ll assume, too, that there’s \(\lambda/14\) RMS of wavefront error; the lens just meets the Marechal Criteria for “diffraction limited.”

[3]:
from prysm.polynomials import zernike_nm
from prysm.propagation import Wavefront
wvl = 0.55 # mid visible band, um

wfe_nm_rms = wvl/14*1e3 # nm, 3/4 of a wave, 1e3 = um to nm
mode = zernike_nm(4, 0, rho, t)
opd = mode * wfe_nm_rms
pup = Wavefront.from_amp_and_phase(aperture, opd, wvl, dx)
coherent_psf = pup.focus(efl, Q=2)

At this point, we are in posession of the coherent PSF, which we will recall can be converted to the incoherent PSF with the .intensity computed property. From there, we simply use the mtf_from_psf function to compute the MTF.

[4]:
from prysm.otf import mtf_from_psf, diffraction_limited_mtf
psf = coherent_psf.intensity
mtf = mtf_from_psf(psf)

This is the diffraction limited MTF for a circular aperture, but it’s close enough for the 14-gon example.

We can start by plotting the X and Y slices of the MTF. If we are on axis, or aligned to a cartesian axis of the image plane, these are the tangential and sagittal MTFs.

[5]:
fx, _ = mtf.slices().x
fig, ax = mtf.slices().plot(['x', 'y', 'azavg'], xlim=(0,200))
difflim = diffraction_limited_mtf(fno, wvl, fx)

ax.plot(fx, difflim, ls=':', c='k', alpha=0.75, zorder=1)
ax.set(xlabel='Spatial frequency, cy/mm', ylabel='MTF')
[5]:
[Text(0.5, 0, 'Spatial frequency, cy/mm'), Text(0, 0.5, 'MTF')]
../_images/tutorials_Lens-MTF-Model_8_1.png

We can see the lens has a bit lower MTF than the diffraction limit. In other words, the Marechal criteria does not mean lens MTF == diffraction limit, even thought the lens is “diffraction limited.” We can also see the x and y MTFs are identical, since spherical aberration, \(Z_4^0\) is rotationally invariant. What if the lens had an equivalent amount of coma?

[6]:
wfe_nm_rms = wvl/14*1e3
mode = zernike_nm(3, 1, rho, t) # only this line changed
opd = mode * wfe_nm_rms
pup = Wavefront.from_amp_and_phase(aperture, opd, wvl, dx)
coherent_psf = pup.focus(efl, Q=2)
psf = coherent_psf.intensity
mtf = mtf_from_psf(psf, psf.dx)

fig, ax = mtf.slices().plot(['x', 'y', 'azavg'], xlim=(0,200))

ax.plot(fx, difflim, ls=':', c='k', alpha=0.75, zorder=1)
ax.set(xlabel='Spatial frequency, cy/mm', ylabel='MTF')
[6]:
[Text(0.5, 0, 'Spatial frequency, cy/mm'), Text(0, 0.5, 'MTF')]
../_images/tutorials_Lens-MTF-Model_10_1.png

Now we can see a similar level of departure from the diffraction limit, and it varies as a function of the angle in k-space (“tangential” and “sagittal,” in this case)

If you were interested in the phase transfer function or the OTF itself, the functions are ptf_from_psf and otf_from_psf, and they work the same way.

In summary, to model the MTF of a system:

  • create a model of the pupil

  • create a model of the OPD within the pupil

  • propagate the pupil to a PSF plane and take its intensity (for incoherent systems)

  • use mtf_from_psf to compute the MTF