dcm-stepper-calibration/dcm_lookup_tables.org

368 lines
12 KiB
Org Mode
Raw Normal View History

2021-12-06 11:58:41 +01:00
#+TITLE: ESRF Double Crystal Monochromator - Lookup Tables
:DRAWER:
#+LANGUAGE: en
#+EMAIL: dehaeze.thomas@gmail.com
#+AUTHOR: Dehaeze Thomas
#+HTML_LINK_HOME: ../index.html
#+HTML_LINK_UP: ../index.html
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://research.tdehaeze.xyz/css/style.css"/>
#+HTML_HEAD: <script type="text/javascript" src="https://research.tdehaeze.xyz/js/script.js"></script>
#+BIND: org-latex-image-default-option "scale=1"
#+BIND: org-latex-image-default-width ""
#+LaTeX_CLASS: scrreprt
#+LaTeX_CLASS_OPTIONS: [a4paper, 10pt, DIV=12, parskip=full]
#+LaTeX_HEADER_EXTRA: \input{preamble.tex}
#+LATEX_HEADER_EXTRA: \bibliography{ref}
#+PROPERTY: header-args:matlab :session *MATLAB*
#+PROPERTY: header-args:matlab+ :comments org
#+PROPERTY: header-args:matlab+ :exports both
#+PROPERTY: header-args:matlab+ :results none
#+PROPERTY: header-args:matlab+ :tangle no
#+PROPERTY: header-args:matlab+ :eval no-export
#+PROPERTY: header-args:matlab+ :noweb yes
#+PROPERTY: header-args:matlab+ :mkdirp yes
#+PROPERTY: header-args:matlab+ :output-dir figs
#+PROPERTY: header-args:latex :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/tikz/org/}{config.tex}")
#+PROPERTY: header-args:latex+ :imagemagick t :fit yes
#+PROPERTY: header-args:latex+ :iminoptions -scale 100% -density 150
#+PROPERTY: header-args:latex+ :imoutoptions -quality 100
#+PROPERTY: header-args:latex+ :results file raw replace
#+PROPERTY: header-args:latex+ :buffer no
#+PROPERTY: header-args:latex+ :tangle no
#+PROPERTY: header-args:latex+ :eval no-export
#+PROPERTY: header-args:latex+ :exports results
#+PROPERTY: header-args:latex+ :mkdirp yes
#+PROPERTY: header-args:latex+ :output-dir figs
#+PROPERTY: header-args:latex+ :post pdf2svg(file=*this*, ext="png")
:END:
#+begin_export html
<hr>
<p>This report is also available as a <a href="./dcm_lookup_tables.pdf">pdf</a>.</p>
<hr>
#+end_export
#+latex: \clearpage
* Introduction
Several Lookup Tables (LUT) are used for the DCM in order to compensate for *repeatable* errors.
- Section [[sec:dcm_stepper_lut]]: the stepper motors are calibrated using interferometers.
- Section [[sec:dcm_attocube_lut]]: the Attocube periodic non-linearities are calibrated using piezoelectric actuators.
2021-12-06 11:58:41 +01:00
* Stepper Motors Calibration
:PROPERTIES:
:header-args:matlab+: :tangle matlab/dcm_stepper_lut.m
:END:
<<sec:dcm_stepper_lut>>
** Introduction :ignore:
** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>>
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
<<matlab-init>>
#+end_src
#+begin_src matlab :tangle no :noweb yes
<<m-init-path>>
#+end_src
#+begin_src matlab :eval no :noweb yes
<<m-init-path-tangle>>
#+end_src
#+begin_src matlab :noweb yes
<<m-init-other>>
#+end_src
** Schematic
** Simulation
In this section, we suppose that we are in the frame of one fast jack (all transformations are already done), and we wish to create a LUT for one fast jack.
Let's say with make a Bragg angle scan between 10deg and 60deg during 100s.
#+begin_src matlab
Fs = 10e3; % Sample Frequency [Hz]
t = 0:1/Fs:10; % Time vector [s]
theta = linspace(10, 40, length(t)); % Bragg Angle [deg]
2021-12-06 11:58:41 +01:00
#+end_src
The IcePAP steps are following the theoretical formula:
\begin{equation}
d_z = \frac{d_{\text{off}}}{2 \cos \theta}
\end{equation}
with $\theta$ the bragg angle and $d_{\text{off}} = 10\,mm$.
The motion to follow is then:
#+begin_src matlab
perfect_motion = 10e-3./(2*cos(theta*pi/180)); % Perfect motion [m]
#+end_src
And the IcePAP is generated those steps:
#+begin_src matlab
icepap_steps = perfect_motion; % IcePAP steps measured by Speedgoat [m]
#+end_src
#+begin_src matlab :exports none
%% Steps as a function of the bragg angle
figure;
plot(theta, icepap_steps);
xlabel('Bragg Angle [deg]'); ylabel('IcePAP Steps [m]');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/bragg_angle_icepap_steps_idealized.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:bragg_angle_icepap_steps_idealized
#+caption: IcePAP Steps as a function of the Bragg Angle
#+RESULTS:
[[file:figs/bragg_angle_icepap_steps_idealized.png]]
Then, we are measuring the motion of the Fast Jack using the Interferometer.
The motion error is larger than in reality to be angle to see it more easily.
#+begin_src matlab
motion_error = 100e-6*sin(2*pi*perfect_motion/1e-3); % Error motion [m]
measured_motion = perfect_motion + motion_error; % Measured motion of the Fast Jack [m]
#+end_src
#+begin_src matlab :exports none
%% Measured Motion and Idealized Motion
figure;
hold on;
plot(icepap_steps, measured_motion, ...
'DisplayName', 'Measured Motion');
plot(icepap_steps, perfect_motion, 'k--', ...
'DisplayName', 'Ideal Motion');
hold off;
xlabel('IcePAP Steps [m]'); ylabel('Measured Motion [m]');
legend('location', 'southeast');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/measured_and_ideal_motion_fast_jacks.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:measured_and_ideal_motion_fast_jacks
#+caption: Measured motion as a function of the IcePAP Steps
#+RESULTS:
[[file:figs/measured_and_ideal_motion_fast_jacks.png]]
Let's now compute the lookup table.
For each micrometer of the IcePAP step, another step is associated that correspond to a position closer to the wanted position.
#+begin_src matlab
%% Get range for the LUT
% We correct only in the range of tested/measured motion
lut_range = round(1e6*min(icepap_steps)):round(1e6*max(icepap_steps)); % IcePAP steps [um]
%% Initialize the LUT
lut = zeros(size(lut_range));
%% For each um in this range
for i = 1:length(lut_range)
% Get points indices where the measured motion is closed to the wanted one
close_points = measured_motion > 1e-6*lut_range(i) - 500e-9 & measured_motion < 1e-6*lut_range(i) + 500e-9;
% Get the corresponding closest IcePAP step
lut(i) = round(1e6*mean(icepap_steps(close_points))); % [um]
end
#+end_src
#+begin_src matlab :exports none
%% Generated Lookup Table
figure;
plot(lut_range, lut);
xlabel('IcePAP input step [um]'); ylabel('Lookup Table output [um]');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/generated_lut_icepap.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:generated_lut_icepap
#+caption: Generated Lookup Table
#+RESULTS:
[[file:figs/generated_lut_icepap.png]]
The current LUT implementation is the following:
2021-12-06 11:58:41 +01:00
#+begin_src matlab
motion_error_lut = zeros(size(lut_range));
for i = 1:length(lut_range)
% Get points indices where the icepap step is close to the wanted one
close_points = icepap_steps > 1e-6*lut_range(i) - 500e-9 & icepap_steps < 1e-6*lut_range(i) + 500e-9;
% Get the corresponding motion error
motion_error_lut(i) = lut_range(i) + (lut_range(i) - round(1e6*mean(measured_motion(close_points)))); % [um]
2021-12-06 11:58:41 +01:00
end
#+end_src
Let's compare the two Lookup Table in Figure [[fig:lut_comparison_two_methods]].
#+begin_src matlab :exports none
%% Comparison of the two Generated Lookup Table
figure;
hold on;
plot(lut_range, lut, ...
'DisplayName', 'New LUT');
plot(lut_range, motion_error_lut, ...
'DisplayName', 'Old LUT');
hold off;
xlabel('IcePAP input step [um]'); ylabel('Lookup Table output [um]');
legend('location', 'southeast');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/lut_comparison_two_methods.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:lut_comparison_two_methods
#+caption: Comparison of the two lookup tables
#+RESULTS:
[[file:figs/lut_comparison_two_methods.png]]
If we plot the "corrected steps" for all steps for both methods, we clearly see the difference (Figure [[fig:lut_correct_and_motion_error]]).
2021-12-06 11:58:41 +01:00
#+begin_src matlab :exports none
%% Corrected motion and motion error at each step position
figure;
hold on;
plot(lut_range, lut-lut_range, ...
'DisplayName', 'New LUT');
plot(lut_range, motion_error_lut-lut_range, ...
'DisplayName', 'Old LUT');
2021-12-06 11:58:41 +01:00
hold off;
xlabel('IcePAP Steps [um]'); ylabel('Corrected motion [um]');
ylim([-110, 110])
legend('location', 'southeast');
2021-12-06 11:58:41 +01:00
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/lut_correct_and_motion_error.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:lut_correct_and_motion_error
#+caption: LUT correction and motion error as a function of the IcePAP steps
#+RESULTS:
[[file:figs/lut_correct_and_motion_error.png]]
Let's now implement both LUT to see which implementation is correct.
#+begin_src matlab :exports none
icepap_steps_output_new = lut(round(1e6*icepap_steps)-lut_range(1)+1);
i = round(1e6*icepap_steps)-motion_error_lut(1)+1;
i(i>length(motion_error_lut)) = length(motion_error_lut);
icepap_steps_output_old = motion_error_lut(i);
#+end_src
#+begin_src matlab
motion_new = zeros(size(icepap_steps_output_new));
motion_old = zeros(size(icepap_steps_output_old));
for i = 1:length(icepap_steps_output_new)
[~, i_step] = min(abs(icepap_steps_output_new(i) - 1e6*icepap_steps));
motion_new(i) = measured_motion(i_step);
[~, i_step] = min(abs(icepap_steps_output_old(i) - 1e6*icepap_steps));
motion_old(i) = measured_motion(i_step);
end
#+end_src
The output motion with both LUT are shown in Figure [[fig:compare_old_new_lut_motion]].
It is confirmed that the new LUT is the correct one.
Also, it is interesting to note that the old LUT gives an output motion that is above the ideal one, as was seen during the experiments.
#+begin_src matlab :exports none
%% Measured Motion and Idealized Motion
% Use only middle motion where the LUT is working
i = round(0.1*length(icepap_steps)):round(0.9*length(icepap_steps));
figure;
hold on;
plot(icepap_steps(i), motion_new(i), ...
'DisplayName', 'Motion (new LUT)');
plot(icepap_steps(i), motion_old(i), ...
'DisplayName', 'Motion (old LUT)');
plot(icepap_steps(i), perfect_motion(i), 'k--', ...
'DisplayName', 'Ideal Motion');
hold off;
xlabel('IcePAP Steps [m]'); ylabel('Measured Motion [m]');
legend('location', 'southeast');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/compare_old_new_lut_motion.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:compare_old_new_lut_motion
#+caption: Comparison of the obtained motion with new and old LUT
#+RESULTS:
[[file:figs/compare_old_new_lut_motion.png]]
* Attocube Calibration
:PROPERTIES:
:header-args:matlab+: :tangle matlab/dcm_attocube_lut.m
:END:
<<sec:dcm_attocube_lut>>
** Introduction :ignore:
** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>>
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
<<matlab-init>>
#+end_src
#+begin_src matlab :tangle no :noweb yes
<<m-init-path>>
#+end_src
#+begin_src matlab :eval no :noweb yes
<<m-init-path-tangle>>
#+end_src
#+begin_src matlab :noweb yes
<<m-init-other>>
#+end_src
2021-12-06 11:58:41 +01:00
* Helping Functions :noexport:
** Initialize Path
#+NAME: m-init-path
#+BEGIN_SRC matlab
%% Path for functions, data and scripts
addpath('./matlab/mat/'); % Path for data
addpath('./matlab/'); % Path for scripts
#+END_SRC
#+NAME: m-init-path-tangle
#+BEGIN_SRC matlab
%% Path for functions, data and scripts
addpath('./mat/'); % Path for data
#+END_SRC
** Initialize Simscape Model
#+NAME: m-init-simscape
#+begin_src matlab
#+end_src
** Initialize other elements
#+NAME: m-init-other
#+BEGIN_SRC matlab
%% Colors for the figures
colors = colororder;
%% Frequency Vector
freqs = logspace(1, 3, 1000);
#+END_SRC
* Bibliography :ignore:
#+latex: \printbibliography