Calibrating Delay Scans
Performing uncalibrated scans using the delay macromotor results in
positional instability of the beam at the sample. To address this, delay has
several methods to characterize and correct the scan.
Warning
The functionality described here has not been commissioned, and should be used with caution.
Characterizing Beam Instability
The main way to characterize the current scan instability is to run the
centroid_scan method. The method performs a scan using the inputted scan
parameters, measuring the centroids of the beam at Opal 1. The results are then
saved and graphed for the user to see.
In [1]: snd.delay.centroid_scan(start, stop, step)
To view the centroids again after the scan has been completed, the method
view_centroids can be used to view the centroids from the most recent
centroids_scan.
In [2]: snd.delay.view_centroids()
To view the graph displayed after the scan, run the graph_centroids method.
In [3]: snd.delay.graph_centroids()
Note
The results shown by view_centroids and graph_centroids come
from the recent centroid scan or calibration. Anytime a new centroid
scan is run, the previous scan data is overwritten.
Calibration Operations
In the event centroid_scan reveals the beam drifts too much throughout the
scan, there is a routine for building a correction table using the
snd.t1.chi1 and snd.t1.y1 motors to correct for the x and y centroids
respectively. This correction table is put together using the table generated
from a centroid_scan along with parameters to find the scaling information
between each of the motor positions and the beam centroids. Together all the
information collected during a calibrate run, constitutes a specific
calibration.
High-Level Properties
The delay macromotor comes with two high level properties pertaining to the
current state of the calibration. has_calibration indicates that a properly
configured calibration is currently loaded to the motor, simply returning a
bool.
The second high level property is use_calibration which determines whether
a calibration should be used during a move. By default, anytime a calibration is
created or loaded, use_calibration is set to be True. However, this is
primarily useful if there is a move where performing a the correction is not
desired. By setting use_calibration to False all moves will be done
without corrections
Note
Motor corrections will only be performed on every move command if
both has_calibration and use_calibration are True.
Creating a New Calibration
If a new calibration is necessary, the entire calibration routine can be run
using the calibrate method along with the desired scan parameters.
In [1]: snd.delay.calibrate(start, stop, step)
The calibration routine itself consists of first performing a centroid scan to
measure the current beam drift, and then performing a walk using each of the
calibration motors to find the motor position to centroid scaling. Once,
complete, the motor will automatically start using the new calibration for all
subsequent move commands. Additionally, all the motors will be returned to
their original positions after the routine has completed.
Note
A confirmation to overwrite the existing calibration will be required
to run calibrate if the motor already has a valid configuration.
Saving and Loading Calibrations
Calibrations used for the delay motor are all saved in the
HXRSnD/calibrations directory. Whenever a calibration routine has
completed, the calibration is saved into a file named
current_calibration.json. To save a calibration more permanently, the
method save_calibration can be used by passing a either filename or a full
path. Running,
In [1]: snd.delay.save_calibration('my_calibration')
Will save the current calibration as
HXRSnD/calibrations/my_calibration.json.
To load this configuration, the load_calibration method takes calibration
names, searches the HXRSnD/calibrations directory, and then applies the
dound calibration. For example,
In [2]: snd.delay.load_calibration('my_calibration')
loads the my_calibration.json from HXRSnD/calibrations.
Note
Running load_calibration without any inputs automatically loads
current_calibration.json.
Inspecting the Calibration
To view the contents of a calibration, the calibration property returns a
dictionary with five keys:
calib :
DataFramecontaining the correction table used by the calibration motors.motors : List of
Motorobjects that refer to the motors used by the calibration.scan :
DataFramecontaining the results of the centroid scan used to build the correction table.scale : List if values in units of ps/pixel, used to convert between pixel positions and delay position.
start : List of starting positions of the motors used to calculate the scale.
Note
calibration is a read-only property and cannot be used to modify
the live calibration.
Modifying Calibrations
Each of the five calibration values listed above can be modified outright using
the configure method. This is done by running configure and passing the
desired change as a keyword argument.
Warning
It is not advisable to change the the calibration in ways not listed below.
Correction Table Post-Processing
A simple reason to modify the correction table would be to apply some level of
post processing to the resulting table. For example, to apply a Savitzky-Golay
smoothing filter, first capturet he current correction table in a new dataframe
using the calibration property,
In [1]: df_calib = snd.delay.calibration['calib']
Then create a new dataframe with the applied filter using some window_length
and polyorder (see documentation on scipy.signal.savgol_filter for more
details),
In [2]: df_savgol = df_calib.apply(savgol_filter, args=(window_length, polyorder))
And then configure the motor to use this new correction table,
In [3]: snd.delay.configure(calib=df_savgol)
Note
Whenever the correction table is modified using configure, the
number of columns must equal the number of motors listed in
snd.delay.calibration['motors'].
Rescaling the Correction Table
In the event that the picosecond per pixel scaling factor may need to be redone,
the method rescale_calibration will perform the scaling routine and then
update the calibration accordingly.
In [1]: snd.delay.rescale_calibration()