1600 lines
56 KiB
Org Mode
1600 lines
56 KiB
Org Mode
#+TITLE: ESRF Double Crystal Monochromator - Metrology
|
|
: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: \addbibresource{dcm-metrology.bib}
|
|
|
|
#+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-metrology.pdf">pdf</a>.</p>
|
|
<hr>
|
|
#+end_export
|
|
|
|
#+latex: \clearpage
|
|
|
|
* Introduction :ignore:
|
|
|
|
In this document, the metrology system is studied.
|
|
First, in Section [[sec:metrology_concept]] the goal of the metrology system is stated and the proposed concept is described.
|
|
|
|
How the relative crystal pose is affecting the pose of the output beam is studied in Section [[sec:relation_crystal_xray]].
|
|
|
|
In order to increase the accuracy of the metrology system, two problems are to be dealt with:
|
|
- The deformation of the metrology frame under the action of gravity (Section [[sec:frame_deformations]])
|
|
- The periodic non-linearity of the interferometers (Section [[sec:dcm_attocube_lut]])
|
|
|
|
* Metrology Concept
|
|
<<sec:metrology_concept>>
|
|
** Introduction :ignore:
|
|
|
|
The goal of the metrology system is to measure the distance and default of parallelism between the first and second crystals.
|
|
|
|
Only 3 degrees of freedom are of interest:
|
|
- $d_z$
|
|
- $r_y$
|
|
- $r_x$
|
|
|
|
** 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
|
|
|
|
** Sensor Topology
|
|
|
|
In order to measure the relative pose of the two crystals, instead of performing a direct measurement which is complicated, the pose of the two crystals are measured from a metrology frame.
|
|
Three interferometers are used to measured the 3dof of interest for each crystals.
|
|
Three additional interferometers are used to measured the relative motion of the metrology frame.
|
|
|
|
|
|
In total, there are 15 interferometers represented in Figure [[fig:metrology_schematic]].
|
|
The measurements are summarized in Table [[tab:interferometer_list]].
|
|
|
|
#+name: tab:metrology_notations
|
|
#+caption: Notations for the metrology frame
|
|
#+attr_latex: :environment tabularx :width 0.4\linewidth :align cX
|
|
#+attr_latex: :center t :booktabs t
|
|
| *Notation* | *Meaning* |
|
|
|------------+--------------------------|
|
|
| =d= | "Downstream": Positive X |
|
|
| =u= | "Upstream": Negative X |
|
|
| =h= | "Hall": Positive Y |
|
|
| =r= | "Ring": Negative Y |
|
|
| =f= | "Frame" |
|
|
| =1= | "First Crystals" |
|
|
| =2= | "Second Crystals" |
|
|
|
|
#+name: tab:interferometer_list
|
|
#+caption: List of Interferometer measurements
|
|
#+attr_latex: :environment tabularx :width 0.7\linewidth :align ccl
|
|
#+attr_latex: :center t :booktabs t
|
|
| *Number* | *Measurement* | *Description* |
|
|
|----------+---------------+-------------------------------------|
|
|
| 1 | $z_{1r,u}$ | First "Ring" Crystal, "upstream" |
|
|
| 2 | $z_{1r,c}$ | First "Ring" Crystal, "center" |
|
|
| 3 | $z_{1r,d}$ | First "Ring" Crystal, "downstream" |
|
|
| 4 | $z_{1h,u}$ | First "Hall" Crystal, "upstream" |
|
|
| 5 | $z_{1h,c}$ | First "Hall" Crystal, "center" |
|
|
| 6 | $z_{1h,d}$ | First "Hall" Crystal, "downstream" |
|
|
| 7 | $z_{2h,u}$ | Second "Hall" Crystal, "upstream" |
|
|
| 8 | $z_{2h,c}$ | Second "Hall" Crystal, "center" |
|
|
| 9 | $z_{2h,d}$ | Second "Hall" Crystal, "downstream" |
|
|
| 10 | $z_{2r,u}$ | Second "Ring" Crystal, "upstream" |
|
|
| 11 | $z_{2r,c}$ | Second "Ring" Crystal, "center" |
|
|
| 12 | $z_{2r,d}$ | Second "Ring" Crystal, "downstream" |
|
|
| 13 | $z_{mf,u}$ | Metrology Frame, "upstream" |
|
|
| 14 | $z_{mf,dr}$ | Metrology Frame, "downstream-ring" |
|
|
| 15 | $z_{mf,dh}$ | Metrology Frame, "downstream-hall" |
|
|
|
|
#+name: fig:metrology_schematic
|
|
#+caption: Schematic of the Metrology System
|
|
[[file:figs/metrology_schematic.png]]
|
|
|
|
** Computation of the relative pose between first and second crystals
|
|
|
|
To understand how the relative pose between the crystals is computed from the interferometer signals, have a look at [[https://gitlab.esrf.fr/dehaeze/dcm-kinematics][this repository]] (=https://gitlab.esrf.fr/dehaeze/dcm-kinematics=).
|
|
|
|
Basically, Jacobian matrices are derived from the geometry and are used to convert the 15 interferometer signals to the *relative pose* of the primary and secondary crystals $[d_{h,z},\ r_{h,y},\ r_{h,x}]$ or $[d_{r,z},\ r_{r,y},\ r_{r,x}]$.
|
|
|
|
#+begin_note
|
|
The sign conventions for the relative crystal pose are:
|
|
- An increase of $d_{h,z}$ means the two crystals are further apart
|
|
- An increase of $r_{h,}$ means that the second crystals experiences a rotation around $y$ with respect to the primary crystal
|
|
- An increase of $r_{h,x}$ means that the second crystals experiences a rotation around $x$ with respect to the primary crystal
|
|
#+end_note
|
|
|
|
The relative pose can be expressed as a function of the interferometers using the Jacobian matrices for the "hall" crystals:
|
|
\begin{equation}
|
|
\boxed{
|
|
\begin{bmatrix} d_{h,z} \\ r_{h,y} \\ r_{h,x} \end{bmatrix}
|
|
=
|
|
\bm{J}_{2h,s}^{-1}
|
|
\begin{bmatrix} z_{2h,u} \\ z_{2h,c} \\ z_{2h,d} \end{bmatrix}
|
|
-
|
|
\bm{J}_{1h,s}^{-1}
|
|
\begin{bmatrix} z_{1h,u} \\ z_{1h,c} \\ z_{1h,d} \end{bmatrix}
|
|
-
|
|
\bm{J}_{mf,s}^{-1}
|
|
\begin{bmatrix} z_{mf,u} \\ z_{mf,dh} \\ z_{mf,dr} \end{bmatrix}
|
|
}
|
|
\end{equation}
|
|
|
|
As well as for the "ring" crystals:
|
|
\begin{equation}
|
|
\boxed{
|
|
\begin{bmatrix} d_{r,z} \\ r_{r,y} \\ r_{r,x} \end{bmatrix}
|
|
=
|
|
\bm{J}_{2r,s}^{-1}
|
|
\begin{bmatrix} z_{2r,u} \\ z_{2r,c} \\ z_{2r,d} \end{bmatrix}
|
|
-
|
|
\bm{J}_{1r,s}^{-1}
|
|
\begin{bmatrix} z_{1r,u} \\ z_{1r,c} \\ z_{1r,d} \end{bmatrix}
|
|
-
|
|
\bm{J}_{mf,s}^{-1}
|
|
\begin{bmatrix} z_{mf,u} \\ z_{mf,dr} \\ z_{mf,dr} \end{bmatrix}
|
|
}
|
|
\end{equation}
|
|
|
|
Values of the matrices can be found in the document describing the kinematics of the DCM (see =https://gitlab.esrf.fr/dehaeze/dcm-kinematics=).
|
|
|
|
* Relation Between Crystal position and X-ray measured displacement
|
|
<<sec:relation_crystal_xray>>
|
|
** Introduction :ignore:
|
|
|
|
In this section, the impact of an error in the relative pose between the first and second crystals on the output X-ray beam is studied.
|
|
|
|
This is very important in order to:
|
|
- link a measurement of the x-ray beam position to a default in the crystal position
|
|
- understand which pose default will have large impact on the output beam position/orientation
|
|
- calibrate the deformations of the metrology frame using an external metrology measuring the x-ray beam position/orientation
|
|
|
|
In order to simplify the problem, the first crystal is supposed to be fixed (i.e. ideally positioned), and only the motion of the second crystal is studied.
|
|
|
|
In order to easily study that, "ray tracing" techniques are used.
|
|
|
|
** 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
|
|
|
|
** Definition of frame
|
|
|
|
| | Position | Orientation |
|
|
|------------------+------------+-------------|
|
|
| input beam | =x1,y1,z1= | =s1= |
|
|
| primary mirror | =xp,yp,zp= | =np= |
|
|
| reflected beam | =x2,y2,z2= | =s2= |
|
|
| secondary mirror | =xs,ys,zz= | =ns= |
|
|
| output beam | =x3,y3,z3= | =s3= |
|
|
| Dectector | =xd,yd,zd= | =nd= |
|
|
|
|
- [ ] Add schematic
|
|
|
|
Notations for the pose of the output beam: =d_b_y=, =d_b_z=, =r_b_y=, =r_b_z=.
|
|
|
|
$d_{b,y}, d_{b,z}, r_{b,y}, r_{b,z}$
|
|
|
|
The xy position of the beam is taken in the $x=0$ plane.
|
|
|
|
** Effect of an error in crystal's distance
|
|
<<sec:ray_tracing_dz>>
|
|
|
|
In Figure [[fig:ray_tracing_error_dz_overview]] is shown the light path for three bragg angles (5, 55 and 85 degrees) when there is an error in the =dz= position of 1mm.
|
|
|
|
Visually, it is clear that this induce a =z= offset of the output beam.
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Visual Effect of an error in dz
|
|
figure;
|
|
hold on;
|
|
for theta = [5, 55, 85]
|
|
results = getBeamPath(theta*pi/180, 'dz', 1e-3);
|
|
set(gca,'ColorOrderIndex',1)
|
|
plotBeamPath(results);
|
|
plotCrystals(results);
|
|
end
|
|
hold off;
|
|
view(0,0)
|
|
xlim([-10, 15])
|
|
zlim([-4, 2])
|
|
grid off;
|
|
axis equal
|
|
xlabel('X [cm]')
|
|
ylabel('Y [cm]')
|
|
zlabel('Z [cm]')
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/ray_tracing_error_dz_overview.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:ray_tracing_error_dz_overview
|
|
#+caption: Visual Effect of an error in =dz= (1mm). Side view.
|
|
#+RESULTS:
|
|
[[file:figs/ray_tracing_error_dz_overview.png]]
|
|
|
|
The motion of the output beam is displayed as a function of the Bragg angle in Figure [[fig:motion_beam_dz_error]].
|
|
It is clear that an error in the distance =dz= between the crystals only induce a =z= offset of the output beam.
|
|
This offset decreases with the Bragg angle.
|
|
|
|
This is indeed equal to:
|
|
\begin{equation}
|
|
\boxed{d_{b,z} = 2 d_z \cos \theta}
|
|
\end{equation}
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Effect of dz
|
|
thetas = 1:1:85;
|
|
Dy = zeros(length(thetas), 1); % [m]
|
|
Dz = zeros(length(thetas), 1); % [m]
|
|
Ry = zeros(length(thetas), 1); % [rad]
|
|
Rz = zeros(length(thetas), 1); % [rad]
|
|
for i = 1:length(thetas)
|
|
results = getBeamPath(thetas(i)*pi/180, 'dz', 1e-9);
|
|
Ry(i) = atan2(results.s3(3), results.s3(1));
|
|
Rz(i) = atan2(results.s3(2), results.s3(1));
|
|
Dy(i) = results.p4(2)-tan(Rz(i));
|
|
Dz(i) = results.p4(3)+tan(Ry(i));
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Motion of the output beam with dZ error
|
|
figure;
|
|
hold on;
|
|
plot(thetas, 1e9*Dy, '--', 'DisplayName', 'Dy');
|
|
plot(thetas, 1e9*(Dz+10e-3), '--', 'DisplayName', 'Dz');
|
|
plot(thetas, 1e9*Ry, 'DisplayName', 'Ry');
|
|
plot(thetas, 1e9*Rz, 'DisplayName', 'Rz');
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Offset [m/m] Tilt [rad/m]')
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
xlim([0, 85]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/motion_beam_dz_error.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:motion_beam_dz_error
|
|
#+caption: Motion of the output beam with dZ error
|
|
#+RESULTS:
|
|
[[file:figs/motion_beam_dz_error.png]]
|
|
|
|
** Effect of an error in crystal's x parallelism
|
|
<<sec:ray_tracing_rx>>
|
|
|
|
The effect of an error in =rx= crystal parallelism on the output beam is visually shown in Figure [[fig:ray_tracing_error_drx_overview]] for three bragg angles (5, 55 and 85 degrees).
|
|
The error is set to one degree, and the top view is shown.
|
|
It is clear that the output beam experiences some rotation around a vertical axis.
|
|
The amount of rotation depends on the bragg angle.
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Visual Effect of an error in drx
|
|
figure;
|
|
hold on;
|
|
for theta = [5, 55, 85]
|
|
results = getBeamPath(theta*pi/180, 'drx', -1*pi/180);
|
|
set(gca,'ColorOrderIndex',1)
|
|
plotBeamPath(results);
|
|
% plotCrystals(results);
|
|
end
|
|
hold off;
|
|
view(0,90)
|
|
axis equal
|
|
xlim([-10, 15])
|
|
ylim([-1, 1])
|
|
grid off;
|
|
xlabel('X [cm]');
|
|
ylabel('Y [cm]');
|
|
zlabel('Z [cm]');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/ray_tracing_error_drx_overview.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:ray_tracing_error_drx_overview
|
|
#+caption: Visual Effect of an error in =drx= (1 degree). Top View.
|
|
#+RESULTS:
|
|
[[file:figs/ray_tracing_error_drx_overview.png]]
|
|
|
|
The effect of =drx= as a function of the Bragg angle on the output beam pose is computed and shown in Figure [[fig:motion_beam_drx_error]].
|
|
|
|
It induces a rotation of the output beam in the =z= direction that depends on the Bragg Angle.
|
|
It is starting at zero for small bragg angles, and it increases with the bragg angle up to 2 times =drx=.
|
|
This is indeed equal to:
|
|
\begin{equation}
|
|
\boxed{r_{b,z} = -2 r_x \sin \theta}
|
|
\end{equation}
|
|
|
|
If also induces a small $y$ shift of the beam.
|
|
This shift is due to the fact that the rotation point (around which the second crystal is moved) is changing as a function of bragg.
|
|
We can note that the $y$ shift is equal to zero for a bragg angle of 45 degrees, at which point the center of rotation of the second crystal is at $x = 0$;
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Effect of drx
|
|
thetas = 1:1:85;
|
|
Dy = zeros(length(thetas), 1);
|
|
Dz = zeros(length(thetas), 1);
|
|
Ry = zeros(length(thetas), 1);
|
|
Rz = zeros(length(thetas), 1);
|
|
for i = 1:length(thetas)
|
|
results = getBeamPath(thetas(i)*pi/180, 'drx', 1e-9);
|
|
Ry(i) = atan2(results.s3(3), results.s3(1));
|
|
Rz(i) = atan2(results.s3(2), results.s3(1));
|
|
Dy(i) = results.p4(2)-tan(Rz(i));
|
|
Dz(i) = results.p4(3)+tan(Ry(i));
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Motion of the output beam with drx error
|
|
figure;
|
|
hold on;
|
|
plot(thetas, 1e9*Dy, '--', 'DisplayName', 'Dy');
|
|
plot(thetas, 1e9*(Dz+10e-3), '--', 'DisplayName', 'Dz');
|
|
plot(thetas, 1e9*Ry, 'DisplayName', 'Ry');
|
|
plot(thetas, 1e9*Rz, 'DisplayName', 'Rz');
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Offset [m/rad] Tilt [rad/rad]')
|
|
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
|
xlim([0, 85]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/motion_beam_drx_error.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:motion_beam_drx_error
|
|
#+caption: Motion of the output beam with drx error
|
|
#+RESULTS:
|
|
[[file:figs/motion_beam_drx_error.png]]
|
|
|
|
** Effect of an error in crystal's y parallelism
|
|
<<sec:ray_tracing_ry>>
|
|
|
|
The effect of an error in =ry= crystal parallelism on the output beam is visually shown in Figure [[fig:ray_tracing_error_dry_overview]] for three bragg angles (5, 55 and 85 degrees).
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Visual Effect of an error in dry
|
|
figure;
|
|
hold on;
|
|
for theta = [5, 55, 85]
|
|
results = getBeamPath(theta*pi/180, 'dry', -1*pi/180);
|
|
set(gca,'ColorOrderIndex',1)
|
|
plotBeamPath(results);
|
|
plotCrystals(results);
|
|
end
|
|
hold off;
|
|
view(0,0)
|
|
axis equal
|
|
xlim([-10, 15])
|
|
zlim([-4, 2])
|
|
grid off;
|
|
xlabel('X [cm]')
|
|
ylabel('Y [cm]')
|
|
zlabel('Z [cm]')
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/ray_tracing_error_dry_overview.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:ray_tracing_error_dry_overview
|
|
#+caption: Visual Effect of an error in =dry= (1 degree). Side view.
|
|
#+RESULTS:
|
|
[[file:figs/ray_tracing_error_dry_overview.png]]
|
|
|
|
The effect of =dry= as a function of the Bragg angle on the output beam pose is computed and shown in Figure [[fig:motion_beam_dry_error]].
|
|
It is clear that this induces a rotation of the output beam in the =y= direction equals to 2 times =dry=:
|
|
\begin{equation}
|
|
\boxed{r_{b,z} = 2 r_z}
|
|
\end{equation}
|
|
|
|
It also induces a small vertical motion of the beam (at the $x=0$ location) which is simply due to the fact that the $x$ coordinate of the impact point on the second crystal changes with the Bragg angle.
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Effect of dry
|
|
thetas = 1:1:85;
|
|
Dy = zeros(length(thetas), 1);
|
|
Dz = zeros(length(thetas), 1);
|
|
Ry = zeros(length(thetas), 1);
|
|
Rz = zeros(length(thetas), 1);
|
|
for i = 1:length(thetas)
|
|
results = getBeamPath(thetas(i)*pi/180, 'dry', 1e-9);
|
|
Ry(i) = atan2(results.s3(3), results.s3(1));
|
|
Rz(i) = atan2(results.s3(2), results.s3(1));
|
|
Dy(i) = results.p4(2)-tan(Rz(i));
|
|
Dz(i) = results.p4(3)-tan(Ry(i));
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Motion of the output beam with dry error
|
|
figure;
|
|
hold on;
|
|
plot(thetas, 1e9*Dy, '--', 'DisplayName', 'Dy');
|
|
plot(thetas, 1e9*(Dz+10e-3), '--', 'DisplayName', 'Dz');
|
|
plot(thetas, 1e9*Ry, 'DisplayName', 'Ry');
|
|
plot(thetas, 1e9*Rz, 'DisplayName', 'Rz');
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Offset [m/rad] Tilt [rad/rad]')
|
|
legend('location', 'east', 'FontSize', 8, 'NumColumns', 2);
|
|
xlim([0, 85]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/motion_beam_dry_error.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:motion_beam_dry_error
|
|
#+caption: Motion of the output beam with dry error
|
|
#+RESULTS:
|
|
[[file:figs/motion_beam_dry_error.png]]
|
|
|
|
** Summary
|
|
|
|
Effects of crystal's pose errors on the output beam are summarized in Table [[tab:crystal_pose_beam_pose]].
|
|
Note that the three pose errors are well decoupled regarding their effects on the output beam.
|
|
Also note that the effect of an error in crystal's distance does not depend on the Bragg angle.
|
|
|
|
#+name: tab:crystal_pose_beam_pose
|
|
#+caption: Summary of the effects of the errors in second crystal's pose on the output beam
|
|
#+attr_latex: :environment tabularx :width 0.65\linewidth :align X|ccc
|
|
#+attr_latex: :center t :booktabs t
|
|
| *Beam Motion* | *Crystal* $d_z$ | *Crystal* $r_x$ | *Crystal* $r_y$ |
|
|
|---------------+--------------------------------+--------------------------------------+--------------------|
|
|
| $d_{b,y}$ | 0 | $\approx 0$ | 0 |
|
|
| $d_{b,z}$ | $\boxed{d_{z} 2 \cos(\theta)}$ | 0 | $\approx 0$ |
|
|
| $r_{b,y}$ | 0 | 0 | $\boxed{2 r_{y}}$ |
|
|
| $r_{b,z}$ | 0 | $\boxed{- r_x 2 \sin(\theta)}$ | 0 |
|
|
|
|
** "Channel cut" Scan
|
|
A "channel cut" scan is a Bragg scan where the distance between the crystals is fixed.
|
|
|
|
This is visually shown in Figure [[fig:ray_tracing_channel_cut]] where it is clear that the output beam experiences some vertical motion.
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Visual Effect of a channel cut scan
|
|
figure;
|
|
hold on;
|
|
for theta = [30, 40, 50]
|
|
results = getBeamPath(theta*pi/180, 'dz', 10e-3/(2*cos(pi/180*theta))-10e-3/(2*cos(pi/180*theta_fixed)));
|
|
set(gca,'ColorOrderIndex',1)
|
|
plotBeamPath(results);
|
|
plotCrystals(results);
|
|
end
|
|
hold off;
|
|
view(0,0)
|
|
axis equal
|
|
xlim([-10, 15])
|
|
zlim([-4, 2])
|
|
grid off;
|
|
xlabel('X [cm]')
|
|
ylabel('Y [cm]')
|
|
zlabel('Z [cm]')
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/ray_tracing_channel_cut.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:ray_tracing_channel_cut
|
|
#+caption: Visual Effect of a channel cut scan
|
|
#+RESULTS:
|
|
[[file:figs/ray_tracing_channel_cut.png]]
|
|
|
|
The $z$ offset of the beam for several channel cut scans are shown in Figure [[fig:channel_cut_scan]].
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Computation of Z motion of the beam during "channel cut" scans
|
|
thetas = 5:1:84;
|
|
Dz = zeros(length(thetas), 1);
|
|
|
|
for i = 1:length(thetas)
|
|
results = getBeamPath(thetas(i)*pi/180, 'dz', 10e-3/(2*cos(pi/180*thetas(i)))-10e-3/(2*cos(pi/180*(10*fix((5+thetas(i))/10)))));
|
|
Dz(i) = results.p4(3);
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Dz motion of the beam during "channel cut" scans
|
|
figure;
|
|
hold on;
|
|
for i = 1:8
|
|
plot(thetas((i-1)*10+1:i*10), 1e3*(Dz((i-1)*10+1:i*10)+10e-3), '-', 'DisplayName', sprintf('$%i^o$: $%.0f\\,\\mu$m/deg', (10*fix((5+thetas((i-1)*10+5))/10)), 1e6*(Dz((i-1)*10+6)-Dz((i-1)*10+5))));
|
|
end
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Dz Offset [mm]')
|
|
xlim([0, 90]); ylim([-4, 4]);
|
|
xticks([0:10:90]);
|
|
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/channel_cut_scan.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:channel_cut_scan
|
|
#+caption: Z motion of the beam during "channel cut" scans
|
|
#+RESULTS:
|
|
[[file:figs/channel_cut_scan.png]]
|
|
|
|
* Determining relative pose between the crystals using the X-ray
|
|
** Introduction :ignore:
|
|
As Interferometers are only measuring /relative/ displacement, it is mandatory to initialize them correctly.
|
|
|
|
They should be initialize in such a way that:
|
|
- $r_x = 0$ and $r_y = 0$ when the two crystallographic planes are parallel
|
|
- measured $d_z$ is equal to the distance between the crystallographic planes
|
|
|
|
In order to do that, an external metrology using the x-ray is used.
|
|
|
|
** Determine the $y$ parallelism - "Rocking Curve"
|
|
|
|
** Determine the $x$ parallelism - Bragg Scan
|
|
|
|
|
|
** Determine the $z$ distance - Bragg Scan
|
|
|
|
** Use Channel cut scan to determine crystal =dry= parallelism
|
|
|
|
Now, let's suppose we want to determine the =dry= angle between the crystals.
|
|
|
|
#+begin_src matlab
|
|
dry = 1e-6; % [rad]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Computation of Z motion of the beam during "channel cut" scans
|
|
thetas = 5:1:84;
|
|
Dz_expected = zeros(length(thetas), 1);
|
|
Dz_obtained = zeros(length(thetas), 1);
|
|
|
|
for i = 1:length(thetas)
|
|
results = getBeamPath(thetas(i)*pi/180, 'dz', 10e-3/(2*cos(pi/180*thetas(i)))-10e-3/(2*cos(pi/180*(10*fix((5+thetas(i))/10)))));
|
|
Dz_expected(i) = results.p4(3);
|
|
|
|
results = getBeamPath(thetas(i)*pi/180, 'dz', 10e-3/(2*cos(pi/180*thetas(i)))-10e-3/(2*cos(pi/180*(10*fix((5+thetas(i))/10)))), 'dry', dry);
|
|
Dz_obtained(i) = results.p4(3);
|
|
end
|
|
#+end_src
|
|
|
|
The error is
|
|
\begin{equation}
|
|
\boxed{d_{b,z} = -2 d_z \cos()}
|
|
\end{equation}
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Dz motion of the beam during "channel cut" scans
|
|
figure;
|
|
hold on;
|
|
plot(thetas, 1e6*(Dz_expected-Dz_obtained), '-');
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Dz Offset [$\mu$m]')
|
|
xlim([0, 90]);
|
|
xticks([0:10:90]);
|
|
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Dz motion of the beam during "channel cut" scans
|
|
figure;
|
|
hold on;
|
|
plot(thetas, 1e3*Dz_expected, '-');
|
|
plot(thetas, 1e3*Dz_obtained, '-');
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Dz Offset [mm]')
|
|
xlim([0, 90]);
|
|
xticks([0:10:90]);
|
|
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
|
#+end_src
|
|
|
|
** Effect of an error on Bragg angle
|
|
|
|
* Deformations of the Metrology Frame
|
|
<<sec:frame_deformations>>
|
|
** Introduction :ignore:
|
|
|
|
The transformation matrices are valid only if the metrology frames are solid bodies.
|
|
|
|
The metrology frame itself is experiencing some deformations due to the gravity.
|
|
When the bragg axis is scanned, the effect of gravity on the metrology frame is changing and this introduce some measurement errors.
|
|
|
|
This can be calibrated.
|
|
|
|
** New idea to calibrate deformations :noexport:
|
|
For each Bragg angle $\theta$:
|
|
- Correct parallelism (Dry) between crystals by maximizing the intensity.
|
|
Save =fjsry=.
|
|
- Correct for (Y,Z) position on the detector by modifying Drx and Dz.
|
|
Save =fjsrx= and =fjsz=.
|
|
|
|
** Measurement Setup
|
|
Two beam viewers:
|
|
- one close to the DCM to measure position of the beam
|
|
- one far away to the DCM to measure orientation of the beam
|
|
|
|
For each Bragg angle, the Fast Jacks are actuated to that the beam is at the center of the beam viewer.
|
|
Then, then position of the crystals as measured by the interferometers is recorded.
|
|
This position is the wanted position for a given Bragg angle.
|
|
|
|
#+name: fig:calibration_setup
|
|
#+caption: Schematic of the setup
|
|
[[file:figs/calibration_setup.png]]
|
|
|
|
Detector:
|
|
|
|
https://www.baslerweb.com/en/products/cameras/area-scan-cameras/ace/aca1920-40gc/
|
|
|
|
Pixel size depends on the magnification used (1x, 6x, 12x).
|
|
|
|
Pixel size of camera is 5.86 um x 5.86 um.
|
|
With typical magnification of 6x, pixel size is ~1.44um x 1.44um
|
|
|
|
Frame rate is: 42 fps
|
|
|
|
|
|
** Simulations
|
|
|
|
The deformations of the metrology frame and therefore the expected interferometric measurements can be computed as a function of the Bragg angle.
|
|
This may be done using FE software.
|
|
|
|
** Comparison
|
|
|
|
** 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
|
|
|
|
** Test
|
|
#+begin_src matlab
|
|
aa = importdata("correctInterf-vlm-220201.dat");
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
plot(aa.data(:,1), aa.data(:,24))
|
|
#+end_src
|
|
|
|
** Measured frame deformation
|
|
|
|
#+begin_src matlab
|
|
data = table2array(readtable('itf_polynom.csv','NumHeaderLines',1));
|
|
th = pi/180*data(:,1); % [rad]
|
|
fj = 0.030427 - 10.51e-3./(2*cos(th)); % [m]
|
|
rx2 = 1e-9*data(:,2); % [rad]
|
|
ry2 = 1e-9*data(:,3); % [rad]
|
|
rx1 = 1e-9*data(:,4); % [rad]
|
|
ry1 = 1e-9*data(:,5); % [rad]
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(180/pi*th, 1e6*detrend(-rx2, 1), '.')
|
|
% plot(180/pi*th, detrend(ry2, 1))
|
|
% plot(180/pi*th, detrend(rx1, 1))
|
|
% plot(180/pi*th, detrend(ry1, 1))
|
|
hold off;
|
|
xlabel('Bragg Angle [deg]');
|
|
ylabel('Measured $R_x$ [$\mu$rad]')
|
|
xlim([10, 75]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/calibration_drx_pres.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:calibration_drx_pres
|
|
#+caption: description
|
|
#+RESULTS:
|
|
[[file:figs/calibration_drx_pres.png]]
|
|
|
|
|
|
Strange that there is correlation between Rx and Ry.
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(108/pi*th, 1e9*detrend(rx1, 0), '-', 'DisplayName', '$Rx_1$')
|
|
plot(108/pi*th, 1e9*detrend(ry1, 0), '-', 'DisplayName', '$Ry_1$')
|
|
hold off;
|
|
xlabel('Bragg Angle [deg]'); ylabel('Angle Offset [nrad]');
|
|
legend()
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(1e3*fj, detrend(rx2, 1), 'DisplayName', '$Rx_1$')
|
|
plot(1e3*fj, detrend(ry2, 1), 'DisplayName', '$Ry_1$')
|
|
hold off;
|
|
xlabel('Fast Jack Displacement [mm]'); ylabel('Angle Offset [nrad]');
|
|
legend()
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Compute best polynomial fit
|
|
f_rx2 = fit(180/pi*th, 1e9*rx2, 'poly4');
|
|
f_ry2 = fit(180/pi*th, 1e9*ry2, 'poly4');
|
|
f_rx1 = fit(180/pi*th, 1e9*rx1, 'poly4');
|
|
f_ry1 = fit(180/pi*th, 1e9*ry1, 'poly4');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(180/pi*th, f_rx2(180/pi*th))
|
|
plot(180/pi*th, f_ry2(180/pi*th))
|
|
plot(180/pi*th, f_rx1(180/pi*th))
|
|
plot(180/pi*th, f_ry1(180/pi*th))
|
|
hold off;
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(th, f_rx2(th) - rx2)
|
|
plot(th, f_ry2(th) - ry2)
|
|
plot(th, f_rx1(th) - rx1)
|
|
plot(th, f_ry1(th) - ry1)
|
|
hold off;
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(th, f(th))
|
|
plot(th, rx2, '.')
|
|
#+end_src
|
|
|
|
** Test
|
|
#+begin_src matlab
|
|
filename = "/home/thomas/mnt/data_id21/22Jan/blc13550/id21/test_xtal1_interf/test_xtal1_interf_0001/test_xtal1_interf_0001.h5";
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
data = struct();
|
|
|
|
data.xtal1_111_u = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM4/data'));
|
|
data.xtal1_111_m = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM5/data'));
|
|
data.xtal1_111_d = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM6/data'));
|
|
data.mframe_u = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM3/data'));
|
|
data.mframe_dh = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM4/data'));
|
|
data.mframe_dr = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM5/data'));
|
|
data.bragg = (pi/180)*double(h5read(filename, '/7.1/instrument/FPGA2_SSIM6/data'));
|
|
data.fj_pos = 0.030427 - 10.5e-3./(2*cos(data.bragg));
|
|
data.time = double(h5read(filename, '/7.1/instrument/time/data'));
|
|
data.rx = 1e-9*double(h5read(filename, '/7.1/instrument/xtal1_111_rx/data'));
|
|
data.ry = 1e-9*double(h5read(filename, '/7.1/instrument/xtal1_111_ry/data'));
|
|
data.z = 1e-9*double(h5read(filename, '/7.1/instrument/xtal1_111_z/data'));
|
|
data.drx = 1e-9*double(h5read(filename, '/7.1/instrument/xtal_111_drx_filter/data'));
|
|
data.dry = 1e-9*double(h5read(filename, '/7.1/instrument/xtal_111_dry_filter/data'));
|
|
data.dz = 1e-9*double(h5read(filename, '/7.1/instrument/xtal_111_dz_filter/data'));
|
|
data.xtal2_111_u = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM10/data'))+10.5e6./(2*cos(data.bragg));
|
|
data.xtal2_111_m = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM1/data'))+10.5e6./(2*cos(data.bragg));
|
|
data.xtal2_111_d = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM2/data'))+10.5e6./(2*cos(data.bragg));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Drifts of the metrology as a function of Bragg Angle
|
|
figure;
|
|
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
|
|
|
ax1 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.mframe_dh, 0))
|
|
plot(180/pi*data.bragg, detrend(data.mframe_u, 0))
|
|
plot(180/pi*data.bragg, detrend(data.mframe_dr, 0))
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Drift [nm]');
|
|
|
|
ax2 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.mframe_dh, 1))
|
|
plot(180/pi*data.bragg, detrend(data.mframe_u, 1))
|
|
plot(180/pi*data.bragg, detrend(data.mframe_dr, 1))
|
|
hold off;
|
|
xlabel('Bragg [deg]'); set(gca, 'YTickLabel',[]);
|
|
|
|
ax3 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.mframe_dh, 2), 'DisplayName', 'dh')
|
|
plot(180/pi*data.bragg, detrend(data.mframe_u, 2), 'DisplayName', 'u')
|
|
plot(180/pi*data.bragg, detrend(data.mframe_dr, 2), 'DisplayName', 'dr')
|
|
hold off;
|
|
xlabel('Bragg [deg]'); set(gca, 'YTickLabel',[]);
|
|
legend();
|
|
|
|
linkaxes([ax1,ax2,ax3], 'xy');
|
|
xlim([10, 70]); ylim([-50, 50]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Drifts of the first crystal as a function of Bragg Angle
|
|
figure;
|
|
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
|
|
|
ax1 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_u, 0))
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_m, 0))
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_d, 0))
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Drift [nm]');
|
|
|
|
ax2 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_u, 1))
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_m, 1))
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_d, 1))
|
|
hold off;
|
|
xlabel('Bragg [deg]'); set(gca, 'YTickLabel',[]);
|
|
|
|
ax3 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_u, 2), 'DisplayName', 'u')
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_m, 2), 'DisplayName', 'm')
|
|
plot(180/pi*data.bragg, detrend(data.xtal1_111_d, 2), 'DisplayName', 'd')
|
|
hold off;
|
|
xlabel('Bragg [deg]'); set(gca, 'YTickLabel',[]);
|
|
legend();
|
|
|
|
linkaxes([ax1,ax2,ax3], 'xy');
|
|
xlim([10, 70]); ylim([-1000, 1000]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Drifts of the second crystal as a function of Bragg Angle
|
|
figure;
|
|
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
|
|
|
ax1 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_u, 0))
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_m, 0))
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_d, 0))
|
|
hold off;
|
|
xlabel('Bragg [deg]'); ylabel('Drift [nm]')
|
|
|
|
ax2 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_u, 1))
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_m, 1))
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_d, 1))
|
|
hold off;
|
|
xlabel('Bragg [deg]'); set(gca, 'YTickLabel',[]);
|
|
|
|
ax3 = nexttile();
|
|
hold on;
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_u, 2))
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_m, 2))
|
|
plot(180/pi*data.bragg, detrend(data.xtal2_111_d, 2))
|
|
hold off;
|
|
xlabel('Bragg [deg]'); set(gca, 'YTickLabel',[]);
|
|
|
|
linkaxes([ax1,ax2,ax3], 'xy');
|
|
xlim([10, 70]); ylim([-1000, 1000]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/drifts_xtal2_detrend.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:drifts_xtal2_detrend
|
|
#+caption: Drifts of the second crystal as a function of Bragg Angle
|
|
#+RESULTS:
|
|
[[file:figs/drifts_xtal2_detrend.png]]
|
|
|
|
#+begin_src matlab :exports none :results none
|
|
%% Drifts of the second crystal as a function of Bragg Angle
|
|
figure;
|
|
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
|
|
|
ax1 = nexttile();
|
|
hold on;
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_u, 0))
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_m, 0))
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_d, 0))
|
|
hold off;
|
|
xlabel('FJ position [mm]'); ylabel('Drift [nrad]')
|
|
|
|
ax2 = nexttile();
|
|
hold on;
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_u, 1))
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_m, 1))
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_d, 1))
|
|
hold off;
|
|
xlabel('FJ position [mm]'); set(gca, 'YTickLabel',[]);
|
|
|
|
ax3 = nexttile();
|
|
hold on;
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_u, 2))
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_m, 2))
|
|
plot(1e3*data.dz, detrend(data.xtal2_111_d, 2))
|
|
hold off;
|
|
xlabel('FJ position [mm]'); set(gca, 'YTickLabel',[]);
|
|
|
|
linkaxes([ax1,ax2,ax3], 'xy');
|
|
% xlim([10, 40]); ylim([-1000, 1000]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(108/pi*data.bragg, data.drx)
|
|
plot(108/pi*data.bragg, data.dry)
|
|
hold off;
|
|
#+end_src
|
|
|
|
** Repeatability of frame deformation
|
|
#+begin_src matlab
|
|
filename = "/home/thomas/mnt/data_id21/22Jan/blc13550/id21/test_xtal1_interf/test_xtal1_interf_0001/test_xtal1_interf_0001.h5";
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
data_1 = struct();
|
|
data_1.time = double(h5read(filename, '/7.1/instrument/time/data'));
|
|
data_1.bragg = (pi/180)*double(h5read(filename, '/7.1/instrument/FPGA2_SSIM6/data'));
|
|
data_1.fj_pos = 0.030427 - 10.5e-3./(2*cos(data_1.bragg));
|
|
data_1.xtal1_111_u = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM4/data'));
|
|
data_1.xtal1_111_m = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM5/data'));
|
|
data_1.xtal1_111_d = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM6/data'));
|
|
data_1.xtal2_111_u = double(h5read(filename, '/7.1/instrument/FPGA1_SSIM10/data'))+10.5e6./(2*cos(data_1.bragg));
|
|
data_1.xtal2_111_m = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM1/data'))+10.5e6./(2*cos(data_1.bragg));
|
|
data_1.xtal2_111_d = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM2/data'))+10.5e6./(2*cos(data_1.bragg));
|
|
data_1.mframe_u = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM3/data'));
|
|
data_1.mframe_dh = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM4/data'));
|
|
data_1.mframe_dr = double(h5read(filename, '/7.1/instrument/FPGA2_SSIM5/data'));
|
|
data_1.drx = 1e-9*double(h5read(filename, '/7.1/instrument/xtal_111_drx_filter/data'));
|
|
data_1.dry = 1e-9*double(h5read(filename, '/7.1/instrument/xtal_111_dry_filter/data'));
|
|
data_1.dz = 1e-9*double(h5read(filename, '/7.1/instrument/xtal_111_dz_filter/data'));
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
data_2 = struct();
|
|
data_2.time = double(h5read(filename, '/6.1/instrument/time/data'));
|
|
data_2.bragg = (pi/180)*double(h5read(filename, '/6.1/instrument/FPGA2_SSIM6/data'));
|
|
data_2.fj_pos = 0.030427 - 10.5e-3./(2*cos(data_2.bragg));
|
|
data_2.xtal1_111_u = double(h5read(filename, '/6.1/instrument/FPGA1_SSIM4/data'));
|
|
data_2.xtal1_111_m = double(h5read(filename, '/6.1/instrument/FPGA1_SSIM5/data'));
|
|
data_2.xtal1_111_d = double(h5read(filename, '/6.1/instrument/FPGA1_SSIM6/data'));
|
|
data_2.xtal2_111_u = double(h5read(filename, '/6.1/instrument/FPGA1_SSIM10/data'))+10.5e6./(2*cos(data_2.bragg));
|
|
data_2.xtal2_111_m = double(h5read(filename, '/6.1/instrument/FPGA2_SSIM1/data'))+10.5e6./(2*cos(data_2.bragg));
|
|
data_2.xtal2_111_d = double(h5read(filename, '/6.1/instrument/FPGA2_SSIM2/data'))+10.5e6./(2*cos(data_2.bragg));
|
|
data_2.mframe_u = double(h5read(filename, '/6.1/instrument/FPGA2_SSIM3/data'));
|
|
data_2.mframe_dh = double(h5read(filename, '/6.1/instrument/FPGA2_SSIM4/data'));
|
|
data_2.mframe_dr = double(h5read(filename, '/6.1/instrument/FPGA2_SSIM5/data'));
|
|
data_2.drx = 1e-9*double(h5read(filename, '/6.1/instrument/xtal_111_drx_filter/data'));
|
|
data_2.dry = 1e-9*double(h5read(filename, '/6.1/instrument/xtal_111_dry_filter/data'));
|
|
data_2.dz = 1e-9*double(h5read(filename, '/6.1/instrument/xtal_111_dz_filter/data'));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(180/pi*data_1.bragg, data_1.mframe_dh)
|
|
plot(180/pi*data_2.bragg, data_2.mframe_dh)
|
|
hold off;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(1e3*data_1.fj_pos, data_1.xtal1_111_u)
|
|
plot(1e3*data_2.fj_pos, data_2.xtal1_111_u)
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(data_1.bragg, data_1.mframe_u)
|
|
plot(data_2.bragg, data_2.mframe_u)
|
|
#+end_src
|
|
|
|
* Attocube - Periodic Non-Linearity
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/dcm_attocube_lut.m
|
|
:END:
|
|
<<sec:dcm_attocube_lut>>
|
|
|
|
** Introduction :ignore:
|
|
|
|
Interferometers have some periodic nonlinearity [cite:@thurner15_fiber_based_distan_sensin_inter].
|
|
The period is a fraction of the wavelength (usually $\lambda/2$) and can be due to polarization mixing, non perfect alignment of the optical components and unwanted reflected beams cite:ducourtieux18_towar_high_precis_posit_contr,thurner15_fiber_based_distan_sensin_inter.
|
|
The amplitude of the nonlinearity can vary from a fraction of a nanometer to tens of nanometers.
|
|
|
|
In the DCM case, when using Attocube interferometers, the period non-linearity are in the order of several nanometers with a period of $765\,nm$.
|
|
This is inducing some positioning errors which are too high.
|
|
|
|
In order to overcome this issue, the periodic non-linearity of the interferometers have to be calibrated.
|
|
To do so, a displacement is imposed and measured both by the interferometers and by another metrology system which does not have this nonlinearity.
|
|
By comparing the two measured displacements, the nonlinearity can be calibration.
|
|
This process is performed over several periods in order to characterize the error over the full stroke.
|
|
|
|
** 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
|
|
|
|
** Measurement Setup
|
|
The metrology that will be compared with the interferometers are the strain gauges incorporated in the PI piezoelectric stacks.
|
|
|
|
It is here supposed that the measured displacement by the strain gauges are converted to the displacement at the interferometer locations.
|
|
It is also supposed that we are at a certain Bragg angle, and that the stepper motors are not moving: only the piezoelectric actuators are used.
|
|
|
|
#+begin_note
|
|
Note that the strain gauges are measuring the relative displacement of the piezoelectric stacks while the interferometers are measuring the relative motion between the second crystals and the metrology frame.
|
|
|
|
Only the interferometers measuring the second crystal motion can be calibrated here.
|
|
|
|
As any deformations of the metrology frame of deformation of the crystal's support can degrade the quality of the calibration, it is better to perform this calibration without any bragg angle motion.
|
|
#+end_note
|
|
|
|
The setup is schematically with the block diagram in Figure [[fig:block_diagram_lut_attocube]].
|
|
|
|
The signals are:
|
|
- $u$: Reference Signal sent to the PI controller (position where we wish to three stacks to be).
|
|
The PI controller takes care or controlling to position as measured by the strain gauges such that it is close to the reference position.
|
|
- $d$: Disturbances affecting the position of the crystals
|
|
- $y$: Displacement of the crystal as measured by one interferometer
|
|
- $y_g$: Measurement of the motion in the frame of the interferometer by the strain gauge with some noise $n_g$
|
|
- $y_a$: Measurement of the crystal motion by the interferometer with some noise $n_a$
|
|
|
|
#+begin_src latex :file block_diagram_lut_attocube.pdf
|
|
\definecolor{myblue}{rgb}{0, 0.447, 0.741}
|
|
\definecolor{myred}{rgb}{0.8500, 0.325, 0.098}
|
|
|
|
\begin{tikzpicture}
|
|
\node[block] (G) at (0,0){$G(s)$};
|
|
\node[block, align=center, right=1 of G] (non_linearity) {Periodic\\Non-linearity};
|
|
\node[addb, right=1 of non_linearity] (addna) {};
|
|
\node[addb, below=1.8 of addna] (addnsg) {};
|
|
|
|
\draw[->] ($(G.west) + (-1.0, 0)$) node[above right]{$u$} -- (G.west);
|
|
\draw[->] ($(G.north) + (0, 1.0)$) node[below right]{$d$} -- (G.north);
|
|
\draw[->] (G.east) -- (non_linearity.west);
|
|
\draw[->] (non_linearity.east) -- (addna.west);
|
|
\draw[->] (addna.east) -- ++(1.2, 0) node[above left]{$y_a$};
|
|
\draw[->] ($(addna.north) + (0, 1.0)$) node[below right](na){$n_a$} -- (addna.north);
|
|
\draw[->] ($(G.east) + (0.4, 0)$)node[branch]{} node[above]{$y$} |- (addnsg.west);
|
|
\draw[->] (addnsg.east) -- ++(1.2, 0) node[above left]{$y_g$};
|
|
\draw[->] ($(addnsg.north) + (0, 1.0)$) node[below right](nsg){$n_{g}$} -- (addnsg.north);
|
|
|
|
\begin{scope}[on background layer]
|
|
\node[fit={(non_linearity.south west) (na.north east)}, fill=myblue!20!white, draw, inner sep=6pt] (attocube) {};
|
|
\node[fit={(non_linearity.west|-addnsg.south) (nsg.north east)}, fill=myred!20!white, draw, inner sep=6pt] (straingauge) {};
|
|
\node[below right] at (attocube.north west) {Attocube};
|
|
\node[below right] at (straingauge.north west) {Strain Gauge};
|
|
\end{scope}
|
|
\end{tikzpicture}
|
|
#+end_src
|
|
|
|
#+name: fig:block_diagram_lut_attocube
|
|
#+caption: Block Diagram schematic of the setup used to measure the periodic non-linearity of the Attocube
|
|
#+RESULTS:
|
|
[[file:figs/block_diagram_lut_attocube.png]]
|
|
|
|
The problem is to estimate the periodic non-linearity of the Attocube from the imperfect measurements $y_a$ and $y_g$.
|
|
|
|
** Choice of the reference signal
|
|
|
|
The main specifications for the reference signal are;
|
|
- sweep several periods (i.e. several micrometers)
|
|
- stay in the linear region of the strain gauge
|
|
- no excitation of mechanical modes (i.e. the frequency content of the signal should be at low frequency)
|
|
- no phase shift due to limited bandwidth of both the interferometers and the strain gauge
|
|
- the full process should be quite fast
|
|
|
|
The travel range of the piezoelectric stacks is 15 micrometers, the resolution of the strain gauges is 0.3nm and the maximum non-linearity is 0.15%.
|
|
If one non-linear period is swept (765nm), the maximum estimation error of the strain gauge is around 1nm.
|
|
|
|
Based on the above discussion, one suitable excitation signal is a sinusoidal sweep with a frequency of 10Hz.
|
|
|
|
** Repeatability of the non-linearity
|
|
|
|
Instead of calibrating the non-linear errors of the interferometers over the full fast jack stroke (25mm), one can only calibrate the errors of one period.
|
|
|
|
For that, we need to make sure that the errors are repeatable from one period to the other and also the period should be very precisely estimated (i.e. the wavelength of the laser).
|
|
|
|
Also, the laser wavelength should be very stable (specified at 50ppb).
|
|
|
|
One way to precisely estimate the laser wavelength is to estimate the non linear errors of the interferometer at an initial position, and then to estimate the non linear errors at a large offset, say 10mm.
|
|
|
|
** Simulation
|
|
Suppose we have a first approximation of the non-linear period.
|
|
#+begin_src matlab
|
|
period_est = 765e-9; % Estimated period [m]
|
|
#+end_src
|
|
|
|
And suppose the real period of the non-linear errors is a little bit above (by 0.02nm):
|
|
#+begin_src matlab
|
|
period_err = 0.02e-9; % Error on the period estimation [m]
|
|
period_nl = period_est + period_err; % Period of the non-linear errors [m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
displacement_step = 1e-8;
|
|
stroke = 0:displacement_step:25e-3; % Measured Stroke [m]
|
|
|
|
nl_errors = 5e-9*sin(2*pi*stroke/period_nl) + ...
|
|
3e-9*sin(2*pi*2*stroke/period_nl) - ...
|
|
1e-9*sin(2*pi*3*stroke/period_nl); % Measured non-linear errors [m]
|
|
|
|
est_errors = 5e-9*sin(2*pi*stroke/period_est) + ...
|
|
3e-9*sin(2*pi*2*stroke/period_est) - ...
|
|
1e-9*sin(2*pi*3*stroke/period_est); % Estimated non-linear errors [m]
|
|
#+end_src
|
|
|
|
The non-linear errors are first estimated at the beginning of the stroke (Figure [[fig:non_linear_errors_start_stroke]]).
|
|
#+begin_src matlab :exports none
|
|
%% Measured errors at the begining of the stroke
|
|
figure;
|
|
plot(1e9*stroke, 1e9*nl_errors);
|
|
xlabel('Displacement [nm]'); ylabel('Non linearity [nm]');
|
|
xlim([0, 1e9*period_nl]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/non_linear_errors_start_stroke.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:non_linear_errors_start_stroke
|
|
#+caption: Estimation of the non-linear errors at the beginning of the stroke
|
|
#+RESULTS:
|
|
[[file:figs/non_linear_errors_start_stroke.png]]
|
|
|
|
From this only measurement, it is not possible to estimate with great accuracy the period of the error.
|
|
To do so, the same measurement is performed with a stroke of several millimeters (Figure [[fig:non_linear_errors_middle_stroke]]).
|
|
|
|
It can be seen that there is an offset between the estimated and the measured errors.
|
|
This is due to a mismatch between the estimated period and the true period of the error.
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Comparison of the estimated error and measured error
|
|
figure;
|
|
hold on;
|
|
plot(1e3*stroke, 1e9*nl_errors, ...
|
|
'DisplayName', 'Measured Errors');
|
|
plot(1e3*stroke, 1e9*est_errors, '--', ...
|
|
'DisplayName', 'Estimated Errors');
|
|
hold off;
|
|
xlabel('Displacement [mm]'); ylabel('Non linearity [nm]');
|
|
xlim([1e3*(5e-3-period_nl/2), 1e3*(5e-3+period_nl/2)]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/non_linear_errors_middle_stroke.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:non_linear_errors_middle_stroke
|
|
#+caption: Estimated non-linear errors at a latter position
|
|
#+RESULTS:
|
|
[[file:figs/non_linear_errors_middle_stroke.png]]
|
|
|
|
Suppose the non-linear error is characterized by a periodic function $\mathcal{E}$, to simplify let's take a sinusoidal function (this can be generalized by taking the fourier transform of the function):
|
|
\begin{equation}
|
|
\mathcal{E}(x) = \sin\left(\frac{x}{\lambda}\right)
|
|
\end{equation}
|
|
with $x$ the displacement and $\lambda$ the period of the error.
|
|
|
|
The measured error at $x_0$ is then:
|
|
\begin{equation}
|
|
\mathcal{E}_m(x_0) = \sin\left( \frac{x_0}{\lambda} \right)
|
|
\end{equation}
|
|
And the estimated one is:
|
|
\begin{equation}
|
|
\mathcal{E}_e(x_0) = \sin \left( \frac{x_0}{\lambda_{\text{est}}} \right)
|
|
\end{equation}
|
|
with $\lambda_{\text{est}}$ the estimated error's period.
|
|
|
|
From Figure [[fig:non_linear_errors_middle_stroke]], we can see that there is an offset between the two curves.
|
|
Let's call this offset $\epsilon_x$, we then have:
|
|
\begin{equation}
|
|
\mathcal{E}_m(x_0) = \mathcal{E}_e(x_0 + \epsilon_x)
|
|
\end{equation}
|
|
|
|
Which gives us:
|
|
\begin{equation}
|
|
\sin\left( \frac{x_0}{\lambda} \right) = \sin \left( \frac{x_0 + \epsilon_x}{\lambda_{\text{est}}} \right)
|
|
\end{equation}
|
|
|
|
Finally:
|
|
\begin{equation}
|
|
\boxed{\lambda = \lambda_{\text{est}} \frac{x_0}{x_0 + \epsilon_x}}
|
|
\end{equation}
|
|
|
|
The estimated delay is computed:
|
|
#+begin_src matlab
|
|
%% Estimation of the offset between the estimated and measured errors
|
|
i_period = stroke > 5e-3-period_nl/2 & stroke < 5e-3+period_nl/2;
|
|
epsilon_x = finddelay(nl_errors(i_period), est_errors(i_period)) % [m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
ans = sprintf('Estimated delay x0 is %.0f [nm]', 1e9*displacement_step*epsilon_x)
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: Estimated delay x0 is -120 [nm]
|
|
|
|
And the period $\lambda$ can be estimated:
|
|
#+begin_src matlab
|
|
%% Computation of the period [m]
|
|
period_fin = period_est * (5e-3)/(5e-3 + d_offset); % Estimated period after measurement [m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
ans = sprintf('The estimated period is %.3f [nm]', 1e9*period_fin)
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: The estimated period is 765.020 [nm]
|
|
|
|
And the results confirms that this method is working on paper.
|
|
|
|
When doing this computation, we suppose that there are *at most* one half period of offset between the estimated and the measured non-linear (to not have any ambiguity whether the estimated period is too large or too small).
|
|
Mathematically this means that the displacement $x_0$ should be smaller than:
|
|
\begin{equation}
|
|
x_0 < \frac{1}{2} \cdot \lambda \cdot \frac{\lambda}{\epsilon_\lambda}
|
|
\end{equation}
|
|
With $\epsilon_\lambda$ the absolute estimation error of the period in meters.
|
|
|
|
For instance, if we estimate the error on the period to be less than 0.1nm, the maximum displacement is:
|
|
#+begin_src matlab
|
|
%% Estimated maximum stroke [m]
|
|
max_x0 = 0.5 * 765e-9 * (765e-9)/(0.1e-9);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
ans = sprintf('The maximum stroke is %.1f [mm]', 1e3*max_x0)
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: The maximum stroke is 2.9 [mm]
|
|
|
|
** Measurements
|
|
|
|
We have some constrains on the way the motion is imposed and measured:
|
|
- We want the frequency content of the imposed motion to be at low frequency in order not to induce vibrations of the structure.
|
|
We have to make sure the forces applied by the piezoelectric actuator only moves the crystal and not the fast jack below.
|
|
Therefore, we have to move much slower than the first resonance frequency in the system.
|
|
- As both $y_a$ and $y_g$ should have rather small noise, we have to filter them with low pass filters.
|
|
The cut-off frequency of the low pass filter should be high as compared to the motion (to not induce any distortion) but still reducing sufficiently the noise.
|
|
Let's say we want the noise to be less than 1nm ($6 \sigma$).
|
|
|
|
Suppose we have the power spectral density (PSD) of both $n_a$ and $n_g$.
|
|
|
|
- [ ] Take the PSD of the Attocube
|
|
- [ ] Take the PSD of the strain gauge
|
|
- [ ] Using 2nd order low pass filter, estimate the required low pass filter cut-off frequency to have sufficiently low noise
|
|
|
|
* 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/src/'); % Path for functions
|
|
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
|
|
addpath('./src/'); % Path for functions
|
|
#+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
|
|
|
|
** Intersection between Ray and Plane
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/src/getPlaneReflection.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:getPlaneReflection>>
|
|
|
|
#+begin_src matlab
|
|
function [p_reflect, s_reflect] = getPlaneReflection(p_in, s_in, p_plane, n_plane)
|
|
% getPlaneReflection -
|
|
%
|
|
% Syntax: [p_reflect, s_reflect] = getPlaneReflection(p_in, s_in, p_plane, n_plane)
|
|
%
|
|
% Inputs:
|
|
% - p_in, s_in, p_plane, n_plane -
|
|
%
|
|
% Outputs:
|
|
% - p_reflect, s_reflect -
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
p_reflect = p_in + s_in*dot(p_plane - p_in, n_plane)/dot(s_in, n_plane);
|
|
s_reflect = s_in-2*n_plane*dot(s_in, n_plane);
|
|
s_reflect = s_reflect./norm(s_reflect);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
end
|
|
#+end_src
|
|
|
|
** Get Beam Path
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/src/getBeamPath.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:getBeamPath>>
|
|
|
|
#+begin_src matlab
|
|
function [results] = getBeamPath(theta, args)
|
|
% getBeamPath -
|
|
%
|
|
% Syntax: [in_data] = getBeamPath(drx, dry, dz, theta, )
|
|
%
|
|
% Inputs:
|
|
% - drx, dry, dz, theta, -
|
|
%
|
|
% Outputs:
|
|
% - in_data -
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
theta
|
|
args.drx (1,1) double {mustBeNumeric} = 0 % [rad]
|
|
args.dry (1,1) double {mustBeNumeric} = 0 % [rad]
|
|
args.dz (1,1) double {mustBeNumeric} = 0 % [m]
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
% Rotation matrix for drx
|
|
udrx = [cos(theta), 0, -sin(theta)];
|
|
Rdrx = cos(args.drx)*eye(3)+sin(args.drx)*[0, -udrx(3), udrx(2); udrx(3), 0, -udrx(1); -udrx(2), udrx(1), 0] + (1-cos(args.drx))*(udrx'*udrx);
|
|
|
|
% Rotation matrix for dry
|
|
Rdry = [ cos(args.dry), 0, sin(args.dry); ...
|
|
0, 1, 0; ...
|
|
-sin(args.dry), 0, cos(args.dry)];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Input Beam
|
|
p1 = [-0.1, 0, 0]; % [m]
|
|
s1 = [ 1, 0, 0];
|
|
|
|
%% Primary Mirror
|
|
pp = [0, 0, 0]; % [m]
|
|
np = [cos(pi/2-theta), 0, sin(pi/2-theta)];
|
|
|
|
%% Reflected beam
|
|
[p2, s2] = getPlaneReflection(p1, s1, pp, np);
|
|
|
|
%% Secondary Mirror
|
|
ps = pp ...
|
|
+ 0.032*[cos(theta), 0, -sin(theta)] ... % x offset (does not matter a lot)
|
|
- np*10e-3./(2*cos(theta)) ... % Theoretical offset
|
|
+ np*args.dz; % Add error in distance
|
|
|
|
ns = [Rdry*Rdrx*[cos(pi/2-theta), 0, sin(pi/2-theta)]']'; % Normal
|
|
|
|
%% Output Beam
|
|
[p3, s3] = getPlaneReflection(p2, s2, ps, ns);
|
|
|
|
%% Detector
|
|
pd = [1, 0, 0]; % [m]
|
|
nd = [-1, 0, 0];
|
|
|
|
%% Get beam position on the decector
|
|
p4 = getPlaneReflection(p3, s3, pd, nd);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
results = struct();
|
|
% Beam position and orientations
|
|
results.p1 = p1;
|
|
results.s1 = s1;
|
|
results.p2 = p2;
|
|
results.s2 = s2;
|
|
results.p3 = p3;
|
|
results.s3 = s3;
|
|
results.p4 = p4;
|
|
% Mirrors/detector positions and orientations
|
|
results.pp = pp;
|
|
results.np = np;
|
|
results.ps = ps;
|
|
results.ns = ns;
|
|
results.pd = pd;
|
|
results.nd = nd;
|
|
#+end_src
|
|
|
|
** Plot Beam Path
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/src/plotBeamPath.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:plotBeamPath>>
|
|
|
|
#+begin_src matlab
|
|
function [] = plotBeamPath(results)
|
|
% plotBeamPath -
|
|
%
|
|
% Syntax: [in_data] = plotBeamPath(drx, dry, dz, theta, )
|
|
%
|
|
% Inputs:
|
|
% - drx, dry, dz, theta, -
|
|
%
|
|
% Outputs:
|
|
% - in_data -
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
plot3(100*[results.p1(1), results.p2(1)],100*[results.p1(2), results.p2(2)], 100*[results.p1(3), results.p2(3)], 'linewidth', 0.5)
|
|
plot3(100*[results.p2(1), results.p3(1)],100*[results.p2(2), results.p3(2)], 100*[results.p2(3), results.p3(3)], 'linewidth', 0.5)
|
|
plot3(100*[results.p3(1), results.p4(1)],100*[results.p3(2), results.p4(2)], 100*[results.p3(3), results.p4(3)], 'linewidth', 0.5)
|
|
#+end_src
|
|
|
|
|
|
** Plot Crystal
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/src/plotCrystals.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:plotCrystals>>
|
|
|
|
#+begin_src matlab
|
|
function [] = plotCrystals(results, args)
|
|
% plotCrystals -
|
|
%
|
|
% Syntax: [in_data] = plotCrystals(drx, dry, dz, theta, )
|
|
%
|
|
% Inputs:
|
|
% - drx, dry, dz, theta, -
|
|
%
|
|
% Outputs:
|
|
% - in_data -
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
results
|
|
args.color (3,1) double {mustBeNumeric} = [1;1;1]
|
|
args.alpha (1,1) double {mustBeNumeric} = 1
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
z = results.np;
|
|
y = [0,1,0];
|
|
x = cross(y,z);
|
|
xtal1_rectangle = [results.pp + 0.02/2*y + 0.035/2*x;
|
|
results.pp - 0.02/2*y + 0.035/2*x;
|
|
results.pp - 0.02/2*y - 0.035/2*x;
|
|
results.pp + 0.02/2*y - 0.035/2*x];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
patch(100*xtal1_rectangle(:,1), 100*xtal1_rectangle(:,2), 100*xtal1_rectangle(:,3), 'k-')
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
z = results.ns;
|
|
% y = [0,cos(drx),sin(drx)];
|
|
y = [0,1,0];
|
|
x = cross(y,z);
|
|
xtal2_rectangle = [results.ps + 0.02/2*y + 0.07/2*x;
|
|
results.ps - 0.02/2*y + 0.07/2*x;
|
|
results.ps - 0.02/2*y - 0.07/2*x;
|
|
results.ps + 0.02/2*y - 0.07/2*x];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
patch(100*xtal2_rectangle(:,1), 100*xtal2_rectangle(:,2), 100*xtal2_rectangle(:,3), 'k-')
|
|
#+end_src
|
|
|
|
* Bibliography
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
#+latex: \printbibliography[heading=none]
|
|
[[bibliography:dcm-metrology.bib]]
|