refactor(csaxsdlpca200): cleanup docs
CI for csaxs_bec / test (push) Waiting to run
CI for csaxs_bec / test (pull_request) Failing after 13m34s

This commit is contained in:
2026-03-02 08:13:56 +01:00
parent ab669459a5
commit d10431f7cd
@@ -6,28 +6,28 @@ connected to Galil RIO digital outputs.
DLPCA-200 Remote Control (datasheet page 4)
-------------------------------------------
Sub-D pin function:
Pin 10 gain LSB (digital out channel, index 0 in bit-tuple)
Pin 11 gain MID (digital out channel, index 1 in bit-tuple)
Pin 12 gain MSB (digital out channel, index 2 in bit-tuple)
Pin 13 coupling LOW = AC, HIGH = DC
Pin 14 speed mode HIGH = low noise (Pin14=1), LOW = high speed (Pin14=0)
Sub-D pin -> function:
Pin 10 -> gain LSB (digital out channel, index 0 in bit-tuple)
Pin 11 -> gain MID (digital out channel, index 1 in bit-tuple)
Pin 12 -> gain MSB (digital out channel, index 2 in bit-tuple)
Pin 13 -> coupling LOW = AC, HIGH = DC
Pin 14 -> speed mode HIGH = low noise (Pin14=1), LOW = high speed (Pin14=0)
Gain truth table (MSB, MID, LSB):
0,0,0 low-noise: 1e3 high-speed: 1e5
0,0,1 low-noise: 1e4 high-speed: 1e6
0,1,0 low-noise: 1e5 high-speed: 1e7
0,1,1 low-noise: 1e6 high-speed: 1e8
1,0,0 low-noise: 1e7 high-speed: 1e9
1,0,1 low-noise: 1e8 high-speed: 1e10
1,1,0 low-noise: 1e9 high-speed: 1e11
0,0,0 -> low-noise: 1e3 high-speed: 1e5
0,0,1 -> low-noise: 1e4 high-speed: 1e6
0,1,0 -> low-noise: 1e5 high-speed: 1e7
0,1,1 -> low-noise: 1e6 high-speed: 1e8
1,0,0 -> low-noise: 1e7 high-speed: 1e9
1,0,1 -> low-noise: 1e8 high-speed: 1e10
1,1,0 -> low-noise: 1e9 high-speed: 1e11
Strategy: prefer low-noise mode (1e31e9). For 1e10 and 1e11,
Strategy: prefer low-noise mode (1e3-1e9). For 1e10 and 1e11,
automatically fall back to high-speed mode.
Device wiring example (galilrioesxbox):
bpm4: Pin10ch0, Pin11ch1, Pin12ch2, Pin13ch3, Pin14ch4
bim: Pin10ch6, Pin11ch7, Pin12ch8, Pin13ch9, Pin14ch10
bpm4: Pin10->ch0, Pin11->ch1, Pin12->ch2, Pin13->ch3, Pin14->ch4
bim: Pin10->ch6, Pin11->ch7, Pin12->ch8, Pin13->ch9, Pin14->ch10
Usage examples
--------------
@@ -57,11 +57,11 @@ dev = builtins.__dict__.get("dev")
# Each entry describes one DLPCA-200 amplifier connected to a Galil RIO.
#
# Keys inside "channels":
# gain_lsb digital output channel number wired to DLPCA-200 Pin 10
# gain_mid digital output channel number wired to DLPCA-200 Pin 11
# gain_msb digital output channel number wired to DLPCA-200 Pin 12
# coupling digital output channel number wired to DLPCA-200 Pin 13
# speed_mode digital output channel number wired to DLPCA-200 Pin 14
# gain_lsb -> digital output channel number wired to DLPCA-200 Pin 10
# gain_mid -> digital output channel number wired to DLPCA-200 Pin 11
# gain_msb -> digital output channel number wired to DLPCA-200 Pin 12
# coupling -> digital output channel number wired to DLPCA-200 Pin 13
# speed_mode -> digital output channel number wired to DLPCA-200 Pin 14
#
# To add a new amplifier, simply extend this dict.
# ---------------------------------------------------------------------------
@@ -70,22 +70,22 @@ DLPCA200_AMPLIFIER_CONFIG: dict[str, dict] = {
"rio_device": "galilrioesxbox",
"description": "Beam Position Monitor 4 current amplifier",
"channels": {
"gain_lsb": 0, # Pin 10 Galil ch0
"gain_mid": 1, # Pin 11 Galil ch1
"gain_msb": 2, # Pin 12 Galil ch2
"coupling": 3, # Pin 13 Galil ch3
"speed_mode": 4, # Pin 14 Galil ch4
"gain_lsb": 0, # Pin 10 -> Galil ch0
"gain_mid": 1, # Pin 11 -> Galil ch1
"gain_msb": 2, # Pin 12 -> Galil ch2
"coupling": 3, # Pin 13 -> Galil ch3
"speed_mode": 4, # Pin 14 -> Galil ch4
},
},
"bim": {
"rio_device": "galilrioesxbox",
"description": "Beam Intensity Monitor current amplifier",
"channels": {
"gain_lsb": 6, # Pin 10 Galil ch6
"gain_mid": 7, # Pin 11 Galil ch7
"gain_msb": 8, # Pin 12 Galil ch8
"coupling": 9, # Pin 13 Galil ch9
"speed_mode": 10, # Pin 14 Galil ch10
"gain_lsb": 6, # Pin 10 -> Galil ch6
"gain_mid": 7, # Pin 11 -> Galil ch7
"gain_msb": 8, # Pin 12 -> Galil ch8
"coupling": 9, # Pin 13 -> Galil ch9
"speed_mode": 10, # Pin 14 -> Galil ch10
},
},
}
@@ -93,7 +93,7 @@ DLPCA200_AMPLIFIER_CONFIG: dict[str, dict] = {
# ---------------------------------------------------------------------------
# DLPCA-200 gain encoding tables
# ---------------------------------------------------------------------------
# (msb, mid, lsb) gain in V/A
# (msb, mid, lsb) -> gain in V/A
_GAIN_BITS_LOW_NOISE: dict[tuple, int] = {
(0, 0, 0): int(1e3),
(0, 0, 1): int(1e4),
@@ -114,13 +114,13 @@ _GAIN_BITS_HIGH_SPEED: dict[tuple, int] = {
(1, 1, 0): int(1e11),
}
# Inverse maps: gain (msb, mid, lsb, low_noise_flag)
# Inverse maps: gain -> (msb, mid, lsb, low_noise_flag)
# low_noise_flag: True = Pin14 HIGH, False = Pin14 LOW
_GAIN_TO_BITS: dict[int, tuple] = {}
for _bits, _gain in _GAIN_BITS_LOW_NOISE.items():
_GAIN_TO_BITS[_gain] = (*_bits, True)
for _bits, _gain in _GAIN_BITS_HIGH_SPEED.items():
if _gain not in _GAIN_TO_BITS: # low-noise takes priority
if _gain not in _GAIN_TO_BITS: # low-noise takes priority
_GAIN_TO_BITS[_gain] = (*_bits, False)
VALID_GAINS = sorted(_GAIN_TO_BITS.keys())
@@ -168,9 +168,7 @@ class cSAXSDLPCA200:
"""Return config dict for a named amplifier, raising on unknown names."""
if amp_name not in self._config:
known = ", ".join(sorted(self._config.keys()))
raise cSAXSDLPCA200Error(
f"{self.TAG} Unknown amplifier '{amp_name}'. Known: [{known}]"
)
raise cSAXSDLPCA200Error(f"{self.TAG} Unknown amplifier '{amp_name}'. Known: [{known}]")
return self._config[amp_name]
def _get_rio(self, amp_name: str):
@@ -181,9 +179,7 @@ class cSAXSDLPCA200:
try:
rio = getattr(dev, rio_name)
except AttributeError:
raise cSAXSDLPCA200Error(
f"{self.TAG} RIO device '{rio_name}' not found in BEC 'dev'."
)
raise cSAXSDLPCA200Error(f"{self.TAG} RIO device '{rio_name}' not found in BEC 'dev'.")
return rio
def _dout_get(self, rio, ch: int) -> int:
@@ -208,9 +204,9 @@ class cSAXSDLPCA200:
"""
rio = self._get_rio(amp_name)
ch = self._get_cfg(amp_name)["channels"]
msb = self._dout_get(rio, ch["gain_msb"])
mid = self._dout_get(rio, ch["gain_mid"])
lsb = self._dout_get(rio, ch["gain_lsb"])
msb = self._dout_get(rio, ch["gain_msb"])
mid = self._dout_get(rio, ch["gain_mid"])
lsb = self._dout_get(rio, ch["gain_lsb"])
speed_mode = self._dout_get(rio, ch["speed_mode"])
return msb, mid, lsb, speed_mode
@@ -218,7 +214,7 @@ class cSAXSDLPCA200:
"""
Decode hardware bit-state into gain value (V/A).
speed_mode=1 low-noise table, speed_mode=0 high-speed table.
speed_mode=1 -> low-noise table, speed_mode=0 -> high-speed table.
Returns None if the bit combination is not in the table.
"""
bits = (msb, mid, lsb)
@@ -228,7 +224,7 @@ class cSAXSDLPCA200:
return _GAIN_BITS_HIGH_SPEED.get(bits)
# ------------------------------------------------------------------
# Public API control
# Public API - control
# ------------------------------------------------------------------
def set_gain(self, amp_name: str, gain: float, force_high_speed: bool = False) -> None:
@@ -236,7 +232,7 @@ class cSAXSDLPCA200:
Set the transimpedance gain of a DLPCA-200 amplifier.
The method automatically selects low-noise mode (Pin14=HIGH) whenever
the requested gain is achievable in low-noise mode (1e3 1e9 V/A).
the requested gain is achievable in low-noise mode (1e3 - 1e9 V/A).
For gains of 1e10 and 1e11 V/A, high-speed mode is used automatically.
Parameters
@@ -258,7 +254,9 @@ class cSAXSDLPCA200:
"""
gain_int = int(gain)
if gain_int not in _GAIN_TO_BITS:
valid_str = ", ".join(f"1e{int(round(__import__('math').log10(g)))}" for g in VALID_GAINS)
valid_str = ", ".join(
f"1e{int(round(__import__('math').log10(g)))}" for g in VALID_GAINS
)
raise cSAXSDLPCA200Error(
f"{self.TAG} Invalid gain {gain:.2e} V/A for '{amp_name}'. "
f"Valid values: {valid_str}"
@@ -284,11 +282,11 @@ class cSAXSDLPCA200:
try:
rio = self._get_rio(amp_name)
ch = self._get_cfg(amp_name)["channels"]
ch = self._get_cfg(amp_name)["channels"]
self._dout_set(rio, ch["gain_msb"], bool(msb))
self._dout_set(rio, ch["gain_mid"], bool(mid))
self._dout_set(rio, ch["gain_lsb"], bool(lsb))
self._dout_set(rio, ch["gain_msb"], bool(msb))
self._dout_set(rio, ch["gain_mid"], bool(mid))
self._dout_set(rio, ch["gain_lsb"], bool(lsb))
self._dout_set(rio, ch["speed_mode"], use_low_noise) # True=low-noise
mode_str = "low-noise" if use_low_noise else "high-speed"
@@ -297,7 +295,7 @@ class cSAXSDLPCA200:
f"({mode_str} mode, bits MSB={msb} MID={mid} LSB={lsb})"
)
print(
f"{amp_name}: gain {gain_int:.2e} V/A [{mode_str}] "
f"{amp_name}: gain -> {gain_int:.2e} V/A [{mode_str}] "
f"(bits: MSB={msb} MID={mid} LSB={lsb})"
)
@@ -318,7 +316,7 @@ class cSAXSDLPCA200:
Amplifier name (e.g. "bpm4", "bim").
coupling : str
"AC" or "DC" (case-insensitive).
DC Pin13 HIGH, AC Pin13 LOW.
DC -> Pin13 HIGH, AC -> Pin13 LOW.
Examples
--------
@@ -328,19 +326,18 @@ class cSAXSDLPCA200:
coupling_upper = coupling.strip().upper()
if coupling_upper not in ("AC", "DC"):
raise cSAXSDLPCA200Error(
f"{self.TAG} Invalid coupling '{coupling}' for '{amp_name}'. "
f"Use 'AC' or 'DC'."
f"{self.TAG} Invalid coupling '{coupling}' for '{amp_name}'. " f"Use 'AC' or 'DC'."
)
pin13_high = coupling_upper == "DC"
try:
rio = self._get_rio(amp_name)
ch = self._get_cfg(amp_name)["channels"]
ch = self._get_cfg(amp_name)["channels"]
self._dout_set(rio, ch["coupling"], pin13_high)
logger.info(f"{self.TAG} [{amp_name}] coupling set to {coupling_upper}")
print(f"{amp_name}: coupling {coupling_upper}")
print(f"{amp_name}: coupling -> {coupling_upper}")
except cSAXSDLPCA200Error:
raise
@@ -350,7 +347,7 @@ class cSAXSDLPCA200:
) from exc
# ------------------------------------------------------------------
# Public API readback / reporting
# Public API - readback / reporting
# ------------------------------------------------------------------
def read_settings(self, amp_name: str) -> dict:
@@ -361,17 +358,17 @@ class cSAXSDLPCA200:
-------
dict with keys:
"amp_name" : str
"gain" : int or None gain in V/A (None if unknown bit pattern)
"mode" : str "low-noise" or "high-speed"
"coupling" : str "AC" or "DC"
"bits" : dict raw bit values {msb, mid, lsb, speed_mode, coupling}
"gain" : int or None - gain in V/A (None if unknown bit pattern)
"mode" : str - "low-noise" or "high-speed"
"coupling" : str - "AC" or "DC"
"bits" : dict - raw bit values {msb, mid, lsb, speed_mode, coupling}
"""
rio = self._get_rio(amp_name)
ch = self._get_cfg(amp_name)["channels"]
ch = self._get_cfg(amp_name)["channels"]
msb = self._dout_get(rio, ch["gain_msb"])
mid = self._dout_get(rio, ch["gain_mid"])
lsb = self._dout_get(rio, ch["gain_lsb"])
msb = self._dout_get(rio, ch["gain_msb"])
mid = self._dout_get(rio, ch["gain_mid"])
lsb = self._dout_get(rio, ch["gain_lsb"])
speed_mode = self._dout_get(rio, ch["speed_mode"])
coupling_bit = self._dout_get(rio, ch["coupling"])
@@ -381,15 +378,15 @@ class cSAXSDLPCA200:
return {
"amp_name": amp_name,
"gain": gain,
"mode": mode,
"gain": gain,
"mode": mode,
"coupling": coupling,
"bits": {
"msb": msb,
"mid": mid,
"lsb": lsb,
"msb": msb,
"mid": mid,
"lsb": lsb,
"speed_mode": speed_mode,
"coupling": coupling_bit,
"coupling": coupling_bit,
},
}
@@ -426,7 +423,9 @@ class cSAXSDLPCA200:
print(f" {'Gain':<12}: {gain_str}")
print(f" {'Mode':<12}: {s['mode']}")
print(f" {'Coupling':<12}: {s['coupling']}")
print(f" {'Raw bits':<12}: MSB={bits['msb']} MID={bits['mid']} LSB={bits['lsb']} speed={bits['speed_mode']} coup={bits['coupling']}")
print(
f" {'Raw bits':<12}: MSB={bits['msb']} MID={bits['mid']} LSB={bits['lsb']} speed={bits['speed_mode']} coup={bits['coupling']}"
)
def info_all(self) -> None:
"""
@@ -440,4 +439,4 @@ class cSAXSDLPCA200:
def list_amplifiers(self) -> list[str]:
"""Return sorted list of configured amplifier names."""
return sorted(self._config.keys())
return sorted(self._config.keys())