First open/close noise budgeting
This commit is contained in:
@@ -54,10 +54,8 @@ G_fs.OutputName = {'fs_ur', 'fs_uh', 'fs_d'};
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% | -1.4113e-13 | 1.0339e-13 | 3.774e-14 |
|
||||
% | 1.0339e-13 | -1.4113e-13 | 3.774e-14 |
|
||||
% | 3.7792e-14 | 3.7792e-14 | -7.5585e-14 |
|
||||
% The Bode plot of the identified dynamics is shown in Figure [[fig:iff_plant_bode_plot]].
|
||||
% At high frequency, the diagonal terms are constants while the off-diagonal terms have some roll-off.
|
||||
|
||||
|
||||
%% Bode plot for the plant
|
||||
@@ -82,7 +80,7 @@ for i = 1:2
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
|
||||
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
||||
legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
ylim([1e-13, 1e-7]);
|
||||
|
||||
@@ -102,7 +100,11 @@ linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
% Controller - Root Locus
|
||||
% We want to have integral action around the resonances of the system, but we do not want to integrate at low frequency.
|
||||
% Therefore, we can use a low pass filter.
|
||||
|
||||
|
||||
%% Integral Force Feedback Controller
|
||||
Kiff_g1 = eye(3)*1/(1 + s/2/pi/20);
|
||||
|
||||
%% Root Locus for IFF
|
||||
@@ -141,10 +143,19 @@ legend('location', 'northwest');
|
||||
% [[file:figs/iff_root_locus.png]]
|
||||
|
||||
|
||||
%% Integral Force Feedback Controller
|
||||
%% Integral Force Feedback Controller with optimal gain
|
||||
Kiff = g*Kiff_g1;
|
||||
|
||||
% Damped Plant
|
||||
%% Save the IFF controller
|
||||
save('mat/Kiff.mat', 'Kiff');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:schematic_jacobian_frame_fastjack_iff
|
||||
% #+caption: Use of Jacobian matrices to obtain the system in the frame of the fastjacks
|
||||
% #+RESULTS:
|
||||
% [[file:figs/schematic_jacobian_frame_fastjack_iff.png]]
|
||||
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
@@ -157,8 +168,8 @@ io(io_i) = linio([mdl, '/control_system'], 1, 'input'); io_i = io_i + 1;
|
||||
% Force Sensor {3x1} [m]
|
||||
io(io_i) = linio([mdl, '/DCM'], 1, 'openoutput'); io_i = io_i + 1;
|
||||
|
||||
%% DCM Kinematics
|
||||
load('mat/dcm_kinematics.mat');
|
||||
%% Load DCM Kinematics
|
||||
load('dcm_kinematics.mat');
|
||||
|
||||
%% Identification of the Open Loop plant
|
||||
controller.type = 0; % Open Loop
|
||||
@@ -172,6 +183,12 @@ G_dp = J_a_111*inv(J_s_111)*linearize(mdl, io);
|
||||
G_dp.InputName = {'u_ur', 'u_uh', 'u_d'};
|
||||
G_dp.OutputName = {'d_ur', 'd_uh', 'd_d'};
|
||||
|
||||
|
||||
|
||||
% The dynamics from $\bm{u}$ to $\bm{d}_{\text{fj}}$ (open-loop dynamics) and from $\bm{u}^\prime$ to $\bm{d}_{\text{fs}}$ are compared in Figure [[fig:comp_damped_undamped_plant_iff_bode_plot]].
|
||||
% It is clear that the Integral Force Feedback control strategy is very effective in damping the resonances of the plant.
|
||||
|
||||
|
||||
%% Comparison of the damped and undamped plant
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
@@ -221,5 +238,3 @@ ylim([-180, 0]);
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
save('mat/Kiff.mat', 'Kiff');
|
||||
|
@@ -40,13 +40,11 @@ clear io; io_i = 1;
|
||||
|
||||
%% Inputs
|
||||
% Control Input {3x1} [N]
|
||||
io(io_i) = linio([mdl, '/u'], 1, 'openinput'); io_i = io_i + 1;
|
||||
% % Stepper Displacement {3x1} [m]
|
||||
% io(io_i) = linio([mdl, '/d'], 1, 'openinput'); io_i = io_i + 1;
|
||||
io(io_i) = linio([mdl, '/control_system'], 1, 'openinput'); io_i = io_i + 1;
|
||||
|
||||
%% Outputs
|
||||
% Strain Gauges {3x1} [m]
|
||||
io(io_i) = linio([mdl, '/sg'], 1, 'openoutput'); io_i = io_i + 1;
|
||||
io(io_i) = linio([mdl, '/DCM'], 2, 'openoutput'); io_i = io_i + 1;
|
||||
|
||||
%% Extraction of the dynamics
|
||||
G_sg = linearize(mdl, io);
|
||||
@@ -57,12 +55,12 @@ G_sg.OutputName = {'sg_ur', 'sg_uh', 'sg_d'};
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% | -1.4113e-13 | 1.0339e-13 | 3.774e-14 |
|
||||
% | 1.0339e-13 | -1.4113e-13 | 3.774e-14 |
|
||||
% | 3.7792e-14 | 3.7792e-14 | -7.5585e-14 |
|
||||
% | 4.4443e-09 | 1.0339e-13 | 3.774e-14 |
|
||||
% | 1.0339e-13 | 4.4443e-09 | 3.774e-14 |
|
||||
% | 3.7792e-14 | 3.7792e-14 | 4.4444e-09 |
|
||||
|
||||
|
||||
%% Bode plot for the plant
|
||||
%% Bode plot for the plant (strain gauge output)
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
@@ -83,7 +81,8 @@ end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
|
||||
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
|
||||
ylim([1e-14, 1e-7]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
@@ -95,7 +94,133 @@ set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
ylim([-180, 180]);
|
||||
ylim([-180, 0]);
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
% Relative Active Damping
|
||||
|
||||
Krad_g1 = eye(3)*s/(s^2/(2*pi*500)^2 + 2*s/(2*pi*500) + 1);
|
||||
|
||||
|
||||
|
||||
% As can be seen in Figure [[fig:relative_damping_root_locus]], very little damping can be added using relative damping strategy using strain gauges.
|
||||
|
||||
|
||||
%% Root Locus for IFF
|
||||
gains = logspace(3, 8, 200);
|
||||
|
||||
figure;
|
||||
|
||||
hold on;
|
||||
plot(real(pole(G_sg)), imag(pole(G_sg)), 'x', 'color', colors(1,:), ...
|
||||
'DisplayName', '$g = 0$');
|
||||
plot(real(tzero(G_sg)), imag(tzero(G_sg)), 'o', 'color', colors(1,:), ...
|
||||
'HandleVisibility', 'off');
|
||||
|
||||
for g = gains
|
||||
clpoles = pole(feedback(G_sg, g*Krad_g1, -1));
|
||||
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:), ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
|
||||
% Optimal gain
|
||||
g = 2e5;
|
||||
clpoles = pole(feedback(G_sg, g*Krad_g1, -1));
|
||||
plot(real(clpoles), imag(clpoles), 'x', 'color', colors(2,:), ...
|
||||
'DisplayName', sprintf('$g=%.0e$', g));
|
||||
hold off;
|
||||
xlim([-6, 0]); ylim([0, 2700]);
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
legend('location', 'northwest');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:relative_damping_root_locus
|
||||
% #+caption: Root Locus for the relative damping control
|
||||
% #+RESULTS:
|
||||
% [[file:figs/relative_damping_root_locus.png]]
|
||||
|
||||
|
||||
Krad = -g*Krad_g1;
|
||||
|
||||
% Damped Plant
|
||||
% The controller is implemented on Simscape, and the damped plant is identified.
|
||||
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
|
||||
%% Inputs
|
||||
% Control Input {3x1} [N]
|
||||
io(io_i) = linio([mdl, '/control_system'], 1, 'input'); io_i = io_i + 1;
|
||||
|
||||
%% Outputs
|
||||
% Force Sensor {3x1} [m]
|
||||
io(io_i) = linio([mdl, '/DCM'], 1, 'openoutput'); io_i = io_i + 1;
|
||||
|
||||
%% DCM Kinematics
|
||||
load('dcm_kinematics.mat');
|
||||
|
||||
%% Identification of the Open Loop plant
|
||||
controller.type = 0; % Open Loop
|
||||
G_ol = J_a_111*inv(J_s_111)*linearize(mdl, io);
|
||||
G_ol.InputName = {'u_ur', 'u_uh', 'u_d'};
|
||||
G_ol.OutputName = {'d_ur', 'd_uh', 'd_d'};
|
||||
|
||||
%% Identification of the damped plant with Relative Active Damping
|
||||
controller.type = 2; % RAD
|
||||
G_dp = J_a_111*inv(J_s_111)*linearize(mdl, io);
|
||||
G_dp.InputName = {'u_ur', 'u_uh', 'u_d'};
|
||||
G_dp.OutputName = {'d_ur', 'd_uh', 'd_d'};
|
||||
|
||||
%% Comparison of the damped and undamped plant
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_ol(1,1), freqs, 'Hz'))), ...
|
||||
'DisplayName', 'd - OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_ol(2,2), freqs, 'Hz'))), ...
|
||||
'DisplayName', 'uh - OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_ol(3,3), freqs, 'Hz'))), ...
|
||||
'DisplayName', 'ur - OL');
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(1,1), freqs, 'Hz'))), '--', ...
|
||||
'DisplayName', 'd - IFF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(2,2), freqs, 'Hz'))), '--', ...
|
||||
'DisplayName', 'uh - IFF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(3,3), freqs, 'Hz'))), '--', ...
|
||||
'DisplayName', 'ur - IFF');
|
||||
for i = 1:2
|
||||
for j = i+1:3
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
|
||||
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
|
||||
ylim([1e-12, 1e-6]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_ol(1,1), freqs, 'Hz'))));
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_ol(2,2), freqs, 'Hz'))));
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_ol(3,3), freqs, 'Hz'))));
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_dp(1,1), freqs, 'Hz'))), '--');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_dp(2,2), freqs, 'Hz'))), '--');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_dp(3,3), freqs, 'Hz'))), '--');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
ylim([-180, 0]);
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
@@ -32,3 +32,308 @@ colors = colororder;
|
||||
|
||||
%% Frequency Vector
|
||||
freqs = logspace(1, 3, 1000);
|
||||
|
||||
% System Identification
|
||||
% Let's identify the damped plant.
|
||||
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
|
||||
%% Inputs
|
||||
% Control Input {3x1} [N]
|
||||
io(io_i) = linio([mdl, '/control_system'], 1, 'input'); io_i = io_i + 1;
|
||||
|
||||
%% Outputs
|
||||
% Force Sensor {3x1} [m]
|
||||
io(io_i) = linio([mdl, '/DCM'], 1, 'openoutput'); io_i = io_i + 1;
|
||||
|
||||
%% Load DCM Kinematics and IFF controller
|
||||
load('dcm_kinematics.mat');
|
||||
load('Kiff.mat');
|
||||
|
||||
%% Identification of the damped plant with IFF
|
||||
controller.type = 1; % IFF
|
||||
G_dp = J_a_111*inv(J_s_111)*linearize(mdl, io);
|
||||
G_dp.InputName = {'u_ur', 'u_uh', 'u_d'};
|
||||
G_dp.OutputName = {'d_ur', 'd_uh', 'd_d'};
|
||||
|
||||
%% Comparison of the damped and undamped plant
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(1,1), freqs, 'Hz'))), '-', ...
|
||||
'DisplayName', 'd - IFF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(2,2), freqs, 'Hz'))), '-', ...
|
||||
'DisplayName', 'uh - IFF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(3,3), freqs, 'Hz'))), '-', ...
|
||||
'DisplayName', 'ur - IFF');
|
||||
for i = 1:2
|
||||
for j = i+1:3
|
||||
plot(freqs, abs(squeeze(freqresp(G_dp(i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
|
||||
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
|
||||
ylim([1e-12, 1e-8]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_dp(1,1), freqs, 'Hz'))), '-');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_dp(2,2), freqs, 'Hz'))), '-');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_dp(3,3), freqs, 'Hz'))), '-');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
ylim([-180, 0]);
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
% High Authority Controller
|
||||
% Let's design a controller with a bandwidth of 100Hz.
|
||||
% As the plant is well decoupled and well approximated by a constant at low frequency, the high authority controller can easily be designed with SISO loop shaping.
|
||||
|
||||
|
||||
%% Controller design
|
||||
wc = 2*pi*100; % Wanted crossover frequency [rad/s]
|
||||
a = 2; % Lead parameter
|
||||
|
||||
Khac = diag(1./diag(abs(evalfr(G_dp, 1j*wc)))) * ... % Diagonal controller
|
||||
wc/s * ... % Integrator
|
||||
1/(sqrt(a))*(1 + s/(wc/sqrt(a)))/(1 + s/(wc*sqrt(a))) * ... % Lead
|
||||
1/(s^2/(4*wc)^2 + 2*s/(4*wc) + 1); % Low pass filter
|
||||
|
||||
%% Save the HAC controller
|
||||
save('mat/Khac_iff.mat', 'Khac');
|
||||
|
||||
%% Loop Gain
|
||||
L_hac_lac = G_dp * Khac;
|
||||
|
||||
%% Bode Plot of the Loop Gain
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(L_hac_lac(1,1), freqs, 'Hz'))), '-', ...
|
||||
'DisplayName', 'd');
|
||||
plot(freqs, abs(squeeze(freqresp(L_hac_lac(2,2), freqs, 'Hz'))), '-', ...
|
||||
'DisplayName', 'uh');
|
||||
plot(freqs, abs(squeeze(freqresp(L_hac_lac(3,3), freqs, 'Hz'))), '-', ...
|
||||
'DisplayName', 'ur');
|
||||
for i = 1:2
|
||||
for j = i+1:3
|
||||
plot(freqs, abs(squeeze(freqresp(L_hac_lac(i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Loop Gain'); set(gca, 'XTickLabel',[]);
|
||||
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
||||
ylim([1e-2, 1e1]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(L_hac_lac(1,1), freqs, 'Hz'))), '-');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(L_hac_lac(2,2), freqs, 'Hz'))), '-');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(L_hac_lac(3,3), freqs, 'Hz'))), '-');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
ylim([-180, 0]);
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:hac_iff_loop_gain_bode_plot
|
||||
% #+caption: Bode Plot of the Loop gain for the High Authority Controller
|
||||
% #+RESULTS:
|
||||
% [[file:figs/hac_iff_loop_gain_bode_plot.png]]
|
||||
|
||||
|
||||
%% Compute the Eigenvalues of the loop gain
|
||||
Ldet = zeros(3, length(freqs));
|
||||
|
||||
Lmimo = squeeze(freqresp(L_hac_lac, freqs, 'Hz'));
|
||||
for i_f = 1:length(freqs)
|
||||
Ldet(:, i_f) = eig(squeeze(Lmimo(:,:,i_f)));
|
||||
end
|
||||
|
||||
|
||||
|
||||
% As shown in the Root Locus plot in Figure [[fig:loci_hac_iff_fast_jack]], the closed loop system should be stable.
|
||||
|
||||
|
||||
%% Plot of the eigenvalues of L in the complex plane
|
||||
figure;
|
||||
hold on;
|
||||
% Angle used to draw the circles
|
||||
theta = linspace(0, 2*pi, 100);
|
||||
% Unit circle
|
||||
plot(cos(theta), sin(theta), '--');
|
||||
% Circle for module margin
|
||||
plot(-1 + min(min(abs(Ldet + 1)))*cos(theta), min(min(abs(Ldet + 1)))*sin(theta), '--');
|
||||
|
||||
for i = 1:3
|
||||
plot(real(squeeze(Ldet(i,:))), imag(squeeze(Ldet(i,:))), 'k.');
|
||||
plot(real(squeeze(Ldet(i,:))), -imag(squeeze(Ldet(i,:))), 'k.');
|
||||
end
|
||||
% Unstable Point
|
||||
plot(-1, 0, 'kx', 'HandleVisibility', 'off');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'lin'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Real'); ylabel('Imag');
|
||||
axis square;
|
||||
xlim([-3, 1]); ylim([-2, 2]);
|
||||
|
||||
% Performances
|
||||
% In order to estimate the performances of the HAC-IFF control strategy, the transfer function from motion errors of the stepper motors to the motion error of the crystal is identified both in open loop and with the HAC-IFF strategy.
|
||||
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
|
||||
%% Inputs
|
||||
% Jack Motion Erros {3x1} [m]
|
||||
io(io_i) = linio([mdl, '/stepper_errors'], 1, 'input'); io_i = io_i + 1;
|
||||
|
||||
%% Outputs
|
||||
% Interferometer Output {3x1} [m]
|
||||
io(io_i) = linio([mdl, '/DCM'], 1, 'output'); io_i = io_i + 1;
|
||||
|
||||
%% Identification of the transmissibility of errors in open-loop
|
||||
controller.type = 0; % Open Loop
|
||||
T_ol = inv(J_s_111)*linearize(mdl, io)*J_a_111;
|
||||
T_ol.InputName = {'e_dz', 'e_ry', 'e_rx'};
|
||||
T_ol.OutputName = {'dx', 'ry', 'rx'};
|
||||
|
||||
%% Load DCM Kinematics and IFF controller
|
||||
load('dcm_kinematics.mat');
|
||||
load('Kiff.mat');
|
||||
|
||||
%% Identification of the transmissibility of errors with HAC-IFF
|
||||
controller.type = 3; % IFF
|
||||
T_hl = inv(J_s_111)*linearize(mdl, io)*J_a_111;
|
||||
T_hl.InputName = {'e_dz', 'e_ry', 'e_rx'};
|
||||
T_hl.OutputName = {'dx', 'ry', 'rx'};
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% : 1
|
||||
|
||||
% And both transmissibilities are compared in Figure [[fig:stepper_transmissibility_comp_ol_hac_iff]].
|
||||
|
||||
|
||||
%% Transmissibility of stepper errors
|
||||
f = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(f, abs(squeeze(freqresp(T_ol(1,1), f, 'Hz'))), '-', ...
|
||||
'DisplayName', '$d_z$ - OL');
|
||||
plot(f, abs(squeeze(freqresp(T_ol(2,2), f, 'Hz'))), '-', ...
|
||||
'DisplayName', '$r_y$ - OL');
|
||||
plot(f, abs(squeeze(freqresp(T_ol(3,3), f, 'Hz'))), '-', ...
|
||||
'DisplayName', '$r_x$ - OL');
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(f, abs(squeeze(freqresp(T_hl(1,1), f, 'Hz'))), '--', ...
|
||||
'DisplayName', '$d_z$ - HAC-IFF');
|
||||
plot(f, abs(squeeze(freqresp(T_hl(2,2), f, 'Hz'))), '--', ...
|
||||
'DisplayName', '$r_y$ - HAC-IFF');
|
||||
plot(f, abs(squeeze(freqresp(T_hl(3,3), f, 'Hz'))), '--', ...
|
||||
'DisplayName', '$r_x$ - HAC-IFF');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Stepper transmissibility');
|
||||
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
|
||||
ylim([1e-2, 1e2]);
|
||||
xlim([f(1), f(end)]);
|
||||
|
||||
% Close Loop noise budget
|
||||
|
||||
%% Load disturbances
|
||||
load('asd_noises_disturbances.mat');
|
||||
|
||||
|
||||
|
||||
% Let's compute the amplitude spectral density of the jack motion errors due to the sensor noise, the actuator noise and disturbances.
|
||||
|
||||
|
||||
%% Computation of ASD of contribution of inputs to the closed-loop motion
|
||||
% Error due to disturbances
|
||||
asd_d = abs(squeeze(freqresp(Wd*(1/(1 + G_dp(1,1)*Khac(1,1))), f, 'Hz')));
|
||||
% Error due to actuator noise
|
||||
asd_u = abs(squeeze(freqresp(Wu*(G_dp(1,1)/(1 + G_dp(1,1)*Khac(1,1))), f, 'Hz')));
|
||||
% Error due to sensor noise
|
||||
asd_n = abs(squeeze(freqresp(Wn*(G_dp(1,1)*Khac(1,1)/(1 + G_dp(1,1)*Khac(1,1))), f, 'Hz')));
|
||||
|
||||
|
||||
|
||||
% The closed-loop ASD is then:
|
||||
|
||||
%% ASD of the closed-loop motion
|
||||
asd_cl = sqrt(asd_d.^2 + asd_u.^2 + asd_n.^2);
|
||||
|
||||
|
||||
|
||||
% The obtained ASD are shown in Figure [[fig:close_loop_asd_noise_budget_hac_iff]].
|
||||
|
||||
|
||||
%% Noise Budget (ASD)
|
||||
f = logspace(-1, 3, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(f, asd_n, 'DisplayName', '$n$');
|
||||
plot(f, asd_u, 'DisplayName', '$d_u$');
|
||||
plot(f, asd_d, 'DisplayName', '$d$');
|
||||
plot(f, asd_cl, 'k--', 'DisplayName', '$y$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('ASD [$m/\sqrt{Hz}$]');
|
||||
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
|
||||
xlim([f(1), f(end)]);
|
||||
ylim([1e-16, 1e-8]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:close_loop_asd_noise_budget_hac_iff
|
||||
% #+caption: Closed Loop noise budget
|
||||
% #+RESULTS:
|
||||
% [[file:figs/close_loop_asd_noise_budget_hac_iff.png]]
|
||||
|
||||
% Let's compare the open-loop and close-loop cases (Figure [[fig:cps_comp_ol_cl_hac_iff]]).
|
||||
|
||||
% Amplitude spectral density of the open loop motion errors [m/sqrt(Hz)]
|
||||
asd_ol = abs(squeeze(freqresp(Wd, f, 'Hz')));
|
||||
|
||||
% CPS of open-loop motion [m^2]
|
||||
cps_ol = flip(-cumtrapz(flip(f), flip(asd_ol.^2)));
|
||||
% CPS of closed-loop motion [m^2]
|
||||
cps_cl = flip(-cumtrapz(flip(f), flip(asd_cl.^2)));
|
||||
|
||||
%% Cumulative Power Spectrum - Motion error of fast jack
|
||||
figure;
|
||||
hold on;
|
||||
plot(f, cps_ol, 'DisplayName', sprintf('OL, $\\epsilon_d = %.0f$ [nm,rms]', 1e9*sqrt(cps_ol(1))));
|
||||
plot(f, cps_cl, 'DisplayName', sprintf('CL, $\\epsilon_d = %.0f$ [nm,rms]', 1e9*sqrt(cps_cl(1))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('CPS [$m^2$]');
|
||||
legend('location', 'southwest', 'FontSize', 8);
|
||||
xlim([f(1), f(end)]);
|
||||
% ylim([1e-16, 1e-8]);
|
||||
|
@@ -63,7 +63,7 @@ G.OutputName = {'int_111_1', 'int_111_2', 'int_111_3'};
|
||||
|
||||
% Plant in the frame of the fastjacks
|
||||
|
||||
load('mat/dcm_kinematics.mat');
|
||||
load('dcm_kinematics.mat');
|
||||
|
||||
|
||||
|
||||
|
@@ -22,6 +22,15 @@ colors = colororder;
|
||||
freqs = logspace(1, 3, 1000);
|
||||
|
||||
% Bragg Angle
|
||||
% There is a simple relation eqref:eq:bragg_angle_formula between:
|
||||
% - $d_{\text{off}}$ is the wanted offset between the incident x-ray and the output x-ray
|
||||
% - $\theta_b$ is the bragg angle
|
||||
% - $d_z$ is the corresponding distance between the first and second crystals
|
||||
|
||||
% \begin{equation} \label{eq:bragg_angle_formula}
|
||||
% d_z = \frac{d_{\text{off}}}{2 \cos \theta_b}
|
||||
% \end{equation}
|
||||
|
||||
|
||||
%% Tested bragg angles
|
||||
bragg = linspace(5, 80, 1000); % Bragg angle [deg]
|
||||
@@ -30,6 +39,11 @@ d_off = 10.5e-3; % Wanted offset between x-rays [m]
|
||||
%% Vertical Jack motion as a function of Bragg angle
|
||||
dz = d_off./(2*cos(bragg*pi/180));
|
||||
|
||||
|
||||
|
||||
% This relation is shown in Figure [[fig:jack_motion_bragg_angle]].
|
||||
|
||||
|
||||
%% Jack motion as a function of Bragg angle
|
||||
figure;
|
||||
plot(bragg, 1e3*dz)
|
||||
@@ -42,6 +56,8 @@ xlabel('Bragg angle [deg]'); ylabel('Jack Motion [mm]');
|
||||
% #+RESULTS:
|
||||
% [[file:figs/jack_motion_bragg_angle.png]]
|
||||
|
||||
% The required jack stroke is approximately 25mm.
|
||||
|
||||
|
||||
%% Required Jack stroke
|
||||
ans = 1e3*(dz(end) - dz(1))
|
||||
|
71
matlab/dcm_noise_budget.m
Normal file
71
matlab/dcm_noise_budget.m
Normal file
@@ -0,0 +1,71 @@
|
||||
% Matlab Init :noexport:ignore:
|
||||
|
||||
%% dcm_noise_budget.m
|
||||
% Basic uniaxial noise budgeting
|
||||
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
|
||||
%% Simscape Model - Nano Hexapod
|
||||
addpath('./STEPS/')
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Frequency Vector
|
||||
freqs = logspace(1, 3, 1000);
|
||||
|
||||
%% Frequency vector for noise budget [Hz]
|
||||
f = logspace(-1, 3, 1000);
|
||||
|
||||
% Power Spectral Density of signals
|
||||
|
||||
% Interferometer noise:
|
||||
|
||||
Wn = 6e-11*(1 + s/2/pi/200)/(1 + s/2/pi/60); % m/sqrt(Hz)
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% : Measurement noise: 0.79 [nm,rms]
|
||||
|
||||
% DAC noise (amplified by the PI voltage amplifier, and converted to newtons):
|
||||
|
||||
Wdac = tf(3e-8); % V/sqrt(Hz)
|
||||
Wu = Wdac*22.5*10; % N/sqrt(Hz)
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% : DAC noise: 0.95 [uV,rms]
|
||||
|
||||
% Disturbances:
|
||||
|
||||
Wd = 5e-7/(1 + s/2/pi); % m/sqrt(Hz)
|
||||
|
||||
%% Save ASD of noise and disturbances
|
||||
save('mat/asd_noises_disturbances.mat', 'Wn', 'Wu', 'Wd');
|
||||
|
||||
% Open Loop disturbance and measurement noise
|
||||
% The comparison of the amplitude spectral density of the measurement noise and of the jack parasitic motion is performed in Figure [[fig:open_loop_noise_budget_fast_jack]].
|
||||
% It confirms that the sensor noise is low enough to measure the motion errors of the crystal.
|
||||
|
||||
|
||||
%% Bode plot for the plant (strain gauge output)
|
||||
figure;
|
||||
hold on;
|
||||
plot(f, abs(squeeze(freqresp(Wn, f, 'Hz'))), ...
|
||||
'DisplayName', 'n');
|
||||
plot(f, abs(squeeze(freqresp(Wd, f, 'Hz'))), ...
|
||||
'DisplayName', 'd');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('ASD [$m/\sqrt{Hz}$]');
|
||||
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
||||
xlim([f(1), f(end)]);
|
BIN
matlab/mat/Khac_iff.mat
Normal file
BIN
matlab/mat/Khac_iff.mat
Normal file
Binary file not shown.
BIN
matlab/mat/asd_noises_disturbances.mat
Normal file
BIN
matlab/mat/asd_noises_disturbances.mat
Normal file
Binary file not shown.
Reference in New Issue
Block a user