From 54c13e3cbc9447150dcffbdec533faa481b46e6a Mon Sep 17 00:00:00 2001 From: x10sa Date: Wed, 2 Sep 2026 11:10:12 +0200 Subject: [PATCH] WIP samcam device --- mx_bec/devices/samcam.py | 72 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 mx_bec/devices/samcam.py diff --git a/mx_bec/devices/samcam.py b/mx_bec/devices/samcam.py new file mode 100644 index 0000000..99acfd5 --- /dev/null +++ b/mx_bec/devices/samcam.py @@ -0,0 +1,72 @@ +from ophyd_devices import PSIDeviceBase +from ophyd import Component as Cpt, EpicsSignal, EpicsSignalRO + +import math +import time + +from ophyd import Component as Cpt +from ophyd import Device +from ophyd import EpicsSignalRO, Kind, SignalRO +from ophyd_devices.devices.psi_motor import EpicsMotor +from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase + + +class ContrastSignal(SignalRO): + """Read-only signal calculated as sigma / mean.""" + + def __init__(self, *args, minimum_mean: float = 1e-12, **kwargs): + super().__init__(*args, **kwargs) + self.minimum_mean = minimum_mean + + def get(self, **kwargs) -> float: + mean = float(self.parent.mean.get()) + sigma = float(self.parent.sigma.get()) + + if not math.isfinite(mean) or not math.isfinite(sigma) or abs(mean) <= self.minimum_mean: + return math.nan + + return sigma / mean + + def read(self): + return {self.name: {"value": self.get(), "timestamp": time.time()}} + + def describe(self): + return { + self.name: { + "source": (f"calculated:{self.parent.sigma.pvname}/{self.parent.mean.pvname}"), + "dtype": "number", + "shape": [], + "units": "", + } + } + + +class CameraContrast(PSIDeviceBase): + """Camera statistics and calculated contrast.""" + + mean = Cpt(EpicsSignalRO, suffix="MeanValue_RBV", kind=Kind.normal) + sigma = Cpt(EpicsSignalRO, suffix="Sigma_RBV", kind=Kind.normal) + contrast = Cpt(ContrastSignal, kind=Kind.hinted) + + +class SamCamStats(PSIDeviceBase): + max = Cpt(EpicsSignalRO, suffix="MaxValue_RBV") + mean = Cpt(EpicsSignalRO, suffix="MeanValue_RBV") + sigma = Cpt(EpicsSignalRO, suffix="Sigma_RBV") + eccentricity = Cpt(EpicsSignalRO, suffix="Eccentricity_RBV") + + +class SamCamCentroid(PSIDeviceBase): + x = Cpt(EpicsSignalRO, suffix="CentroidX_RBV") + x_sig = Cpt(EpicsSignalRO, suffix="SigmaX_RBV") + y = Cpt(EpicsSignalRO, suffix="CentroidY_RBV") + y_sig = Cpt(EpicsSignalRO, suffix="SigmaY_RBV") + + +class SamCam(PSIDeviceBase): + stats = Cpt(SamCamStats, suffix="Stats5:") + centroid = Cpt(SamCamCentroid, suffix="Stats5:") + exposure_time = Cpt(EpicsSignal, suffix="cam1:AcquireTime") + gain = Cpt(EpicsSignal, suffix="cam1:Gain") + contrast = Cpt(CameraContrast, suffix="Stats1:") + zoom = Cpt(EpicsMotor, suffix="ZOOM")