feat(csaxs): invert option for BPM and SignalForwarder, enabled for BPM XBox2
CI for csaxs_bec / test (push) Successful in 4m17s

The XBox2 BPM amplifier outputs a negative current, so more beam showed as
more negative blade values. invert: true in the device config negates the
input signals; the BPM position/diagonal ratios are unchanged and the
intensity becomes positive. Enabled for bpm_xbox2_slowrb.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017NrH3poJsYBCTVq2Y9fuHZ
This commit is contained in:
x12saandClaude Opus 5.5 committed 2026-10-28 10:40:19 +01:00
1 parent c4a23cc5b6
commit e9a1b83bc6
4 files changed
+45 -7

No files matched your search

@@ -1163,6 +1163,7 @@ bpm_xbox2_slowrb:
right_top_ref: galilrioesxbox.analog_in.ch1
right_bot_ref: galilrioesxbox.analog_in.ch2
left_bot_ref: galilrioesxbox.analog_in.ch3
invert: true # amplifier output is negative; positive values = more beam
enabled: true
readoutPriority: monitored
onFailure: retry
+9 -2
View File
@@ -7,7 +7,12 @@ from ophyd_devices.utils.bec_processed_signal import BECProcessedSignal
class BPM(PSIPseudoDeviceBase):
"""BPM positioner pseudo device."""
"""BPM positioner pseudo device.
invert=True negates the four blade signals, e.g. for an amplifier whose
output current is negative. pos_x, pos_y and diagonal are ratios and do
not change; intensity changes sign.
"""
# Blade signals, a,b,c,d
left_top = Cpt(
@@ -76,11 +81,13 @@ class BPM(PSIPseudoDeviceBase):
right_top_ref: str,
right_bot_ref: str,
left_bot_ref: str,
invert: bool = False,
device_manager=None,
scan_info=None,
**kwargs,
):
super().__init__(name=name, device_manager=device_manager, scan_info=scan_info, **kwargs)
self._sign = -1 if invert else 1
# Get all blade signal objects from utility method
signal_t = self.left_top.get_device_object_from_bec(
object_name=left_top_ref, signal_name=self.name, device_manager=device_manager
@@ -131,7 +138,7 @@ class BPM(PSIPseudoDeviceBase):
)
def _compute_blade_signal(self, signal: Signal) -> float:
return signal.get()
return self._sign * signal.get()
def _compute_intensity(
self, left_top: Signal, right_top: Signal, right_bot: Signal, left_bot: Signal
@@ -9,7 +9,7 @@ from ophyd_devices.utils.bec_processed_signal import BECProcessedSignal
class SignalForwarder(PSIPseudoDeviceBase):
"""Forward one signal unchanged."""
"""Forward one signal unchanged, or negated with invert=True."""
signal = Cpt(
BECProcessedSignal,
@@ -20,8 +20,17 @@ class SignalForwarder(PSIPseudoDeviceBase):
doc="Forwarded signal",
)
def __init__(self, name, signal_ref: str, device_manager=None, scan_info=None, **kwargs):
def __init__(
self,
name,
signal_ref: str,
invert: bool = False,
device_manager=None,
scan_info=None,
**kwargs,
):
super().__init__(name=name, device_manager=device_manager, scan_info=scan_info, **kwargs)
self._sign = -1 if invert else 1
src = self.signal.get_device_object_from_bec(
object_name=signal_ref, signal_name=self.name, device_manager=device_manager
@@ -30,4 +39,4 @@ class SignalForwarder(PSIPseudoDeviceBase):
self.signal.set_compute_method(self._compute_signal, signal=src)
def _compute_signal(self, signal: Signal) -> float:
return signal.get()
return self._sign * signal.get()
+23 -2
View File
@@ -141,8 +141,9 @@ def patched_dm_bpm(dm_with_devices):
return dm
@pytest.fixture
def bpm(patched_dm_bpm):
@pytest.fixture(params=[False])
def bpm(request, patched_dm_bpm):
invert = request.param
name = "bpm"
bpm_config = Device(
name=name,
@@ -165,6 +166,7 @@ def bpm(patched_dm_bpm):
right_top_ref="right_top",
right_bot_ref="right_bot",
left_bot_ref="left_bot",
invert=invert,
device_manager=patched_dm_bpm,
)
patched_dm_bpm.devices._add_device(bpm.name, bpm)
@@ -239,3 +241,22 @@ def test_bpm_positions(bpm):
assert bpm.pos_x.get() == 0
assert bpm.pos_y.get() == 0
assert bpm.diagonal.get() == 1
@pytest.mark.parametrize("bpm", [True], indirect=True)
def test_bpm_invert_negates_blades_keeps_positions(bpm):
"""invert=True: negative amplifier currents read as positive blade
signals and intensity; the ratio-based positions are unchanged."""
devices = bpm.device_manager.devices
devices["left_top"].put(-1)
devices["right_top"].put(-3)
devices["right_bot"].put(-2)
devices["left_bot"].put(-2)
assert bpm.left_top.get() == 1
assert bpm.right_top.get() == 3
assert bpm.intensity.get() == 8
# same ratios as the non-inverted signals would give
assert bpm.pos_x.get() == 0.25
assert bpm.pos_y.get() == 0
assert bpm.diagonal.get() == 0.25