pado.light.Light

class Light(dim, pitch, wvl, field=None, device='cpu')[source]

Light wave with complex field wavefront.

Represent a light wave with complex field wavefront that can be manipulated through various optical operations.

Parameters:
__init__(dim, pitch, wvl, field=None, device='cpu')[source]

Create light wave instance with complex field wavefront.

Parameters:
  • dim (tuple) – Field dimensions (B, Ch, R, C) for batch, channels, rows, cols

  • pitch (float) – Pixel pitch in meters

  • wvl (float or list) – Wavelength in meters. Can be single value or list for multi-wavelength

  • field (torch.Tensor, optional) – Initial complex field [B, Ch, R, C]

  • device (str) – Device for computation (‘cpu’, ‘cuda:0’, etc.)

Examples

>>> light = Light(dim=(1, 1, 1024, 1024), pitch=6.4e-6, wvl=633e-9)
>>> light = Light(dim=(2, 3, 512, 512), pitch=2e-6, wvl=[450e-9, 550e-9, 650e-9])
crop(crop_width)[source]

Crop light wavefront.

Parameters:

crop_width (tuple) – Crop dimensions (left, right, top, bottom)

Return type:

None

Examples

>>> light.crop((32, 32, 32, 32))
clone()[source]

Create deep copy of light instance.

Returns:

New light instance with copied attributes

Return type:

Light

Examples

>>> light_copy = light.clone()
pad(pad_width, padval=0)[source]

Pad light field with constant value.

Parameters:
  • pad_width (tuple) – Padding dimensions (left, right, top, bottom)

  • padval (int) – Padding value (only 0 supported)

Return type:

None

Examples

>>> light.pad((16, 16, 16, 16))  # Add 16 pixels padding on all sides
set_real(real, c=None)[source]

Set real part of light wavefront.

Parameters:
  • real (torch.Tensor) – Real part in rectangular representation. If c is None: Expected shape is (B,Ch,R,C) matching self.field.real.shape If c is provided: Expected shape is (B,R,C) matching self.field[:, c, …].real.shape where B=batch size, Ch=channels, R=rows, C=columns

  • c (int, optional) – Channel index to modify. If provided, only that specific channel will be updated.

Return type:

None

Examples

>>> # Set real part for all channels (B=1, Ch=1, R=1024, C=1024)
>>> real_part = torch.ones((1, 1, 1024, 1024))  # (B,Ch,R,C)
>>> light.set_real(real_part)
>>>
>>> # Set real part for only channel 0 (B=1, R=1024, C=1024)
>>> real_part_channel0 = torch.ones((1, 1024, 1024))  # (B,R,C)
>>> light.set_real(real_part_channel0, c=0)
set_imag(imag, c=None)[source]

Set imaginary part of light wavefront.

Parameters:
  • imag (torch.Tensor) – Imaginary part in rectangular representation. If c is None: Expected shape is (B,Ch,R,C) matching self.field.imag.shape If c is provided: Expected shape is (B,R,C) matching self.field[:, c, …].imag.shape where B=batch size, Ch=channels, R=rows, C=columns

  • c (int, optional) – Channel index to modify. If provided, only that specific channel will be updated.

Return type:

None

Examples

>>> # Set imaginary part for all channels (B=1, Ch=1, R=1024, C=1024)
>>> imag_part = torch.ones((1, 1, 1024, 1024))  # (B,Ch,R,C)
>>> light.set_imag(imag_part)
>>>
>>> # Set imaginary part for only channel 0 (B=1, R=1024, C=1024)
>>> imag_part_channel0 = torch.ones((1, 1024, 1024))  # (B,R,C)
>>> light.set_imag(imag_part_channel0, c=0)
set_amplitude(amplitude, c=None)[source]

Set amplitude of light wavefront (keeps phase unchanged) without maintaining computation graph.

Parameters:
  • amplitude (torch.Tensor) – Amplitude in polar representation.

  • c (int, optional) – Channel index to modify.

Return type:

None

set_phase(phase, c=None)[source]

Set phase of light wavefront (keeps amplitude unchanged).

