Source code for herosdevices.hardware.dummy.displays
"""Dummy SLM for testing purposes."""
import time
import numpy as np
import numpy.typing as npt
from heros import event
from herosdevices.core.templates import DisplayDeviceTemplate
[docs]
def compute_intensity_in_focal_plane(phase_pattern: np.array, value_2_pi: float = 1024) -> np.array:
"""Compute intensity in the focal plane of a lens after imprinting the given phase pattern."""
# Assume uniform amplitude
phase_radians = (phase_pattern / value_2_pi) * 2 * np.pi
field = np.exp(1j * phase_radians)
# Compute Fourier transform (shifted so center is in the middle)
ft = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(field)))
# Compute intensity (square of absolute value)
intensity = np.abs(ft) ** 2
# Normalize
intensity /= np.max(intensity)
return intensity
[docs]
class SlmDummy(DisplayDeviceTemplate):
"""Dummy SLM for testing purposes."""
default_config_dict: dict = {
"slots": 32,
"image_size": (1200, 1920),
"value_2_pi": 1024,
}
image_size: tuple | list
value_2_pi: float
simulate: bool
def __init__(
self,
config_dict: dict,
default_config: str | None = None,
keep_device_open: bool = True,
simulate: bool = True,
) -> None:
self.simulate = simulate
DisplayDeviceTemplate.__init__(self, config_dict, default_config, keep_device_open)
def _open(self) -> None:
return None
def _teardown(self) -> None:
return None
def _get_status(self) -> dict:
"""Return the current device status as dict."""
return {
"firmware_serialnumber": self.firmware_serialnumber(),
}
def _set_config(self, config: dict) -> bool:
"""Set the configuration from a dict."""
self.slots = config["slots"]
self.image_size = config["image_size"]
self.value_2_pi = config["value_2_pi"]
self.images = [None] * self.slots
return True
def _push_image(self, slot: int, image: npt.NDArray[np.uint16]) -> bool:
"""
Load a phase pattern to a slot of the device.
Args:
slot: The slot to use.
image: The phase pattern.
"""
assert slot < len(self.images), f"Slot {slot} is out of range!"
assert image.shape == tuple(self.image_size), (
f"Phase pattern size {image.shape} does not match SLM size {self.image_size}"
)
self.images[slot] = image
return True
def _display_slot(self, slot: int = 1) -> bool:
"""Display a certain slot."""
assert slot < len(self.images), f"Slot {slot} is out of range!"
self.phase_data(self.images[slot], {"type": "phase", "slot": slot})
if self.simulate:
t0 = time.time()
image = compute_intensity_in_focal_plane(self.images[slot], self.value_2_pi)
dt = time.time() - t0
self.simulation_data(image, {"type": "image", "slot": slot, "calculation_time": dt})
return True
[docs]
def firmware_serialnumber(self) -> str:
"""Return a dummy firmware serial number."""
return "20090123_142415"
@event
def simulation_data(self, image: np.ndarray, metadata: dict = {}) -> tuple: # noqa: B006
"""Publish simulation results."""
return image, metadata
@event
def phase_data(self, phase: np.ndarray, metadata: dict = {}) -> tuple: # noqa: B006
"""Publish phase pattern."""
return phase, metadata