%% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); % Effect of the Sercalo angle error on the measured distance by the Attocube % <> % To simplify, we suppose that the Newport mirror is a flat mirror (instead of a concave one). % The geometry of the setup is shown in Fig. [[fig:angle_error_schematic_sercalo]] where: % - $O$ is the reference surface of the Attocube % - $S$ is the point where the beam first hits the Sercalo mirror % - $X$ is the point where the beam first hits the Newport mirror % - $\delta \theta_c$ is the angle error from its ideal 45 degrees % We define the angle error range $\delta \theta_c$ where we want to evaluate the distance error $\delta L$ measured by the Attocube. thetas_c = logspace(-7, -4, 100); % [rad] % The geometrical parameters of the setup are defined below. H = 0.05; % [m] L = 0.05; % [m] % #+NAME: fig:angle_error_schematic_sercalo % #+CAPTION: Schematic of the geometry used to evaluate the effect of $\delta \theta_c$ on the measured distance $\delta L$ % #+RESULTS: % [[file:figs/angle_error_schematic_sercalo.png]] % The nominal points $O$, $S$ and $X$ are defined. O = [-L, 0]; S = [0, 0]; X = [0, H]; % Thus, the initial path length $L$ is: path_nominal = norm(S-O) + norm(X-S) + norm(S-X) + norm(O-S); % We now compute the new path length when there is an error angle $\delta \theta_c$ on the Sercalo mirror angle. path_length = zeros(size(thetas_c)); for i = 1:length(thetas_c) theta_c = thetas_c(i); Y = [H*tan(2*theta_c), H]; M = 2*H/(tan(pi/4-theta_c)+1/tan(2*theta_c))*[1, tan(pi/4-theta_c)]; T = [-L, M(2)+(L+M(1))*tan(4*theta_c)]; path_length(i) = norm(S-O) + norm(Y-S) + norm(M-Y) + norm(T-M); end % We then compute the distance error and we plot it as a function of the Sercalo angle error (Fig. [[fig:effect_sercalo_angle_distance_meas]]). path_error = path_length - path_nominal; figure; plot(thetas_c, path_error) set(gca,'xscale','log'); set(gca,'yscale','log'); xlabel('Sercalo angle error [rad]'); ylabel('Attocube measurement error [m]'); % #+NAME: fig:effect_sercalo_angle_distance_meas % #+CAPTION: Effect of an angle error of the Sercalo on the distance error measured by the Attocube ([[./figs/effect_sercalo_angle_distance_meas.png][png]], [[./figs/effect_sercalo_angle_distance_meas.pdf][pdf]]) % [[file:figs/effect_sercalo_angle_distance_meas.png]] % And we plot the beam path using Matlab for an high angle to verify that the code is working (Fig. [[fig:simulation_beam_path_high_angle]]). theta = 2*2*pi/360; % [rad] H = 0.05; % [m] L = 0.05; % [m] O = [-L, 0]; S = [0, 0]; X = [0, H]; Y = [H*tan(2*theta), H]; M = 2*H/(tan(pi/4-theta)+1/tan(2*theta))*[1, tan(pi/4-theta)]; T = [-L, M(2)+(L+M(1))*tan(4*theta)]; figure; hold on; plot([-L, -L], [0, H], 'k-'); % Interferometer plot([-L, 0.1*L], [H, H], 'k-'); % Reflector plot(0.5*min(L, H)*[-cos(pi/4-theta), cos(pi/4-theta)], 0.5*min(L, H)*[-sin(pi/4-theta), sin(pi/4-theta)], 'k-'); % Tilt-Mirror plot(0.5*min(L, H)*[-cos(pi/4), cos(pi/4)], 0.5*min(L, H)*[-sin(pi/4), sin(pi/4)], 'k--'); % Initial position of tilt mirror plot([O(1), S(1), Y(1), M(1), T(1)], [O(2), S(2), Y(2), M(2), T(2)], 'r-'); plot([O(1), S(1), X(1), S(1), O(1)], [O(2), S(2), X(2), S(2), O(2)], 'b--'); hold off; xlabel('X [m]'); ylabel('Y [m]'); axis equal % Error due to DAC noise used for the Sercalo load('./mat/plant.mat', 'Gi', 'Gc', 'Gd'); G = inv(Gd)*Gc*Gi; % Dynamical estimation: % - ASD of DAC noise used for the Sercalo % - Multiply by transfer function from Sercalo voltage to angle estimation using the 4QD freqs = logspace(1, 3, 1000); fs = 1e4; % ASD of the DAC voltage going to the Sercalo in [V/sqrt(Hz)] asd_uc = (20/2^16)/sqrt(12*fs)*ones(length(freqs), 1); % ASD of the measured angle by the QD in [rad/sqrt(Hz)] asd_theta = asd_uc.*abs(squeeze(freqresp(G(1,1), freqs, 'Hz'))); figure; loglog(freqs, asd_theta) % Then the corresponding ASD of the measured displacement by the interferometer is: asd_L = asd_theta*10^(-6); % [m/sqrt(Hz)] % And we integrate that to have the RMS value: cps_L = 1/pi*cumtrapz(2*pi*freqs, (asd_L).^2); % The RMS value is: sqrt(cps_L(end)) % #+RESULTS: % : 1.647e-11 figure; loglog(freqs, cps_L) % Let's estimate the beam angle error corresponding to 1 LSB of the sercalo's DAC. % Gain of the Sercalo is approximatively 5 degrees for 10V. % However the beam angle deviation is 4 times the angle deviation of the sercalo mirror, thus: d_alpha = 4*(20/2^16)*(5*pi/180)/10 % [rad] % #+RESULTS: % : 1.0653e-05 % This corresponds to a measurement error of the Attocube equals to (in [m]) 1e-6*d_alpha % [m] %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); % Coprime Factorization load('mat/plant.mat', 'sys', 'Gi', 'Zc', 'Ga', 'Gc', 'Gn', 'Gd'); [fact, Ml, Nl] = lncf(Gc*Gi); %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); % Load Plant load('mat/plant.mat', 'G'); % RGA-Number freqs = logspace(2, 4, 1000); G_resp = freqresp(G, freqs, 'Hz'); A = zeros(size(G_resp)); RGAnum = zeros(1, length(freqs)); for i = 1:length(freqs) A(:, :, i) = G_resp(:, :, i).*inv(G_resp(:, :, i))'; RGAnum(i) = sum(sum(abs(A(:, :, i)-eye(2)))); end % RGA = G0.*inv(G0)'; figure; plot(freqs, RGAnum); set(gca, 'xscale', 'log'); U = zeros(2, 2, length(freqs)); S = zeros(2, 2, length(freqs)) V = zeros(2, 2, length(freqs)); for i = 1:length(freqs) [Ui, Si, Vi] = svd(G_resp(:, :, i)); U(:, :, i) = Ui; S(:, :, i) = Si; V(:, :, i) = Vi; end % Rotation Matrix G0 = freqresp(G, 0); %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); freqs = logspace(0, 2, 1000); % Load Plant load('mat/plant.mat', 'Gn', 'Gd'); % Analysis % The plant is basically a constant until frequencies up to the required bandwidth. % We get that constant value. Gn0 = freqresp(inv(Gd)*Gn, 0); % We design two controller containing 2 integrators and one lead near the crossover frequency set to 10Hz. h = 2; w0 = 2*pi*10; Knh = 1/Gn0(1,1) * (w0/s)^2 * (1 + s/w0*h)/(1 + s/w0/h)/h; Knv = 1/Gn0(2,2) * (w0/s)^2 * (1 + s/w0*h)/(1 + s/w0/h)/h; figure; hold on; plot(freqs, abs(squeeze(freqresp(Gn0(1,1)*Knh, freqs, 'Hz')))) hold off; set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); xlabel('Frequency [Hz]'); ylabel('Loop Gain'); % Save Kn = blkdiag(Knh, Knv); Knd = c2d(Kn, 1e-4, 'tustin'); % The controllers can be downloaded [[./mat/K_newport.mat][here]]. save('mat/K_newport.mat', 'Kn', 'Knd'); %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); fs = 1e4; % Data Load and pre-processing uh = load('mat/data_rep_h.mat', ... 't', 'Uch', 'Ucv', ... 'Unh', 'Unv', ... 'Vph', 'Vpv', ... 'Vnh', 'Vnv', ... 'Va'); uv = load('mat/data_rep_v.mat', ... 't', 'Uch', 'Ucv', ... 'Unh', 'Unv', ... 'Vph', 'Vpv', ... 'Vnh', 'Vnv', ... 'Va'); % Let's start one second after the first command in the system i0 = find(uh.Unh ~= 0, 1) + fs; iend = i0+fs*floor((length(uh.t)-i0)/fs); uh.Uch([1:i0-1, iend:end]) = []; uh.Ucv([1:i0-1, iend:end]) = []; uh.Unh([1:i0-1, iend:end]) = []; uh.Unv([1:i0-1, iend:end]) = []; uh.Vph([1:i0-1, iend:end]) = []; uh.Vpv([1:i0-1, iend:end]) = []; uh.Vnh([1:i0-1, iend:end]) = []; uh.Vnv([1:i0-1, iend:end]) = []; uh.Va ([1:i0-1, iend:end]) = []; uh.t ([1:i0-1, iend:end]) = []; % We reset the time t uh.t = uh.t - uh.t(1); % Let's start one second after the first command in the system i0 = find(uv.Unv ~= 0, 1) + fs; iend = i0+fs*floor((length(uv.t)-i0)/fs); uv.Uch([1:i0-1, iend:end]) = []; uv.Ucv([1:i0-1, iend:end]) = []; uv.Unh([1:i0-1, iend:end]) = []; uv.Unv([1:i0-1, iend:end]) = []; uv.Vph([1:i0-1, iend:end]) = []; uv.Vpv([1:i0-1, iend:end]) = []; uv.Vnh([1:i0-1, iend:end]) = []; uv.Vnv([1:i0-1, iend:end]) = []; uv.Va ([1:i0-1, iend:end]) = []; uv.t ([1:i0-1, iend:end]) = []; % We reset the time t uv.t = uv.t - uv.t(1); % Some Time domain plots tend = 5; % [s] figure; ax1 = subplot(2, 2, 1); hold on; plot(uh.t(1:tend*fs), uh.Unh(1:tend*fs)); hold off; xlabel('Time [s]'); ylabel('Voltage [V]'); title('Newport Tilt - Horizontal Direction'); ax3 = subplot(2, 2, 3); hold on; plot(uh.t(1:tend*fs), 1e9*uh.Va(1:tend*fs)); hold off; xlabel('Time [s]'); ylabel('Distance [nm]'); title('Attocube - Horizontal Direction'); ax2 = subplot(2, 2, 2); hold on; plot(uv.t(1:tend*fs), uv.Unv(1:tend*fs)); hold off; xlabel('Time [s]'); ylabel('Voltage [V]'); title('Newport Tilt - Vertical Direction'); ax4 = subplot(2, 2, 4); hold on; plot(uv.t(1:tend*fs), 1e9*uv.Va(1:tend*fs)); hold off; xlabel('Time [s]'); ylabel('Distance [nm]'); title('Attocube - Vertical Direction'); linkaxes([ax1,ax2,ax3,ax4],'x'); linkaxes([ax1,ax2],'xy'); linkaxes([ax3,ax4],'xy'); % Verify Tracking Angle Error % Let's verify that the positioning error of the beam is small and what could be the effect on the distance measured by the intereferometer. load('./mat/plant.mat', 'Gd'); figure; ax1 = subplot(1, 2, 1); hold on; plot(uh.t(1:2*fs), 1e6*uh.Vph(1:2*fs)/freqresp(Gd(1,1), 0), 'DisplayName', '$\theta_{h}$'); plot(uh.t(1:2*fs), 1e6*uh.Vpv(1:2*fs)/freqresp(Gd(2,2), 0), 'DisplayName', '$\theta_{v}$'); hold off; xlabel('Time [s]'); ylabel('$\theta$ [$\mu$ rad]'); title('Newport Tilt - Horizontal Direction'); legend(); ax2 = subplot(1, 2, 2); hold on; plot(uv.t(1:2*fs), 1e6*uv.Vph(1:2*fs)/freqresp(Gd(1,1), 0), 'DisplayName', '$\theta_{h}$'); plot(uv.t(1:2*fs), 1e6*uv.Vpv(1:2*fs)/freqresp(Gd(2,2), 0), 'DisplayName', '$\theta_{v}$'); hold off; xlabel('Time [s]'); ylabel('$\theta$ [$\mu$ rad]'); title('Newport Tilt - Vertical Direction'); legend(); linkaxes([ax1,ax2],'xy'); % #+NAME: fig:repeat_tracking_errors % #+CAPTION: Tracking errors during the repeatability measurement ([[./figs/repeat_tracking_errors.png][png]], [[./figs/repeat_tracking_errors.pdf][pdf]]) % [[file:figs/repeat_tracking_errors.png]] % Let's compute the PSD of the error to see the frequency content. [psd_UhRh, f] = pwelch(uh.Vph/freqresp(Gd(1,1), 0), hanning(ceil(1*fs)), [], [], fs); [psd_UhRv, ~] = pwelch(uh.Vpv/freqresp(Gd(2,2), 0), hanning(ceil(1*fs)), [], [], fs); [psd_UvRh, ~] = pwelch(uv.Vph/freqresp(Gd(1,1), 0), hanning(ceil(1*fs)), [], [], fs); [psd_UvRv, ~] = pwelch(uv.Vpv/freqresp(Gd(2,2), 0), hanning(ceil(1*fs)), [], [], fs); figure; ax1 = subplot(1, 2, 1); hold on; plot(f, sqrt(psd_UhRh), 'DisplayName', '$\Gamma_{\theta_h}$'); plot(f, sqrt(psd_UhRv), 'DisplayName', '$\Gamma_{\theta_v}$'); hold off; set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); xlabel('Frequency [Hz]'); ylabel('ASD $\left[\frac{rad}{\sqrt{Hz}}\right]$') legend('Location', 'southwest'); title('Newport Tilt - Horizontal Direction'); ax2 = subplot(1, 2, 2); hold on; plot(f, sqrt(psd_UvRh), 'DisplayName', '$\Gamma_{\theta_h}$'); plot(f, sqrt(psd_UvRv), 'DisplayName', '$\Gamma_{\theta_v}$'); hold off; set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); xlabel('Frequency [Hz]'); ylabel('ASD $\left[\frac{rad}{\sqrt{Hz}}\right]$') legend('Location', 'southwest'); title('Newport Tilt - Vertical Direction'); linkaxes([ax1,ax2],'xy'); xlim([1, 1000]); % #+NAME: fig:psd_tracking_error_rad % #+CAPTION: Power Spectral Density of the tracking errors ([[./figs/psd_tracking_error_rad.png][png]], [[./figs/psd_tracking_error_rad.pdf][pdf]]) % [[file:figs/psd_tracking_error_rad.png]] % Let's convert that to errors in distance % \[ \Delta L = L^\prime - L = \frac{L}{\cos(\alpha)} - L \approx \frac{L \alpha^2}{2} \] % with % - $L$ is the nominal distance traveled by the beam % - $L^\prime$ is the distance traveled by the beam with an angle error % - $\alpha$ is the angle error L = 0.1; % [m] [psd_UhLh, f] = pwelch(0.5*L*(uh.Vph/freqresp(Gd(1,1), 0)).^2, hanning(ceil(1*fs)), [], [], fs); [psd_UhLv, ~] = pwelch(0.5*L*(uh.Vpv/freqresp(Gd(2,2), 0)).^2, hanning(ceil(1*fs)), [], [], fs); [psd_UvLh, ~] = pwelch(0.5*L*(uv.Vph/freqresp(Gd(1,1), 0)).^2, hanning(ceil(1*fs)), [], [], fs); [psd_UvLv, ~] = pwelch(0.5*L*(uv.Vpv/freqresp(Gd(2,2), 0)).^2, hanning(ceil(1*fs)), [], [], fs); % Now, compare that with the PSD of the measured distance by the interferometer (Fig. [[fig:compare_tracking_error_attocube_meas]]). [psd_Lh, f] = pwelch(uh.Va, hanning(ceil(1*fs)), [], [], fs); [psd_Lv, ~] = pwelch(uv.Va, hanning(ceil(1*fs)), [], [], fs); figure; ax1 = subplot(1, 2, 1); hold on; plot(f, sqrt(psd_UhLh), 'DisplayName', '$\Gamma_{L_h}$'); plot(f, sqrt(psd_UhLv), 'DisplayName', '$\Gamma_{L_v}$'); plot(f, sqrt(psd_Lh), '--k', 'DisplayName', '$\Gamma_{L_h}$'); hold off; set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); xlabel('Frequency [Hz]'); ylabel('ASD $\left[\frac{m}{\sqrt{Hz}}\right]$') legend('Location', 'southwest'); title('Newport Tilt - Horizontal Direction'); ax2 = subplot(1, 2, 2); hold on; plot(f, sqrt(psd_UvLh), 'DisplayName', '$\Gamma_{L_h}$'); plot(f, sqrt(psd_UvLv), 'DisplayName', '$\Gamma_{L_v}$'); plot(f, sqrt(psd_Lv), '--k', 'DisplayName', '$\Gamma_{L_h}$'); hold off; set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); xlabel('Frequency [Hz]'); ylabel('ASD $\left[\frac{m}{\sqrt{Hz}}\right]$') legend('Location', 'southwest'); title('Newport Tilt - Vertical Direction'); linkaxes([ax1,ax2],'xy'); xlim([1, 1000]); % Processing % First, we get the mean value as measured by the interferometer for each value of the Newport angle. Vahm = mean(reshape(uh.Va, [fs floor(length(uh.t)/fs)]),2); Unhm = mean(reshape(uh.Unh, [fs floor(length(uh.t)/fs)]),2); Vavm = mean(reshape(uv.Va, [fs floor(length(uv.t)/fs)]),2); Unvm = mean(reshape(uv.Unv, [fs floor(length(uv.t)/fs)]),2); % #+RESULTS: % | Va - Horizontal [nm rms] | Va - Vertical [nm rms] | % |--------------------------+------------------------| % | 19.6 | 13.9 | figure; ax1 = subplot(1, 2, 1); hold on; plot(uh.Unh, uh.Va); plot(Unhm, Vahm) hold off; xlabel('$V_{n,h}$ [V]'); ylabel('$V_a$ [m]'); ax2 = subplot(1, 2, 2); hold on; plot(uv.Unv, uv.Va); plot(Unvm, Vavm) hold off; xlabel('$V_{n,v}$ [V]'); ylabel('$V_a$ [m]'); linkaxes([ax1,ax2],'xy'); % #+NAME: fig:repeat_plot_raw % #+CAPTION: Repeatability of the measurement ([[./figs/repeat_plot_raw.png][png]], [[./figs/repeat_plot_raw.pdf][pdf]]) % [[file:figs/repeat_plot_raw.png]] figure; ax1 = subplot(1, 2, 1); hold on; plot(uh.Unh, 1e9*(uh.Va - repmat(Vahm, length(uh.t)/length(Vahm),1))); hold off; xlabel('$V_{n,h}$ [V]'); ylabel('$V_a$ [nm]'); ax2 = subplot(1, 2, 2); hold on; plot(uv.Unv, 1e9*(uv.Va - repmat(Vavm, length(uv.t)/length(Vavm),1))); hold off; xlabel('$V_{n,v}$ [V]'); ylabel('$V_a$ [nm]'); linkaxes([ax1,ax2],'xy'); ylim([-100 100]); % Analysis of the non-repeatable contributions % Let's know try to determine where does the non-repeatability comes from. % From the 4QD signal, we can compute the angle error of the beam and thus determine the corresponding displacement measured by the attocube. % We then take the non-repeatable part of this displacement and we compare that with the total non-repeatability. % We also plot the displacement measured during the huddle test. % All the signals are shown on Fig. [[]]. Vphm = mean(reshape(uh.Vph/freqresp(Gd(1,1), 0), [fs floor(length(uh.t)/fs)]),2); Unhm = mean(reshape(uh.Unh, [fs floor(length(uh.t)/fs)]),2); Vpvm = mean(reshape(uv.Vpv/freqresp(Gd(2,2), 0), [fs floor(length(uv.t)/fs)]),2); Unvm = mean(reshape(uv.Unv, [fs floor(length(uv.t)/fs)]),2); % =Vaheq= is the equivalent measurement error in [m] due to error angle of the Sercalo. Vaheq = uh.Vph/freqresp(Gd(1,1), 0) - repmat(Vphm, length(uh.t)/length(Vphm),1); Vaveq = uv.Vpv/freqresp(Gd(2,2), 0) - repmat(Vpvm, length(uv.t)/length(Vpvm),1); Vaheq = sign(Vaheq).*Vaheq.^2; Vaveq = sign(Vaveq).*Vaveq.^2; ht = load('./mat/data_huddle_test_3.mat', 't', 'Va'); htm = 1e9*ht.Va(1:length(Vaheq)) - repmat(mean(1e9*ht.Va(1:length(Vaheq))), length(uh.t)/length(Vaheq),1); figure; ax1 = subplot(1, 2, 1); hold on; plot(uh.Unh, 1e9*(uh.Va - repmat(Vahm, length(uh.t)/length(Vahm),1))); plot(uh.Unh, 1e9*ht.Va(1:length(Vaheq))-mean(1e9*ht.Va(1:length(Vaheq)))); plot(uh.Unh, 1e9*Vaheq); hold off; xlabel('$V_{n,h}$ [V]'); ylabel('$V_a$ [nm]'); ax2 = subplot(1, 2, 2); hold on; plot(uv.Unv, 1e9*(uv.Va - repmat(Vavm, length(uv.t)/length(Vavm),1)), 'DisplayName', 'Measured Non-Repeatability'); plot(uv.Unv, 1e9*ht.Va(1:length(Vaveq))-mean(1e9*ht.Va(1:length(Vaveq))), 'DisplayName', 'Huddle Test'); plot(uv.Unv, 1e9*Vaveq, 'DisplayName', 'Due to Sercalo Angle Error'); hold off; xlabel('$V_{n,v}$ [V]'); ylabel('$V_a$ [nm]'); legend('location', 'northeast'); linkaxes([ax1,ax2],'xy'); ylim([-100 100]);