DAQ: removed samcam script as it duplicated area_detector
This commit is contained in:
@@ -1,163 +0,0 @@
|
||||
from epics import PV
|
||||
|
||||
from aare.common.beamline import MXBeamline
|
||||
|
||||
|
||||
class SamCam:
|
||||
def __init__(self, bl: MXBeamline):
|
||||
BEAMLINE = bl.value.upper()
|
||||
sam_cam_pv_name = f"{BEAMLINE}-SAMCAM"
|
||||
self.cam_exp = PV(f"{sam_cam_pv_name}:cam1:AcquireTime")
|
||||
self.cam_gain = PV(f"{sam_cam_pv_name}:cam1:Gain")
|
||||
self.cam_mean = PV(f"{sam_cam_pv_name}:Stats1:MeanValue_RBV")
|
||||
|
||||
def auto_exposure(self,
|
||||
target_mean=128,
|
||||
tolerance=5,
|
||||
max_iterations=50,
|
||||
timeout=30.0):
|
||||
"""
|
||||
Auto-expose a camera by adaptively adjusting exposure and gain.
|
||||
|
||||
Args:
|
||||
cam_exp_pv: PV for exposure time (0 to 0.2s)
|
||||
cam_gain_pv: PV for gain (36 to 512)
|
||||
cam_mean_pv: PV for image mean value
|
||||
target_mean: Target mean pixel value (default 128)
|
||||
tolerance: Acceptable range ±tolerance (default ±5)
|
||||
max_iterations: Maximum iterations before giving up
|
||||
timeout: Total timeout in seconds
|
||||
|
||||
Returns:
|
||||
dict with status, final_mean, iterations, exposure, gain
|
||||
|
||||
Raises:
|
||||
TimeoutError if target not reached within timeout
|
||||
ValueError if PVs are invalid
|
||||
"""
|
||||
import time
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# Validate PVs and get initial values
|
||||
try:
|
||||
exp = self.cam_exp.get()
|
||||
gain = self.cam_gain.get()
|
||||
mean = self.cam_mean.get()
|
||||
except Exception as e:
|
||||
raise ValueError(f"Failed to read camera PVs: {e}")
|
||||
|
||||
# Hardware limits
|
||||
EXP_MIN, EXP_MAX = 0.0, 0.2
|
||||
GAIN_MIN, GAIN_MAX = 36, 512
|
||||
|
||||
# Check if we're already in target range
|
||||
if abs(mean - target_mean) <= tolerance:
|
||||
return {
|
||||
"status": "success",
|
||||
"final_mean": mean,
|
||||
"iterations": 0,
|
||||
"exposure": exp,
|
||||
"gain": gain,
|
||||
"converged": True
|
||||
}
|
||||
|
||||
iteration = 0
|
||||
|
||||
while iteration < max_iterations:
|
||||
# Check timeout
|
||||
if time.time() - start_time > timeout:
|
||||
raise TimeoutError(
|
||||
f"Auto-exposure failed to converge after {timeout}s. "
|
||||
f"Last mean: {mean:.1f}"
|
||||
)
|
||||
|
||||
iteration += 1
|
||||
error = mean - target_mean # Positive = too bright, negative = too dark
|
||||
|
||||
# Calculate adaptive step size based on error magnitude
|
||||
# Larger errors → larger steps for faster convergence
|
||||
error_magnitude = abs(error)
|
||||
|
||||
if error_magnitude > 30: # Large error: aggressive steps
|
||||
exp_step = 0.01
|
||||
gain_step = 40
|
||||
elif error_magnitude > 15: # Medium error: moderate steps
|
||||
exp_step = 0.005
|
||||
gain_step = 20
|
||||
else: # Small error: fine adjustments
|
||||
exp_step = 0.001
|
||||
gain_step = 5
|
||||
|
||||
# Strategy: Prefer adjusting gain first (faster response), then exposure
|
||||
# This prioritizes the parameter that responds more quickly to changes
|
||||
|
||||
if error > tolerance: # Too bright: reduce signal
|
||||
# Try to reduce gain first (has faster effect on some cameras)
|
||||
if gain > GAIN_MIN:
|
||||
gain = max(GAIN_MIN, gain - gain_step)
|
||||
self.cam_gain.put(gain)
|
||||
elif exp > EXP_MIN:
|
||||
exp = max(EXP_MIN, exp - exp_step)
|
||||
self.cam_exp.put(exp)
|
||||
else:
|
||||
# Already at minimum - can't go darker
|
||||
return {
|
||||
"status": "warning_min_limits",
|
||||
"final_mean": mean,
|
||||
"iterations": iteration,
|
||||
"exposure": exp,
|
||||
"gain": gain,
|
||||
"converged": False,
|
||||
"message": "Reached minimum exposure/gain, cannot reduce further"
|
||||
}
|
||||
|
||||
elif error < -tolerance: # Too dark: increase signal
|
||||
# Try to increase exposure first (more precise control)
|
||||
if exp < EXP_MAX:
|
||||
exp = min(EXP_MAX, exp + exp_step)
|
||||
self.cam_exp.put(exp)
|
||||
elif gain < GAIN_MAX:
|
||||
gain = min(GAIN_MAX, gain + gain_step)
|
||||
self.cam_gain.put(gain)
|
||||
else:
|
||||
# Already at maximum - can't go brighter
|
||||
return {
|
||||
"status": "warning_max_limits",
|
||||
"final_mean": mean,
|
||||
"iterations": iteration,
|
||||
"exposure": exp,
|
||||
"gain": gain,
|
||||
"converged": False,
|
||||
"message": "Reached maximum exposure/gain, cannot increase further"
|
||||
}
|
||||
|
||||
# Small settling time for camera to stabilize
|
||||
time.sleep(0.1)
|
||||
mean = self.cam_mean.get()
|
||||
|
||||
# Check convergence
|
||||
if abs(mean - target_mean) <= tolerance:
|
||||
return {
|
||||
"status": "success",
|
||||
"final_mean": mean,
|
||||
"iterations": iteration,
|
||||
"exposure": exp,
|
||||
"gain": gain,
|
||||
"converged": True
|
||||
}
|
||||
|
||||
# Max iterations exceeded
|
||||
return {
|
||||
"status": "warning_max_iterations",
|
||||
"final_mean": mean,
|
||||
"iterations": iteration,
|
||||
"exposure": exp,
|
||||
"gain": gain,
|
||||
"converged": False,
|
||||
"message": f"Did not converge after {max_iterations} iterations. Final mean: {mean:.1f}"
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
from aare.common.beamline import mx_beamline
|
||||
beamline = mx_beamline()
|
||||
Reference in New Issue
Block a user