Parameters:
  • phase (torch.Tensor) – Phase in polar representation (in radians). If c is None: Expected shape is (B,Ch,R,C) matching self.field.shape If c is provided: Expected shape is (B,R,C) matching self.field[:, c, …].shape where B=batch size, Ch=channels, R=rows, C=columns

  • c (int, optional) – Channel index to modify. If provided, only that specific channel will be updated.

Return type:

None

Examples

>>> # Set phase for all channels (B=1, Ch=1, R=1024, C=1024)
>>> phase = torch.zeros((1, 1, 1024, 1024))  # (B,Ch,R,C)
>>> light.set_phase(phase)
>>>
>>> # Set phase for only channel 0 (B=1, R=1024, C=1024)
>>> phase_channel0 = torch.zeros((1, 1024, 1024))  # (B,R,C)
>>> light.set_phase(phase_channel0, c=0)
set_field(field, c=None)[source]

Set complex field of light wavefront.

Parameters:
  • field (torch.Tensor) – Complex field tensor. If c is None: Expected shape is (B,Ch,R,C) matching self.field.shape If c is provided: Expected shape is (B,R,C) matching self.field[:, c, …].shape where B=batch size, Ch=channels, R=rows, C=columns

  • c (int, optional) – Channel index to modify. If provided, only that specific channel will be updated.

Return type:

None

Examples

>>> # Set field for all channels (B=1, Ch=1, R=1024, C=1024)
>>> field = torch.ones((1, 1, 1024, 1024), dtype=torch.complex64)  # (B,Ch,R,C)
>>> light.set_field(field)
>>>
>>> # Set field for only channel 0 (B=1, R=1024, C=1024)
>>> field_channel0 = torch.ones((1, 1024, 1024), dtype=torch.complex64)  # (B,R,C)
>>> light.set_field(field_channel0, c=0)
set_pitch(pitch)[source]

Set pixel pitch of light field.

Parameters:

pitch (float) – New pixel pitch in meters

Return type:

None

Examples

>>> light.set_pitch(6.4e-6)  # Set 6.4μm pitch
get_channel()[source]

Return number of channels in light field.

Returns:

Number of channels

Return type:

int

Examples

>>> channels = light.get_channel()
get_amplitude(c=None)[source]

Get amplitude of light wavefront.

Parameters:

c (int, optional) – Channel index to retrieve. If provided, only that specific channel will be returned.

Returns:

Amplitude in polar representation.

If c is None: Shape is (B,Ch,R,C) If c is provided: Shape is (B,R,C) where B=batch size, Ch=channels, R=rows, C=columns

Return type:

torch.Tensor

Examples

>>> # Get amplitude for all channels (B=1, Ch=1, R=1024, C=1024)
>>> amp = light.get_amplitude()  # Shape: (1, 1, 1024, 1024)
>>>
>>> # Get amplitude for only channel 0 (B=1, R=1024, C=1024)
>>> amp_channel0 = light.get_amplitude(c=0)  # Shape: (1, 1024, 1024)
get_phase(c=None)[source]

Get phase of light wavefront.

Parameters:

c (int, optional) – Channel index to retrieve. If provided, only that specific channel will be returned.

Returns:

Phase in polar representation (in radians).

If c is None: Shape is (B,Ch,R,C) If c is provided: Shape is (B,R,C) where B=batch size, Ch=channels, R=rows, C=columns

Return type:

torch.Tensor

Examples

>>> # Get phase for all channels (B=1, Ch=1, R=1024, C=1024)
>>> phase = light.get_phase()  # Shape: (1, 1, 1024, 1024)
>>>
>>> # Get phase for only channel 0 (B=1, R=1024, C=1024)
>>> phase_channel0 = light.get_phase(c=0)  # Shape: (1, 1024, 1024)
get_intensity(c=None)[source]

Get intensity (amplitude squared) of light wavefront.

Parameters:

c (int, optional) – Channel index to retrieve. If provided, only that specific channel will be returned.

Returns:

Intensity values.

If c is None: Shape is (B,Ch,R,C) If c is provided: Shape is (B,R,C) where B=batch size, Ch=channels, R=rows, C=columns

Return type:

torch.Tensor

Examples

