diff --git a/figs/test_id31_hac_tomography_Wz36_simulation.pdf b/figs/test_id31_hac_tomography_Wz36_simulation.pdf index b0d5f72..0f3b8f3 100644 Binary files a/figs/test_id31_hac_tomography_Wz36_simulation.pdf and b/figs/test_id31_hac_tomography_Wz36_simulation.pdf differ diff --git a/figs/test_id31_hac_tomography_Wz36_simulation.png b/figs/test_id31_hac_tomography_Wz36_simulation.png index d925179..ee70e1f 100644 Binary files a/figs/test_id31_hac_tomography_Wz36_simulation.png and b/figs/test_id31_hac_tomography_Wz36_simulation.png differ diff --git a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.pdf b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.pdf index 7171f16..a6f1c3f 100644 Binary files a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.pdf and b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.pdf differ diff --git a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png index 30d3c74..17c7a88 100644 Binary files a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png and b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png differ diff --git a/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.pdf b/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.pdf index b664fae..b652697 100644 Binary files a/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.pdf and b/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.pdf differ diff --git a/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.png b/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.png index 466bb40..0088085 100644 Binary files a/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.png and b/figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.png differ diff --git a/test-bench-id31.org b/test-bench-id31.org index c6a1f58..9ff63c4 100644 --- a/test-bench-id31.org +++ b/test-bench-id31.org @@ -181,7 +181,8 @@ CLOSED: [2025-01-30 Thu 11:16] - RMS errors (/ by 6.6) gives 30nmRMS in Dy and 15nmRMS in Dz. - Ry error <1.7urad, 250nrad RMS -** TODO [#A] Maybe should only put experimental results in last section +** DONE [#A] Maybe should only put experimental results in last section +CLOSED: [2025-02-01 Sat 18:38] Some Tomography experiments are presented in ref:sec:test_id31_iff_hac Maybe it should only be simulations, and put everything in the last "experimental" section. @@ -193,7 +194,8 @@ Maybe it should only be simulations, and put everything in the last "experimenta - Reflectivity - Diffraction tomography -** TODO [#A] Check why simulation gives worst performances than reality +** DONE [#A] Check why simulation gives worst performances than reality +CLOSED: [2025-02-01 Sat 18:38] - [X] Check if low pass filtering the disturbances resolves the issue No but it makes the simulation faster! @@ -219,7 +221,8 @@ RMS errors: - Dy: < 30nm RMS - Ry: < 0.25urad RMS -** TODO [#C] Make sure the display order to directions is always the same +** DONE [#C] Make sure the display order to directions is always the same +CLOSED: [2025-02-01 Sat 18:38] *Dy, Dz, Ry* @@ -237,7 +240,8 @@ CLOSED: [2024-11-14 Thu 11:32] Fn => Vs -** TODO [#C] Talk about experimental conditions +** DONE [#C] Talk about experimental conditions +CLOSED: [2025-02-01 Sat 18:38] - Air Conditioning: +/-0.1 deg? - Experimental hutch is closed for a long time to have best thermal stability @@ -253,7 +257,8 @@ Maybe deg/s is the most adequate Make a choice, and then adapt all notations. Also, change the =initializeReferences= to accept the chosen description instead of =period=. -** TODO [#B] Explain that RMS values are not filtered +** DONE [#B] Explain that RMS values are not filtered +CLOSED: [2025-02-01 Sat 18:38] Maybe say that the detectors are integrating the signals (maybe 10ms?). Then update some RMS values to show that it can be considered better than the values given. @@ -419,7 +424,9 @@ First identification: - New identification for all masses - Better match with Simscape model! -** QUES [#C] Why now we have minimum phase zero for IFF Plant? +** CANC [#C] Why now we have minimum phase zero for IFF Plant? +CLOSED: [2025-02-01 Sat 18:39] +- State "CANC" from "QUES" [2025-02-01 Sat 18:39] ** CANC [#C] Find identification where Rz was not taken into account CLOSED: [2024-11-12 Tue 16:03] @@ -3361,7 +3368,6 @@ Yet it was decided that this controller will be tested experimentally, and impro #+begin_src matlab %% Simulation of tomography experiments at 1RPM with all payloads - % Configuration set_param(mdl, 'StopTime', '2'); % 30 degrees at 1rpm initializeLoggingConfiguration('log', 'all', 'Ts', 1e-3); @@ -3412,7 +3418,7 @@ plot(1e9*exp_tomo_cl_m0_1rpm.y.y.Data(1e3:end), 1e9*exp_tomo_cl_m0_1rpm.y.z.Data theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') axis equal -xticks([-400:100:400]); yticks([-50:50:50]); +xticks([-400:100:400]); yticks([-100:100:100]); xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; @@ -3423,7 +3429,7 @@ plot(1e9*exp_tomo_cl_m1_1rpm.y.y.Data(1e3:end), 1e9*exp_tomo_cl_m1_1rpm.y.z.Data theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] plot(100*cos(theta), 50*sin(theta), 'k--', 'HandleVisibility', 'off') axis equal -xticks([-400:100:400]); yticks([-50:50:50]); +xticks([-400:100:400]); yticks([-100:100:100]); xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; @@ -3434,7 +3440,7 @@ plot(1e9*exp_tomo_cl_m2_1rpm.y.y.Data(1e3:end), 1e9*exp_tomo_cl_m2_1rpm.y.z.Data theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] plot(100*cos(theta), 50*sin(theta), 'k--', 'HandleVisibility', 'off') axis equal -xticks([-400:100:400]); yticks([-50:50:50]); +xticks([-400:100:400]); yticks([-100:100:100]); xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; @@ -3445,7 +3451,7 @@ plot(1e9*exp_tomo_cl_m3_1rpm.y.y.Data(1e3:end), 1e9*exp_tomo_cl_m3_1rpm.y.z.Data theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] plot(100*cos(theta), 50*sin(theta), 'k--', 'HandleVisibility', 'off') axis equal -xticks([-400:100:400]); yticks([-50:50:50]); +xticks([-400:100:400]); yticks([-100:100:100]); xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; @@ -3488,22 +3494,32 @@ These results demonstrate both the effectiveness and limitations of implementing <> ** Introduction :ignore: -# - [ ] Where are different experiment explained? -# - [ ] Explain which controller was used here: robust one that works for all payloads! -# - [ ] All results are not filtered (i.e. 10kHz) -# - [ ] For ramp scans, a higher performance controller was used with two integrators +In this section, the goal is to evaluate the performances of the NASS and validate its use for real work scientific experiments. +However, the online metrology prototype (presented in Section ref:sec:test_id31_metrology) does not allow samples to be placed on top of the nano-hexapod while being illuminated by the x-ray beam. +Nevertheless, in order to fully validate the NASS, typical motion performed during scientific experiments can be mimicked, and the positioning performances can be evaluated. -The online metrology prototype does not allow samples to be placed on top of the nano-hexapod while being illuminated by the x-ray beam. -However, in order to fully validate the NASS, typical motion performed during scientific experiments can be mimicked, and the positioning performances can be evaluated. - -For tomography scans, performances were already evaluated in Section ref:ssec:test_id31_iff_hac_perf. -Here, other typical experiments are performed: -- /Lateral scans/: the $T_y$ translations stage performs $D_y$ scans and the errors are corrected by the NASS in real time (Section ref:ssec:test_id31_scans_dy) -- /Vertical layer scans/: the nano-hexapod is used to perform $D_z$ step motion or ramp scans (Section ref:ssec:test_id31_scans_dz) -- /Reflectivity scans/: the tilt stage is doing $R_y$ rotations and the errors are corrected by the NASS in real time (Section ref:ssec:test_id31_scans_reflectivity) -- /Diffraction Tomography/: the Spindle is performing continuous $R_z$ rotation while the translation stage is performing lateral $D_y$ scans at the same time. +Several scientific experiments are mimicked, such as: +- Tomography scans: continuous rotation of the Spindle along the vertical axis (Section ref:ssec:test_id31_scans_tomography) +- Reflectivity scans: $R_y$ rotations using the tilt-stage (Section ref:ssec:test_id31_scans_reflectivity) +- Vertical layer scans: the nano-hexapod is used to perform $D_z$ step motion or ramp scans (Section ref:ssec:test_id31_scans_dz) +- Lateral scans: $D_y$ scans using the $T_y$ translation stage (Section ref:ssec:test_id31_scans_dy) +- Diffraction Tomography: the Spindle is performing continuous $R_z$ rotation while the translation stage is performing lateral $D_y$ scans at the same time. This is the experiment with the most stringent requirements (Section ref:ssec:test_id31_scans_diffraction_tomo) +For each experiment, the obtained performances are compared to the specifications for the most depending case in which nano-focusing optics are used to focus the beam down to $200\,nm\times 100\,nm$. +In that case the goal is to keep the sample's point of interested in the beam, and therefore the $D_y$ and $D_z$ positioning errors should be less than $200\,nm$ and $100\,nm$ peak-to-peak respectively. +The $R_y$ error should be less than $1.7\,\mu\text{rad}$ peak-to-peak. +In terms of RMS errors, this corresponds to $30\,nm$ in $D_y$, $15\,nm$ in $D_z$ and $250\,\text{nrad}$ in $R_y$ (a summary of the specifications is given in Table ref:tab:test_id31_experiments_specifications). + +#+name: tab:test_id31_experiments_specifications +#+caption: Specifications for the Nano-Active-Stabilization-System +#+attr_latex: :environment tabularx :width 0.4\linewidth :align Xccc +#+attr_latex: :center t :booktabs t +| | $D_y$ | $D_z$ | $R_y$ | +|-------------+-------+-------+----------------------| +| peak 2 peak | 200nm | 100nm | $1.7\,\mu\text{rad}$ | +| RMS | 30nm | 15nm | $250\,\text{nrad}$ | + ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> @@ -3525,161 +3541,18 @@ Here, other typical experiments are performed: <> #+end_src -** $R_z$ scans: Tomography +** Tomography Scans <> -**** Introduction :ignore: +**** Slow Tomography scans -*Issue with this control architecture (or controller?)*: -- The position is not converging to zero +First, tomography scans are performed with a rotational velocity of $6\,\text{deg/s}$ for all considered payload masses (shown in Figure ref:fig:test_id31_picture_masses). +For each experiment, a complete spindle rotation was first performed in open-loop, and then the loop was closed during another full spindle rotation. -*Compare*: -- 1rpm, 6rpm, 30rpm -- at 1rpm: m0, m1, m2, m3 (same robust controller!) - -**** Previous results at 30rpm - -Then the same tomography experiment (i.e. constant spindle rotation at 30rpm, and no payload) was performed experimentally. -The measured position of the "point of interest" during the experiment are shown in Figure ref:fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp. - -#+begin_src matlab -%% Experimental Results for Tomography at 30RPM, no payload -% Load measured noise -data_tomo_m0_Wz180 = load('2023-08-17_15-26_tomography_30rpm_m0_robust.mat'); - -[~, i_cl] = find(data_tomo_m0_Wz180.hac_status == 1); -#+end_src - -#+begin_src matlab :exports none :results none -%% Measured radial errors of the Spindle -figure; -hold on; -plot(1e6*data_tomo_m0_Wz180.Dx_int(1:i_cl), 1e6*data_tomo_m0_Wz180.Dy_int(1:i_cl), 'DisplayName', 'OL') -plot(1e6*data_tomo_m0_Wz180.Dx_int(i_cl:i_cl+1e4), 1e6*data_tomo_m0_Wz180.Dy_int(i_cl:i_cl+1e4), 'color', colors(3,:), 'HandleVisibility', 'off') -plot(1e6*data_tomo_m0_Wz180.Dx_int(i_cl+1e4:end), 1e6*data_tomo_m0_Wz180.Dy_int(i_cl+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') -hold off; -xlabel('$D_x$ [$\mu$m]'); ylabel('$D_y$ [$\mu$m]'); -axis equal -xlim([-3, 3]); ylim([-3, 3]); -xticks([-3:1:3]); -yticks([-3:1:3]); -leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); -leg.ItemTokenSize(1) = 15; -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.pdf', 'width', 'half', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Measured radial errors of the Spindle -figure; -tiledlayout(2, 1, 'TileSpacing', 'compact', 'Padding', 'None'); - -ax1 = nexttile(); -hold on; -plot(1e6*data_tomo_m0_Wz180.Dy_int(1:i_cl), 1e6*data_tomo_m0_Wz180.Dz_int(1:i_cl), 'DisplayName', 'OL') -plot(1e6*data_tomo_m0_Wz180.Dy_int(i_cl:i_cl+1e4), 1e6*data_tomo_m0_Wz180.Dz_int(i_cl:i_cl+1e4), 'color', colors(3,:), 'HandleVisibility', 'off') -plot(1e6*data_tomo_m0_Wz180.Dy_int(i_cl+1e4:end), 1e6*data_tomo_m0_Wz180.Dz_int(i_cl+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') -% theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -% plot(0.1*cos(theta), 0.05*sin(theta), 'k-', 'DisplayName', 'Best Fit') -hold off; -xlabel('$D_y$ [$\mu$m]'); ylabel('$D_z$ [$\mu$m]'); -axis equal -xlim([-3, 3]); ylim([-0.6, 0.6]); -xticks([-3:1:3]); -yticks([-3:0.3:3]); -leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); -leg.ItemTokenSize(1) = 15; - -ax2 = nexttile(); -hold on; -plot(1e9*data_tomo_m0_Wz180.Dy_int(i_cl+1e4:end), 1e9*data_tomo_m0_Wz180.Dz_int(i_cl+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') -theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') -hold off; -xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); -axis equal -xlim([-300, 300]); ylim([-100, 100]); -% xticks([-3:1:3]); -% yticks([-3:1:3]); -leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); -leg.ItemTokenSize(1) = 15; -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.pdf', 'width', 'half', 'height', 'normal'); -#+end_src - -#+name: fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp -#+caption: Experimental results of a tomography experiment at 30RPM without payload. Position error of the sample is shown in the XY (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}) and YZ (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}) planes. -#+attr_latex: :options [htbp] -#+begin_figure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}XY plane} -#+attr_latex: :options {0.49\textwidth} -#+begin_subfigure -#+attr_latex: :scale 0.9 -[[file:figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}YZ plane} -#+attr_latex: :options {0.49\textwidth} -#+begin_subfigure -#+attr_latex: :scale 0.9 -[[file:figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png]] -#+end_subfigure -#+end_figure - -Even though the simulation (Figure ref:fig:test_id31_tomo_m0_30rpm_robust_hac_iff_sim) and the experimental results (Figure ref:fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp) are looking similar, the most important metric to compare is the RMS values of the positioning errors in closed-loop. -These are computed for both the simulation and the experimental results and are compared in Table ref:tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms. -The lateral and vertical errors are similar, however the tilt ($R_y$) errors are underestimated by the model, which is reasonable as disturbances in $R_y$ were not modeled. - -Results obtained with this conservative HAC are already close to the specifications. - -#+begin_src matlab -%% Compute RMS of errors - -% Simulation - OL -rms_Dy_m0_Wz180_ol_sim = rms(detrend(exp_tomo_ol_m0_Wz180.y.y.Data, 0)); -rms_Dz_m0_Wz180_ol_sim = rms(detrend(exp_tomo_ol_m0_Wz180.y.z.Data, 0)); -rms_Ry_m0_Wz180_ol_sim = rms(detrend(squeeze(atan2(exp_tomo_ol_m0_Wz180.y.R.Data(1,3,:), sqrt(exp_tomo_ol_m0_Wz180.y.R.Data(1,1,:).^2+exp_tomo_ol_m0_Wz180.y.R.Data(1,2,:).^2))), 0)); -i_stab = 1000; % Remove the transient that is irrelevant here -% Simulation - CL -rms_Dy_m0_Wz180_cl_sim = rms(detrend(exp_tomo_cl_m0_Wz180.y.y.Data(i_stab:end), 0)); -rms_Dz_m0_Wz180_cl_sim = rms(detrend(exp_tomo_cl_m0_Wz180.y.z.Data(i_stab:end), 0)); -rms_Ry_m0_Wz180_cl_sim = rms(detrend(squeeze(atan2(exp_tomo_cl_m0_Wz180.y.R.Data(1,3,i_stab:end), sqrt(exp_tomo_cl_m0_Wz180.y.R.Data(1,1,i_stab:end).^2+exp_tomo_cl_m0_Wz180.y.R.Data(1,2,i_stab:end).^2))), 0)); - -% Experimental - OL -[~, i_cl] = find(data_tomo_m0_Wz180.hac_status == 1); -rms_Dy_m0_Wz180_ol_exp = rms(detrend(data_tomo_m0_Wz180.Dy_int(1:i_cl), 0)); -rms_Dz_m0_Wz180_ol_exp = rms(detrend(data_tomo_m0_Wz180.Dz_int(1:i_cl), 0)); -rms_Ry_m0_Wz180_ol_exp = rms(detrend(data_tomo_m0_Wz180.Ry_int(1:i_cl), 0)); -% Experimental - CL -rms_Dy_m0_Wz180_cl_exp = rms(detrend(data_tomo_m0_Wz180.Dy_int(i_cl+10000:end), 0)); -rms_Dz_m0_Wz180_cl_exp = rms(detrend(data_tomo_m0_Wz180.Dz_int(i_cl+10000:end), 0)); -rms_Ry_m0_Wz180_cl_exp = rms(detrend(data_tomo_m0_Wz180.Ry_int(i_cl+10000:end), 0)); -#+end_src - -#+name: tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms -#+caption: RMS values of the errors for a tomography experiment at 30RPM and without payload. Experimental results and simulation are compared. -#+attr_latex: :environment tabularx :width 0.7\linewidth :align Xccc -#+attr_latex: :center t :booktabs t -| | $D_y$ | $D_z$ | $R_y$ | -|-----------------+-----------------------+--------------------+------------------------| -| Experiment (OL) | $1.8\,\mu\text{mRMS}$ | $24\,\text{nmRMS}$ | $10\,\mu\text{radRMS}$ | -|-----------------+-----------------------+--------------------+------------------------| -| Simulation (CL) | $30\,\text{nmRMS}$ | $8\,\text{nmRMS}$ | $73\,\text{nradRMS}$ | -| Experiment (CL) | $39\,\text{nmRMS}$ | $11\,\text{nmRMS}$ | $130\,\text{nradRMS}$ | -|-----------------+-----------------------+--------------------+------------------------| -| Specifications | $30\,\text{nmRMS}$ | $15\,\text{nmRMS}$ | $250\,\text{nradRMS}$ | - -**** Previous results at 1rpm - -The tomography experiments that were simulated were then experimentally conducted. -For each payload, a spindle rotating was first performed in open-loop, and then the loop was closed during another full spindle rotation. -An example with the $26\,\text{kg}$ payload is shown in Figure ref:fig:test_id31_tomo_m2_1rpm_robust_hac_iff_fit. +Results with the $26\,\text{kg}$ payload is shown in Figure ref:fig:test_id31_tomo_m2_1rpm_robust_hac_iff_fit. The eccentricity between the "point of interest" and the spindle rotation axis is quite large as the added payload mass statically deforms the micro-station stages. -To estimate the open-loop errors, it is supposed that the "point of interest" can be perfectly aligned with the spindle rotation axis. -Therefore, the eccentricity is first estimated by performing a circular fit (dashed black circle in Figure ref:fig:test_id31_tomo_m2_1rpm_robust_hac_iff_fit), and then subtracted from the data in Figure ref:fig:test_id31_tomo_m2_1rpm_robust_hac_iff_fit_removed. -This underestimate the real condition open-loop errors as it is difficult to obtain a perfect alignment in practice. +To estimate the open-loop errors, it is here supposed that the "point of interest" can be perfectly aligned with the spindle rotation axis. +To simulate this case, the eccentricity is first estimated by performing a circular fit (dashed black circle in Figure ref:fig:test_id31_tomo_m2_1rpm_robust_hac_iff_fit), and is then subtracted from the data in Figure ref:fig:test_id31_tomo_m2_1rpm_robust_hac_iff_fit_removed. +This underestimate the real open-loop errors as it is difficult to obtain a perfect alignment in practice, but it provides a more equitable comparison with the closed-loop case. #+begin_src matlab %% Load Tomography scans with robust controller @@ -3697,133 +3570,48 @@ data_tomo_m3_Wz6.time = Ts*[0:length(data_tomo_m3_Wz6.Rz)-1]; #+end_src #+begin_src matlab +%% Find best circle fit for all experiments [~, i_m0] = find(data_tomo_m0_Wz6.hac_status == 1); -% Find best circle -[x_m0, y_m0, R_m0] = circlefit(data_tomo_m2_Wz6.Dx_int(1:i_m2), data_tomo_m2_Wz6.Dy_int(1:i_m2)); +[x_m0, y_m0, R_m0] = circlefit(data_tomo_m0_Wz6.Dx_int(1:i_m0), data_tomo_m0_Wz6.Dy_int(1:i_m0)); fun = @(theta)rms((data_tomo_m0_Wz6.Dx_int(1:i_m0) - (x_m0 + R_m0*cos(data_tomo_m0_Wz6.Rz(1:i_m0)+theta(1)))).^2 + ... (data_tomo_m0_Wz6.Dy_int(1:i_m0) - (y_m0 + R_m0*sin(data_tomo_m0_Wz6.Rz(1:i_m0)+theta(1)))).^2); delta_theta_m0 = fminsearch(fun, 0); [~, i_m1] = find(data_tomo_m1_Wz6.hac_status == 1); +[x_m1, y_m1, R_m1] = circlefit(data_tomo_m1_Wz6.Dx_int(1:i_m1), data_tomo_m1_Wz6.Dy_int(1:i_m1)); +fun = @(theta)rms((data_tomo_m1_Wz6.Dx_int(1:i_m1) - (x_m1 + R_m1*cos(data_tomo_m1_Wz6.Rz(1:i_m1)+theta(1)))).^2 + ... + (data_tomo_m1_Wz6.Dy_int(1:i_m1) - (y_m1 + R_m1*sin(data_tomo_m1_Wz6.Rz(1:i_m1)+theta(1)))).^2); +delta_theta_m1 = fminsearch(fun, 0); + [~, i_m2] = find(data_tomo_m2_Wz6.hac_status == 1); +[x_m2, y_m2, R_m2] = circlefit(data_tomo_m2_Wz6.Dx_int(1:i_m2), data_tomo_m2_Wz6.Dy_int(1:i_m2)); +fun = @(theta)rms((data_tomo_m2_Wz6.Dx_int(1:i_m2) - (x_m2 + R_m2*cos(data_tomo_m2_Wz6.Rz(1:i_m2)+theta(1)))).^2 + ... + (data_tomo_m2_Wz6.Dy_int(1:i_m2) - (y_m2 + R_m2*sin(data_tomo_m2_Wz6.Rz(1:i_m2)+theta(1)))).^2); +delta_theta_m2 = fminsearch(fun, 0); + [~, i_m3] = find(data_tomo_m3_Wz6.hac_status == 1); +[x_m3, y_m3, R_m3] = circlefit(data_tomo_m3_Wz6.Dx_int(1:i_m3), data_tomo_m3_Wz6.Dy_int(1:i_m3)); +fun = @(theta)rms((data_tomo_m3_Wz6.Dx_int(1:i_m3) - (x_m3 + R_m3*cos(data_tomo_m3_Wz6.Rz(1:i_m3)+theta(1)))).^2 + ... + (data_tomo_m3_Wz6.Dy_int(1:i_m3) - (y_m3 + R_m3*sin(data_tomo_m3_Wz6.Rz(1:i_m3)+theta(1)))).^2); +delta_theta_m3 = fminsearch(fun, 0); #+end_src #+begin_src matlab :exports none :results none %% Tomography experiment at 1rpm with 26kg payload figure; hold on; -plot(1e9*data_tomo_m0_Wz6.Dy_int(i_cl+1e4:end), 1e9*data_tomo_m0_Wz6.Dz_int(i_cl+1e4:end)) +plot(1e6*data_tomo_m2_Wz6.Dx_int(1:10:i_m2), 1e6*data_tomo_m2_Wz6.Dy_int(1:10:i_m2), 'DisplayName', '$m = 26$ kg (OL)') +plot(1e6*data_tomo_m2_Wz6.Dx_int(i_m2:10:i_m2+1e4), 1e6*data_tomo_m2_Wz6.Dy_int(i_m2:10:i_m2+1e4), 'color', colors(3,:), 'HandleVisibility', 'off') +plot(1e6*data_tomo_m2_Wz6.Dx_int(i_m2+1e4:10:end), 1e6*data_tomo_m2_Wz6.Dy_int(i_m2+1e4:10:end), 'color', colors(2,:), 'DisplayName', '$m = 26$ kg (CL)') theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') -hold off; -xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); -axis equal -xticks([-400:100:400]); -yticks([-50:50:50]) -% xlim([-20, 100]); ylim([-20, 100]); -% xticks([-20:20:100]); -% yticks([-20:20:100]); -% leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -% leg.ItemTokenSize(1) = 15; -#+end_src - -#+begin_src matlab -figure; -tiledlayout(2, 2, 'TileSpacing', 'compact', 'Padding', 'None'); - -ax1 = nexttile; -hold on; -plot(1e9*detrend(data_tomo_m0_Wz6.Dy_int(i_cl+1e4:end), 0), 1e9*detrend(data_tomo_m0_Wz6.Dz_int(i_cl+1e4:end), 0), 'color', colors(1,:)) -theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') -axis equal -xticks([-400:100:400]); -yticks([-50:50:50]) - -ax2 = nexttile; -hold on; -plot(1e9*detrend(data_tomo_m1_Wz6.Dy_int(i_cl+1e4:end), 0), 1e9*detrend(data_tomo_m1_Wz6.Dz_int(i_cl+1e4:end), 0), 'color', colors(2,:)) -theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') -axis equal -xticks([-400:100:400]); -yticks([-50:50:50]) - -ax3 = nexttile; -hold on; -plot(1e9*detrend(data_tomo_m2_Wz6.Dy_int(i_cl+1e4:end), 0), 1e9*detrend(data_tomo_m2_Wz6.Dz_int(i_cl+1e4:end), 0), 'color', colors(3,:)) -theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') -axis equal -xticks([-400:100:400]); -yticks([-50:50:50]) - -ax4 = nexttile; -hold on; -plot(1e9*detrend(data_tomo_m3_Wz6.Dy_int(i_cl+1e4:end), 0), 1e9*detrend(data_tomo_m3_Wz6.Dz_int(i_cl+1e4:end), 0), 'color', colors(4,:)) -theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') -axis equal -xticks([-400:100:400]); -yticks([-50:50:50]) - -linkaxes([ax1,ax2,ax3, ax4],'xy'); -xlim([-450, 450]); ylim([-100, 100]); -#+end_src - -#+begin_src matlab :exports none :results none -%% Tomography experiment at 1rpm with 26kg payload -figure; -hold on; -plot(1e6*data_tomo_m0_Wz6.Dx_int(1:i_cl), 1e6*data_tomo_m0_Wz6.Dy_int(1:i_cl), 'DisplayName', 'OL') -plot(1e6*data_tomo_m0_Wz6.Dx_int(i_cl:i_cl+1e4), 1e6*data_tomo_m0_Wz6.Dy_int(i_cl:i_cl+1e4), 'color', colors(3,:), 'HandleVisibility', 'off') -plot(1e6*data_tomo_m0_Wz6.Dx_int(i_cl+1e4:end), 1e6*data_tomo_m0_Wz6.Dy_int(i_cl+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') -theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(1e6*(x_m0 + R_m0*cos(theta)), 1e6*(y_m0 + R_m0*sin(theta)), 'k--', 'DisplayName', 'Best Fit') +plot(1e6*(x_m2 + R_m2*cos(theta)), 1e6*(y_m2 + R_m2*sin(theta)), 'k--', 'DisplayName', 'Best Circular Fit') hold off; xlabel('$D_x$ [$\mu$m]'); ylabel('$D_y$ [$\mu$m]'); axis equal xlim([-20, 100]); ylim([-20, 100]); xticks([-20:20:100]); yticks([-20:20:100]); -leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -leg.ItemTokenSize(1) = 15; -#+end_src - - - - -#+begin_src matlab :exports none :results none -%% Compute best circle fit for the displayed tomography experiment -[~, i_cl] = find(data_tomo_m0_Wz6.hac_status == 1); - -% Find best circle -[x0, y0, R] = circlefit(data_tomo_m2_Wz6.Dx_int(1:i_m2), data_tomo_m2_Wz6.Dy_int(1:i_m2)); -fun = @(theta)rms((data_tomo_m2_Wz6.Dx_int(1:i_m2) - (x0 + R*cos(data_tomo_m2_Wz6.Rz(1:i_m2)+theta(1)))).^2 + ... - (data_tomo_m2_Wz6.Dy_int(1:i_m2) - (y0 + R*sin(data_tomo_m2_Wz6.Rz(1:i_m2)+theta(1)))).^2); -delta_theta = fminsearch(fun, 0); -#+end_src - -- [ ] Maybe show in the YZ plane? -- [ ] Add the beam size? - -#+begin_src matlab :exports none :results none -%% Tomography experiment at 1rpm with 26kg payload -figure; -hold on; -plot(1e6*data_tomo_m2_Wz6.Dx_int(1:i_cl), 1e6*data_tomo_m2_Wz6.Dy_int(1:i_cl), 'DisplayName', 'OL') -plot(1e6*data_tomo_m2_Wz6.Dx_int(i_cl:i_cl+1e4), 1e6*data_tomo_m2_Wz6.Dy_int(i_cl:i_cl+1e4), 'color', colors(3,:), 'HandleVisibility', 'off') -plot(1e6*data_tomo_m2_Wz6.Dx_int(i_cl+1e4:end), 1e6*data_tomo_m2_Wz6.Dy_int(i_cl+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') -theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] -plot(1e6*(x0 + R*cos(theta)), 1e6*(y0 + R*sin(theta)), 'k--', 'DisplayName', 'Best Fit') -hold off; -xlabel('$D_x$ [$\mu$m]'); ylabel('$D_y$ [$\mu$m]'); -axis equal -xlim([-20, 100]); ylim([-20, 100]); -xticks([-20:20:100]); -yticks([-20:20:100]); -leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; #+end_src @@ -3835,9 +3623,9 @@ exportFig('figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit.pdf', 'width', 'half', %% Measured radial errors of the Spindle figure; hold on; -plot(1e6*(data_tomo_m2_Wz6.Dx_int(1:100:i_m2) - (x0 + R*cos(data_tomo_m2_Wz6.Rz(1:100:i_m2)+delta_theta))), ... - 1e6*(data_tomo_m2_Wz6.Dy_int(1:100:i_m2) - (y0 + R*sin(data_tomo_m2_Wz6.Rz(1:100:i_m2)+delta_theta))), 'color', colors(1,:), 'DisplayName', 'OL') -plot(1e6*detrend(data_tomo_m2_Wz6.Dx_int(i_cl+1e4:100:end), 0), 1e6*detrend(data_tomo_m2_Wz6.Dy_int(i_cl+1e4:100:end), 0), 'color', colors(2,:), 'DisplayName', 'CL') +plot(1e6*(data_tomo_m2_Wz6.Dx_int(1:10:i_m2) - (x_m2 + R_m2*cos(data_tomo_m2_Wz6.Rz(1:10:i_m2)+delta_theta_m2))), ... + 1e6*(data_tomo_m2_Wz6.Dy_int(1:10:i_m2) - (y_m2 + R_m2*sin(data_tomo_m2_Wz6.Rz(1:10:i_m2)+delta_theta_m2))), 'color', colors(1,:), 'DisplayName', '$m = 26$ kg (OL)') +plot(1e6*detrend(data_tomo_m2_Wz6.Dx_int(i_m2+1e4:10:end), 0), 1e6*detrend(data_tomo_m2_Wz6.Dy_int(i_m2+1e4:10:end), 0), 'color', colors(2,:), 'DisplayName', '$m = 26$ kg (CL)') hold off; xlabel('$D_x$ [$\mu$m]'); ylabel('$D_y$ [$\mu$m]'); axis equal @@ -3870,23 +3658,97 @@ exportFig('figs/test_id31_tomo_m2_1rpm_robust_hac_iff_fit_removed.pdf', 'width', #+end_subfigure #+end_figure -The RMS values of the open-loop and closed-loop errors for all masses are summarized in Table ref:tab:test_id31_tomo_1rpm_robust_ol_cl_errors. +After removing the eccentricity for each experiment, the remaining measured motion are shown in the $Y-Z$ plane and compared with the smallest beam size in Figure ref:fig:test_id31_tomo_Wz36_results. +Results are indicating the NASS succeeds in keeping the sample's point of interests on the beam, except for the highest mass of $39\,\text{kg}$ for which the lateral motion is a bit too high. +This confirms what was found during the tomography simulations performed in Section ref:ssec:test_id31_iff_hac_robustness. + +#+begin_src matlab :exports none :results none +%% Tomography experiment at 1rpm with 26kg payload +figure; +tiledlayout(2, 2, 'TileSpacing', 'compact', 'Padding', 'None'); + +ax1 = nexttile; +hold on; +plot(1e9*detrend(data_tomo_m0_Wz6.Dy_int(1:10:i_m0) - y_m0 - R_m0*sin(data_tomo_m0_Wz6.Rz(1:10:i_m0)+delta_theta_m0), 0), 1e9*detrend(data_tomo_m0_Wz6.Dz_int(1:10:i_m0), 0), 'DisplayName', 'OL') +plot(1e9*detrend(data_tomo_m0_Wz6.Dy_int(i_m0+1e4:10:end), 0), 1e9*detrend(data_tomo_m0_Wz6.Dz_int(i_m0+1e4:10:end), 0), 'DisplayName', 'CL') +theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] +plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam') +text(-430, 90, '$m = 0$ kg', 'Horiz','left', 'Vert','top', 'FontWeight', 'bold') +hold off; +xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); +axis equal +xlim([-450, 450]); ylim([-100, 100]); +xticks([-400:100:400]); yticks([-50:50:50]); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; + +ax2 = nexttile; +hold on; +plot(1e9*detrend(data_tomo_m1_Wz6.Dy_int(1:10:i_m1) - y_m1 - R_m1*sin(data_tomo_m1_Wz6.Rz(1:10:i_m1)+delta_theta_m1), 0), 1e9*detrend(data_tomo_m1_Wz6.Dz_int(1:10:i_m1), 0), 'DisplayName', 'OL') +plot(1e9*detrend(data_tomo_m1_Wz6.Dy_int(i_m1+1e4:10:end), 0), 1e9*detrend(data_tomo_m1_Wz6.Dz_int(i_m1+1e4:10:end), 0), 'DisplayName', 'CL') +theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] +plot(100*cos(theta), 50*sin(theta), 'k--', 'HandleVisibility', 'off') +text(-430, 90, '$m = 13$ kg', 'Horiz','left', 'Vert','top', 'FontWeight', 'bold') +hold off; +xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); +axis equal +xlim([-450, 450]); ylim([-100, 100]); +xticks([-400:100:400]); yticks([-50:50:50]); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; + +ax3 = nexttile; +hold on; +plot(1e9*detrend(data_tomo_m2_Wz6.Dy_int(1:10:i_m2) - y_m2 - R_m2*sin(data_tomo_m2_Wz6.Rz(1:10:i_m2)+delta_theta_m2), 0), 1e9*detrend(data_tomo_m2_Wz6.Dz_int(1:10:i_m2), 0), 'DisplayName', 'OL') +plot(1e9*detrend(data_tomo_m2_Wz6.Dy_int(i_m2+1e4:10:end), 0), 1e9*detrend(data_tomo_m2_Wz6.Dz_int(i_m2+1e4:10:end), 0), 'DisplayName', 'CL') +theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] +plot(100*cos(theta), 50*sin(theta), 'k--', 'HandleVisibility', 'off') +text(-430, 90, '$m = 26$ kg', 'Horiz','left', 'Vert','top', 'FontWeight', 'bold') +hold off; +xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); +axis equal +xlim([-450, 450]); ylim([-100, 100]); +xticks([-400:100:400]); yticks([-50:50:50]); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; + +ax4 = nexttile; +hold on; +plot(1e9*detrend(data_tomo_m3_Wz6.Dy_int(1:10:i_m3) - y_m3 - R_m3*sin(data_tomo_m3_Wz6.Rz(1:10:i_m3)+delta_theta_m3), 0), 1e9*detrend(data_tomo_m3_Wz6.Dz_int(1:10:i_m3), 0), 'DisplayName', 'OL') +plot(1e9*detrend(data_tomo_m3_Wz6.Dy_int(i_m3+1e4:10:end), 0), 1e9*detrend(data_tomo_m3_Wz6.Dz_int(i_m3+1e4:10:end), 0), 'DisplayName', 'CL') +theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] +plot(100*cos(theta), 50*sin(theta), 'k--', 'HandleVisibility', 'off') +text(-860, 180, '$m = 39$ kg', 'Horiz','left', 'Vert','top', 'FontWeight', 'bold') +hold off; +xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); +axis equal +xlim([-900, 900]); ylim([-200, 200]); +xticks([-800:200:800]); yticks([-100:100:100]); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/test_id31_tomo_Wz36_results.pdf', 'width', 'full', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_tomo_Wz36_results +#+caption: Positioning errors in the Y-Z plane during tomography experiments simulated using the multi-body model (in closed-loop) +#+RESULTS: +[[file:figs/test_id31_tomo_Wz36_results.png]] + +The RMS values of the open-loop (with the eccentricity removed) and closed-loop errors for all masses are summarized in Table ref:tab:test_id31_tomo_1rpm_robust_ol_cl_errors. The obtained closed-loop errors are fulfilling the requirements, except for the $39\,\text{kg}$ payload in the lateral ($D_y$) direction. #+begin_src matlab %% Estimate RMS of the errors while in closed-loop and open-loop % No mass -[~, i_m0] = find(data_tomo_m0_Wz6.hac_status == 1); data_tomo_m0_Wz6.Dy_rms_cl = rms(detrend(data_tomo_m0_Wz6.Dy_int(i_m0+50000:end), 0)); data_tomo_m0_Wz6.Dz_rms_cl = rms(detrend(data_tomo_m0_Wz6.Dz_int(i_m0+50000:end), 0)); data_tomo_m0_Wz6.Ry_rms_cl = rms(detrend(data_tomo_m0_Wz6.Ry_int(i_m0+50000:end), 0)); % Remove eccentricity for OL errors -[x0, y0, R] = circlefit(data_tomo_m0_Wz6.Dx_int(1:i_m0), data_tomo_m0_Wz6.Dy_int(1:i_m0)); -fun = @(theta)rms((data_tomo_m0_Wz6.Dx_int(1:i_m0) - (x0 + R*cos(data_tomo_m0_Wz6.Rz(1:i_m0)+theta(1)))).^2 + ... - (data_tomo_m0_Wz6.Dy_int(1:i_m0) - (y0 + R*sin(data_tomo_m0_Wz6.Rz(1:i_m0)+theta(1)))).^2); -delta_theta = fminsearch(fun, 0); -data_tomo_m0_Wz6.Dy_rms_ol = rms(data_tomo_m0_Wz6.Dy_int(1:i_m0) - (y0 + R*sin(data_tomo_m0_Wz6.Rz(1:i_m0)+delta_theta))); +data_tomo_m0_Wz6.Dy_rms_ol = rms(data_tomo_m0_Wz6.Dy_int(1:i_m0) - (y_m0 + R_m0*sin(data_tomo_m0_Wz6.Rz(1:i_m0)+delta_theta_m0))); data_tomo_m0_Wz6.Dz_rms_ol = rms(detrend(data_tomo_m0_Wz6.Dz_int(1:i_m0), 0)); [x0, y0, R] = circlefit(data_tomo_m0_Wz6.Rx_int(1:i_m0), data_tomo_m0_Wz6.Ry_int(1:i_m0)); fun = @(theta)rms((data_tomo_m0_Wz6.Rx_int(1:i_m0) - (x0 + R*cos(data_tomo_m0_Wz6.Rz(1:i_m0)+theta(1)))).^2 + ... @@ -3895,17 +3757,12 @@ delta_theta = fminsearch(fun, 0); data_tomo_m0_Wz6.Ry_rms_ol = rms(data_tomo_m0_Wz6.Ry_int(1:i_m0) - (y0 + R*sin(data_tomo_m0_Wz6.Rz(1:i_m0)+delta_theta))); % 1 "layer mass" -[~, i_m1] = find(data_tomo_m1_Wz6.hac_status == 1); data_tomo_m1_Wz6.Dy_rms_cl = rms(detrend(data_tomo_m1_Wz6.Dy_int(i_m1+50000:end), 0)); data_tomo_m1_Wz6.Dz_rms_cl = rms(detrend(data_tomo_m1_Wz6.Dz_int(i_m1+50000:end), 0)); data_tomo_m1_Wz6.Ry_rms_cl = rms(detrend(data_tomo_m1_Wz6.Ry_int(i_m1+50000:end), 0)); % Remove eccentricity for OL errors -[x0, y0, R] = circlefit(data_tomo_m1_Wz6.Dx_int(1:i_m1), data_tomo_m1_Wz6.Dy_int(1:i_m1)); -fun = @(theta)rms((data_tomo_m1_Wz6.Dx_int(1:i_m1) - (x0 + R*cos(data_tomo_m1_Wz6.Rz(1:i_m1)+theta(1)))).^2 + ... - (data_tomo_m1_Wz6.Dy_int(1:i_m1) - (y0 + R*sin(data_tomo_m1_Wz6.Rz(1:i_m1)+theta(1)))).^2); -delta_theta = fminsearch(fun, 0); -data_tomo_m1_Wz6.Dy_rms_ol = rms(data_tomo_m1_Wz6.Dy_int(1:i_m1) - (y0 + R*sin(data_tomo_m1_Wz6.Rz(1:i_m1)+delta_theta))); +data_tomo_m1_Wz6.Dy_rms_ol = rms(data_tomo_m1_Wz6.Dy_int(1:i_m1) - (y_m1 + R_m1*sin(data_tomo_m1_Wz6.Rz(1:i_m1)+delta_theta_m1))); data_tomo_m1_Wz6.Dz_rms_ol = rms(detrend(data_tomo_m1_Wz6.Dz_int(1:i_m1), 0)); [x0, y0, R] = circlefit(data_tomo_m1_Wz6.Rx_int(1:i_m1), data_tomo_m1_Wz6.Ry_int(1:i_m1)); fun = @(theta)rms((data_tomo_m1_Wz6.Rx_int(1:i_m1) - (x0 + R*cos(data_tomo_m1_Wz6.Rz(1:i_m1)+theta(1)))).^2 + ... @@ -3914,17 +3771,12 @@ delta_theta = fminsearch(fun, 0); data_tomo_m1_Wz6.Ry_rms_ol = rms(data_tomo_m1_Wz6.Ry_int(1:i_m1) - (y0 + R*sin(data_tomo_m1_Wz6.Rz(1:i_m1)+delta_theta))); % 2 "layer masses" -[~, i_m2] = find(data_tomo_m2_Wz6.hac_status == 1); data_tomo_m2_Wz6.Dy_rms_cl = rms(detrend(data_tomo_m2_Wz6.Dy_int(i_m2+50000:end), 0)); data_tomo_m2_Wz6.Dz_rms_cl = rms(detrend(data_tomo_m2_Wz6.Dz_int(i_m2+50000:end), 0)); data_tomo_m2_Wz6.Ry_rms_cl = rms(detrend(data_tomo_m2_Wz6.Ry_int(i_m2+50000:end), 0)); % Remove eccentricity for OL errors -[x0, y0, R] = circlefit(data_tomo_m2_Wz6.Dx_int(1:i_m2), data_tomo_m2_Wz6.Dy_int(1:i_m2)); -fun = @(theta)rms((data_tomo_m2_Wz6.Dx_int(1:i_m2) - (x0 + R*cos(data_tomo_m2_Wz6.Rz(1:i_m2)+theta(1)))).^2 + ... - (data_tomo_m2_Wz6.Dy_int(1:i_m2) - (y0 + R*sin(data_tomo_m2_Wz6.Rz(1:i_m2)+theta(1)))).^2); -delta_theta = fminsearch(fun, 0); -data_tomo_m2_Wz6.Dy_rms_ol = rms(data_tomo_m2_Wz6.Dy_int(1:i_m2) - (y0 + R*sin(data_tomo_m2_Wz6.Rz(1:i_m2)+delta_theta))); +data_tomo_m2_Wz6.Dy_rms_ol = rms(data_tomo_m2_Wz6.Dy_int(1:i_m2) - (y_m2 + R_m2*sin(data_tomo_m2_Wz6.Rz(1:i_m2)+delta_theta_m2))); data_tomo_m2_Wz6.Dz_rms_ol = rms(detrend(data_tomo_m2_Wz6.Dz_int(1:i_m2), 0)); [x0, y0, R] = circlefit(data_tomo_m2_Wz6.Rx_int(1:i_m2), data_tomo_m2_Wz6.Ry_int(1:i_m2)); fun = @(theta)rms((data_tomo_m2_Wz6.Rx_int(1:i_m2) - (x0 + R*cos(data_tomo_m2_Wz6.Rz(1:i_m2)+theta(1)))).^2 + ... @@ -3933,17 +3785,12 @@ delta_theta = fminsearch(fun, 0); data_tomo_m2_Wz6.Ry_rms_ol = rms(data_tomo_m2_Wz6.Ry_int(1:i_m2) - (y0 + R*sin(data_tomo_m2_Wz6.Rz(1:i_m2)+delta_theta))); % 3 "layer masses" -[~, i_m3] = find(data_tomo_m3_Wz6.hac_status == 1); data_tomo_m3_Wz6.Dy_rms_cl = rms(detrend(data_tomo_m3_Wz6.Dy_int(i_m3+50000:end), 0)); data_tomo_m3_Wz6.Dz_rms_cl = rms(detrend(data_tomo_m3_Wz6.Dz_int(i_m3+50000:end), 0)); data_tomo_m3_Wz6.Ry_rms_cl = rms(detrend(data_tomo_m3_Wz6.Ry_int(i_m3+50000:end), 0)); % Remove eccentricity for OL errors -[x0, y0, R] = circlefit(data_tomo_m3_Wz6.Dx_int(1:i_m3), data_tomo_m3_Wz6.Dy_int(1:i_m3)); -fun = @(theta)rms((data_tomo_m3_Wz6.Dx_int(1:i_m3) - (x0 + R*cos(data_tomo_m3_Wz6.Rz(1:i_m3)+theta(1)))).^2 + ... - (data_tomo_m3_Wz6.Dy_int(1:i_m3) - (y0 + R*sin(data_tomo_m3_Wz6.Rz(1:i_m3)+theta(1)))).^2); -delta_theta = fminsearch(fun, 0); -data_tomo_m3_Wz6.Dy_rms_ol = rms(data_tomo_m3_Wz6.Dy_int(1:i_m3) - (y0 + R*sin(data_tomo_m3_Wz6.Rz(1:i_m3)+delta_theta))); +data_tomo_m3_Wz6.Dy_rms_ol = rms(data_tomo_m3_Wz6.Dy_int(1:i_m3) - (y_m3 + R_m3*sin(data_tomo_m3_Wz6.Rz(1:i_m3)+delta_theta_m3))); data_tomo_m3_Wz6.Dz_rms_ol = rms(detrend(data_tomo_m3_Wz6.Dz_int(1:i_m3), 0)); [x0, y0, R] = circlefit(data_tomo_m3_Wz6.Rx_int(1:i_m3), data_tomo_m3_Wz6.Ry_int(1:i_m3)); fun = @(theta)rms((data_tomo_m3_Wz6.Rx_int(1:i_m3) - (x0 + R*cos(data_tomo_m3_Wz6.Rz(1:i_m3)+theta(1)))).^2 + ... @@ -3974,14 +3821,942 @@ data2orgtable([1e9*data_tomo_m0_Wz6.Dy_rms_ol, 1e9*data_tomo_m0_Wz6.Dz_rms_ol, 1 #+end_src #+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable([1e9*data_tomo_m0_Wz6.Dx_rms_cl, 1e9*data_tomo_m0_Wz6.Dy_rms_cl, 1e9*data_tomo_m0_Wz6.Dz_rms_cl, 1e9*data_tomo_m0_Wz6.Rx_rms_cl, 1e9*data_tomo_m0_Wz6.Ry_rms_cl; ... - 1e9*data_tomo_m1_Wz6.Dx_rms_cl, 1e9*data_tomo_m1_Wz6.Dy_rms_cl, 1e9*data_tomo_m1_Wz6.Dz_rms_cl, 1e9*data_tomo_m1_Wz6.Rx_rms_cl, 1e9*data_tomo_m1_Wz6.Ry_rms_cl; ... - 1e9*data_tomo_m2_Wz6.Dx_rms_cl, 1e9*data_tomo_m2_Wz6.Dy_rms_cl, 1e9*data_tomo_m2_Wz6.Dz_rms_cl, 1e9*data_tomo_m2_Wz6.Rx_rms_cl, 1e9*data_tomo_m2_Wz6.Ry_rms_cl; ... - 1e9*data_tomo_m3_Wz6.Dx_rms_cl, 1e9*data_tomo_m3_Wz6.Dy_rms_cl, 1e9*data_tomo_m3_Wz6.Dz_rms_cl, 1e9*data_tomo_m3_Wz6.Rx_rms_cl, 1e9*data_tomo_m3_Wz6.Ry_rms_cl], ... - {'$m_0$', '$m_1$', '$m_2$', '$m_3$'}, {'$D_x$ [nm]', '$D_y$ [nm]', '$D_z$ [nm]', '$R_x$ [nrad]', '$R_y$ [nrad]'}, ' %.0f '); +data2orgtable([1e9*data_tomo_m0_Wz6.Dy_rms_cl, 1e9*data_tomo_m0_Wz6.Dz_rms_cl, 1e9*data_tomo_m0_Wz6.Ry_rms_cl; ... + 1e9*data_tomo_m1_Wz6.Dy_rms_cl, 1e9*data_tomo_m1_Wz6.Dz_rms_cl, 1e9*data_tomo_m1_Wz6.Ry_rms_cl; ... + 1e9*data_tomo_m2_Wz6.Dy_rms_cl, 1e9*data_tomo_m2_Wz6.Dz_rms_cl, 1e9*data_tomo_m2_Wz6.Ry_rms_cl; ... + 1e9*data_tomo_m3_Wz6.Dy_rms_cl, 1e9*data_tomo_m3_Wz6.Dz_rms_cl, 1e9*data_tomo_m3_Wz6.Ry_rms_cl], ... + {'$m_0$', '$m_1$', '$m_2$', '$m_3$'}, {'$D_y$ [nm]', '$D_z$ [nm]', '$R_y$ [nrad]'}, ' %.0f '); #+end_src -** $D_y$ - Lateral Scans +**** Fast Tomography scans + +A tomography experiment was then performed with the highest rotational velocity of the Spindle: $180\,\text{deg/s}$[fn:7]. +The measured position of the "point of interest" during the experiment is shown in Figure ref:fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp. + +#+begin_src matlab +%% Experimental Results for Tomography at 30RPM, no payload +data_tomo_m0_Wz180 = load('2023-08-17_15-26_tomography_30rpm_m0_robust.mat'); + +[~, i_m0] = find(data_tomo_m0_Wz180.hac_status == 1); +[x_m0, y_m0, R_m0] = circlefit(data_tomo_m0_Wz180.Dx_int(1:i_m0), data_tomo_m0_Wz180.Dy_int(1:i_m0)); +fun = @(theta)rms((data_tomo_m0_Wz180.Dx_int(1:i_m0) - (x_m0 + R_m0*cos(data_tomo_m0_Wz180.Rz(1:i_m0)+theta(1)))).^2 + ... + (data_tomo_m0_Wz180.Dy_int(1:i_m0) - (y_m0 + R_m0*sin(data_tomo_m0_Wz180.Rz(1:i_m0)+theta(1)))).^2); +delta_theta_m0 = fminsearch(fun, 0); +#+end_src + +#+begin_src matlab :exports none :results none +%% Tomography at 180deg/s - Errors in the X/Y plane +figure; +hold on; +plot(1e6*data_tomo_m0_Wz180.Dx_int(1:i_m0), 1e6*data_tomo_m0_Wz180.Dy_int(1:i_m0), 'DisplayName', 'OL') +plot(1e6*data_tomo_m0_Wz180.Dx_int(i_m0:i_m0+1e4), 1e6*data_tomo_m0_Wz180.Dy_int(i_m0:i_m0+1e4), 'color', colors(3,:), 'HandleVisibility', 'off') +plot(1e6*data_tomo_m0_Wz180.Dx_int(i_m0+1e4:end), 1e6*data_tomo_m0_Wz180.Dy_int(i_m0+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') +theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] +plot(1e6*(x_m0 + R_m0*cos(theta)), 1e6*(y_m0 + R_m0*sin(theta)), 'k--', 'DisplayName', 'Circ. Fit') +hold off; +xlabel('$D_x$ [$\mu$m]'); ylabel('$D_y$ [$\mu$m]'); +axis equal +xlim([-3, 3]); ylim([-3, 3]); +xticks([-3:1:3]); +yticks([-3:1:3]); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.pdf', 'width', 'half', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Tomography at 180deg/s - Errors in the Y/Z plane +figure; +tiledlayout(2, 1, 'TileSpacing', 'compact', 'Padding', 'None'); + +ax1 = nexttile(); +hold on; +plot(1e6*data_tomo_m0_Wz180.Dy_int(1:i_m0), 1e6*data_tomo_m0_Wz180.Dz_int(1:i_m0), 'DisplayName', 'OL') +plot(1e6*data_tomo_m0_Wz180.Dy_int(i_m0:i_m0+1e4), 1e6*data_tomo_m0_Wz180.Dz_int(i_m0:i_m0+1e4), 'color', colors(3,:), 'HandleVisibility', 'off') +plot(1e6*data_tomo_m0_Wz180.Dy_int(i_m0+1e4:end), 1e6*data_tomo_m0_Wz180.Dz_int(i_m0+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') +% theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] +% plot(0.1*cos(theta), 0.05*sin(theta), 'k-', 'DisplayName', 'Best Fit') +hold off; +xlabel('$D_y$ [$\mu$m]'); ylabel('$D_z$ [$\mu$m]'); +axis equal +xlim([-3, 3]); ylim([-0.6, 0.6]); +xticks([-3:1:3]); +yticks([-3:0.3:3]); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; + +ax2 = nexttile(); +hold on; +plot(1e9*data_tomo_m0_Wz180.Dy_int(i_m0+1e4:end), 1e9*data_tomo_m0_Wz180.Dz_int(i_m0+1e4:end), 'color', colors(2,:), 'DisplayName', 'CL') +theta = linspace(0, 2*pi, 500); % Angle to plot the circle [rad] +plot(100*cos(theta), 50*sin(theta), 'k--', 'DisplayName', 'Beam size') +hold off; +xlabel('$D_y$ [nm]'); ylabel('$D_z$ [nm]'); +axis equal +xlim([-300, 300]); ylim([-100, 100]); +% xticks([-3:1:3]); +% yticks([-3:1:3]); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.pdf', 'width', 'half', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp +#+caption: Experimental results of a tomography experiment at 180 deg/s without payload. Position error of the sample is shown in the XY (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}) and YZ (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}) planes. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}XY plane} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :scale 0.9 +[[file:figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}YZ plane} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :scale 0.9 +[[file:figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png]] +#+end_subfigure +#+end_figure + +Even though the simulation (Figure ref:fig:test_id31_tomo_m0_30rpm_robust_hac_iff_sim) and the experimental results (Figure ref:fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp) are looking similar, the most important metric to compare is the RMS values of the positioning errors in closed-loop. +These are computed for both the simulation and the experimental results and are compared in Table ref:tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms. +The lateral and vertical errors are similar, however the tilt ($R_y$) errors are underestimated by the model, which is reasonable as disturbances in $R_y$ were not modeled. +Results obtained with this robust (i.e. conservative) HAC are already close to the specifications. + +#+name: tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms +#+caption: RMS values of the errors for a tomography experiment at 30RPM and without payload. Experimental results and simulation are compared. +#+attr_latex: :environment tabularx :width 0.7\linewidth :align Xccc +#+attr_latex: :center t :booktabs t +| | $D_y$ | $D_z$ | $R_y$ | +|-----------------+-----------------------+--------------------+------------------------| +| Experiment (OL) | $1.8\,\mu\text{mRMS}$ | $24\,\text{nmRMS}$ | $10\,\mu\text{radRMS}$ | +|-----------------+-----------------------+--------------------+------------------------| +| Simulation (CL) | $30\,\text{nmRMS}$ | $8\,\text{nmRMS}$ | $73\,\text{nradRMS}$ | +| Experiment (CL) | $39\,\text{nmRMS}$ | $11\,\text{nmRMS}$ | $130\,\text{nradRMS}$ | +|-----------------+-----------------------+--------------------+------------------------| +| Specifications | $30\,\text{nmRMS}$ | $15\,\text{nmRMS}$ | $250\,\text{nradRMS}$ | + +**** Dynamic Error Budgeting + +In this section, the noise budget is performed. +The vibrations of the sample is measured in different conditions using the external metrology. + +- Effect of rotation. +- Comparison with measurement noise: should be higher +- Maybe say that we then focus on the high rotation velocity +- Also say that for the RMS errors, we don't take into account drifts (so we NASS we can correct drifts) +- Focus on 30rpm case + +#+begin_src matlab +%% Load measured vibrations in Open-Loop +data_ol_Wz0 = load('2023-08-11_16-51_m0_lac_off.mat'); % no rotation +data_ol_Wz36 = load('2023-08-11_17-18_m0_lac_off_1rpm.mat'); % 6 deg/s +data_ol_Wz180 = load('2023-08-11_17-39_m0_lac_off_30rpm.mat'); % 180 deg/s +#+end_src + +#+begin_src matlab +figure; +hold on; +% plot(detrend(data_ol_Wz0.Dx_int, 0), detrend(data_ol_Wz0.Dy_int, 0)) +plot(detrend(movmean(data_ol_Wz36.Dx_int, 1e4), 0), detrend(movmean(data_ol_Wz36.Dy_int, 1e4), 0)) +% plot(detrend(data_ol_Wz180.Dx_int, 0), detrend(data_ol_Wz180.Dy_int, 0)) +#+end_src + +#+begin_src matlab +figure; +hold on; +plot(1e-4*(1:length(data_ol_Wz0.Dz_int)), detrend(data_ol_Wz0.Dz_int, 0)) +plot(1e-4*(1:length(data_ol_Wz36.Dz_int)), detrend(data_ol_Wz36.Dz_int, 0)) +plot(1e-4*(1:length(data_ol_Wz180.Dz_int)), detrend(data_ol_Wz180.Dz_int, 0)) +#+end_src + +#+begin_src matlab +%% Compute the motion in the X-Y-Z-Rx-Ry directions +% Coordinate transform +J_int_to_X = [ 0 0 -0.787401574803149 -0.212598425196851 0; + 0.78740157480315 0.21259842519685 0 0 0; + 0 0 0 0 -1; + -13.1233595800525 13.1233595800525 0 0 0; + 0 0 -13.1233595800525 13.1233595800525 0]; + +a = J_int_to_X*[data_ol_Wz0.d1; data_ol_Wz0.d2; data_ol_Wz0.d3; data_ol_Wz0.d4; data_ol_Wz0.d5]; +data_ol_Wz0.Dx_int = a(1,:); +data_ol_Wz0.Dy_int = a(2,:); +data_ol_Wz0.Dz_int = a(3,:); +data_ol_Wz0.Rx_int = a(4,:); +data_ol_Wz0.Ry_int = a(5,:); + +a = J_int_to_X*[data_ol_Wz36.d1; data_ol_Wz36.d2; data_ol_Wz36.d3; data_ol_Wz36.d4; data_ol_Wz36.d5]; +data_ol_Wz36.Dx_int = a(1,:); +data_ol_Wz36.Dy_int = a(2,:); +data_ol_Wz36.Dz_int = a(3,:); +data_ol_Wz36.Rx_int = a(4,:); +data_ol_Wz36.Ry_int = a(5,:); + +a = J_int_to_X*[data_ol_Wz180.d1; data_ol_Wz180.d2; data_ol_Wz180.d3; data_ol_Wz180.d4; data_ol_Wz180.d5]; +data_ol_Wz180.Dx_int = a(1,:); +data_ol_Wz180.Dy_int = a(2,:); +data_ol_Wz180.Dz_int = a(3,:); +data_ol_Wz180.Rx_int = a(4,:); +data_ol_Wz180.Ry_int = a(5,:); + +%% Computed the power spectral density of the measured motion +% Hannning Windows +Nfft = floor(20.0/Ts); +win = hanning(Nfft); +Noverlap = floor(Nfft/2); + +[data_ol_Wz0.pxx_Dx, data_ol_Wz0.f] = pwelch(detrend(data_ol_Wz0.Dx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz0.pxx_Dy, ~ ] = pwelch(detrend(data_ol_Wz0.Dy_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz0.pxx_Dz, ~ ] = pwelch(detrend(data_ol_Wz0.Dz_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz0.pxx_Rx, ~ ] = pwelch(detrend(data_ol_Wz0.Rx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz0.pxx_Ry, ~ ] = pwelch(detrend(data_ol_Wz0.Ry_int, 0), win, Noverlap, Nfft, 1/Ts); + +[data_ol_Wz36.pxx_Dx, data_ol_Wz36.f] = pwelch(detrend(data_ol_Wz36.Dx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz36.pxx_Dy, ~ ] = pwelch(detrend(data_ol_Wz36.Dy_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz36.pxx_Dz, ~ ] = pwelch(detrend(data_ol_Wz36.Dz_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz36.pxx_Rx, ~ ] = pwelch(detrend(data_ol_Wz36.Rx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz36.pxx_Ry, ~ ] = pwelch(detrend(data_ol_Wz36.Ry_int, 0), win, Noverlap, Nfft, 1/Ts); + +[data_ol_Wz180.pxx_Dx, data_ol_Wz180.f] = pwelch(detrend(data_ol_Wz180.Dx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz180.pxx_Dy, ~ ] = pwelch(detrend(data_ol_Wz180.Dy_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz180.pxx_Dz, ~ ] = pwelch(detrend(data_ol_Wz180.Dz_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz180.pxx_Rx, ~ ] = pwelch(detrend(data_ol_Wz180.Rx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_ol_Wz180.pxx_Ry, ~ ] = pwelch(detrend(data_ol_Wz180.Ry_int, 0), win, Noverlap, Nfft, 1/Ts); +#+end_src + +#+begin_src matlab :exports none :results none +%% Cumulative Amplitude Spectrum - Open-Loop - Dy +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +hold on; +plot(data_ol_Wz0.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz0.f), flip(data_ol_Wz0.pxx_Dy)))), ... + 'DisplayName', sprintf('0rpm: $%.0f nm$', 1e9*rms(detrend(data_ol_Wz0.Dy_int, 0)))); +plot(data_ol_Wz36.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz36.f), flip(data_ol_Wz36.pxx_Dy)))), ... + 'DisplayName', sprintf('6rpm: $%.0f nm$', 1e9*rms(detrend(data_ol_Wz36.Dy_int, 0)))); +plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Dy)))), ... + 'DisplayName', sprintf('30rpm: $%.1f \\mu m$', 1e6*rms(detrend(data_ol_Wz180.Dy_int, 0)))); +plot([1e-2, 1e4], 1e-9*[specs_dy_rms, specs_dy_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm', specs_dy_rms)) +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('CAS [m]'); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xticks([1e0, 1e1, 1e2]); yticks([1e-9, 1e-8, 1e-7, 1e-6]); +xlim([0.1, 5e2]); ylim([1e-10, 3e-6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_hac_cas_ol_dy.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Cumulative Amplitude Spectrum - Open-Loop - Dz +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +hold on; +plot(data_ol_Wz0.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz0.f), flip(data_ol_Wz0.pxx_Dz)))), ... + 'DisplayName', sprintf('0rpm: $%.0f nm$', 1e9*rms(detrend(data_ol_Wz0.Dz_int, 0)))); +plot(data_ol_Wz36.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz36.f), flip(data_ol_Wz36.pxx_Dz)))), ... + 'DisplayName', sprintf('6rpm: $%.0f nm$', 1e9*rms(detrend(data_ol_Wz36.Dz_int, 0)))); +plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Dz)))), ... + 'DisplayName', sprintf('30rpm: $%.0f nm$', 1e9*rms(detrend(data_ol_Wz180.Dz_int, 0)))); +plot([1e-2, 1e4], 1e-9*[specs_dz_rms, specs_dz_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm', specs_dz_rms)) +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('CAS [m]'); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xticks([1e0, 1e1, 1e2]); yticks([1e-9, 1e-8, 1e-7, 1e-6]); +xlim([0.1, 5e2]); ylim([1e-10, 3e-6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_hac_cas_ol_dz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Cumulative Amplitude Spectrum - Open-Loop - Ry +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +hold on; +plot(data_ol_Wz0.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz0.f), flip(data_ol_Wz0.pxx_Ry)))), ... + 'DisplayName', sprintf('0rpm: $%.2f \\mu$rad', 1e6*rms(detrend(data_ol_Wz0.Ry_int, 0)))); +plot(data_ol_Wz36.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz36.f), flip(data_ol_Wz36.pxx_Ry)))), ... + 'DisplayName', sprintf('6rpm: $%.2f \\mu$rad', 1e6*rms(detrend(data_ol_Wz36.Ry_int, 0)))); +plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Ry)))), ... + 'DisplayName', sprintf('30rpm: $%.0f \\mu$rad', 1e6*rms(detrend(data_ol_Wz180.Ry_int, 0)))); +plot([1e-2, 1e4], 1e-6*[specs_ry_rms, specs_ry_rms], 'k--', 'DisplayName', sprintf('Spec: $%.2f \\mu$rad', specs_ry_rms)) +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('CAS [rad]'); +leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xticks([1e0, 1e1, 1e2]); yticks([1e-9, 1e-8, 1e-7, 1e-6]); +xlim([0.1, 5e2]); ylim([1e-10, 3e-6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_hac_cas_ol_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_hac_cas_ol +#+caption: Cumulative Amplitude Spectrum of the measured positioning errors without any rotation, with $\Omega_z = 36\,\text{deg}/s$ and with $\Omega_z = 180\,\text{deg}/s$. Open-loop case. RMS values are indicated in the legend. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_hac_cas_ol_dy} $D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_hac_cas_ol_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_hac_cas_ol_dz} $D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_hac_cas_ol_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_hac_cas_ol_ry} $R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_hac_cas_ol_ry.png]] +#+end_subfigure +#+end_figure + +Effect of LAC: +- reduce amplitude around 80Hz +- Inject some noise between 200 and 700Hz? + +Effect of HAC: +- Bandwidth is approximately 10Hz + +#+begin_src matlab +%% Effect of LAC - 180 deg/s + +% Load measured noise +data_lac_Wz180 = load('2023-08-11_17-36_m0_lac_on_30rpm.mat'); + +a = J_int_to_X*[data_lac_Wz180.d1; data_lac_Wz180.d2; data_lac_Wz180.d3; data_lac_Wz180.d4; data_lac_Wz180.d5]; +data_lac_Wz180.Dx_int = a(1,:); +data_lac_Wz180.Dy_int = a(2,:); +data_lac_Wz180.Dz_int = a(3,:); +data_lac_Wz180.Rx_int = a(4,:); +data_lac_Wz180.Ry_int = a(5,:); + +[data_lac_Wz180.pxx_Dx, data_lac_Wz180.f] = pwelch(detrend(data_lac_Wz180.Dx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_lac_Wz180.pxx_Dy, ~ ] = pwelch(detrend(data_lac_Wz180.Dy_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_lac_Wz180.pxx_Dz, ~ ] = pwelch(detrend(data_lac_Wz180.Dz_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_lac_Wz180.pxx_Rx, ~ ] = pwelch(detrend(data_lac_Wz180.Rx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_lac_Wz180.pxx_Ry, ~ ] = pwelch(detrend(data_lac_Wz180.Ry_int, 0), win, Noverlap, Nfft, 1/Ts); + +%% Effect of HAC - 180 deg/s +% Load measured noise +data_hac_Wz180 = load('2023-08-11_16-49_m0_hac_on.mat'); + +a = J_int_to_X*[data_hac_Wz180.d1; data_hac_Wz180.d2; data_hac_Wz180.d3; data_hac_Wz180.d4; data_hac_Wz180.d5]; +data_hac_Wz180.Dx_int = a(1,:); +data_hac_Wz180.Dy_int = a(2,:); +data_hac_Wz180.Dz_int = a(3,:); +data_hac_Wz180.Rx_int = a(4,:); +data_hac_Wz180.Ry_int = a(5,:); + +[data_hac_Wz180.pxx_Dx, data_hac_Wz180.f] = pwelch(detrend(data_hac_Wz180.Dx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_hac_Wz180.pxx_Dy, ~ ] = pwelch(detrend(data_hac_Wz180.Dy_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_hac_Wz180.pxx_Dz, ~ ] = pwelch(detrend(data_hac_Wz180.Dz_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_hac_Wz180.pxx_Rx, ~ ] = pwelch(detrend(data_hac_Wz180.Rx_int, 0), win, Noverlap, Nfft, 1/Ts); +[data_hac_Wz180.pxx_Ry, ~ ] = pwelch(detrend(data_hac_Wz180.Ry_int, 0), win, Noverlap, Nfft, 1/Ts); +#+end_src + +#+begin_src matlab :exports none :results none +%% Cumulative Amplitude Spectrum - Closed-Loop - Dy +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +hold on; +plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Dy)))), 'DisplayName', sprintf('OL $%.1f \\mu m$', 1e6*rms(detrend(data_ol_Wz180.Dy_int, 0)))); +plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Dy)))), 'DisplayName', sprintf('LAC $%.1f \\mu m$', 1e6*rms(detrend(data_lac_Wz180.Dy_int, 0)))); +plot(data_hac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_hac_Wz180.f), flip(data_hac_Wz180.pxx_Dy)))), 'DisplayName', sprintf('HAC $%.0f nm$', 1e9*rms(detrend(data_hac_Wz180.Dy_int, 0)))); +plot([1e-2, 1e4], 1e-9*[specs_dy_rms, specs_dy_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm', specs_dy_rms)) +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('CAS [rad]'); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xticks([1e0, 1e1, 1e2]); yticks([1e-9, 1e-8, 1e-7, 1e-6]); +xlim([0.1, 5e2]); ylim([1e-10, 3e-6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_hac_cas_cl_dy.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Cumulative Amplitude Spectrum - Closed-Loop - Dz +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +hold on; +plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Dz)))), 'DisplayName', sprintf('OL $%.0f nm$', 1e9*rms(detrend(data_ol_Wz180.Dz_int, 0)))); +plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Dz)))), 'DisplayName', sprintf('LAC $%.0f nm$', 1e9*rms(detrend(data_lac_Wz180.Dz_int, 0)))); +plot(data_hac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_hac_Wz180.f), flip(data_hac_Wz180.pxx_Dz)))), 'DisplayName', sprintf('HAC $%.0f nm$', 1e9*rms(detrend(data_hac_Wz180.Dz_int, 0)))); +plot([1e-2, 1e4], 1e-9*[specs_dz_rms, specs_dz_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm', specs_dz_rms)) +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('CAS [rad]'); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xticks([1e0, 1e1, 1e2]); yticks([1e-9, 1e-8, 1e-7, 1e-6]); +xlim([0.1, 5e2]); ylim([1e-10, 3e-6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_hac_cas_cl_dz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Cumulative Amplitude Spectrum - Closed-Loop - Ry +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +hold on; +plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Ry)))), 'DisplayName', sprintf('OL $%.0f \\mu$rad', 1e6*rms(detrend(data_ol_Wz180.Ry_int, 0)))); +plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Ry)))), 'DisplayName', sprintf('LAC $%.0f \\mu$rad', 1e6*rms(detrend(data_lac_Wz180.Ry_int, 0)))); +plot(data_hac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_hac_Wz180.f), flip(data_hac_Wz180.pxx_Ry)))), 'DisplayName', sprintf('HAC $%.2f \\mu$rad', 1e6*rms(detrend(data_hac_Wz180.Ry_int, 0)))); +plot([1e-2, 1e4], 1e-6*[specs_ry_rms, specs_ry_rms], 'k--', 'DisplayName', sprintf('Spec: $%.2f \\mu$rad', specs_ry_rms)) +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('CAS [rad]'); +leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xticks([1e0, 1e1, 1e2]); yticks([1e-9, 1e-8, 1e-7, 1e-6]); +xlim([0.1, 5e2]); ylim([1e-10, 3e-6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_hac_cas_cl_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_hac_cas_cl +#+caption: Cumulative Amplitude Spectrum for tomography experiments at $180\,\text{deg}/s$. Open-Loop case, IFF, and HAC-LAC are compared. Specifications are indicated by black dashed lines. RSM values are indicated in the legend. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_hac_cas_cl_dy} $D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_hac_cas_cl_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_hac_cas_cl_dz} $D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_hac_cas_cl_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_hac_cas_cl_ry} $R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_hac_cas_cl_ry.png]] +#+end_subfigure +#+end_figure + +** Reflectivity Scans +<> + +X-ray reflectivity consists of scanning the $R_y$ angle of thin structures (typically solid/liquid interfaces) through the beam. +Here, a $R_y$ scan is performed with a rotational velocity of $100\,\mu rad/s$ and the positioning errors in closed-loop are recorded (Figure ref:fig:test_id31_reflectivity). +It is shown that the NASS is able to keep the point of interest in the beam within specifications. + +#+begin_src matlab +%% Load data for the reflectivity scan +data_ry = load("2023-08-18_15-24_first_reflectivity_m0.mat"); +data_ry.time = Ts*[0:length(data_ry.Ry_int)-1]; +#+end_src + +#+begin_src matlab :exports none :results none +%% Ry reflectivity scan - Lateral error +figure; +hold on; +plot(data_ry.time, 1e9*data_ry.e_dy, 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nm RMS', 1e9*rms(data_ry.e_dy))) +plot([0, 6.2], [specs_dy_peak, specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +plot([0, 6.2], [-specs_dy_peak, -specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +hold off; +xlabel('Time [s]'); +ylabel('$D_y$ error [nm]') +% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +xlim([0, 6.2]); +ylim([-150, 150]); +xticks([0:2:6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_reflectivity_dy.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Ry reflectivity scan - Vertical error +figure; +hold on; +plot(data_ry.time, 1e9*data_ry.e_dz, 'DisplayName', sprintf('$\\epsilon D_z = %.0f$ nm RMS', 1e9*rms(data_ry.e_dz))) +plot([0, 6.2], [specs_dz_peak, specs_dz_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +plot([0, 6.2], [-specs_dz_peak, -specs_dz_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +hold off; +xlabel('Time [s]'); +ylabel('$D_z$ error [nm]') +% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +xlim([0, 6.2]); +ylim([-100, 100]); +xticks([0:2:6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_reflectivity_dz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Ry reflectivity scan - Setpoint and Error +figure; +yyaxis left +hold on; +plot(data_ry.time, 1e6*data_ry.e_ry, 'DisplayName', '$\epsilon_{R_y}$') +plot([0, 6.2], [specs_ry_peak, specs_ry_peak], '--', 'HandleVisibility', 'off'); +plot([0, 6.2], [-specs_ry_peak, -specs_ry_peak], '--', 'HandleVisibility', 'off'); +hold off; +ylim([-2, 2]) +ylabel('$R_y$ error [$\mu$rad]') +yyaxis right +hold on; +plot(data_ry.time, 1e6*data_ry.Ry_int, 'DisplayName', '$R_y$') +plot(data_ry.time, 1e6*data_ry.m_hexa_ry, 'k--', 'DisplayName', 'Setpoint') +hold off; +xlabel('Time [s]'); +ylabel('$R_y$ motion [$\mu$rad]') +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xlim([0, 6.2]); +ylim([-310, 310]); +xticks([0:2:6]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_reflectivity_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_reflectivity +#+caption: Reflectivity scan ($R_y$) with a rotational velocity of $100\,\mu \text{rad}/s$. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_reflectivity_dy}$D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_reflectivity_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_reflectivity_dz}$D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_reflectivity_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_reflectivity_ry}$R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_reflectivity_ry.png]] +#+end_subfigure +#+end_figure + + +** Dirty Layer Scans +<> +**** Introduction :ignore: + +In some cases, samples are composed of several atomic "layers" that are first aligned in the horizontal plane with precise $R_y$ positioning and that are then scanned vertically with precise $D_z$ motion. +The vertical scan can be performed continuously of using step-by-step motion. + +**** Step by Step $D_z$ motion + +Vertical steps are here performed using the nano-hexapod only. +Step sizes from $10\,nm$ to $1\,\mu m$ are tested, and the results are shown in Figure ref:fig:test_id31_dz_mim_steps. +10nm steps can be resolved if detectors are integrating over 50ms (see red curve in Figure ref:fig:test_id31_dz_mim_10nm_steps), which is reasonable for many experiments. + +When doing step-by-step scans, the time to reach the next value is quite critical as long settling time can render the total experiment excessively long. +The response time to reach the wanted value (to within $\pm 20\,nm$) is around $70\,ms$ as shown with the $1\,\mu m$ step response in Figure ref:fig:test_id31_dz_mim_1000nm_steps. + +#+begin_src matlab +%% Load Dz steps data +data_dz_steps_10nm = load("2023-08-18_14-57_dz_mim_10_nm.mat"); +data_dz_steps_10nm.time = Ts*[0:length(data_dz_steps_10nm.Dz_int)-1]; + +data_dz_steps_100nm = load("2023-08-18_14-57_dz_mim_100_nm.mat"); +data_dz_steps_100nm.time = Ts*[0:length(data_dz_steps_100nm.Dz_int)-1]; + +data_dz_steps_1000nm = load("2023-08-18_14-57_dz_mim_1000_nm.mat"); +data_dz_steps_1000nm.time = Ts*[0:length(data_dz_steps_1000nm.Dz_int)-1]; +#+end_src + +#+begin_src matlab :exports none :results none +%% Dz MIM test with 10nm steps +figure; +hold on; +plot(data_dz_steps_10nm.time, 1e9*(data_dz_steps_10nm.Dz_int - mean(data_dz_steps_10nm.Dz_int(1:1000))), 'DisplayName', '$D_z$') +plot(data_dz_steps_10nm.time, 1e9*lsim(1/(1 + s/2/pi/20), data_dz_steps_10nm.Dz_int - mean(data_dz_steps_10nm.Dz_int(1:1000)), data_dz_steps_10nm.time), 'DisplayName', '$D_z$ (LPF)') +plot(data_dz_steps_10nm.time, 1e9*(data_dz_steps_10nm.m_hexa_dz-data_dz_steps_10nm.m_hexa_dz(1)), 'k--', 'DisplayName', 'Setpoint') +hold off; +xlabel('Time [s]'); +ylabel('$D_z$ Motion [nm]'); +legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +xlim([0, 0.6]); +ylim([-10, 40]); +xticks([0:0.2:0.6]); +yticks([-10:10:50]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_mim_10nm_steps.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Dz MIM test with 100nm steps +figure; +hold on; +plot(data_dz_steps_100nm.time, 1e9*(data_dz_steps_100nm.Dz_int - mean(data_dz_steps_100nm.Dz_int(1:1000))), 'DisplayName', '$D_z$') +plot(data_dz_steps_100nm.time, 1e9*(data_dz_steps_100nm.m_hexa_dz-data_dz_steps_100nm.m_hexa_dz(1)), 'k--', 'DisplayName', 'Setpoint') +hold off; +xlabel('Time [s]'); +ylabel('$D_z$ Motion [nm]'); +legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +xlim([0, 0.6]); +% ylim([-10, 40]); +xticks([0:0.2:0.6]); +yticks([-0:100:300]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_mim_100nm_steps.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Dz step response - Stabilization time is around 70ms +figure; +[~, i] = find(data_dz_steps_1000nm.m_hexa_dz>data_dz_steps_1000nm.m_hexa_dz(1)); +i0 = i(1); + +figure; +hold on; +plot(1e3*(data_dz_steps_1000nm.time-data_dz_steps_1000nm.time(i0)), 1e6*(data_dz_steps_1000nm.Dz_int - mean(data_dz_steps_1000nm.Dz_int(1:1000)))) +plot(1e3*[-1, 1], 1e-3*[1000-20, 1000-20], 'k--') +plot(1e3*[-1, 1], 1e-3*[1000+20, 1000+20], 'k--') +xline(0, 'k--', 'LineWidth', 1.5) +xline(70, 'k--', 'LineWidth', 1.5) +hold off; +xlabel('Time [ms]'); +ylabel('$D_z$ Motion [$\mu$m]'); +xlim([-10, 140]); +ylim([-0.1, 1.6]) +xticks([0, 70]) +yticks([0, 1]) +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_mim_1000nm_steps.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_dz_mim_steps +#+caption: Vertical steps performed with the nano-hexapod. 10nm steps are shown in (\subref{fig:test_id31_dz_mim_10nm_steps}) with the low pass filtered data corresponding to an integration time of $50\,ms$. 100nm steps are shown in (\subref{fig:test_id31_dz_mim_100nm_steps}). The response time to reach a peak to peak error of $\pm 20\,nm$ is $\approx 70\,ms$ as shown in (\subref{fig:test_id31_dz_mim_1000nm_steps}) for a $1\,\mu m$ step. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_mim_10nm_steps}10nm steps} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_mim_10nm_steps.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_mim_100nm_steps}100nm steps} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_mim_100nm_steps.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_mim_1000nm_steps}$1\,\mu$m step} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_mim_1000nm_steps.png]] +#+end_subfigure +#+end_figure + +**** Continuous $D_z$ motion: Dirty Layer Scans + +- [ ] In this section and the following experiments, the NASS performs "ramp scans" (i.e. constant velocity scans). + In order to have no tracking errors, two integrators needs to be present in the feedback loop. + As the plant present not integral action at low frequency, two integrators are included in the controller. + +Instead of performing "step-by-step" scans, continuous scans can also be performed in the vertical direction. +At $10\,\mu m/s$, the errors are well within the specifications (see Figure ref:fig:test_id31_dz_scan_10ums). + +#+begin_src matlab +%% Dirty layer scans - 10um/s +data_dz_10ums = load("2023-08-18_15-33_dirty_layer_m0_small.mat"); +data_dz_10ums.time = Ts*[0:length(data_dz_10ums.Dz_int)-1]; + +%% Dirty layer scans - 100um/s +data_dz_100ums = load("2023-08-18_15-32_dirty_layer_m0.mat"); +data_dz_100ums.time = Ts*[0:length(data_dz_100ums.Dz_int)-1]; +#+end_src + +#+begin_src matlab :exports none :results none +%% Dz scan at 10um/s - Lateral error +figure; +hold on; +plot(data_dz_10ums.time, 1e9*data_dz_10ums.e_dy, 'DisplayName', sprintf('$\\epsilon D_y: %.0f$ nm RMS', 1e9*rms(data_dz_10ums.e_dy))) +plot([0, 2.2], [specs_dy_peak, specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +plot([0, 2.2], [-specs_dy_peak, -specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +hold off; +xlabel('Time [s]'); +ylabel('$D_y$ error [nm]') +% leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +% leg.ItemTokenSize(1) = 15; +xlim([0, 2.2]); +ylim([-150, 150]) +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_scan_10ums_dy.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Dz scan at 10um/s - Vertical error +figure; +yyaxis left +hold on; +plot(data_dz_10ums.time, 1e9*data_dz_10ums.e_dz, 'DisplayName', '$\epsilon_{D_z}$') +plot([0, 2.2], [specs_dz_peak, specs_dz_peak], '--', 'HandleVisibility', 'off'); +plot([0, 2.2], [-specs_dz_peak, -specs_dz_peak], '--', 'HandleVisibility', 'off'); +hold off; +ylabel('$D_z$ error [nm]'); +ylim([-100, 100]); +yticks([-50:50:50]); +yyaxis right +hold on; +plot(data_dz_10ums.time, 1e6*(data_dz_10ums.Dz_int), 'DisplayName', '$D_z$') +plot(data_dz_10ums.time, 1e6*(data_dz_10ums.m_hexa_dz), 'k--', 'DisplayName', 'Setpoint') +hold off; +xlabel('Time [s]'); +ylabel('$D_z$ Motion [$\mu$m]'); +leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xlim([0, 2.2]); +ylim([-10, 10]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_scan_10ums_dz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Dz scan at 10um/s - Ry error +figure; +hold on; +plot(data_dz_10ums.time, 1e6*data_dz_10ums.e_ry, 'DisplayName', sprintf('$\\epsilon R_y: %.2f \\mu$rad RMS', 1e6*rms(data_dz_10ums.e_ry))) +plot([0, 2.2], [specs_ry_peak, specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +plot([0, 2.2], [-specs_ry_peak, -specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +hold off; +xlabel('Time [s]'); +ylabel('$R_y$ error [$\mu$rad]') +% leg = legend('location', 'north', 'FontSize', 8, 'NumColumns', 1); +% leg.ItemTokenSize(1) = 15; +xlim([0, 2.2]); +ylim([-2, 2]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_scan_10ums_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_dz_scan_10ums +#+caption: $D_z$ scan with a velocity of $10\,\mu m/s$. $D_z$ setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_10ums_dz}). Errors in $D_y$ and $R_y$ are respectively shown in (\subref{fig:test_id31_dz_scan_10ums_dy}) and (\subref{fig:test_id31_dz_scan_10ums_ry}) +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_10ums_dy}$D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_scan_10ums_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_10ums_dz}$D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_scan_10ums_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_10ums_ry}$R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_scan_10ums_ry.png]] +#+end_subfigure +#+end_figure + +The second tested velocity is $100\,\mu m/s$, which is the fastest velocity for $D_z$ scans when the ultimate performances is wanted (corresponding to a 1ms integration time and 100nm "resolution"). +At this velocity, the positioning errors are also within the specifications except for the very start and very end of the motion (i.e. during acceleration/deceleration phases, see Figure ref:fig:test_id31_dz_scan_100ums). +However, the detectors are usually triggered only during the constant velocity phase, so this is not not an issue. +The performances during acceleration phase may also be improved by using a feedforward controller. + +#+begin_src matlab :exports none :results none +%% Ry reflectivity scan - Vertical error +figure; +hold on; +plot(data_dz_100ums.time, 1e9*data_dz_100ums.e_dy, 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nm RMS', 1e9*rms(data_dz_100ums.e_dy))) +plot([0, 2.2], [specs_dy_peak, specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +plot([0, 2.2], [-specs_dy_peak, -specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +hold off; +xlabel('Time [s]'); +ylabel('$D_y$ error [nm]') +% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +xlim([0, 2.2]); +ylim([-150, 150]) +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_scan_100ums_dy.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +figure; +yyaxis left +hold on; +plot(data_dz_100ums.time, 1e9*data_dz_100ums.e_dz, 'DisplayName', '$\epsilon_{d_z}$') +plot([0, 2.2], [specs_dz_peak, specs_dz_peak], '--', 'HandleVisibility', 'off'); +plot([0, 2.2], [-specs_dz_peak, -specs_dz_peak], '--', 'HandleVisibility', 'off'); +hold off; +ylabel('$D_z$ error [nm]'); +ylim([-100, 100]); +yticks([-50:50:50]); +yyaxis right +hold on; +plot(data_dz_100ums.time, 1e6*(data_dz_100ums.Dz_int), 'DisplayName', '$D_z$') +plot(data_dz_100ums.time, 1e6*(data_dz_100ums.m_hexa_dz), 'k--', 'DisplayName', 'Setpoint') +hold off; +xlabel('Time [s]'); +ylabel('$D_z$ Motion [$\mu$m]'); +leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xlim([0, 2.2]); +ylim([-100, 100]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_scan_100ums_dz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Ry reflectivity scan - Vertical error +figure; +hold on; +plot(data_dz_100ums.time, 1e6*data_dz_100ums.e_ry, 'DisplayName', sprintf('$\\epsilon R_y = %.2f \\mu$rad RMS', 1e6*rms(data_dz_100ums.e_ry))) +plot([0, 2.2], [specs_ry_peak, specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +plot([0, 2.2], [-specs_ry_peak, -specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); +hold off; +xlabel('Time [s]'); +ylabel('$R_y$ error [$\mu$rad]') +% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +xlim([0, 2.2]); +ylim([-2, 2]) +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_dz_scan_100ums_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_dz_scan_100ums +#+caption: $D_z$ scan with a velocity of $100\,\mu m/s$. $D_z$ setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_100ums_dz}). Errors in $D_y$ and $R_y$ are respectively shown in (\subref{fig:test_id31_dz_scan_100ums_dy}) and (\subref{fig:test_id31_dz_scan_100ums_ry}) +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_100ums_dy}$D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_scan_100ums_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_100ums_dz}$D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_scan_100ums_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_100ums_ry}$R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dz_scan_100ums_ry.png]] +#+end_subfigure +#+end_figure + +**** Summary + +#+begin_src matlab +%% Performances for Dz scans +% Determine when the motion starts and stops +i_dz_10ums = abs(diff(data_dz_10ums.m_hexa_dz)/Ts-10e-6) < 10*eps; +i_dz_100ums = abs(diff(data_dz_100ums.m_hexa_dz)/Ts-100e-6) < 10*eps; +% i_dz_10ums = data_dz_10ums.m_hexa_dz>data_dz_10ums.m_hexa_dz(1) & data_dz_10ums.m_hexa_dzdata_dz_100ums.m_hexa_dz(1) & data_dz_100ums.m_hexa_dz> **** Introduction :ignore: Lateral scans are performed with the $T_y$ stage. @@ -4301,494 +5076,7 @@ data2orgtable([ | 100um/s (OL) | 2687.67 | 328.45 | 11.26 | | 100um/s (CL) | 1339.31 | 69.5 | 0.91 | -** $D_z$ scans: Dirty Layer Scans -<> -**** Introduction :ignore: - -In some cases, samples are composed of several atomic "layers" that are first aligned in the horizontal plane with precise $R_y$ positioning and that are then scanned vertically with precise $D_z$ motion. -The vertical scan can be performed continuously of using step-by-step motion. - -**** Step by Step $D_z$ motion - -Vertical steps are here performed using the nano-hexapod only. -Step sizes from $10\,nm$ to $1\,\mu m$ are tested, and the results are shown in Figure ref:fig:test_id31_dz_mim_steps. -10nm steps can be resolved if detectors are integrating over 50ms (see red curve in Figure ref:fig:test_id31_dz_mim_10nm_steps), which is reasonable for many experiments. - -When doing step-by-step scans, the time to reach the next value is quite critical as long settling time can render the total experiment excessively long. -The response time to reach the wanted value (to within $\pm 20\,nm$) is around $70\,ms$ as shown with the $1\,\mu m$ step response in Figure ref:fig:test_id31_dz_mim_1000nm_steps. - -#+begin_src matlab -%% Load Dz steps data -data_dz_steps_10nm = load("2023-08-18_14-57_dz_mim_10_nm.mat"); -data_dz_steps_10nm.time = Ts*[0:length(data_dz_steps_10nm.Dz_int)-1]; - -data_dz_steps_100nm = load("2023-08-18_14-57_dz_mim_100_nm.mat"); -data_dz_steps_100nm.time = Ts*[0:length(data_dz_steps_100nm.Dz_int)-1]; - -data_dz_steps_1000nm = load("2023-08-18_14-57_dz_mim_1000_nm.mat"); -data_dz_steps_1000nm.time = Ts*[0:length(data_dz_steps_1000nm.Dz_int)-1]; -#+end_src - -#+begin_src matlab :exports none :results none -%% Dz MIM test with 10nm steps -figure; -hold on; -plot(data_dz_steps_10nm.time, 1e9*(data_dz_steps_10nm.Dz_int - mean(data_dz_steps_10nm.Dz_int(1:1000))), 'DisplayName', '$D_z$') -plot(data_dz_steps_10nm.time, 1e9*lsim(1/(1 + s/2/pi/20), data_dz_steps_10nm.Dz_int - mean(data_dz_steps_10nm.Dz_int(1:1000)), data_dz_steps_10nm.time), 'DisplayName', '$D_z$ (LPF)') -plot(data_dz_steps_10nm.time, 1e9*(data_dz_steps_10nm.m_hexa_dz-data_dz_steps_10nm.m_hexa_dz(1)), 'k--', 'DisplayName', 'Setpoint') -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ Motion [nm]'); -legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); -xlim([0, 0.6]); -ylim([-10, 40]); -xticks([0:0.2:0.6]); -yticks([-10:10:50]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_mim_10nm_steps.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Dz MIM test with 100nm steps -figure; -hold on; -plot(data_dz_steps_100nm.time, 1e9*(data_dz_steps_100nm.Dz_int - mean(data_dz_steps_100nm.Dz_int(1:1000))), 'DisplayName', '$D_z$') -plot(data_dz_steps_100nm.time, 1e9*(data_dz_steps_100nm.m_hexa_dz-data_dz_steps_100nm.m_hexa_dz(1)), 'k--', 'DisplayName', 'Setpoint') -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ Motion [nm]'); -legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); -xlim([0, 0.6]); -% ylim([-10, 40]); -xticks([0:0.2:0.6]); -yticks([-0:100:300]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_mim_100nm_steps.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Dz step response - Stabilization time is around 70ms -figure; -[~, i] = find(data_dz_steps_1000nm.m_hexa_dz>data_dz_steps_1000nm.m_hexa_dz(1)); -i0 = i(1); - -figure; -hold on; -plot(1e3*(data_dz_steps_1000nm.time-data_dz_steps_1000nm.time(i0)), 1e6*(data_dz_steps_1000nm.Dz_int - mean(data_dz_steps_1000nm.Dz_int(1:1000)))) -plot(1e3*[-1, 1], 1e-3*[1000-20, 1000-20], 'k--') -plot(1e3*[-1, 1], 1e-3*[1000+20, 1000+20], 'k--') -xline(0, 'k--', 'LineWidth', 1.5) -xline(70, 'k--', 'LineWidth', 1.5) -hold off; -xlabel('Time [ms]'); -ylabel('$D_z$ Motion [$\mu$m]'); -xlim([-10, 140]); -ylim([-0.1, 1.6]) -xticks([0, 70]) -yticks([0, 1]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_mim_1000nm_steps.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+name: fig:test_id31_dz_mim_steps -#+caption: Vertical steps performed with the nano-hexapod. 10nm steps are shown in (\subref{fig:test_id31_dz_mim_10nm_steps}) with the low pass filtered data corresponding to an integration time of $50\,ms$. 100nm steps are shown in (\subref{fig:test_id31_dz_mim_100nm_steps}). The response time to reach a peak to peak error of $\pm 20\,nm$ is $\approx 70\,ms$ as shown in (\subref{fig:test_id31_dz_mim_1000nm_steps}) for a $1\,\mu m$ step. -#+attr_latex: :options [htbp] -#+begin_figure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_mim_10nm_steps}10nm steps} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_mim_10nm_steps.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_mim_100nm_steps}100nm steps} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_mim_100nm_steps.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_mim_1000nm_steps}$1\,\mu$m step} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_mim_1000nm_steps.png]] -#+end_subfigure -#+end_figure - -**** Continuous $D_z$ motion: Dirty Layer Scans - -Instead of performing "step-by-step" scans, continuous scans can also be performed in the vertical direction. -At $10\,\mu m/s$, the errors are well within the specifications (see Figure ref:fig:test_id31_dz_scan_10ums). - -#+begin_src matlab -%% Dirty layer scans - 10um/s -data_dz_10ums = load("2023-08-18_15-33_dirty_layer_m0_small.mat"); -data_dz_10ums.time = Ts*[0:length(data_dz_10ums.Dz_int)-1]; - -%% Dirty layer scans - 100um/s -data_dz_100ums = load("2023-08-18_15-32_dirty_layer_m0.mat"); -data_dz_100ums.time = Ts*[0:length(data_dz_100ums.Dz_int)-1]; -#+end_src - -#+begin_src matlab :exports none :results none -%% Dz scan at 10um/s - Lateral error -figure; -hold on; -plot(data_dz_10ums.time, 1e9*data_dz_10ums.e_dy, 'DisplayName', sprintf('$\\epsilon D_y: %.0f$ nm RMS', 1e9*rms(data_dz_10ums.e_dy))) -plot([0, 2.2], [specs_dy_peak, specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -plot([0, 2.2], [-specs_dy_peak, -specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -hold off; -xlabel('Time [s]'); -ylabel('$D_y$ error [nm]') -% leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); -% leg.ItemTokenSize(1) = 15; -xlim([0, 2.2]); -ylim([-150, 150]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_scan_10ums_dy.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Dz scan at 10um/s - Vertical error -figure; -yyaxis left -hold on; -plot(data_dz_10ums.time, 1e9*data_dz_10ums.e_dz, 'DisplayName', '$\epsilon_{D_z}$') -plot([0, 2.2], [specs_dz_peak, specs_dz_peak], '--', 'HandleVisibility', 'off'); -plot([0, 2.2], [-specs_dz_peak, -specs_dz_peak], '--', 'HandleVisibility', 'off'); -hold off; -ylabel('$D_z$ error [nm]'); -ylim([-100, 100]); -yticks([-50:50:50]); -yyaxis right -hold on; -plot(data_dz_10ums.time, 1e6*(data_dz_10ums.Dz_int), 'DisplayName', '$D_z$') -plot(data_dz_10ums.time, 1e6*(data_dz_10ums.m_hexa_dz), 'k--', 'DisplayName', 'Setpoint') -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ Motion [$\mu$m]'); -leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); -leg.ItemTokenSize(1) = 15; -xlim([0, 2.2]); -ylim([-10, 10]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_scan_10ums_dz.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Dz scan at 10um/s - Ry error -figure; -hold on; -plot(data_dz_10ums.time, 1e6*data_dz_10ums.e_ry, 'DisplayName', sprintf('$\\epsilon R_y: %.2f \\mu$rad RMS', 1e6*rms(data_dz_10ums.e_ry))) -plot([0, 2.2], [specs_ry_peak, specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -plot([0, 2.2], [-specs_ry_peak, -specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -hold off; -xlabel('Time [s]'); -ylabel('$R_y$ error [$\mu$rad]') -% leg = legend('location', 'north', 'FontSize', 8, 'NumColumns', 1); -% leg.ItemTokenSize(1) = 15; -xlim([0, 2.2]); -ylim([-2, 2]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_scan_10ums_ry.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+name: fig:test_id31_dz_scan_10ums -#+caption: $D_z$ scan with a velocity of $10\,\mu m/s$. $D_z$ setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_10ums_dz}). Errors in $D_y$ and $R_y$ are respectively shown in (\subref{fig:test_id31_dz_scan_10ums_dy}) and (\subref{fig:test_id31_dz_scan_10ums_ry}) -#+attr_latex: :options [htbp] -#+begin_figure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_10ums_dy}$D_y$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_scan_10ums_dy.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_10ums_dz}$D_z$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_scan_10ums_dz.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_10ums_ry}$R_y$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_scan_10ums_ry.png]] -#+end_subfigure -#+end_figure - -The second tested velocity is $100\,\mu m/s$, which is the fastest velocity for $D_z$ scans when the ultimate performances is wanted (corresponding to a 1ms integration time and 100nm "resolution"). -At this velocity, the positioning errors are also within the specifications except for the very start and very end of the motion (i.e. during acceleration/deceleration phases, see Figure ref:fig:test_id31_dz_scan_100ums). -However, the detectors are usually triggered only during the constant velocity phase, so this is not not an issue. -The performances during acceleration phase may also be improved by using a feedforward controller. - -#+begin_src matlab :exports none :results none -%% Ry reflectivity scan - Vertical error -figure; -hold on; -plot(data_dz_100ums.time, 1e9*data_dz_100ums.e_dy, 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nm RMS', 1e9*rms(data_dz_100ums.e_dy))) -plot([0, 2.2], [specs_dy_peak, specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -plot([0, 2.2], [-specs_dy_peak, -specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -hold off; -xlabel('Time [s]'); -ylabel('$D_y$ error [nm]') -% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -xlim([0, 2.2]); -ylim([-150, 150]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_scan_100ums_dy.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -figure; -yyaxis left -hold on; -plot(data_dz_100ums.time, 1e9*data_dz_100ums.e_dz, 'DisplayName', '$\epsilon_{d_z}$') -plot([0, 2.2], [specs_dz_peak, specs_dz_peak], '--', 'HandleVisibility', 'off'); -plot([0, 2.2], [-specs_dz_peak, -specs_dz_peak], '--', 'HandleVisibility', 'off'); -hold off; -ylabel('$D_z$ error [nm]'); -ylim([-100, 100]); -yticks([-50:50:50]); -yyaxis right -hold on; -plot(data_dz_100ums.time, 1e6*(data_dz_100ums.Dz_int), 'DisplayName', '$D_z$') -plot(data_dz_100ums.time, 1e6*(data_dz_100ums.m_hexa_dz), 'k--', 'DisplayName', 'Setpoint') -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ Motion [$\mu$m]'); -leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); -leg.ItemTokenSize(1) = 15; -xlim([0, 2.2]); -ylim([-100, 100]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_scan_100ums_dz.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Ry reflectivity scan - Vertical error -figure; -hold on; -plot(data_dz_100ums.time, 1e6*data_dz_100ums.e_ry, 'DisplayName', sprintf('$\\epsilon R_y = %.2f \\mu$rad RMS', 1e6*rms(data_dz_100ums.e_ry))) -plot([0, 2.2], [specs_ry_peak, specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -plot([0, 2.2], [-specs_ry_peak, -specs_ry_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -hold off; -xlabel('Time [s]'); -ylabel('$R_y$ error [$\mu$rad]') -% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -xlim([0, 2.2]); -ylim([-2, 2]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_dz_scan_100ums_ry.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+name: fig:test_id31_dz_scan_100ums -#+caption: $D_z$ scan with a velocity of $100\,\mu m/s$. $D_z$ setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_100ums_dz}). Errors in $D_y$ and $R_y$ are respectively shown in (\subref{fig:test_id31_dz_scan_100ums_dy}) and (\subref{fig:test_id31_dz_scan_100ums_ry}) -#+attr_latex: :options [htbp] -#+begin_figure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_100ums_dy}$D_y$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_scan_100ums_dy.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_100ums_dz}$D_z$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_scan_100ums_dz.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_dz_scan_100ums_ry}$R_y$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_dz_scan_100ums_ry.png]] -#+end_subfigure -#+end_figure - -**** Summary - -#+begin_src matlab -%% Performances for Dz scans -% Determine when the motion starts and stops -i_dz_10ums = abs(diff(data_dz_10ums.m_hexa_dz)/Ts-10e-6) < 10*eps; -i_dz_100ums = abs(diff(data_dz_100ums.m_hexa_dz)/Ts-100e-6) < 10*eps; -% i_dz_10ums = data_dz_10ums.m_hexa_dz>data_dz_10ums.m_hexa_dz(1) & data_dz_10ums.m_hexa_dzdata_dz_100ums.m_hexa_dz(1) & data_dz_100ums.m_hexa_dz> - -X-ray reflectivity consists of scanning the $R_y$ angle of thin structures (typically solid/liquid interfaces) through the beam. -Here, a $R_y$ scan is performed with a rotational velocity of $100\,\mu rad/s$ and the positioning errors in closed-loop are recorded (Figure ref:fig:test_id31_reflectivity). -It is shown that the NASS is able to keep the point of interest in the beam within specifications. - -#+begin_src matlab -%% Load data for the reflectivity scan -data_ry = load("2023-08-18_15-24_first_reflectivity_m0.mat"); -data_ry.time = Ts*[0:length(data_ry.Ry_int)-1]; -#+end_src - -#+begin_src matlab :exports none :results none -%% Ry reflectivity scan - Lateral error -figure; -hold on; -plot(data_ry.time, 1e9*data_ry.e_dy, 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nm RMS', 1e9*rms(data_ry.e_dy))) -plot([0, 6.2], [specs_dy_peak, specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -plot([0, 6.2], [-specs_dy_peak, -specs_dy_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -hold off; -xlabel('Time [s]'); -ylabel('$D_y$ error [nm]') -% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -xlim([0, 6.2]); -ylim([-150, 150]); -xticks([0:2:6]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_reflectivity_dy.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Ry reflectivity scan - Vertical error -figure; -hold on; -plot(data_ry.time, 1e9*data_ry.e_dz, 'DisplayName', sprintf('$\\epsilon D_z = %.0f$ nm RMS', 1e9*rms(data_ry.e_dz))) -plot([0, 6.2], [specs_dz_peak, specs_dz_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -plot([0, 6.2], [-specs_dz_peak, -specs_dz_peak], '--', 'color', colors(1,:), 'HandleVisibility', 'off'); -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ error [nm]') -% legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -xlim([0, 6.2]); -ylim([-100, 100]); -xticks([0:2:6]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_reflectivity_dz.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+begin_src matlab :exports none :results none -%% Ry reflectivity scan - Setpoint and Error -figure; -yyaxis left -hold on; -plot(data_ry.time, 1e6*data_ry.e_ry, 'DisplayName', '$\epsilon_{R_y}$') -plot([0, 6.2], [specs_ry_peak, specs_ry_peak], '--', 'HandleVisibility', 'off'); -plot([0, 6.2], [-specs_ry_peak, -specs_ry_peak], '--', 'HandleVisibility', 'off'); -hold off; -ylim([-2, 2]) -ylabel('$R_y$ error [$\mu$rad]') -yyaxis right -hold on; -plot(data_ry.time, 1e6*data_ry.Ry_int, 'DisplayName', '$R_y$') -plot(data_ry.time, 1e6*data_ry.m_hexa_ry, 'k--', 'DisplayName', 'Setpoint') -hold off; -xlabel('Time [s]'); -ylabel('$R_y$ motion [$\mu$rad]') -leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -leg.ItemTokenSize(1) = 15; -xlim([0, 6.2]); -ylim([-310, 310]); -xticks([0:2:6]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file none -exportFig('figs/test_id31_reflectivity_ry.pdf', 'width', 'third', 'height', 'normal'); -#+end_src - -#+name: fig:test_id31_reflectivity -#+caption: Reflectivity scan ($R_y$) with a rotational velocity of $100\,\mu \text{rad}/s$. -#+attr_latex: :options [htbp] -#+begin_figure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_reflectivity_dy}$D_y$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_reflectivity_dy.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_reflectivity_dz}$D_z$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_reflectivity_dz.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_id31_reflectivity_ry}$R_y$} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :scale 1 -[[file:figs/test_id31_reflectivity_ry.png]] -#+end_subfigure -#+end_figure - - -** Combined $R_z$ and $D_y$: Diffraction Tomography +** Diffraction Tomography <> In diffraction tomography, the micro-station performs combined $R_z$ rotation and $D_y$ lateral scans. @@ -7912,10 +8200,10 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit #+end_src * Footnotes - -[fn:6]The roundness of the spheres is specified at $50\,nm$ -[fn:5]The "IcePAP" [[cite:&janvier13_icepap]] which is developed at the ESRF +[fn:7]The highest rotational velocity of $360\,\text{deg/s}$ could not be tested due to issue in the Spindle's controller. +[fn:6]The roundness of the spheres is specified at $50\,nm$. +[fn:5]The "IcePAP" [[cite:&janvier13_icepap]] which is developed at the ESRF. [fn:4]Note that the eccentricity of the "point of interest" with respect to the Spindle rotation axis has been tuned based on measurements. -[fn:3]The "PEPU" [[cite:&hino18_posit_encod_proces_unit]] was used for digital protocol conversion between the interferometers and the Speedgoat -[fn:2]M12/F40 model from Attocube -[fn:1]Depending on the measuring range, gap can range from $\approx 1\,\mu m$ to $\approx 100\,\mu m$ +[fn:3]The "PEPU" [[cite:&hino18_posit_encod_proces_unit]] was used for digital protocol conversion between the interferometers and the Speedgoat. +[fn:2]M12/F40 model from Attocube. +[fn:1]Depending on the measuring range, gap can range from $\approx 1\,\mu m$ to $\approx 100\,\mu m$. diff --git a/test-bench-id31.pdf b/test-bench-id31.pdf index bbb6b52..4d9b067 100644 Binary files a/test-bench-id31.pdf and b/test-bench-id31.pdf differ diff --git a/test-bench-id31.tex b/test-bench-id31.tex index de525bb..95ca326 100644 --- a/test-bench-id31.tex +++ b/test-bench-id31.tex @@ -1,4 +1,4 @@ -% Created 2025-02-01 Sat 18:34 +% Created 2025-02-03 Mon 14:43 % Intended LaTeX compiler: pdflatex \documentclass[a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc]{scrreprt} @@ -216,6 +216,7 @@ Results are summarized in Table \ref{tab:test_id31_metrology_acceptance}. The obtained lateral acceptance for pure displacements in any direction is estimated to be around \(+/-0.5\,mm\), which is enough for the current application as it is well above the micro-station errors to be actively corrected by the NASS. \begin{table}[htbp] +\caption{\label{tab:test_id31_metrology_acceptance}Estimated measurement range for each interferometer, and for three different directions.} \centering \begin{tabularx}{0.45\linewidth}{Xccc} \toprule @@ -228,8 +229,6 @@ The obtained lateral acceptance for pure displacements in any direction is estim \(d_5\) (z) & \(1.33\, mm\) & \(1.06\,mm\) & \(>2\,mm\)\\ \bottomrule \end{tabularx} -\caption{\label{tab:test_id31_metrology_acceptance}Estimated measurement range for each interferometer, and for three different directions.} - \end{table} @@ -746,19 +745,39 @@ These results demonstrate both the effectiveness and limitations of implementing \chapter{Validation with Scientific experiments} \label{sec:test_id31_experiments} -The online metrology prototype does not allow samples to be placed on top of the nano-hexapod while being illuminated by the x-ray beam. -However, in order to fully validate the NASS, typical motion performed during scientific experiments can be mimicked, and the positioning performances can be evaluated. +In this section, the goal is to evaluate the performances of the NASS and validate its use for real work scientific experiments. -For tomography scans, performances were already evaluated in Section \ref{ssec:test_id31_iff_hac_perf}. -Here, other typical experiments are performed: +However, the online metrology prototype (presented in Section \ref{sec:test_id31_metrology}) does not allow samples to be placed on top of the nano-hexapod while being illuminated by the x-ray beam. +Nevertheless, in order to fully validate the NASS, typical motion performed during scientific experiments can be mimicked, and the positioning performances can be evaluated. + +Several scientific experiments are mimicked, such as: \begin{itemize} -\item \emph{Lateral scans}: the \(T_y\) translations stage performs \(D_y\) scans and the errors are corrected by the NASS in real time (Section \ref{ssec:test_id31_scans_dy}) -\item \emph{Vertical layer scans}: the nano-hexapod is used to perform \(D_z\) step motion or ramp scans (Section \ref{ssec:test_id31_scans_dz}) -\item \emph{Reflectivity scans}: the tilt stage is doing \(R_y\) rotations and the errors are corrected by the NASS in real time (Section \ref{ssec:test_id31_scans_reflectivity}) -\item \emph{Diffraction Tomography}: the Spindle is performing continuous \(R_z\) rotation while the translation stage is performing lateral \(D_y\) scans at the same time. +\item Tomography scans: continuous rotation of the Spindle along the vertical axis (Section \ref{ssec:test_id31_scans_tomography}) +\item Reflectivity scans: \(R_y\) rotations using the tilt-stage (Section \ref{ssec:test_id31_scans_reflectivity}) +\item Vertical layer scans: the nano-hexapod is used to perform \(D_z\) step motion or ramp scans (Section \ref{ssec:test_id31_scans_dz}) +\item Lateral scans: \(D_y\) scans using the \(T_y\) translation stage (Section \ref{ssec:test_id31_scans_dy}) +\item Diffraction Tomography: the Spindle is performing continuous \(R_z\) rotation while the translation stage is performing lateral \(D_y\) scans at the same time. This is the experiment with the most stringent requirements (Section \ref{ssec:test_id31_scans_diffraction_tomo}) \end{itemize} -\section{\(R_z\) scans: Tomography} + +For each experiment, the obtained performances are compared to the specifications for the most depending case in which nano-focusing optics are used to focus the beam down to \(200\,nm\times 100\,nm\). +In that case the goal is to keep the sample's point of interested in the beam, and therefore the \(D_y\) and \(D_z\) positioning errors should be less than \(200\,nm\) and \(100\,nm\) peak-to-peak respectively. +The \(R_y\) error should be less than \(1.7\,\mu\text{rad}\) peak-to-peak. +In terms of RMS errors, this corresponds to \(30\,nm\) in \(D_y\), \(15\,nm\) in \(D_z\) and \(250\,\text{nrad}\) in \(R_y\). + +\begin{table}[htbp] +\caption{\label{tab:test_id31_experiments_specifications}Specifications for the Nano-Active-Stabilization-System} +\centering +\begin{tabularx}{0.5\linewidth}{Xccc} +\toprule + & \(D_y\) & \(D_z\) & \(R_y\)\\ +\midrule +peak 2 peak & 200nm & 100nm & \(1.7\,\mu\text{rad}\)\\ +RMS & 30nm & 15nm & \(250\,\text{nrad}\)\\ +\bottomrule +\end{tabularx} +\end{table} +\section{Tomography Scans} \label{ssec:test_id31_scans_tomography} \textbf{Issue with this control architecture (or controller?)}: \begin{itemize} @@ -770,51 +789,6 @@ This is the experiment with the most stringent requirements (Section \ref{ssec:t \item 1rpm, 6rpm, 30rpm \item at 1rpm: m0, m1, m2, m3 (same robust controller!) \end{itemize} -\paragraph{Previous results at 30rpm} - -Then the same tomography experiment (i.e. constant spindle rotation at 30rpm, and no payload) was performed experimentally. -The measured position of the ``point of interest'' during the experiment are shown in Figure \ref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp}. - -\begin{figure}[htbp] -\begin{subfigure}{0.49\textwidth} -\begin{center} -\includegraphics[scale=1,scale=0.9]{figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png} -\end{center} -\subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}XY plane} -\end{subfigure} -\begin{subfigure}{0.49\textwidth} -\begin{center} -\includegraphics[scale=1,scale=0.9]{figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png} -\end{center} -\subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}YZ plane} -\end{subfigure} -\caption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp}Experimental results of a tomography experiment at 30RPM without payload. Position error of the sample is shown in the XY (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}) and YZ (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}) planes.} -\end{figure} - -Even though the simulation (Figure \ref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_sim}) and the experimental results (Figure \ref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp}) are looking similar, the most important metric to compare is the RMS values of the positioning errors in closed-loop. -These are computed for both the simulation and the experimental results and are compared in Table \ref{tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms}. -The lateral and vertical errors are similar, however the tilt (\(R_y\)) errors are underestimated by the model, which is reasonable as disturbances in \(R_y\) were not modeled. - -Results obtained with this conservative HAC are already close to the specifications. - -\begin{table}[htbp] -\centering -\begin{tabularx}{0.7\linewidth}{Xccc} -\toprule - & \(D_y\) & \(D_z\) & \(R_y\)\\ -\midrule -Experiment (OL) & \(1.8\,\mu\text{mRMS}\) & \(24\,\text{nmRMS}\) & \(10\,\mu\text{radRMS}\)\\ -\midrule -Simulation (CL) & \(30\,\text{nmRMS}\) & \(8\,\text{nmRMS}\) & \(73\,\text{nradRMS}\)\\ -Experiment (CL) & \(39\,\text{nmRMS}\) & \(11\,\text{nmRMS}\) & \(130\,\text{nradRMS}\)\\ -\midrule -Specifications & \(30\,\text{nmRMS}\) & \(15\,\text{nmRMS}\) & \(250\,\text{nradRMS}\)\\ -\bottomrule -\end{tabularx} -\caption{\label{tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms}RMS values of the errors for a tomography experiment at 30RPM and without payload. Experimental results and simulation are compared.} - -\end{table} - \paragraph{Previous results at 1rpm} The tomography experiments that were simulated were then experimentally conducted. @@ -850,6 +824,7 @@ The RMS values of the open-loop and closed-loop errors for all masses are summar The obtained closed-loop errors are fulfilling the requirements, except for the \(39\,\text{kg}\) payload in the lateral (\(D_y\)) direction. \begin{table}[htbp] +\caption{\label{tab:test_id31_tomo_1rpm_robust_ol_cl_errors}RMS values of the measured errors during open-loop and closed-loop tomography scans (1rpm) for all considered payloads. Measured closed-Loop errors are indicated by ``bold'' font.} \centering \begin{tabularx}{0.9\linewidth}{Xccc} \toprule @@ -863,11 +838,286 @@ The obtained closed-loop errors are fulfilling the requirements, except for the \textbf{Specifications} & \(30\,\text{nmRMS}\) & \(15\,\text{nmRMS}\) & \(250\,\text{nradRMS}\)\\ \bottomrule \end{tabularx} -\caption{\label{tab:test_id31_tomo_1rpm_robust_ol_cl_errors}RMS values of the measured errors during open-loop and closed-loop tomography scans (1rpm) for all considered payloads. Measured closed-Loop errors are indicated by ``bold'' font.} - \end{table} -\section{\(D_y\) - Lateral Scans} +\paragraph{Previous results at 30rpm} + +Then the same tomography experiment (i.e. constant spindle rotation at 30rpm, and no payload) was performed experimentally. +The measured position of the ``point of interest'' during the experiment are shown in Figure \ref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp}. + +\begin{figure}[htbp] +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,scale=0.9]{figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.png} +\end{center} +\subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}XY plane} +\end{subfigure} +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,scale=0.9]{figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png} +\end{center} +\subcaption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}YZ plane} +\end{subfigure} +\caption{\label{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp}Experimental results of a tomography experiment at 30RPM without payload. Position error of the sample is shown in the XY (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy}) and YZ (\subref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz}) planes.} +\end{figure} + +Even though the simulation (Figure \ref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_sim}) and the experimental results (Figure \ref{fig:test_id31_tomo_m0_30rpm_robust_hac_iff_exp}) are looking similar, the most important metric to compare is the RMS values of the positioning errors in closed-loop. +These are computed for both the simulation and the experimental results and are compared in Table \ref{tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms}. +The lateral and vertical errors are similar, however the tilt (\(R_y\)) errors are underestimated by the model, which is reasonable as disturbances in \(R_y\) were not modeled. + +Results obtained with this conservative HAC are already close to the specifications. + +\begin{table}[htbp] +\caption{\label{tab:test_id31_tomo_m0_30rpm_robust_hac_iff_rms}RMS values of the errors for a tomography experiment at 30RPM and without payload. Experimental results and simulation are compared.} +\centering +\begin{tabularx}{0.7\linewidth}{Xccc} +\toprule + & \(D_y\) & \(D_z\) & \(R_y\)\\ +\midrule +Experiment (OL) & \(1.8\,\mu\text{mRMS}\) & \(24\,\text{nmRMS}\) & \(10\,\mu\text{radRMS}\)\\ +\midrule +Simulation (CL) & \(30\,\text{nmRMS}\) & \(8\,\text{nmRMS}\) & \(73\,\text{nradRMS}\)\\ +Experiment (CL) & \(39\,\text{nmRMS}\) & \(11\,\text{nmRMS}\) & \(130\,\text{nradRMS}\)\\ +\midrule +Specifications & \(30\,\text{nmRMS}\) & \(15\,\text{nmRMS}\) & \(250\,\text{nradRMS}\)\\ +\bottomrule +\end{tabularx} +\end{table} + +\paragraph{Dynamic Error Budgeting} + +In this section, the noise budget is performed. +The vibrations of the sample is measured in different conditions using the external metrology. + +\textbf{Tomography}: +\begin{itemize} +\item Beam size: 200nm x 100nm +\item Keep the PoI in the beam: peak to peak errors of 200nm in Dy and 100nm in Dz +\item RMS errors (/ by 6.6) gives 30nmRMS in Dy and 15nmRMS in Dz. +\item Ry error <1.7urad, 250nrad RMS +\end{itemize} + +\begin{center} +\begin{tabular}{lllllll} + & Dx & Dy & Dz & Rx & Ry & Rz\\ +\hline +peak 2 peak & & 200nm & 100nm & & 1.7 urad & \\ +RMS & & 30nm & 15nm & & 250 nrad & \\ +\end{tabular} +\end{center} + + +\begin{itemize} +\item Effect of rotation. +\item Comparison with measurement noise: should be higher +\item Maybe say that we then focus on the high rotation velocity +\item Also say that for the RMS errors, we don't take into account drifts (so we NASS we can correct drifts) +\item Focus on 30rpm case +\end{itemize} + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_hac_cas_ol_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_hac_cas_ol_dy} $D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_hac_cas_ol_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_hac_cas_ol_dz} $D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_hac_cas_ol_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_hac_cas_ol_ry} $R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_hac_cas_ol}Cumulative Amplitude Spectrum of the measured positioning errors without any rotation, with \(\Omega_z = 36\,\text{deg}/s\) and with \(\Omega_z = 180\,\text{deg}/s\). Open-loop case. RMS values are indicated in the legend.} +\end{figure} + +Effect of LAC: +\begin{itemize} +\item reduce amplitude around 80Hz +\item Inject some noise between 200 and 700Hz? +\end{itemize} + +Effect of HAC: +\begin{itemize} +\item Bandwidth is approximately 10Hz +\end{itemize} + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_hac_cas_cl_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_hac_cas_cl_dy} $D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_hac_cas_cl_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_hac_cas_cl_dz} $D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_hac_cas_cl_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_hac_cas_cl_ry} $R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_hac_cas_cl}Cumulative Amplitude Spectrum for tomography experiments at \(180\,\text{deg}/s\). Open-Loop case, IFF, and HAC-LAC are compared. Specifications are indicated by black dashed lines. RSM values are indicated in the legend.} +\end{figure} + +\section{Reflectivity Scans} +\label{ssec:test_id31_scans_reflectivity} + +X-ray reflectivity consists of scanning the \(R_y\) angle of thin structures (typically solid/liquid interfaces) through the beam. +Here, a \(R_y\) scan is performed with a rotational velocity of \(100\,\mu rad/s\) and the positioning errors in closed-loop are recorded (Figure \ref{fig:test_id31_reflectivity}). +It is shown that the NASS is able to keep the point of interest in the beam within specifications. + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_reflectivity_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_reflectivity_dy}$D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_reflectivity_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_reflectivity_dz}$D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_reflectivity_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_reflectivity_ry}$R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_reflectivity}Reflectivity scan (\(R_y\)) with a rotational velocity of \(100\,\mu \text{rad}/s\).} +\end{figure} + + +\section{Dirty Layer Scans} +\label{ssec:test_id31_scans_dz} +In some cases, samples are composed of several atomic ``layers'' that are first aligned in the horizontal plane with precise \(R_y\) positioning and that are then scanned vertically with precise \(D_z\) motion. +The vertical scan can be performed continuously of using step-by-step motion. +\paragraph{Step by Step \(D_z\) motion} + +Vertical steps are here performed using the nano-hexapod only. +Step sizes from \(10\,nm\) to \(1\,\mu m\) are tested, and the results are shown in Figure \ref{fig:test_id31_dz_mim_steps}. +10nm steps can be resolved if detectors are integrating over 50ms (see red curve in Figure \ref{fig:test_id31_dz_mim_10nm_steps}), which is reasonable for many experiments. + +When doing step-by-step scans, the time to reach the next value is quite critical as long settling time can render the total experiment excessively long. +The response time to reach the wanted value (to within \(\pm 20\,nm\)) is around \(70\,ms\) as shown with the \(1\,\mu m\) step response in Figure \ref{fig:test_id31_dz_mim_1000nm_steps}. + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_mim_10nm_steps.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_mim_10nm_steps}10nm steps} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_mim_100nm_steps.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_mim_100nm_steps}100nm steps} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_mim_1000nm_steps.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_mim_1000nm_steps}$1\,\mu$m step} +\end{subfigure} +\caption{\label{fig:test_id31_dz_mim_steps}Vertical steps performed with the nano-hexapod. 10nm steps are shown in (\subref{fig:test_id31_dz_mim_10nm_steps}) with the low pass filtered data corresponding to an integration time of \(50\,ms\). 100nm steps are shown in (\subref{fig:test_id31_dz_mim_100nm_steps}). The response time to reach a peak to peak error of \(\pm 20\,nm\) is \(\approx 70\,ms\) as shown in (\subref{fig:test_id31_dz_mim_1000nm_steps}) for a \(1\,\mu m\) step.} +\end{figure} + +\paragraph{Continuous \(D_z\) motion: Dirty Layer Scans} + +\begin{itemize} +\item[{$\square$}] In this section and the following experiments, the NASS performs ``ramp scans'' (i.e. constant velocity scans). +In order to have no tracking errors, two integrators needs to be present in the feedback loop. +As the plant present not integral action at low frequency, two integrators are included in the controller. +\end{itemize} + +Instead of performing ``step-by-step'' scans, continuous scans can also be performed in the vertical direction. +At \(10\,\mu m/s\), the errors are well within the specifications (see Figure \ref{fig:test_id31_dz_scan_10ums}). + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_10ums_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_scan_10ums_dy}$D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_10ums_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_scan_10ums_dz}$D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_10ums_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_scan_10ums_ry}$R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_dz_scan_10ums}\(D_z\) scan with a velocity of \(10\,\mu m/s\). \(D_z\) setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_10ums_dz}). Errors in \(D_y\) and \(R_y\) are respectively shown in (\subref{fig:test_id31_dz_scan_10ums_dy}) and (\subref{fig:test_id31_dz_scan_10ums_ry})} +\end{figure} + +The second tested velocity is \(100\,\mu m/s\), which is the fastest velocity for \(D_z\) scans when the ultimate performances is wanted (corresponding to a 1ms integration time and 100nm ``resolution''). +At this velocity, the positioning errors are also within the specifications except for the very start and very end of the motion (i.e. during acceleration/deceleration phases, see Figure \ref{fig:test_id31_dz_scan_100ums}). +However, the detectors are usually triggered only during the constant velocity phase, so this is not not an issue. +The performances during acceleration phase may also be improved by using a feedforward controller. + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_100ums_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_scan_100ums_dy}$D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_100ums_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_scan_100ums_dz}$D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_100ums_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_dz_scan_100ums_ry}$R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_dz_scan_100ums}\(D_z\) scan with a velocity of \(100\,\mu m/s\). \(D_z\) setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_100ums_dz}). Errors in \(D_y\) and \(R_y\) are respectively shown in (\subref{fig:test_id31_dz_scan_100ums_dy}) and (\subref{fig:test_id31_dz_scan_100ums_ry})} +\end{figure} + +\paragraph{Summary} + +\begin{center} +\begin{tabular}{lrrr} + & \(D_y\) & \(D_z\) & \(R_y\)\\ +\hline +Specs & 100.0 & 50.0 & 0.85\\ +10um/s & 82.35 & 17.94 & 0.41\\ +100um/s & 98.72 & 41.45 & 0.48\\ +\end{tabular} +\end{center} + +\begin{center} +\begin{tabular}{lrrr} + & \(D_y\) & \(D_z\) & \(R_y\)\\ +\hline +Specs & 30.0 & 15.0 & 0.25\\ +10um/s & 25.11 & 5.04 & 0.11\\ +100um/s & 34.84 & 9.08 & 0.13\\ +\end{tabular} +\end{center} + +\section{Lateral Scans} \label{ssec:test_id31_scans_dy} Lateral scans are performed with the \(T_y\) stage. The stepper motor controller\footnote{The ``IcePAP'' \cite{janvier13_icepap} which is developed at the ESRF} outputs the setpoint which is received by the Speedgoat. @@ -958,7 +1208,6 @@ Specs & 30.0 & 15.0 & 0.25\\ 100um/s (OL) & 1063.58 & 166.85 & 6.44\\ 100um/s (CL) & 731.63 & 19.91 & 0.36\\ \end{tabular} - \end{center} \begin{center} @@ -971,153 +1220,9 @@ Specs & 100.0 & 50.0 & 0.85\\ 100um/s (OL) & 2687.67 & 328.45 & 11.26\\ 100um/s (CL) & 1339.31 & 69.5 & 0.91\\ \end{tabular} - \end{center} -\section{\(D_z\) scans: Dirty Layer Scans} -\label{ssec:test_id31_scans_dz} -In some cases, samples are composed of several atomic ``layers'' that are first aligned in the horizontal plane with precise \(R_y\) positioning and that are then scanned vertically with precise \(D_z\) motion. -The vertical scan can be performed continuously of using step-by-step motion. -\paragraph{Step by Step \(D_z\) motion} - -Vertical steps are here performed using the nano-hexapod only. -Step sizes from \(10\,nm\) to \(1\,\mu m\) are tested, and the results are shown in Figure \ref{fig:test_id31_dz_mim_steps}. -10nm steps can be resolved if detectors are integrating over 50ms (see red curve in Figure \ref{fig:test_id31_dz_mim_10nm_steps}), which is reasonable for many experiments. - -When doing step-by-step scans, the time to reach the next value is quite critical as long settling time can render the total experiment excessively long. -The response time to reach the wanted value (to within \(\pm 20\,nm\)) is around \(70\,ms\) as shown with the \(1\,\mu m\) step response in Figure \ref{fig:test_id31_dz_mim_1000nm_steps}. - -\begin{figure}[htbp] -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_mim_10nm_steps.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_mim_10nm_steps}10nm steps} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_mim_100nm_steps.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_mim_100nm_steps}100nm steps} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_mim_1000nm_steps.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_mim_1000nm_steps}$1\,\mu$m step} -\end{subfigure} -\caption{\label{fig:test_id31_dz_mim_steps}Vertical steps performed with the nano-hexapod. 10nm steps are shown in (\subref{fig:test_id31_dz_mim_10nm_steps}) with the low pass filtered data corresponding to an integration time of \(50\,ms\). 100nm steps are shown in (\subref{fig:test_id31_dz_mim_100nm_steps}). The response time to reach a peak to peak error of \(\pm 20\,nm\) is \(\approx 70\,ms\) as shown in (\subref{fig:test_id31_dz_mim_1000nm_steps}) for a \(1\,\mu m\) step.} -\end{figure} - -\paragraph{Continuous \(D_z\) motion: Dirty Layer Scans} - -Instead of performing ``step-by-step'' scans, continuous scans can also be performed in the vertical direction. -At \(10\,\mu m/s\), the errors are well within the specifications (see Figure \ref{fig:test_id31_dz_scan_10ums}). - -\begin{figure}[htbp] -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_10ums_dy.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_scan_10ums_dy}$D_y$} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_10ums_dz.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_scan_10ums_dz}$D_z$} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_10ums_ry.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_scan_10ums_ry}$R_y$} -\end{subfigure} -\caption{\label{fig:test_id31_dz_scan_10ums}\(D_z\) scan with a velocity of \(10\,\mu m/s\). \(D_z\) setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_10ums_dz}). Errors in \(D_y\) and \(R_y\) are respectively shown in (\subref{fig:test_id31_dz_scan_10ums_dy}) and (\subref{fig:test_id31_dz_scan_10ums_ry})} -\end{figure} - -The second tested velocity is \(100\,\mu m/s\), which is the fastest velocity for \(D_z\) scans when the ultimate performances is wanted (corresponding to a 1ms integration time and 100nm ``resolution''). -At this velocity, the positioning errors are also within the specifications except for the very start and very end of the motion (i.e. during acceleration/deceleration phases, see Figure \ref{fig:test_id31_dz_scan_100ums}). -However, the detectors are usually triggered only during the constant velocity phase, so this is not not an issue. -The performances during acceleration phase may also be improved by using a feedforward controller. - -\begin{figure}[htbp] -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_100ums_dy.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_scan_100ums_dy}$D_y$} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_100ums_dz.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_scan_100ums_dz}$D_z$} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_dz_scan_100ums_ry.png} -\end{center} -\subcaption{\label{fig:test_id31_dz_scan_100ums_ry}$R_y$} -\end{subfigure} -\caption{\label{fig:test_id31_dz_scan_100ums}\(D_z\) scan with a velocity of \(100\,\mu m/s\). \(D_z\) setpoint, measured position and error are shown in (\subref{fig:test_id31_dz_scan_100ums_dz}). Errors in \(D_y\) and \(R_y\) are respectively shown in (\subref{fig:test_id31_dz_scan_100ums_dy}) and (\subref{fig:test_id31_dz_scan_100ums_ry})} -\end{figure} - -\paragraph{Summary} - -\begin{center} -\begin{tabular}{lrrr} - & \(D_y\) & \(D_z\) & \(R_y\)\\ -\hline -Specs & 100.0 & 50.0 & 0.85\\ -10um/s & 82.35 & 17.94 & 0.41\\ -100um/s & 98.72 & 41.45 & 0.48\\ -\end{tabular} - -\end{center} - -\begin{center} -\begin{tabular}{lrrr} - & \(D_y\) & \(D_z\) & \(R_y\)\\ -\hline -Specs & 30.0 & 15.0 & 0.25\\ -10um/s & 25.11 & 5.04 & 0.11\\ -100um/s & 34.84 & 9.08 & 0.13\\ -\end{tabular} - -\end{center} - -\section{\(R_y\) scans: Reflectivity} -\label{ssec:test_id31_scans_reflectivity} - -X-ray reflectivity consists of scanning the \(R_y\) angle of thin structures (typically solid/liquid interfaces) through the beam. -Here, a \(R_y\) scan is performed with a rotational velocity of \(100\,\mu rad/s\) and the positioning errors in closed-loop are recorded (Figure \ref{fig:test_id31_reflectivity}). -It is shown that the NASS is able to keep the point of interest in the beam within specifications. - -\begin{figure}[htbp] -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_reflectivity_dy.png} -\end{center} -\subcaption{\label{fig:test_id31_reflectivity_dy}$D_y$} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_reflectivity_dz.png} -\end{center} -\subcaption{\label{fig:test_id31_reflectivity_dz}$D_z$} -\end{subfigure} -\begin{subfigure}{0.33\textwidth} -\begin{center} -\includegraphics[scale=1,scale=1]{figs/test_id31_reflectivity_ry.png} -\end{center} -\subcaption{\label{fig:test_id31_reflectivity_ry}$R_y$} -\end{subfigure} -\caption{\label{fig:test_id31_reflectivity}Reflectivity scan (\(R_y\)) with a rotational velocity of \(100\,\mu \text{rad}/s\).} -\end{figure} - - -\section{Combined \(R_z\) and \(D_y\): Diffraction Tomography} +\section{Diffraction Tomography} \label{ssec:test_id31_scans_diffraction_tomo} In diffraction tomography, the micro-station performs combined \(R_z\) rotation and \(D_y\) lateral scans. @@ -1169,7 +1274,6 @@ Specs & 100.0 & 50.0 & 0.85\\ 0.5 mm/s & 117.94 & 28.03 & 0.27\\ 1 mm/s & 186.88 & 33.02 & 0.53\\ \end{tabular} - \end{center} \begin{center} @@ -1181,7 +1285,6 @@ Specs & 30.0 & 15.0 & 0.25\\ 0.5 mm/s & 28.58 & 7.52 & 0.08\\ 1 mm/s & 53.05 & 9.84 & 0.14\\ \end{tabular} - \end{center} \section*{Conclusion} @@ -1190,6 +1293,7 @@ Specs & 30.0 & 15.0 & 0.25\\ For each conducted experiments, the \(D_y\), \(D_z\) and \(R_y\) errors are computed and summarized in Table \ref{tab:id31_experiments_results_summary}. \begin{table}[htbp] +\caption{\label{tab:id31_experiments_results_summary}Table caption} \centering \begin{tabularx}{\linewidth}{Xccc} \toprule @@ -1212,8 +1316,6 @@ Diffraction Tomography (\(R_z\) 1rpm, \(D_y\) 0.1mm/s) & 75 & 9 & 118\\ Diffraction Tomography (\(R_z\) 1rpm, \(D_y\) 1mm/s) & 428 & 11 & 169\\ \bottomrule \end{tabularx} -\caption{\label{tab:id31_experiments_results_summary}Table caption} - \end{table} \chapter*{Conclusion}