plesty.pow_pl.rig
Instrument composite (rig) for the power-dependent PL experiment.
Wires the three remote device servers of the power-dependent measurement into
one CompositeDevice:
hwp— Thorlabs K10CR1 rotation stage carrying the half-wave plate that sets the excitation power (plesty-k10cr1),spec— Princeton Instruments LightField spectrometer (plesty-lightfield-spectrometer),pm— Thorlabs powermeter (plesty-thorlabs-powermeter), optional: a rig built withwith_powermeter=Falseconnects only the stage and the spectrometer, andacquire_rowreturns spectra without a power reading.
Everything the composite already does is used rather than repeated: the
resilient call (timeout → reconnect → retry), one thread per sub-device
so no ZMQ socket is touched from a foreign thread, and submit for the
simultaneity PowPlRig.acquire_row() needs — the exposure and the power
reading cover the same time window. What is left here is this rig’s own
vocabulary: home the plate, move it, acquire a row.
The instruments and their operation budgets are declared in the packaged
config.yaml; the server addresses come from the environment. Neither is
written in this file.
Frame data never crosses the TCP transport: the spectrometer writes each frame to the data path the run routed it to, and reports only the file path.
Attributes
Classes
HWP rotation stage + spectrometer + powermeter as one instrument. |
Functions
|
Return the signed shortest angular distance from target to reported. |
Module Contents
- plesty.pow_pl.rig._logger
- plesty.pow_pl.rig.DEVICES: dict[str, Any]
- plesty.pow_pl.rig._HWP
- plesty.pow_pl.rig._SPEC
- plesty.pow_pl.rig._PM
- plesty.pow_pl.rig._angular_error_deg(reported_deg: float, target_deg: float) float
Return the signed shortest angular distance from target to reported.
- Parameters:
reported_deg (float)
target_deg (float)
- Return type:
float
- class plesty.pow_pl.rig.PowPlRig(devices: collections.abc.Mapping[str, Any] | None = None, env: plesty.lib.utils.settings.EnvSettings | None = None, env_prefix: str | None = None, with_powermeter: bool = True)
Bases:
plesty.lib.device.composite_device.CompositeDeviceHWP rotation stage + spectrometer + powermeter as one instrument.
The rig owns the whole device vocabulary of the experiment; the experiment layer never issues raw device commands.
Connect the rig’s instruments, each on its own thread.
Addresses are not arguments: each is read from
<NAME>_ADDRESSin the environment (HWP_ADDRESS,SPEC_ADDRESS,PM_ADDRESS), so a deployment is configured by its.env. Thread affinity is not optional here — this rig drives its instruments concurrently, and ZMQ sockets belong to the thread that opened them.- Parameters:
devices (Optional[collections.abc.Mapping[str, Any]]) – Sub-device overrides in the form
CompositeDeviceaccepts; defaults to thedevicesblock of the packagedconfig.yaml.env (Optional[plesty.lib.utils.settings.EnvSettings]) – Environment source for the address lookups.
env_prefix (Optional[str]) – Deployment prefix for the derived variable names.
with_powermeter (bool) –
Falsebuilds the rig without thepmsub-device — noPM_ADDRESSneeded, and rows carry spectra only.
- Raises:
RuntimeError – If a device server cannot be reached.
ValueError – If a sub-device’s address is neither configured nor present in the environment.
- has_powermeter
- _last_hwp_deg: float | None = None
- _pm_averaging
- _pm_delay_s
- home_hwp() bool
Home the rotation stage and return its homed status.
- Return type:
bool
- set_hwp(angle_deg: float) float
Move the HWP to an absolute angle and return the settled position.
- Parameters:
angle_deg (float) – Target angle in degrees (user frame, applied mod 360).
- Return type:
float
Small steps from a known position (the 2 deg sweep moves) run under a fast 5 s window; larger or first moves keep the full mechanical budget — a park from 360 deg is a ~70 s physical rotation.
The stage answers only once it has physically stopped (plesty-k10cr1#2), so the reported angle is the angle the row is measured at. It is checked against the target: on a mismatch beyond
position_tolerance_degthe move is issued once more, and a second mismatch raises so the step is retried instead of recording a row at the wrong angle.- Returns:
The stage-reported position in degrees after the move.
- Raises:
RuntimeError – If the stage settles away from the target twice.
- Parameters:
angle_deg (float)
- Return type:
float
- configure(exposure_s: float, frames: int, pm_wavelength_nm: float | None = None, pm_averaging: int = int(_PM['averaging']), pm_delay_s: float = float(_PM['delay_s'])) None
Push the acquisition settings to the spectrometer and powermeter.
The powermeter wavelength is written once here; the averaging count is applied per reading via
measure_power(averaging=...). On a rig without a powermeter (or with no wavelength given), only the spectrometer is configured.- Parameters:
exposure_s (float) – Spectrometer exposure time in seconds.
frames (int) – Frames stored per acquisition.
pm_wavelength_nm (Optional[float]) – Powermeter correction wavelength in nanometres;
Noneskips the powermeter configuration.pm_averaging (int) – Powermeter samples per reading (~3 ms each).
pm_delay_s (float) – Delay before the power sample so it lands inside the exposure (LightField opens the shutter only after ~0.3-0.5 s of setup).
- Return type:
None
- set_exposure(exposure_s: float) None
Change only the spectrometer exposure, leaving every other setting.
LightField takes the exposure in whole milliseconds and rejects a fraction, so the value is rounded.
- Parameters:
exposure_s (float) – Exposure time in seconds.
- Return type:
None
- center_wavelength_nm() float
Return the grating center wavelength (nm) currently set on the spectrometer.
- Return type:
float
- acquire_row(exposure_s: float, frames: int, file_stem: str | None = None) dict[str, Any]
Expose the spectrometer and read the optical power simultaneously.
The exposure and the power reading are launched together on two worker threads so the powermeter samples during the exposure window. On a rig without a powermeter only the exposure runs, and the row carries no power keys. The frame stays on the spectrometer host’s (shared) data disk; only its path is fetched afterwards.
- Parameters:
exposure_s (float) – Exposure time in seconds (used to size the timeout).
frames (int) – Frames stored by the acquisition.
file_stem (Optional[str]) – Name the frame is saved under, unique per acquisition;
Nonekeeps whatever is set.
- Returns:
{"data_file": str, "power_w": float, "pm_averaging": int}— the saved frame’s path on the shared disk, the optical power in watts, and the averaging count applied to that reading. Without a powermeter,{"data_file": str}only.- Raises:
RuntimeError – If the spectrometer reports no saved frame.
- Return type:
dict[str, Any]