>>> # Get intensity for all channels (B=1, Ch=1, R=1024, C=1024)
>>> intensity = light.get_intensity()  # Shape: (1, 1, 1024, 1024)
>>>
>>> # Get intensity for only channel 0 (B=1, R=1024, C=1024)
>>> intensity_channel0 = light.get_intensity(c=0)  # Shape: (1, 1024, 1024)
get_field(c=None)[source]

Get complex field of light wavefront.

Parameters:

c (int, optional) – Channel index to retrieve. If provided, only that specific channel will be returned.

Returns:

Complex field tensor.

If c is None: Shape is (B,Ch,R,C) If c is provided: Shape is (B,R,C) where B=batch size, Ch=channels, R=rows, C=columns

Return type:

torch.Tensor

Examples

>>> # Get field for all channels (B=1, Ch=1, R=1024, C=1024)
>>> field = light.get_field()  # Shape: (1, 1, 1024, 1024), dtype=torch.complex64
>>>
>>> # Get field for only channel 0 (B=1, R=1024, C=1024)
>>> field_channel0 = light.get_field(c=0)  # Shape: (1, 1024, 1024), dtype=torch.complex64
get_device()[source]

Return device of light field.

Returns:

Device name (‘cpu’, ‘cuda:0’, etc.)

Return type:

str

Examples

>>> device = light.get_device()
get_bandwidth()[source]

Return spatial bandwidth of light wavefront.

Returns:

Spatial height and width of wavefront in meters

Return type:

tuple

Examples

>>> height, width = light.get_bandwidth()
get_ideal_angle_limit()[source]

Return ideal angle limit of light wavefront based on optical axis.

Calculate the maximum diffraction angle supported by the current sampling, based on the Nyquist sampling criterion: sin(θ_max) = λ/(2·pitch). Use the shortest wavelength for multi-wavelength cases.

Returns:

Ideal angle limit in degrees

Return type:

float

Examples

>>> angle_limit = light.get_ideal_angle_limit()
magnify(scale_factor, interp_mode='nearest', c=None)[source]

Change wavefront resolution without changing pixel pitch.

Parameters:
  • scale_factor (float) – Scale factor for interpolation

  • interp_mode (str) – Interpolation method (‘bilinear’ or ‘nearest’)

  • c (int, optional) – Channel index to modify

Return type:

None

Examples

>>> light.magnify(2.0)  # Double resolution
>>> light.magnify(0.5, interp_mode='bilinear')  # Half resolution
resize(target_pitch, interp_mode='nearest')[source]

Resize wavefront by changing pixel pitch.

Parameters:
  • target_pitch (float) – New pixel pitch in meters

  • interp_mode (str) – Interpolation method (‘bilinear’ or ‘nearest’)

Return type:

None

Examples

>>> light.resize(4e-6)  # Change pitch to 4μm
set_spherical_light(z, dx=0.0, dy=0.0)[source]

Set spherical wavefront from point source.

Parameters:
  • z (float) – Distance from source along optical axis

  • dx (float) – Lateral x-offset of source

  • dy (float) – Lateral y-offset of source

Return type:

None

Examples

>>> light.set_spherical_light(z=0.1)  # Source at 10cm
>>> light.set_spherical_light(z=0.05, dx=1e-3)  # Offset source
set_plane_light(theta=0)[source]

Set plane wave with unit amplitude.

Parameters:

theta (float) – Incident angle in degrees

Return type:

None

Examples

>>> light.set_plane_light(theta=15)  # 15° incident angle
set_amplitude_ones()[source]

Set amplitude to ones. :rtype: None

Examples

>>> light.set_amplitude_ones()
Return type:

None

set_amplitude_zeros()[source]

Set amplitude to zeros. :rtype: None

Examples

>>> light.set_amplitude_zeros()
Return type:

None

set_phase_zeros()[source]

Set phase to zeros. :rtype: None

Examples

>>> light.set_phase_zeros()
Return type:

None

set_phase_random(std=1.5707963267948966, distribution='gaussian', c=None)[source]

Set random phase with specified distribution.

Parameters:
  • std (float, optional) – Standard deviation for phase randomness. - For gaussian: Standard deviation in radians - For uniform: Half-width of uniform distribution in radians - For von_mises: Inverse of concentration parameter (1/κ) Defaults to π/2.

  • distribution (str, optional) – Type of random distribution. Must be one of [‘gaussian’, ‘uniform’, ‘von_mises’]. Defaults to ‘gaussian’.

  • c (int, optional) – Channel index to modify. If None, all channels are modified.

