hswfs.sensor
This module provides the main class that is used to simulates a Hartmann-Shack wavefront sensor (HSWFS).
- class hswfs.sensor.HSWFS(relative_shifts: ndarray, aperture_size: int = 32)[source]
A virtual Hartmann-Shack wavefront sensor.
- Parameters
relative_shifts – A numpy array of shape (N, N, 2), where N is the grid size, containing the relative shift (or offset) for each subaperture. “Relative” means that the shift values are in [-1, 1].
aperture_size – An integer specifying the size of a subaperture in pixels (subapertures are assumed to be quadratic).
- fit_wavefront(n_zernike: int = 9) ndarray[source]
Perform a modal (i.a. Zernike polynomial-based) least squares fit to find the wavefront that matches the sensor data. The result is a vector of Zernike coefficients.
For more details (also about, for example, the notation), please see [Cubalchini_1979]. For an alternative discussion of the same topic, see also, for example, section 4.3.2 of [Dai_2007].
Note
Note that the code in this package uses a slightly different notation for indexing the Zernike polynomials: when using only a single index \(j\), we start counting them at \(j = 0\) (the constant polynomial which corresponds to \(Z^0_0\) when using double indices \(m\) and \(n\)). [Cubalchini_1979], on the other hand, starts counting the Zernike polynomials at 1, which is clearly unpythonic :)
Note
For compatibility reasons, the coefficient vector that is return by the function will also contain a value for the first Zernike polynomial \(Z^0_0\), which is always set to be zero. the coefficient vector will, therefore, have n_zernike + 1 entries.
Warning
Fitting the wavefront requires the Cartesian derivatives of the Zernike polynomials. Computing these “on the fly” is relatively slow, which is why there exists the
hswfs.fast_zernikemodule, which contains pre-computed versions of these derivatives up to \(j = 135\). If n_zernike is chosen to be larger than this value, fitting the wavefront may take a relatively long time. However, for most practical purposes, using this many Zernike polynomials will probably be unnecessary.- Parameters
n_zernike – The number of Zernike polynomials to be used in the fit. Note that \(Z^0_0\) (the constant term) is ignored in the fit. The index j_max of the Zernike polynomial with the highest order will, therefore, be n_zernike + 1.
- Returns
A numpy array of length n_zernike + 1, where the \(j\)-th entry is the coefficient that corresponds to the Zernike polynomial \(Z_j\).
- static get_psf(wavefront: Wavefront, resolution: int = 256) ndarray[source]
Compute the point spread function (PSF) that corresponds to the given wavefront. This needs to happen in discretized form, because in the general case, the integral that connects the PSF and the wavefront is not analytically tractable.
The mathematics in this function — using the FFT to compute the PSF — is based on section (14.15), particularly on eq. (14.188), in [Malacara_2007], as well as the exemplary MATLAB implementation on appendix 8.C of [Dai_2007].
For small abberations, there exists an analytical approximation based on the Fourier transformations of the Zernike polynomials. It can be found in eq. (8.28) in [Dai_2007], where it is also formally derived in appendix 8.B.
Warning
Please note that the point spread function will, in general, also depend on the wavelength \(\lambda\). This dependency is currently not correctly modeled by the get_psf() function; instead, \(\lambda = 1\) is used.
- Parameters
wavefront –
resolution – The size of the grid on which the wavefront is computed (and thus also the PSF).
- Returns
The PSF that corresponds to the wavefront that was fitted to the sensor data.