Array preview also works

This commit is contained in:
gac-x06da
2025-01-27 15:13:16 +01:00
parent 7ab682817f
commit 286c7a4bff
4 changed files with 90 additions and 3 deletions
@@ -430,7 +430,7 @@ samcam:
readoutPriority: monitored
readOnly: false
softwareTrigger: false
samimg:
samstream:
description: Sample camera ZMQ stream
deviceClass: pxiii_bec.devices.StdDaqPreviewDetector
deviceConfig:
@@ -441,6 +441,20 @@ samimg:
readoutPriority: async
readOnly: false
softwareTrigger: false
samimg:
description: Sample camera image from EPICS
deviceClass: pxiii_bec.devices.NDArrayPreview
deviceConfig:
prefix: 'X06DA-SAMCAM:image1:'
deviceTags:
- detector
enabled: true
readoutPriority: async
readOnly: false
softwareTrigger: false
bstop_pneum:
+69
View File
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
"""
Standard DAQ preview image stream module
Created on Thu Jun 27 17:28:43 2024
@author: mohacsi_i
"""
import numpy as np
from ophyd import Device, Component, EpicsSignal, Kind, Staged
from ophyd.areadetector.base import NDDerivedSignal
from bec_lib import bec_logger
logger = bec_logger.logger
class NDArrayPreview(Device):
"""Wrapper class around AreaDetector's NDStdArray plugins
This is a monolithic class to display images from AreaDetector's
ImagePlugin without the use of DynamicDeviceComponent or multiple
interitance (that doesn't work with BEC).
"""
# Subscriptions for plotting image
USER_ACCESS = ["image"]
SUB_MONITOR = "device_monitor_2d"
_default_sub = SUB_MONITOR
# Status attributes
array_size_x = Component(EpicsSignal, "ArraySize0_RBV", kind=Kind.config)
array_size_y = Component(EpicsSignal, "ArraySize1_RBV", kind=Kind.config)
array_size_z = Component(EpicsSignal, "ArraySize2_RBV", kind=Kind.config)
ndimensions = Component(EpicsSignal, "NDimensions_RBV", kind=Kind.config)
array_data = Component(EpicsSignal, "ArrayData", kind=Kind.omitted)
shaped_image = Component(
NDDerivedSignal,
derived_from="array_data",
shape=("array_size_z", "array_size_y", "array_size_x"),
num_dimensions="ndimensions",
kind=Kind.normal,
)
def read(self):
""" Stream out data on every read()"""
if self._staged==Staged.yes:
image = self.shaped_image.get()
self._run_subs(sub_type=self.SUB_MONITOR, value=image)
return super().read()
def image(self):
""" Fallback method in case image streaming fills up the BEC"""
array_size = (self.array_size_z.get(), self.array_size_y.get(), self.array_size_x.get())
if array_size == (0, 0, 0):
raise RuntimeError("Invalid image; ensure array_callbacks are on")
if array_size[-1] == 0:
array_size = array_size[:-1]
pixel_count = np.prod(array_size)
image = self.array_data.get()
if image.size == pixel_count:
return np.array(image).reshape(array_size)
# Automatically connect to SAMCAM at PXIII if directly invoked
if __name__ == "__main__":
img = NDArrayPreview("X06DA-SAMCAM:image1:", name="samimg")
img.wait_for_connection()
+4 -1
View File
@@ -43,6 +43,9 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
self.parent.unstage()
sleep(0.5)
logger.info(
f"[{self.parent.name}] Attaching monitor to {self.parent.url.get()}"
)
self.parent.connect()
self._stop_polling = False
self._mon = Thread(target=self.poll, daemon=True)
@@ -107,7 +110,7 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
self.parent._last_image = image
self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=image)
t_last = t_curr
logger.debug(
logger.info(
f"[{self.parent.name}] Updated frame {header['frame']}\t"
f"Shape: {header['shape']}\tMean: {np.mean(image):.3f}"
)
+2 -1
View File
@@ -7,4 +7,5 @@ Ophyd devices for the PX III beamline, including the MX specific Aerotech A3200
from .A3200 import AerotechAbrStage
from .A3200utils import A3200Axis
from .SmarGon import SmarGonAxis
from .StdDaqPreview import StdDaqPreviewDetector
from .StdDaqPreview import StdDaqPreviewDetector
from .NDArrayPreview import NDArrayPreview