13.1. openwfs
- class Actuator(*, duration, latency)[source]
Bases:
Device,ABCBase class for all actuators.
Actuators are devices that can modify the state of the system, such as spatial light modulators, stages, or other control devices. This class extends the Device base class and sets the _is_actuator property to True.
- class Detector(*, data_shape, pixel_size, duration, latency, multi_threaded=True)[source]
Bases:
Device,ABCBase class for all detectors, cameras and other data sources with possible dynamic behavior.
Detectors are devices that can measure or acquire data from the system, such as cameras, sensors, or other measurement devices. This class extends the Device base class and sets the _is_actuator property to False.
See Detectors in the documentation for more information.
- final coordinates(dimension)[source]
Returns an array with the coordinate values along the d-th axis.
The coordinates represent the _centers_ of the grid points. For example, for an array of shape
(2,)the coordinates are [0.5, 1.5] * pixel_size and not [0, 1] * pixel_size. If self.pixel_size is None, a pixel size of 1.0 is used.The coordinates are returned as an array with the same number of dimensions as data_shape, with the d-th dimension holding the coordinates. This facilitates meshgrid-like computations, e.g. cam.coordinates(0) + cam.coordinates(1) gives a 2-dimensional array of coordinates.
- Parameters:
dimension (
int) – Dimension for which to return the coordinates.
- property data_shape: Tuple[int, ...]
The shape of the data array that read() will return.
For some detectors this property may be mutable, for example, for a camera it represents the height and width of the ROI, which can be changed.
- property extent: Quantity
Physical size of the data array
If a pixel_size is set, this function returns data_shape * pixel_size as an astropy.units.Quantity. If no pixel_size is set, this function uses the dimensionless_unscaled unit.
- property pixel_size: Quantity | None
Physical dimension of one element in the returned data array.
For cameras, this is the pixel size (in astropy length units). For detectors returning a time trace, this value is specified in astropy time units. The pixel_size is a 1-D array with an element for each dimension of the returned data.
By default, the pixel size cannot be set. However, in some cases (such as when the pixel_size is actually a sampling interval), it makes sense for the child class to implement a setter.
- final read(*args, immediate=True, **kwargs)[source]
Triggers the detector and waits for the data to arrive.
Shortcut for trigger().result().
- trigger(*args, out=None, immediate=False, **kwargs)[source]
Triggers the detector to start acquisition of the data.
This function does not wait for the measurement to complete. Instead, it returns a
concurrent.futures.Future. Call.result()on the returned object to wait for the data. Here is a typical usage pattern:# Trigger the detector, which starts the data capture process future = detector.trigger() # Do some other work, perhaps trigger other detectors to capture # data simultaneously... # Now read the data from the detector. If the data is not ready yet, # this will block until it is. data = future.result()
An alternative method for asynchronous data capture is to use the out parameter to specify a location where to store the data:
out = np.zeros((2,), dtype='float32') detector.trigger(out=out[0]) # start the first measurement detector.trigger(out=out[1]) # queue the second measurement detector.wait() # wait for both measurements to complete # Now the data is stored in the `out` array.
All input parameters are passed to the _fetch function of the detector. Child classes may override trigger() to call super().trigger() with additional parameters. If any of these parameters is a Future, it is awaited before calling _fetch. This way, data from multiple sources can be combined (see Processor).
Note
To implement hardware triggering, do not override this function. Instead, override _do_trigger() to ensure proper synchronization and locking.
- Parameters:
out – If specified, the data is stored in this array once it is available.
immediate – If True, the data is fetched in the current thread. This is useful for debugging, and for cases where the data is needed immediately. It avoids the overhead (and debugging complications) of dispatching the call to _fetch to a worker thread.
*args – Additional arguments passed to the _fetch function. If any of these arguments is a concurrent.futures.Future, the data is awaited before calling _fetch, and the data is passed instead of the Future. This is useful for combining data from multiple sources (see Processor).
**kwargs – Additional keyword arguments passed to the _fetch function. Any concurrent.futures.Future in the keyword arguments is awaited before calling _fetch, and the data is passed instead of the Future.
- wait(up_to=None)[source]
Waits until the hardware has (almost) finished measuring
Due to the automatic synchronization between detectors and actuators, this function only needs to be called explicitly when waiting for data to be stored in the out argument of
trigger().- Parameters:
up_to (
Annotated[Quantity]) – if specified, this function may return up_to milliseconds before the hardware has finished measurements. If None, this function waits until the hardware has finished all measurements and all data is fetched, and stored in the out array if that was passed to trigger().
- class Device(*, duration, latency)[source]
Bases:
ABCBase class for detectors and actuators.
This is the abstract base class for all devices in the openwfs framework, including both detectors and actuators.
See key_concepts for more information.
- busy()[source]
Returns true if the device is measuring or moving (see wait()).
Note: if a device does not define a finite duration, it must override this function to poll for finalization.
- property duration: Annotated[Quantity, Unit('ms')]
Maximum amount of time it takes to perform the measurement or for the actuator to stabilize.
This value does not include the latency.
For a detector, this is the maximum amount of time that elapses between returning from trigger() and the end of the measurement. For an actuator, this is the maximum amount of time that elapses from returning from a command like update() and the stabilization of the device.
If the duration of an operation is not known in advance, (e.g., when waiting for a hardware trigger), this function should return np.inf * u.ms.
Note
A device may update the duration dynamically. For example, a stage may compute the required time to move to the target position and update the duration accordingly.
Note
If latency is a (lower) estimate, the duration should be high enough to guarantee that latency + duration is at least as large as the time between starting the operation and finishing it.
- property latency: Annotated[Quantity, Unit('ms')]
Minimum amount of time between sending a command or trigger to the device and the moment the device starts responding.
The default value is 0.0 ms.
Note
The latency is used to compute when it is safe to switch the global state from ‘moving’ to ‘measuring’ or vice versa. Devices that report a non-zero latency promise not to do anything before the latency has passed. This allows making the state switch even before the devices of the other type have all finished.
This construct is used for spatial light modulators, which typically have a long latency (1-2 frames). Due to this latency, we may send an update command to the SLM even before the camera has finished reading the previous frame.
Note
A device is allowed to report a different latency every time latency is called. For example, for a spatial light modulator that only refreshes at a fixed rate, we can add the remaining time until the next refresh to the latency.
- property timeout: Annotated[Quantity, Unit('ms')]
Time after which a timeout error is raised when waiting for the device.
The timeout is automatically adjusted if the duration changes. The default value is duration + 5 s.
- wait(up_to=None)[source]
Waits until the device is (almost) in the ready state, i.e., has finished measuring or moving.
This function is called by _start automatically to ensure proper synchronization between detectors and actuators, and it is called by __del__ to ensure the device is not active when it is destroyed. The only time to call wait explicitly is when using pipelined measurements, see Detector.trigger().
For devices that report a duration (duration ≠ ∞), this function waits until current_time - up_to >= self._end_time_ns, where _end_time_ns was set by the last call to _start.
For devices that report no duration duration = ∞, this function repeatedly calls busy until busy returns False. In this case, up_to is ignored.
- Parameters:
up_to (Quantity[u.ms]) – when specified, specifies that this function may return ‘up_to’ milliseconds before the device is finished.
- Raises:
Any other exception raised by the device in another thread (e.g., during _fetch). –
TimeoutError – if the device has duration = ∞, and busy does not return True within self.timeout
RuntimeError – if wait is called from inside a setter or from inside _fetch. This would cause a deadlock.
- class PhaseSLM[source]
Bases:
ABCBase class for phase-only Spatial Light Modulators (SLMs).
This abstract base class defines the interface for phase-only spatial light modulators, which are devices that can modulate the phase of light. Implementations of this class should provide methods to set phase patterns and update the display.
- abstractmethod set_phases(values, update=True)[source]
Sets the phase pattern on the SLM.
- Parameters:
values (ArrayLike) – phase pattern, in radians. The pattern is automatically stretched to fill the full SLM.
update (
bool) – when True, calls update after setting the phase pattern. Set to False to suppress the call to update. This is useful in advanced scenarios where multiple parameters of the SLM need to be changed before updating the displayed image.
- abstractmethod update()[source]
Sends the new phase pattern to be displayed on the SLM.
Implementations should call _start() before triggering the SLM.
Note
This function does not wait for the image to appear on the SLM. To wait for the image stabilization explicitly, use ‘wait()’. However, this should rarely be needed since all Detectors already wait for the image to stabilize before starting a measurement.
- class Processor(*args, data_shape=Ellipsis, pixel_size=Ellipsis, multi_threaded=True)[source]
Bases:
Detector,ABCBase class for all Processors.
Processors can be used to build data processing graphs, where each Processor takes input from one or more input Detectors and processes that data (e.g., cropping an image, averaging over an ROI, etc.). A processor, itself, is a Detector to allow chaining multiple processors together to combine functionality.
To implement a processor, implement _fetch, and optionally override data_shape, pixel_size, and __init__. The latency and duration properties are computed from the latency and duration of the inputs and cannot be set. By default, the pixel_size and data_shape are the same as the pixel_size and data_shape of the first input. To override this behavior, override the pixel_size and data_shape properties.
- busy()[source]
Returns true if the device is measuring or moving (see wait()).
Note: if a device does not define a finite duration, it must override this function to poll for finalization.
- property data_shape
This default implementation returns the data shape of the first source.
- property duration: Annotated[Quantity, Unit('ms')]
Returns the last end time minus the first start time for all detectors i.e., max (duration + latency) - min(latency).
Note that latency is allowed to vary over time for devices that can only be triggered periodically, so this duration may also vary over time.
- property latency: Annotated[Quantity, Unit('ms')]
Returns the shortest latency for all detectors.
- property pixel_size: Quantity | None
This default implementation returns the pixel size of the first source.
- trigger(*args, immediate=False, **kwargs)[source]
Triggers all sources at the same time (regardless of latency), and schedules a call to _fetch()
- version()[source]
Return the version information of the installed OpenWFS package.
- version is the version of the package during build. For development releases it will include the
git hash and date of the commit. Note that the version is only updated during build (uv build), so it may be outdated if you are developing OpenWFS.
- commit_id is the git hash of the code that is currently used. If you have local commits but did not build the package yet,
this value will differ from the tag in version.