Add analysis of errors based on ray-tracing

This commit is contained in:
Thomas Dehaeze 2022-06-02 18:06:51 +02:00
parent f17ceca29d
commit f549fc5313
23 changed files with 1144 additions and 872 deletions

File diff suppressed because it is too large Load Diff

View File

@ -184,69 +184,11 @@ In this section, the impact of an error in the relative pose between the first a
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 and external metrology measuring the x-ray 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.
** 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
bragg = pi/180*linspace(5,75,100);
#+end_src
** Axial motion of second crystal
Let's consider the relation between the $[y, z]$ motion of the beam and the motion of the second crystal $[z^\prime, R_{y^\prime}, R_{x^\prime}]$.
#+name: fig:relation_dz_output_beam
#+caption: Relation between $d_{z^\prime}$ motion of the second crystal and vertical motion of the beam
[[file:figs/relation_dz_output_beam.png]]
\begin{equation}
d_z = d_{z^\prime} 2 \cos \theta
\end{equation}
#+begin_src matlab :exports none :results none
%% Relation between vertical motion of the second crystal and vertical motion of the output beam
figure;
hold on;
plot(180/pi*bragg, 2*cos(bragg))
xlabel('Bragg [deg]'); ylabel('Motion amplification');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/relation_vert_motion_crystal_beam.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:relation_vert_motion_crystal_beam
#+caption: Relation between vertical motion of the second crystal and vertical motion of the output beam
#+RESULTS:
[[file:figs/relation_vert_motion_crystal_beam.png]]
** Ry motion of second crystal
\begin{equation}
d_z = D_{\text{vlm}} d_{R_y^\prime}
\end{equation}
with $D_{\text{vlm}} \approx 10\,m$.
** Rx motion of second crystal
\begin{equation}
d_y = 2 D_{\text{vlm}} \sin \theta \cdot d_{R_x^\prime}
\end{equation}
* Ray Tracing
** Introduction :ignore:
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)
@ -280,271 +222,73 @@ d_y = 2 D_{\text{vlm}} \sin \theta \cdot d_{R_x^\prime}
| output beam | =x3,y3,z3= | =s3= |
| Dectector | =xd,yd,zd= | =nd= |
#+begin_src matlab
theta = 85*pi/180; % [rad]
#+end_src
- [ ] Add schematic
#+begin_src matlab
thetas = pi/180*[5:1:85];
#+end_src
Notations for the pose of the output beam: =d_b_y=, =d_b_z=, =r_b_y=, =r_b_z=.
#+begin_src matlab
yz = zeros(2, length(thetas));
#+end_src
$d_{b,y}, d_{b,z}, r_{b,y}, r_{b,z}$
#+begin_src matlab
for i = 1:length(thetas)
theta = thetas(i);
#+end_src
The xy position of the beam is taken in the $x=0$ plane.
#+begin_src matlab
%% Secondary crystal defaults
drx = 0; % [rad]
dry = 0; % [rad]
dz = 1e-9; % [m]
** Effect of an error in crystal's distance
<<sec:ray_tracing_dz>>
% Rotation matrix for drx
udrx = [cos(theta), 0, -sin(theta)];
Rdrx = cos(drx)*eye(3)+sin(drx)*[0, -udrx(3), udrx(2); udrx(3), 0, -udrx(1); -udrx(2), udrx(1), 0] + (1-cos(drx))*(udrx'*udrx);
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.
% Rotation matrix for dry
Rdry = [ cos(dry), 0, sin(dry); ...
0, 1, 0; ...
-sin(dry), 0, cos(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] = get_plane_reflection(p1, s1, pp, np);
%% Secondary Mirror
ps = pp ...
+ 0.07*[cos(theta), 0, -sin(theta)] ... % x offset (does not matter a lot)
- np*10e-3./(2*cos(theta)) ... % Theoretical offset
+ np*dz; % Add error in distance
ns = [Rdry*Rdrx*[cos(pi/2-theta), 0, sin(pi/2-theta)]']'; % Normal
%% Output Beam
[p3, s3] = get_plane_reflection(p2, s2, ps, ns);
%% Detector
pd = [1, 0, 0]; % [m]
nd = [-1, 0, 0];
%% Get beam position on the decector
p4 = get_plane_reflection(p3, s3, pd, nd);
yz(:,i) = p4(2:3);
end
#+end_src
#+begin_src matlab
figure;
hold on;
plot(180/pi*thetas, 1e9*(yz(2,:) + 10e-3));
xlabel('Bragg Angle [deg]'); ylabel('Z position [nm/m/nrad]');
#+end_src
#+begin_src matlab
figure;
hold on;
plot(180/pi*thetas, 1e9*yz(1,:));
xlabel('Bragg Angle [deg]'); ylabel('Y position [nm/m/nrad]');
#+end_src
#+begin_src matlab
%% Primary crystal plane
z = np;
y = [0,1,0];
x = cross(y,z);
xtal1_rectangle = [pp + 0.02*y + 0.07*x;
pp - 0.02*y + 0.07*x;
pp - 0.02*y - 0.07*x;
pp + 0.02*y - 0.07*x];
%% Secondary crystal plane
z = ns;
y = [0,cos(drx),sin(drx)];
x = cross(y,z);
xtal2_rectangle = [ps + 0.02*y + 0.07*x;
ps - 0.02*y + 0.07*x;
ps - 0.02*y - 0.07*x;
ps + 0.02*y - 0.07*x];
#+end_src
#+begin_src matlab
figure;
tiledlayout(2, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile();
hold on;
plot3([p1(1), p2(1)],[p1(2), p2(2)], [p1(3), p2(3)])
plot3([p2(1), p3(1)],[p2(2), p3(2)], [p2(3), p3(3)])
plot3([p3(1), p3(1)+0.3*s3(1)],[p3(2), p3(2)+0.3*s3(2)], [p3(3), p3(3)+0.3*s3(3)])
patch(xtal1_rectangle(:,1), xtal1_rectangle(:,2), xtal1_rectangle(:,3), 'k')
patch(xtal2_rectangle(:,1), xtal2_rectangle(:,2), xtal2_rectangle(:,3), 'k')
hold off;
view(0,0)
axis equal
xlim([-0.1, 0.15])
zlim([-0.02, 0.01])
grid off;
xlabel('X')
ylabel('Y')
zlabel('Z')
ax2 = nexttile();
hold on;
plot3([p1(1), p2(1)],[p1(2), p2(2)], [p1(3), p2(3)])
plot3([p2(1), p3(1)],[p2(2), p3(2)], [p2(3), p3(3)])
plot3([p3(1), p3(1)+0.3*s3(1)],[p3(2), p3(2)+0.3*s3(2)], [p3(3), p3(3)+0.3*s3(3)])
patch(xtal1_rectangle(:,1), xtal1_rectangle(:,2), xtal1_rectangle(:,3), 'k')
patch(xtal2_rectangle(:,1), xtal2_rectangle(:,2), xtal2_rectangle(:,3), 'k')
hold off;
view(0,90)
axis equal
xlim([-0.1, 0.15])
zlim([-0.02, 0.01])
grid off;
xlabel('X')
ylabel('Y')
zlabel('Z')
#+end_src
#+begin_src matlab
figure;
hold on;
plot3([p1(1), p2(1)],[p1(2), p2(2)], [p1(3), p2(3)])
plot3([p2(1), p3(1)],[p2(2), p3(2)], [p2(3), p3(3)])
plot3([p3(1), p3(1)+0.3*s3(1)],[p3(2), p3(2)+0.3*s3(2)], [p3(3), p3(3)+0.3*s3(3)])
surf(xtal1_x, xtal1_y, xtal1_z)
patch(xtal2_rectangle(:,1), xtal2_rectangle(:,2), xtal2_rectangle(:,3), 'k')
hold off;
view(0,0)
axis equal
xlim([-0.1, 0.15])
zlim([-0.02, 0.01])
grid off;
#+end_src
#+begin_src matlab
figure;
hold on;
plot3([p1(1), p2(1)],[p1(2), p2(2)], [p1(3), p2(3)])
plot3([p2(1), p3(1)],[p2(2), p3(2)], [p2(3), p3(3)])
plot3([p3(1), p3(1)+0.3*s3(1)],[p3(2), p3(2)+0.3*s3(2)], [p3(3), p3(3)+0.3*s3(3)])
surf(xtal1_x, xtal1_y, xtal1_z)
patch(xtal2_rectangle(:,1), xtal2_rectangle(:,2), xtal2_rectangle(:,3), 'k')
hold off;
view(90,90)
axis equal
xlim([-0.1, 0.15])
zlim([-0.02, 0.01])
grid off;
#+end_src
** Effect of =dry=
#+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);
Dy(i) = results.p4(2);
Dz(i) = results.p4(3);
Ry(i) = atan2(results.s3(3), results.s3(1));
Rz(i) = atan2(results.s3(2), results.s3(1));
end
#+end_src
Visually, it is clear that this induce a =z= offset of the output beam.
#+begin_src matlab :exports none :results none
%% Motion of the output beam with dry error
%% Visual Effect of an error in dz
figure;
hold on;
plot(thetas, 1e9*(Dz+10e-3), '--', 'DisplayName', 'Dz');
plot(thetas, 1e9*Dy, '--', 'DisplayName', 'Dy');
plot(thetas, 1e9*Rz, 'DisplayName', 'Rz');
plot(thetas, 1e9*Ry, 'DisplayName', 'Ry');
for theta = [5, 55, 85]
results = getBeamPath(theta*pi/180, 'dz', 1e-3);
set(gca,'ColorOrderIndex',1)
plotBeamPath(results);
plotCrystals(results);
end
hold off;
xlabel('Bragg [deg]'); ylabel('Offset [nm/m], Tilt [nrad]')
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
xlim([0, 85]);
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/motion_beam_dry_error.pdf', 'width', 'wide', 'height', 'normal');
exportFig('figs/ray_tracing_error_dz_overview.pdf', 'width', 'full', 'height', 'normal');
#+end_src
#+name: fig:motion_beam_dry_error
#+caption: Motion of the output beam with dry error
#+name: fig:ray_tracing_error_dz_overview
#+caption: Visual Effect of an error in =dz= (1mm). Side view.
#+RESULTS:
[[file:figs/motion_beam_dry_error.png]]
[[file:figs/ray_tracing_error_dz_overview.png]]
** Effect of =drx=
#+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);
Dy(i) = results.p4(2);
Dz(i) = results.p4(3);
Ry(i) = atan2(results.s3(3), results.s3(1));
Rz(i) = atan2(results.s3(2), results.s3(1));
end
#+end_src
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.
#+begin_src matlab :exports none :results none
%% Motion of the output beam with drx error
figure;
hold on;
plot(thetas, 1e9*(Dz+10e-3), '--', 'DisplayName', 'Dz');
plot(thetas, 1e9*Dy, '--', 'DisplayName', 'Dy');
plot(thetas, 1e9*Rz, 'DisplayName', 'Rz');
plot(thetas, 1e9*Ry, 'DisplayName', 'Ry');
hold off;
xlabel('Bragg [deg]'); ylabel('Offset [nm/m], Tilt [nrad]')
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
xlim([0, 85]);
#+end_src
This is indeed equal to:
\begin{equation}
\boxed{d_{b,z} = 2 d_z \cos \theta}
\end{equation}
#+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 =dz=
#+begin_src matlab :exports none
%% Effect of dz
thetas = 1:1:85;
Dy = zeros(length(thetas), 1);
Dz = zeros(length(thetas), 1);
Ry = zeros(length(thetas), 1);
Rz = zeros(length(thetas), 1);
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);
Dy(i) = results.p4(2);
Dz(i) = results.p4(3);
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
@ -552,12 +296,12 @@ end
%% Motion of the output beam with dZ error
figure;
hold on;
plot(thetas, 1e9*(Dz+10e-3), '--', 'DisplayName', 'Dz');
plot(thetas, 1e9*Dy, '--', 'DisplayName', 'Dy');
plot(thetas, 1e9*Rz, 'DisplayName', 'Rz');
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 [nm/m], Tilt [nrad]')
xlabel('Bragg [deg]'); ylabel('Offset [m/m] Tilt [rad/m]')
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
xlim([0, 85]);
#+end_src
@ -571,98 +315,338 @@ exportFig('figs/motion_beam_dz_error.pdf', 'width', 'wide', 'height', 'normal');
#+RESULTS:
[[file:figs/motion_beam_dz_error.png]]
** Test :noexport:
#+begin_src matlab
figure;
plot(thetas, 1e9*yz(:,1));
xlabel('Bragg [deg]'); ylabel('Y Displacement [nm/m/nrad]')
#+end_src
** Effect of an error in crystal's x parallelism
<<sec:ray_tracing_rx>>
#+begin_src matlab
figure;
plot(thetas, 1e9*yz(:,1));
xlabel('Bragg [deg]'); ylabel('Y Displacement [nm/m/nrad]')
#+end_src
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
%% Effect of dry
thetas = 1:1:85;
yz = zeros(length(thetas), 2);
for i = 1:length(thetas)
results = getBeamPath(thetas(i)*pi/180, 'dry', 1e-9);
yz(i,:) = results.p4(2:3);
end
#+end_src
#+begin_src matlab
figure;
plot(thetas, 1e9*(yz(:,2) + 10e-3));
xlabel('Bragg [deg]'); ylabel('Z Displacement [nm/m/nrad]')
#+end_src
#+begin_src matlab
%% Effect of dz
thetas = 1:1:85;
yz = zeros(length(thetas), 2);
for i = 1:length(thetas)
results = getBeamPath(thetas(i)*pi/180, 'dz', 1e-9);
yz(i,:) = results.p4(2:3);
end
#+end_src
#+begin_src matlab
figure;
plot(thetas, 1e9*(yz(:,2) + 10e-3));
xlabel('Bragg [deg]'); ylabel('Z Displacement [nm/m/nm]')
#+end_src
#+begin_src matlab
#+begin_src matlab :exports none :results none
%% Visual Effect of an error in drx
figure;
hold on;
for theta = 5:5:85
for theta = [5, 55, 85]
results = getBeamPath(theta*pi/180, 'drx', -1*pi/180);
set(gca,'ColorOrderIndex',1)
plotBeamPath(getBeamPath(theta*pi/180, 'dz', 1e-3))
end
hold off;
view(0,0)
axis equal
xlim([-0.1, 0.15])
zlim([-0.02, 0.01])
grid off;
#+end_src
#+begin_src matlab
figure;
hold on;
for theta = 5:5:85
set(gca,'ColorOrderIndex',1)
plotBeamPath(getBeamPath(theta*pi/180, 'dry', 1*pi/180))
end
hold off;
view(0,0)
axis equal
xlim([-0.1, 0.15])
zlim([-0.02, 0.01])
grid off;
#+end_src
#+begin_src matlab
figure;
hold on;
for theta = 5:5:85
set(gca,'ColorOrderIndex',1)
plotBeamPath(getBeamPath(theta*pi/180, 'drx', 1*pi/180))
plotBeamPath(results);
% plotCrystals(results);
end
hold off;
view(0,90)
axis equal
xlim([-0.1, 0.15])
zlim([-0.02, 0.01])
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 \cos \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:
@ -1396,16 +1380,16 @@ freqs = logspace(1, 3, 1000);
** Intersection between Ray and Plane
:PROPERTIES:
:header-args:matlab+: :tangle matlab/src/get_plane_reflection.m
:header-args:matlab+: :tangle matlab/src/getPlaneReflection.m
:header-args:matlab+: :comments none :mkdirp yes :eval no
:END:
<<sec:get_plane_reflection>>
<<sec:getPlaneReflection>>
#+begin_src matlab
function [p_reflect, s_reflect] = get_plane_reflection(p_in, s_in, p_plane, n_plane)
% get_plane_reflection -
function [p_reflect, s_reflect] = getPlaneReflection(p_in, s_in, p_plane, n_plane)
% getPlaneReflection -
%
% Syntax: [p_reflect, s_reflect] = get_plane_reflection(p_in, s_in, p_plane, n_plane)
% Syntax: [p_reflect, s_reflect] = getPlaneReflection(p_in, s_in, p_plane, n_plane)
%
% Inputs:
% - p_in, s_in, p_plane, n_plane -
@ -1474,25 +1458,25 @@ pp = [0, 0, 0]; % [m]
np = [cos(pi/2-theta), 0, sin(pi/2-theta)];
%% Reflected beam
[p2, s2] = get_plane_reflection(p1, s1, pp, np);
[p2, s2] = getPlaneReflection(p1, s1, pp, np);
%% Secondary Mirror
ps = pp ...
+ 0.07*[cos(theta), 0, -sin(theta)] ... % x offset (does not matter a lot)
+ 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] = get_plane_reflection(p2, s2, ps, ns);
[p3, s3] = getPlaneReflection(p2, s2, ps, ns);
%% Detector
pd = [1, 0, 0]; % [m]
nd = [-1, 0, 0];
%% Get beam position on the decector
p4 = get_plane_reflection(p3, s3, pd, nd);
p4 = getPlaneReflection(p3, s3, pd, nd);
#+end_src
#+begin_src matlab
@ -1535,8 +1519,65 @@ function [] = plotBeamPath(results)
#+end_src
#+begin_src matlab
plot3([results.p1(1), results.p2(1)],[results.p1(2), results.p2(2)], [results.p1(3), results.p2(3)])
plot3([results.p2(1), results.p3(1)],[results.p2(2), results.p3(2)], [results.p2(3), results.p3(3)])
plot3([results.p3(1), results.p4(1)],[results.p3(2), results.p4(2)], [results.p3(3), results.p4(3)])
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

Binary file not shown.

BIN
figs/channel_cut_scan.pdf Normal file

Binary file not shown.

BIN
figs/channel_cut_scan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -34,25 +34,25 @@ pp = [0, 0, 0]; % [m]
np = [cos(pi/2-theta), 0, sin(pi/2-theta)];
%% Reflected beam
[p2, s2] = get_plane_reflection(p1, s1, pp, np);
[p2, s2] = getPlaneReflection(p1, s1, pp, np);
%% Secondary Mirror
ps = pp ...
+ 0.07*[cos(theta), 0, -sin(theta)] ... % x offset (does not matter a lot)
+ 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] = get_plane_reflection(p2, s2, ps, ns);
[p3, s3] = getPlaneReflection(p2, s2, ps, ns);
%% Detector
pd = [1, 0, 0]; % [m]
nd = [-1, 0, 0];
%% Get beam position on the decector
p4 = get_plane_reflection(p3, s3, pd, nd);
p4 = getPlaneReflection(p3, s3, pd, nd);
results = struct();
% Beam position and orientations

View File

@ -1,7 +1,7 @@
function [p_reflect, s_reflect] = get_plane_reflection(p_in, s_in, p_plane, n_plane)
% get_plane_reflection -
function [p_reflect, s_reflect] = getPlaneReflection(p_in, s_in, p_plane, n_plane)
% getPlaneReflection -
%
% Syntax: [p_reflect, s_reflect] = get_plane_reflection(p_in, s_in, p_plane, n_plane)
% Syntax: [p_reflect, s_reflect] = getPlaneReflection(p_in, s_in, p_plane, n_plane)
%
% Inputs:
% - p_in, s_in, p_plane, n_plane -

View File

@ -9,6 +9,6 @@ function [] = plotBeamPath(results)
% Outputs:
% - in_data -
plot3([results.p1(1), results.p2(1)],[results.p1(2), results.p2(2)], [results.p1(3), results.p2(3)])
plot3([results.p2(1), results.p3(1)],[results.p2(2), results.p3(2)], [results.p2(3), results.p3(3)])
plot3([results.p3(1), results.p4(1)],[results.p3(2), results.p4(2)], [results.p3(3), results.p4(3)])
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)

37
matlab/src/plotCrystals.m Normal file
View File

@ -0,0 +1,37 @@
function [] = plotCrystals(results, args)
% plotCrystals -
%
% Syntax: [in_data] = plotCrystals(drx, dry, dz, theta, )
%
% Inputs:
% - drx, dry, dz, theta, -
%
% Outputs:
% - in_data -
arguments
results
args.color (3,1) double {mustBeNumeric} = [1;1;1]
args.alpha (1,1) double {mustBeNumeric} = 1
end
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];
patch(100*xtal1_rectangle(:,1), 100*xtal1_rectangle(:,2), 100*xtal1_rectangle(:,3), 'k-')
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];
patch(100*xtal2_rectangle(:,1), 100*xtal2_rectangle(:,2), 100*xtal2_rectangle(:,3), 'k-')