Raises:

ValueError – If distribution is not one of the supported types.

Return type:

None

Examples

>>> light.set_phase_random()  # Default gaussian with π/2 std for all channels
>>> light.set_phase_random(std=np.pi/4)  # Reduced randomness
>>> light.set_phase_random(distribution='uniform')  # Uniform distribution
>>> light.set_phase_random(std=0.25, distribution='von_mises')  # von Mises with κ=4
>>> light.set_phase_random(c=0)  # Only modify first channel
save(fn)[source]

Save light field to file.

Parameters:

fn (str) – Filename (.pt, .pth, .npy or .mat)

Return type:

None

Examples

>>> light.save("field.pt")  # Save as PyTorch format
>>> light.save("field.npy")  # Save as NumPy format
>>> light.save("field.mat")  # Save as MATLAB format
adjust_amplitude_to_other_light(other_light)[source]

Scale amplitude to match average of another light field.

Parameters:

other_light (Light) – Reference light field

Return type:

None

Examples

>>> target = Light(dim=(1,1,1024,1024), pitch=6.4e-6, wvl=633e-9)
>>> light.adjust_amplitude_to_other_light(target)
load_image(image_path, random_phase=False, std=3.141592653589793, distribution='uniform', batch_idx=None)[source]

Load image as amplitude pattern with optional random phase.

Parameters:
  • image_path (str) – Path to image file.

  • random_phase (bool, optional) – Whether to apply random phase. Defaults to False.

  • std (float, optional) – Standard deviation for phase randomness. For gaussian: Standard deviation in radians For uniform: Half-width of uniform distribution in radians For von_mises: Inverse of concentration parameter (1/κ) Defaults to π.

  • distribution (str, optional) – Type of random distribution. Must be one of [‘gaussian’, ‘uniform’, ‘von_mises’]. Defaults to ‘uniform’.

  • batch_idx (int, optional) – Specific batch index to load the image into. If None, loads the image into all batches. Defaults to None.

Return type:

None

Examples

>>> light.load_image("target.png")  # No random phase, all batches
>>> light.load_image("target.png", random_phase=True)  # Default uniform, all batches
>>> light.load_image("target.png", random_phase=True, std=np.pi/4)
>>> light.load_image("target.png", random_phase=True, distribution='gaussian')
>>> light.load_image("target.png", batch_idx=0)  # Load only into first batch
visualize(b=0, c=None, uniform_scale=False, vmin=None, vmax=None, fix_noise=True, amp_threshold=1e-05)[source]

Visualize amplitude, phase, and intensity of light field with improved noise handling.

Parameters:
  • b (int) – Batch index

  • c (int, optional) – Channel index

  • uniform_scale (bool) – Use same scale for all channels

  • vmin (float, optional) – Intensity plot range

  • vmax (float, optional) – Intensity plot range

  • fix_noise (bool) – Whether to fix numerical noise in amplitude visualization

  • amp_threshold (float) – Threshold for detecting uniform amplitude with noise

Return type:

None

Examples

>>> light.visualize()  # Show all channels
>>> light.visualize(c=0)  # Show only first channel
>>> light.visualize(uniform_scale=True)  # Use uniform scaling
>>> light.visualize(fix_noise=False)  # Don't fix numerical noise
>>> light.visualize(b=1)  # Visualize the second batch
visualize_image(b=0)[source]

Visualize amplitude, phase, and intensity as RGB images.

Parameters:

b (int) – Batch index to visualize

Return type:

None

Examples

>>> light.visualize_image()
>>> light.visualize_image(b=1)  # Visualize the second batch
shape()[source]

Return shape of light wavefront.

Returns:

Shape of the field tensor

Return type:

tuple

Examples

>>> shape = light.shape()
load(fn)[source]

Load light field from file.

Parameters:

fn (str) – Filename (.pt, .pth, .npy or .mat)

Return type:

None

Examples

>>> light.load("field.pt")  # Load PyTorch format
>>> light.load("field.npy")  # Load NumPy format
>>> light.load("field.mat")  # Load MATLAB format