PSFs¶
PSFs in prysm have a very simple constructor;
>>> import numpy as np
>>> from prysm import PSF
>>> x = y = np.linspace(-1,1,128)
>>> z = np.random.random((128,128))
>>> ps = PSF(data=z, unit_x=x, unit_y=y)
PSFs are usually created from a pupil instance in a model, but the constructor can be used with e.g. experimental data.
>>> ps = PSF.from_pupil(your_pupil)
The encircled energy can be computed, for either a single point or an iterable (tuple, list, numpy array, …) of points;
>>> print(ps.encircled_energy(0.1), ps.encircled_energy([0.1, 0.2, 0.3])
12.309576159990891, array([12.30957616, 24.61581586, 36.92244558])
encircled energy is computed via the method described in V Baliga, B D Cohn, “Simplified Method For Calculating Encircled Energy,” Proc. SPIE 0892, Simulation and Modeling of Optical Systems, (9 June 1988).
The inverse can also be computed using the L-BFGS-B nonlinear optimization routine, but the wavelength and F/# must be provided for the initial guess,
>>> ps.wavelength, ps.fno = 0.5, 2
>>> print(ps.ee_radius(1))
0.008104694339936169
Baliga’s method is relatively slow for large arrays, so a dictionary is kept of all computed encircled energies at ps._ee
. The encircled energy can be plotted. An axis limit must be provided if no encircled energy values have been computed. If some have, by default prysm will plot the computed values if no axis limit is given
>>> ps.plot_encircled_energy()
or
>>> ps.plot_encircled_energy(axlim=1, npts=50)
The PSF can be plotted in 2D,
>>> # ~0.838, exact value of energy contained in first airy zero
>>> from prysm.psf import FIRST_AIRY_ENCIRCLED
>>> ps.plot2d(axlim=0.8, power=2, interp_method='sinc', pix_grid=0.2, show_axlabels=True, show_colorbar=True, circle_ee=FIRST_AIRY_ENCIRCLED)
Both plot_encircled_energy
and plot2d
take the usual fig
and ax
kwargs as well. For plot2d, the axlim arg sets the x and y axis limits to symmetrical values of axlim
, i.e. the limits above will be [0.8, 0.8], [0.8, 0.8]. power
controls the stretch of the color scale. The image will be stretched by the 1/power power, e.g. 2 plots psf^(1/2). interp_method
is passed to matplotlib. pix_grid
will use the minor axis ticks to draw a light grid over the PSF, intended to show the size of a PSF relative to the pixels of a detector. Units of microns. show_axlabels
and show_colorbar
both default to True, and control whether the axis labels are set and if the colorbar is drawn. circle_ee
will draw a dashed circle at the radius containing the specified portion of the energy, and another at the diffraction limited radius for a circular aperture.
PSFs are a subclass of Convolvable
and inherit all methods and attributes. The complete documentation is below.
-
class
prysm.psf.
PSF
(data, unit_x, unit_y)[source]¶ Bases:
prysm.convolution.Convolvable
A Point Spread Function.
- center_x : int
- center sample along x
- center_y : int
- center sample along y
- data : numpy.ndarray
- PSF normalized intensity data
- sample_spacing : float
- center to center spacing of samples
- unit_x : numpy.ndarray
- x Cartesian axis locations of samples, 1D ndarray
- unit_y numpy.ndarray
- y Cartesian axis locations of samples, 1D ndarray
-
encircled_energy
(radius)[source]¶ Compute the encircled energy of the PSF.
- radius : float or iterable
- radius or radii to evaluate encircled energy at
- encircled energy
- if radius is a float, returns a float, else returns a list.
implementation of “Simplified Method for Calculating Encircled Energy,” Baliga, J. V. and Cohn, B. D., doi: 10.1117/12.944334
-
static
from_pupil
(pupil, efl, Q=2)[source]¶ Use scalar diffraction propogation to generate a PSF from a pupil.
- pupil : Pupil
- Pupil, with OPD data and wavefunction
- efl : int or float
- effective focal length of the optical system
- Q : int or float
- ratio of pupil sample count to PSF sample count; Q > 2 satisfies nyquist
- PSF
- A new PSF instance
-
plot2d
(axlim=25, power=1, clim=(None, None), interp_method='lanczos', pix_grid=None, invert=False, fig=None, ax=None, show_axlabels=True, show_colorbar=True, circle_ee=None, circle_ee_lw=None)[source]¶ Create a 2D plot of the PSF.
- axlim : float
- limits of axis, symmetric. xlim=(-axlim,axlim), ylim=(-axlim, axlim)
- power : float
- power to stretch the data by for plotting
- clim : iterable
- limits to use for log color scaling. If power != 1 and clim != (None, None), clim (log axes) takes precedence
- interp_method : string
- method used to interpolate the image between samples of the PSF
- pix_grid : float
- if not None, overlays gridlines with spacing equal to pix_grid. Intended to show the collection into camera pixels while still in the oversampled domain
- invert : bool, optional
- whether to invert the color scale
- fig : matplotlib.figure.Figure, optional:
- Figure containing the plot
- ax : matplotlib.axes.Axis, optional:
- Axis containing the plot
- show_axlabels : bool
- whether or not to show the axis labels
- show_colorbar : bool
- whether or not to show the colorbar
- circle_ee : float, optional
- relative encircled energy to draw a circle at, in addition to diffraction limited airy radius (1.22*λ*F#). First airy zero occurs at circle_ee=0.8377850436212378
- circle_ee_lw : float, optional
- linewidth passed to matplotlib for the encircled energy circles
- fig : matplotlib.figure.Figure, optional
- Figure containing the plot
- ax : matplotlib.axes.Axis, optional
- Axis containing the plot
-
plot_encircled_energy
(axlim=None, npts=50, lw=3, fig=None, ax=None)[source]¶ Make a 1D plot of the encircled energy at the given azimuth.
- azimuth : float
- azimuth to plot at, in degrees
- axlim : float
- limits of axis, will plot [0, axlim]
- npts : int, optional
- number of points to use from [0, axlim]
- lw : float, optional
- linewidth provided directly to matplotlib
- fig : matplotlib.figure.Figure, optional
- Figure containing the plot
- ax : matplotlib.axes.Axis, optional:
- Axis containing the plot
- fig : matplotlib.figure.Figure, optional
- Figure containing the plot
- ax : matplotlib.axes.Axis, optional:
- Axis containing the plot