fix(xrayeye): make DAP sine fit converge by fixing start values and signed amplitude
CI for csaxs_bec / test (push) Failing after 2m13s
CI for csaxs_bec / test (push) Failing after 2m13s
The xray eye alignment fit (A*sin(f*x+shift)+intercept, 5 points) relied on lmfit's SineModel.guess() for the start values. Its FFT-based shift guess is arbitrary for 5 points and often left the fit stuck at the shift bound (2*pi) far from the data, so the plotted fit missed the submitted points and wrong parameters were loaded into flomni. Override all five parameters so the DAP server skips guess(): signed amplitude (start 30), shift start 0 within +-pi, intercept start 0, frequency and slope still fixed. Shared by the x and y waveforms. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017szgTwuHG65YhjoBGiK2Gj
This commit is contained in:
1 parent
d01af690a9
commit
bd85d5e673
1 file changed
+22
-8
@@ -34,6 +34,26 @@ from qtpy.QtWidgets import (
|
||||
logger = bec_logger.logger
|
||||
CAMERA = ("cam_xeye", "image")
|
||||
|
||||
# Start values / bounds for the DAP fit A*sin(f*x + shift) + intercept of the
|
||||
# alignment offsets vs. angle (5 points, 0..180 deg, f fixed to 1 deg in rad).
|
||||
# All five parameters are given so the DAP server does not use lmfit's
|
||||
# SineModel.guess(): its FFT-based shift guess is arbitrary for 5 points and
|
||||
# regularly left the fit stuck at the shift bound (2*pi) far from the data.
|
||||
# A signed amplitude (SineModel defaults to A >= 0) plus a fixed start
|
||||
# (A=30, shift=0, intercept=0) converged to the global least-squares optimum
|
||||
# in 1500/1500 random test datasets; A >= 0 failed in a few percent.
|
||||
SINE_FIT_DAP_PARAMETERS = [
|
||||
{
|
||||
"amplitude": {"value": 30, "vary": True, "min": -1e6, "max": 1e6},
|
||||
"frequency": {"value": 0.0174533, "vary": False, "min": 0.01, "max": 0.02},
|
||||
"shift": {"value": 0, "vary": True, "min": -math.pi, "max": math.pi},
|
||||
},
|
||||
{
|
||||
"slope": {"value": 0, "vary": False, "min": 0.0, "max": 0.02},
|
||||
"intercept": {"value": 0, "vary": True, "min": -1e6, "max": 1e6},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class TargetCrosshair:
|
||||
"""
|
||||
@@ -615,10 +635,7 @@ class OMNY_XRayEye(BECWidget, QWidget):
|
||||
y=[1],
|
||||
label="fit-x",
|
||||
dap=["SineModel", "LinearModel"],
|
||||
dap_parameters=[
|
||||
{"frequency": {"value": 0.0174533, "vary": False, "min": 0.01, "max": 0.02}},
|
||||
{"slope": {"value": 0, "vary": False, "min": 0.0, "max": 0.02}},
|
||||
],
|
||||
dap_parameters=SINE_FIT_DAP_PARAMETERS,
|
||||
dap_oversample=5,
|
||||
)
|
||||
self.waveform_y.plot(
|
||||
@@ -626,10 +643,7 @@ class OMNY_XRayEye(BECWidget, QWidget):
|
||||
y=[2],
|
||||
label="fit-y",
|
||||
dap=["SineModel", "LinearModel"],
|
||||
dap_parameters=[
|
||||
{"frequency": {"value": 0.0174533, "vary": False, "min": 0.01, "max": 0.02}},
|
||||
{"slope": {"value": 0, "vary": False, "min": 0.0, "max": 0.02}},
|
||||
],
|
||||
dap_parameters=SINE_FIT_DAP_PARAMETERS,
|
||||
dap_oversample=5,
|
||||
)
|
||||
self.fit_x = self.waveform_x.curves[0]
|
||||
|
||||
Reference in new issue
Block a user