diff --git a/figs/test_id31_diffraction_tomo_dy.pdf b/figs/test_id31_diffraction_tomo_dy.pdf new file mode 100644 index 0000000..e6de9ec Binary files /dev/null and b/figs/test_id31_diffraction_tomo_dy.pdf differ diff --git a/figs/test_id31_diffraction_tomo_dy.png b/figs/test_id31_diffraction_tomo_dy.png new file mode 100644 index 0000000..9e3fad6 Binary files /dev/null and b/figs/test_id31_diffraction_tomo_dy.png differ diff --git a/figs/test_id31_diffraction_tomo_dz.pdf b/figs/test_id31_diffraction_tomo_dz.pdf new file mode 100644 index 0000000..6022a49 Binary files /dev/null and b/figs/test_id31_diffraction_tomo_dz.pdf differ diff --git a/figs/test_id31_diffraction_tomo_dz.png b/figs/test_id31_diffraction_tomo_dz.png new file mode 100644 index 0000000..ee0bcf7 Binary files /dev/null and b/figs/test_id31_diffraction_tomo_dz.png differ diff --git a/figs/test_id31_diffraction_tomo_ry.pdf b/figs/test_id31_diffraction_tomo_ry.pdf new file mode 100644 index 0000000..758c054 Binary files /dev/null and b/figs/test_id31_diffraction_tomo_ry.pdf differ diff --git a/figs/test_id31_diffraction_tomo_ry.png b/figs/test_id31_diffraction_tomo_ry.png new file mode 100644 index 0000000..de07cc2 Binary files /dev/null and b/figs/test_id31_diffraction_tomo_ry.png differ diff --git a/figs/test_id31_diffraction_tomo_setpoint.pdf b/figs/test_id31_diffraction_tomo_setpoint.pdf new file mode 100644 index 0000000..44e596b Binary files /dev/null and b/figs/test_id31_diffraction_tomo_setpoint.pdf differ diff --git a/figs/test_id31_diffraction_tomo_setpoint.png b/figs/test_id31_diffraction_tomo_setpoint.png new file mode 100644 index 0000000..fca2ba2 Binary files /dev/null and b/figs/test_id31_diffraction_tomo_setpoint.png differ diff --git a/figs/test_id31_dy_100ums_dy.pdf b/figs/test_id31_dy_100ums_dy.pdf new file mode 100644 index 0000000..dd480b6 Binary files /dev/null and b/figs/test_id31_dy_100ums_dy.pdf differ diff --git a/figs/test_id31_dy_100ums_dy.png b/figs/test_id31_dy_100ums_dy.png new file mode 100644 index 0000000..cdfc170 Binary files /dev/null and b/figs/test_id31_dy_100ums_dy.png differ diff --git a/figs/test_id31_dy_100ums_dz.pdf b/figs/test_id31_dy_100ums_dz.pdf new file mode 100644 index 0000000..d1e654a Binary files /dev/null and b/figs/test_id31_dy_100ums_dz.pdf differ diff --git a/figs/test_id31_dy_100ums_dz.png b/figs/test_id31_dy_100ums_dz.png new file mode 100644 index 0000000..67294ba Binary files /dev/null and b/figs/test_id31_dy_100ums_dz.png differ diff --git a/figs/test_id31_dy_100ums_ry.pdf b/figs/test_id31_dy_100ums_ry.pdf new file mode 100644 index 0000000..60ff66f Binary files /dev/null and b/figs/test_id31_dy_100ums_ry.pdf differ diff --git a/figs/test_id31_dy_100ums_ry.png b/figs/test_id31_dy_100ums_ry.png new file mode 100644 index 0000000..e2594b4 Binary files /dev/null and b/figs/test_id31_dy_100ums_ry.png differ diff --git a/figs/test_id31_dy_10ums_dy.pdf b/figs/test_id31_dy_10ums_dy.pdf new file mode 100644 index 0000000..7b79f82 Binary files /dev/null and b/figs/test_id31_dy_10ums_dy.pdf differ diff --git a/figs/test_id31_dy_10ums_dy.png b/figs/test_id31_dy_10ums_dy.png new file mode 100644 index 0000000..8c1b404 Binary files /dev/null and b/figs/test_id31_dy_10ums_dy.png differ diff --git a/figs/test_id31_dy_10ums_dz.pdf b/figs/test_id31_dy_10ums_dz.pdf new file mode 100644 index 0000000..98b6538 Binary files /dev/null and b/figs/test_id31_dy_10ums_dz.pdf differ diff --git a/figs/test_id31_dy_10ums_dz.png b/figs/test_id31_dy_10ums_dz.png new file mode 100644 index 0000000..294706f Binary files /dev/null and b/figs/test_id31_dy_10ums_dz.png differ diff --git a/figs/test_id31_dy_10ums_ry.pdf b/figs/test_id31_dy_10ums_ry.pdf new file mode 100644 index 0000000..182b1f3 Binary files /dev/null and b/figs/test_id31_dy_10ums_ry.pdf differ diff --git a/figs/test_id31_dy_10ums_ry.png b/figs/test_id31_dy_10ums_ry.png new file mode 100644 index 0000000..4ee04c5 Binary files /dev/null and b/figs/test_id31_dy_10ums_ry.png differ diff --git a/figs/test_id31_dz_mim_1000nm_steps.pdf b/figs/test_id31_dz_mim_1000nm_steps.pdf new file mode 100644 index 0000000..18d80c8 Binary files /dev/null and b/figs/test_id31_dz_mim_1000nm_steps.pdf differ diff --git a/figs/test_id31_dz_mim_1000nm_steps.png b/figs/test_id31_dz_mim_1000nm_steps.png new file mode 100644 index 0000000..cbd8dee Binary files /dev/null and b/figs/test_id31_dz_mim_1000nm_steps.png differ diff --git a/figs/test_id31_dz_mim_100nm_steps.pdf b/figs/test_id31_dz_mim_100nm_steps.pdf new file mode 100644 index 0000000..8416a87 Binary files /dev/null and b/figs/test_id31_dz_mim_100nm_steps.pdf differ diff --git a/figs/test_id31_dz_mim_100nm_steps.png b/figs/test_id31_dz_mim_100nm_steps.png new file mode 100644 index 0000000..cf8a3a1 Binary files /dev/null and b/figs/test_id31_dz_mim_100nm_steps.png differ diff --git a/figs/test_id31_dz_mim_10nm_steps.pdf b/figs/test_id31_dz_mim_10nm_steps.pdf new file mode 100644 index 0000000..51e5895 Binary files /dev/null and b/figs/test_id31_dz_mim_10nm_steps.pdf differ diff --git a/figs/test_id31_dz_mim_10nm_steps.png b/figs/test_id31_dz_mim_10nm_steps.png new file mode 100644 index 0000000..2982edb Binary files /dev/null and b/figs/test_id31_dz_mim_10nm_steps.png differ diff --git a/figs/test_id31_dz_scan_100ums_dy.pdf b/figs/test_id31_dz_scan_100ums_dy.pdf new file mode 100644 index 0000000..52a8580 Binary files /dev/null and b/figs/test_id31_dz_scan_100ums_dy.pdf differ diff --git a/figs/test_id31_dz_scan_100ums_dy.png b/figs/test_id31_dz_scan_100ums_dy.png new file mode 100644 index 0000000..e7966a4 Binary files /dev/null and b/figs/test_id31_dz_scan_100ums_dy.png differ diff --git a/figs/test_id31_dz_scan_100ums_dz.pdf b/figs/test_id31_dz_scan_100ums_dz.pdf new file mode 100644 index 0000000..216e02a Binary files /dev/null and b/figs/test_id31_dz_scan_100ums_dz.pdf differ diff --git a/figs/test_id31_dz_scan_100ums_dz.png b/figs/test_id31_dz_scan_100ums_dz.png new file mode 100644 index 0000000..7f8f0e7 Binary files /dev/null and b/figs/test_id31_dz_scan_100ums_dz.png differ diff --git a/figs/test_id31_dz_scan_100ums_ry.pdf b/figs/test_id31_dz_scan_100ums_ry.pdf new file mode 100644 index 0000000..8d298ae Binary files /dev/null and b/figs/test_id31_dz_scan_100ums_ry.pdf differ diff --git a/figs/test_id31_dz_scan_100ums_ry.png b/figs/test_id31_dz_scan_100ums_ry.png new file mode 100644 index 0000000..d027188 Binary files /dev/null and b/figs/test_id31_dz_scan_100ums_ry.png differ diff --git a/figs/test_id31_dz_scan_10ums_dy.pdf b/figs/test_id31_dz_scan_10ums_dy.pdf new file mode 100644 index 0000000..5c7b913 Binary files /dev/null and b/figs/test_id31_dz_scan_10ums_dy.pdf differ diff --git a/figs/test_id31_dz_scan_10ums_dy.png b/figs/test_id31_dz_scan_10ums_dy.png new file mode 100644 index 0000000..170113c Binary files /dev/null and b/figs/test_id31_dz_scan_10ums_dy.png differ diff --git a/figs/test_id31_dz_scan_10ums_dz.pdf b/figs/test_id31_dz_scan_10ums_dz.pdf new file mode 100644 index 0000000..b80cb62 Binary files /dev/null and b/figs/test_id31_dz_scan_10ums_dz.pdf differ diff --git a/figs/test_id31_dz_scan_10ums_dz.png b/figs/test_id31_dz_scan_10ums_dz.png new file mode 100644 index 0000000..62e6f22 Binary files /dev/null and b/figs/test_id31_dz_scan_10ums_dz.png differ diff --git a/figs/test_id31_dz_scan_10ums_ry.pdf b/figs/test_id31_dz_scan_10ums_ry.pdf new file mode 100644 index 0000000..0b6e947 Binary files /dev/null and b/figs/test_id31_dz_scan_10ums_ry.pdf differ diff --git a/figs/test_id31_dz_scan_10ums_ry.png b/figs/test_id31_dz_scan_10ums_ry.png new file mode 100644 index 0000000..b93bf8f Binary files /dev/null and b/figs/test_id31_dz_scan_10ums_ry.png differ diff --git a/figs/test_id31_reflectivity_dy.pdf b/figs/test_id31_reflectivity_dy.pdf new file mode 100644 index 0000000..d71346e Binary files /dev/null and b/figs/test_id31_reflectivity_dy.pdf differ diff --git a/figs/test_id31_reflectivity_dy.png b/figs/test_id31_reflectivity_dy.png new file mode 100644 index 0000000..521ac5b Binary files /dev/null and b/figs/test_id31_reflectivity_dy.png differ diff --git a/figs/test_id31_reflectivity_dz.pdf b/figs/test_id31_reflectivity_dz.pdf new file mode 100644 index 0000000..04fc9b0 Binary files /dev/null and b/figs/test_id31_reflectivity_dz.pdf differ diff --git a/figs/test_id31_reflectivity_dz.png b/figs/test_id31_reflectivity_dz.png new file mode 100644 index 0000000..917f055 Binary files /dev/null and b/figs/test_id31_reflectivity_dz.png differ diff --git a/figs/test_id31_reflectivity_ry.pdf b/figs/test_id31_reflectivity_ry.pdf new file mode 100644 index 0000000..636e501 Binary files /dev/null and b/figs/test_id31_reflectivity_ry.pdf differ diff --git a/figs/test_id31_reflectivity_ry.png b/figs/test_id31_reflectivity_ry.png new file mode 100644 index 0000000..e10bedf Binary files /dev/null and b/figs/test_id31_reflectivity_ry.png differ diff --git a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.pdf b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.pdf index 0b48dec..b20de2e 100644 Binary files a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.pdf and b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.pdf differ diff --git a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png index 5f0bfc2..9382b70 100644 Binary files a/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png and b/figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_yz.png differ diff --git a/matlab/src/circlefit.m b/matlab/src/circlefit.m new file mode 100644 index 0000000..db5c99f --- /dev/null +++ b/matlab/src/circlefit.m @@ -0,0 +1,21 @@ +function [xc,yc,R,a] = circlefit(x,y) +% +% [xc yx R] = circfit(x,y) +% +% fits a circle in x,y plane in a more accurate +% (less prone to ill condition ) +% procedure than circfit2 but using more memory +% x,y are column vector where (x(i),y(i)) is a measured point +% +% result is center point (yc,xc) and radius R +% an optional output is the vector of coeficient a +% describing the circle's equation +% +% x^2+y^2+a(1)*x+a(2)*y+a(3)=0 +% +% By: Izhak bucher 25/oct /1991, + x=x(:); y=y(:); + a=[x y ones(size(x))]\[-(x.^2+y.^2)]; + xc = -.5*a(1); + yc = -.5*a(2); + R = sqrt((a(1)^2+a(2)^2)/4-a(3)); diff --git a/matlab/src/unwrapphase.m b/matlab/src/unwrapphase.m new file mode 100644 index 0000000..d1e4afb --- /dev/null +++ b/matlab/src/unwrapphase.m @@ -0,0 +1,11 @@ +function [unwraped_phase] = unwrapphase(frf, f, args) + +arguments + frf + f + args.f0 (1,1) double {mustBeNumeric} = 1 +end + +unwraped_phase = unwrap(frf); +[~,i] = min(abs(f - args.f0)); +unwraped_phase = unwraped_phase - 2*pi*round(unwraped_phase(i)./(2*pi)); diff --git a/test-bench-id31.bib b/test-bench-id31.bib index 50ce904..d181f73 100644 --- a/test-bench-id31.bib +++ b/test-bench-id31.bib @@ -11,6 +11,27 @@ +@inproceedings{dehaeze22_fastj_uhv, + author = {Thomas Dehaeze and Ludovic Ducott{\'e}}, + title = {The Fastjack - A robust, UHV compatible and high + performance linear actuator}, + year = 2022, + organization = {EUSPEN}, +} + + +@article{janvier13_icepap, + author = {Janvier, N and Clement, JM and Fajardo, P and Cun{\'\i}, G}, + title = {Icepap: an Advanced Motor Controller for Scientific + Applications in Large User Facilities}, + journal = {TUPPC081, ICALEPCS2013, San Francisco}, + volume = 2016, + year = 2013, + keywords = {esrf}, +} + + + @article{hino18_posit_encod_proces_unit, author = {Ricardo Hino and Pablo Fajardo and Nicolas Janvier and Thierry Le Ca{\"e}r and Fabien Le Mentec}, @@ -25,3 +46,5 @@ url = {http://jacow.org/icalepcs2017/doi/JACoW-ICALEPCS2017-THPHA072.html}, } + + diff --git a/test-bench-id31.org b/test-bench-id31.org index f0b3d6e..d678f8e 100644 --- a/test-bench-id31.org +++ b/test-bench-id31.org @@ -133,25 +133,61 @@ mat_dir = "/home/thomas/mnt/data_id31/nass" - Reflectivity - Diffraction tomography -** TODO [#C] Should I speak about higher bandwidth controllers even though they give lower performances? -[[file:backup.org::*High Performance HAC][High Performance HAC]] +** DONE [#A] Make detailed outline +CLOSED: [2025-01-30 Thu 11:34] -** DONE [#A] Copy all necessary .mat files -CLOSED: [2024-11-13 Wed 21:20] +- [ ] Where to put *noise budget*? + - Separated (OL, IFF, HAC-IFF)? + - Or all at once? + - It was made specifically for tomography experiments + - Each time, 3 figures (Dy, Dz, Ry) +- [ ] Separate sections for different control strategies? -** DONE [#B] Change the name of the I/O in the Simscape model to match the notations -CLOSED: [2024-11-14 Thu 11:32] +*Outline*: +- Short stroke metrology +- Open-Loop plant + - Effect of poor Rz alignment + - Effect of payload mass, effect of rotation +- IFF + - Controller design + - Check robustness + - Estimated damped plant? +- Robust HAC (frame of the struts) + - Damped plants + - Loop Shaping + - Check stability + - Noise budget -Fn => Vs +** DONE [#A] Find specifications for each experiment +CLOSED: [2025-01-30 Thu 11:16] -** TODO [#B] Coherent notation/description of spindle rotation +*Specifications for different directions* (Check this [[file:~/Cloud/work-projects/ID31-NASS/documents/work-package-1/work-package-1.pdf][document]].) +- [ ] Add these specifications in CAS plots (RMS values). +- [ ] Add these specifications in Y-Z plots (show beam size: 200nm x 100nm) -- RPM -- rpm -- Wz (deg/s) +| | Dx | Dy | Dz | Rx | Ry | Rz | +|-------------+----+-------+-------+----+----------+-------| +| RMS | | 30nm | 15nm | | 250 nrad | | +| peak 2 peak | | 200nm | 100nm | | 1.7 urad | | +|-------------+----+-------+-------+----+----------+-------| +| MIM | | 20nm | 10nm | | 1urad | 2urad | -Make a choice, and then adapt all notations. -Also, change the =initializeReferences= to accept the chosen description instead of =period=. +- [ ] Also check what was used for the uniaxial model and NASS Simscape model + *20nmRMS* from the uniaxial model + +*Tomography*: +- Beam size: 200nm x 100nm +- Keep the PoI in the beam: peak to peak errors of 200nm in Dy and 100nm in Dz +- RMS errors (/ by 6.6) gives 30nmRMS in Dy and 15nmRMS in Dz. +- Ry error <1.7urad, 250nrad RMS + +** TODO [#A] Ask Veijo to give me a short summary (5 lines) for each experiment type with references + +- Tomography +- Lateral scans +- "dirty layer scan" +- Reflectivity +- Diffraction tomography ** TODO [#A] Check why simulation gives worst performances than reality @@ -166,33 +202,58 @@ One big advantage of doing the control in the cartesian plane, is that we don't Maybe this should be done in A6 (simscape-nass). Here it can be reminded when doing the control in the cartesian frame. +** TODO [#A] Add same specifications for all the curves + +Peak to peak errors: +- Dz < +/- 50nm +- Dy < +/- 100nm +- Ry < +/- 0.85urad + +RMS errors: +- Dz: < 15nm RMS +- Dy: < 30nm RMS +- Ry: < 0.25urad RMS + +** TODO [#C] Make sure the display order to directions is always the same + +*Dy, Dz, Ry* + +** TODO [#C] Should I speak about higher bandwidth controllers even though they give lower performances? + +Probably not + +[[file:backup.org::*High Performance HAC][High Performance HAC]] + +** DONE [#A] Copy all necessary .mat files +CLOSED: [2024-11-13 Wed 21:20] + +** DONE [#B] Change the name of the I/O in the Simscape model to match the notations +CLOSED: [2024-11-14 Thu 11:32] + +Fn => Vs + +** TODO [#C] Talk about experimental conditions + +- Air Conditioning: +/-0.1 deg? +- Experimental hutch is closed for a long time to have best thermal stability + +** TODO [#B] Coherent notation/description of spindle rotation + +- RPM +- rpm +- Wz (deg/s) + +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 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. +Maybe give RMS value at 10kHz, and at 100Hz (LPF 1st order) -** TODO [#A] Find specifications for each experiment - -*Specifications for different directions* (Check this [[file:~/Cloud/work-projects/ID31-NASS/documents/work-package-1/work-package-1.pdf][document]].) -- [ ] Add these specifications in CAS plots (RMS values). - -| | Dx | Dy | Dz | Rx | Ry | Rz | -|-------------+----+-------+-------+----+-------+----------| -| RMS | | 30nm | 15nm | | | 250 nrad | -| peak 2 peak | | 200nm | 100nm | | | 1.7 urad | -|-------------+----+-------+-------+----+-------+----------| -| MIM | | 20nm | 10nm | | 2urad | 1urad | - -- [ ] Also check what was used for the uniaxial model and NASS Simscape model - *20nmRMS* from the uniaxial model - -*Tomography*: -- Beam size: 200nm x 100nm -- Keep the PoI in the beam: peak to peak errors of 200nm in Dy and 100nm in Dz -- RMS errors (/ by 6.6) gives 30nmRMS in Dy and 15nmRMS in Dz. -- Ry error <1.7urad, 250nrad RMS - -** TODO [#B] Analyze the observed modes +** DONE [#B] Analyze the observed modes +CLOSED: [2025-01-30 Thu 11:12] Added mode compared to Nano-Hexapod test bench: - Modes of the metrology spheres (between 600 and 700Hz) @@ -203,7 +264,9 @@ Added mode compared to Nano-Hexapod test bench: Look at =2023-08-10_18-32_identify_spurious_modes.mat= -** TODO [#A] Explain why position error does not converges to zero during tomography experiments +*Conclusion is not clear* + +** TODO [#B] Explain why position error does not converges to zero during tomography experiments In closed-loop, the position does not converges to zeros but to a stable position. @@ -212,6 +275,7 @@ This is due to the limited loop-gain at a frequency corresponding to the eccentr Even though there is an integrator in the controller, this integrator is in the frame of the struts, and not in the cartesian frame. The eccentricity is seen as DC disturbance in the cartesian frame, but at "Wz" frequency in the frame of the strut, hence the non-convergence to zero position. +Or the opposite? - *Before 2023-08-11_11-41_tomography_30rpm_m0.mat*: Static errors - *After 2023-08-11_14-16_m0_1rpm.mat*: No more static errors @@ -268,29 +332,7 @@ leg.ItemTokenSize(1) = 15; Yes it converges to zero. -** TODO [#A] Make detailed outline - -- [ ] Where to put *noise budget*? - - Separated (OL, IFF, HAC-IFF)? - - Or all at once? - - It was made specifically for tomography experiments - - Each time, 3 figures (Dy, Dz, Ry) -- [ ] Separate sections for different control strategies? - -*Outline*: -- Short stroke metrology -- Open-Loop plant - - Effect of poor Rz alignment - - Effect of payload mass, effect of rotation -- IFF - - Controller design - - Check robustness - - Estimated damped plant? -- Robust HAC (frame of the struts) - - Damped plants - - Loop Shaping - - Check stability - - Noise budget +- [ ] Maybe just show results where the error converges to zero? ** DONE [#C] Talk about additional delay observed in the plant from u to d (interf) CLOSED: [2024-11-15 Fri 18:22] @@ -1288,6 +1330,8 @@ exportFig('figs/test_id31_Rz_align_correct.pdf', 'width', 'half', 'height', 'nor The plant dynamics is identified after the fine alignment and is compared with the model dynamics in Figure ref:fig:test_id31_first_id_int_better_rz_align. Compared to the initial identification shown in Figure ref:fig:test_id31_first_id_int, the obtained coupling has decreased and is now close to the coupling obtained with the multi-body model. At low frequency (below $10\,\text{Hz}$) all the off-diagonal elements have an amplitude $\approx 100$ times lower compared to the diagonal elements, indicating that a low bandwidth feedback controller can be implemented in a decentralized way (i.e. $6$ SISO controllers). +Between $650\,\text{Hz}$ and $1000\,\text{Hz}$, several modes can be observed that are due to flexible modes of the top platform and modes of the two spheres adjustment mechanism. +The flexible modes of the top platform can be passively damped while the modes of the two reference spheres should not be present in the final application. #+begin_src matlab %% Identification of the plant after Rz alignment @@ -1679,7 +1723,7 @@ exportFig('figs/test_id31_comp_simscape_iff_diag_masses.pdf', 'width', 'half', ' #+end_src #+name: fig:test_nhexa_comp_simscape_diag_masses -#+caption: Comparison of the diagonal elements (i.e. "direct" terms) of the measured FRF matrix and the dynamics identified from the Simscape model. Both for the dynamics from $u$ to $e\mathcal{L}$ (\subref{fig:test_id31_comp_simscape_int_diag_masses}) and from $u$ to $V_s$ (\subref{fig:test_id31_comp_simscape_iff_diag_masses}) +#+caption: Comparison of the diagonal elements (i.e. "direct" terms) of the measured FRF matrix and the dynamics identified from the multi-body model. Both for the dynamics from $u$ to $e\mathcal{L}$ (\subref{fig:test_id31_comp_simscape_int_diag_masses}) and from $u$ to $V_s$ (\subref{fig:test_id31_comp_simscape_iff_diag_masses}) #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_id31_comp_simscape_int_diag_masses}from $u$ to $e\mathcal{L}$} @@ -1864,53 +1908,6 @@ exportFig('figs/test_id31_effect_rotation_coupling.pdf', 'width', 'half', 'heigh #+end_subfigure #+end_figure -** TODO Identification of Spurious modes - -- [ ] These are made to identify the modes of the spheres -- [ ] Also discuss other observed modes - -#+begin_src matlab -%% Load identification data -% mat_dir = "/home/thomas/mnt/data_id31/nass"; -data = load(sprintf('%s/dynamics/2023-08-10_18-32_identify_spurious_modes.mat', mat_dir)); -#+end_src - -#+begin_src matlab :exports none -Ts = 1e-4; -% Hannning Windows -Nfft = floor(1.0/Ts); -win = hanning(Nfft); -Noverlap = floor(Nfft/2); -#+end_src - -#+begin_src matlab :exports none -% And we get the frequency vector -[G1, f] = tfestimate(data.id_plant, data.d1, win, Noverlap, Nfft, 1/Ts); -[G2, ~] = tfestimate(data.id_plant, data.d2, win, Noverlap, Nfft, 1/Ts); -[G3, ~] = tfestimate(data.id_plant, data.d3, win, Noverlap, Nfft, 1/Ts); -[G4, ~] = tfestimate(data.id_plant, data.d4, win, Noverlap, Nfft, 1/Ts); -[G5, ~] = tfestimate(data.id_plant, data.d5, win, Noverlap, Nfft, 1/Ts); -#+end_src - -#+begin_src matlab :exports none :results none -%% Obtained transfer function from generated voltages to measured voltages on the piezoelectric force sensor -figure; -tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); - -ax1 = nexttile(); -hold on; -plot(f, abs(G1), 'DisplayName', '1 - top'); -plot(f, abs(G2), 'DisplayName', '2 - bot'); -plot(f, abs(G3), 'DisplayName', '3 - top'); -plot(f, abs(G4), 'DisplayName', '4 - bot'); -plot(f, abs(G5), 'DisplayName', '5 - vertical'); -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); -xlim([500, 800]) -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -#+end_src - ** Conclusion :PROPERTIES: :UNNUMBERED: t @@ -2899,6 +2896,54 @@ exportFig('figs/test_id31_comp_all_undamped_damped_plants.pdf', 'width', 'half', #+end_subfigure #+end_figure +** Interaction Analysis +Decoupled system up to 10Hz +Higher coupling for higher masses (when considering control in the frame of the struts) + +#+begin_src matlab +%% RGA +rga_m0 = zeros(size(G_hac_m0_Wz0)); +for i = 1:size(rga_m0,1) + rga_m0(i,:,:) = inv(squeeze(G_hac_m0_Wz0(i,:,:)).').*squeeze(G_hac_m0_Wz0(i,:,:)); +end + +rga_m1 = zeros(size(G_hac_m1_Wz0)); +for i = 1:size(rga_m1,1) + rga_m1(i,:,:) = inv(squeeze(G_hac_m1_Wz0(i,:,:)).').*squeeze(G_hac_m1_Wz0(i,:,:)); +end + +rga_m2 = zeros(size(G_hac_m2_Wz0)); +for i = 1:size(rga_m2,1) + rga_m2(i,:,:) = inv(squeeze(G_hac_m2_Wz0(i,:,:)).').*squeeze(G_hac_m2_Wz0(i,:,:)); +end + +rga_m3 = zeros(size(G_hac_m3_Wz0)); +for i = 1:size(rga_m3,1) + rga_m3(i,:,:) = inv(squeeze(G_hac_m3_Wz0(i,:,:)).').*squeeze(G_hac_m3_Wz0(i,:,:)); +end +#+end_src + +#+begin_src matlab +figure; +hold on; +for i = 1:5 + plot(f, real(rga_m0(:,i,i)), 'color', colors(1,:)) + plot(f, real(rga_m1(:,i,i)), 'color', colors(2,:)) + plot(f, real(rga_m2(:,i,i)), 'color', colors(3,:)) + plot(f, real(rga_m3(:,i,i)), 'color', colors(4,:)) +end +for i = 1:5 + for j = i+1:6 + plot(f, real(rga_m0(:,i,j)), 'color', [colors(1,:),0.2]) + plot(f, real(rga_m1(:,i,j)), 'color', [colors(2,:),0.2]) + plot(f, real(rga_m2(:,i,j)), 'color', [colors(3,:),0.2]) + plot(f, real(rga_m3(:,i,j)), 'color', [colors(4,:),0.2]) + end +end +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +xlim([1, 1e2]); ylim([0, 2]); +#+end_src + ** Robust Controller Design <> @@ -3067,7 +3112,7 @@ exportFig('figs/test_id31_hac_characteristic_loci.pdf', 'width', 'half', 'height #+end_subfigure #+end_figure -** Estimation of performances +** Estimation of performances with Tomography scans <> To estimate the performances that can be expected with this HAC-LAC architecture and the designed controllers, two simulations of tomography experiments were performed[fn:4]. @@ -3231,16 +3276,35 @@ exportFig('figs/test_id31_tomo_m0_30rpm_robust_hac_iff_exp_xy.pdf', 'width', 'ha #+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([-1, 1]); +xlim([-3, 3]); ylim([-0.6, 0.6]); xticks([-3:1:3]); -yticks([-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 @@ -3301,18 +3365,20 @@ rms_Ry_m0_Wz180_cl_exp = rms(detrend(data_tomo_m0_Wz180.Ry_int(i_cl+10000:end), #+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 (CL) | $30\,\text{nmRMS}$ | $15\,\text{nmRMS}$ | $250\,\text{nradRMS}$ | +| | $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}$ | ** Robustness to change of payload <> +- [ ] Make simulations with all masses? + To verify the robustness to the change of payload mass, four simulations of tomography experiments were performed with payloads as shown Figure ref:fig:test_id31_picture_masses (i.e. $0\,kg$, $13\,kg$, $26\,kg$ and $39\,kg$). This time, the rotational velocity was set at 1rpm (i.e. 6deg/s), as it is the typical rotational velocity for heavy samples. The closed-loop systems were stable for all payload conditions, indicating good control robustness. @@ -3418,6 +3484,9 @@ fun = @(theta)rms((data_tomo_m2_Wz6.Dx_int(1:i_m2) - (x0 + R*cos(data_tomo_m2_Wz 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; @@ -3596,13 +3665,26 @@ data2orgtable([1e9*data_tomo_m0_Wz6.Dx_rms_cl, 1e9*data_tomo_m0_Wz6.Dy_rms_cl, 1 :UNNUMBERED: t :END: -* Dynamic Error Budgeting :noexport: +* Dynamic Error Budgeting <> ** Introduction :ignore: In this section, the noise budget is performed. The vibrations of the sample is measured in different conditions using the external metrology. +# If Dynamic Error Budgeting: we should include PSD of disturbances + +*Tomography*: +- Beam size: 200nm x 100nm +- Keep the PoI in the beam: peak to peak errors of 200nm in Dy and 100nm in Dz +- RMS errors (/ by 6.6) gives 30nmRMS in Dy and 15nmRMS in Dz. +- Ry error <1.7urad, 250nrad RMS + +| | Dx | Dy | Dz | Rx | Ry | Rz | +|-------------+----+-------+-------+----+----------+----| +| peak 2 peak | | 200nm | 100nm | | 1.7 urad | | +| RMS | | 30nm | 15nm | | 250 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) <> @@ -3628,6 +3710,8 @@ The vibrations of the sample is measured in different conditions using the exter - 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) #+begin_src matlab %% Effect of rotation @@ -3699,6 +3783,7 @@ plot(data_ol_Wz36.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz36.f), flip(data_ol_Wz36 '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], [specs_dy_rms, specs_dy_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm RMS', 1e9*specs_dy_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('CAS [m rms, rad RMS]'); @@ -3714,6 +3799,7 @@ plot(data_ol_Wz36.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz36.f), flip(data_ol_Wz36 '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], [specs_dz_rms, specs_dz_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm RMS', 1e9*specs_dz_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); @@ -3729,6 +3815,7 @@ plot(data_ol_Wz36.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz36.f), flip(data_ol_Wz36 'DisplayName', sprintf('6rpm: $%.1f \\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], [specs_ry_rms, specs_ry_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f \\mu$rad RMS', 1e6*specs_ry_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); @@ -3741,6 +3828,7 @@ xlim([0.1, 5e2]); ylim([1e-10, 3e-5]); #+end_src ** Effect of LAC +- [ ] Maybe merge this with the HAC-LAC #+begin_src matlab %% Effect of LAC @@ -3775,6 +3863,7 @@ ax1 = nexttile(); hold on; plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Dy)))), 'DisplayName', 'OL'); plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Dy)))), 'DisplayName', 'LAC'); +plot([1e-2, 1e4], [specs_dy_rms, specs_dy_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm RMS', 1e9*specs_dy_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('CAS [$m$]'); @@ -3785,6 +3874,7 @@ ax2 = nexttile(); hold on; plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Dz)))), 'DisplayName', 'OL'); plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Dz)))), 'DisplayName', 'LAC'); +plot([1e-2, 1e4], [specs_dz_rms, specs_dz_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm RMS', 1e9*specs_dz_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); @@ -3795,6 +3885,7 @@ ax3 = nexttile(); hold on; plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Ry)))), 'DisplayName', 'OL'); plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Ry)))), 'DisplayName', 'LAC'); +plot([1e-2, 1e4], [specs_ry_rms, specs_ry_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f \\mu$rad RMS', 1e6*specs_ry_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); @@ -3877,9 +3968,10 @@ tiledlayout(1, 3, 'TileSpacing', 'compact', 'Padding', 'None'); ax1 = nexttile(); 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 nm RMS' )); -plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Dy)))), 'DisplayName', 'LAC'); -plot(data_hac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_hac_Wz180.f), flip(data_hac_Wz180.pxx_Dy)))), 'DisplayName', 'HAC'); +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], [specs_dy_rms, specs_dy_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm RMS', 1e9*specs_dy_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('CAS [$m$]'); @@ -3888,9 +3980,10 @@ legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); ax2 = nexttile(); hold on; -plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Dz)))), 'DisplayName', 'OL'); -plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Dz)))), 'DisplayName', 'LAC'); -plot(data_hac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_hac_Wz180.f), flip(data_hac_Wz180.pxx_Dz)))), 'DisplayName', 'HAC'); +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], [specs_dz_rms, specs_dz_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f$nm RMS', 1e9*specs_dz_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); @@ -3899,9 +3992,10 @@ legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); ax3 = nexttile(); hold on; -plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Ry)))), 'DisplayName', 'OL'); -plot(data_lac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_lac_Wz180.f), flip(data_lac_Wz180.pxx_Ry)))), 'DisplayName', 'LAC'); -plot(data_hac_Wz180.f, sqrt(flip(-cumtrapz(flip(data_hac_Wz180.f), flip(data_hac_Wz180.pxx_Ry)))), 'DisplayName', 'HAC'); +plot(data_ol_Wz180.f, sqrt(flip(-cumtrapz(flip(data_ol_Wz180.f), flip(data_ol_Wz180.pxx_Ry)))), 'DisplayName', sprintf('OL $%.2f \\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 $%.2f \\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], [specs_ry_rms, specs_ry_rms], 'k--', 'DisplayName', sprintf('Spec: $%.0f \\mu$rad RMS', 1e6*specs_ry_rms)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); @@ -3912,18 +4006,23 @@ linkaxes([ax1,ax2,ax3],'xy'); xlim([0.1, 5e2]); ylim([1e-10, 3e-5]); #+end_src -* TODO Scans for scientific experiments :noexport: -:PROPERTIES: -:header-args:matlab+: :tangle matlab/test_id31_x_scans.m -:END: -<> +* Validation with Scientific experiments ** Introduction :ignore: -- Section ref:sec:id31_scans_tomography -- Section ref:sec:id31_scans_dz -- Section ref:sec:id31_scans_reflectivity -- Section ref:sec:id31_scans_dy -- Section ref:sec:id31_scans_diffraction_tomo +# - [ ] 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) + +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. + This is the experiment with the most stringent requirements (Section ref:ssec:test_id31_scans_diffraction_tomo) ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) @@ -3946,10 +4045,12 @@ xlim([0.1, 5e2]); ylim([1e-10, 3e-5]); <> #+end_src -** $R_z$ scans: Tomography +** $R_z$ scans: Tomography :noexport: <> *** Introduction :ignore: +- [ ] *Maybe this was already shown in Section ref:ssec:test_id31_iff_hac_perf and ref:ssec:test_id31_iff_hac_robustness* + - m0: 30rpm, 6rpm, 1rpm - m1: 6rpm, 1rpm - m2: 6rpm, 1rpm @@ -3989,9 +4090,9 @@ tiledlayout(1, 2, 'TileSpacing', 'compact', 'Padding', 'None'); ax1 = nexttile; hold on; -plot(1e6*data_tomo_1rpm_m0.Dx_int(data_tomo_1rpm_m0.hac_status == 0), 1e6*data_tomo_1rpm_m0.Dy_int(data_tomo_1rpm_m0.hac_status == 0), ... +plot(1e6*data_tomo_1rpm_m3.Dx_int(data_tomo_1rpm_m3.hac_status == 0), 1e6*data_tomo_1rpm_m3.Dy_int(data_tomo_1rpm_m3.hac_status == 0), ... 'DisplayName', 'OL') -plot(1e6*data_tomo_1rpm_m0.Dx_int(data_tomo_1rpm_m0.hac_status == 1), 1e6*data_tomo_1rpm_m0.Dy_int(data_tomo_1rpm_m0.hac_status == 1), ... +plot(1e6*data_tomo_1rpm_m3.Dx_int(data_tomo_1rpm_m3.hac_status == 1), 1e6*data_tomo_1rpm_m3.Dy_int(data_tomo_1rpm_m3.hac_status == 1), ... 'DisplayName', 'CL') hold off; axis equal @@ -4003,9 +4104,9 @@ legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); ax2 = nexttile; hold on; -plot(1e6*data_tomo_1rpm_m0.Dy_int(data_tomo_1rpm_m0.hac_status == 0), 1e6*data_tomo_1rpm_m0.Dz_int(data_tomo_1rpm_m0.hac_status == 0), ... +plot(1e6*data_tomo_1rpm_m3.Dy_int(data_tomo_1rpm_m3.hac_status == 0), 1e6*data_tomo_1rpm_m3.Dz_int(data_tomo_1rpm_m3.hac_status == 0), ... 'DisplayName', 'OL') -plot(1e6*data_tomo_1rpm_m0.Dy_int(data_tomo_1rpm_m0.hac_status == 1), 1e6*data_tomo_1rpm_m0.Dz_int(data_tomo_1rpm_m0.hac_status == 1), ... +plot(1e6*data_tomo_1rpm_m3.Dy_int(data_tomo_1rpm_m3.hac_status == 1), 1e6*data_tomo_1rpm_m3.Dz_int(data_tomo_1rpm_m3.hac_status == 1), ... 'DisplayName', 'CL') hold off; % axis equal @@ -4024,8 +4125,89 @@ exportFig('figs/id31_tomo_1rpm_robust_m0.pdf', 'width', 'full', 'height', 'norma #+RESULTS: [[file:figs/id31_tomo_1rpm_robust_m0.png]] +- [ ] Errors in CL + +#+begin_src matlab :exports none :results none +%% Measured motion during tomography scan at 30RPM with a robust controller +[~, i_m0] = find(data_tomo_1rpm_m0.hac_status == 1); +[~, i_m1] = find(data_tomo_1rpm_m1.hac_status == 1); +[~, i_m2] = find(data_tomo_1rpm_m2.hac_status == 1); +[~, i_m3] = find(data_tomo_1rpm_m3.hac_status == 1); + +figure; +tiledlayout(1, 4, 'TileSpacing', 'compact', 'Padding', 'None'); +nexttile; +hold on; +plot(1e9*detrend(data_tomo_1rpm_m0.Dy_int(i_m0+50000:end), 0), 1e9*detrend(data_tomo_1rpm_m0.Dz_int(i_m0+50000:end), 0)) +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; +axis equal +xlim([-200, 200]) +ylim([-100, 100]) + +nexttile; +hold on; +plot(1e9*detrend(data_tomo_1rpm_m1.Dy_int(i_m1+50000:end), 0), 1e9*detrend(data_tomo_1rpm_m1.Dz_int(i_m1+50000:end), 0)) +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; +axis equal +xlim([-200, 200]) +ylim([-100, 100]) + +nexttile; +hold on; +plot(1e9*detrend(data_tomo_1rpm_m2.Dy_int(i_m2+50000:end), 0), 1e9*detrend(data_tomo_1rpm_m2.Dz_int(i_m2+50000:end), 0)) +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; +axis equal +xlim([-200, 200]) +ylim([-100, 100]) + +nexttile; +hold on; +plot(1e9*detrend(data_tomo_1rpm_m3.Dy_int(i_m3+100000:end), 0), 1e9*detrend(data_tomo_1rpm_m3.Dz_int(i_m3+100000:end), 0)) +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; +axis equal +xlim([-200, 200]) +ylim([-100, 100]) + +xlabel("Y motion [$nm$]"); +ylabel("Z motion [$nm$]"); +#+end_src + +- [ ] If the integration time of detectors is set at 50ms (which is quite typical for such experiment), the average position of the sample within 50ms is now fulfilling the requirements. +- [ ] Maybe add the 50ms average to the previous figure + +#+begin_src matlab :exports none :results none +%% Measured motion during tomography scan at 30RPM with a robust controller +[~, i_m3] = find(data_tomo_1rpm_m3.hac_status == 1); + +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +nexttile; +hold on; +plot(1e9*movmean(detrend(data_tomo_1rpm_m3.Dy_int(i_m3+100000:end), 0), 0.05*1e4), 1e9*movmean(detrend(data_tomo_1rpm_m3.Dz_int(i_m3+100000:end), 0), 0.05*1e4)) +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; +axis equal +xlim([-200, 200]) +ylim([-100, 100]) + +xlabel("Y motion [$nm$]"); +ylabel("Z motion [$nm$]"); +#+end_src + The obtained open-loop and closed-loop errors are shown in tables ref:tab:id31_tomo_1rpm_robust_ol_errors and ref:tab:id31_tomo_1rpm_robust_cl_errors respectively. +For large mass, the lateral motion is larger than the specifications. +In order to improve the performances, a controller could be specifically tuned for high masses. + #+begin_src matlab %% Compute RMS values while in closed-loop and open-loop [~, i_m0] = find(data_tomo_1rpm_m0.hac_status == 1); @@ -4297,6 +4479,24 @@ exportFig('figs/id31_tomography_m0_30rpm_robust_xyz.pdf', 'width', 'full', 'heig #+RESULTS: [[file:figs/id31_tomography_m0_30rpm_robust_xyz.png]] +#+begin_src matlab :exports none :results none +%% Measured motion during tomography scan at 30RPM with a robust controller +[~, i_m0] = find(data_tomo_30rpm_m0.hac_status == 1); + +figure; +tiledlayout(1, 1, 'TileSpacing', 'compact', 'Padding', 'None'); +hold on; +plot(1e9*data_tomo_30rpm_m0.Dy_int(i_m0+50000:end), 1e9*data_tomo_30rpm_m0.Dz_int(i_m0+50000:end)) +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; +axis equal +xlim([-200, 200]) +ylim([-100, 100]) +xlabel("Y motion [$nm$]"); +ylabel("Z motion [$nm$]"); +#+end_src + #+begin_src matlab %% Compute RMS values while in closed-loop [~, i_m0] = find(data_tomo_30rpm_m0.hac_status == 1); @@ -4349,513 +4549,34 @@ yztomography3dmovie('movies/id31_tomography_m0_30rpm_robust_xyz.avi', data_tomo_ yztomographymovie('movies/tomography_30rpm_m0_robust', data_tomo_30rpm_m0, 'xlim_ax1', [-3, 3], 'ylim_ax1', [-3, 3], 'xlim_ax2', [-300, 300], 'ylim_ax2', [-300, 300]) #+end_src -*** TODO Slow Tomography Scans Comparison of control performances :noexport: -#+begin_src matlab -% Decentralized in the frame of the struts -data = load("2023-08-18_10-43_m0_1rpm.mat"); -data.time = Ts*[0:length(data.Rz)-1]; - -% Rotating cartesian frame -data_cart = load("2023-08-18_18-33_m0_1rpm_K_cart.mat"); -data_cart.time = Ts*[0:length(data_cart.Rz)-1]; - -% Fixed cartesian frame -data_cart_fixed = load("2023-08-18_19-08_m0_1rpm_K_cart_fixed.mat"); -data_cart_fixed.time = Ts*[0:length(data_cart_fixed.Rz)-1]; - -% Fixed cartesian frame with Complementary Filters -data_cf = load("2023-08-21_14-28_m0_1rpm_K_cf.mat"); -data_cf.time = Ts*[0:length(data_cf.Rz)-1]; -#+end_src - -#+begin_src matlab -1e9*rms(data.Dx_int(data.time<45)) -1e9*rms(data_cart.Dx_int(data_cart.time<45)) -1e9*rms(data_cart_fixed.Dx_int(data_cart_fixed.time<45)) -1e9*rms(data_cf.Dx_int(data_cf.time<45)) -#+end_src - -#+begin_src matlab -1e9*rms(data.Dy_int(data.time<45)) -1e9*rms(data_cart.Dy_int(data_cart.time<45)) -1e9*rms(data_cart_fixed.Dy_int(data_cart_fixed.time<45)) -1e9*rms(data_cf.Dy_int(data_cf.time<45)) -#+end_src - -#+begin_src matlab -1e9*rms(data.Dz_int(data.time<45)) -1e9*rms(data_cart.Dz_int(data_cart.time<45)) -1e9*rms(data_cart_fixed.Dz_int(data_cart_fixed.time<45)) -1e9*rms(data_cf.Dz_int(data_cf.time<45)) -#+end_src - -#+begin_src matlab -1e9*rms(data.Rx_int(data.time<45)) -1e9*rms(data_cart.Rx_int(data_cart.time<45)) -1e9*rms(data_cart_fixed.Rx_int(data_cart_fixed.time<45)) -1e9*rms(data_cf.Rx_int(data_cf.time<45)) -#+end_src - -#+begin_src matlab -1e9*rms(data.Ry_int(data.time<45)) -1e9*rms(data_cart.Ry_int(data_cart.time<45)) -1e9*rms(data_cart_fixed.Ry_int(data_cart_fixed.time<45)) -1e9*rms(data_cf.Ry_int(data_cf.time<45)) -#+end_src - -#+begin_src matlab -figure; - -hold on; -plot(data.time, data.Dy_int) -plot(data_cart.time, data_cart.Dy_int) -plot(data_cart_fixed.time, data_cart_fixed.Dy_int) -plot(data_cf.time, data_cf.Dy_int) -hold off; -#+end_src - -#+begin_src matlab :exports none -% Hannning Windows -Nfft = floor(10.0/Ts); -win = hanning(Nfft); -Noverlap = floor(Nfft/2); - -[data.pxx_Dx, data.f] = pwelch(detrend(data.Dx_int(data.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data.pxx_Dy, ~ ] = pwelch(detrend(data.Dy_int(data.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data.pxx_Dz, ~ ] = pwelch(detrend(data.Dz_int(data.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data.pxx_Rx, ~ ] = pwelch(detrend(data.Rx_int(data.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data.pxx_Ry, ~ ] = pwelch(detrend(data.Ry_int(data.time<45), 0), win, Noverlap, Nfft, 1/Ts); - -[data_cart.pxx_Dx, data_cart.f] = pwelch(detrend(data_cart.Dx_int(data_cart.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart.pxx_Dy, ~ ] = pwelch(detrend(data_cart.Dy_int(data_cart.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart.pxx_Dz, ~ ] = pwelch(detrend(data_cart.Dz_int(data_cart.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart.pxx_Rx, ~ ] = pwelch(detrend(data_cart.Rx_int(data_cart.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart.pxx_Ry, ~ ] = pwelch(detrend(data_cart.Ry_int(data_cart.time<45), 0), win, Noverlap, Nfft, 1/Ts); - -[data_cart_fixed.pxx_Dx, data_cart_fixed.f] = pwelch(detrend(data_cart_fixed.Dx_int(data_cart_fixed.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart_fixed.pxx_Dy, ~ ] = pwelch(detrend(data_cart_fixed.Dy_int(data_cart_fixed.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart_fixed.pxx_Dz, ~ ] = pwelch(detrend(data_cart_fixed.Dz_int(data_cart_fixed.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart_fixed.pxx_Rx, ~ ] = pwelch(detrend(data_cart_fixed.Rx_int(data_cart_fixed.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cart_fixed.pxx_Ry, ~ ] = pwelch(detrend(data_cart_fixed.Ry_int(data_cart_fixed.time<45), 0), win, Noverlap, Nfft, 1/Ts); - -[data_cf.pxx_Dx, data_cf.f] = pwelch(detrend(data_cf.Dx_int(data_cf.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cf.pxx_Dy, ~ ] = pwelch(detrend(data_cf.Dy_int(data_cf.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cf.pxx_Dz, ~ ] = pwelch(detrend(data_cf.Dz_int(data_cf.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cf.pxx_Rx, ~ ] = pwelch(detrend(data_cf.Rx_int(data_cf.time<45), 0), win, Noverlap, Nfft, 1/Ts); -[data_cf.pxx_Ry, ~ ] = pwelch(detrend(data_cf.Ry_int(data_cf.time<45), 0), win, Noverlap, Nfft, 1/Ts); -#+end_src - -#+begin_src matlab -figure; - -hold on; -plot(data.f, data.pxx_Dy) -plot(data_cart.f, data_cart.pxx_Dy) -plot(data_cart_fixed.f, data_cart_fixed.pxx_Dy) -plot(data_cf.f, data_cf.pxx_Dy) -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); -% legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); -xlim([0.1, 5e2]); -#+end_src - -#+begin_src matlab -figure; - -hold on; -plot(data.f, sqrt(flip(-cumtrapz(flip(data.f), flip(data.pxx_Dy))))) -plot(data_cart.f, sqrt(flip(-cumtrapz(flip(data_cart.f), flip(data_cart.pxx_Dy))))) -plot(data_cart_fixed.f, sqrt(flip(-cumtrapz(flip(data_cart_fixed.f), flip(data_cart_fixed.pxx_Dy))))) -plot(data_cf.f, sqrt(flip(-cumtrapz(flip(data_cf.f), flip(data_cf.pxx_Dy))))) -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); -% legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); -xlim([0.1, 5e2]); -#+end_src - -*** TODO Medium velocity tomography scans with CF control :noexport: -#+begin_src matlab -data_m1_cf = load("2023-08-21_19-18_m1_6rpm_cf_control.mat"); -data_m1_cf.time = Ts*[0:length(data_m1_cf.Rz)-1]; -#+end_src - -#+begin_src matlab -data_m2_cf = load("2023-08-21_18-07_m2_6rpm_cf_control.mat"); -data_m2_cf.time = Ts*[0:length(data_m2_cf.Rz)-1]; -#+end_src - -And higher bandwidth: -#+begin_src matlab -data_m1_cf_high_fb = load("2023-08-21_19-24_m1_6rpm_cf_control_60Hz.mat"); -data_m1_cf_high_fb.time = Ts*[0:length(data_m1_cf_high_fb.Rz)-1]; -#+end_src - -#+begin_src matlab -figure; -hold on; -plot(data_m1_cf.Dy_int, detrend(data_m1_cf.Dz_int, 0), 'DisplayName', 'm1') -plot(data_m2_cf.Dy_int, detrend(data_m2_cf.Dz_int, 0), 'DisplayName', 'm2') -plot(data_m1_cf_high_fb.Dy_int, detrend(data_m1_cf_high_fb.Dz_int, 0), 'DisplayName', 'm1, high BW') -axis equal -legend -#+end_src - -#+begin_src matlab -1e9*rms(detrend(data_m1.Dz_int(i_m1+50000:end), 0)) -1e9*rms(detrend(data_m1.Dy_int(i_m1+50000:end), 0)) -1e9*rms(detrend(data_m1.Ry_int(i_m1+50000:end), 0)) -#+end_src - -#+begin_src matlab -1e9*rms(detrend(data_m1_cf.Dz_int, 0)) -1e9*rms(detrend(data_m1_cf.Dy_int, 0)) -1e9*rms(detrend(data_m1_cf.Ry_int, 0)) -#+end_src - -#+begin_src matlab -1e9*rms(detrend(data_m2.Dz_int, 0)) -1e9*rms(detrend(data_m2.Dy_int, 0)) -1e9*rms(detrend(data_m2.Ry_int, 0)) -#+end_src - -#+begin_src matlab -1e9*rms(detrend(data_m1_high_fb.Dz_int, 0)) -1e9*rms(detrend(data_m1_high_fb.Dy_int, 0)) -1e9*rms(detrend(data_m1_high_fb.Ry_int, 0)) -#+end_src - -*** TODO Fast Tomography Scan with Complementary Filter Controller :noexport: -#+begin_src matlab -data_cf = load("2023-08-21_14-33_m0_30rpm_cf_control.mat"); -data_cf.time = Ts*[0:length(data_cf.Rz)-1]; -#+end_src - -#+begin_src matlab -[~, i0] = find(data.hac_status == 1); -1e9*rms(data.Dy_int(i0(1)+5000:end)) -1e9*rms(data.Dz_int(i0(1)+5000:end)) - -1e9*rms(data_cf.Dy_int) -1e9*rms(data_cf.Dz_int) -#+end_src - -Same performance than the robust controller in terms of RMS residual motion. - -#+begin_src matlab -figure; plot3(data.Dx_int, data.Dy_int, data.Dz_int) -#+end_src - -*** Tomography - Effect of the scanning velocity :noexport: -- [ ] What are the controller used here? Why worst results than with the robust controller? - -#+begin_src matlab -data_1rpm = load("2023-08-18_10-43_m0_1rpm.mat"); -data_1rpm.time = Ts*[0:length(data_1rpm.Rz)-1]; -#+end_src - -#+begin_src matlab -data_30rpm = load("2023-08-18_10-45_m0_30rpm.mat"); -data_30rpm.time = Ts*[0:length(data_30rpm.Rz)-1]; -#+end_src - -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable([1e9*rms(detrend(data_1rpm.Dy_int, 0)), 1e9*rms(detrend(data_30rpm.Dy_int, 0)); 1e9*rms(detrend(data_1rpm.Dz_int, 0)), 1e9*rms(detrend(data_30rpm.Dz_int, 0)); 1e9*rms(detrend(data_1rpm.Ry_int, 0)), 1e9*rms(detrend(data_30rpm.Ry_int, 0))]', {'1RPM', '30RPM'}, {'$D_y$', '$D_z$', '$R_y$'}, ' %.1f '); -#+end_src - -#+name: tab:id31_tomography_effect_velocity_rms -#+caption: RMS values of the errors during tomography scan - Effect of $R_z$ velocity -#+attr_latex: :environment tabularx :width 0.5\linewidth :align lXXX -#+attr_latex: :center t :booktabs t -#+RESULTS: -| | $D_y$ | $D_z$ | $R_y$ | -|-------+-------+-------+-------| -| 1RPM | 30.9 | 5.9 | 92.4 | -| 30RPM | 71.7 | 12.5 | 301.3 | - - -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable([1e9*data_tomo_1rpm_m0.Dx_rms_cl, 1e9*data_tomo_1rpm_m0.Dy_rms_cl, 1e9*data_tomo_1rpm_m0.Dz_rms_cl, 1e9*data_tomo_1rpm_m0.Rx_rms_cl, 1e9*data_tomo_1rpm_m0.Ry_rms_cl; ... - 1e9*data_tomo_6rpm_m0.Dx_rms_cl, 1e9*data_tomo_6rpm_m0.Dy_rms_cl, 1e9*data_tomo_6rpm_m0.Dz_rms_cl, 1e9*data_tomo_6rpm_m0.Rx_rms_cl, 1e9*data_tomo_6rpm_m0.Ry_rms_cl; ... - 1e9*data_tomo_30rpm_m0.Dx_rms_cl, 1e9*data_tomo_30rpm_m0.Dy_rms_cl, 1e9*data_tomo_30rpm_m0.Dz_rms_cl, 1e9*data_tomo_30rpm_m0.Rx_rms_cl, 1e9*data_tomo_30rpm_m0.Ry_rms_cl], ... - {'1rpm', '6rpm', '30rpm'}, {'$D_x$ [$\mu m$]', '$D_y$ [$\mu m$]', '$D_z$ [$nm$]', '$R_x$ [$\mu\text{rad}$]', '$R_y$ [$\mu\text{rad}$]'}, ' %.0f '); -#+end_src - -#+RESULTS: -| | $D_x$ [$\mu m$] | $D_y$ [$\mu m$] | $D_z$ [$nm$] | $R_x$ [$\mu\text{rad}$] | $R_y$ [$\mu\text{rad}$] | -|-------+-----------------+-----------------+--------------+-------------------------+-------------------------| -| 1rpm | 13 | 15 | 5 | 57 | 55 | -| 6rpm | 17 | 19 | 5 | 70 | 73 | -| 30rpm | 34 | 38 | 10 | 127 | 129 | - -** $D_z$ scans: Dirty Layer Scans -<> -*** Step by Step $D_z$ motion -#+begin_src matlab -%% Load Dz MIM data -data_dz_steps_3nm = load("2023-08-18_14-57_dz_mim_3_nm.mat"); -data_dz_steps_3nm.time = Ts*[0:length(data_dz_steps_3nm.Dz_int)-1]; - -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 - -Three step sizes are tested: -- $10\,nm$ steps (Figure ref:fig:id31_dz_mim_10nm_steps) -- $100\,nm$ steps (Figure ref:fig:id31_dz_mim_100nm_steps) -- $1\,\mu m$ steps (Figure ref:fig:id31_dz_steps_response) - -#+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)))) -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ Motion [nm]'); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_dz_mim_10nm_steps.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:id31_dz_mim_10nm_steps -#+caption: Dz MIM test with 10nm steps (low pass filter with cut-off frequency of 10Hz is applied) -#+RESULTS: -[[file:figs/id31_dz_mim_10nm_steps.png]] - -#+begin_src matlab :exports none :results none -%% Dz MIM test with 10nm 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)))) -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ Motion [nm]'); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_dz_mim_100nm_steps.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:id31_dz_mim_100nm_steps -#+caption: Dz MIM test with 100nm steps -#+RESULTS: -[[file:figs/id31_dz_mim_100nm_steps.png]] - -#+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(data_dz_steps_1000nm.time-data_dz_steps_1000nm.time(i0), 1e9*(data_dz_steps_1000nm.Dz_int - mean(data_dz_steps_1000nm.Dz_int(1:1000)))) -plot([-1, 1], [1000-20, 1000-20], 'k--') -plot([-1, 1], [1000+20, 1000+20], 'k--') -xline(0, 'k--', 'LineWidth', 1.5) -xline(0.07, 'k--', 'LineWidth', 1.5) -hold off; -xlabel('Time [s]'); -ylabel('$D_z$ Motion [nm]'); -xlim([-0.1, 0.2]); -ylim([-100, 1600]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_dz_steps_response.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:id31_dz_steps_response -#+caption: $D_z$ step response - Stabilization time is around 70ms -#+RESULTS: -[[file:figs/id31_dz_steps_response.png]] - - -*** Continuous $D_z$ motion: Dirty Layer Scans -#+begin_src matlab -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]; -#+end_src - -#+begin_src matlab -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 - -Two $D_z$ scans are performed: -- at $10\,\mu m/s$ in Figure ref:fig:id31_dirty_layer_scan_m0 -- at $100\,\mu m/s$ in Figure ref:fig:id31_dirty_layer_scan_m0_large - -#+begin_src matlab :exports none :results none -%% Dirty layer scan: Dz motion -figure; -hold on; -plot(data_dz_10ums.time, 1e6*data_dz_10ums.Dz_int, ... - 'DisplayName', sprintf('$\\epsilon D_z = %.0f$ nm RMS', 1e9*rms(data_dz_10ums.e_dz))) -plot(data_dz_10ums.time, 1e6*data_dz_10ums.e_dy, ... - 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nm RMS', 1e9*rms(data_dz_10ums.e_dy))) -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))) -hold off; -xlabel('Time [s]'); -ylabel('Motion [$\mu$m]'); -xlim([0, 2.2]) -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_dirty_layer_scan_m0.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:id31_dirty_layer_scan_m0 -#+caption: Dirty layer scan: $D_z$ motion at $10\,\mu m/s$ -#+RESULTS: -[[file:figs/id31_dirty_layer_scan_m0.png]] - -#+begin_src matlab :exports none :results none -%% Dirty layer scan: Dz motion -figure; -hold on; -plot(data_dz_100ums.time, 1e6*data_dz_100ums.Dz_int, ... - 'DisplayName', sprintf('$\\epsilon D_z = %.0f$ nm RMS', 1e9*rms(data_dz_100ums.e_dz))) -plot(data_dz_100ums.time, 1e6*data_dz_100ums.e_dy, ... - 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nm RMS', 1e9*rms(data_dz_100ums.e_dy))) -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))) -hold off; -xlabel('Time [s]'); -ylabel('Motion [$\mu$m]'); -xlim([0, 2.2]) -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_dirty_layer_scan_m0_large.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:id31_dirty_layer_scan_m0_large -#+caption: Dirty layer scan: $D_z$ motion at $100\,\mu m/s$ -#+RESULTS: -[[file:figs/id31_dirty_layer_scan_m0_large.png]] - -#+begin_src matlab -%% Not so good results with the CF controller -data_cf = load(sprintf("%s/scans/2023-08-21_19-20_dirty_layer_m1_cf.mat", mat_dir)); -data_cf.time = Ts*[0:length(data_cf.Dz_int)-1]; -#+end_src - -** $R_y$ scans: Reflectivity -<> -#+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 - -An $R_y$ scan is performed at $100\,\mu rad/s$ velocity (Figure ref:fig:id31_reflectivity_scan_Ry_100urads). -During the $R_y$ scan, the errors in $D_y$ are $D_z$ are kept small. - -#+begin_src matlab :exports none :results none -%% Ry reflectivity scan -figure; -hold on; -plot(data_ry.time, 1e6*data_ry.Ry_int, 'DisplayName', sprintf('$\\epsilon R_y = %.2f$ $\\mu$rad RMS', 1e6*rms(data_ry.e_ry))) -plot(data_ry.time, 1e6*data_ry.e_dy, 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nm RMS', 1e9*rms(data_ry.e_dy))) -plot(data_ry.time, 1e6*data_ry.e_dz, 'DisplayName', sprintf('$\\epsilon D_z = %.0f$ nm RMS', 1e9*rms(data_ry.e_dz))) -hold off; -xlabel('Time [s]'); -ylabel('$R_y$ motion [$\mu$rad]') -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); -xlim([0, 6.2]); -ylim([-310, 310]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_reflectivity_scan_Ry_100urads.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:id31_reflectivity_scan_Ry_100urads -#+caption: $R_y$ reflecitivity scan at $100\,\mu\text{rad}/s$ velocity -#+RESULTS: -[[file:figs/id31_reflectivity_scan_Ry_100urads.png]] - - -** $D_y$ Scans +** $D_y$ - Lateral Scans <> -*** Introduction :ignore: -The steps generated by the IcePAP for the $T_y$ stage are send to the Speedgoat. -Then, we can know in real time what is the wanted position in $D_y$ during $T_y$ scans. -*** Open Loop +**** Introduction :ignore: +Lateral scans are performed with the $T_y$ stage. +The stepper motor controller[fn:5] outputs the setpoint which is received by the Speedgoat. +In the Speedgoat, the setpoint is compared with the measured $D_y$ position of the top-platform, and the Nano-Hexapod is used to correct positioning errors induced by the scanning of the $T_y$ stage. +The stroke is here limited to $\pm 100\,\mu m$ due to the limited acceptance of the metrology system. + +**** Slow scan + +The $T_y$ stage is first scanned with a velocity of $10\,\mu m/s$ which is typical for such experiments. +The errors in open-loop (i.e. without using the NASS) and in closed-loop are compared in Figure ref:fig:test_id31_dy_10ums. + +In the direction of motion, periodic errors can be observed in the open-loop case (Figure ref:fig:test_id31_dy_10ums_dy). +These errors are induced by the stepper motor being used in the $T_y$ stage. +Indeed, stepper motors inherently have "micro-stepping errors" which are periodic errors happening 200 times per motor rotation with an amplitude approximately equal to $1\,\text{mrad}$. +As the lead screw for the $T_y$ stage has a pitch of $2\,mm$, this means that the micro-stepping errors have a period of $10\,\mu m$ and an amplitude of $\approx 300\,nm$ which can indeed be seen in open-loop. + +In the vertical direction (Figure ref:fig:test_id31_dy_10ums_dz), open-loop errors are most likely due to measurement errors of the metrology itself as the top interferometer point at a sphere (see Figure ref:fig:test_id31_xy_map_sphere). + +In closed-loop, the errors are within the specifications in all directions. + #+begin_src matlab -%% Slow Ty scan (10um/s) +%% Slow Ty scan (10um/s) - OL data_ty_ol_slow = load("2023-08-21_20-05_ty_scan_m1_open_loop_slow.mat"); data_ty_ol_slow.time = Ts*[0:length(data_ty_ol_slow.Dy_int)-1]; -#+end_src -We can clearly see micro-stepping errors of the stepper motor used for the $T_y$ stage. -The errors have a period of $10\,\mu m$ with an amplitude of $\pm 100\,nm$. - -#+begin_src matlab :exports none :results none -%% Ty scan (at 10um/s) - Dy errors -figure; -plot(1e6*data_ty_ol_slow.Ty, 1e6*detrend(data_ty_ol_slow.e_dy, 0)) -xlabel('Ty position [$\mu$m]'); -ylabel('$D_y$ error [$\mu$m]'); -xlim([-100, 100]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_ty_scan_10ums_ol_dy_errors.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:id31_ty_scan_10ums_ol_dy_errors -#+caption: $T_y$ scan (at $10\,\mu m/s$) - $D_y$ errors. The micro-stepping errors can clearly be seen with a period of $10\,\mu m$ and an amplitude of $\pm 100\,nm$ -#+RESULTS: -[[file:figs/id31_ty_scan_10ums_ol_dy_errors.png]] - -#+begin_src matlab :exports none :results none -%% Ty scan (at 10um/s) - Dz and Ry errors -figure; -tiledlayout(1, 2, 'TileSpacing', 'compact', 'Padding', 'None'); - -ax1 = nexttile; -hold on; -plot(1e6*data_ty_ol_slow.Ty, 1e6*detrend(data_ty_ol_slow.e_dz, 0)) -hold off; -xlabel('Ty position [$\mu$m]'); -ylabel('$D_z$ error [$\mu$m]'); -xlim([-100, 100]) - -ax2 = nexttile; -hold on; -plot(1e6*data_ty_ol_slow.Ty, 1e6*data_ty_ol_slow.e_ry) -hold off; -xlabel('Ty position [$\mu$m]'); -ylabel('$R_y$ error [$\mu$rad]'); -xlim([-100, 100]) -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_ty_scan_10ums_ol_dz_ry_errors.pdf', 'width', 'full', 'height', 'normal'); -#+end_src - -#+name: fig:id31_ty_scan_10ums_ol_dz_ry_errors -#+caption: $T_y$ scan (at $10\,\mu m/s$) - $D_z$ and $R_y$ errors. The $D_z$ error is most likely due to having the top interferometer pointing to a sphere. The large $R_y$ errors might also be due to the metrology system -#+RESULTS: -[[file:figs/id31_ty_scan_10ums_ol_dz_ry_errors.png]] - -*** Closed Loop -#+begin_src matlab %% Slow Ty scan (10um/s) - CL data_ty_cl_slow = load("2023-08-21_20-07_ty_scan_m1_cf_closed_loop_slow.mat"); data_ty_cl_slow.time = Ts*[0:length(data_ty_cl_slow.Dy_int)-1]; @@ -4866,278 +4587,1046 @@ data_ty_cl_slow.time = Ts*[0:length(data_ty_cl_slow.Dy_int)-1]; figure; hold on; plot(1e6*data_ty_ol_slow.Ty, 1e6*detrend(data_ty_ol_slow.e_dy, 0), ... - 'DisplayName', 'OL') + 'DisplayName', 'Open-loop') plot(1e6*data_ty_cl_slow.Ty, 1e6*detrend(data_ty_cl_slow.e_dy, 0), ... - 'DisplayName', sprintf('CL - $\\epsilon D_y = %.0f$ nmRMS', 1e9*rms(detrend(data_ty_cl_slow.e_dy, 0)))) + 'DisplayName', 'Closed-loop') +plot([-100, 100], 1e-3*[specs_dy_peak, specs_dy_peak], 'k--', 'DisplayName', 'Specifications'); +plot([-100, 100], 1e-3*[-specs_dy_peak, -specs_dy_peak], 'k--', 'HandleVisibility', 'off'); hold off; xlabel('Ty position [$\mu$m]'); ylabel('$D_y$ error [$\mu$m]'); xlim([-100, 100]) -legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; #+end_src #+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_ty_scan_10ums_cl_dy_errors.pdf', 'width', 'wide', 'height', 'normal'); +exportFig('figs/test_id31_dy_10ums_dy.pdf', 'width', 'third', 'height', 'normal'); #+end_src -#+name: fig:id31_ty_scan_10ums_cl_dy_errors -#+caption: $T_y$ scan (at $10\,\mu m/s$) - $D_y$ errors. Open-loop and Closed-loop scans -#+RESULTS: -[[file:figs/id31_ty_scan_10ums_cl_dy_errors.png]] - #+begin_src matlab :exports none :results none %% Ty scan (at 10um/s) - Dz and Ry errors figure; -tiledlayout(1, 2, 'TileSpacing', 'compact', 'Padding', 'None'); - -ax1 = nexttile; hold on; plot(1e6*data_ty_ol_slow.Ty, 1e6*detrend(data_ty_ol_slow.e_dz, 0), ... - 'DisplayName', 'OL') + 'DisplayName', 'Open-loop') plot(1e6*data_ty_cl_slow.Ty, 1e6*detrend(data_ty_cl_slow.e_dz, 0), ... - 'DisplayName', sprintf('Cl - $\\epsilon D_z = %.0f$ nmRMS', 1e9*rms(detrend(data_ty_cl_slow.e_dz, 0)))) + 'DisplayName', 'Closed-loop') +plot([-100, 100], 1e-3*[specs_dz_peak, specs_dz_peak], 'k--', 'DisplayName', 'Specifications'); +plot([-100, 100], 1e-3*[-specs_dz_peak, -specs_dz_peak], 'k--', 'HandleVisibility', 'off'); hold off; xlabel('Ty position [$\mu$m]'); ylabel('$D_z$ error [$\mu$m]'); xlim([-100, 100]) -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); - -ax2 = nexttile; -hold on; -plot(1e6*data_ty_ol_slow.Ty, 1e6*data_ty_ol_slow.e_ry, ... - 'DisplayName', 'OL') -plot(1e6*data_ty_cl_slow.Ty, 1e6*data_ty_cl_slow.e_ry, ... - 'DisplayName', sprintf('Cl - $\\epsilon R_y = %.2f$ uradRMS', 1e6*rms(detrend(data_ty_cl_slow.e_ry, 0)))) -hold off; -xlabel('Ty position [$\mu$m]'); -ylabel('$R_y$ error [$\mu$rad]'); -xlim([-100, 100]) -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +ylim([-0.4, 0.4]) +leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; #+end_src #+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_ty_scan_10ums_cl_dz_ry_errors.pdf', 'width', 'full', 'height', 'normal'); +exportFig('figs/test_id31_dy_10ums_dz.pdf', 'width', 'third', 'height', 'normal'); #+end_src -#+name: fig:id31_ty_scan_10ums_cl_dz_ry_errors -#+caption: $T_y$ scan (at $10\,\mu m/s$) - $D_z$ and $R_y$ errors. Open-loop and Closed-loop scans -#+RESULTS: -[[file:figs/id31_ty_scan_10ums_cl_dz_ry_errors.png]] +#+begin_src matlab :exports none :results none +figure; +hold on; +plot(1e6*data_ty_ol_slow.Ty, 1e6*data_ty_ol_slow.e_ry, ... + 'DisplayName', 'Open-loop') +plot(1e6*data_ty_cl_slow.Ty, 1e6*data_ty_cl_slow.e_ry, ... + 'DisplayName', 'Closed-loop') +plot([-100, 100], [specs_ry_peak, specs_ry_peak], 'k--', 'DisplayName', 'Specifications'); +plot([-100, 100], [-specs_ry_peak, -specs_ry_peak], 'k--', 'HandleVisibility', 'off'); +hold off; +xlabel('Ty position [$\mu$m]'); +ylabel('$R_y$ error [$\mu$rad]'); +xlim([-100, 100]); +ylim([-10, 10]) +leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/test_id31_dy_10ums_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_dy_10ums +#+caption: Open-Loop (in blue) and Closed-loop (i.e. using the NASS, in red) during a $10\,\mu m/s$ scan with the $T_y$ stage. Errors in $D_y$ is shown in (\subref{fig:test_id31_dy_10ums_dy}). +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dy_10ums_dy} $D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dy_10ums_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dy_10ums_dz} $D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dy_10ums_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dy_10ums_ry} $R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dy_10ums_ry.png]] +#+end_subfigure +#+end_figure + +**** Faster Scan + +The performance of the NASS is then tested for a scanning velocity of $100\,\mu m/s$ and the results are shown in Figure ref:fig:test_id31_dy_100ums. +At this velocity, the micro-stepping errors have a frequency of $10\,\text{Hz}$ and are inducing lot's of vibrations which are even amplified by some resonances of the micro-station. +These vibrations are outside the bandwidth of the NASS feedback controller and therefore not well reduced in closed-loop. + +This is the main reason why stepper motors should be not be used for "long-stroke / short-stroke" systems when good scanning performances are wanted [[cite:&dehaeze22_fastj_uhv]]. +In order to improve the scanning performances at high velocity, the stepper motor of the $T_y$ stage could be replaced by a three-phase torque motor for instance. + +As the closed-loop errors in $D_z$ and $R_y$ directions are within specifications (see Figures ref:fig:test_id31_dy_100ums_dz and ref:fig:test_id31_dy_100ums_ry), another option would be to trigger the detectors based on the measured $D_y$ position instead of based on time or on the $T_y$ setpoint. +This would make the experiment less sensitive to $D_y$ vibrations. +For small $D_y$ scans, the nano-hexapod alone can be used for the scans, but with limited strokes. -*** Faster Scan #+begin_src matlab %% Fast Ty scan (100um/s) - OL data_ty_ol_fast = load("2023-08-21_20-05_ty_scan_m1_open_loop.mat"); data_ty_ol_fast.time = Ts*[0:length(data_ty_ol_fast.Dy_int)-1]; -#+end_src -#+begin_src matlab %% Fast Ty scan (10um/s) - CL data_ty_cl_fast = load("2023-08-21_20-07_ty_scan_m1_cf_closed_loop.mat"); data_ty_cl_fast.time = Ts*[0:length(data_ty_cl_fast.Dy_int)-1]; #+end_src -Because of micro-stepping errors of the Ty stepper motor, when scanning at high velocity this induce high frequency vibration that are outside the bandwidth of the feedback controller. - -At $100\,\mu m/s$, the micro-stepping errors with a period of $10\,\mu m$ (see Figure ref:fig:id31_ty_scan_10ums_ol_dy_errors) are at 10Hz. -These errors are them amplified by some resonances in the system. - -This could be easily solved by changing the stepper motor for a torque motor for instance. - #+begin_src matlab :exports none :results none %% Ty scan (at 100um/s) - Dy errors figure; hold on; plot(1e6*data_ty_ol_fast.Ty, 1e6*detrend(data_ty_ol_fast.e_dy, 0), ... - 'DisplayName', 'OL') + 'DisplayName', 'Open-loop') plot(1e6*data_ty_cl_fast.Ty, 1e6*detrend(data_ty_cl_fast.e_dy, 0), ... - 'DisplayName', sprintf('CL - $\\epsilon D_y = %.0f$ nmRMS', 1e9*rms(detrend(data_ty_cl_fast.e_dy, 0)))) + 'DisplayName', 'Closed-loop') +plot([-100, 100], 1e-3*[specs_dy_peak, specs_dy_peak], 'k--', 'DisplayName', 'Specifications'); +plot([-100, 100], 1e-3*[-specs_dy_peak, -specs_dy_peak], 'k--', 'HandleVisibility', 'off'); hold off; xlabel('Ty position [$\mu$m]'); ylabel('$D_y$ error [$\mu$m]'); -xlim([-100, 100]) -legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +xlim([-100, 100]); +ylim([-3, 3]); +leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; #+end_src #+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_ty_scan_100ums_cl_dy_errors.pdf', 'width', 'wide', 'height', 'normal'); +exportFig('figs/test_id31_dy_100ums_dy.pdf', 'width', 'third', 'height', 'normal'); #+end_src -#+name: fig:id31_ty_scan_100ums_cl_dy_errors -#+caption: $T_y$ scan (at $100\,\mu m/s$) - $D_y$ errors. Open-loop and Closed-loop scans -#+RESULTS: -[[file:figs/id31_ty_scan_100ums_cl_dy_errors.png]] - #+begin_src matlab :exports none :results none %% Ty scan (at 100um/s) - Dz and Ry errors figure; -tiledlayout(1, 2, 'TileSpacing', 'compact', 'Padding', 'None'); - -ax1 = nexttile; hold on; plot(1e6*data_ty_ol_fast.Ty, 1e6*detrend(data_ty_ol_fast.e_dz, 0), ... - 'DisplayName', 'OL') + 'DisplayName', 'Open-loop') plot(1e6*data_ty_cl_fast.Ty, 1e6*detrend(data_ty_cl_fast.e_dz, 0), ... - 'DisplayName', sprintf('Cl - $\\epsilon D_z = %.0f$ nmRMS', 1e9*rms(detrend(data_ty_cl_fast.e_dz, 0)))) + 'DisplayName', 'Closed-loop') +plot([-100, 100], 1e-3*[specs_dz_peak, specs_dz_peak], 'k--', 'DisplayName', 'Specifications'); +plot([-100, 100], 1e-3*[-specs_dz_peak, -specs_dz_peak], 'k--', 'HandleVisibility', 'off'); hold off; xlabel('Ty position [$\mu$m]'); ylabel('$D_z$ error [$\mu$m]'); -xlim([-100, 100]) -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); - -ax2 = nexttile; -hold on; -plot(1e6*data_ty_ol_fast.Ty, 1e6*data_ty_ol_fast.e_ry, ... - 'DisplayName', 'OL') -plot(1e6*data_ty_cl_fast.Ty, 1e6*data_ty_cl_fast.e_ry, ... - 'DisplayName', sprintf('Cl - $\\epsilon R_y = %.2f$ uradRMS', 1e6*rms(detrend(data_ty_cl_fast.e_ry, 0)))) -hold off; -xlabel('Ty position [$\mu$m]'); -ylabel('$R_y$ error [$\mu$rad]'); -xlim([-100, 100]) -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +xlim([-100, 100]); +ylim([-0.4, 0.4]); +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/id31_ty_scan_100ums_cl_dz_ry_errors.pdf', 'width', 'full', 'height', 'normal'); +exportFig('figs/test_id31_dy_100ums_dz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +figure; +hold on; +plot(1e6*data_ty_ol_fast.Ty, 1e6*data_ty_ol_fast.e_ry, ... + 'DisplayName', 'Open-loop') +plot(1e6*data_ty_cl_fast.Ty, 1e6*data_ty_cl_fast.e_ry, ... + 'DisplayName', 'Closed-loop') +plot([-100, 100], [specs_ry_peak, specs_ry_peak], 'k--', 'DisplayName', 'Specifications'); +plot([-100, 100], [-specs_ry_peak, -specs_ry_peak], 'k--', 'HandleVisibility', 'off'); +hold off; +xlabel('Ty position [$\mu$m]'); +ylabel('$R_y$ error [$\mu$rad]'); +xlim([-100, 100]); +ylim([-10, 10]) +leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/test_id31_dy_100ums_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:test_id31_dy_100ums +#+caption: Open-Loop (in blue) and Closed-loop (i.e. using the NASS, in red) during a $100\,\mu m/s$ scan with the $T_y$ stage. Errors in $D_y$ is shown in (\subref{fig:test_id31_dy_100ums_dy}). +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dy_100ums_dy} $D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dy_100ums_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dy_100ums_dz} $D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dy_100ums_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_dy_100ums_ry} $R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_dy_100ums_ry.png]] +#+end_subfigure +#+end_figure + +**** Conclusion + +#+begin_src matlab +%% Compute errors for Dy scans +i_ty_ol_slow = data_ty_ol_slow.Ty > data_ty_ol_slow.Ty(1) & data_ty_ol_slow.Ty < data_ty_ol_slow.Ty(end); +i_ty_cl_slow = data_ty_cl_slow.Ty > data_ty_cl_slow.Ty(1) & data_ty_cl_slow.Ty < data_ty_cl_slow.Ty(end); +i_ty_ol_fast = data_ty_ol_fast.Ty > data_ty_ol_fast.Ty(1) & data_ty_ol_fast.Ty < data_ty_ol_fast.Ty(end); +i_ty_cl_fast = data_ty_cl_fast.Ty > data_ty_cl_fast.Ty(1) & data_ty_cl_fast.Ty < data_ty_cl_fast.Ty(end); + +% Peak to Peak errors +ty_ol_slow_dy_peak = 1e9*(max(detrend(data_ty_ol_slow.e_dy(i_ty_ol_slow), 0))-min(detrend(data_ty_ol_slow.e_dy(i_ty_ol_slow), 0)))/2; +ty_ol_slow_dz_peak = 1e9*(max(detrend(data_ty_ol_slow.e_dz(i_ty_ol_slow), 0))-min(detrend(data_ty_ol_slow.e_dz(i_ty_ol_slow), 0)))/2; +ty_ol_slow_ry_peak = 1e6*(max(detrend(data_ty_ol_slow.e_ry(i_ty_ol_slow), 0))-min(detrend(data_ty_ol_slow.e_ry(i_ty_ol_slow), 0)))/2; + +ty_cl_slow_dy_peak = 1e9*(max(detrend(data_ty_cl_slow.e_dy(i_ty_cl_slow), 0))-min(detrend(data_ty_cl_slow.e_dy(i_ty_cl_slow), 0)))/2; +ty_cl_slow_dz_peak = 1e9*(max(detrend(data_ty_cl_slow.e_dz(i_ty_cl_slow), 0))-min(detrend(data_ty_cl_slow.e_dz(i_ty_cl_slow), 0)))/2; +ty_cl_slow_ry_peak = 1e6*(max(detrend(data_ty_cl_slow.e_ry(i_ty_cl_slow), 0))-min(detrend(data_ty_cl_slow.e_ry(i_ty_cl_slow), 0)))/2; + +ty_ol_fast_dy_peak = 1e9*(max(detrend(data_ty_ol_fast.e_dy(i_ty_ol_fast), 0))-min(detrend(data_ty_ol_fast.e_dy(i_ty_ol_fast), 0)))/2; +ty_ol_fast_dz_peak = 1e9*(max(detrend(data_ty_ol_fast.e_dz(i_ty_ol_fast), 0))-min(detrend(data_ty_ol_fast.e_dz(i_ty_ol_fast), 0)))/2; +ty_ol_fast_ry_peak = 1e6*(max(detrend(data_ty_ol_fast.e_ry(i_ty_ol_fast), 0))-min(detrend(data_ty_ol_fast.e_ry(i_ty_ol_fast), 0)))/2; + +ty_cl_fast_dy_peak = 1e9*(max(detrend(data_ty_cl_fast.e_dy(i_ty_cl_fast), 0))-min(detrend(data_ty_cl_fast.e_dy(i_ty_cl_fast), 0)))/2; +ty_cl_fast_dz_peak = 1e9*(max(detrend(data_ty_cl_fast.e_dz(i_ty_cl_fast), 0))-min(detrend(data_ty_cl_fast.e_dz(i_ty_cl_fast), 0)))/2; +ty_cl_fast_ry_peak = 1e6*(max(detrend(data_ty_cl_fast.e_ry(i_ty_cl_fast), 0))-min(detrend(data_ty_cl_fast.e_ry(i_ty_cl_fast), 0)))/2; + +% RMS error +ty_ol_slow_dy_rms = 1e9*rms(detrend(data_ty_ol_slow.e_dy(i_ty_ol_slow), 0)); +ty_ol_slow_dz_rms = 1e9*rms(detrend(data_ty_ol_slow.e_dz(i_ty_ol_slow), 0)); +ty_ol_slow_ry_rms = 1e6*rms(detrend(data_ty_ol_slow.e_ry(i_ty_ol_slow), 0)); + +ty_cl_slow_dy_rms = 1e9*rms(detrend(data_ty_cl_slow.e_dy(i_ty_cl_slow), 0)); +ty_cl_slow_dz_rms = 1e9*rms(detrend(data_ty_cl_slow.e_dz(i_ty_cl_slow), 0)); +ty_cl_slow_ry_rms = 1e6*rms(detrend(data_ty_cl_slow.e_ry(i_ty_cl_slow), 0)); + +ty_ol_fast_dy_rms = 1e9*rms(detrend(data_ty_ol_fast.e_dy(i_ty_ol_fast), 0)); +ty_ol_fast_dz_rms = 1e9*rms(detrend(data_ty_ol_fast.e_dz(i_ty_ol_fast), 0)); +ty_ol_fast_ry_rms = 1e6*rms(detrend(data_ty_ol_fast.e_ry(i_ty_ol_fast), 0)); + +ty_cl_fast_dy_rms = 1e9*rms(detrend(data_ty_cl_fast.e_dy(i_ty_cl_fast), 0)); +ty_cl_fast_dz_rms = 1e9*rms(detrend(data_ty_cl_fast.e_dz(i_ty_cl_fast), 0)); +ty_cl_fast_ry_rms = 1e6*rms(detrend(data_ty_cl_fast.e_ry(i_ty_cl_fast), 0)); +#+end_src + +#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) +data2orgtable([ + specs_dy_rms, specs_dz_rms, specs_ry_rms; ... % Specifications + ty_ol_slow_dy_rms, ty_ol_slow_dz_rms, ty_ol_slow_ry_rms; + ty_cl_slow_dy_rms, ty_cl_slow_dz_rms, ty_cl_slow_ry_rms; + ty_ol_fast_dy_rms, ty_ol_fast_dz_rms, ty_ol_fast_ry_rms; + ty_cl_fast_dy_rms, ty_cl_fast_dz_rms, ty_cl_fast_ry_rms], {'Specs', '10um/s (OL)', '10um/s (CL)', '100um/s (OL)', '100um/s (CL)'}, {'$D_y$', '$D_z$', '$R_y$'}, ' %.2f '); #+end_src -#+name: fig:id31_ty_scan_100ums_cl_dz_ry_errors -#+caption: $T_y$ scan (at $100\,\mu m/s$) - $D_z$ and $R_y$ errors. Open-loop and Closed-loop scans #+RESULTS: -[[file:figs/id31_ty_scan_100ums_cl_dz_ry_errors.png]] +| | $D_y$ | $D_z$ | $R_y$ | +|--------------+---------+--------+-------| +| Specs | 30.0 | 15.0 | 0.25 | +|--------------+---------+--------+-------| +| 10um/s (OL) | 585.43 | 154.51 | 6.3 | +| 10um/s (CL) | 20.64 | 9.67 | 0.06 | +|--------------+---------+--------+-------| +| 100um/s (OL) | 1063.58 | 166.85 | 6.44 | +| 100um/s (CL) | 731.63 | 19.91 | 0.36 | + +#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) +data2orgtable([ + specs_dy_peak, specs_dz_peak, specs_ry_peak; ... % Specifications + ty_ol_slow_dy_peak, ty_ol_slow_dz_peak, ty_ol_slow_ry_peak; + ty_cl_slow_dy_peak, ty_cl_slow_dz_peak, ty_cl_slow_ry_peak; + ty_ol_fast_dy_peak, ty_ol_fast_dz_peak, ty_ol_fast_ry_peak; + ty_cl_fast_dy_peak, ty_cl_fast_dz_peak, ty_cl_fast_ry_peak], {'Specs', '10um/s (OL)', '10um/s (CL)', '100um/s (OL)', '100um/s (CL)'}, {'$D_y$', '$D_z$', '$R_y$'}, ' %.2f '); +#+end_src + +#+RESULTS: +| | $D_y$ | $D_z$ | $R_y$ | +|--------------+---------+--------+-------| +| Specs | 100.0 | 50.0 | 0.85 | +| 10um/s (OL) | 1167.8 | 308.35 | 11.06 | +| 10um/s (CL) | 86.36 | 41.6 | 0.28 | +| 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 <> -Instead of doing a fast $R_z$ motion a slow $D_y$, the idea is to perform slow $R_z$ (here 1rpm) and fast $D_y$ scans with the nano-hexapod. + +In diffraction tomography, the micro-station performs combined $R_z$ rotation and $D_y$ lateral scans. +Here the spindle is performing a continuous 1rpm rotation while the nano-hexapod is used to perform fast $D_y$ scans. + +The $T_y$ stage is here not used as the stepper motor would induce high frequency vibrations, therefore the stroke is here limited to $\approx \pm 100\,\mu m/s$. +Several $D_y$ velocities are tested: $0.1\,mm/s$, $0.5\,mm/s$ and $1\,mm/s$. + +The $D_y$ setpoint and the measured positions are shown for all tested velocities in Figure ref:fig:test_id31_diffraction_tomo_setpoint. #+begin_src matlab %% 100um/s - Robust controller data_dt_100ums = load("2023-08-18_17-12_diffraction_tomo_m0.mat"); +t = Ts*[0:length(data_dt_100ums.Dy_int)-1]; +data_dt_100ums = structfun(@(field) field(t>1.0861),data_dt_100ums, 'UniformOutput', false) data_dt_100ums.time = Ts*[0:length(data_dt_100ums.Dy_int)-1]; -%% 500um/s - Robust controller (Not used) -% data_dt_500ums = load(sprintf("%s/scans/2023-08-18_17-19_diffraction_tomo_m0_fast.mat", mat_dir)); -% data_dt_500ums.time = Ts*[0:length(data_dt_500ums.Dy_int)-1]; - %% 500um/s - Complementary filters data_dt_500ums = load("2023-08-21_15-15_diffraction_tomo_m0_fast_cf.mat"); +t = Ts*[0:length(data_dt_500ums.Dy_int)-1]; +data_dt_500ums = structfun(@(field) field(t>0.275),data_dt_500ums, 'UniformOutput', false) data_dt_500ums.time = Ts*[0:length(data_dt_500ums.Dy_int)-1]; %% 1mm/s - Complementary filters data_dt_1000ums = load("2023-08-21_15-16_diffraction_tomo_m0_fast_cf.mat"); +t = Ts*[0:length(data_dt_1000ums.Dy_int)-1]; +data_dt_1000ums = structfun(@(field) field(t>0.19),data_dt_1000ums, 'UniformOutput', false) data_dt_1000ums.time = Ts*[0:length(data_dt_1000ums.Dy_int)-1]; - -%% 5mm/s - Complementary filters -% data_dt_5000ums = load(sprintf("%s/scans/2023-08-21_18-03_diffraction_tomo_m2_fast_cf.mat", mat_dir)); -% data_dt_5000ums.time = Ts*[0:length(data_dt_5000ums.Dy_int)-1]; - -%% 10mm/s - Complementary filters -data_dt_10000ums = load("2023-08-21_15-17_diffraction_tomo_m0_fast_cf.mat"); -data_dt_10000ums.time = Ts*[0:length(data_dt_10000ums.Dy_int)-1]; #+end_src -Here, the $D_y$ scans are performed only with the nano-hexapod (the Ty stage is not moving), so we are limited to $\pm 100\,\mu m$. - -Several $D_y$ velocities are tested: $0.1\,mm/s$, $0.5\,mm/s$, $1\,mm/s$ and $10\,mm/s$ (see Figure ref:fig:id31_diffraction_tomo_velocities). - #+begin_src matlab :exports none :results none %% Dy motion for several configured velocities figure; hold on; -plot(data_dt_10000ums.time, 1e6*data_dt_10000ums.Dy_int, ... - 'DisplayName', '$10 mm/s$') -plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.Dy_int, ... +plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.Dy_int, 'color', colors(1,:), ... 'DisplayName', '$1 mm/s$') -plot(data_dt_500ums.time, 1e6*data_dt_500ums.Dy_int, ... +plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.m_hexa_dy, 'k--', ... + 'HandleVisibility', 'off') +plot(data_dt_500ums.time, 1e6*data_dt_500ums.Dy_int, 'color', colors(2,:), ... 'DisplayName', '$0.5 mm/s$') -plot(data_dt_100ums.time, 1e6*data_dt_100ums.Dy_int, ... +plot(data_dt_500ums.time, 1e6*data_dt_500ums.m_hexa_dy, 'k--', ... + 'HandleVisibility', 'off') +plot(data_dt_100ums.time, 1e6*data_dt_100ums.Dy_int, 'color', colors(3,:), ... 'DisplayName', '$0.1 mm/s$') +plot(data_dt_100ums.time, 1e6*data_dt_100ums.m_hexa_dy, 'k--', ... + 'DisplayName', 'Setpoint') hold off; xlim([0, 4]); +ylim([-110, 110]); xlabel('Time [s]'); ylabel('$D_y$ position [$\mu$m]') legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); #+end_src #+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_diffraction_tomo_velocities.pdf', 'width', 'wide', 'height', 'normal'); +exportFig('figs/test_id31_diffraction_tomo_setpoint.pdf', 'width', 'wide', 'height', 'normal'); #+end_src -#+name: fig:id31_diffraction_tomo_velocities +#+name: fig:test_id31_diffraction_tomo_setpoint #+caption: Dy motion for several configured velocities #+RESULTS: -[[file:figs/id31_diffraction_tomo_velocities.png]] +[[file:figs/test_id31_diffraction_tomo_setpoint.png]] -The corresponding "repetition rate" and $D_y$ scan per spindle turn are shown in Table ref:tab:diffraction_tomo_velocities. - -The main issue here is the "waiting" time between two scans that is in the order of 50ms. -By removing this waiting time (fairly easily), we can double the repetition rate at 10mm/s. - -#+name: tab:diffraction_tomo_velocities -#+caption: $D_y$ scaning repetition rate -#+attr_latex: :environment tabularx :width 0.6\linewidth :align lXX -#+attr_latex: :center t :booktabs t -| $D_y$ Velocity | Repetition rate | Scans per turn (at 1RPM) | -|----------------+-----------------+--------------------------| -| 0.1 mm/s | 4 s | 15 | -| 0.5 mm/s | 0.9 s | 65 | -| 1 mm/s | 0.5 s | 120 | -| 10 mm/s | 0.18 s | 330 | - - -The scan results for a velocity of 1mm/s is shown in Figure ref:fig:id31_diffraction_tomo_1mms. -The $D_z$ and $R_y$ errors are quite small during the scan. - -The $D_y$ errors are quite large as the velocity is increased. -This type of scan can probably be massively improved by using feed-forward and optimizing the trajectory. -Also, if the detectors are triggered in position (the Speedgoat could generate an encoder signal for instance), we don't care about the $D_y$ errors. +The measured errors in $D_y$, $D_z$ and $R_y$ directions are shown in Figure ref:fig:test_id31_diffraction_tomo. +While the $D_z$ and $R_y$ errors are within specifications (see Figures ref:fig:test_id31_diffraction_tomo_dz and ref:fig:test_id31_diffraction_tomo_ry), the lateral error goes outside of specifications during acceleration and deceleration phases (Figure ref:fig:test_id31_diffraction_tomo_dy). +However, it goes out of specifications during only during $\approx 20\,ms$, and this could be optimized using feedforward and more appropriate setpoint signals. #+begin_src matlab :exports none :results none -%% Diffraction tomography with Dy velocity of 1mm/s and Rz velocity of 1RPM +%% Diffraction Tomography - Dy errors for several configured velocities figure; hold on; -plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.Dz_int, ... - 'DisplayName', sprintf('$\\epsilon D_z = %.0f$ nmRMS', 1e9*rms(data_dt_1000ums.Dz_int))) -plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.Ry_int, ... - 'DisplayName', sprintf('$\\epsilon R_y = %.2f$ $\\mu$radRMS', 1e6*rms(data_dt_1000ums.Ry_int))) -plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.Dy_int, ... - 'DisplayName', sprintf('$\\epsilon D_y = %.0f$ nmRMS', 1e9*rms(data_dt_1000ums.Dy_int - data_dt_1000ums.m_hexa_dy))) -plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.m_hexa_dy, 'k--', 'HandleVisibility', 'off') +plot(data_dt_1000ums.time, 1e9*(data_dt_1000ums.Dy_int - data_dt_1000ums.m_hexa_dy), ... + 'DisplayName', '$1 mm/s$') +plot(data_dt_500ums.time, 1e9*(data_dt_500ums.Dy_int - data_dt_500ums.m_hexa_dy), ... + 'DisplayName', '$0.5 mm/s$') +plot(data_dt_100ums.time, 1e9*(data_dt_100ums.Dy_int - data_dt_100ums.m_hexa_dy), ... + 'DisplayName', '$0.1 mm/s$') +plot([0, 6.2], [specs_dy_peak, specs_dy_peak], 'k--', 'DisplayName', 'Specs'); +plot([0, 6.2], [-specs_dy_peak, -specs_dy_peak], 'k--', 'HandleVisibility', 'off'); hold off; -xlim([0, 1]) +xlim([0, 1]); xlabel('Time [s]'); -ylabel('Measurement [nm,nrad]') -legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); -ylim([-110, 110]) +ylabel('$D_y$ error [nm]') +leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; #+end_src -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/id31_diffraction_tomo_1mms.pdf', 'width', 'full', 'height', 'normal'); +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_diffraction_tomo_dy.pdf', 'width', 'third', 'height', 'normal'); #+end_src -#+name: fig:id31_diffraction_tomo_1mms -#+caption: Diffraction tomography with Dy velocity of 1mm/s and Rz velocity of 1RPM -#+RESULTS: -[[file:figs/id31_diffraction_tomo_1mms.png]] +#+begin_src matlab :exports none :results none +%% Diffraction Tomography - Dz errors for several configured velocities +figure; +hold on; +plot(data_dt_1000ums.time, 1e9*data_dt_1000ums.Dz_int, ... + 'DisplayName', '$1 mm/s$') +plot(data_dt_500ums.time, 1e9*data_dt_500ums.Dz_int, ... + 'DisplayName', '$0.5 mm/s$') +plot(data_dt_100ums.time, 1e9*data_dt_100ums.Dz_int, ... + 'DisplayName', '$0.1 mm/s$') +plot([0, 6.2], [specs_dz_peak, specs_dz_peak], 'k--', 'DisplayName', 'Specs'); +plot([0, 6.2], [-specs_dz_peak, -specs_dz_peak], 'k--', 'HandleVisibility', 'off'); +hold off; +xlim([0, 4]); +ylim([-100, 100]) +xlabel('Time [s]'); +ylabel('$D_z$ position [nm]') +leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_diffraction_tomo_dz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Diffraction Tomography - Ry errors for several configured velocities +figure; +hold on; +plot(data_dt_1000ums.time, 1e6*data_dt_1000ums.Ry_int, ... + 'DisplayName', '$1 mm/s$') +plot(data_dt_500ums.time, 1e6*data_dt_500ums.Ry_int, ... + 'DisplayName', '$0.5 mm/s$') +plot(data_dt_100ums.time, 1e6*data_dt_100ums.Ry_int, ... + 'DisplayName', '$0.1 mm/s$') +plot([0, 6.2], [specs_ry_peak, specs_ry_peak], 'k--', 'DisplayName', 'Specs'); +plot([0, 6.2], [-specs_ry_peak, -specs_ry_peak], 'k--', 'HandleVisibility', 'off'); +hold off; +xlim([0, 4]); +ylim([-1.5, 1.5]) +xlabel('Time [s]'); +ylabel('$R_y$ position [$\mu$rad]') +leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/test_id31_diffraction_tomo_ry.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + + +#+name: fig:test_id31_diffraction_tomo +#+caption: Diffraction tomography scans (combined $R_z$ and $D_y$ motions) at several $D_y$ velocities ($R_z$ rotational velocity is 1rpm). +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_diffraction_tomo_dy} $D_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_diffraction_tomo_dy.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_diffraction_tomo_dz} $D_z$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_diffraction_tomo_dz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_id31_diffraction_tomo_ry} $R_y$} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 1 +[[file:figs/test_id31_diffraction_tomo_ry.png]] +#+end_subfigure +#+end_figure + +#+begin_src matlab +%% Computation of errors during diffraction tomography experiments +% Ignore acceleration and deceleration phases +acc_dt = 20e-3; % Acceleration phase to remove [s] +acc_n = acc_dt/Ts; % Number of points to delete + +% Determine when the motion starts and stops +i_dt_100ums = data_dt_100ums.m_hexa_dy>data_dt_100ums.m_hexa_dy(1) & data_dt_100ums.m_hexa_dy0); % Acceleration phases +for i = i_acc + i_dt_100ums(i:i+acc_n) = 0; +end +[~, i_dec] = find(diff(i_dt_100ums)<0); % Deceleration phases +for i = i_dec(2:2:end) + i_dt_100ums(i-acc_n:i) = 0; +end + +i_dt_500ums = data_dt_500ums.m_hexa_dy>data_dt_500ums.m_hexa_dy(1) & data_dt_500ums.m_hexa_dy0); % Acceleration phases +for i = i_acc + i_dt_500ums(i:i+acc_n) = 0; +end +[~, i_dec] = find(diff(i_dt_500ums)<0); % Deceleration phases +for i = i_dec(2:2:end) + i_dt_500ums(i-acc_n:i) = 0; +end + +i_dt_1000ums = data_dt_1000ums.m_hexa_dy>data_dt_1000ums.m_hexa_dy(1) & data_dt_1000ums.m_hexa_dy0); % Acceleration phases +for i = i_acc + i_dt_1000ums(i:i+acc_n) = 0; +end +[~, i_dec] = find(diff(i_dt_1000ums)<0); % Deceleration phases +for i = i_dec(2:2:end) + i_dt_1000ums(i-acc_n:i) = 0; +end + +% Peak to Peak errors +dt_100ums_dy_peak = 1e9*(max(detrend(data_dt_100ums.Dy_int(i_dt_100ums)-data_dt_100ums.m_hexa_dy(i_dt_100ums), 0))-min(detrend(data_dt_100ums.Dy_int(i_dt_100ums)-data_dt_100ums.m_hexa_dy(i_dt_100ums), 0)))/2; +dt_100ums_dz_peak = 1e9*(max(detrend(data_dt_100ums.Dz_int(i_dt_100ums), 0))-min(detrend(data_dt_100ums.Dz_int(i_dt_100ums), 0)))/2; +dt_100ums_ry_peak = 1e6*(max(detrend(data_dt_100ums.Ry_int(i_dt_100ums), 0))-min(detrend(data_dt_100ums.Ry_int(i_dt_100ums), 0)))/2; + +dt_500ums_dy_peak = 1e9*(max(detrend(data_dt_500ums.Dy_int(i_dt_500ums)-data_dt_500ums.m_hexa_dy(i_dt_500ums), 0))-min(detrend(data_dt_500ums.Dy_int(i_dt_500ums)-data_dt_500ums.m_hexa_dy(i_dt_500ums), 0)))/2; +dt_500ums_dz_peak = 1e9*(max(detrend(data_dt_500ums.Dz_int(i_dt_500ums), 0))-min(detrend(data_dt_500ums.Dz_int(i_dt_500ums), 0)))/2; +dt_500ums_ry_peak = 1e6*(max(detrend(data_dt_500ums.Ry_int(i_dt_500ums), 0))-min(detrend(data_dt_500ums.Ry_int(i_dt_500ums), 0)))/2; + +dt_1000ums_dy_peak = 1e9*(max(detrend(data_dt_1000ums.Dy_int(i_dt_1000ums)-data_dt_1000ums.m_hexa_dy(i_dt_1000ums), 0))-min(detrend(data_dt_1000ums.Dy_int(i_dt_1000ums)-data_dt_1000ums.m_hexa_dy(i_dt_1000ums), 0)))/2; +dt_1000ums_dz_peak = 1e9*(max(detrend(data_dt_1000ums.Dz_int(i_dt_1000ums), 0))-min(detrend(data_dt_1000ums.Dz_int(i_dt_1000ums), 0)))/2; +dt_1000ums_ry_peak = 1e6*(max(detrend(data_dt_1000ums.Ry_int(i_dt_1000ums), 0))-min(detrend(data_dt_1000ums.Ry_int(i_dt_1000ums), 0)))/2; + +% RMS error +dt_100ums_dy_rms = 1e9*(rms(detrend(data_dt_100ums.Dy_int(i_dt_100ums)-data_dt_100ums.m_hexa_dy(i_dt_100ums), 0))); +dt_100ums_dz_rms = 1e9*(rms(detrend(data_dt_100ums.Dz_int(i_dt_100ums), 0))); +dt_100ums_ry_rms = 1e6*(rms(detrend(data_dt_100ums.Ry_int(i_dt_100ums), 0))); + +dt_500ums_dy_rms = 1e9*(rms(detrend(data_dt_500ums.Dy_int(i_dt_500ums)-data_dt_500ums.m_hexa_dy(i_dt_500ums), 0))); +dt_500ums_dz_rms = 1e9*(rms(detrend(data_dt_500ums.Dz_int(i_dt_500ums), 0))); +dt_500ums_ry_rms = 1e6*(rms(detrend(data_dt_500ums.Ry_int(i_dt_500ums), 0))); + +dt_1000ums_dy_rms = 1e9*(rms(detrend(data_dt_1000ums.Dy_int(i_dt_1000ums)-data_dt_1000ums.m_hexa_dy(i_dt_1000ums), 0))); +dt_1000ums_dz_rms = 1e9*(rms(detrend(data_dt_1000ums.Dz_int(i_dt_1000ums), 0))); +dt_1000ums_ry_rms = 1e6*(rms(detrend(data_dt_1000ums.Ry_int(i_dt_1000ums), 0))); +#+end_src #+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable([1e9*rms(data_dt_100ums.Dy_int - data_dt_100ums.m_hexa_dy), 1e9*rms(data_dt_500ums.Dy_int - data_dt_500ums.m_hexa_dy), 1e9*rms(data_dt_1000ums.Dy_int - data_dt_1000ums.m_hexa_dy), 1e9*rms(data_dt_10000ums.Dy_int - data_dt_10000ums.m_hexa_dy); -1e9*rms(data_dt_100ums.Dz_int), 1e9*rms(data_dt_500ums.Dz_int), 1e9*rms(data_dt_1000ums.Dz_int), 1e9*rms(data_dt_10000ums.Dz_int); -1e6*rms(data_dt_100ums.Ry_int), 1e6*rms(data_dt_500ums.Ry_int), 1e6*rms(data_dt_1000ums.Ry_int), 1e6*rms(data_dt_10000ums.Ry_int)]', {'0.1 mm/s' ,'0.5 mm/s', '1 mm/s', '10 mm/s'}, {'Velocity', '$D_y$ [nmRMS]', '$D_z$ [nmRMS]', '$R_y$ [$\mu\text{radRMS}$]'}, ' %.1f '); +data2orgtable([ + specs_dy_peak, specs_dz_peak, specs_ry_peak; ... % Specifications + dt_100ums_dy_peak, dt_100ums_dz_peak, dt_100ums_ry_peak; + dt_500ums_dy_peak, dt_500ums_dz_peak, dt_500ums_ry_peak; + dt_1000ums_dy_peak, dt_1000ums_dz_peak, dt_1000ums_ry_peak +], {'Specs', '0.1 mm/s', '0.5 mm/s', '1 mm/s'}, {'Velocity', '$D_y$ [nmRMS]', '$D_z$ [nmRMS]', '$R_y$ [$\mu\text{radRMS}$]'}, ' %.2f '); #+end_src -#+name: tab:id31_diffraction_tomo_results -#+caption: Obtained errors for several $D_y$ velocities -#+attr_latex: :environment tabularx :width \linewidth :align lXX -#+attr_latex: :center t :booktabs t #+RESULTS: | Velocity | $D_y$ [nmRMS] | $D_z$ [nmRMS] | $R_y$ [$\mu\text{radRMS}$] | |----------+---------------+---------------+----------------------------| -| 0.1 mm/s | 75.5 | 9.1 | 0.1 | -| 0.5 mm/s | 190.5 | 10.0 | 0.1 | -| 1 mm/s | 428.0 | 11.2 | 0.2 | -| 10 mm/s | 4639.9 | 55.9 | 1.4 | +| Specs | 100.0 | 50.0 | 0.85 | +| 0.1 mm/s | 208.25 | 35.33 | 0.73 | +| 0.5 mm/s | 117.94 | 28.03 | 0.27 | +| 1 mm/s | 186.88 | 33.02 | 0.53 | + +#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) +data2orgtable([ + specs_dy_rms, specs_dz_rms, specs_ry_rms; ... % Specifications + dt_100ums_dy_rms, dt_100ums_dz_rms, dt_100ums_ry_rms; + dt_500ums_dy_rms, dt_500ums_dz_rms, dt_500ums_ry_rms; + dt_1000ums_dy_rms, dt_1000ums_dz_rms, dt_1000ums_ry_rms +], {'Specs', '0.1 mm/s', '0.5 mm/s', '1 mm/s'}, {'Velocity', '$D_y$ [nmRMS]', '$D_z$ [nmRMS]', '$R_y$ [$\mu\text{radRMS}$]'}, ' %.2f '); +#+end_src + +#+RESULTS: +| Velocity | $D_y$ [nmRMS] | $D_z$ [nmRMS] | $R_y$ [$\mu\text{radRMS}$] | +|----------+---------------+---------------+----------------------------| +| Specs | 30.0 | 15.0 | 0.25 | +| 0.1 mm/s | 36.18 | 7.35 | 0.11 | +| 0.5 mm/s | 28.58 | 7.52 | 0.08 | +| 1 mm/s | 53.05 | 9.84 | 0.14 | + +#+name: tab:id31_diffraction_tomo_results +#+caption: Obtained errors during diffraction tomography experiments for several $D_y$ velocities +#+attr_latex: :environment tabularx :width \linewidth :align lXX +#+attr_latex: :center t :booktabs t +#+RESULTS: ** Conclusion :PROPERTIES: @@ -5150,20 +5639,21 @@ For each conducted experiments, the $D_y$, $D_z$ and $R_y$ errors are computed a #+begin_src matlab %% Summary of results data_results = [... + specs_dy_rms, specs_dz_rms, 1e3*specs_ry_rms ; ... % Specifications 1e9*data_tomo_1rpm_m0.Dy_rms_cl, 1e9*data_tomo_1rpm_m0.Dz_rms_cl, 1e9*data_tomo_1rpm_m0.Ry_rms_cl ; ... % Tomo 1rpm 1e9*data_tomo_6rpm_m0.Dy_rms_cl, 1e9*data_tomo_6rpm_m0.Dz_rms_cl, 1e9*data_tomo_6rpm_m0.Ry_rms_cl ; ... % Tomo 6rpm 1e9*data_tomo_30rpm_m0.Dy_rms_cl, 1e9*data_tomo_30rpm_m0.Dz_rms_cl, 1e9*data_tomo_30rpm_m0.Ry_rms_cl ; ... % Tomo 30rpm 1e9*rms(detrend(data_dz_10ums.e_dy, 0)), 1e9*rms(detrend(data_dz_10ums.e_dz, 0)), 1e9*rms(detrend(data_dz_10ums.e_ry, 0)) ; ... % Dz 10um/s 1e9*rms(detrend(data_dz_100ums.e_dy,0)), 1e9*rms(detrend(data_dz_100ums.e_dz,0)), 1e9*rms(detrend(data_dz_100ums.e_ry,0)) ; ... % Dz 100um/s 1e9*rms(detrend(data_ry.e_dy,0)), 1e9*rms(detrend(data_ry.e_dz,0)), 1e9*rms(detrend(data_ry.e_ry,0)) ; ... % Ry 100urad/s - 1e9*rms(detrend(data_ty_cl_slow.e_dy, 0)), 1e9*rms(detrend(data_ty_cl_slow.e_dz, 0)), 1e9*rms(detrend(data_ty_cl_slow.e_rz, 0)) ; ... % Dy 10 um/s + 1e9*rms(detrend(data_ty_cl_slow.e_dy, 0)), 1e9*rms(detrend(data_ty_cl_slow.e_dz, 0)), 1e9*rms(detrend(data_ty_cl_slow.e_ry, 0)) ; ... % Dy 10 um/s 1e9*rms(detrend(data_dt_100ums.Dy_int-data_dt_100ums.m_hexa_dy, 0)), 1e9*rms(detrend(data_dt_100ums.Dz_int, 0)), 1e9*rms(detrend(data_dt_100ums.Ry_int, 0)); ... % Diffraction tomo 0.1mm/s 1e9*rms(detrend(data_dt_1000ums.Dy_int-data_dt_1000ums.m_hexa_dy,0)), 1e9*rms(detrend(data_dt_1000ums.Dz_int,0)), 1e9*rms(detrend(data_dt_1000ums.Ry_int,0)) ... % Diffraction tomo 1mm/s ]; #+end_src #+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable(data_results, {'Tomography ($R_z$ 1rpm)', 'Tomography ($R_z$ 6rpm)', 'Tomography ($R_z$ 30rpm)', 'Dirty Layer ($D_z$ $10\,\mu m/s$)', 'Dirty Layer ($D_z$ $100\,\mu m/s$)', 'Reflectivity ($R_y$ $100\,\mu\text{rad}/s$)', 'Lateral Scan ($D_y$ $10\,\mu m/s$)', 'Diffraction Tomography ($R_z$ 1rpm, $D_y$ 0.1mm/s)', 'Diffraction Tomography ($R_z$ 1rpm, $D_y$ 1mm/s)'}, {'$D_y$ [nmRMS]', '$D_z$ [nmRMS]', '$R_y$ [nradRMS]'}, ' %.0f '); +data2orgtable(data_results, {'Specifications', 'Tomography ($R_z$ 1rpm)', 'Tomography ($R_z$ 6rpm)', 'Tomography ($R_z$ 30rpm)', 'Dirty Layer ($D_z$ $10\,\mu m/s$)', 'Dirty Layer ($D_z$ $100\,\mu m/s$)', 'Reflectivity ($R_y$ $100\,\mu\text{rad}/s$)', 'Lateral Scan ($D_y$ $10\,\mu m/s$)', 'Diffraction Tomography ($R_z$ 1rpm, $D_y$ 0.1mm/s)', 'Diffraction Tomography ($R_z$ 1rpm, $D_y$ 1mm/s)'}, {'$D_y$ [nmRMS]', '$D_z$ [nmRMS]', '$R_y$ [nradRMS]'}, ' %.0f '); #+end_src #+name: tab:id31_experiments_results_summary @@ -5173,16 +5663,28 @@ data2orgtable(data_results, {'Tomography ($R_z$ 1rpm)', 'Tomography ($R_z$ 6rpm) #+RESULTS: | | $D_y$ [nmRMS] | $D_z$ [nmRMS] | $R_y$ [nradRMS] | |----------------------------------------------------+---------------+---------------+-----------------| +| Specifications | | | | +|----------------------------------------------------+---------------+---------------+-----------------| | Tomography ($R_z$ 1rpm) | 15 | 5 | 55 | | Tomography ($R_z$ 6rpm) | 19 | 5 | 73 | | Tomography ($R_z$ 30rpm) | 38 | 10 | 129 | +|----------------------------------------------------+---------------+---------------+-----------------| | Dirty Layer ($D_z$ $10\,\mu m/s$) | 25 | 5 | 114 | | Dirty Layer ($D_z$ $100\,\mu m/s$) | 34 | 15 | 130 | +|----------------------------------------------------+---------------+---------------+-----------------| | Reflectivity ($R_y$ $100\,\mu\text{rad}/s$) | 28 | 6 | 118 | +|----------------------------------------------------+---------------+---------------+-----------------| | Lateral Scan ($D_y$ $10\,\mu m/s$) | 21 | 10 | 37 | +|----------------------------------------------------+---------------+---------------+-----------------| | 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 | +* Conclusion +:PROPERTIES: +:UNNUMBERED: t +:END: +<> + * Bibliography :ignore: #+latex: \printbibliography[heading=bibintoc,title={Bibliography}] @@ -5232,6 +5734,14 @@ freqs = logspace(log10(1), log10(2e3), 1000); %% Sampling Time Ts = 1e-4; + +%% Specifications for Experiments +specs_dz_peak = 50; % [nm] +specs_dy_peak = 100; % [nm] +specs_ry_peak = 0.85; % [urad] +specs_dz_rms = 15; % [nm RMS] +specs_dy_rms = 30; % [nm RMS] +specs_ry_rms = 0.25; % [urad RMS] #+END_SRC * Matlab Functions :noexport: @@ -7971,6 +8481,7 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit #+end_src * Footnotes +[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 from the 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 diff --git a/test-bench-id31.pdf b/test-bench-id31.pdf index 53c246a..5f7beb9 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 f9e303a..ac20904 100644 --- a/test-bench-id31.tex +++ b/test-bench-id31.tex @@ -1,4 +1,4 @@ -% Created 2024-11-15 Fri 18:44 +% Created 2025-01-31 Fri 14:50 % Intended LaTeX compiler: pdflatex \documentclass[a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc]{scrreprt} @@ -205,7 +205,6 @@ 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. \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 @@ -218,6 +217,8 @@ 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} @@ -345,6 +346,8 @@ Results shown in Figure \ref{fig:test_id31_Rz_align_correct} are indeed indicati The plant dynamics is identified after the fine alignment and is compared with the model dynamics in Figure \ref{fig:test_id31_first_id_int_better_rz_align}. Compared to the initial identification shown in Figure \ref{fig:test_id31_first_id_int}, the obtained coupling has decreased and is now close to the coupling obtained with the multi-body model. At low frequency (below \(10\,\text{Hz}\)) all the off-diagonal elements have an amplitude \(\approx 100\) times lower compared to the diagonal elements, indicating that a low bandwidth feedback controller can be implemented in a decentralized way (i.e. \(6\) SISO controllers). +Between \(650\,\text{Hz}\) and \(1000\,\text{Hz}\), several modes can be observed that are due to flexible modes of the top platform and modes of the two spheres adjustment mechanism. +The flexible modes of the top platform can be passively damped while the modes of the two reference spheres should not be present in the final application. \begin{figure}[htbp] \centering @@ -401,7 +404,7 @@ It is interesting to note that the anti-resonances in the force sensor plant are \end{center} \subcaption{\label{fig:test_id31_comp_simscape_iff_diag_masses}from $u$ to $V_s$} \end{subfigure} -\caption{\label{fig:test_nhexa_comp_simscape_diag_masses}Comparison of the diagonal elements (i.e. ``direct'' terms) of the measured FRF matrix and the dynamics identified from the Simscape model. Both for the dynamics from \(u\) to \(e\mathcal{L}\) (\subref{fig:test_id31_comp_simscape_int_diag_masses}) and from \(u\) to \(V_s\) (\subref{fig:test_id31_comp_simscape_iff_diag_masses})} +\caption{\label{fig:test_nhexa_comp_simscape_diag_masses}Comparison of the diagonal elements (i.e. ``direct'' terms) of the measured FRF matrix and the dynamics identified from the multi-body model. Both for the dynamics from \(u\) to \(e\mathcal{L}\) (\subref{fig:test_id31_comp_simscape_int_diag_masses}) and from \(u\) to \(V_s\) (\subref{fig:test_id31_comp_simscape_iff_diag_masses})} \end{figure} \section{Effect of Spindle Rotation} @@ -432,13 +435,6 @@ This also indicates that the metrology kinematics is correct and is working in r \caption{\label{fig:test_id31_effect_rotation}Effect of the spindle rotation on the plant dynamics from \(u\) to \(e\mathcal{L}\). Three rotational velocities are tested (\(0\,\text{deg}/s\), \(36\,\text{deg}/s\) and \(180\,\text{deg}/s\)). Both direct terms (\subref{fig:test_id31_effect_rotation_direct}) and coupling terms (\subref{fig:test_id31_effect_rotation_coupling}) are displayed.} \end{figure} -\section{Identification of Spurious modes} - -\begin{itemize} -\item[{$\square$}] These are made to identify the modes of the spheres -\item[{$\square$}] Also discuss other observed modes -\end{itemize} - \section*{Conclusion} Thanks to the model, poor alignment between the nano-hexapod axes and the external metrology axes could be identified. After alignment, the identified dynamics is well matching with the multi-body model. @@ -609,6 +605,10 @@ This is one of the key benefit of using the HAC-LAC strategy. \caption{\label{fig:test_id31_hac_plant_effect_mass_comp_model}Comparison of the measured damped plants and modeled plants for all considered payloads, only ``direct'' terms (\(\epsilon\mathcal{L}_i/u_i^\prime\)) are displayed (\subref{fig:test_id31_hac_plant_effect_mass}). Comparison of all undamped \(\epsilon\mathcal{L}_i/u_i\) and damped \(\epsilon\mathcal{L}_i/u_i^\prime\) measured frequency response functions for all payloads is done in (\subref{fig:test_id31_comp_all_undamped_damped_plants}).} \end{figure} +\section{Interaction Analysis} +Decoupled system up to 10Hz +Higher coupling for higher masses (when considering control in the frame of the struts) + \section{Robust Controller Design} \label{ssec:test_id31_iff_hac_controller} @@ -639,7 +639,7 @@ The closed-loop stability is verified by computing the characteristic Loci (Figu \caption{\label{fig:test_id31_hac_loop_gain_loci}Robust High Authority Controller. ``Decentralized loop-gains'' are shown in (\subref{fig:test_id31_hac_loop_gain}) and characteristic loci are shown in (\subref{fig:test_id31_hac_characteristic_loci})} \end{figure} -\section{Estimation of performances} +\section{Estimation of performances with Tomography scans} \label{ssec:test_id31_iff_hac_perf} To estimate the performances that can be expected with this HAC-LAC architecture and the designed controllers, two simulations of tomography experiments were performed\footnote{Note that the eccentricity of the ``point of interest'' with respect to the Spindle rotation axis has been tuned from the measurements.}. @@ -665,6 +665,10 @@ An open-loop simulation and a closed-loop simulation were performed and compared 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{itemize} +\item[{$\square$}] Add beam size (200x100nm) +\end{itemize} + \begin{figure}[htbp] \begin{subfigure}{0.49\textwidth} \begin{center} @@ -688,7 +692,6 @@ The lateral and vertical errors are similar, however the tilt (\(R_y\)) errors a 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 @@ -699,9 +702,11 @@ Experiment (OL) & \(1.8\,\mu\text{mRMS}\) & \(24\,\text{nmRMS}\) & \(10\,\mu\tex Simulation (CL) & \(30\,\text{nmRMS}\) & \(8\,\text{nmRMS}\) & \(73\,\text{nradRMS}\)\\ Experiment (CL) & \(39\,\text{nmRMS}\) & \(11\,\text{nmRMS}\) & \(130\,\text{nradRMS}\)\\ \midrule -Specifications (CL) & \(30\,\text{nmRMS}\) & \(15\,\text{nmRMS}\) & \(250\,\text{nradRMS}\)\\ +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} \section{Robustness to change of payload} @@ -719,6 +724,11 @@ To estimate the open-loop errors, it is supposed that the ``point of interest'' 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. +\begin{itemize} +\item[{$\square$}] Maybe show in the YZ plane? +\item[{$\square$}] Add the beam size? +\end{itemize} + \begin{figure}[htbp] \begin{subfigure}{0.49\textwidth} \begin{center} @@ -739,7 +749,6 @@ 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 @@ -753,9 +762,423 @@ 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*{Conclusion} +\chapter{Dynamic Error Budgeting} +\label{sec:test_id31_error_budget} +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} +\section{Open-Loop Noise Budget} + +\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) +\end{itemize} + +\section{Effect of LAC} +\begin{itemize} +\item[{$\square$}] Maybe merge this with the HAC-LAC +\end{itemize} + +Effect of LAC: +\begin{itemize} +\item reduce amplitude around 80Hz +\item Inject some noise between 200 and 700Hz? +\end{itemize} + +\section{Effect of HAC} + +Bandwidth is approximately 10Hz. + +\chapter{Validation with Scientific experiments} +The online metrology prototype does not allow samples to be placed on top of the nano-hexapod and to be 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. + +Performances were already evaluated with tomography scans (Section \ref{ssec:test_id31_iff_hac_perf}). +Here, other typical experiments are performed: +\begin{itemize} +\item Lateral scans: the 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 Vertical layer scans: the nano-hexapod is used to perform \(D_z\) steps or ramp scans (Section \ref{ssec:test_id31_scans_dz}) +\item 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 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{\(D_y\) - 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. + +Therefore, the Nano-Hexapod can be used to correct positioning errors induced by the scanning of the \(T_y\) stage. + +\paragraph{Slow scan} + +The \(T_y\) stage is first scanned at \(10\,\mu m/s\) which is typical for such experiments. +The errors in open-loop (i.e. without using the NASS) and in closed-loop are compared in Figure \ref{fig:test_id31_dy_10ums}. + +In the direction of motion, periodic errors can be observed in the open-loop case (Figure \ref{fig:test_id31_dy_10ums_dy}). +These are due to the stepper motor being used in the \(T_y\) stage. +Indeed, stepper motors inherently have ``micro-stepping'' errors which are periodic errors happening 200 times per motor rotation with an amplitude approximately equal to \(1\,\text{mrad}\). +As the lead screw for the \(T_y\) stage has a pitch of \(2\,mm\), this means that the micro-stepping errors have a period of \(10\,\mu m\) and an amplitude of \(\approx 300\,nm\) which can indeed be seen in open-loop. + +In the vertical direction (Figure \ref{fig:test_id31_dy_10ums_dz}), open-loop errors are most likely due to measurement errors of the metrology itself (see Figure \ref{fig:test_id31_xy_map_sphere}). + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dy_10ums_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_dy_10ums_dy} $D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dy_10ums_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_dy_10ums_dz} $D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dy_10ums_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_dy_10ums_ry} $R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_dy_10ums}Open-Loop (in blue) and Closed-loop (i.e. using the NASS, in red) during a \(10\,\mu m/s\) scan with the \(T_y\) stage. Errors in \(D_y\) is shown in (\subref{fig:test_id31_dy_10ums_dy}).} +\end{figure} + +\paragraph{Faster Scan} + +The performance of the NASS is then tested for a scanning velocity of \(100\,\mu m/s\) and the results are shown in Figure \ref{fig:test_id31_dy_100ums}. +At this velocity, the micro-stepping errors have a frequency of \(10\,\text{Hz}\) and are inducing lot's of vibrations which are amplified by some resonances of the micro-station. +These vibrations are outside the bandwidth of the NASS feedback controller and therefore not well reduced in closed-loop. + +This is the main reason why stepper motors should be not be used for ``long-stroke / short-stroke'' systems when good scanning performances are wanted \cite{dehaeze22_fastj_uhv}. +In order to improve the scanning performances at high velocity, the stepper motor of the \(T_y\) stage could be replaced by a three-phase torque motor for instance. + +As the closed-loop errors in \(D_z\) and \(R_y\) directions are within specifications (see Figures \ref{fig:test_id31_dy_100ums_dz} and \ref{fig:test_id31_dy_100ums_ry}), the detectors could be triggered based on the measured \(D_y\) position and therefore the experiment would be much less sensitive to \(D_y\) vibrations. + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dy_100ums_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_dy_100ums_dy} $D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dy_100ums_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_dy_100ums_dz} $D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_dy_100ums_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_dy_100ums_ry} $R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_dy_100ums}Open-Loop (in blue) and Closed-loop (i.e. using the NASS, in red) during a \(100\,\mu m/s\) scan with the \(T_y\) stage. Errors in \(D_y\) is shown in (\subref{fig:test_id31_dy_100ums_dy}).} +\end{figure} + +\paragraph{Conclusion} + +\begin{center} +\begin{tabular}{lrrr} + & \(D_y\) & \(D_z\) & \(R_y\)\\ +\hline +Specs & 30.0 & 15.0 & 0.25\\ +\hline +10um/s (OL) & 585.43 & 154.51 & 6.3\\ +10um/s (CL) & 20.64 & 9.67 & 0.06\\ +\hline +100um/s (OL) & 1063.58 & 166.85 & 6.44\\ +100um/s (CL) & 731.63 & 19.91 & 0.36\\ +\end{tabular} + +\end{center} + +\begin{center} +\begin{tabular}{lrrr} + & \(D_y\) & \(D_z\) & \(R_y\)\\ +\hline +Specs & 100.0 & 50.0 & 0.85\\ +10um/s (OL) & 1167.8 & 308.35 & 11.06\\ +10um/s (CL) & 86.36 & 41.6 & 0.28\\ +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 then scanned vertically with precise \(D_z\) motion. +The vertical scan can be performed step-by-step or continuously. +\paragraph{Step by Step \(D_z\) motion} + +Vertical steps are here performed using the nano-hexapod. +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 very typical. + +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}). + +The second tested velocity is \(100\,\mu m/s\), which is typically the fastest velocity for \(D_z\) scans when the ultimate performances is wanted (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 should not be 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_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} + +\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 at \(100\,\mu rad/s\) velocity and the positioning errors 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. + +\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} +\label{ssec:test_id31_scans_diffraction_tomo} + +The goal of this experiment is to perform combined \(R_z\) rotation and \(D_z\) lateral scans. +Here the spindle is performing a continuous 1rpm rotation while the nano-hexapod is used to perform fast \(D_z\) scans. + +The \(T_y\) stage is here not used as the stepper motor would induce high frequency vibrations, therefore the stroke is here limited to \(\approx \pm 100\,\mu m/s\). +Several \(D_y\) velocities are tested: \(0.1\,mm/s\), \(0.5\,mm/s\) and \(1\,mm/s\). + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/test_id31_diffraction_tomo_setpoint.png} +\caption{\label{fig:test_id31_diffraction_tomo_setpoint}Dy motion for several configured velocities} +\end{figure} + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_diffraction_tomo_dy.png} +\end{center} +\subcaption{\label{fig:test_id31_diffraction_tomo_dy}$D_y$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_diffraction_tomo_dz.png} +\end{center} +\subcaption{\label{fig:test_id31_diffraction_tomo_dz}$D_z$} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=1]{figs/test_id31_diffraction_tomo_ry.png} +\end{center} +\subcaption{\label{fig:test_id31_diffraction_tomo_ry}$R_y$} +\end{subfigure} +\caption{\label{fig:test_id31_diffraction_tomo}Diffraction tomography scans (combined \(R_z\) and \(D_y\) motions) at several \(D_y\) velocities (\(R_z\) rotational velocity is 1rpm).} +\end{figure} + +The corresponding ``repetition rate'' and \(D_y\) scan per spindle turn are shown in Table \ref{tab:diffraction_tomo_velocities}. +The main issue here is the ``waiting'' time between two scans that is in the order of 50ms. +By removing this waiting time (fairly easily), we can double the repetition rate at 10mm/s. + +\begin{table}[htbp] +\centering +\begin{tabularx}{0.6\linewidth}{lXX} +\toprule +\(D_y\) Velocity & Repetition rate & Scans per turn (at 1RPM)\\ +\midrule +0.1 mm/s & 4 s & 15\\ +0.5 mm/s & 0.9 s & 65\\ +1 mm/s & 0.5 s & 120\\ +\bottomrule +\end{tabularx} +\caption{\label{tab:diffraction_tomo_velocities}\(D_y\) scaning repetition rate} + +\end{table} + +The scan results for a velocity of 1mm/s is shown in Figure \ref{fig:id31_diffraction_tomo_1mms}. +The \(D_z\) and \(R_y\) errors are quite small during the scan. + +The \(D_y\) errors are quite large as the velocity is increased. +This type of scan can probably be massively improved by using feed-forward and optimizing the trajectory. +Also, if the detectors are triggered in position (the Speedgoat could generate an encoder signal for instance), we don't care about the \(D_y\) errors. + +\begin{table}[htbp] +\centering +\begin{tabularx}{\linewidth}{lXX} +\toprule +Velocity & \(D_y\) [nmRMS] & \(D_z\) [nmRMS] & \(R_y\) [\(\mu\text{radRMS}\)]\\ +\midrule +0.1 mm/s & 75.45 & 9.13 & 0.12\\ +0.5 mm/s & 190.47 & 9.97 & 0.1\\ +1 mm/s & 428.0 & 11.24 & 0.17\\ +\bottomrule +\end{tabularx} +\caption{\label{tab:id31_diffraction_tomo_results}Obtained errors for several \(D_y\) velocities} + +\end{table} + +\section*{Conclusion} +\label{ssec:test_id31_scans_conclusion} + +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] +\centering +\begin{tabularx}{\linewidth}{Xccc} +\toprule + & \(D_y\) [nmRMS] & \(D_z\) [nmRMS] & \(R_y\) [nradRMS]\\ +\midrule +Tomography (\(R_z\) 1rpm) & 15 & 5 & 55\\ +Tomography (\(R_z\) 6rpm) & 19 & 5 & 73\\ +Tomography (\(R_z\) 30rpm) & 38 & 10 & 129\\ +Dirty Layer (\(D_z\) \(10\,\mu m/s\)) & 25 & 5 & 114\\ +Dirty Layer (\(D_z\) \(100\,\mu m/s\)) & 34 & 15 & 130\\ +Reflectivity (\(R_y\) \(100\,\mu\text{rad}/s\)) & 28 & 6 & 118\\ +Lateral Scan (\(D_y\) \(10\,\mu m/s\)) & 21 & 10 & 37\\ +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} + \printbibliography[heading=bibintoc,title={Bibliography}] \end{document}