Skip to content

Propagation¤

FFT

dLux.utils.propagation.FFT(phasor, wavelength, pixel_scale, focal_length=None, pad=2, inverse=False) ¤

Calculates the Fast Fourier Transform (FFT) of the input phasor.

Parameters:

Name Type Description Default
phasor Array[complex]

The input phasor.

required
wavelength (float, meters)

The wavelength of the input phasor.

required
pixel_scale (float, meters / pixel)

The pixel scale of the input phasor.

required
focal_length float = None

The focal length of the propagation. If None, the output pixel scale has units of radians, else meters.

None
pad int = 2

The amount to pad the input array by before propagation. Note this function does not automatically crop the output.

2
inverse bool = False

If False, apply the forward propagation transform. If True, apply the backward propagation transform.

False

Returns:

Name Type Description
phasor Array[complex]

The propagated phasor.

new_pixel_scale float

The pixel scale of the output phasor.

Source code in dLux/utils/propagation.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def FFT(
    phasor: Array,
    wavelength: float,
    pixel_scale: float,
    focal_length: float = None,
    pad: int = 2,
    inverse: bool = False,
) -> Array:
    """
    Calculates the Fast Fourier Transform (FFT) of the input phasor.

    Parameters
    ----------
    phasor : Array[complex]
        The input phasor.
    wavelength : float, meters
        The wavelength of the input phasor.
    pixel_scale : float, meters/pixel
        The pixel scale of the input phasor.
    focal_length : float = None
        The focal length of the propagation. If None, the output pixel scale has units
        of radians, else meters.
    pad : int = 2
        The amount to pad the input array by before propagation. Note this function
        does not automatically crop the output.
    inverse : bool = False
        If False, apply the forward propagation transform. If True, apply the
        backward propagation transform.

    Returns
    -------
    phasor : Array[complex]
        The propagated phasor.
    new_pixel_scale : float
        The pixel scale of the output phasor.
    """
    npixels = phasor.shape[-1]

    # Calculate the output pixel scale
    fringe_size = wavelength / (pixel_scale * npixels)
    new_pixel_scale = fringe_size / pad
    if focal_length is not None:
        new_pixel_scale *= focal_length

    # Pad the input array
    npixels = (npixels * (pad - 1)) // 2
    phasor = np.pad(phasor, npixels)

    # Perform the FFT
    if inverse:
        phasor = np.fft.fftshift(np.fft.ifft2(np.fft.ifftshift(phasor)))
        phasor *= phasor.shape[-1]

    else:
        phasor = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(phasor)))
        phasor /= phasor.shape[-1]
    return phasor, new_pixel_scale
MFT

dLux.utils.propagation.MFT(phasor, wavelength, pixel_scale_in, npixels_out, pixel_scale_out, focal_length=None, shift=np.zeros(2), pixel=True, inverse=False) ¤

Propagates a phasor using a Matrix Fourier Transform (MFT), allowing for output pixel scale and a shift to be specified.

Soummer et al. (2007) describes the MFT formulation: https://arxiv.org/pdf/0711.0368

Parameters:

Name Type Description Default
phasor Array

The input phasor.

required
wavelength (float, meters)

The wavelength of the input phasor.

required
pixel_scale_in (float, meters / pixel, radians / pixel)

The pixel scale of the input plane.

required
npixels_out int

The number of pixels in the output plane.

required
pixel_scale_out (float, meters / pixel or radians / pixel)

The pixel scale of the output plane.

required
focal_length float = None

The focal length of the propagation. If None, the propagation is angular and pixel_scale_out is taken in as radians/pixel, else meters/pixel.

None
shift Array = np.zeros(2)

The shift in the center of the output plane.

zeros(2)
pixel bool = True

Should the shift be taken in units of pixels, or pixel scale.

True
inverse bool = False

If False, apply the forward propagation transform. If True, apply the backward propagation transform.

False

Returns:

Name Type Description
phasor Array

The propagated phasor.

Source code in dLux/utils/propagation.py
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
def MFT(
    phasor: Array,
    wavelength: float,
    pixel_scale_in: float,
    npixels_out: int,
    pixel_scale_out: float,
    focal_length: float = None,
    shift: Array = np.zeros(2),
    pixel: bool = True,
    inverse: bool = False,
) -> Array:
    """
    Propagates a phasor using a Matrix Fourier Transform (MFT), allowing for output
    pixel scale and a shift to be specified.

    Soummer et al. (2007) describes the MFT formulation: https://arxiv.org/pdf/0711.0368

    Parameters
    ----------
    phasor : Array
        The input phasor.
    wavelength : float, meters
        The wavelength of the input phasor.
    pixel_scale_in : float, meters/pixel, radians/pixel
        The pixel scale of the input plane.
    npixels_out : int
        The number of pixels in the output plane.
    pixel_scale_out : float, meters/pixel or radians/pixel
        The pixel scale of the output plane.
    focal_length : float = None
        The focal length of the propagation. If None, the propagation is angular and
        pixel_scale_out is taken in as radians/pixel, else meters/pixel.
    shift : Array = np.zeros(2)
        The shift in the center of the output plane.
    pixel : bool = True
        Should the shift be taken in units of pixels, or pixel scale.
    inverse : bool = False
        If False, apply the forward propagation transform. If True, apply the
        backward propagation transform.

    Returns
    -------
    phasor : Array
        The propagated phasor.
    """
    # Get parameters
    npixels_in = phasor.shape[-1]
    if not pixel:
        shift /= pixel_scale_out

    # Alias the transfer matrix function
    get_tf_mat = lambda s: transfer_matrix(
        wavelength,
        npixels_in,
        pixel_scale_in,
        npixels_out,
        pixel_scale_out,
        s,
        focal_length,
        0.0,
        inverse,
    )

    # Get transfer matrices and propagate
    x_mat, y_mat = vmap(get_tf_mat)(shift)
    phasor = (y_mat.T @ phasor) @ x_mat

    # Normalise
    nfringes = calc_nfringes(
        wavelength,
        npixels_in,
        pixel_scale_in,
        npixels_out,
        pixel_scale_out,
        focal_length,
    )
    phasor *= np.exp(np.log(nfringes) - (np.log(npixels_in) + np.log(npixels_out)))

    return phasor