94 lines
3.3 KiB
Python
94 lines
3.3 KiB
Python
"""Module for additional utils of the Mo1 Bragg Positioner"""
|
|
|
|
import numpy as np
|
|
from scipy.interpolate import BSpline
|
|
|
|
################ Define Constants ############
|
|
SAFETY_FACTOR = 0.025 # safety factor to limit acceleration -> NEVER SET TO ZERO !
|
|
N_SAMPLES = 41 # number of samples to generate -> Always choose uneven number,
|
|
# otherwise peak value will not be included
|
|
DEGREE_SPLINE = 3 # DEGREE_SPLINE of spline, 3 works good
|
|
TIME_COMPENSATE_SPLINE = 0.0062 # time to be compensated each spline in s
|
|
POSITION_COMPONSATION = 0.02 # angle to add at both limits, must be same values
|
|
# as used on ACS controller for simple scans
|
|
|
|
|
|
class Mo1UtilsSplineError(Exception):
|
|
"""Exception for spline computation"""
|
|
|
|
|
|
def compute_spline(
|
|
low_deg: float, high_deg: float, p_kink: float, e_kink_deg: float, scan_time: float
|
|
) -> tuple[float, float, float]:
|
|
"""Spline computation for the advanced scan mode
|
|
|
|
Args:
|
|
low_deg (float): Low angle value of the scan in deg
|
|
high_deg (float): High angle value of the scan in deg
|
|
scan_time (float): Time for a half oscillation in s
|
|
p_kink (float): Position of kink in %
|
|
e_kink_deg (float): Position of kink in degree
|
|
|
|
Returns:
|
|
tuple[float,float,float] : Position, Velocity and delta T arrays for the spline
|
|
"""
|
|
|
|
# increase motion range slightly so that xas trigger signals will occur at defined energy limits
|
|
low_deg = low_deg - POSITION_COMPONSATION
|
|
high_deg = high_deg + POSITION_COMPONSATION
|
|
|
|
if not (0 <= p_kink <= 100):
|
|
raise Mo1UtilsSplineError(
|
|
"Kink position not within range of [0..100%]" + f"for p_kink: {p_kink}"
|
|
)
|
|
|
|
if not (low_deg < e_kink_deg < high_deg):
|
|
raise Mo1UtilsSplineError(
|
|
"Kink energy not within selected energy range of scan,"
|
|
+ f"for e_kink_deg {e_kink_deg}, low_deg {low_deg} and"
|
|
+ f"high_deg {high_deg}."
|
|
)
|
|
|
|
tc1 = SAFETY_FACTOR / scan_time * TIME_COMPENSATE_SPLINE
|
|
t_kink = (scan_time - TIME_COMPENSATE_SPLINE - 2 * (SAFETY_FACTOR - tc1)) * p_kink / 100 + (
|
|
SAFETY_FACTOR - tc1
|
|
)
|
|
|
|
t_input = [
|
|
0,
|
|
SAFETY_FACTOR - tc1,
|
|
t_kink,
|
|
scan_time - TIME_COMPENSATE_SPLINE - SAFETY_FACTOR + tc1,
|
|
scan_time - TIME_COMPENSATE_SPLINE,
|
|
]
|
|
p_input = [0, 0, e_kink_deg - low_deg, high_deg - low_deg, high_deg - low_deg]
|
|
|
|
cv = np.stack((t_input, p_input)).T # spline coefficients
|
|
max_param = len(cv) - DEGREE_SPLINE
|
|
kv = np.clip(np.arange(len(cv) + DEGREE_SPLINE + 1) - DEGREE_SPLINE, 0, max_param) # knots
|
|
spl = BSpline(kv, cv, DEGREE_SPLINE) # get spline function
|
|
p = spl(np.linspace(0, max_param, N_SAMPLES))
|
|
v = spl(np.linspace(0, max_param, N_SAMPLES), 1)
|
|
a = spl(np.linspace(0, max_param, N_SAMPLES), 2)
|
|
j = spl(np.linspace(0, max_param, N_SAMPLES), 3)
|
|
|
|
tim, pos = p.T
|
|
pos = pos + low_deg
|
|
vel = v[:, 1] / v[:, 0]
|
|
|
|
acc = []
|
|
for item in a:
|
|
acc.append(0) if item[1] == 0 else acc.append(item[1] / item[0])
|
|
jerk = []
|
|
for item in j:
|
|
jerk.append(0) if item[1] == 0 else jerk.append(item[1] / item[0])
|
|
|
|
dt = np.zeros(len(tim))
|
|
for i in np.arange(len(tim)):
|
|
if i == 0:
|
|
dt[i] = 0
|
|
else:
|
|
dt[i] = 1000 * (tim[i] - tim[i - 1])
|
|
|
|
return pos, vel, dt
|