From b54db6fa0d70887117d6acddb510bd9f857919c1 Mon Sep 17 00:00:00 2001 From: Thomas Dehaeze Date: Tue, 18 Feb 2020 11:33:04 +0100 Subject: [PATCH] New configurable simscape model. Add logging block --- .../Root.type.Files/simscape.type.File.xml | 2 + .../1.type.DIR_SIGNIFIER.xml | 2 + .../index.html.type.File.xml | 6 + .../index.org.type.File.xml | 2 + .../nass_model.slx.type.File.xml | 6 + ...-4b31-b2a0-09d3356191b1.type.Reference.xml | 2 + active_damping/index.org | 205 ++---- .../matlab/act_damp_variability_plant.m | 668 +++++++++++------- active_damping/matlab/dvf.m | 345 +++++---- active_damping/matlab/iff.m | 348 +++++---- active_damping/matlab/ine.m | 303 ++++---- active_damping/matlab/undamped_system.m | 237 +++++-- .../src/prepareLinearizeIdentification.m | 13 +- .../src/prepareTomographyExperiment.m | 13 +- disturbances/index.org | 4 +- experiment_tomography/index.org | 4 +- experiment_tomography/matlab/tomo_exp.m | 4 +- hac_lac/index.org | 22 +- identification/index.org | 12 +- kinematics/index.org | 4 +- positioning_error/index.org | 6 +- simscape/nass_model.slx | Bin 0 -> 116382 bytes simscape_subsystems/index.org | 63 ++ simulink_project/index.org | 2 +- src/project_startup.m | 2 +- 25 files changed, 1225 insertions(+), 1050 deletions(-) create mode 100644 .SimulinkProject/Root.type.Files/simscape.type.File.xml create mode 100644 .SimulinkProject/Root.type.Files/simscape.type.File/1.type.DIR_SIGNIFIER.xml create mode 100644 .SimulinkProject/Root.type.Files/simscape.type.File/index.html.type.File.xml create mode 100644 .SimulinkProject/Root.type.Files/simscape.type.File/index.org.type.File.xml create mode 100644 .SimulinkProject/Root.type.Files/simscape.type.File/nass_model.slx.type.File.xml create mode 100644 .SimulinkProject/Root.type.ProjectPath/b547b640-2f80-4b31-b2a0-09d3356191b1.type.Reference.xml create mode 100644 simscape/nass_model.slx diff --git a/.SimulinkProject/Root.type.Files/simscape.type.File.xml b/.SimulinkProject/Root.type.Files/simscape.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/.SimulinkProject/Root.type.Files/simscape.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.SimulinkProject/Root.type.Files/simscape.type.File/1.type.DIR_SIGNIFIER.xml b/.SimulinkProject/Root.type.Files/simscape.type.File/1.type.DIR_SIGNIFIER.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/.SimulinkProject/Root.type.Files/simscape.type.File/1.type.DIR_SIGNIFIER.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.SimulinkProject/Root.type.Files/simscape.type.File/index.html.type.File.xml b/.SimulinkProject/Root.type.Files/simscape.type.File/index.html.type.File.xml new file mode 100644 index 0000000..d9a9e30 --- /dev/null +++ b/.SimulinkProject/Root.type.Files/simscape.type.File/index.html.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.SimulinkProject/Root.type.Files/simscape.type.File/index.org.type.File.xml b/.SimulinkProject/Root.type.Files/simscape.type.File/index.org.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/.SimulinkProject/Root.type.Files/simscape.type.File/index.org.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.SimulinkProject/Root.type.Files/simscape.type.File/nass_model.slx.type.File.xml b/.SimulinkProject/Root.type.Files/simscape.type.File/nass_model.slx.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/.SimulinkProject/Root.type.Files/simscape.type.File/nass_model.slx.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.SimulinkProject/Root.type.ProjectPath/b547b640-2f80-4b31-b2a0-09d3356191b1.type.Reference.xml b/.SimulinkProject/Root.type.ProjectPath/b547b640-2f80-4b31-b2a0-09d3356191b1.type.Reference.xml new file mode 100644 index 0000000..d2266e4 --- /dev/null +++ b/.SimulinkProject/Root.type.ProjectPath/b547b640-2f80-4b31-b2a0-09d3356191b1.type.Reference.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/active_damping/index.org b/active_damping/index.org index 33064fe..24df94a 100644 --- a/active_damping/index.org +++ b/active_damping/index.org @@ -96,7 +96,7 @@ After that, a tomography experiment is simulation without any active damping tec #+end_src #+begin_src matlab - open('active_damping/matlab/sim_nass_active_damping.slx') + open('nass_model.slx') #+end_src ** Identification of the dynamics for Active Damping @@ -113,11 +113,11 @@ We identify the dynamics of the system using the =linearize= function. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; - io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs + io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = io_i + 1; % Relative Motion Outputs io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; % Force Sensors io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; % Absolute Velocity Outputs @@ -272,12 +272,12 @@ We identify the dynamics of the system using the =linearize= function. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; - io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs - io(io_i) = linio([mdl, '/Compute Error in NASS base'], 2, 'openoutput'); io_i = io_i + 1; % Metrology Outputs + io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs + io(io_i) = linio([mdl, '/Tracking Error'], 1, 'openoutput', [], 'En'); io_i = io_i + 1; % Metrology Outputs #+end_src #+begin_src matlab @@ -420,8 +420,8 @@ We initialize elements for the tomography experiment. We change the simulation stop time. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '4.5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '4.5'); #+end_src And we simulate the system. @@ -540,8 +540,8 @@ This is done in order for the transient phase to be over. #+end_src #+begin_src matlab - open('active_damping/matlab/sim_nass_active_damping.slx') - load('mat/conf_simscape.mat'); + open('nass_model.slx') + load('mat/conf_simulink.mat'); #+end_src ** Variation of the Sample Mass @@ -561,7 +561,7 @@ We initialize all the stages with the default parameters. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -741,7 +741,7 @@ We initialize all the stages with the default parameters. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -920,7 +920,7 @@ We initialize all the stages with the default parameters. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -1252,7 +1252,7 @@ We initialize all the stages with the default parameters. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -1440,7 +1440,7 @@ We initialize all the stages with the default parameters. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -1710,7 +1710,7 @@ The control architecture is represented in figure [[fig:iff_1dof]] where one of #+end_src #+begin_src matlab - open('active_damping/matlab/sim_nass_active_damping.slx') + open('nass_model.slx') #+end_src ** Control Design @@ -1832,7 +1832,7 @@ We initialize all the stages with the default parameters. We set the IFF controller. #+begin_src matlab load('./active_damping/mat/K_iff.mat', 'K_iff'); - save('./mat/controllers.mat', 'K_iff', '-append'); + initializeController('type', 'iff', 'K', K_iff); #+end_src We identify the dynamics of the system using the =linearize= function. @@ -1842,7 +1842,7 @@ We identify the dynamics of the system using the =linearize= function. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -2023,13 +2023,13 @@ We initialize elements for the tomography experiment. We set the IFF controller. #+begin_src matlab load('./active_damping/mat/K_iff.mat', 'K_iff'); - save('./mat/controllers.mat', 'K_iff', '-append'); + initializeController('type', 'iff', 'K', K_iff); #+end_src We change the simulation stop time. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '4.5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '4.5'); #+end_src And we simulate the system. @@ -2191,7 +2191,7 @@ The actuator displacement can be measured with a capacitive sensor for instance. #+end_src #+begin_src matlab - open('active_damping/matlab/sim_nass_active_damping.slx') + open('nass_model.slx') #+end_src ** Control Design @@ -2312,7 +2312,7 @@ We initialize all the stages with the default parameters. We set the DVF controller. #+begin_src matlab load('./active_damping/mat/K_dvf.mat', 'K_dvf'); - save('./mat/controllers.mat', 'K_dvf', '-append'); + initializeController('type', 'dvf', 'K', K_dvf); #+end_src We identify the dynamics of the system using the =linearize= function. @@ -2322,7 +2322,7 @@ We identify the dynamics of the system using the =linearize= function. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -2503,13 +2503,13 @@ We initialize elements for the tomography experiment. We set the DVF controller. #+begin_src matlab load('./active_damping/mat/K_dvf.mat', 'K_dvf'); - save('./mat/controllers.mat', 'K_dvf', '-append'); + initializeController('type', 'dvf', 'K', K_dvf); #+end_src We change the simulation stop time. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '4.5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '4.5'); #+end_src And we simulate the system. @@ -2668,7 +2668,7 @@ In Inertial Control, a feedback is applied between the measured *absolute* motio #+end_src #+begin_src matlab - open('active_damping/matlab/sim_nass_active_damping.slx') + open('nass_model.slx') #+end_src ** Control Design @@ -2787,7 +2787,7 @@ We initialize all the stages with the default parameters. We set the Inertial controller. #+begin_src matlab load('./active_damping/mat/K_ine.mat', 'K_ine'); - save('./mat/controllers.mat', 'K_ine', '-append'); + initializeController('type', 'ine', 'K', K_ine); #+end_src We identify the dynamics of the system using the =linearize= function. @@ -2797,7 +2797,7 @@ We identify the dynamics of the system using the =linearize= function. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -3438,16 +3438,19 @@ We set the references and disturbances to zero. initializeDisturbances('enable', false); #+end_src -And all the controllers are set to 0. +We set the controller type to Open-Loop. #+begin_src matlab - K = tf(zeros(6)); - save('./mat/controllers.mat', 'K', '-append'); - K_ine = tf(zeros(6)); - save('./mat/controllers.mat', 'K_ine', '-append'); - K_iff = tf(zeros(6)); - save('./mat/controllers.mat', 'K_iff', '-append'); - K_dvf = tf(zeros(6)); - save('./mat/controllers.mat', 'K_dvf', '-append'); + initializeController('type', 'open-loop'); +#+end_src + +And we put some gravity. +#+begin_src matlab + initializeSimscapeConfiguration('gravity', true); +#+end_src + +We do not need to log any signal. +#+begin_src matlab + initializeLoggingConfiguration('log', 'none'); #+end_src ** prepareTomographyExperiment @@ -3511,16 +3514,19 @@ We set the references that corresponds to a tomography experiment. initializeDisturbances(); #+end_src -And all the controllers are set to 0. +Open Loop. #+begin_src matlab - K = tf(zeros(6)); - save('./mat/controllers.mat', 'K', '-append'); - K_ine = tf(zeros(6)); - save('./mat/controllers.mat', 'K_ine', '-append'); - K_iff = tf(zeros(6)); - save('./mat/controllers.mat', 'K_iff', '-append'); - K_dvf = tf(zeros(6)); - save('./mat/controllers.mat', 'K_dvf', '-append'); + initializeController('type', 'open-loop'); +#+end_src + +And we put some gravity. +#+begin_src matlab + initializeSimscapeConfiguration('gravity', true); +#+end_src + +We log the signals. +#+begin_src matlab + initializeLoggingConfiguration('log', 'all'); #+end_src * TODO Order :noexport: @@ -3532,7 +3538,7 @@ And all the controllers are set to 0. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -3554,7 +3560,7 @@ And all the controllers are set to 0. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -3638,7 +3644,7 @@ And all the controllers are set to 0. options.SampleTime = 0; %% Name of the Simulink File - mdl = 'sim_nass_active_damping'; + mdl = 'nass_model'; %% Input/Output definition clear io; io_i = 1; @@ -3682,103 +3688,6 @@ Why don't we see any resonance? linkaxes([ax1,ax2],'x'); #+end_src -*** TODO test on hexapod -#+begin_src matlab - %% Options for Linearized - options = linearizeOptions; - options.SampleTime = 0; - - %% Name of the Simulink File - mdl = 'test_nano_hexapod'; - - %% Input/Output definition - clear io; io_i = 1; - io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; - io(io_i) = linio([mdl, '/x'], 1, 'openoutput'); io_i = io_i + 1; - io(io_i) = linio([mdl, '/y'], 1, 'openoutput'); io_i = io_i + 1; - io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1; - - %% Run the linearization - G = linearize(mdl, io, options); - G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; - G.OutputName = {'x', 'y', 'z'}; -#+end_src - -#+begin_src matlab - %% Options for Linearized - options = linearizeOptions; - options.SampleTime = 0; - - %% Name of the Simulink File - mdl = 'test_nano_hexapod'; - - %% Input/Output definition - clear io; io_i = 1; - io(io_i) = linio([mdl, '/Fx'], 1, 'openinput'); io_i = io_i + 1; - io(io_i) = linio([mdl, '/x'], 1, 'openoutput'); io_i = io_i + 1; - io(io_i) = linio([mdl, '/y'], 1, 'openoutput'); io_i = io_i + 1; - io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1; - - %% Run the linearization - G = linearize(mdl, io, options); - G.InputName = {'Fx'}; - G.OutputName = {'x', 'y', 'z'}; -#+end_src - -#+begin_src matlab :exports none - freqs = logspace(0, 3, 1000); - - figure; - - ax1 = subplot(2, 1, 1); - hold on; - plot(freqs, abs(squeeze(freqresp(G('Edy', 'Dy(1)'), freqs, 'Hz'))), 'DisplayName', '$T_{x}$'); - hold off; - set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); - ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); - legend('location', 'southwest') - - ax2 = subplot(2, 1, 2); - hold on; - plot(freqs, 180/pi*angle(squeeze(freqresp(G('Edy', 'Dy(1)'), freqs, 'Hz')))); - hold off; - set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); - ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); - ylim([-180, 180]); - yticks([-180, -90, 0, 90, 180]); - - linkaxes([ax1,ax2],'x'); -#+end_src - -#+begin_src matlab :exports none - freqs = logspace(0, 3, 1000); - - figure; - - ax1 = subplot(2, 1, 1); - hold on; - plot(freqs, abs(squeeze(freqresp(G_cart('Erx', 'Mnx'), freqs, 'Hz'))), 'DisplayName', '$R_{x}$'); - plot(freqs, abs(squeeze(freqresp(G_cart('Ery', 'Mny'), freqs, 'Hz'))), 'DisplayName', '$R_{y}$'); - plot(freqs, abs(squeeze(freqresp(G_cart('Erz', 'Mnz'), freqs, 'Hz'))), 'DisplayName', '$R_{z}$'); - hold off; - set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); - ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); - legend('location', 'southwest') - - ax2 = subplot(2, 1, 2); - hold on; - plot(freqs, 180/pi*angle(squeeze(freqresp(G_cart('Erx', 'Mnx'), freqs, 'Hz')))); - plot(freqs, 180/pi*angle(squeeze(freqresp(G_cart('Ery', 'Mny'), freqs, 'Hz')))); - plot(freqs, 180/pi*angle(squeeze(freqresp(G_cart('Erz', 'Mnz'), freqs, 'Hz')))); - hold off; - set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); - ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); - ylim([-180, 180]); - yticks([-180, -90, 0, 90, 180]); - - linkaxes([ax1,ax2],'x'); -#+end_src - *** Sensitivity to disturbances The sensitivity to disturbances are shown on figure [[fig:sensitivity_dist_undamped]]. diff --git a/active_damping/matlab/act_damp_variability_plant.m b/active_damping/matlab/act_damp_variability_plant.m index 6152d4d..caea50c 100644 --- a/active_damping/matlab/act_damp_variability_plant.m +++ b/active_damping/matlab/act_damp_variability_plant.m @@ -5,53 +5,12 @@ clear; close all; clc; s = zpk('s'); open('active_damping/matlab/sim_nass_active_damping.slx') -load('mat/conf_simscape.mat'); +load('mat/conf_simulink.mat'); -% Initialize the Simulation +% Identification :ignore: % We initialize all the stages with the default parameters. -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); - - - -% No disturbances. - -initializeDisturbances('enable', false); - - - -% The nano-hexapod is a piezoelectric hexapod. - -initializeNanoHexapod('actuator', 'piezo'); - - - -% We set the references to zero. - -initializeReferences(); - - - -% And all the controllers are set to 0. - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); - -% Identification -% First, we identify the dynamics of the system using the =linearize= function. +prepareLinearizeIdentification(); %% Options for Linearized options = linearizeOptions; @@ -67,7 +26,11 @@ io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = i io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; -masses = [1, 10, 50]; + + +% We identify the dynamics for the following sample mass. + +masses = [1, 10, 50]; % [kg] Gm = {zeros(length(masses))}; Gm_iff = {zeros(length(masses))}; @@ -78,7 +41,7 @@ for i = 1:length(masses) initializeSample('mass', masses(i)); %% Run the linearization - G = linearize(mdl, io, 0.1, options); + G = linearize(mdl, io, 0.3, options); G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6', ... @@ -89,11 +52,11 @@ for i = 1:length(masses) Gm_ine(i) = {minreal(G({'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}))}; end -save('./active_damping/mat/plants_variable.mat', 'Gm_iff', 'Gm_dvf', 'Gm_ine', '-append'); +save('./active_damping/mat/plants_variable.mat', 'masses', 'Gm_iff', 'Gm_dvf', 'Gm_ine', '-append'); -% Plots +% Plots :ignore: -load('./active_damping/mat/plants_variable.mat', 'Gm_iff', 'Gm_dvf', 'Gm_ine'); +load('./active_damping/mat/plants_variable.mat', 'masses', 'Gm_iff', 'Gm_dvf', 'Gm_ine'); freqs = logspace(0, 3, 1000); @@ -101,13 +64,8 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gm) - set(gca,'ColorOrderIndex',i); +for i = 1:length(Gm_iff) plot(freqs, abs(squeeze(freqresp(Gm_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz')))); - for j = 2:6 - set(gca,'ColorOrderIndex',i); - plot(freqs, abs(squeeze(freqresp(Gm_iff{i}(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); - end end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); @@ -115,13 +73,9 @@ ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gm) - set(gca,'ColorOrderIndex',i); - plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); - for j = 2:6 - set(gca,'ColorOrderIndex',i); - plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_iff{i}(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz'))), 'HandleVisibility', 'off'); - end +for i = 1:length(Gm_iff) + plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); @@ -131,11 +85,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_iff_sample_mass -% #+CAPTION: Variability of the IFF plant with the Spindle Angle ([[./figs/act_damp_variability_iff_sample_mass.png][png]], [[./figs/act_damp_variability_iff_sample_mass.pdf][pdf]]) +% #+name: fig:act_damp_variability_iff_sample_mass +% #+caption: Variability of the dynamics from actuator force to force sensor with the Sample Mass ([[./figs/act_damp_variability_iff_sample_mass.png][png]], [[./figs/act_damp_variability_iff_sample_mass.pdf][pdf]]) % [[file:figs/act_damp_variability_iff_sample_mass.png]] @@ -146,13 +101,8 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gm) - set(gca,'ColorOrderIndex',i); +for i = 1:length(Gm_dvf) plot(freqs, abs(squeeze(freqresp(Gm_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz')))); - for j = 2:6 - set(gca,'ColorOrderIndex',i); - plot(freqs, abs(squeeze(freqresp(Gm_dvf{i}(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); - end end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); @@ -160,13 +110,8 @@ ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gm) - set(gca,'ColorOrderIndex',i); +for i = 1:length(Gm_dvf) plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); - for j = 2:6 - set(gca,'ColorOrderIndex',i); - plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_dvf{i}(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz'))), 'HandleVisibility', 'off'); - end end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); @@ -176,11 +121,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_dvf_sample_mass -% #+CAPTION: Variability of the DVF plant with the Spindle Angle ([[./figs/act_damp_variability_dvf_sample_mass.png][png]], [[./figs/act_damp_variability_dvf_sample_mass.pdf][pdf]]) +% #+name: fig:act_damp_variability_dvf_sample_mass +% #+caption: Variability of the dynamics from actuator force to relative motion sensor with the Sample Mass ([[./figs/act_damp_variability_dvf_sample_mass.png][png]], [[./figs/act_damp_variability_dvf_sample_mass.pdf][pdf]]) % [[file:figs/act_damp_variability_dvf_sample_mass.png]] @@ -190,13 +136,8 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gm) - set(gca,'ColorOrderIndex',i); +for i = 1:length(Gm_ine) plot(freqs, abs(squeeze(freqresp(Gm_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz')))); - for j = 2:6 - set(gca,'ColorOrderIndex',i); - plot(freqs, abs(squeeze(freqresp(Gm_ine{i}(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); - end end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); @@ -204,13 +145,8 @@ ylabel('Amplitude [$\frac{m/s}{N}$]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gm) - set(gca,'ColorOrderIndex',i); +for i = 1:length(Gm_ine) plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); - for j = 2:6 - set(gca,'ColorOrderIndex',i); - plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_ine{i}(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz'))), 'HandleVisibility', 'off'); - end end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); @@ -220,47 +156,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% Initialize the Simulation +% Identification :ignore: % We initialize all the stages with the default parameters. -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); - - - -% No disturbances. - -initializeDisturbances('enable', false); - - - -% The nano-hexapod is a piezoelectric hexapod. - -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); - - - -% And all the controllers are set to 0. - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); - -% Identification -% First, we identify the dynamics of the system using the =linearize= function. +prepareLinearizeIdentification(); %% Options for Linearized options = linearizeOptions; @@ -276,6 +177,10 @@ io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = i io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; + + +% We identify the dynamics for the following Spindle angles. + Rz_amplitudes = [0, pi/4, pi/2, pi]; % [rad] Ga = {zeros(length(Rz_amplitudes))}; @@ -284,10 +189,10 @@ Ga_dvf = {zeros(length(Rz_amplitudes))}; Ga_ine = {zeros(length(Rz_amplitudes))}; for i = 1:length(Rz_amplitudes) -initializeReferences('Rz_type', 'constant', 'Rz_amplitude', Rz_amplitudes(i)) + initializeReferences('Rz_type', 'constant', 'Rz_amplitude', Rz_amplitudes(i)) %% Run the linearization - G = linearize(mdl, io, 0.1, options); + G = linearize(mdl, io, 0.3, options); G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6', ... @@ -298,11 +203,11 @@ initializeReferences('Rz_type', 'constant', 'Rz_amplitude', Rz_amplitudes(i)) Ga_ine(i) = {minreal(G({'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}))}; end -save('./active_damping/mat/plants_variable.mat', 'Ga_iff', 'Ga_dvf', 'Ga_ine', '-append'); +save('./active_damping/mat/plants_variable.mat', 'Rz_amplitudes', 'Ga_iff', 'Ga_dvf', 'Ga_ine', '-append'); -% Plots +% Plots :ignore: -load('./active_damping/mat/plants_variable.mat', 'Ga_iff', 'Ga_dvf', 'Ga_ine'); +load('./active_damping/mat/plants_variable.mat', 'Rz_amplitudes', 'Ga_iff', 'Ga_dvf', 'Ga_ine'); freqs = logspace(0, 3, 1000); @@ -310,7 +215,7 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Ga) +for i = 1:length(Ga_iff) plot(freqs, abs(squeeze(freqresp(Ga_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; @@ -319,7 +224,7 @@ ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Ga) +for i = 1:length(Ga_iff) plot(freqs, 180/pi*angle(squeeze(freqresp(Ga_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Rz = %.0f$ [deg]', Rz_amplitudes(i)*180/pi)); end hold off; @@ -330,11 +235,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_iff_spindle_angle -% #+CAPTION: Variability of the IFF plant with the Spindle Angle ([[./figs/act_damp_variability_iff_spindle_angle.png][png]], [[./figs/act_damp_variability_iff_spindle_angle.pdf][pdf]]) +% #+name: fig:act_damp_variability_iff_spindle_angle +% #+caption: Variability of the dynamics from the actuator force to the force sensor with the Spindle Angle ([[./figs/act_damp_variability_iff_spindle_angle.png][png]], [[./figs/act_damp_variability_iff_spindle_angle.pdf][pdf]]) % [[file:figs/act_damp_variability_iff_spindle_angle.png]] @@ -345,7 +251,7 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Ga) +for i = 1:length(Ga_dvf) plot(freqs, abs(squeeze(freqresp(Ga_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; @@ -354,7 +260,7 @@ ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Ga) +for i = 1:length(Ga_dvf) plot(freqs, 180/pi*angle(squeeze(freqresp(Ga_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Rz = %.0f$ [deg]', Rz_amplitudes(i)*180/pi)); end hold off; @@ -365,11 +271,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_dvf_spindle_angle -% #+CAPTION: Variability of the DVF plant with the Spindle Angle ([[./figs/act_damp_variability_dvf_spindle_angle.png][png]], [[./figs/act_damp_variability_dvf_spindle_angle.pdf][pdf]]) +% #+name: fig:act_damp_variability_dvf_spindle_angle +% #+caption: Variability of the dynamics from actuator force to relative motion sensor with the Spindle Angle ([[./figs/act_damp_variability_dvf_spindle_angle.png][png]], [[./figs/act_damp_variability_dvf_spindle_angle.pdf][pdf]]) % [[file:figs/act_damp_variability_dvf_spindle_angle.png]] @@ -379,7 +286,7 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Ga) +for i = 1:length(Ga_ine) plot(freqs, abs(squeeze(freqresp(Ga_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; @@ -388,7 +295,7 @@ ylabel('Amplitude [$\frac{m/s}{N}$]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Ga) +for i = 1:length(Ga_ine) plot(freqs, 180/pi*angle(squeeze(freqresp(Ga_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Rz = %.0f$ [deg]', Rz_amplitudes(i)*180/pi)); end hold off; @@ -399,47 +306,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% Initialize the Simulation +% Identification :ignore: % We initialize all the stages with the default parameters. -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); - - - -% No disturbances. - -initializeDisturbances('enable', false); - - - -% The nano-hexapod is a piezoelectric hexapod. - -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); - - - -% And all the controllers are set to 0. - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); - -% Identification -% First, we identify the dynamics of the system using the =linearize= function. +prepareLinearizeIdentification(); %% Options for Linearized options = linearizeOptions; @@ -455,7 +327,16 @@ io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = i io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; -Rz_periods = [60, 10, 1]; % [s] + + +% We identify the dynamics for the following Spindle rotation periods. + +Rz_periods = [60, 6, 2, 1]; % [s] + + + +% The identification of the dynamics is done at the same Spindle angle position. + Gw = {zeros(length(Rz_periods))}; Gw_iff = {zeros(length(Rz_periods))}; @@ -463,44 +344,54 @@ Gw_dvf = {zeros(length(Rz_periods))}; Gw_ine = {zeros(length(Rz_periods))}; for i = 1:length(Rz_periods) - initializeReferences('Rz_type', 'rotating', 'Rz_period', Rz_periods(i)); + initializeReferences('Rz_type', 'rotating', ... + 'Rz_period', Rz_periods(i), ... % Rotation period [s] + 'Rz_amplitude', -0.5*(2*pi/Rz_periods(i))); % Angle offset [rad] + + load('mat/nass_references.mat', 'Rz'); % We load the reference for the Spindle + [~, i_end] = min(abs(Rz.signals.values)); % Obtain the indice where the spindle angle is zero + t_sim = Rz.time(i_end) % Simulation time before identification [s] %% Run the linearization - G = linearize(mdl, io, 0.5, options); + G = linearize(mdl, io, t_sim, options); G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6', ... 'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}; + Gw(i) = {G}; Gw_iff(i) = {minreal(G({'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}))}; Gw_dvf(i) = {minreal(G({'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}))}; Gw_ine(i) = {minreal(G({'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}))}; end -save('./active_damping/mat/plants_variable.mat', 'Gw_iff', 'Gw_dvf', 'Gw_ine', '-append'); +save('./active_damping/mat/plants_variable.mat', 'Rz_periods', 'Gw_iff', 'Gw_dvf', 'Gw_ine', '-append'); -% Plots +% Dynamics of the Active Damping plants -load('./active_damping/mat/plants_variable.mat', 'Gw_iff', 'Gw_dvf', 'Gw_ine'); +load('./active_damping/mat/plants_variable.mat', 'Rz_periods', 'Gw_iff', 'Gw_dvf', 'Gw_ine'); +load('./active_damping/mat/undamped_plants.mat', 'G_iff', 'G_dvf', 'G_ine'); -freqs = logspace(0, 3, 1000); +freqs = logspace(0, 3, 10000); figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gw) +for i = 1:length(Gw_iff) plot(freqs, abs(squeeze(freqresp(Gw_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz')))); end +plot(freqs, abs(squeeze(freqresp(G_iff('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gw) +for i = 1:length(Gw_iff) plot(freqs, 180/pi*angle(squeeze(freqresp(Gw_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Rz = %.0f$ [rpm]', 60/Rz_periods(i))); end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', 'No Rotation'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); @@ -509,33 +400,45 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_iff_spindle_speed -% #+CAPTION: Variability of the IFF plant with the Spindle Angle ([[./figs/act_damp_variability_iff_spindle_speed.png][png]], [[./figs/act_damp_variability_iff_spindle_speed.pdf][pdf]]) +% #+name: fig:act_damp_variability_iff_spindle_speed +% #+caption: Variability of the dynamics from the actuator force to the force sensor with the Spindle rotation speed ([[./figs/act_damp_variability_iff_spindle_speed.png][png]], [[./figs/act_damp_variability_iff_spindle_speed.pdf][pdf]]) % [[file:figs/act_damp_variability_iff_spindle_speed.png]] -freqs = logspace(0, 3, 1000); +xlim([20, 30]); + + + +% #+name: fig:act_damp_variability_iff_spindle_speed_zoom +% #+caption: Variability of the dynamics from the actuator force to the force sensor with the Spindle rotation speed ([[./figs/act_damp_variability_iff_spindle_speed_zoom.png][png]], [[./figs/act_damp_variability_iff_spindle_speed_zoom.pdf][pdf]]) +% [[file:figs/act_damp_variability_iff_spindle_speed_zoom.png]] + + +freqs = logspace(0, 3, 5000); figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gw) +for i = 1:length(Gw_dvf) plot(freqs, abs(squeeze(freqresp(Gw_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz')))); end +plot(freqs, abs(squeeze(freqresp(G_dvf('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gw) +for i = 1:length(Gw_dvf) plot(freqs, 180/pi*angle(squeeze(freqresp(Gw_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Rz = %.0f$ [rpm]', 60/Rz_periods(i))); end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', 'No Rotation'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); @@ -544,32 +447,44 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_dvf_spindle_speed -% #+CAPTION: Variability of the DVF plant with the Spindle Angle ([[./figs/act_damp_variability_dvf_spindle_speed.png][png]], [[./figs/act_damp_variability_dvf_spindle_speed.pdf][pdf]]) +% #+name: fig:act_damp_variability_dvf_spindle_speed +% #+caption: Variability of the dynamics from the actuator force to the relative motion sensor with the Spindle rotation speed ([[./figs/act_damp_variability_dvf_spindle_speed.png][png]], [[./figs/act_damp_variability_dvf_spindle_speed.pdf][pdf]]) % [[file:figs/act_damp_variability_dvf_spindle_speed.png]] -freqs = logspace(0, 2, 5000); +xlim([20, 30]); + + + +% #+name: fig:act_damp_variability_dvf_spindle_speed_zoom +% #+caption: Variability of the dynamics from the actuator force to the relative motion sensor with the Spindle rotation speed ([[./figs/act_damp_variability_dvf_spindle_speed_zoom.png][png]], [[./figs/act_damp_variability_dvf_spindle_speed_zoom.pdf][pdf]]) +% [[file:figs/act_damp_variability_dvf_spindle_speed_zoom.png]] + + +freqs = logspace(0, 3, 5000); figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gw) +for i = 1:length(Gw_ine) plot(freqs, abs(squeeze(freqresp(Gw_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz')))); end +plot(freqs, abs(squeeze(freqresp(G_ine('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [$\frac{m/s}{N}$]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gw) +for i = 1:length(Gw_ine) plot(freqs, 180/pi*angle(squeeze(freqresp(Gw_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Rz = %.0f$ [rpm]', 60/Rz_periods(i))); end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', 'No Rotation'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); @@ -578,47 +493,102 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% Initialize the Simulation + + +% #+name: fig:act_damp_variability_ine_spindle_speed +% #+caption: Variability of the dynamics from the actuator force to the absolute velocity sensor with the Spindle rotation speed ([[./figs/act_damp_variability_ine_spindle_speed.png][png]], [[./figs/act_damp_variability_ine_spindle_speed.pdf][pdf]]) +% [[file:figs/act_damp_variability_ine_spindle_speed.png]] + + +xlim([20, 30]); + +% Variation of the poles and zeros with the Spindle rotation frequency + +load('./active_damping/mat/plants_variable.mat', 'Rz_periods', 'Gw_iff', 'Gw_dvf', 'Gw_ine'); +load('./active_damping/mat/undamped_plants.mat', 'G_iff', 'G_dvf', 'G_ine'); + +figure; + +subplot(1,2,1); +hold on; +for i = 1:length(Gw_iff) + G_poles = pole(Gw_iff{i}('Fnlm1', 'Fnl1')); + plot(1/Rz_periods(i), real(G_poles(imag(G_poles)<2*pi*30 & imag(G_poles)>2*pi*22)), 'kx'); +end +G_poles = pole(G_iff('Fnlm1', 'Fnl1')); +plot(0, real(G_poles(imag(G_poles)<2*pi*30 & imag(G_poles)>2*pi*22)), 'kx'); +hold off; +ylim([-inf, 0]); +xlabel('Rotation Speed [Hz]'); +ylabel('Real Part'); + +subplot(1,2,2); +hold on; +for i = 1:length(Gw_iff) + G_poles = pole(Gw_iff{i}('Fnlm1', 'Fnl1')); + plot(1/Rz_periods(i), imag(G_poles(imag(G_poles)<2*pi*30 & imag(G_poles)>2*pi*22)), 'kx'); +end +G_poles = pole(G_iff('Fnlm1', 'Fnl1')); +plot(0, imag(G_poles(imag(G_poles)<2*pi*30 & imag(G_poles)>2*pi*22)), 'kx'); +hold off; +ylim([0, inf]); +xlabel('Rotation Speed [Hz]'); +ylabel('Imaginary Part'); + + + +% #+name: fig:campbell_diagram_spindle_rotation +% #+caption: Evolution of the pole with respect to the spindle rotation speed ([[./figs/campbell_diagram_spindle_rotation.png][png]], [[./figs/campbell_diagram_spindle_rotation.pdf][pdf]]) +% [[file:figs/campbell_diagram_spindle_rotation.png]] + + +figure; + +subplot(1,2,1); +hold on; +for i = 1:length(Gw_ine) + set(gca,'ColorOrderIndex',1); + G_zeros = zero(Gw_ine{i}('Vnlm1', 'Fnl1')); + plot(1/Rz_periods(i), real(G_zeros(imag(G_zeros)<2*pi*25 & imag(G_zeros)>2*pi*22)), 'o'); + + set(gca,'ColorOrderIndex',2); + G_zeros = zero(Gw_iff{i}('Fnlm1', 'Fnl1')); + plot(1/Rz_periods(i), real(G_zeros(imag(G_zeros)<2*pi*25 & imag(G_zeros)>2*pi*22)), 'o'); + + set(gca,'ColorOrderIndex',3); + G_zeros = zero(Gw_dvf{i}('Dnlm1', 'Fnl1')); + plot(1/Rz_periods(i), real(G_zeros(imag(G_zeros)<2*pi*25 & imag(G_zeros)>2*pi*22)), 'o'); +end +hold off; +xlabel('Rotation Speed [Hz]'); +ylabel('Real Part'); + +subplot(1,2,2); +hold on; +for i = 1:length(Gw_ine) + set(gca,'ColorOrderIndex',1); + G_zeros = zero(Gw_ine{i}('Vnlm1', 'Fnl1')); + p_ine = plot(1/Rz_periods(i), imag(G_zeros(imag(G_zeros)<2*pi*25 & imag(G_zeros)>2*pi*22)), 'o'); + + set(gca,'ColorOrderIndex',2); + G_zeros = zero(Gw_iff{i}('Fnlm1', 'Fnl1')); + p_iff = plot(1/Rz_periods(i), imag(G_zeros(imag(G_zeros)<2*pi*25 & imag(G_zeros)>2*pi*22)), 'o'); + + set(gca,'ColorOrderIndex',3); + G_zeros = zero(Gw_dvf{i}('Dnlm1', 'Fnl1')); + p_dvf = plot(1/Rz_periods(i), imag(G_zeros(imag(G_zeros)<2*pi*25 & imag(G_zeros)>2*pi*22)), 'o'); +end +hold off; +xlabel('Rotation Speed [Hz]'); +ylabel('Imaginary Part'); +legend([p_ine p_iff p_dvf],{'Inertial Sensor','Force Sensor', 'Relative Motion Sensor'}, 'location', 'southwest'); + +% Identification :ignore: % We initialize all the stages with the default parameters. -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); - - - -% No disturbances. - -initializeDisturbances('enable', false); - - - -% The nano-hexapod is a piezoelectric hexapod. - -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); - - - -% And all the controllers are set to 0. - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); - -% Identification -% First, we identify the dynamics of the system using the =linearize= function. +prepareLinearizeIdentification(); %% Options for Linearized options = linearizeOptions; @@ -634,7 +604,11 @@ io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = i io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; -Ry_amplitudes = [0, 3*pi/180]; % [rad] + + +% We identify the dynamics for the following Tilt stage angles. + +Ry_amplitudes = [-3*pi/180, 3*pi/180]; % [rad] Gy = {zeros(length(Ry_amplitudes))}; Gy_iff = {zeros(length(Ry_amplitudes))}; @@ -645,7 +619,7 @@ for i = 1:length(Ry_amplitudes) initializeReferences('Ry_type', 'constant', 'Ry_amplitude', Ry_amplitudes(i)) %% Run the linearization - G = linearize(mdl, io, 0.1, options); + G = linearize(mdl, io, 0.3, options); G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6', ... @@ -656,11 +630,12 @@ for i = 1:length(Ry_amplitudes) Gy_ine(i) = {minreal(G({'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}))}; end -save('./active_damping/mat/plants_variable.mat', 'Gy_iff', 'Gy_dvf', 'Gy_ine', '-append'); +save('./active_damping/mat/plants_variable.mat', 'Ry_amplitudes', 'Gy_iff', 'Gy_dvf', 'Gy_ine', '-append'); -% Plots +% Plots :ignore: -load('./active_damping/mat/plants_variable.mat', 'Gy_iff', 'Gy_dvf', 'Gy_ine'); +load('./active_damping/mat/plants_variable.mat', 'Ry_amplitudes', 'Gy_iff', 'Gy_dvf', 'Gy_ine'); +load('./active_damping/mat/undamped_plants.mat', 'G_iff', 'G_dvf', 'G_ine'); freqs = logspace(0, 3, 1000); @@ -668,18 +643,20 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gy) +for i = 1:length(Gy_iff) plot(freqs, abs(squeeze(freqresp(Gy_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz')))); end +plot(freqs, abs(squeeze(freqresp(G_iff('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gy) +for i = 1:length(Gy_iff) plot(freqs, 180/pi*angle(squeeze(freqresp(Gy_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Ry = %.0f$ [deg]', Ry_amplitudes(i)*180/pi)); end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', '$Ry = 0$ [deg]'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); @@ -688,11 +665,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_iff_tilt_angle -% #+CAPTION: Variability of the IFF plant with the Spindle Angle ([[./figs/act_damp_variability_iff_tilt_angle.png][png]], [[./figs/act_damp_variability_iff_tilt_angle.pdf][pdf]]) +% #+name: fig:act_damp_variability_iff_tilt_angle +% #+caption: Variability of the dynamics from the actuator force to the force sensor with the Tilt stage Angle ([[./figs/act_damp_variability_iff_tilt_angle.png][png]], [[./figs/act_damp_variability_iff_tilt_angle.pdf][pdf]]) % [[file:figs/act_damp_variability_iff_tilt_angle.png]] @@ -703,18 +681,20 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gy) +for i = 1:length(Gy_dvf) plot(freqs, abs(squeeze(freqresp(Gy_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz')))); end +plot(freqs, abs(squeeze(freqresp(G_dvf('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gy) +for i = 1:length(Gy_dvf) plot(freqs, 180/pi*angle(squeeze(freqresp(Gy_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Ry = %.0f$ [deg]', Ry_amplitudes(i)*180/pi)); end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', '$Ry = 0$ [deg]'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); @@ -723,11 +703,12 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); -% #+NAME: fig:act_damp_variability_dvf_tilt_angle -% #+CAPTION: Variability of the DVF plant with the Spindle Angle ([[./figs/act_damp_variability_dvf_tilt_angle.png][png]], [[./figs/act_damp_variability_dvf_tilt_angle.pdf][pdf]]) +% #+name: fig:act_damp_variability_dvf_tilt_angle +% #+caption: Variability of the dynamics from the actuator force to the relative motion sensor with the Tilt Angle ([[./figs/act_damp_variability_dvf_tilt_angle.png][png]], [[./figs/act_damp_variability_dvf_tilt_angle.pdf][pdf]]) % [[file:figs/act_damp_variability_dvf_tilt_angle.png]] @@ -737,18 +718,20 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:length(Gy) +for i = 1:length(Gy_ine) plot(freqs, abs(squeeze(freqresp(Gy_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz')))); end +plot(freqs, abs(squeeze(freqresp(G_ine('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [$\frac{m/s}{N}$]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i = 1:length(Gy) +for i = 1:length(Gy_ine) plot(freqs, 180/pi*angle(squeeze(freqresp(Gy_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Ry = %.0f$ [deg]', Ry_amplitudes(i)*180/pi)); end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', '$Ry = 0$ [deg]'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); @@ -757,3 +740,182 @@ yticks([-180, -90, 0, 90, 180]); legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); + +% Identification :ignore: +% We initialize all the stages with the default parameters. + +prepareLinearizeIdentification(); + +%% Options for Linearized +options = linearizeOptions; +options.SampleTime = 0; + +%% Name of the Simulink File +mdl = 'sim_nass_active_damping'; + +%% Input/Output definition +clear io; io_i = 1; +io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; + + + +% We initialize the translation stage reference to be a sinus with an amplitude of 5mm and a period of 1s (Figure [[fig:ty_scanning_reference_sinus]]). + +initializeReferences('Dy_type', 'sinusoidal', ... + 'Dy_amplitude', 5e-3, ... % [m] + 'Dy_period', 1); % [s] + +load('mat/nass_references.mat', 'Dy'); +figure; +plot(Dy.time, Dy.signals.values); +xlabel('Time [s]'); ylabel('Dy - Position [m]'); +xlim([0, 2]); + + + +% #+name: fig:ty_scanning_reference_sinus +% #+caption: Reference path for the translation stage ([[./figs/ty_scanning_reference_sinus.png][png]], [[./figs/ty_scanning_reference_sinus.pdf][pdf]]) +% [[file:figs/ty_scanning_reference_sinus.png]] + +% We identify the dynamics at different positions (times) when scanning with the Translation stage. + +t_lin = [0.5, 0.75, 1, 1.25]; + +Gty = {zeros(length(t_lin))}; +Gty_iff = {zeros(length(t_lin))}; +Gty_dvf = {zeros(length(t_lin))}; +Gty_ine = {zeros(length(t_lin))}; + +%% Run the linearization +G = linearize(mdl, io, t_lin, options); +G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; +G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... + 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6', ... + 'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}; + +for i = 1:length(t_lin) + Gty(i) = {G(:,:,i)}; + Gty_iff(i) = {minreal(G({'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}, i))}; + Gty_dvf(i) = {minreal(G({'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}, i))}; + Gty_ine(i) = {minreal(G({'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}, i))}; +end + +Gty_tlin = t_lin; +save('./active_damping/mat/plants_variable.mat', 'Gty_tlin', 'Dy', 'Gty_iff', 'Gty_dvf', 'Gty_ine', '-append'); + +% Plots :ignore: + +load('./active_damping/mat/plants_variable.mat', 'Gty_tlin', 'Dy', 'Gty_iff', 'Gty_dvf', 'Gty_ine'); +load('./active_damping/mat/undamped_plants.mat', 'G_iff', 'G_dvf', 'G_ine'); + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); +hold on; +for i = 1:length(Gty_iff) + plot(freqs, abs(squeeze(freqresp(Gty_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz')))); +end +plot(freqs, abs(squeeze(freqresp(G_iff('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:length(Gty_iff) + [~, i_t] = min(abs(Dy.time - Gty_tlin(i))); + plot(freqs, 180/pi*angle(squeeze(freqresp(Gty_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Dy = %.0f$ [mm]', 1e3*Dy.signals.values(i_t))); +end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff('Fnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', '$Ry = 0$ [deg]'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); +ylim([-180, 180]); +yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); + +linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); + + + +% #+name: fig:act_damp_variability_iff_ty_scans +% #+caption: Variability of the dynamics from the actuator force to the absolute velocity sensor plant at different Ty scan positions ([[./figs/act_damp_variability_iff_ty_scans.png][png]], [[./figs/act_damp_variability_iff_ty_scans.pdf][pdf]]) +% [[file:figs/act_damp_variability_iff_ty_scans.png]] + + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); +hold on; + +for i = 1:length(Gty_dvf) + plot(freqs, abs(squeeze(freqresp(Gty_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz')))); +end +plot(freqs, abs(squeeze(freqresp(G_dvf('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:length(Gty_dvf) + [~, i_t] = min(abs(Dy.time - Gty_tlin(i))); + plot(freqs, 180/pi*angle(squeeze(freqresp(Gty_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Dy = %.0f$ [mm]', 1e3*Dy.signals.values(i_t))); +end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf('Dnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', '$Ry = 0$ [deg]'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); +ylim([-180, 180]); +yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); + +linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); + + + +% #+name: fig:act_damp_variability_dvf_ty_scans +% #+caption: Variability of the dynamics from actuator force to relative displacement sensor at different Ty scan positions ([[./figs/act_damp_variability_dvf_ty_scans.png][png]], [[./figs/act_damp_variability_dvf_ty_scans.pdf][pdf]]) +% [[file:figs/act_damp_variability_dvf_ty_scans.png]] + + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); +hold on; +for i = 1:length(Gty_ine) + plot(freqs, abs(squeeze(freqresp(Gty_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz')))); +end +plot(freqs, abs(squeeze(freqresp(G_ine('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [$\frac{m/s}{N}$]'); set(gca, 'XTickLabel',[]); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:length(Gty_ine) + [~, i_t] = min(abs(Dy.time - Gty_tlin(i))); + plot(freqs, 180/pi*angle(squeeze(freqresp(Gty_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'DisplayName', sprintf('$Dy = %.0f$ [mm]', 1e3*Dy.signals.values(i_t))); +end +plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine('Vnlm1', 'Fnl1'), freqs, 'Hz'))), 'k--', 'DisplayName', '$Ry = 0$ [deg]'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); +ylim([-180, 180]); +yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); + +linkaxes([ax1,ax2],'x'); +xlim([freqs(1), freqs(end)]); diff --git a/active_damping/matlab/dvf.m b/active_damping/matlab/dvf.m index 16df905..95915c6 100644 --- a/active_damping/matlab/dvf.m +++ b/active_damping/matlab/dvf.m @@ -4,9 +4,12 @@ clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); +addpath('active_damping/src/'); + open('active_damping/matlab/sim_nass_active_damping.slx') -load('./active_damping/mat/plants.mat', 'G_dvf'); +load('./active_damping/mat/undamped_plants.mat', 'G_dvf'); +load('./active_damping/mat/plants_variable.mat', 'masses', 'Gm_dvf'); freqs = logspace(0, 3, 1000); @@ -14,8 +17,8 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i=1:6 - plot(freqs, abs(squeeze(freqresp(G_dvf(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, abs(squeeze(freqresp(-Gm_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); @@ -23,18 +26,20 @@ ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i=1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, 180/pi*angle(squeeze(freqresp(-Gm_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz'))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); ylim([-180, 180]); yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); -K_dvf = s*20000/(1 + s/2/pi/10000); +K_dvf = s*30000/(1 + s/2/pi/10000); freqs = logspace(0, 3, 1000); @@ -42,23 +47,25 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i=1:6 - plot(freqs, abs(squeeze(freqresp(K_dvf*G_dvf(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, abs(squeeze(freqresp(K_dvf*Gm_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); +ylabel('Loop Gain'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i=1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(K_dvf*G_dvf(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, 180/pi*angle(squeeze(freqresp(K_dvf*Gm_dvf{i}('Dnlm1', 'Fnl1'), freqs, 'Hz'))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); ylim([-180, 180]); yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); @@ -66,26 +73,10 @@ K_dvf = -K_dvf*eye(6); save('./active_damping/mat/K_dvf.mat', 'K_dvf'); -initializeReferences(); -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); +prepareLinearizeIdentification(); -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = K_dvf; -save('./mat/controllers.mat', 'K_dvf', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); +load('./active_damping/mat/K_dvf.mat', 'K_dvf'); +initializeController('type', 'dvf', 'K', K_dvf); %% Options for Linearized options = linearizeOptions; @@ -96,185 +87,193 @@ mdl = 'sim_nass_active_damping'; %% Input/Output definition clear io; io_i = 1; -io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Compute Error in NASS base'], 2, 'openoutput'); io_i = io_i + 1; -%% Run the linearization -G = linearize(mdl, io, options); -G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; -G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... - 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6'}; +load('./active_damping/mat/cart_plants.mat', 'masses'); -save('./active_damping/mat/plants.mat', 'G_dvf', '-append'); +G_cart_dvf = {zeros(length(masses))}; + +load('mat/stages.mat', 'nano_hexapod'); + +for i = 1:length(masses) + initializeSample('mass', masses(i)); + + %% Run the linearization + G = linearize(mdl, io, 0.3, options); + G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; + G.OutputName = {'Dnx', 'Dny', 'Dnz', 'Rnx', 'Rny', 'Rnz'}; + + G_cart = G*inv(nano_hexapod.J'); + G_cart.InputName = {'Fnx', 'Fny', 'Fnz', 'Mnx', 'Mny', 'Mnz'}; + + G_cart_dvf(i) = {G_cart}; +end + +save('./active_damping/mat/cart_plants.mat', 'G_cart_dvf', '-append'); + +load('./active_damping/mat/cart_plants.mat', 'masses', 'G_cart', 'G_cart_dvf'); freqs = logspace(0, 3, 1000); figure; -subplot(2, 1, 1); -title('$D_g$ to $D$'); +ax1 = subplot(2, 1, 1); hold on; -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dx', 'Dgx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / D_{g,x}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dy', 'Dgy'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / D_{g,y}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dz', 'Dgz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / D_{g,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_gm('Dx', 'Dgx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_gm('Dy', 'Dgy'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_gm('Dz', 'Dgz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/m]'); xlabel('Frequency [Hz]'); -legend('location', 'southeast'); - -subplot(2, 1, 2); -title('$F_s$ to $D$'); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dx', 'Fsx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{s,x}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dy', 'Fsy'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / F_{s,y}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dz', 'Fsz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{s,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_fs('Dx', 'Fsx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_fs('Dy', 'Fsy'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_fs('Dz', 'Fsz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart_dvf{i}('Dnx', 'Fnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart_dvf{i}('Dny', 'Fny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart_dvf{i}('Dnz', 'Fnz'), freqs, 'Hz'))), ':'); +end set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); +legend([p1,p2,p3], {'Fx/Dx', 'Fy/Dx', 'Fz/Dz'}); -freqs = logspace(0, 3, 1000); - -figure; +ax2 = subplot(2, 1, 2); hold on; -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dz', 'Frzz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{rz, z}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dz', 'Ftyz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{ty, z}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dx', 'Ftyx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{ty, x}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_dist('Dz', 'Frzz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_dist('Dz', 'Ftyz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_dist('Dx', 'Ftyx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); - -freqs = logspace(0, 3, 1000); - -figure; - -ax1 = subplot(2, 2, 1); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dx', 'Fnx'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dy', 'Fny'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dz', 'Fnz'), freqs, 'Hz')))); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_cart('Dy', 'Fny'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), '--'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); - -ax2 = subplot(2, 2, 2); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_cart('Rx', 'Mnx'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Ry', 'Mny'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Rz', 'Mnz'), freqs, 'Hz')))); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_cart('Ry', 'Mny'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_dvf.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), '--'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [rad/(Nm)]'); xlabel('Frequency [Hz]'); - -ax3 = subplot(2, 2, 3); -hold on; -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{n,x}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dy', 'Fny'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / F_{n,y}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{n,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf.G_cart('Dy', 'Fny'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_dvf{i}('Dnx', 'Fnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_dvf{i}('Dny', 'Fny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_dvf{i}('Dnz', 'Fnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); +end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); -ylim([-180, 180]); -yticks([-180, -90, 0, 90, 180]); -legend('location', 'northwest'); +yticks([-540:180:540]); +legend('location', 'northeast'); -ax4 = subplot(2, 2, 4); +linkaxes([ax1,ax2],'x'); + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); hold on; -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), 'DisplayName', '$\left|R_x / M_{n,x}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Ry', 'Mny'), freqs, 'Hz'))), 'DisplayName', '$\left|R_y / M_{n,y}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), 'DisplayName', '$\left|R_z / M_{n,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf.G_cart('Ry', 'Mny'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart_dvf{i}('Rnx', 'Mnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart_dvf{i}('Rny', 'Mny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart_dvf{i}('Rnz', 'Mnz'), freqs, 'Hz'))), ':'); +end +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); +legend([p1,p2,p3], {'Fx/Dx', 'Fy/Dx', 'Fz/Dz'}); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_dvf{i}('Rnx', 'Mnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_dvf{i}('Rny', 'Mny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_dvf{i}('Rnz', 'Mnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); +end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); -ylim([-180, 180]); -yticks([-180, -90, 0, 90, 180]); -legend('location', 'northwest'); +yticks([-540:180:540]); +legend('location', 'northeast'); -linkaxes([ax1,ax2,ax3,ax4],'x'); +linkaxes([ax1,ax2],'x'); -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); +freqs = logspace(1, 3, 1000); -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); +figure; -initializeReferences('Rz_type', 'rotating', 'Rz_period', 1); +for ix = 1:6 + for iy = 1:6 + subplot(6, 6, (ix-1)*6 + iy); + hold on; + plot(freqs, abs(squeeze(freqresp(G_cart{1}(ix, iy), freqs, 'Hz'))), 'k-'); + plot(freqs, abs(squeeze(freqresp(G_cart_dvf{1}(ix, iy), freqs, 'Hz'))), 'k--'); + set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); + ylim([1e-13, 1e-4]); + xticks([]) + yticks([]) + end +end -initDisturbances(); +prepareTomographyExperiment(); -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = K_dvf; -save('./mat/controllers.mat', 'K_dvf', '-append'); +load('./active_damping/mat/K_dvf.mat', 'K_dvf'); +initializeController('type', 'dvf', 'K', K_dvf); -load('mat/conf_simscape.mat'); -set_param(conf_simscape, 'StopTime', '3'); +load('mat/conf_simulink.mat'); +set_param(conf_simulink, 'StopTime', '4.5'); sim('sim_nass_active_damping'); -t_dvf = t; -Ern_dvf = Ern; -save('./active_damping/mat/tomo_exp.mat', 'Ern_dvf', 't_dvf', '-append'); +En_dvf = En; +Eg_dvf = Eg; +save('./active_damping/mat/tomo_exp.mat', 'En_dvf', 'Eg_dvf', '-append'); -load('./active_damping/mat/tomo_exp.mat', 'Ern', 'Ern_dvf', 't', 't_dvf'); +load('./active_damping/mat/tomo_exp.mat', 'En', 'En_dvf'); +Fs = 1e3; % Sampling Frequency of the Data +t = (1/Fs)*[0:length(En(:,1))-1]; figure; hold on; -plot(t, Ern(:,1), 'DisplayName', '$\epsilon_{x}$') -plot(t, Ern(:,2), 'DisplayName', '$\epsilon_{y}$') -plot(t, Ern(:,3), 'DisplayName', '$\epsilon_{z}$') -set(gca,'ColorOrderIndex',1); -plot(t_dvf, Ern_dvf(:,1), '--', 'DisplayName', '$\epsilon_{x}$ - DVF') -plot(t_dvf, Ern_dvf(:,2), '--', 'DisplayName', '$\epsilon_{y}$ - DVF') -plot(t_dvf, Ern_dvf(:,3), '--', 'DisplayName', '$\epsilon_{z}$ - DVF') -hold off; -xlim([1,inf]); +plot(En(:,1), En(:,2), 'DisplayName', '$\epsilon_{x,y}$ - OL') +plot(En_dvf(:,1), En_dvf(:,2), 'DisplayName', '$\epsilon_{x,y}$ - DVF') +xlabel('X Motion [m]'); ylabel('Y Motion [m]'); legend(); figure; +ax1 = subplot(3, 1, 1); hold on; -plot(t, Ern(:,4), 'DisplayName', '$\epsilon_{\theta_x}$') -plot(t, Ern(:,5), 'DisplayName', '$\epsilon_{\theta_y}$') -plot(t, Ern(:,6), 'DisplayName', '$\epsilon_{\theta_z}$') -set(gca,'ColorOrderIndex',1); -plot(t_dvf, Ern_dvf(:,4), '--', 'DisplayName', '$\epsilon_{\theta_x}$ - DVF') -plot(t_dvf, Ern_dvf(:,5), '--', 'DisplayName', '$\epsilon_{\theta_y}$ - DVF') -plot(t_dvf, Ern_dvf(:,6), '--', 'DisplayName', '$\epsilon_{\theta_z}$ - DVF') -hold off; -xlim([1,inf]); +plot(t, En(:,1), 'DisplayName', '$\epsilon_{x}$') +plot(t, En_dvf(:,1), 'DisplayName', '$\epsilon_{x}$ - DVF') legend(); + +ax2 = subplot(3, 1, 2); +hold on; +plot(t, En(:,2), 'DisplayName', '$\epsilon_{y}$') +plot(t, En_dvf(:,2), 'DisplayName', '$\epsilon_{y}$ - DVF') +legend(); +ylabel('Position Error [m]'); + +ax3 = subplot(3, 1, 3); +hold on; +plot(t, En(:,3), 'DisplayName', '$\epsilon_{z}$') +plot(t, En_dvf(:,3), 'DisplayName', '$\epsilon_{z}$ - DVF') +legend(); +xlabel('Time [s]'); + +linkaxes([ax1,ax2,ax3],'x'); +xlim([0.5,inf]); + +figure; +ax1 = subplot(3, 1, 1); +hold on; +plot(t, En(:,4), 'DisplayName', '$\epsilon_{\theta_x}$') +plot(t, En_dvf(:,4), 'DisplayName', '$\epsilon_{\theta_x}$ - DVF') +legend(); + +ax2 = subplot(3, 1, 2); +hold on; +plot(t, En(:,5), 'DisplayName', '$\epsilon_{\theta_y}$') +plot(t, En_dvf(:,5), 'DisplayName', '$\epsilon_{\theta_y}$ - DVF') +legend(); +ylabel('Position Error [rad]'); + +ax3 = subplot(3, 1, 3); +hold on; +plot(t, En(:,6), 'DisplayName', '$\epsilon_{\theta_z}$') +plot(t, En_dvf(:,6), 'DisplayName', '$\epsilon_{\theta_z}$ - DVF') +legend(); +xlabel('Time [s]'); + +linkaxes([ax1,ax2,ax3],'x'); +xlim([0.5,inf]); diff --git a/active_damping/matlab/iff.m b/active_damping/matlab/iff.m index c238bd3..fe07927 100644 --- a/active_damping/matlab/iff.m +++ b/active_damping/matlab/iff.m @@ -4,18 +4,21 @@ clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); +addpath('active_damping/src/'); + open('active_damping/matlab/sim_nass_active_damping.slx') load('./active_damping/mat/undamped_plants.mat', 'G_iff'); +load('./active_damping/mat/plants_variable.mat', 'masses', 'Gm_iff'); -freqs = logspace(0, 3, 1000); +freqs = logspace(-2, 3, 1000); figure; ax1 = subplot(2, 1, 1); hold on; -for i=1:6 - plot(freqs, abs(squeeze(freqresp(G_iff(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, abs(squeeze(freqresp(-Gm_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); @@ -23,18 +26,21 @@ ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i=1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, 180/pi*angle(squeeze(freqresp(-Gm_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); ylim([-180, 180]); yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); -K_iff = 1000/s; +w0 = 2*pi*50; +K_iff = -5000/s * (s/w0)/(1 + s/w0); freqs = logspace(0, 3, 1000); @@ -42,8 +48,8 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i=1:6 - plot(freqs, abs(squeeze(freqresp(K_iff*G_iff(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, abs(squeeze(freqresp(K_iff*Gm_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); @@ -51,14 +57,16 @@ ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i=1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(K_iff*G_iff(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, 180/pi*angle(squeeze(freqresp(K_iff*Gm_iff{i}('Fnlm1', 'Fnl1'), freqs, 'Hz'))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); ylim([-180, 180]); yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); @@ -66,28 +74,10 @@ K_iff = -K_iff*eye(6); save('./active_damping/mat/K_iff.mat', 'K_iff'); -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); +prepareLinearizeIdentification(); -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); - -initializeReferences(); - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = K_iff; -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); +load('./active_damping/mat/K_iff.mat', 'K_iff'); +initializeController('type', 'iff', 'K', K_iff); %% Options for Linearized options = linearizeOptions; @@ -98,131 +88,108 @@ mdl = 'sim_nass_active_damping'; %% Input/Output definition clear io; io_i = 1; -io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Compute Error in NASS base'], 2, 'openoutput'); io_i = io_i + 1; -%% Run the linearization -G = linearize(mdl, io, options); -G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; -G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... - 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6'}; +load('./active_damping/mat/cart_plants.mat', 'masses'); -G_iff = minreal(G({'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'})); -% G_rmc = minreal(G({'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6'}, {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'})); +G_cart_iff = {zeros(length(masses))}; -save('./active_damping/mat/plants.mat', 'G_iff', '-append'); +load('mat/stages.mat', 'nano_hexapod'); + +for i = 1:length(masses) + initializeSample('mass', masses(i)); + + %% Run the linearization + G = linearize(mdl, io, 0.3, options); + G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; + G.OutputName = {'Dnx', 'Dny', 'Dnz', 'Rnx', 'Rny', 'Rnz'}; + + G_cart = G*inv(nano_hexapod.J'); + G_cart.InputName = {'Fnx', 'Fny', 'Fnz', 'Mnx', 'Mny', 'Mnz'}; + + G_cart_iff(i) = {G_cart}; +end + +save('./active_damping/mat/cart_plants.mat', 'G_cart_iff', '-append'); + +load('./active_damping/mat/cart_plants.mat', 'masses', 'G_cart', 'G_cart_iff'); freqs = logspace(0, 3, 1000); figure; -subplot(2, 1, 1); -title('$D_g$ to $D$'); +ax1 = subplot(2, 1, 1); hold on; -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dx', 'Dgx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / D_{g,x}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dy', 'Dgy'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / D_{g,y}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dz', 'Dgz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / D_{g,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_iff.G_gm('Dx', 'Dgx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_gm('Dy', 'Dgy'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_gm('Dz', 'Dgz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/m]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); - -subplot(2, 1, 2); -title('$F_s$ to $D$'); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dx', 'Fsx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{s,x}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dy', 'Fsy'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / F_{s,y}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dz', 'Fsz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{s,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_iff.G_fs('Dx', 'Fsx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_fs('Dy', 'Fsy'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_fs('Dz', 'Fsz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart_iff{i}('Dnx', 'Fnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart_iff{i}('Dny', 'Fny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart_iff{i}('Dnz', 'Fnz'), freqs, 'Hz'))), ':'); +end set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); +legend([p1,p2,p3], {'Fx/Dx', 'Fy/Dx', 'Fz/Dz'}); -freqs = logspace(0, 3, 1000); - -figure; +ax2 = subplot(2, 1, 2); hold on; -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dz', 'Frzz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{rz, z}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dz', 'Ftyz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{ty, z}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dx', 'Ftyx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{ty, x}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(minreal(prescale(G_iff.G_dist('Dz', 'Frzz'), {2*pi, 2*pi*1e3})), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(minreal(G_iff.G_dist('Dz', 'Ftyz')), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(minreal(G_iff.G_dist('Dx', 'Ftyx')), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); - -freqs = logspace(0, 3, 1000); - -figure; - -ax1 = subplot(2, 2, 1); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dx', 'Fnx'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dy', 'Fny'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dz', 'Fnz'), freqs, 'Hz')))); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_iff.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_cart('Dy', 'Fny'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), '--'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); - -ax2 = subplot(2, 2, 2); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_cart('Rx', 'Mnx'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Ry', 'Mny'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Rz', 'Mnz'), freqs, 'Hz')))); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_iff.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_cart('Ry', 'Mny'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_iff.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), '--'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [rad/(Nm)]'); xlabel('Frequency [Hz]'); - -ax3 = subplot(2, 2, 3); -hold on; -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{n,x}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dy', 'Fny'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / F_{n,y}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{n,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff.G_cart('Dy', 'Fny'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_iff{i}('Dnx', 'Fnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_iff{i}('Dny', 'Fny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_iff{i}('Dnz', 'Fnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); +end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); -ylim([-180, 180]); -yticks([-180, -90, 0, 90, 180]); -legend('location', 'northwest'); +yticks([-540:180:540]); +legend('location', 'northeast'); -ax4 = subplot(2, 2, 4); +linkaxes([ax1,ax2],'x'); + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); hold on; -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), 'DisplayName', '$\left|R_x / M_{n,x}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Ry', 'Mny'), freqs, 'Hz'))), 'DisplayName', '$\left|R_y / M_{n,y}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), 'DisplayName', '$\left|R_z / M_{n,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff.G_cart('Ry', 'Mny'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart_iff{i}('Rnx', 'Mnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart_iff{i}('Rny', 'Mny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart_iff{i}('Rnz', 'Mnz'), freqs, 'Hz'))), ':'); +end +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); +legend([p1,p2,p3], {'Fx/Dx', 'Fy/Dx', 'Fz/Dz'}); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_iff{i}('Rnx', 'Mnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_iff{i}('Rny', 'Mny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_iff{i}('Rnz', 'Mnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); +end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); -ylim([-180, 180]); -yticks([-180, -90, 0, 90, 180]); -legend('location', 'northwest'); +yticks([-540:180:540]); +legend('location', 'northeast'); -linkaxes([ax1,ax2,ax3,ax4],'x'); +linkaxes([ax1,ax2],'x'); -freqs = logspace(0, 3, 1000); +freqs = logspace(1, 3, 1000); figure; @@ -230,71 +197,84 @@ for ix = 1:6 for iy = 1:6 subplot(6, 6, (ix-1)*6 + iy); hold on; - plot(freqs, abs(squeeze(freqresp(G.G_cart(ix, iy), freqs, 'Hz'))), 'k-'); - plot(freqs, abs(squeeze(freqresp(G_iff.G_cart(ix, iy), freqs, 'Hz'))), 'k--'); + plot(freqs, abs(squeeze(freqresp(G_cart{1}(ix, iy), freqs, 'Hz'))), 'k-'); + plot(freqs, abs(squeeze(freqresp(G_cart_iff{1}(ix, iy), freqs, 'Hz'))), 'k--'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); - ylim([1e-12, 1e-5]); + ylim([1e-13, 1e-4]); + xticks([]) + yticks([]) end end -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); +prepareTomographyExperiment(); -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); +load('./active_damping/mat/K_iff.mat', 'K_iff'); +initializeController('type', 'iff', 'K', K_iff); -initializeReferences('Rz_type', 'rotating', 'Rz_period', 1); - -initDisturbances(); - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = K_iff; -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); - -load('mat/conf_simscape.mat'); -set_param(conf_simscape, 'StopTime', '3'); +load('mat/conf_simulink.mat'); +set_param(conf_simulink, 'StopTime', '4.5'); sim('sim_nass_active_damping'); -t_iff = t; -Ern_iff = Ern; -save('./active_damping/mat/tomo_exp.mat', 'Ern_iff', 't_iff', '-append'); +En_iff = En; +Eg_iff = Eg; +save('./active_damping/mat/tomo_exp.mat', 'En_iff', 'Eg_iff', '-append'); -load('./active_damping/mat/tomo_exp.mat', 'Ern', 'Ern_iff', 't', 't_iff'); +load('./active_damping/mat/tomo_exp.mat', 'En', 'En_iff'); +Fs = 1e3; % Sampling Frequency of the Data +t = (1/Fs)*[0:length(En(:,1))-1]; figure; hold on; -plot(t, Ern(:,1), 'DisplayName', '$\epsilon_{x}$') -plot(t, Ern(:,2), 'DisplayName', '$\epsilon_{y}$') -plot(t, Ern(:,3), 'DisplayName', '$\epsilon_{z}$') -set(gca,'ColorOrderIndex',1); -plot(t_iff, Ern_iff(:,1), '--', 'DisplayName', '$\epsilon_{x}$ - IFF') -plot(t_iff, Ern_iff(:,2), '--', 'DisplayName', '$\epsilon_{y}$ - IFF') -plot(t_iff, Ern_iff(:,3), '--', 'DisplayName', '$\epsilon_{z}$ - IFF') -hold off; -xlim([1,inf]); -legend(); +plot(En(:,1), En(:,2), 'DisplayName', '$\epsilon_{x,y}$ - OL') +plot(En_iff(:,1), En_iff(:,2), 'DisplayName', '$\epsilon_{x,y}$ - IFF') +xlabel('X Motion [m]'); ylabel('Y Motion [m]'); +legend('location', 'northwest'); figure; +ax1 = subplot(3, 1, 1); hold on; -plot(t, Ern(:,4), 'DisplayName', '$\epsilon_{\theta_x}$') -plot(t, Ern(:,5), 'DisplayName', '$\epsilon_{\theta_y}$') -plot(t, Ern(:,6), 'DisplayName', '$\epsilon_{\theta_z}$') -set(gca,'ColorOrderIndex',1); -plot(t_iff, Ern_iff(:,4), '--', 'DisplayName', '$\epsilon_{\theta_x}$ - IFF') -plot(t_iff, Ern_iff(:,5), '--', 'DisplayName', '$\epsilon_{\theta_y}$ - IFF') -plot(t_iff, Ern_iff(:,6), '--', 'DisplayName', '$\epsilon_{\theta_z}$ - IFF') -hold off; -xlim([1,inf]); +plot(t, En(:,1), 'DisplayName', '$\epsilon_{x}$') +plot(t, En_iff(:,1), 'DisplayName', '$\epsilon_{x}$ - IFF') +legend('location', 'southwest'); + +ax2 = subplot(3, 1, 2); +hold on; +plot(t, En(:,2), 'DisplayName', '$\epsilon_{y}$') +plot(t, En_iff(:,2), 'DisplayName', '$\epsilon_{y}$ - IFF') +legend('location', 'southwest'); +ylabel('Position Error [m]'); + +ax3 = subplot(3, 1, 3); +hold on; +plot(t, En(:,3), 'DisplayName', '$\epsilon_{z}$') +plot(t, En_iff(:,3), 'DisplayName', '$\epsilon_{z}$ - IFF') +legend('location', 'northwest'); +xlabel('Time [s]'); + +linkaxes([ax1,ax2,ax3],'x'); +xlim([0.5,inf]); + +figure; +ax1 = subplot(3, 1, 1); +hold on; +plot(t, En(:,4), 'DisplayName', '$\epsilon_{\theta_x}$') +plot(t, En_iff(:,4), 'DisplayName', '$\epsilon_{\theta_x}$ - IFF') +legend('location', 'northwest'); + +ax2 = subplot(3, 1, 2); +hold on; +plot(t, En(:,5), 'DisplayName', '$\epsilon_{\theta_y}$') +plot(t, En_iff(:,5), 'DisplayName', '$\epsilon_{\theta_y}$ - IFF') +legend('location', 'southwest'); +ylabel('Position Error [rad]'); + +ax3 = subplot(3, 1, 3); +hold on; +plot(t, En(:,6), 'DisplayName', '$\epsilon_{\theta_z}$') +plot(t, En_iff(:,6), 'DisplayName', '$\epsilon_{\theta_z}$ - IFF') legend(); +xlabel('Time [s]'); + +linkaxes([ax1,ax2,ax3],'x'); +xlim([0.5,inf]); diff --git a/active_damping/matlab/ine.m b/active_damping/matlab/ine.m index 4c6e624..6134903 100644 --- a/active_damping/matlab/ine.m +++ b/active_damping/matlab/ine.m @@ -4,9 +4,12 @@ clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); +addpath('active_damping/src/'); + open('active_damping/matlab/sim_nass_active_damping.slx') load('./active_damping/mat/undamped_plants.mat', 'G_ine'); +load('./active_damping/mat/plants_variable.mat', 'masses', 'Gm_ine'); freqs = logspace(0, 3, 1000); @@ -14,27 +17,29 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i=1:6 - plot(freqs, abs(squeeze(freqresp(G_ine(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, abs(squeeze(freqresp(Gm_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); +ylabel('Amplitude [(m/s)/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i=1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, 180/pi*angle(squeeze(freqresp(Gm_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz'))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); ylim([-180, 180]); yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); -K_ine = 1e3/(1+s/(2*pi*100)); +K_ine = 2.5e4; freqs = logspace(0, 3, 1000); @@ -42,23 +47,25 @@ figure; ax1 = subplot(2, 1, 1); hold on; -for i=1:6 - plot(freqs, abs(squeeze(freqresp(K_ine*G_ine(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, abs(squeeze(freqresp(K_ine*Gm_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); +ylabel('Loop Gain'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; -for i=1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(K_ine*G_ine(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i=1:length(masses) + plot(freqs, 180/pi*angle(squeeze(freqresp(K_ine*Gm_ine{i}('Vnlm1', 'Fnl1'), freqs, 'Hz'))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); ylim([-180, 180]); yticks([-180, -90, 0, 90, 180]); +legend('location', 'southwest'); linkaxes([ax1,ax2],'x'); @@ -66,198 +73,134 @@ K_ine = -K_ine*eye(6); save('./active_damping/mat/K_ine.mat', 'K_ine'); -initializeReferences(); -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); +prepareLinearizeIdentification(); -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_ine = -K_ine*eye(6); -save('./mat/controllers.mat', 'K_ine', '-append'); +load('./active_damping/mat/K_ine.mat', 'K_ine'); +initializeController('type', 'ine', 'K', K_ine); -G_ine = identifyPlant(); +%% Options for Linearized +options = linearizeOptions; +options.SampleTime = 0; -save('./active_damping/mat/plants.mat', 'G_ine', '-append'); +%% Name of the Simulink File +mdl = 'sim_nass_active_damping'; + +%% Input/Output definition +clear io; io_i = 1; +io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Compute Error in NASS base'], 2, 'openoutput'); io_i = io_i + 1; + +load('./active_damping/mat/cart_plants.mat', 'masses'); + +G_cart_ine = {zeros(length(masses))}; + +load('mat/stages.mat', 'nano_hexapod'); + +for i = 1:length(masses) + initializeSample('mass', masses(i)); + + %% Run the linearization + G = linearize(mdl, io, 0.3, options); + G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; + G.OutputName = {'Dnx', 'Dny', 'Dnz', 'Rnx', 'Rny', 'Rnz'}; + + G_cart = G*inv(nano_hexapod.J'); + G_cart.InputName = {'Fnx', 'Fny', 'Fnz', 'Mnx', 'Mny', 'Mnz'}; + + G_cart_ine(i) = {G_cart}; +end + +save('./active_damping/mat/cart_plants.mat', 'G_cart_dvf', '-append'); + +load('./active_damping/mat/cart_plants.mat', 'masses', 'G_cart', 'G_cart_ine'); freqs = logspace(0, 3, 1000); figure; -subplot(2, 1, 1); -title('$D_g$ to $D$'); +ax1 = subplot(2, 1, 1); hold on; -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dx', 'Dgx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / D_{g,x}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dy', 'Dgy'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / D_{g,y}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_gm('Dz', 'Dgz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / D_{g,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_ine.G_gm('Dx', 'Dgx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_gm('Dy', 'Dgy'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_gm('Dz', 'Dgz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/m]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); - -subplot(2, 1, 2); -title('$F_s$ to $D$'); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dx', 'Fsx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{s,x}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dy', 'Fsy'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / F_{s,y}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_fs('Dz', 'Fsz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{s,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_ine.G_fs('Dx', 'Fsx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_fs('Dy', 'Fsy'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_fs('Dz', 'Fsz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart_ine{i}('Dnx', 'Fnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart_ine{i}('Dny', 'Fny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart_ine{i}('Dnz', 'Fnz'), freqs, 'Hz'))), ':'); +end set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); +legend([p1,p2,p3], {'Fx/Dx', 'Fy/Dx', 'Fz/Dz'}); -freqs = logspace(0, 3, 1000); - -figure; +ax2 = subplot(2, 1, 2); hold on; -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dz', 'Frzz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{rz, z}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dz', 'Ftyz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{ty, z}\right|$'); -plot(freqs, abs(squeeze(freqresp(G.G_dist('Dx', 'Ftyx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{ty, x}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_ine.G_dist('Dz', 'Frzz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_dist('Dz', 'Ftyz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_dist('Dx', 'Ftyx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); -legend('location', 'northeast'); - -freqs = logspace(0, 3, 1000); - -figure; - -ax1 = subplot(2, 2, 1); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dx', 'Fnx'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dy', 'Fny'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Dz', 'Fnz'), freqs, 'Hz')))); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_ine.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_cart('Dy', 'Fny'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), '--'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); - -ax2 = subplot(2, 2, 2); -hold on; -plot(freqs, abs(squeeze(freqresp(G.G_cart('Rx', 'Mnx'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Ry', 'Mny'), freqs, 'Hz')))); -plot(freqs, abs(squeeze(freqresp(G.G_cart('Rz', 'Mnz'), freqs, 'Hz')))); -set(gca,'ColorOrderIndex',1); -plot(freqs, abs(squeeze(freqresp(G_ine.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_cart('Ry', 'Mny'), freqs, 'Hz'))), '--'); -plot(freqs, abs(squeeze(freqresp(G_ine.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), '--'); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [rad/(Nm)]'); xlabel('Frequency [Hz]'); - -ax3 = subplot(2, 2, 3); -hold on; -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), 'DisplayName', '$\left|D_x / F_{n,x}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dy', 'Fny'), freqs, 'Hz'))), 'DisplayName', '$\left|D_y / F_{n,y}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), 'DisplayName', '$\left|D_z / F_{n,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine.G_cart('Dx', 'Fnx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine.G_cart('Dy', 'Fny'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine.G_cart('Dz', 'Fnz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_ine{i}('Dnx', 'Fnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_ine{i}('Dny', 'Fny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_ine{i}('Dnz', 'Fnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); +end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); -ylim([-180, 180]); -yticks([-180, -90, 0, 90, 180]); -legend('location', 'northwest'); +yticks([-540:180:540]); +legend('location', 'northeast'); -ax4 = subplot(2, 2, 4); +linkaxes([ax1,ax2],'x'); + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); hold on; -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), 'DisplayName', '$\left|R_x / M_{n,x}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Ry', 'Mny'), freqs, 'Hz'))), 'DisplayName', '$\left|R_y / M_{n,y}\right|$'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), 'DisplayName', '$\left|R_z / M_{n,z}\right|$'); -set(gca,'ColorOrderIndex',1); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine.G_cart('Rx', 'Mnx'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine.G_cart('Ry', 'Mny'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); -plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine.G_cart('Rz', 'Mnz'), freqs, 'Hz'))), '--', 'HandleVisibility', 'off'); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart_ine{i}('Rnx', 'Mnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart_ine{i}('Rny', 'Mny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart_ine{i}('Rnz', 'Mnz'), freqs, 'Hz'))), ':'); +end +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); +legend([p1,p2,p3], {'Fx/Dx', 'Fy/Dx', 'Fz/Dz'}); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_ine{i}('Rnx', 'Mnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_ine{i}('Rny', 'Mny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart_ine{i}('Rnz', 'Mnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); +end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); -ylim([-180, 180]); -yticks([-180, -90, 0, 90, 180]); -legend('location', 'northwest'); +yticks([-540:180:540]); +legend('location', 'northeast'); -linkaxes([ax1,ax2,ax3,ax4],'x'); +linkaxes([ax1,ax2],'x'); -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); - -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); - -initializeReferences('Rz_type', 'rotating', 'Rz_period', 1); - -initDisturbances(); - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = K_ine; -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); - -load('mat/conf_simscape.mat'); -set_param(conf_simscape, 'StopTime', '3'); - -sim('sim_nass_active_damping'); - -t_ine = t; -Ern_ine = Ern; -save('./active_damping/mat/tomo_exp.mat', 'Ern_ine', 't_ine', '-append'); - -load('./active_damping/mat/tomo_exp.mat', 'Ern', 'Ern_ine', 't', 't_ine'); +freqs = logspace(1, 3, 1000); figure; -hold on; -plot(t, Ern(:,1), 'DisplayName', '$\epsilon_{x}$') -plot(t, Ern(:,2), 'DisplayName', '$\epsilon_{y}$') -plot(t, Ern(:,3), 'DisplayName', '$\epsilon_{z}$') -set(gca,'ColorOrderIndex',1); -plot(t_ine, Ern_ine(:,1), '--', 'DisplayName', '$\epsilon_{x}$ - Inertial') -plot(t_ine, Ern_ine(:,2), '--', 'DisplayName', '$\epsilon_{y}$ - Inertial') -plot(t_ine, Ern_ine(:,3), '--', 'DisplayName', '$\epsilon_{z}$ - Inertial') -hold off; -xlim([1,inf]); -legend(); -figure; -hold on; -plot(t, Ern(:,4), 'DisplayName', '$\epsilon_{\theta_x}$') -plot(t, Ern(:,5), 'DisplayName', '$\epsilon_{\theta_y}$') -plot(t, Ern(:,6), 'DisplayName', '$\epsilon_{\theta_z}$') -set(gca,'ColorOrderIndex',1); -plot(t_ine, Ern_ine(:,4), '--', 'DisplayName', '$\epsilon_{\theta_x}$ - Inertial') -plot(t_ine, Ern_ine(:,5), '--', 'DisplayName', '$\epsilon_{\theta_y}$ - Inertial') -plot(t_ine, Ern_ine(:,6), '--', 'DisplayName', '$\epsilon_{\theta_z}$ - Inertial') -hold off; -xlim([1,inf]); -legend(); +for ix = 1:6 + for iy = 1:6 + subplot(6, 6, (ix-1)*6 + iy); + hold on; + plot(freqs, abs(squeeze(freqresp(G_cart{1}(ix, iy), freqs, 'Hz'))), 'k-'); + plot(freqs, abs(squeeze(freqresp(G_cart_ine{1}(ix, iy), freqs, 'Hz'))), 'k--'); + set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); + ylim([1e-13, 1e-4]); + xticks([]) + yticks([]) + end +end diff --git a/active_damping/matlab/undamped_system.m b/active_damping/matlab/undamped_system.m index e49889d..32c176d 100644 --- a/active_damping/matlab/undamped_system.m +++ b/active_damping/matlab/undamped_system.m @@ -4,30 +4,11 @@ clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); +addpath('active_damping/src/'); + open('active_damping/matlab/sim_nass_active_damping.slx') -initializeGround(); -initializeGranite(); -initializeTy(); -initializeRy(); -initializeRz(); -initializeMicroHexapod(); -initializeAxisc(); -initializeMirror(); - -initializeNanoHexapod('actuator', 'piezo'); -initializeSample('mass', 50); - -initializeReferences(); - -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); +prepareLinearizeIdentification(); %% Options for Linearized options = linearizeOptions; @@ -38,13 +19,13 @@ mdl = 'sim_nass_active_damping'; %% Input/Output definition clear io; io_i = 1; -io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs +io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Dnlm'); io_i = io_i + 1; % Relative Motion Outputs +io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Fnlm'); io_i = io_i + 1; % Force Sensors +io(io_i) = linio([mdl, '/Micro-Station'], 3, 'openoutput', [], 'Vlm'); io_i = io_i + 1; % Absolute Velocity Outputs %% Run the linearization -G = linearize(mdl, io, options); +G = linearize(mdl, io, 0.5, options); G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; G.OutputName = {'Dnlm1', 'Dnlm2', 'Dnlm3', 'Dnlm4', 'Dnlm5', 'Dnlm6', ... 'Fnlm1', 'Fnlm2', 'Fnlm3', 'Fnlm4', 'Fnlm5', 'Fnlm6', ... @@ -56,6 +37,8 @@ G_ine = minreal(G({'Vnlm1', 'Vnlm2', 'Vnlm3', 'Vnlm4', 'Vnlm5', 'Vnlm6'}, {'Fnl1 save('./active_damping/mat/undamped_plants.mat', 'G_iff', 'G_dvf', 'G_ine'); +load('./active_damping/mat/undamped_plants.mat', 'G_iff', 'G_dvf', 'G_ine'); + freqs = logspace(0, 3, 1000); figure; @@ -63,7 +46,33 @@ figure; ax1 = subplot(2, 1, 1); hold on; for i = 1:6 - plot(freqs, abs(squeeze(freqresp(G(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); + plot(freqs, abs(squeeze(freqresp(G_iff(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:6 + plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); +ylim([-180, 180]); +yticks([-180, -90, 0, 90, 180]); + +linkaxes([ax1,ax2],'x'); + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); +hold on; +for i = 1:6 + plot(freqs, abs(squeeze(freqresp(G_dvf(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); @@ -72,7 +81,7 @@ ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; for i = 1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(G(['Fnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); + plot(freqs, 180/pi*angle(squeeze(freqresp(G_dvf(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); @@ -89,16 +98,16 @@ figure; ax1 = subplot(2, 1, 1); hold on; for i = 1:6 - plot(freqs, abs(squeeze(freqresp(G(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); + plot(freqs, abs(squeeze(freqresp(G_ine(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); +ylabel('Amplitude [$\frac{m/s}{N}$]'); set(gca, 'XTickLabel',[]); ax2 = subplot(2, 1, 2); hold on; for i = 1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(G(['Dnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); + plot(freqs, 180/pi*angle(squeeze(freqresp(G_ine(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); @@ -108,59 +117,169 @@ yticks([-180, -90, 0, 90, 180]); linkaxes([ax1,ax2],'x'); +prepareLinearizeIdentification(); + +%% Options for Linearized +options = linearizeOptions; +options.SampleTime = 0; + +%% Name of the Simulink File +mdl = 'sim_nass_active_damping'; + +%% Input/Output definition +clear io; io_i = 1; +io(io_i) = linio([mdl, '/Fnl'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs +io(io_i) = linio([mdl, '/Compute Error in NASS base'], 2, 'openoutput'); io_i = io_i + 1; % Metrology Outputs + +masses = [1, 10, 50]; % [kg] + +G_cart = {zeros(length(masses))}; + +load('mat/stages.mat', 'nano_hexapod'); + +for i = 1:length(masses) + initializeSample('mass', masses(i)); + + %% Run the linearization + G = linearize(mdl, io, 0.3, options); + G.InputName = {'Fnl1', 'Fnl2', 'Fnl3', 'Fnl4', 'Fnl5', 'Fnl6'}; + G.OutputName = {'Dnx', 'Dny', 'Dnz', 'Rnx', 'Rny', 'Rnz'}; + + G_cart_i = G*inv(nano_hexapod.J'); + G_cart_i.InputName = {'Fnx', 'Fny', 'Fnz', 'Mnx', 'Mny', 'Mnz'}; + + G_cart(i) = {G_cart_i}; +end + +save('./active_damping/mat/cart_plants.mat', 'G_cart', 'masses'); + +load('./active_damping/mat/cart_plants.mat', 'G_cart', 'masses'); + +freqs = logspace(0, 3, 1000); + +figure; + +ax1 = subplot(2, 1, 1); +hold on; +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart{i}('Dnx', 'Fnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart{i}('Dny', 'Fny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart{i}('Dnz', 'Fnz'), freqs, 'Hz'))), ':'); +end +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); +legend([p1,p2,p3], {'Fx/Dx', 'Fy/Dx', 'Fz/Dz'}); + +ax2 = subplot(2, 1, 2); +hold on; +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart{i}('Dnx', 'Fnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart{i}('Dny', 'Fny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart{i}('Dnz', 'Fnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); +yticks([-540:180:540]); +legend('location', 'northeast'); + +linkaxes([ax1,ax2],'x'); + freqs = logspace(0, 3, 1000); figure; ax1 = subplot(2, 1, 1); hold on; -for i = 1:6 - plot(freqs, abs(squeeze(freqresp(G(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + p1 = plot(freqs, abs(squeeze(freqresp(G_cart{i}('Rnx', 'Mnx'), freqs, 'Hz')))); + set(gca,'ColorOrderIndex',i); + p2 = plot(freqs, abs(squeeze(freqresp(G_cart{i}('Rny', 'Mny'), freqs, 'Hz'))), '--'); + set(gca,'ColorOrderIndex',i); + p3 = plot(freqs, abs(squeeze(freqresp(G_cart{i}('Rnz', 'Mnz'), freqs, 'Hz'))), ':'); end -hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [(m/s)/N]'); set(gca, 'XTickLabel',[]); +ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); +legend([p1,p2,p3], {'Rx/Mx', 'Ry/Mx', 'Rz/Mz'}); ax2 = subplot(2, 1, 2); hold on; -for i = 1:6 - plot(freqs, 180/pi*angle(squeeze(freqresp(G(['Vnlm', num2str(i)], ['Fnl', num2str(i)]), freqs, 'Hz')))); +for i = 1:length(masses) + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart{i}('Rnx', 'Mnx'), freqs, 'Hz')))), ... + 'DisplayName', sprintf('$M = %.0f$ [kg]', masses(i))); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart{i}('Rny', 'Mny'), freqs, 'Hz')))), '--', 'HandleVisibility', 'off'); + set(gca,'ColorOrderIndex',i); + plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G_cart{i}('Rnz', 'Mnz'), freqs, 'Hz')))), ':', 'HandleVisibility', 'off'); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); ylabel('Phase [deg]'); xlabel('Frequency [Hz]'); -ylim([-180, 180]); -yticks([-180, -90, 0, 90, 180]); +yticks([-540:180:540]); +legend('location', 'northeast'); linkaxes([ax1,ax2],'x'); -initDisturbances(); +prepareTomographyExperiment(); -initializeReferences('Rz_type', 'rotating', 'Rz_period', 1); - -load('mat/conf_simscape.mat'); -set_param(conf_simscape, 'StopTime', '3'); +load('mat/conf_simulink.mat'); +set_param(conf_simulink, 'StopTime', '4.5'); sim('sim_nass_active_damping'); -save('./active_damping/mat/tomo_exp.mat', 'Ern', 't'); +save('./active_damping/mat/tomo_exp.mat', 'En', 'Eg', '-append'); + +load('./active_damping/mat/tomo_exp.mat', 'En'); +Fs = 1e3; % Sampling Frequency of the Data +t = (1/Fs)*[0:length(En(:,1))-1]; figure; +ax1 = subplot(3, 1, 1); hold on; -plot(t, Ern(:,1), 'DisplayName', '$\epsilon_{x}$') -plot(t, Ern(:,2), 'DisplayName', '$\epsilon_{y}$') -plot(t, Ern(:,3), 'DisplayName', '$\epsilon_{z}$') -hold off; -xlim([1,inf]); -legend(); -xlabel('Time [s]'); ylabel('Position Error [m]'); +plot(t, En(:,1), 'DisplayName', '$\epsilon_{x}$') +legend('location', 'southwest'); + +ax2 = subplot(3, 1, 2); +hold on; +plot(t, En(:,2), 'DisplayName', '$\epsilon_{y}$') +legend('location', 'southwest'); +ylabel('Position Error [m]'); + +ax3 = subplot(3, 1, 3); +hold on; +plot(t, En(:,3), 'DisplayName', '$\epsilon_{z}$') +legend('location', 'northwest'); +xlabel('Time [s]'); + +linkaxes([ax1,ax2,ax3],'x'); +xlim([0.5,inf]); figure; +ax1 = subplot(3, 1, 1); hold on; -plot(t, Ern(:,4), 'DisplayName', '$\epsilon_{\theta_x}$') -plot(t, Ern(:,5), 'DisplayName', '$\epsilon_{\theta_y}$') -plot(t, Ern(:,6), 'DisplayName', '$\epsilon_{\theta_z}$') -hold off; -xlim([1,inf]); +plot(t, En(:,4), 'DisplayName', '$\epsilon_{\theta_x}$') +legend('location', 'northwest'); + +ax2 = subplot(3, 1, 2); +hold on; +plot(t, En(:,5), 'DisplayName', '$\epsilon_{\theta_y}$') +legend('location', 'southwest'); +ylabel('Position Error [rad]'); + +ax3 = subplot(3, 1, 3); +hold on; +plot(t, En(:,6), 'DisplayName', '$\epsilon_{\theta_z}$') legend(); -xlabel('Time [s]'); ylabel('Position Error [rad]'); +xlabel('Time [s]'); + +linkaxes([ax1,ax2,ax3],'x'); +xlim([0.5,inf]); diff --git a/active_damping/src/prepareLinearizeIdentification.m b/active_damping/src/prepareLinearizeIdentification.m index 9b3e555..3488e7f 100644 --- a/active_damping/src/prepareLinearizeIdentification.m +++ b/active_damping/src/prepareLinearizeIdentification.m @@ -20,11 +20,8 @@ initializeSample('mass', args.sample_mass); initializeReferences(); initializeDisturbances('enable', false); -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); +initializeController('type', 'open-loop'); + +initializeSimscapeConfiguration('gravity', true); + +initializeLoggingConfiguration('log', 'none'); diff --git a/active_damping/src/prepareTomographyExperiment.m b/active_damping/src/prepareTomographyExperiment.m index 7a65466..441044d 100644 --- a/active_damping/src/prepareTomographyExperiment.m +++ b/active_damping/src/prepareTomographyExperiment.m @@ -22,11 +22,8 @@ initializeReferences('Rz_type', 'rotating', 'Rz_period', args.Rz_period); initializeDisturbances(); -K = tf(zeros(6)); -save('./mat/controllers.mat', 'K', '-append'); -K_ine = tf(zeros(6)); -save('./mat/controllers.mat', 'K_ine', '-append'); -K_iff = tf(zeros(6)); -save('./mat/controllers.mat', 'K_iff', '-append'); -K_dvf = tf(zeros(6)); -save('./mat/controllers.mat', 'K_dvf', '-append'); +initializeController('type', 'open-loop'); + +initializeSimscapeConfiguration('gravity', true); + +initializeLoggingConfiguration('log', 'all'); diff --git a/disturbances/index.org b/disturbances/index.org index a9c4023..9da2f92 100644 --- a/disturbances/index.org +++ b/disturbances/index.org @@ -203,8 +203,8 @@ Also, we measure the absolute displacement of the granite and of the top platfor We load the configuration and we set a small =StopTime=. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '0.5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '0.5'); #+end_src We initialize all the stages. diff --git a/experiment_tomography/index.org b/experiment_tomography/index.org index c6b4932..c83d6ce 100644 --- a/experiment_tomography/index.org +++ b/experiment_tomography/index.org @@ -79,8 +79,8 @@ The simulink file to do tomography experiments is =sim_nano_station_tomo.slx=. We load the shared simulink configuration and we set the =StopTime=. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '5'); #+end_src We first initialize all the stages. diff --git a/experiment_tomography/matlab/tomo_exp.m b/experiment_tomography/matlab/tomo_exp.m index a6df3dd..aa2ca64 100644 --- a/experiment_tomography/matlab/tomo_exp.m +++ b/experiment_tomography/matlab/tomo_exp.m @@ -15,8 +15,8 @@ open('experiment_tomography/matlab/sim_nano_station_tomo.slx') % We load the shared simulink configuration and we set the =StopTime=. -load('mat/conf_simscape.mat'); -set_param(conf_simscape, 'StopTime', '5'); +load('mat/conf_simulink.mat'); +set_param(conf_simulink, 'StopTime', '5'); diff --git a/hac_lac/index.org b/hac_lac/index.org index e4f3f5a..c45b262 100644 --- a/hac_lac/index.org +++ b/hac_lac/index.org @@ -95,14 +95,7 @@ We set the references to zero. And all the controllers are set to 0. #+begin_src matlab - K = tf(zeros(6)); - save('./mat/controllers.mat', 'K', '-append'); - K_ine = tf(zeros(6)); - save('./mat/controllers.mat', 'K_ine', '-append'); - K_iff = tf(zeros(6)); - save('./mat/controllers.mat', 'K_iff', '-append'); - K_dvf = tf(zeros(6)); - save('./mat/controllers.mat', 'K_dvf', '-append'); + initializeController('type', 'open-loop'); #+end_src *** Identification @@ -330,8 +323,8 @@ We initialize elements for the tomography experiment. We change the simulation stop time. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '3'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '3'); #+end_src And we simulate the system. @@ -423,14 +416,7 @@ We set the references to zero. And all the controllers are set to 0. #+begin_src matlab - K = tf(zeros(6)); - save('./mat/controllers.mat', 'K', '-append'); - K_ine = tf(zeros(6)); - save('./mat/controllers.mat', 'K_ine', '-append'); - K_iff = tf(zeros(6)); - save('./mat/controllers.mat', 'K_iff', '-append'); - K_dvf = tf(zeros(6)); - save('./mat/controllers.mat', 'K_dvf', '-append'); + initializeController('type', 'open-loop'); #+end_src *** Identification diff --git a/identification/index.org b/identification/index.org index 97dfc23..fdc4c6a 100644 --- a/identification/index.org +++ b/identification/index.org @@ -74,8 +74,8 @@ The simulink file for the identification is =sim_micro_station_id.slx=. We load the configuration and we set a small =StopTime=. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '0.5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '0.5'); #+end_src We initialize all the stages. @@ -159,8 +159,8 @@ The simulink file for the analysis is =sim_micro_station_modal_analysis.slx=. We load the configuration and we set a small =StopTime=. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '0.5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '0.5'); #+end_src We initialize all the stages. @@ -279,12 +279,12 @@ Some of the springs and dampers values can be estimated from the joints/stages s We load the configuration. #+begin_src matlab - load('mat/conf_simscape.mat'); + load('mat/conf_simulink.mat'); #+end_src We set a small =StopTime=. #+begin_src matlab - set_param(conf_simscape, 'StopTime', '0.5'); + set_param(conf_simulink, 'StopTime', '0.5'); #+end_src We initialize all the stages. diff --git a/kinematics/index.org b/kinematics/index.org index b78a493..3c755ef 100644 --- a/kinematics/index.org +++ b/kinematics/index.org @@ -152,8 +152,8 @@ We open the Simulink file. We load the configuration and set a small =StopTime=. #+begin_src matlab - load('mat/conf_simscape.mat'); - set_param(conf_simscape, 'StopTime', '0.5'); + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '0.5'); #+end_src We define the wanted position/orientation of the Hexapod under study. diff --git a/positioning_error/index.org b/positioning_error/index.org index 2f819a2..2efbb39 100644 --- a/positioning_error/index.org +++ b/positioning_error/index.org @@ -89,7 +89,7 @@ The goal here is to perfectly move the station and verify that there is no misma ** Prepare the Simulation We set a small =StopTime=. #+begin_src matlab - set_param(conf_simscape, 'StopTime', '0.5'); + set_param(conf_simulink, 'StopTime', '0.5'); #+end_src We initialize all the stages. @@ -232,12 +232,12 @@ We want to verify that we are able to measure this positioning error and convert ** Prepare the Simulation We load the configuration. #+begin_src matlab - load('mat/conf_simscape.mat'); + load('mat/conf_simulink.mat'); #+end_src We set a small =StopTime=. #+begin_src matlab - set_param(conf_simscape, 'StopTime', '0.5'); + set_param(conf_simulink, 'StopTime', '0.5'); #+end_src We initialize all the stages. diff --git a/simscape/nass_model.slx b/simscape/nass_model.slx new file mode 100644 index 0000000000000000000000000000000000000000..018390b5240903e0b70c122dc28bc5d4287a0e29 GIT binary patch literal 116382 zcmaI6Q

wx2652ZQHi(N?Vn-ZQHhO+jgaGJ1cEF|N2gkfAl%sWAx3w*jGE|GuPS? zv8IAF2q-E50DuI1XelY+=|ojL0|5YZ&;S6+zqeWgB;EvC*MKZNzC|<0>hzg8R z?wcd$eT->uq1l3`xLKQ()$52B7Sg7G^n@ZVx7|N;9ju5mIU{XioVhcMfLbEQt#Rz6 zPb!vbb~2b{Yjdf(+16^;b7Ae}B;gZ+FUQ06tfO^ljq#VoP^ixaagaYj^SA981I~ZP zJXOVmRalWtQ!ffXS+-hHzeU8ZO9zN|9IqUXd2Bo>9z@-My}CnWRx-vQf&S93v7bL{ z^fT;xZi>>u6BVolF~iMgr<5!D4pul(S3F5|_-AT}tp7GTyD zzlo&PEhuYwtEAR#Y)bFC3)Cfut&v~GI<|UT$@YOL{12O?c2162{IiJ}7ytnC&n9|~ zCe}_2^#6I5Bu~l>F(Qikk=^$?AR_`VHD?7bfguOp11%b7sz(qs>TG=T!H2UWw4EDe zXwUYDyCKJwY3V}jmcu0xlR01}07S{1$Rm@z>2$^8NEy+8!MC8MC*olv%TOF5R1b7w zDKnb@n-R-MNm(tkl#tUT1VNPu?TmjBv+%o*GSoX%w`AS^YeYOon8nD0T*550Dp78dq7ep7_e ze?n%0P;)4$kx!A9eVma-7UBPK2-`R?uAgi@WXe2(%}lEio!=r^)rS*cs(WJU?P7V|!VMgV`VK_jUz8k7^%#=i zc{x0S_}@f6{}rw~KW@75KO#NA007QEA~q(@2F3=?1`I}ajwT9@cJ?NY&K4$4|0!S} zrT-%InKJhB$5l!(JW&OB2_*#)G@u>JYg6oxt8o_pt7kSvNoD&w%i;R^lW9~?br2q= zmPHB)HWI4;fu@ROQc;>C7CB{oEY*Nz4WYPrJ*7G-mYq^99542^zXRG@KMqyaJ-N8n zNhYe%WE){dOt-LyV@-_ljNUXjN3>rf++KRT73~1i0PawY!J160c|EFkqjj&$HWp-T z0XWozh73uhUrVFoC^&sD<~T|V2+5VG!>G(eP!0LAZ(rPVlibOJ@@K23`?V$<&2nrc z$oa_-u5~jPx)Mw|i#N21$XPPZZ91fPKr;eAb6r!{hhs!!`Wz{#8W9_}9<3sL# z(@Twk-%2SZm^GHSNL6M(yW(`U)?1&B8li1m$fo6wfKEM&X(R>2<*qjqlqBv#@#DTJ zYtF3veGIsc4@g&~PII8xL$GTIMfu+_KH6OGSq=g`0pYLLZ)@$l|5h&lfm0{fp*!*q ziugZ3c>f)ajobf?$0Tmj7MKb4Uja?@qUeiO$*eULRZ@NdlGJ5bBT$C-nf&C@X-!WT zQfKdaJYT|vw(9HUmnL1>5`o9bPtF!5`xd{AXu#A6A&8Kk9fea3&78Y8Rc_0Qqf0!E z=XwA1;95@WNj2ax0=prd+sm6A&6JiiuOZQwvsXQd(Ro-j%c>-tTTGY}p6t;rrAlp& zP4iwJvbke-rQ?Fv94~1%FyN1eoZ%2>?qZO_|Ktzn*!lry$6+F3PB(yk@mjTPwZ7GK zdjS7WcQ#bBiuL?kIOsnC$p2pgh`Rs#+c;U++5X3lMptYA9 zq6gn%+OS5XOo^XkyJ3G)l=Jv_te)jLl6Xc~!FH8~$;eJ^PAU8>&Q3-X*piE3d&9Wg ztTsp-?pV_*<*c$?Qg}_7#S4wsN zAk0R8a|G7fj=qctLYteU5S2nIKiFL;vyJo%1t*XOn!dI)r7^mRUE}9gnZ%en} z(Jm_Xecd9g)l>?uQ3!HI8T$NtMl>x>lLqX=yP95`6*)HdaD;=iG4*dEkg%nbOWi|C z)lL~WAOk3d&YCOr0*v!k#E?N<{Ev!gnW-T|)3X#gj3UB2LMEIEKl5$)mvkT1@L51# z|3JR9iZF@|8X67u+hsYy{#;c3{cmH$kKGf3|0x26IO$6l1^{q?2>_t~cM+V;U2F_( z4J@qb?QPA5-A&Y!{MMe$Nz3{r3@8u&1h8^*qq!tILxzXT2nu$Rh0N1QkT3;HlHd^& z!XX!tlTDwR^1l3heE9n0;#C=qer?ur);;jng;-hemX_`30|f{^p3AE^`>$UA;4dZj zJ5?BHkl#8^-$l$rAchwo_d!Ig$uy%t{z)ybEiAvdGqGxY;XC<-vJ6kuO7hoC%Ct~N z{xfHETpP!M8ryt~kDGs!kl*Wy8ak6YMBV+D#;|4v@CBI>SWN?roQu?$Rl1ABrww=q zw-B)}v&X(gc8{Vc(sEB33_&g|?Q;gyN!7@>{Tb!x-}k#_@G*N>`(Yhe-p04p(OS-Z zPZrKr;2j3g1G*Se)xy$3NN|=pg$GBbpcMSU{DD|a=%t5spgmVnC&_V?%kc)5V~k@pB08;cFmefeTwmMzZct14P#kRqr<7=8fwR-s*9`c;u@{R zmQ}35&^z~$LB(0E1vX9|cKlq35pm9}>g?|B?oPlqQ|alX^zI(~67++}D`Ykldh$%QJ(BBU}rdd-4iE z4Gj%w4!_#8b&zq9u;ih|FSc4aac`#|Jv|@j!*Qblh$J0_fr3h2PhC)`L(PAe&+_}~ zyS=BjwzPd}4k%o?Uyz*o7XLmEgoc769Gpd(v@n&)DH@bwOiNqS-LU%c|6wa~@-Y&r z4uAm_jtvwfKoiWrgkz9))$$`G-AlHtOG{gwTU%5Ajyady>}X{d<;0!w9M?#E2_c(j*|HL?5OF{fpViHBTE7Cs@(b*#bPLf+@VVD>n8VO$0ebq|2A_XO6{9* z%F~mTmBkFmR|GZNbY#t=%|Ar=JM-I4AcDefV03DBHjLa?hnx(o$Nf%Nx(<64N;FbR z5-Z!iv#SXl3``@5EB9Jsh=4af(1|LaD((9lETpO#VcE;eYY}GtMMhqp#>$epGhJ~w z)%xi{v>V%X*w$vfZbcjeV;6^SVaJkg{dVD*p_!D4nbjJPAndlHt*tdsdulL$sbS?( za8;fj>iZbqgGu*9tA#iYKLlYS$4~18#yY6?QQP$Gx8_D@WV8uE6IlQs)- z_brq>x8!;!I|K9c!n)DgU91InqRT5Ny@FKT2qlY|-+VL;KNUv!FVQN`_Ay1ZikiBG(kI&IBHLH z*WW#y+YD=+IR#Ang=vzN#?|CA^Bv89AV|v!@pwC*S;8Zca2G?4tRJ~=Cq>Xgs<07m z5#7qif>4EOC@2tsUNPI*B)jaiyk8YEjBGxV`7uZc-`_gYag+{827b=9pP*^JPg;8T z_yCl`i%c)laURfr&x|h!z`Au~Wq#l%F(*gT-e zf5zogOFdSdpZy<4J;ILPUpW<;r(~`@lh*z$Ps_eiaRf%~i%x!7hC2UF{Bx2~^AYs@ zt5gSpK1_4wy%B!!&IVFbF>AefzUXu3?qm5q?Zaw;L>D*icVAy}Jhk6h(`H3#J111o zw+JB=d*F)1H>j#{&I4fxDU zqL_j9503MF+`3Kl^mL)UT3dt9*7qw&Qho-x-O9tm!%{QruZ}hWM$*}t>n@aIP`~_; z^;7hfQK?5uf+Su`!5rIE1^vs@!@LI`o!k!Bqn;E&@D!Wit!HxNlb8S6UsaiH1w%WS0B2R590N7&meelV$l=QwmjITd zinTzz9x(S?T(iFOF8ANQWzsOR&x@atm!Cz_hDaNz4b zwO626L3lZ(g%m@G=O2f4PVDuBK^oq*bWW7q587j1c>c!z-CZHn zH*7lXRA!Z}f@(TCEhow0@$vKXAZsoqS3D73D*Y4x8-n(Lkohp8Tm?QtO#9QtYMpw_ zV4}mVdZ9a)WqVeRL*EJqaT>Q3V|9gOYmr{;@nT%FhyaJ$D*GVQg>||}OT*&xRGj-N z&$$$UT}^FQvll+cr5~H1M6xcW*U>46*X!B(x2CRU+en-a zH}B_E;EK^N3O7V4X)wtT;)}|mghNb_PfPA&7eQ7g*hWU5>+5thzoe}Lv-c;k>9wy5-vwtI%@zMF@Uj84?=UoQ%Hq2#?&&cw#a;G7rxvOt8P-5H zCfb_f?{ib;h(ch(YTwr-{Ca~U-dSCF`J98?C6|CkG*w+~DdfeRYl@t_d|H0p{)dT~ z-7Jg{kL;)YwtqMY4?Vpxu&K(9mWD=2X_;Gg4$;=uR-*yZune7K(YDa@Yor94eHpI z#M-b`HS})VbJ!y1<%ZCtz-j> z@RbegJpyhfweh35zZw7i^5FKA^SDgZPflNQ7fh+|bQ1abuMF0CLNnMtKHd3X7_+uN zUOWW5v9Pd+LWDo2n~gGZ+p(d}#nb9yg1hNaUu~ORf|;(LBjCt0Tb5QDkIm8G*1y>G zKBWiJc5Y-4>o5Ki&K}E;lw7@A@cQMx4!5sgDD1UE*P0kQC+#yahx2`jU83}=nF-{i z8;L`#YI7nkdhU1BU#}LjaD6U^Zv#@aRs&c&*bDUyif3$TEhaibYemn)qy2nG`^Y94 zJ~bT&G4yakfa7bpQN>f;N5a-67rw*h`*6E0jb>t1IlIoQ{W#XwG_|zQMhZU}T)Pb4 zYJrrdM`m`!NGCF&8-Pd4+Jt$IcfVsz1oLaM#1TH*I~40C;4Z}GM{bYwOjTNqx@I%} z9o6dWn*%gmYPQL#gs1L)-}vTu)xsM8(GmuF&!l8Q;ki`;HDV~d(E^GOlZd} z2h0=zA4sAVpT{a8CwkJI2t@bLyZ#X9!$%E{9vy$ydCPkr=_3Vnb;%{n&$lJ!lD|#3 zWTCvM1Bog42LcFKLZ7O1>k^wB=sQdOKaX2+o^~kY*Cesv6~&AJ1u&978o;<^`;%$H z3DC)yej`9UxqA%0X!bOAc5;M^h*pCB02+fZp6EgpZ_@aJgyrO+pOdokjq8R;Nx>WL-pDEyq$#1);hqDvvX(i;Eah0td}` ztmKRhR}`*arkPSmR)mq>uIyFuv(#Q4LyTxwd44~dQ&9?*sIl;0&XFgFe`5{Mwq7i$ zegrX&9etVTW}modz>hJMOq4M#p8d_FZl39Q7>cuzO-(>klGwdt ztxM|edJh9Odn%{kwE&<8G~Du_4CPkYmyQ=u4pLBKMPG-Di#ccRY$+C+pU~IkRbwxM zY+FgVbj@aXTD_){aPFAmu14d97&Zy>h&dotS7-u}9c zSUddbqD-@oc{2+_Synn_Yd;gY|9U_`eSZmOeuhJkH$pZs(#Tu@Uo9Z0$9fM6OoR|M zyg`91|jX z@kIU1f#ULbHZPh!VM?w%HFMb2+OsCDNc_bCFN{JAyY{cKxhf|v{_G*@nwb2h_=H+Y z76N-VycaWFJQ|?94U0ZH^bw~f*1u5EswURRRFj|gD6>;y!sN>(RY>7x1h4FiiH_N9 zYYTCH;tmV#AOCmU*~WG!u>}Hu<8M_QO zG5ZN`NVupeCcKv44g?O*kl=u+MHB}&U?k!b@xsHa+&Ex4_x`HX&@^sxku!FX9|Lmn zyjL|Ft+H^mm6LsJf=0zY9r@uEEd^no}@QXDU*|vk4)t!DLFCk=m?cTwwC`f z8OnV|yd>iSY6Tut)x2oM3yXgY21Co_R>BCgyxcV>2#ud2v6=Eh8qhXEOgtbF5jt(a z%R#n;J%H)0fzpZpYrQw3k4~-`j?B>0Myk6c_k-_F#tA~?VT?0GhXZ+|qobwlJw`@h z`dxB=B#-3}TxEA525d+tU}k0pw2&-dVdTv}Z5Q=x!S`Kzd~$xtnoI78(L1P9^{Nm=JkGdhc+hZB2vmLmV_a;;?y_B zjhFSaUW#iipla-WfyC_lQ!crcr{`gO(mX|rpaQdl&fDA6mHnL~DA;da@hA>aX9_>c zDfp2-O1Iu1Pp%FHQm5>L=AjGU*|f&Hq+}CF+cybLC(5Q@?71@g>h~6k4IRQmS;~CX zK6M8rd9%c+)w~sx4#RVCLQ%t)9j#T_=Gq_a`^Vnjh^?)(H8oU6jhF#ldN96;X6em7 zx@*(hcs)M1-S$gHJ?)Ishz|%Pa3v)rVBjRivVoT*=I|1P?MD1*eN7?m;Wg!WWw1)1 zuAM=LMnM`N&zGQ6w-f>xGR z(zsIU!F~Y&RLLo9PU{x8efL$r;x5p`(}HNVbu^9`jop9JHE9gViba!CR3YM=bq`;n9bv!h7m%DP@pZ+=sewt`maY=boC|?5& z3~9HtMUitXX6u{$_3=H#5XD!8F&PA^h*J)UC*Xvb=xHvAK{RmJ0`>5q}X+43Nm!^F7-HFBqr9p<2nWbGn@)a!*uiOTkH>EAJo=&*iO zL1^u4U66*5ac6WITI5a;jbQ@r{n*ScmP<$M;0@Fe>`P1^CTG#bWM?cbJ9*@pQFDWEe(arclAh1dY36fwF8QV; zNLwZe_n}LosPZO@Y+Ut`3*ni2&xxPfA79a2p_x^@A{(w?sC(m~0>HpDA@L8k3W@LmoPl32D88Jy&LfH5wbalRqO6l^8 zDPObtDJ$vueSYA7-^uBOj%Hoy93>S&+&?zMHYBhxGQ2CY*TPP_F7Z>HhQ6R()%y>E zdJUWDDfsv6CF!**5fmZpTEyGuJPDx8y))}WEVuZTWR_jcvzmz#(mEFk z0rhA4HQ3G(--c5qq!3+xZwbhCTgz-dM?*c6i}er(3KPf{wO43Uk_``J>CT$78_LXUF(FBES4y@gS8$ zPlLEr@+=jm#WJxz-7_+S0qslrHyG$Kg?bA~!oo(lp0u4z|- z6WG6>34bZD6Jmr$_3YlRcff>zQF9hvpLk+V~erYuef!YV0+gth{GzLYX_5Z zF2gE*Arf>;n>I&Lzd-Xz0$U5I)-U0d?40DPjkfMNQET0^{BfDyt%_~GgaaibTfUxu z{D>XasYQOk?r-LA#-j%@K0g#k*8lhA!+GWWy)tJPI)oVvg<9uSyrEqUN? z^Qjpvr1GPxO=eM<@k@VubJ`pj2tdK+0LFC_`b8xe=Ik95-2wf9&2@h`CM4Tr>zZXJ z?~BuoSJ0gU4zwzlwH$I?3xCpMFz&=DAmC;rxl$GNvgm*n){Qv*t|HjbEJBWpj{T0S z77wGWn!AxkT$PLcb)J~u+_b9|CfgaIsJznpSpTCK@H0$2J5zz+qCR>)BBnrZ?daKQ zWIFPgW3BDj@C0%^HGVau=f0v?Km|nE`Ua~S(V9>10Gioi*_|$#?F!(hR|$FX&yz&b zpWg8wgJZP+t>XELupoMS8dY3kef$-~HgT?~az>d2(e7wnhSQ57kX87IE= z`)@Ok|6~bp_uATP|BWMaApiiZf7ks^7B(){7PeLl%0}iU#xB+-BL7B{|CK0E9k<`Cf!(%nz|dHOo-3U!I4zKz0TNYe)wc?eXp`*gO*URnJ!H3;FZ3sjU>Vv!^vd2p zcyHL6>0Mhvb7_g5!xdxEI@>^9w#3@r?ExX~l&eFxy~qkvt;&3|V2m`4S-@#&e6iV2 zo!|I4R>kG%X)Vc2o2ctsxf+>v(HSv;KjfFz7|CP$#q4#u6R#f%8LH^Xmi06_HOVYv ze)TD<@Puu*p{xJ^aK-3mf2dq zIViA=TC>b=P5Px!y^`l@V!9bO@h1AoYnW~!yMOV#LSx5Z;OXTY*ZvD$b}$`uuHK(! z6-yzJoKQU3RNeBAQ|Bn!J;wEO#ll5vZKT~waqsrJsJAI@{2vO1=hD{NuN=oL=`rpP zNGPQhK5W8LuKd6gLY5@}RpKw=T26y|NXZ`^r~?thk2Px;omW;hEsRzV%s8MFY8y`@ zr?cVeG1h`Wd+OLqyumGc9QaGH+Z&!yNIn$EEYb!+b7>waM8pyB3j129 zi5S9T2}y}dkeq9>To$rq!c;(n2e7$5m_!64q5)MXVc7GpcYd4F>?`KW5CK?uqwf^_ zzT$Cv3E9ZO3RV;&26+hm$|V&#=)5Ra+->_vhWod-;$%z}F)d1#w`|dRb{0}gfkkiKM#`(iAzt-CMrv7c-U@*SIyRiO$~=_-LwO5%!RAtrutXW zv~w>@Je~-9z2QP^?!H|nD}Gb%dJaP;*Y?Rd@75RpfF`+&87*TbB^c!>7b35;|5OC) z1a&UT6H1`nT+}156lW;Z{;6LhZy4ei(Bi2{DTc!?7Cam!KF{1*%P9V~p37ayIUI+L zcemx@&HtWh{m0~PQ+Yol|4beL^}pus|Ch-{jV+w*9RFkUn%}ZcS^u%Q8sj525maz6 zH+zOf(({VQVm8bBpegVeh-22{s+zu0QuN_QjZZ%<%~h{XPa9*GM{U(!nMKzE`vaml zC9F(QHGS4FulMU6nDM@>FWUumn znAAuFIj^*3#m8pY(u4DU5Bm^WF@3EbRw6`MP(c{Tj1^331WIj*k^T>RZCrJ#Nr~1X zF8t@TCCi9xBPvoZ@!lo|NFW(_q6M@JF_lns;jf#+_pz$hW}7oz$3Rniv&*j<`%<3l z=PtKxXb!klk(Lyj2L$ui>AjI`diBU_Ws_y)v@Ta0Q+qpkwI>g!KEKyIZtXMbq?a<* zpsWwRH3JtnpvO>MV4q+_-?l(4Z{TmE;b+yqO3wIy?7Lo0Yx1d;vrLQMo(-DktyH{b zROWRKi+ZEC6fr5VH{#z!S;#eT9d;S-e!`O%J@O*j8GC{ zTw};ofLItM$Q0Ayhuftf{;H8HcdP(ZTqY3~5Qz;KYz(M)O&US(kSzrpL%cp}s;%&B~(M5o{*0l1!VzqQlgMB%TLi_D8z^{!NOlMF)N|ce8Nv#SY@+}_j~&d z?60wZds(~bxEE1swk+KM-ge)h zcM%T(5xYrtbrlbB2c$~!W#99zIV&j-f8k~`tb>l&C3l=5ueDem{fbvt_;J3d7!DQ9 zZ>+u`Z?Sk?qrbJF<@ihQ1^%b~WsKCxi~h~Dr~dVL(*NG$|5qZ&(Av((%Gkod%+bK+ zKPB*A389{48|foPM8IC3()}0v1&k;D?*vr?A%qUqPs(-UjZj$@qNJUj_X~zz{mt#_ zeA=({apz+L?8L>7V{S6|n6 zh-k<=oXX}RTJ(nGCTh@^D5pfUr9iRM{*fGDA39;}_e35dj6%>}0ek|7-I{@Swx)`S z^^oN!tD_m#l2+O-jNagQmX}WQ-c-iOZNr6$fl#tiRq00P?Hyn^T zc3m?k{gq2o=Jis`mr$|cjY=j)Aq2WAoG<3nVaIyYvzE6hhZ5)0+;3m+vecK~RMR9= zX3V-gkIpf&-A(*mJgq12pEM`ne-HkqhHIoLgpYt)b~u&n80}&o++|X()0RX+)h;Nd zSH#>4kIgV`Zf$OlA^RwIzmkJd!qRIki<`Tp$0fE2|K2F2lD0vkx3GkgxQS~12N&-jXtMtsvXPywsfC%ciSz#-TKF%@CUFCnLyWMY zdc&u^lz2taNM&sUwN@X15k~cP{oJO`jw0E=LyPsJX#5uE2WTkm* z_k}Cln=6qBxO<#?rOWRBEmHNL*8V!;4G{d-)^GnA`(J9|fA3!mjg3uA4P309|0_;) zrD5jr08?%N3;>Jm9Zb92rAemBZc;f40CNbV% zwBXvhI^=r_e4)M&k2}N5@&Nlcir_a)0&fuezZ;at&moOW|0$Ij6Nil7uCDj1k6|lr z7;3^M@;Won)95C(TKs9 z$~#+yJ|QTrIC?oZCgnq#=)&9u1@lIYnopJbOAEIGn(i(#jCEtRDo0kc4oxxE(pjQf zAQ({FjYKJi^fj~#DvL9%jZUCD*i;xd%I;m>|%8x6!#Lt;?cx`@Os zc{_J_o9JRNPpYUWE)3pkAFR0*$;XZr<1N{+YxkQ%IukzSKNTEO4|?`yGR#^t-16ua;MMn68)lGzBD35YIY%sL%gsR7-Q`bL{YBwnv`Mxs*l z*fDUup3|}sn%BV<4v@-wv?Gou-$8bg2yR(0Fk7qD;=6zj=LM zo!1?lK2;l{c^NM0q$G$eQ`_Dn>neM^?W@hXovtd5SybzbwrH@DZd{b>eKeh}ev3y1 ziEZkC5kDRufgGn()2NbUy7zLo5HS`xe^E!cQ3i3iIo3sCI1M9*8J05E2Is77#IJ~m zS?0?pUYLIpCAR8F8o^53N2@6HSrNRCJED|$3wNo)g zbjdsnn?#PY^p`oO4x%)o>MpH95P~HJ+US>Ju)Ys!w6t3cbhVT*&yy{c=u5j`(CZT~ zMtO{9pX=SPGw;HTU9SV?+|{X94{WFG>$SrJXB3?}QJ0>vEJ6nal$SHrzDgN!5T};D zh8u1)PeD%}l$pO)y<4%@*(DZj_XYi))>Yrn~fUMm~L zwO|SDRsOP)2OkUh1^)Tz^6IQZZ)>a$C-j9qJEl4<(jtEJHoB)DZ8Xldn2Fm4z;mQ3 zGI{abk$|tE2W(Y_6vsYPaNXFV-OKX#qmvmn-D=sZ#mi&_@E)}Ai!b}Vb3G^5JoCbN zb$=&LA@+>ls8>u0Wa3dI3-#~9Oh*X4swADt3U+T3M01t6(gzXK+rTS=rHGq^V#l)x zh!m~8`XF8o7HVE~BFG*nKAp^Eii<5^?_B7f;zd5q9d~*9DE*GnNNC+C0IL9A>MWr{ zg&E(wnzjYS*s2cuaC!d&X~@If(Ir&;!ldT#%i;IKyw(2c>v$s0>vtZ(x55|ysZwM# zpZW9bp}XtsP`KEf(4fp9mBpv2gR}ke(EL5&13%*KITV_l35h99jE6O0g)zojlMzuK zl(_dHR4IIaQjsz~(XG}HSt@|^SC=N-_BJ82kN*qxSz!{T^U~uFio~DDGXqln-**#j zaB> zZchtfzfhrz_+Xz$eZR}Owg^Yjhi(inMF3rs3sqGa8dyPsG3=(avEt&ETKDc{O>o}UOfT}M< zAWQWpzac+07x<1=9A;F)>``e%FADh3QRuq3%m{h{zYA-=>o$g^VoGTr1gwd#A z!pRfB#;_7lc5ac{F3ePOdj7RM*IT%(y@s!~KXkK({^eV~UTj5tE<_TbYp-ku%MF}; zI=%SZmiQcMM6|S?E%%A{PII%;3b~NVgs0IWyIBb~>kS^&kC)`Ah3Y1i5=2|o3|`&p zaL>L}*{v%i28QyxwIE`7X~{L>Z>%*uXkM!ZLAUy&u)@-`GbaLnG=*;SVWKuq;*mmi z8W*9y1KY>ncK@M3Szb*c7 z8NT3B@@;jU2H_W|xew4u>Loy6oTkcMBhb*N)H^V{>(I*$#efIqF-^woG9Q9?R8iY! z9AG}waPD4Bjw5tUI>Vi7BSZAf@{zV^Pk2bDOvyZHrQ9``*}E$u5TXTwh$^8|qh ze98-!pq-)=J-21AE>PwxEhVRXw939ZBGB5GE&zQ}-V!H#M8m(&t8PosjR#l57VhSl{@)d=?W3KT<>uPqa@YcOHQUiq`P; zQXo6<i@hn`ah2n zmpyN8n-VjW?_S@~crRW~rV&OCi_AICe6eX~-W;($bZ%~m{4D&2^ySA!tZ^FzQ*3R&_q>sc@K6T{tnRwrL zyw(|blzBgMeE#L+-nrL6i8On+N&M=3cB!6jnA(y8E(V+zK3-^24>xnpG$Lj`UY<_7;s-Ma6aKa7I%H+-mr_fT(2&` zxYOkn5&wlyE&*TrZ+bx~e4;!bxmw`q-mlK5bZY#*_z1bT)@DB>86RLL>lJOn80N7A zy*+<$x7Tm_&TxMB?J@{>g_2FXnU=#2;S49B%sDWiKYH-??Rd|4Ou^eQ|H0%!uLJnp zmOdK>4kAu!&A~d=YtrEcXEZg%>Ag7g{OV;PL$KGE$9q}oC5e9sdHD)*a~d-4yeskO z2l4Z~@D?#%zr0Lh==+chpHQGUNyD&8^WIq>CGfO2G6?UoZyA*(KDrx1@;q-Np)<73w#=sTpWLLF4mBOHT3-<{<-{-qB=q)MEuMWjn) zMewk1y1%my()9URXH389-mtIAL8b@hF+Z4eq&yv1&kvngl3v}mDZ97FRon?Hf3Q!N z=?k|qnd9SQ9rJD^&GHDU0jGT*NgLR}weT;f2N~S|VtQc_E-v7ZS_VmjwweL{vrB4d zEj5Q9SJ)Po-Z3*>adja1WE4Q#^VqgL1wUUWhv@kY4rBkk8V4y&YFF$YJhLU#cbQ}4T@c5~EP$C|BmLmT z+%A!$$E}Qi5L@80jBUZOZuno6$G|Sm4E|Vx41>a5ALiGH`zal-0E7M33B2~I(WbCa zi3!+l$Fq%J(CUL)HMklKj{IEo*$~#vn?U_u(y(5PgJV<*nlJJC(>Vd(%O~SX;*-2# zh$Oq(2e|x=^}$yA^FfeL4EnNy#uk#xoi`pWE>C{ux{h__j)ZA2I~xew4u26Su7f+c?Uh``$|r>)zs>^$1h5 zZ`ik#qR;JTyiK?}&*7$!T`hSx>ju1ixB&+W8rB-`?^k$PDl$x$@M}s4>{Vp^DL$RC zH!_`}V0{~gY_G?iVM`noFNe3<>o?`ipH5v>_`~hNEMGE$Gebvgd>J>WxkGj9vfd_Q zR#{;J27E*n2j5J8dOo|mnOao0>gORBg@=Bg-H%v}adJ|{jAbR?M%S`=+Aen>rYA)q z1d$lEzpK02v`J;I3PG>VJ&-w*S_JD&A_zB&9$iLpZ4uo$h!;6hvQO8Eyo0c!9CjgQ zdEP(!pI;F7D#6xfyQZm#exv%c@~7|lj|szlO$44*Wb5Kqf{r4ckH4LFZSXbmV}T7Y z^3i8BbT?M*(Qyy@4!;O+;1;JI0yq%*Hu*PPwzhB4ujuPDufEvq(ftmuWuLk8yI6BA zqh0{6@U;nk?0LcA?b+CFd$m2#wmrAop8TVO5g5F_^?ENyUe(T@cF%?99j`S@gt7X! zn;o;vZZ})GN<`%wL1%dk_0B4D@r!n418@f2QSIg4cCkKjnQ8{ZN$%Mwc2_8U5088I zLjzq$R``T>>KHP@3^qUDAry~n>~HU~?diVM_B>dbQowWsH{MlK$ywH+a( z44`0LebZWbHrMqI^lCqEdDL9q{#X)eXY0qEpBDe}qpB84HaKD+pRpwGFE|0lO1JI_3HET)h+k8Vh}ULMh}PM-84-UyQEabZO);`iNUz#2k1 zqnqOE=j9!y)-}1s7fXhmc(c2{|Cnk~FO?L+KbHCd^<0;+a$=V}Ka|$%G<3kF-oNV2 zmg&(fd1#7HHew$_JR^fg3)POq%l!@lZLC+5uo1Y4v&^C@aF859$}oll=6yS_j_tmohobmf zV7VKBMvkutVml~=4rbtbLeyX$6{>A<)*B;>bwuJ8St-k9ICp|?g3bb?zVwcbTmNE~ zg18hU%mVGaw_80PNCPhaatczqwtDHy-oD&uAF7`UUC_KfHI zgZzWXaN2j*Hdv{K4+?klr}*(UG{Uz2)6P?u-yg^w=#JOKd{7U_VsP+clZK(ORMGun z8hhufLI2^eYx@?oCS7&~ilG)mF>8voJhpLF8g*+Ta#B6+Q6}SILV5r#VXxZ--8_D& zkp+a8dq=I=D+Vg(0RFQV`twt6l*M|?;k?%tq>FdsFpR=&x{T9(-6VqVcI-;n3_ z;v>8M1BSK=nsbjX_Z^_vbhY;ccFVrGPgxEAH zlo9M?s7!-j+H+Gx;c%(*Ksf1Dg#xg7Ql8NsP(8ayzM+`V6p+)kHrD3M;IW}%F^EjV zr75UdXj$UvZCx9XFj=;VaUl84XlXI9Szu4v@U7(&%w@AgrdBs;dY)_#5Xv^F#nn5G z=@Zm)ZL~Rc2af)XY-u0?Rh^&JCQCV`S}j4q7rfBmOJ3@R5Imy#y`1pQgF+~E?*XD7 z;~GyM2TBRJD+24JsU2YfFxi927+iT=H!B06bf*QvQ$(N3dcK`JuUy}{(p)QbC+geW zb%wPj`)IWnBHd*Q$MA5RPLr0ZxgCFuOpZzQ_L|u5xV39UT+_p$_#H8%A^U~=xwOLY zAL>3`0tRS{a}hKg2uz#fS%H~*g$IR?-}rW{1`d*54;pSiZ>rYYJct>8J1A4mlh89d zpDe>w&&W_S1|g~I)AFw#fs%7~ND~un;0#&!&*Bca(F(G_4O-n(t$oRccK4uPN zgpx6$B7u@hO&Jg)UCGVkcpcF`Y;>UriYVQ|TbSS6CL%oVz@55E9+0*OL+{>0`wxJ_ zz^Am7QtT2mVsffIUw}jFf*8A)v8TIK(ueiKnQp~BW60jXTr-#?QM??9+%Oz{!ZF(G ztm1(4-<9!v7{`5&YlZz-tE-70!KPcw3vkiDthae}2e8GUR|-!qWqg5eBb8u(MU-{z zGOjaGyaQ*~SKD$WDE)SneJdIUK}>He7&G6!cF6Xk$~)$R^V*2Q=Ry({O#}Z3HcjJ? z5%tCnqIE{Lp5ruyw;uI$q?e6xs?yGk6tWpEAwsV5#wN-Ot*3y>q4@ z&yr2kHnG_1K4+zi2QkHqugpa@XR?*@T5b$8^B#D72=kuz)8nw>wtlv|Vz~zqL|ESj z-K95$UhuI;D1k#IG?{u%(WQ|`zttoaI@FXBx- z62X`Yk&W39d=;47x$~pSQwL^x`7hn5bVadQ%*2Pt;bbCk|F8;^n=2IfhFG8?4-v;` z(5;pO(MsWLo0zlbfv=f>7u8G@Bw+a!LFXTuDPnT_f-uV-mfpeGJPhAuRbXRAV~+^r z^F)a<1jNf19rOKvguQc+oL%(qo3S#sZQHhOWRP*jwr$(CZQHhOW@a+DoxHzui*GdukG#!UA;f+`|LK+Apg0`D`tjIt7K-3qFX??T=IuPI&+pXYKobqGM3>~h=_j% z{h6ivts_^RLU^$kh4G^F@Vn=&wfi06FAH+jPzDEZ@TqKHHiGY)xCwz_h=}L|iy1B9 z(BS160vlaWi(9z({KP^-zEtuu5*(vUxBTVO0^Pq$$t=3NBDfpA8w}m*p&F#)DHdZ2 z%v(&;;5{eH$5iu_3)X2zBj(C+Q}uh(P@D(2Eu};~JBTt**7>3J~^@_9GGj zZOP`kX>F11e9LITL7+f*cCdLXI3UU@vsFzKGr(JMYZ+1cJFF1(%=B*jx`267-CghH zCQ5X-p#~&-KLEj z&AZc7PQeCkOi&Nz-7ArMoVX*+J8#Skx{G#7cpzO7Y;O`5BKxwk%I?{@9DYn6Ld{#=w` zquHYY@~?Wcbh>eA`t*a0m67XVpJc6qlkoE@GlFbA6QFCOPPfR+Ei>R3QMqJR?)GnN7Fk7Y&E(z2G5#tcOQX9ActK;DP2fFP{#kn zjcRno#FVw6s4SpmsG+M>HPizMvPxZXRYGU9VF*uCmw~g^$GZWmN>fJ;qh_q}>t~y^ zTb zs<0aD7G)ZQ_#gpAJ>0oJRRn%)=b)seZh)fy-;B1w=~#MW^|ZS0X1jPhM;@bC$zmXJ zO78(nwK6ZJB+eJryTyGCfq2bY(R2EdO?&vRGqSHG5qB{s?9E3%tWsMCyTNCgVE^QH zTyq%bVElIV{-u4rB&sYecfxkb3vw7&L>AF_X?G#hWRlan+-I&ekNJlrxtid2`)}$g zaBdPp#Zefxz;Pp}H4P$ZQIQ!IFn$;Z*d=C?1!^W_&=Ys;ZpE!QfiMpuF@J*JxyQUG z^UlZ{xq6B&tZNd&?UP<3>3?AM&;E40xndmM1lX`Gp~$RRe0ooL_^iHrbefPG6tfCkhC4C)@)Ug%1Zw zDl){G391%6@yDk>_k|`F24hhVRT8w!VxsB|BY$s|g;4of-WJ(s0$F5;G7~fhp-y}> zBF{xYtXyyWUDiGSXRQi>l$a4gOS6gTh9^cWL^!RHp8)u>;|Axn4Fhs~U-%-;5VRF{ zKu}OXvS%NE`ob4HH zv+-jXEX^K_y9tc?S`#eh%1lg*?TRiuag-B!#6|uIiUDVJWFW4>xRw#=?Z3yO8rvN* zG7XIz1h<5!(_y2HMwO{pRXcne6gxX#KdztVe#3sce7%uu>TJ#Byfpa8drzk$Ea}J` z=(&#HRb2~Vov0wkBzaW6COb?(ecE5YQr{fC|J-t>ud$j;@Z#iOYucJLmRqH7*-&YiDlU7x$&+B|^W?r0I@_^smq=iaI_%O}0p zjhDYo-M)b`XalZmVY?5Q+CVF+3;m0cD|(hTG-_++oxgLZNY2Q%!^l2X1iR#k(^z@D z&*L&ejekinTGfl0T7mQlXAnNayC@A_gYU_3?axAs>DROb-J^jTu&V8M?4V>)FjVby4L&zanl{0oBvCjE zvrOxU!m7*4a2%XW2RUg+*{J2?nr#xVIug;$@lppO2sLt^^-biRyGMN}u5pfJlb=0$ zZF&_PlJa7WeH>Ee!`dC+m^s6yicI-AR=Tfjyv4l*b~ro-?vSJv07y(8@n~b(yS7t{ zW5wg9bFJ8=GnY)V)@7eY!DgQ}(|)%C7#rEuuGL{@z>?(WFgn^FeG8*1yLP?6X;!>= zf^-*WU$`zzF(}z0_Cp(l#-27g47&}}RWJx)1pT|?l~QVZc99C0pGJN^Yk0VM z0=uG03yjzuJw@~)gnU4bH$2c^^NbqM@zx_K4fu!#hf4`GZ5>0prLam}vleeDZ)pGvtnGQ^dEk4%AR_O5nP zCcacuxhjST*xw~6A!B+#$>ju~f^fh@a;Bz{Ec=JJVI*D(#EqnBRGF9!aG@yJVabV%>7Aj>cOt!BvU(Q0RXuy1-61X9b`FS@;UElU-#L=n5XJkuU;`;f;TVm z&)0YK_{12+jWu1deD90_XOk}0IP9NMS5k*95~iFB$UhS(bA8Wp&O%pz82(yivA60$ zul#7^73B>OLdnkCIr`yt%`N>41|fm`^Bi&t7kw(a7A-seD#G(Ch8`vPcgcJ2gK{q> z+aKDPcZcIPBx^j_&Kr(I83eQv%)n0h4U!vW^g}!IwTZ9|JvoUA615QNU#C@ga)zv= zby9|HNR|R5&x5W4inv-*8a}oLThdn`p;34AJ9=AO3yWaL4^r?VI`7$Z|eK%95sQA@|sZNbVPA$SC!;hP^6!B$lLuFn5O`!>EvG0CekR%@~Mv@pL z+y@elI-+u^G&)5Nfn$dWS%NJ30~tpdPPOB;!%3$yGL(Pn3U38+<^0N&+Cz$$Hr6x^ z0?GAmqw6?V)!6uI6Jb>N7v}(ura<2#ut0I)fUjO(1(drQ3X~6mz3(?S`^R!%T-^ka z`=*V_Xu$>jit)z91Y(pVexZpc-T2TM?=Yjg&W%h`=z@lZ@dj)@uSO7TNjg%im`OX_ ztRjc+-lSQZ4O6`E_Aw1QWw~Bp{qt6G1HmQHYVK_hz!eKh(?n6YqvcurBDcv3yG{aod zOqoF+71?z3Z9b%w{ko%rP6<{c{n13E)*D;48Y4J%&TeKiUY_wniZXVl-2^?#OYaDr z5^$K+&nRDL+R>m6g&x2=zWxY<_$b4pMG(uIQy~V%RZy@S>(IXG5jb;hKby$^{TU^w zWjivH@0Ac5CnG09A;!pmBzkLhZOs#pzsF&<1fde?dF{eKzTvs`({(bG*hpCMDz1Y3CgWT{Cm;olVZ^Z}!rB>1A(v9pl+4Yb$ zc_|-S7u9kaz-_-OCARM+&i5*dwlMu!GNWId6f7u0h2{^QP=hEN!J0I%;OAZ|ywgUk z$3S>tO0;{)&lEo$3k3&_! zmOSXUmOhwX3jE>FKtDR2X%l-@LPtVrGe4X2f$kXapf~RSXkbWJi!Xqis`VZ>9;) zQuQ&1lyOGYKXQ=FHGq=z1PvhbQTGu@<|Osr6QfIiR)T?@$S)hlk&7}QHsYy8r#eIB zajN)B=5ekH8B#2%PI2b(pv-nE;8pTm*}vv-qG-<`^3LHg_?X{j&Zl&jJ{F1HHz#%{ zY6CM-%5Z`jn#=Ia9;*~XQ@Cx-NlGEZ8)Y;WlX+H+S;cKHhE_lAY87#^68_?CM>~^? zI$fWkX1FRtYkr~-IFo1f<(I*ritfI;#I|8kZWw;+WvZNW<)}V2oA9#J5-;WVX0ppB zwX@pih#9jS=*ufS54N)U6ak}OU3wAJG2E-&a+Zc#tmR*D{^9KxdV<B;N zwA~_SG}lNO&NOi$vZb2nK?qOLmMOBdBE>hA!dp^unG50vJ2J&^p)|=z3Qr{QAjL>p zUfRQ@sbl-xj>=nIS~-{#r;L3=iTZxO6E7-i9b9^}X!NqfiiaUC&~r~kNSQ49@`oXs za=01vw0b3o$cU2!biGiojG3~^qw9%i^6PR}A{><=WP=wK9>pQ#SLD3?FnNOY=TWyk zdGh6gk~+K(10&u>U>w-zStQ&2zU*@owYC%0&0@Ty@Qu>esQ)pyie-QOLe4!Z>xZBF zY*g?vLslxAVnbE}rz)GrBjFo~6H2>dNQjg?DHmXf~3k46GMU zHk&b6%w|z2s32sp>pi;8lY@kaf$(N{%RD=S!|<+gkE8IzgTgaTYsGMTDnewoy`PSz zIg|bJe0s>&{C@i4f)c%vh~F-+@bZj17ME-CiJDwjVW2FgyhW_6q_ZJ%o44;M6}gj( zobO0VS%*k8ZP;64Xvcb~@EM!5I@+uRulz2=LV&}l*a-vc3680hPI+xU!>=G;lxJcX zpvC8&7`I_)kod{*S!_{0c-1*?1x|Tgf@I&_p+k_i_#5p)%_y2~1ehguTu>sTP z!QXn>Ue78@-fOLif>^)MdxO#ree~&_>uD(Y!7c6{sEc)3G}U=yd#+?>=p1)N{AXOQ z8)fq#565X>l(bUa{%rSUrgN*pdTg=#kLt1QxO?xl`mieorsi?(a2gGx59BHCbM015 zBOzgsLcVtLCk>Xq*InmP7%%Kt{34A4{gU`unz35b@C0ntLbfKBRoaTYcWORfFNT?7 zX|X2#F@h@V6p~0;x(O>#MX_eNxf(9t5{oqJ)OcprzdRazjz#*?*jcbiTz`8MY-08} zta%ytu2%zVn6`PkvD(uiUEGfB_$6Hznrv2&?s~EID#+qnF9?W}=$rUGlIj7?vs#jQ z1(TJifNJp-@>HX0R719Qew9UL5t5Z^ew9=s7_o9#Gu2!(k{anc-vZ2h2g${8*r5A; zRD&4&Hiu;j$@~1d?_qKyAHr2e5i8Dgc`Gc!(nIt{>9nRSB;ewL{CAC!MMybKyRX|} zFL6pYO}H{;>8hO2kk-yf>8k?L>KO^0ziGL=j0)gKIM-;IU@@Hi;y({?(;cGRSQw4! z-k)r8MZ~|?&cjA+ zSIomk;6iPGtrKEjQwZR6eW``X4M{G7dY+vRDf~s$B`5z@blR^wGIBs$Jj$~|rj<;# zBr<`+6SpjEDBC!Rn2U{;vc6muf|nPTOt~fkGjDzg#Wsi4T<~0{9UR6wS5L52+q&4S z*K!2t`e`QH$gJVbiuyww^#aUZ77u!%R_LN*#w%c^Rh? zaX>MvnE1}90xbDzD<%Fg_mJ`o49p@(M+g)%+rr49rYk!&hvm!Pt&_nRVMDibTrrL!ie^aep@e7r1_KaE4sEy z7$k>C0b+qti(m)M2j3_%knKx=WeCFbEO4H}Tf0gtR{}yH8ZMJF)0py*dmq_A-tc?; z3vgy?J>|EFG1uT@l{K?cI(H=q>S}uqiFGBUs;^+-4hsR!DrKRCio$DO6`xQ|Eg|wvp6;+@V zE$dQd>+y5eO{}|ds7-L{+P`>o)<0p9^z7VD9d_>)l&qOLWF!nVhe89jcogfZTAjrykC?&wwN2+bB(9! zelL#!0i%pE;)Q0m7YtjQnDPuCo+=$WVrs}wcxxOFh%HZ%r1e#Hd{c_9gje~gE4r-u z*BIDR)$75O5nWK1=$dV{Tv*?g&AOw7L06s3mCm+9R}Ji{nCS*BtNt~4wN#DOLKjxT z7X%MR)NxL!vU<2$5bKBkO6&8S8miqN9$>06jzQuc7y#L8|IKEh3l_Zd)*mi2as`({uNO<`_EZIz%NZ6~1Mu}m z*hY3ua9Lo>_#T+oT~Zw6Xcjg>{@8XY(GBwL;SEMyLWldhKwb{Bzl~P9^>Q)aH~%;z zb0~Y*9nxBjkmA7iczmu0&+Djw?9}?ucrPBE@tb(;^ zCic5sAV9j}ANsGhjf zjq2y-p0Gjb7$So8#QmDqzc|*Hld`FGLI@qSkjn(aLt)E=-&{ldyq$u}vI(Shc!P*- z6}bq>1J+TOB`|-C@Y6M%@XN+uWs!R+{-NDPYdk**;{y{LvvSC8DuyN2I9?W#>K9>%jsOUA!0-w91>&@vrtG%H-1CN+u_jp;jqq*CGdomuEqd`_6L zP&?O>%p^BHeeH&x2x!6SsjIykYa2%;O-XF_e!V+f@*K}F?=#t)K`j0hAP{7%5le+- zY@OylS*2*zn4cbaZisp{1V%KA_%Ssk&Y`USBitw>Q8gr&N*%}-lhJsYSP8t83qg5V zXQ0%+O_dQ)3AC@sXgsB=7oLb2!)Xf4Id9gS!At;4+=_|NtD7*K|t}g5J8H7_8qTmD^FS;I=qi7t zjKMGFw9au~**JnKCZxfpTyx4kK~FmURM_0HW=&)MVmPk5lz>}+K+HUHpU(4U+t4P? zU3sb7#68*UPqeI5czfOr?f(24;j#8#ae=3%S!DPv?Mn-5P((aK5PMYo<|j^^8Rjul z)j(-lu%2;Ekzp7Gz8L}mT$2j-29yR6867X5wtR&@q$Wg0aC>dw5Pf7%IWVmxxpNb9 z_4-i#?-HAt&n(25azj%d!GU=5$nQ!bP+!<9i)7R{IKEW}yvv{Bas_9 z7mf?!-=>Q?+2mYmnf%N#0|ELISVMt7%C|SOWVA}2{uHoI-aecB?s=6k&-nnfHNKiv z8i+}JJ7)ify34CwW#loMtqvTV=owak+1aH?y)_E^w~i*xHQ3H6Sd%5pe<-Rr*{ZET z*0zIfTmM_ty3#dtlleraY^SL9v3`T7M>D9j!$8AkL2UCc&TnmrX0F_9bdZIp*ysw@ zjfS+VRDHd;6I6^6Cbtnyx)s65ifj)Fj0+H*MnQ5N`g_ohz97A$i!9(h7A-%<~`yx9;BLTDQ5G+$94S|yt^4p4kZ z{F=+DM^mj3Y&w_L3;_@nt;d2&(Ix9oUoQ&kJ*_U>MW1@$)1e*6>jdKHyNEVKnbEl) zGIg>87zvRnSLhowxY=>OiOEoahl$_YfZY1bItAllALHceJ!`L+*c(+K)oNi< z>q{KTl(b#Ax`Ts?>xu^Ago`Ye$ILm*z~Fu!61YJKOhR6-U0z_-XVa6IJsFn$Rq|7zZ=w+P;@?-9PSRlEAFm7O~Ji#khxy2f}{iFYe3L< zdh-y!+h+7%eK)by!byDK-K`p-ED z9RY-UY332WKqa2A7+i!$(%4GfjbumCA%!~I`Lou-a^OIv-KgJUcnr`LVHPxYJS%%* zCxUowZP04FVRdf%4L^yV+}(Fnq3d~X;NC6C9}5(aRY^X`0`j0D-g70cb_0SO4v<(N zQgd>0V}EK-3i>ZuTxZ>g5IEd;k~9B7c80~p-HdbSZnbCn|0fn>5rLICVZIGtqY_-g zWE>O{rvY76!+q1R5NOO4egZgGe~CqG2C0_O%w_tEA5EB(U7)ojPHL58Wf=7=KRb88 zW$Od@n)fgSPRkw85Uv1{DZyus*uvM~N6&djOxsDG+bw6Vb(Yv(r67P)91{RIg*~F+ zTA;{v1`-s2Q^Z64OJ za*FGvf1CoU?jNTZ3k7frs4xJhP$B|wiq}v8r^pof$0^#v{&EU=9ss9sF}clDGVLy1 zO#90zxDo)I;*1%Hl#Gt%d(M#VX4`PEp48AE!7f{>LfG z*#B}094fe;|BF+w{RHOK@_7eX>HT#Qzih@EEVhuu@{6n{N)*(|+~4)EO6v0?>h8E7uR2OnRj`b%;nO z$VH$6gj6nl6^KYp6!(L!ID8gcsuIs2jiXPxqafOD1g@PX~6ESHVB!Ra;Qv>NI87~s;3%>!J zV(2fYsQzD^BC!@!egMEJPyw967QiX?#E8FbZtx0CIiFSikRWxxYei>zjQ)ez)nsLW z=ezBGQzCPtk-j~YklWH;2c5EAw{7o@ubu4&#*gIQl>D&azYVey1qZ2AWi4c83^b)$ zxZ$z=j=F(+Tat~RhZ0?SVbn>hL6R)TXSN&q=5cSbqNiVg?@{}D%7-u%<`81iLv(V? z7HETsatd#Xwhi6u%GZ9^)x<4bHE8z(8@_R+>k+vb?d;39z{ga+$2s~DvV(oqD8p@M zZ?Wip@E6I3_;XU0CuQrFFz0!2oQFou*?iw!j$4QNRzaB;f90iQ(v$B;t&9-{rjA+QRv2F&S6>M7NQGaQLm~_+JcxK_h{9js8ur#I_ zViG6R5rvzSJst(16?=ba#fEtSYxVhpZhlY3_jO%&*>rcGjz*`JT9{CXt|4N=BscAt z^Rf1@@+35m3aL)juoj|Rs=Mbfvh8v;tr^-IwWfI`w-%}!wWBTnxUx>|Bo}R{ihJvv zv!FBGc-IFJf8HQ9tpW&}q9*BkAM-8&drK|+Q0Mu1tY}l!UGUIzHwbGL`YJL|DqCXE zVqkVE+XT@fcXQsW-l+4UA}lkWG(GzAlw_n;Q_|YM>53^y_1|=foUHtuL_F(okwBT8 z^Pi^zcY;_S?$X3~$oJ}CT`Vf;xfZsNZo)TD!>7ScE47czNk`+dfWdKome2 z)ZXj*!#5-lY%mws)ud?)c6?StW5mLJ=6z$t#ziJTJ$;9qR4@PXzpc{MsQ)nl{`b!> z){P-MxfC0+R=EV+R6~H9YE_nPQ6CPE?;7~D-1w2TuUhLZHc_sS9k9hYif$|7 zt83>FN!rP}8q7?9j&{}EZdfBB(yt0uJfL->yECh;;8VtRizwp_3&Hgm-l1l#f#gR% zXKcp0W-T%NdAtaDn~NuH>k8w?CvnS)qBQXBb8ulL{S^ZK;PM(Y+YygAuO{alD9Ix2{mEcJXhsjm6N5KBeFY zw)z?%TkbEp*}|;8@dGJmtb+p}*MNO)zFQE@`wB;=8rl%9pMp(cxi=*C?p*~*Za^&=#bV2pMInT`6rl+bP~<%ezPlKd>LRFAGz%taq-%kz_TX*Ol>!AF zzQx)gtLPoY)A~~(Kz#>Cs;i1xh8D93DrnTnNEb1iGRPv;Mb1JcEunK?gyl3+PRAi6 zKSO$z9%+)CS#zBj_e|grSGDSPGa_%Hk3w|*C03Ycn^mIiY+c^ZCd7gYa)N(FskLi$ zsP1T5b32{3sfZgED|(%XRPMMOB;i|b@RSS@IAwS&YRT#wuRk zT~>L9>Gj(Vvb$ESwvLlUQST}Yl5+g+FQ?sVPeTUa?_|(5aE&>gP8!H8G~ifw(C=eq z(M)RM7(oSP#_cjNvzvc59dxj8=Oz*LKGUC=qoOokdI}7zKx<{n=P)9?{=jW4EdUm7 zvWpTQ`?u$S#hWH37p?4o*|#vY6p2mNrxi!~VXA61;RZ$P6i^Aksqo)kxiBpG72RK;&gj7h0HCY@GtRE;XS7tUb&_A{C@7wY>kyyr)F{RJ9xrk(d7L z4BANWu}mshTI~+{Q7zR<2^e=tkg&-$j1*oe3VD;tWyE=c2cH#!`A(6=Akk%DUEL32 zLMUwd!ozM61^zsV5SpLAHWKnhh2IBGk>MTCTa%yaIr}sx9tC^Y0C!%Nbg~2s=q1z2Zfk8b(F1BiQ`E+#L**h}&A&5sviNq={L#kI+qTI_=|p!N zoDl4nu5cA>i%xMLm%gm-b%k0pinea)8g~2JaUd~e=$0@gC0No;vR=p0Xz(XWb4!|W zN6x^6{zm6vS1z$$G_oF?KxZQ)x=Y&B0Gm39*&mHwTBnK0!=5~B>*8fee8U(^kbbd! zZrISEerf-c+c<~cVI|ZZwK9*3!8pFo%4E33*>P~W%k|@*45md^x?C?dr(#@6%<>>s zK*5q$cIAz?^10*l1QVC}5``#&WmRDJ<+50SEg#ZAs2&BrfQfFzcRC0twlo|=3FVCN z2S}dt?xGJ|LH#0cZ5>v?BnuKrLcLA*aEObbxFmCpQnD?m9#%;xlNBmWT2vE`H!9`J zm}!6!dD$BzAt|QSLW@K&?`gU_`owj#nQOz`+SX9sOmLMn}&C1`-RL*)SJn;*GxCyCL&#*+)MUr#O$)ZQ9p>))+ zMl<5=-6BMapcMlCD8+cPTk z!~N4|W!{n5%)B47mF4KWPVA#JeIq(jLRLRidECq8NrT`{UQ86f$N?7zZOCiZ6Grw&9&! zt|&S_gs6wsAo>p|HIuuf*v68=r+rHSQfkL6y6)BS*2WKPlDcmXwyeo)X_>o;?`E?^ufju?o5i#bd>0A?cze&f$YCzIvxP2;jPW zu<5pXXVB^N$il4H5MR8Z0u41Pu>)$8E=B^-mL#^?yfe_Me_*PKp*tPDS+zTSq$`X; z>!vK9{Oj-d5pHYfc{=>G(P;nSI-4I+!ws0E|A~5FoTj@PFse)S4`eFMybH&>CdUu9 zD&4>H#6VCFFI@vFr2%c%0bOlBTxhb@>S>vs%4zXzE3pTt2Ql>_4uLbb34_S8lq4E?nqu-nLx!{(H69eq0;t z_7DM1?D_ChhYjGLopME4m0YTKykJ&pzEc-Ov;#VK{O`{LD8A8~f1>UWyUW7{jQ8&V z=z0PUz;9Ze9;V94{fqIZj+^NxOQHWxTryxN%YPG(1fU*R{2f^ukZrnf+39~e=!0(e z=0TzF>4{Xci{m4`z`TZ6=g4rgu;?)3BV!ftt}JSxwd;IRVnb z%&NZG?@)O(@^pcoJq_NR94JYo`UXaJIYfBF{PhopN~h``SV_ z6limR%ie#fe><}ZgK?$#2hc+G#r5k?_HG<;n`T`1YxcvC(Uo~hDm~wm+e{xnYxP z%b#@^WqJosZQ~DZ!X8!_7p!%9`5HBX>s5d2wNTTfYLW!?vh|piyM`^zQcfJm-J{f! zR?Jq|)_bQ=%u6cLGP~uAN|N-H-K*kdidM!6=;doP!}O?~x+osnxVzY77O`rgji7i6 zmQ`GSy;uEHyN%SGv#oztW=8BM1ekO{Vw78?~ScDELx_vOh;O< zq;IkQem5?k4c}54|6Wb=Kv}vFEVgLs!BKf?tL8s##^T$2Ry|Hmi;w>J%jKEMK(ki- zHPxH2xQfK@hwYsFI1IQ;c)vFMMH`g&&E&HwgbN%6Jxu@+IB&)bNMai^((1$#ux=HP zVjzC)@=v$KUeO<%7;T08a9sV#Ssy;0h@kT4Q^TFF4Lbv05K8V#W?ITli0}}Jq8i{R zlEXB@EqI^kYkNNCtnc)=uwVCRLCrK!n7g5onC)>RgyNGy=*Nj8;xnlJ+yFK!@#}@L zbkcva3$3AZ*t^=_Vx$D*YaMC~d`wI>Nni?XJ5bP?p>Xt~ufNR>Dja08Lmq*m-sUKm z52oh=7lrC~wM%{jw}A;MS1WO_vCe$*J6V9S>DPiOLV#2a`92b)xjP^9*i+oVoW0vd z-pytlIC)@VPS|YySEv-d@Z)^LaLAi4jyC_CjGlo-a4`*Q)*l)3`%<;bq0yo?5 z$#HpiJ@0vmh4g9FoP+|F`r-M*#)m|*?fx{~qYigNbjfC~OgeAkc;~2v5fb>&R*7MO z%b!rTs72i9XSmON?jtabB85?#PKQ zlgQxypYq&cU>A4iF)hy}(zah)bWTHYRT zJ@z&WFk$YmF29TsKPUPA?rg#NO8a^A5$T!#!~F0!?=#q|L`BPBk7uO5+^RA@GsU#$ z$*|qQ&MLTwcSK?$Gq0d?>oX#l%$H0^|0j}B1{dF)owrTMu~E6ztLmIyY`Hi zDJG}=ow|4^$?wVN+T*PFsqp_-o4fjOc@mlVku3hn`Je;E9s|DZf+Ix+88QD|XuE_q zzU5CD%zbO)<&lULJ$bI`e0e~j>P~(m_-Qc3$@VG^1*NLec#;wbNzpJ`kz-S>Zlz*C z6MsvIMhSoySMs;kUKc%o8!UcFv8l1nGC#KnbHo2sKa{t&0_M@&GQ@-OH4p}OUrrJl z#neMg>fr`r(^QYtxIC*ygY;=?MnBXx?CmGYLHtjwi|@JjN)miOd@1@RkjDp?tTq_u zA2`@8HDdI%@3W4rp_3F+zLX1>yi#c5!bKMKo#K-a5T319E8x=O65REikkRcy|N7qw z-H@eFT(uuz6@Hda&kada;o$+EBRsRx@XGL&KwXfJ36MH!%F~IYitV ze;!MDxh{JxtQ5U|W^-Q?=tgLOW4#0h`pzaY5<=c1$pVX|_%aUaf5xmHpc}^I(9T7D zNCF=>fKH-AVf1O{G59wK8Hku3jlzJDi(%~R*R`W&VM7yhu%n3CT2n-xh7&U6QwR4# z&O{9!LI!yHH(M3R`=GhMMa(XsvvqQT8J%}EpagK(0}DQPy6ia-VDJZ-?lv$CqTBV= zn(kkqHK=2R+G=1xGHdEs4~c#>aEzjdv4(2Wj#zS^F(l8RQuzVeXsvc}+S+ABR-JPD3_z>wToj5}wn0nlAhsWmiQ@4kDpMk$w^ zcMNS==JC7dij=+pw?CM0;hb+szVuTgJHuivAD^ZNb&q1?jT$q6hybFUv-3lF&MJaIZzM|^7#l?TOdCU zAaoG6KR4Wt@$}6}IK=z>g-;UNchH#{v!^q zJY5YLdI;*`t)BRH!BUd;t)9YXjh@UotUcI80;NXuy^z>zS`COzK(9u?EZJ zz+Uf)v6U`6Yjp>fEWQ|%;CsJQD}m1rG8zwv7k;-kd;$aI%$K?0-$$xyQ|;9(Kw3Y! zBZEC0Mn6>4pTOWDGY3YK`Jq9O0NZ#@3tK1{=8H|8y0*=QLfH25)p=S54w9{_>TBd{xi zjQgcv{|-@&joK_lWFFNNwkkPh1C;(GRKxz{i7$(upbHUe4-k*zRG(?AtB!3EY&oD2WCXOn{Ovf2O7@jOX^l zT+~g~mZp1CRO=rQq$?>tbDOtEA78|O0#s4gLywBFD&B|g0SYP75M0DHzWSQWLuo%> zs@_(PyG@4nWUa2TVq*Vr_XDroQ-xTuJC6zpF%P^d_E(E*j|sg*x}0}KiAD1lH+5#c z-(nSY)RI2k@o);KRiqzR+dq*5%{1Sohw21g3ytf$O)&Nw(3Fr^xy@72+$rZrqA{BhjVOmx;g7%Er4aiHC&+8B|^>&3>$3%YuS6gQ@={txMhnW%tQ zogcuoR}I#2bQa#xE_{j-nrz#q?|FRLwgT2$>W!oqws}QP8+hr#Q?vL*FdoV(OC6e?zl1|Qqz{(b%CY#1w`%=lA?zL?oRyt!ks!$(&l$rZtOs}2 zAUe1k`l0HVT!`6_Ng_-F5ps4DCy)_KwvYz0#>dG8kp7tqnJpgICmkWrD&2ps@;-%SaH75^q~H194&8rL zmH%#W|Gi*o-@M_o(Bim&5ncOW1~(GSc)fSiXt%S-;>E%O-fj?W#)_c2|0C%|o%B;R z%t!Kj`5=FcX!&3d)!h%ge&OU7cGh{ei!i-sgklqxCA6#zT?UkLJuHrQg-nI?wA@`!jvPDoO0uK zO3?}SnYn=R07-V*fe5r*PbzZpUF+9RxzxzWjmOwBcN52cmVCa#U8n@OR-eN6Vlo!_ zEgPjaclfvp(|DaOzwssI?8N)RMDijY$|K3JT!rjK=7&NtmX?bl9Kk5Df)GxBU{nuM z^(ZGhsKVsUuSye0? zy2D_ozPc>joF|Z8Vi{=T1-X(~bVfcQ8h0}l=4Q5C7njnCBlKKiPZnQKJiJDB{`MgG zLgLP45A>bzT*92IYT)HNw4^GU>i8h(I(j^p?#__E4F51IXx}S(uxZ@`BiH^(EhcRoOBo=XS z`Y4;x5$%j*xwui%%gkoPjB21LsyJ0<{Wq~oJ)ly)`c+5N1@p@E2T5aW)wp0?J5OZW^+)#h4(Z`^;c%qb&O*q*YStkz+>jU^YJEv9aCa6#{|{;J99`MBb&JL}E4FRhwpFo{if!ArE2`M6*tTsa z731ytopZl??sxBN@3!{-Sjn1eWz4bWN^5(MK6)Qx`X?rZKD-Y*1bkpC zau}zS!)fR8r-HXD*y)Ul;tW@TpzzFZ?^vv<;6%DKS3QiD;^ha`nuta;+v??L&6!J~q(=<*s)FI-Cua?~}F{#G^~HOM^~IqfI8ZlDJ}L#4&_78A)V< zD2i_Mb37M553!gQ5gUvvJilcsC9o)u&?EZ0zK5MW)4yZhr3O<(cXD_ojql%&>N|s> zeLcayV0g~q+^(9tgNG3r)yoSvwhOXjh(C@s^oy*lk9^$!M?vMve->2o{8vFG5HGjlW)jJ;tBZjJG%cVu-pie|%x! z*qt7=zh$^KKS2GECh57ZV;GTG6X*RrGzN3(%Y983aya7Qh{gFDVkf-QDK5@Fg|6>! zilhAgYR--JnD%Xb;Wi@n-fO<;3;qx5_#BnuF4L>tXZ3M+Lo{yNb0vvry_cDU=KWmM z+`*flcR_8Zz~OMNxq$h>MGNoUbjGoCs|V{%_r4;tkY=(O(jC8TLg%J}Ui@&0DFcO- z7Z-4KqBoULMpaq%96^EOQRU)Pwz7m`L;w|TW)2i#g8ub|< z?1KyVu*|ALYO0yL)$DrCdxXHy0Q6I1`x$iD6f`3D=q{VNDD&THC{>oP2fx6ElSKex zKs!9lN}@d`#LDZ}rQRmbx7D#+WdoQ4o}&PL&vZ{oo%cnIj}t~&I#~pye8Jd1MsrE{ zbZ5CH12ecK(2k&0a(g=+RE~1h@p)iW2l2c9Quj&XBFc`<3NS+7jDEWbe)Cy>ks2M= zh>kHTaMwD)#ElmaV}FD>L6$%>dF{W)T$Dg>V@$%yKRF=4%^)Ux_^A&S*eROiKTGx< zjw$_%I zA;{SPl+$hm^$)`7b0T5l>Lbjvsw_v(`=ot%z$_?Zuz7C!KD6LvP6gp`02X-RaoxwT z!|V$)-D_?b&af9~I6bgTXI8_AvxFM-_>R;m(SI z^<~m7pWAj;@^g71TpwlGT3>OlE&hDivF5H1ILJXHg6tZ2KB4ynvtj^3P+}a2 zF0oWG;S<73?Qx0S;`dFGwLgAuH@^`jSmP?)r(nB0NnXYi!f<9n%GI93rO=<2vQ$$A zH478J>ZdaoL7QYH3!Q~aBuB8<602e1Coo&sw@)OZDCu@&W?0Zy|4QRFZzoWQFNnEh zUc;>g9!TapLIJ;+6B`41r7n~u5Fj?)p?6YEBwIQmNrbTNPt9PHSL=Ax1-KZM9}>s&{kd;8on;Rh_YordkV2+p0X&kBrkpwJy@M z(hgVTdBN^OG9J115F_EUSW*MBJASHL3cB=%z5T&Z$?t;PhgPwm=PE{$P_ojlvV`JT{Vv#B1E-o}d3q`M0-s-T68t0cv3X1Hi^ z#z+}nC0W^5SA((?HZmF1xNUBNMr@er3;UJ(=%ozN`16#6^J~casT}_6`SJVmdu2>O z+z^SrM48p9j3x!4hj+g!`Pn2{W?2F!B1n74XOtZ%w6*jwXo-^>yfS$5uxu3W*X)63 z&ZEu&>2g|8Sf*C$?*poc$NbY%U~BlXl=VFksjr!nr+Srm!CswE^+wo9T=S?V7`bJn zRyhk0;w56%oDv%^#i%k`W>}qKHVZAg?T$9^55AV%woi1wZC1${C5mZaYn z%wTYJAVHNyXLglGD*5AL{5ByNWvzIW!0FAWPZ0Sng2Rk=iJ)HK0L=++6yQ=QX96-` zZTyYQI9RpRTQMzCI$cmgsKw~xIP_X5(-8jWLv28 zhP_#&EaW%_(duqTFr=s^`Kfjl?3cd~NBbm6i0aeMh;<@PjUA`yDJz*~$_k!Lq-18q z;?FE9EoTmaB7aoSQXJL_U^q$sGMsDpyZ>f5LxTjD4Ze?EiTnq}X(yeZX{oE3P_d#5 zmdF-)O-{4zU{7AalGlK(A&3q0WA<6#3Yd!0e?0bcWC-YLvLNip$y_=zJ^-3Bh@AD^ zr49344kL<|%7zYCwx7+KRj7rHxZ)gXa)rP!T%K>uj4bYi&ys!W6C|6kUQ%T=)K$y; zM-Pe3$4rH((T{(XQl)xO7$>BM#t8}_ecb-m;x>dO?WtC;jxP=(RQt?sgSuB6q2Iyg4H`qdb*2o z3JvOmrQvmTh7AL!D4qd0z+&gaU0d$k8}>x}E%CYj^~ReU_B;HoQdmU$`H-*{%iUdD z6TVIW1&DDr1h{*517IlIfARqC_Voi8%9EmByq$7x`1=1alyf5+f9(_T^^xVH5jWl4 zv()kN5dkZ7Io`F^b_dkQWDG8+gteSb_5T+G2=LYPkDuG`gRN^hfYVdJ-+H-cVE|0k zXZrUG;tvje{;$@t>9)7KDdXw>1Xv5e;#z;JzvH^^Ux)qf?&dh)4G1#PEyRSmZIAWu z3q_q3Uh#ImVc_cnxLE?1!`)4{<6X9bMD%w0mtK3wfqZ*s7(#qJ~P7|i30RDpL`Z z3TW(CNlx`Qw&h1x`jWw?H`i&32ko_jV_y;9@Hv@#5gIc8k0Cfobj3O>nk|!tEx}@9uLO9UKT(w~C$u+1ooTy|mBI6h!BS~%9%vgpwt>B; za?Mg29IF*qn;>+5`-ID0ig}wZitV~he|d&%;0%lX1HEQVe0*AKgZ%5v(RH~Iu zNN5yMyX{pjN>Q=1hEsX&d zrwAYx)ANT2h3BIP%Ig=g4MBpQ&_D4+FA3F5D)5TI3SHx2(5xUWSA-s%A%PnS&z&K$ zNO{6FIi&mjRqr%-!qD5$?Ok0c z0VBwcyNiy_1jKV52R6P|kg7xvuP*Qs)Ieh5IUz|nj;zNLQ{LU=j(D)~fOtMaQXV5} z;|H;!l$kFCW-b(~(e`py*P)-FxdC$afqU0}M+#=X2}48$)^BA|l4d-H9Kzl#*D)Vj zj#+`YAja++Oz}_X8;s3*brR(a3Y(?^aFa@1WxYefMehoRZzt9o)W#kg_=)Q%6 zl=_v582Lriee8Gt)1Jn38sk&CXT0ZP!!6Z4jknbag*pz2>BLMTJ*rWge()`%@9s01 zz)?S&6V$BdHs0y8ub?)O9)S!s_|O7^=z5-g^lbs$Ls$FJF|j!dhcQ zfandKolU(ZT^5*eX#pzvG)cH|?#(8O|F+AtbHUI|z;zLi=T}r)I?6nFgppwf>4?n8 zMU;VkK9FNH*PovOp6qeqq`&iX)y>D2fhdeW-vI1jSVegL;z4e;jcbr#CG;OabBv>D zCK9bgKQaqLh*ZYLy`6(42fWl7o+|$N@&N0nM|5JEafM3|qnQT3Kvy9IKsD9J6gf!yyQJ+6 z$q?|8T7+b>3>3uM9UkWBj(=WBxTIs!&-QA#Sy z&sF=QnG(^N+-5cn=3JdrLnA157ffe>;CY7sD4BVe%i2n=M{X=1Z)()Ad?K64Ots4t z5SKgJ5sx{0jFIBZv=qXvE#?$Uj;b_oE?vz`U6H2g)CM5r%C}8jf%HS#Y|Y+;8PD!o zuM_Zp=a_UNNYuiI-`@DVu@)vq--oo3yM2z4uA7OYGCqaSq~rChJr4^tX^yf1>kth8hNq z;ZiEi3Zm+1xRHkN_R={@zx|v4E3l3!{n6mHU(ux7bl&c)o?ebYw!WTREW;LoxBJ)O z^U2xS$`i`# zfSkQ(PU%xYsHgF|IVf+FJ5fS;Q>e(?bp)%=7Mn!8*>t99%4M&!$AVeSA&YFQMvk)B zmh+%gV3PLOm{D{-Jk1{_V*KLF>kQM6AO9_EXC39zZBcG$1mImF>cyNuvlj$9^y zw(m6oTe@>GOR3rnSbB`sNkEwLR3}wOcQCZ2(~UMe&q0?ZJv|T`Cpzey<7nTiTSROg zR&mGT4Vyl-D!iE_K6bEzcOW)Oj&%af<4-M-3@x^c-NwSJClW?+EyU?xgqqmv zGlCc*w-V_Wi;r!CWFC`5FJDtNi55+(xp9Ou`S#hEWhW$hbgjD(z~4KlGDz#ECL zDcL+k;WPjnB3V?L6`a!+MY>M5g>}fVnql$qt><(}w_;osGcF+wzXWx(*VLkqhEA5y;X-Ru zg$77OlK(9c$wU~=Hk2B)Kbx8sO4mkpMUI0?)>Z{5M4agV-xVStri-@@Bgm*_$pdTq zBsbLRaBe$WwDBu9#)=ti8D4Z<+oW)du?mo%O{lL*M^?p<-=$o1;T(gACVdexreb6i zaRogj*nizH#hAuoE}b+_?G!VZ@#|L? z<39cEluD(zT|yO`3J$VCnD<_oAk0m9Kd6+OMN$fcsbG3Gg)ziQXa77kgvCcNsJ1~U z`1*(&n(WKEwvoxeCRLYjnjvF8oMFK4rQUEX8+aP|t2Q|NCtxY$M7Yr6o+hIk5z>9&wL}4#hE!nXR208?pkCS_-|K zwrU*f(wGTRiDuSArw2o)SQmN*;$4);0}4!^hSRproWO1l;{ZVsBxu&gI#Lvnm8h7d zy8uDbDE@=B9fUc;(+#JtmxI+CM{HJ{C`hkDHV^9?Ix-okiUAs7#WjNG);)5EQs!12 z)>G51|H7Bl|2w@_5|QEF9Cty(^Mcad162Gq;M9LIW#po5!%aBFB)Cr7ekVl&y+97F zu;H@s;W2fk88zh;4U-q@mOcL?zy5F^_w%7*Kf4i`Gj*^?F2TL=35rQc= zw3s|Y>pU^V)v&tGTw0AxvXuQuFAVh6Qbx)c2Pt{=B#`KjJFCxS23$pFki; zvrbxoe;*_ZGkyhji%_#`1#)s~+fDBwPD50+a?kSY$b_DJB%{*2G1(?vU#*zdKQuK; zqP6+0YP0Fysd~Xpz2k8yTG=RV?FVycv??2J8k}_a30Hxcq^FQwUm7?JQhv2xFzZeh z5i+b=%7Z9q+U}Ncia;6h@tkp$4;$MVE}+mS)zv~&r!O^tuZ^)dQx#h5a2r{sJVafP zygZU2LnXyTp$BEr)>}ai#;c7}(E*b(g#HtA-Q!~;vN95z;i)q*NL#?HKz;Esa9HG1 zd?7Rp{u`P5ir(xd^rn^P@D<1KlWt-yvd&kKp>f-gaKFQMDWM>Bt|3=^D(Rnb7D0*J zGtPDsbSY>Ttz$XVT2EVgrt0@nGjI3%=Uc-)3|~1gn9fwFT3B)6Vj{mbd&dnCaUMRs zY!JoSxFbrA!uZm}gV%o6&7E;;1s14HPsGe+)@wWd=G7nFQUstcZY>q8-FtA=$pP(oZExu!3!Tw96atVr}OX>*LGh0vebH z!=MVWPRU5brI^1+{vw*v9>Ww&2(IWv3#Ulc>w{=Zmol;pm2!$D^q|Wyg@Y<`NlO=Q zL%SfW@)GMo8W&9fe0pb4CL@+Pvl8(6Sq3GdQ;d+2?jXNv@&vEA{ZbhR+EJ*^7ibCm zB!=}leR0pSf~1q<1WhZ=4uDPcjo5q&889jP5qMDQ9~fNf&rCWdYXhMeDp`IyA=o#{ z`;bag51KD966@@B@O-ND@$U{XnM47l1VYF!9s6Iu@TyjQ%)4YcN=DQ>KuyDcIE0g8 zIv`7y-fYYLSDP5B4P-il?F}iSaHyA7NYWA@dYK_)e6}H{lY*Cx3~tsKzCsh2lHzC* zqNAGet{wY&O%qF_%7gFNzqGhT8+Yq!3@PRLG9i*BgqD7Di?TdQ?64*@Wx;eJtz1K` zi#|BQ{AiQ-S9U|-PI%xuR?@(OFW75d|gGE6XvCWQQ7?ebsEbuf9bGTlG< zjgwYsk&ZkBE{fUL#!KUoXC%-nzM=dS-HbndaAAG-!*6X?6I-n->sdjQJlhUfOXH}=gJ zpTFs!U-N^@bJy#QkAMB}<5zvt=(q=*0v^a3VA^*L&^f>Q@S-JlcGld#T^XX?{(u^V zKn$SeTlC%TLIV+!1E|o+ik7ZHmFFV1|Ekbcyn3#?X?m{pr>;BF9^S5Wo_(I~e7Ait z|9!v$ZY^EYfJB}a+r4+c{m<2Gw%ojp)iSsL1Q>Vo^wdD7RL!_pdTs$OUy*%u6K8)T zXuk!__u|8AF*~@Nvkj18U;j&o4wwh9I`V&|rL0e%Hd`M5am)))*Sj7AhJT;q&FAT# z73Oabi`>qQL!Q3IZv?wjg=oM#3ds=gsX6-3XHX2g*PA*70D(I~C;%kerJ97p7xq14 z_NROMOf<9(Vw(drI66O+K7AbvD(ZAh22DrK-s07CYez0wjc?jH2y;}MkPrCPk21Ai zrW{T!M=KM!aE&l=sVx4G4dWh7h)E0yY!;?j%Au-IY&Ih%H>40A!!&?exxiTl7OG8vM` zei9qO)&q4yea|L4$8JEhPK1X zWmo|Xbk&V`dLdc6uImGpdFE07?CSnSZkrvCqZfkhlfkmCwxwp3Pm!q-lT zKU`e|Q7)cwrwVHBfV!HN9FY?vvFd2)FcEjb*{Wo?>=V1nc=We*53UnH{B<-Z! z`bK{i^OzdfrXAl^CifHD8*(?Js@8MZR4N77tt$T*ky{5e)wEwf%BRYrS43iiiTE`I z*y=9o3?UmF&1PKQPIU>7QuVh_YVaE|G{pchxd0hHUT^_lSB&;cL<~_^1{LS?gHb73 zK3K>176n6kb`gVp>VqvrrzROfq_0Mxu6f%ZO}t(q@ib zV+QvpZ{f?Qzm1feQ2G+{cZ4*$2j6x!;) z^HL5r=(-qCiJdgHzT@R}N<+0drqn4CLe{7<9)|-odIZ&OLQ=s?_$* zZtTAkV}h6XiqJ(QZE?aPzzuw-(iyIfR25NnQek+uHGNz5KAFF}m$DeC9|j+Z#>_AD z#h?Oyss)<$<}~mhYX>TIC&kF$Tlz)?(*>l)JOdlA@2_m)2|Nd@_)y+OCwS=&Ol?J( zj8gjveloH_Cx~*6_ycS9T!9R<>+|Ffh1lcCd7Qpa?%UaXghpPWt2Gtyxq;6F<;POW zNH=g?@1H%DQ9%ZN&s(X4(?JOa{&y8G9q;yzL37Q87b3FnA5jVdvEHP@d3R3IU9Y`Z zCyNp_{8Y?cuP2LPepdFC3Jm%_k+0{)U>hPQ^N~gb4RpxwXf2G=N+*Y9i2?e)4|hq# zUJr*7dGFrUu!_xD7h;_gXq()!5eb^4+*LlbU2Thocp$SJEhEHA`Y&xo{;a8!$SF^; zAy!E1oqDuXKL)BIcsx*2=Q) zOc99%ZW+r&1bZt6^+&4e3+WT0C?Xa}_AeQVfxN~@7B^3*oGlP0)*l05+=vGvnDPy0 zC!`4D;tFbiZ_+%V(6O3JHG=y)3P$5w56EncvmNctDo$wRW3!amB}5>s297Zjad@-Z zOMU70O0Jf^ z9Ie4P_TCFLK)%G*A#oTx8J(F%IJaY!$$(5I;`nOx+9`(*8i=NVt%t!0B8q+E7 zsF}jYz2(pZgY)D7`0#gahxmej-TSC~$DXZbF~yHD4BqzmBzCnBd&VLTORdlsdSeX= z&9hC~*8CM%HTl-4?|@J|BbCy(8PTN*<|3i6EAq2L(z23#-sBx(%0LQboOn&`r3!_W zCwp4BXyuYJgPwD<1aHG@U_NH_NuJKn^KQrgW)PK@c&@UeBL%Mo|87Nww5Dai)REG6 zCz=5_4A-vHA8&CaN<*MqA~8?fL`#<|6{q}gT0Q8UU}PV?K`GS=4IVN$K8s>t=jFIO zCG1Pd^_d_g^sBCPcY9+!fQ&{skQ2?=YWl!q1e)b8FnQZuL*G25h{wU)35Vl7oRx)0 zps*)Zjk2J8;lX*&&k>}Z{Z5I6LQ&gadkRnjg1P1G%j{-GZ|VTzV&*(5t>h!)tJ?mu8E9^QtU49$RbRij4guxuMy2TWm7%7;07MIu#ryhi1_vqPJ zC!rP5Ln%$o53wnd{E!Jo7<1p&RlE6pk#} z$F;0HMxF)gyo$X%tnHT#9?qutdp~C=mj^Hl*R`w~YZr`;v931F%$=)r_xxkc)yc7v zwMrsVgT4IR=qMKT#Y9_&j!IE@<2FI2=sjqXwZqkd~HJ-09XD%vrM`ERb_ni%R-0jc7M-11U z{`Hd>+wHoeDfZxZ3dFq*j~mplj}EPy`75=Dy~*Uyp)KZhG89(TtxgI4EB-12I1kJH?Ef9I>;#KjR3ns!tS74a?-D87)4g2Xt>R1Cm1=p-HjU z2U1IsZnv&gI-gv^DUwSv>YL5R#Ix!?gpYbl4*i-xZo3Ar6zQ)c(xI4{-KZnY!O^5E z>9_TCpSOrJuaNdQeqBPwqF+%~zXV^k+t6ZmOF*ZUg8v9gTFLW<0H3(SNs@`XY^}Kx zcF^*-0TS7xy|tSVp#209`>6#X9rt2odE5N}K}(TJo^&xb=JuNSI<8cNp1z-7{QI_R zpSx4e`LwG`n7hf|V9h!9<(57`oa~*zF)iMxg!Sik4*Kk^qnkmttnuB_TIRf4`H&2= zqk-vOne{`iW0ZOoXV;dZHm>U4@z7iUy+BPk%W8?QU8ne77bUPNSbe4p5Yapz9trjL z3u$yljOCSU{*MkZ_MW^W_UX7_o<&H(q2oEve3hLwCtYf6QVA2Ey2*w*7N=^iy4RwH z(8IT-(p$ca3DkOojst`KOs}gdhvVnUe5M#}4vZ(KIF{F`er8TBJJXoHaqCqVq?49N#fh`JR6`TG6JlXO zYAp*o9b3AK`ES;vdjipJ&><`GkvE~D)49#xY+E3!B2Znh$gj`}p8M>pKq2-8$3I99 zhV>c8V~`z*s5*r-V%Fjn2|0!ZVm@VDr!;5BXysc&Fi9(aMPV3-s%StLA8~YAEthwC zWvAF6ZBEfBzw?uU+Bg!AzTPGB4Y7dIjwG1adW=TW8s{YfV<6IF-CEy3V^22dhcG`< zVGVGEPFKCg`t7pN)W7&htHXK6J5@kv*Bhcc3Wk^nVny!4f$7)c`jAoxQSr<2^)pD- z9pwtaa{1PyT=~7n=WN)y<_{^bk3oJD@HS?u60R9tRiH9a9(`8O<)AfQy9AFC{O!6u z>UIEN^Ab$=r|x^8uP!0BH46Knifp@W(pjS!bxd>?AZ)|8T01k|N)D%SIrOkV2`Szj zyk2Q|=0Yz=uznLvCFh0*@n63@PCPALvC8Wr=nU0LFxX!Dvc&3K{MD&9ljm8Rx*vIs z-*&P6`3#Uk!+} z0sP||HCA;q74^#4@I0ZQ`fT?1o5~#aJOl=uu0moYcNDXyQDnM2UGQVX$KXu}FQ~27 zr{?S0WarxmH*V6hLq5A5ulr3Zb-{(D=V?Fey+35X5(I(cK6OEIkTC`1swgQ-5-4XI zR?U5!)2!u7&h>zi)X!`IJ)cy`t_nb zhh7{^WiL9~+3I%|&X@1jtNPJJu&f(!{u0X*Oy-d3M71mi75pZ-L*CLS8@_6%=KLMg zvUmp0O72#%oO=1sg%dmEtP^|K$T8e%MLD^LRV>D;s-SI0dilsj$C*Ll3V1JP4n^Q+ zxmN@;#4O4pK4B`Q!;QyJGU@kXe8Y&dtRRY3VLYQzq9f?mZ@2^kEq&l&r8zy#f5;N;W?Ii8+o5DzNMqIo!ySoT?k+_GdPXiQ$|+{qfRgEvRTxM5A) zP-eHzT8{QcVB*J{^2cTGw;{j%)^gr!p@uvWD{9DFjrt=}tnkS%mjTn{aaDFD-EK@qR#$;n^ zPXt@^3&xePwIP`oRaH9riP1L_i54#*10)$G7Pgp+6b|!oHTUIx#OXXtgM#te9T|4x z2mE<6a-k=o#H%7wJZZ5FUq^0kXb@{hf-RWeF#%4=iWn5hGk`-;qt&b0^(23ZJlRL8 z&Eo9M5WSWQMRL_5l=89MXHPz^;?*bxtsh@i7)(jKZw#+jC85@PU5VIG>(6ykVlD1b zyJ+7W>p>Dq9j_B~g9|f7w%T|-9XhT(%qX99oSxP34ty>ta(=XyZ{0=7a=IgkH zm|4a`yJ&GNMX^Z8pF`|o1szQ4%rl$c3=2Z9hQbM#H@_7uOjqELcmqe)IDG5nk7;5M z?9$_SEfCd4T3M4}5KMu404c`IN6XOne*i)Av9gC%q-it@@eO_iM1PsnWlDo)!kr`OT zS`bu>NN)*rHgAs9!!|9&wl}E7;N+ATf$8zK%UU+6vsL!W6+Cnn?z+j)u?GtEBgnvG z(@9dX)END+>XCXzEPzKM4gFo`hz~$Q(~(iuIlO8Gx)zYO5o+Hr#BoBR40xX0|onIdDvq7!`mrOqda9lNQ7wT7QW%rx5#sm@4O4wSL4XfurdV zTC*;WB@jppmcsz$J#VYFk23F2r1F{2&0O>PAxpUIOc9S&n`&ujCFN)_iTJ#@S8$QDWl5_y!(LhPW=# zyU47hZucf2mnT}>a9s*2V4eyTi}_cum-0i%$FaH%Nrv#PmO-235^S-4U?J2)Xr>&E z`-QRoFG`;GIO+Z`&G{SqtIOU*bRr?#NTwzsJjg-bgJ7(Xo$iEvca7Ygso9*?hPD_S zU(w8rc!F7japissYBs){=e+D*#5b={d7z~qiX;D9d_MW#<8y-L6$-=$w7}Tjx8cXr z|2070Y0r+*lAMY|LmWJ{1@FG^#Wrcyl*tbL{T0-tKLy2@;w95WX^OMDLz~V7% zZtv%yEG`}wLQ*f?pXB~xq$s&&GGoM<>Yv?=r)&{|*vC#;E(f-E2v7Wc*Y?p}Z7R`U zWN`7tqj?VDXs*e8THcN}Fj}~OTp2B*)=wboXKfQRvfWClGxbB#i_>}`7R%Ue#~fUS zJ9J2vN=b>#wzG>>&W^o~Ha4rvl|d(Lv15FvGxCVC~n_t z=WO#9%jVWhv_$NIv^^P=_k6uQ8JOoH46>_VvPW#PmDcFzy9{N%L z6}HC592vrPR>z#3u08W_C~m{;^EDh7t^QEn?oMF+^Lfi?uyWjsm^?7LMF+&AGhNtn@vtKb zc3Veu9#8mvsOh7(t`Dz-EpJ9IE#|QAiE?+Y5y?a*Q8<`znTRN9XVjzIn?(V@1kIqG| zXqx^~>C2?srg5CG7!}8QQ(2>BVbefn^DL!x8FSMa9h;Mm`5gWP8AdM#7P|{(X&Xcl zY-NoGO|2O7Hzcsnt}7&t32>{EnRT8U`8wORjj0l4#Z>8ln_tMQNsG5mhgobX;bD$} zLX2HE1~Y%!;FHh#Y$!Z#NCV|tfnM71jf*e+z^UPl>2lzsL&SYp^|KUostB`o|)+bKe5Uvq=wQdYr+)(x^)@lt5Ye67!~JtGL@5ImsMfMsFebHS1SFS?J4qx7>JFH?L&2@?xI| zGr;&kq9m?vmT1_eT<8L2eZXOSDu-**Kg@sps$`zovqkV$1du|io)ixTh&~^w4E&li(dUaJvXt=jAU4~9V zD5F;SAijGgyW}t&&~<=j>Q;{0d=Hs{TUnyEIl)Q<8Pe8%JLFeGx9!VfNDn0|r`}@F z6@uwLKAF{fgkU{LUH-jcUEAZ6O#G4w`r~ZnT_|p6f`>t)}>+12ZFef@s+a&+~Y;#z)MLNb*1MSM3JiQVg{ zF8i`vB57Zch`u_^Emx+Lj}2-^JYr@>VvI`gP4Wsy{)i=ucDM0)@J^$)kj3b@%8+4| zEey~_?l6lZ?YQL_ldyWl$-1Gv5i_^PqbqmnB!;HQG!+EtqO+HqFqY~EIZrW7t$7sG zk9gJFiMsdR-LxFu?ab9#w#ua2%Z~f|hI$Z)@| z3BC-nwdk#+Npp=@f3MnwnHPyeYIGQ)F+AR85F`DhciK^fP;ObaLfoqeC_83tp;FV_%S*#={rpKsiRGzu8FI(ua>aO_vn-isK3k-zG*|fv zT5Tx6JIxF~5RkfZOYkgMxtFa+VBv!fslBjZ3LN|pk;*??@g)ii16ruikhqce{on>o zq2Xr-kIg_$T*HGyD*qIUpC*C1Dc8w9txvX^WYxc~&JAmY3~QOVSp)szKD(#&$xYE{ z=AY*7^}xs}NLdE^6QEwM+PhDC1ZO(kU@}#QbWAk?m%C&+GQ7ZC*F8&%%%*Qu4@Xnfro;P1}VIq9@b^@L4k3rq?|Y{CXi=r@QWf-wjvOH19AczZM^4>sloH++Balf5Sbx7)+s z$%#dlc=9nr@a?6q;JpXl!v+9K8F!ZT@^5Y~-QUi=2*Jv>BTdgR2 zxqL@DJzdk}<_izvtrKOiFPXeh^QT>rb8Mxi2{>hQt;VuPowD@N+5_ck*}Jk8a(Vf9 zmAlRyG`n!Q*?3<={TsHsrCi7NVF<|yi|JB6or3hWhC`{`BJ=a1Tsh~)q$Ovc+-ic5 z!jc$lFo2Jyn!o9EF(a#JKmtyEywweptX$jxB~bfu)uRrLgjtdSci~ z*E!ms$<6p;_2H5pI)#`uvD(8vGd@4T;#yJJR)709Glqc1_p2e*7FD?4o(;!I-l;@Y zh0zQj9fkuEbBwpK@nN1JU<`tH46P+o8fc<_I=Yd1or^K zX?OCN!pZzd8G}O9?V3o{x%$6{>GtG*)95+HBsZURKCjZD<53#d0{&>pZ=P24G|6R{ z4e{9oRQQqe>oDHO0WKnTb#Kz}LI32@k&PG)OqcZ3VEe7nc zdhhMT4Hs}ap_Rb4H=jApgV|bOQoM{YiHd~k1EW=3Oii4gi0bAk?)xIV)W@JoC$s&w zCo2RZjv9VnanYWW?=3?CvaQ6*>6&Uhpy|U?s!9MHxp@_f)Uuw z#MO--4HI156DJpXW=_Wh(80x9l>x?62}$uxtRP&~RmuH{Q>G8^t)HYC>ibUBd!piA z%3~MlM9$%5cwy+JI?(D-pybnbsmrJY+-{-Bw4(H^jOb^N`^#oO(U`S;yJhzDCAfog zCAr7D>tBjsuR3n#ZT~d)HevKdW)AvQ7EX+>J{4z9aZwSA7y7 zi{_y=W$OeOu-{HRQiC>bMDqOc{bCUq1Y<+8!4`7lYFyo6>9uqOhX{O=cU7yx!wPgF z_Ng*`DcqcHF)0(i&5c5P9VxZc)w{`X4rc_n$1tr@XgQf%D|qnrMrr)tpcC+~g$}SN znr$Ml=M!{;h?B}0C9Wjcb(p2@NvM5+hJu?O(GBugg^%p*^r{aA*Zvbko@mN@CICLs z`HN5RpGEC+R-L!G_(-kGxc}0+L$Ohwf1(NL>{1CN`)l znZg5JJqov5%S5?~sb*sfnN*;*Lqo6`Kt0b(cUu_)UZ5L}r~l#&jGhnqW|0G z!iwVWQ3{fKcxd*F(>k*I9qp1@mX@-+W%%eXI2jIH|6;_`DTk>yPu!<4vmzH>MxBG> zTD`;xhT{^_J$Fl%G^DtS_3%%u;aUcY)r>Tjl?Aauz{J^e_&R5k>YaxF58@d`4Hz)!H}GBWRJ zh6U^fH5w-B6WAAI^khV0uh9)CvWT5Q13c3PnocW6YkIe``S!?nu+tK(6G+HC8ik+v zq901BuS54=`ZD8_RV&`rjwX@LgrY&^X9NVX#rh!YS{+qXshzOY=>E zk?BsT)JLlv+kXjZ6ndfb44B$$(EpJ`(d}EwR!-v}lcX0yJoc*rH1`9j$HJFM{Jh?Q ztbIuehfP>Q;7FZh5RFsSupmu3ra3%BW2c9EjRJ5zD2F=8731OBs*ubvh<=!t<@&fC z%bu8Jk1_>}Cmh$J9=?e={Sm0wH6hz;2(quSkTPtYxot6|rRP(Z&N36a^ut?G`IOiZ zDRg3IcSc*iW?zM@gXeun&zR4VC4c0-pb05CloxA)e@$ zkX^(mMgEXHKQOF|)=d(F1P#lJqwE5iQm!{T!0Ol1DCQ-z9j%|4jBGFKN7J=C|GM}4 z*~FD8XRR^(P7@muoqQz-M15v7yMBG9?EJU|^CWPY6tL}vgKlO>F+GRa?G^-iOgO$N zCNV^P{m(%!Eyv=x>BMoE0^Dn8PRUjeU`(xuh5ar$z1uBu`mJ@zAupT|cY6|oYumH% zCw7;Ce+_Z2O`#n=f9AT|7olB8{H(kB*$p^Fx<0ft^;QCymUg?>M5a{DF18(RPy%d5 z-5F%U=0*4blTvM=Dj8E4_yA6cw#MhjWV_qGg_#ZB9m3bBbcrUIEuK}MISct z&iWGijqM>wceP1xiyG8(^BwSZbF9C;j>Nx)^}q(HNXPMK(9g}%zGPW5K=?MX64B!JoYOcXt=JeP)3t6u7C(gOc5&6Uor26G zRAhdr84n_NXXfK?*&i=t8p%sNJxigyB8NiRc`bm}Rw$cj_{&5LKjOY<$0vIQ5ybuC z$bZH%V9+a(XbL{QMRr`ey0W&)MNn0E=SHO!f}++LIzlg_{?Sl ztQ|io=I7cc*M^7A2r|>vNq^3Hb#=$(L`>5+6jBK>Q}P+w zLn=62RFt4cJnBHoQaB;!Cs#^Ak$%)%9aXb1NOLM=+>lYhJRLYh)KDrR)pm+6#PNVR zvBZ!_lo3IZOT*ke4nXS=|99-mAiJSdpZy)>Th0*_R2Zd@uKHxHxNNvxDIGD2Qdlm2 z@RCw}rSGJyLpQlS6?8dzg0qf;l@KbWu*gHG?EW`}&rnAcSh%RD5g>cIT!gwF0eM8a zo8*r^uB&hX^1%1h`?VXjKJaTWrS%GrW!!AySeS~AvdB@f7Za8zUKtNw76zB#xqcvh1* zJeZkw(BCOgvw|_i_Q`egxs{yzT+ijaxDO8%lvf#Y1P(|SXq7(F%9d_Ag2+cFulv3V z$@FE;gZHzTJ-*B;Bnp4hG3X)VS#FwlDKqd*W24eSi+R>6FRNWGF#@#tno7kBr@0=h zWZet116W0YVWFJJ1pE`q*>;{i7!89avR+G>O&X%}C|ByKtyObkXWfzy%Tm$wKtm#J zdrO36Dt}`QjdA|+f-mL)O9MMCU@DRzMj_YIB1oEfIRv$c2f#Ivmv*(m$yd8

+4! zL(afwdZgxIGpX@x+nJvNMdtIYb~ZYE-mn{nx4oKy;?E!`C!Tz7`ba-1ue9&OTx{LQS)Qy| zN{g9L(s}WE{`{Lt@3vLrC1PH*4c+h%)}#qy(iC$SR!ZW+>VaaYKn~5ERjH{fk!G*=qsFIoN*3Evd+I@YAse>%jKo7h@ z;+46)d2bxcDY6q9OMXj1!&OqoozZUaxyMBXf~@Rw5y~O~Jz5KP(~sh|0Gi~(dL$wi zWVKwx*w7;~zZPVc+?eCFc4Wf2r}BU*fp=gG%U}y+ zt8(h~1rCm)2n$+YXwxnWM-kL++9dmjc^EjFW^r=5peu67U zBY8ICQIW95I?9Qf={L!n%3{qt_wU@7WvB9UU;ZyV*Y|5(fxEXsR3!Rp11+xZP639v{ z7u2`6rOS%`Lj%KfO=s?y*C@B;moXAa%}Zl9HOH?Sg$s?5=B)ehm2>jrQKsOeTsxCb zap+ZnnsqlP>5+F{z>dxh&=|uT>RB-;tKBcnVuKy{!=cD9?87hs+Jvp`Q#=epP(bX@ zJYxvwUz14p#$|_<9!lsL&^IUY=-#0{`xNlKA`o69C!XNL0O|#pY>Yu++Y1`z05=I$ zM@&}2FN_fhB_;^~*@7T5BvVygtM<$2LXm+$lL6QDH=@{t))D~k!gebexq^spNxumJ z6lvT)_h#}|6fJ4+DiXqdduqU1V@Z*vO?eW56W!lyrQ%G43EKRnkAPoXS|s%OcOE%- z#{qq5p+<;_Q0aP^NidfrF;mdmF8nwB?PBy>7=iIW^Y$LDXDstU)Koxa|bJjZsz`-InqhSpVX39cQyt z>1Mq?WBi@Qa(WV*hgoxj-Ah>W%F;e6<%wywjQ-V~y8(UypJMs-_t=FI>O$DDHuU%E z%R%1{z6l40`(Cr`OaA0xgCMwc^9WcRUlxdtj8L3!Pi6xrs9G7X=Mh@PC*Nm5?KaRQ z4_kw`_6Ftd2R|-$lF$ZxUsl?b1-LRdTJATAB-RNIC)V?J_SVnX2nEcqS6P8#ti2Z|SY|qIzm3o;+b$x}n?Zhdw=Z%FrO+y9*E0%xCPL3)W&_2xz%mb*f2I@@j?h|5K@^@e z!Unp?lzwf*81Md42c!@{yYBWXX(&vEV{RjJ+~}%*F9+KNzP#PA!*5U&lpsiOso)7G z;hqQ?4dl!n^Lo*>@WK$T*{u$(Wl&)gM4|GO5@4H6|kXCM{M9 zL{|4T3sz@(V5!{l~P7%p919$Lv1-Pa% zk9N^y&E>Tx)o&&GL=JK2lgCz*@8{oiVTC|_X9>kT7@Q4FTLZD5RtJ5Z=9)Ht{quC={SEbv!`Q%?jo(;2ETg38-U#p83&e^K% z8rO*hF1?jA(sj=|if6jg8>uhn6M)vm zPq2L-#81H1$EdD~_qb5^NH1 zv%mjJE)dScmLhrFd=dn>tCQup#@L)#mn=IUQK$2!_FIn@fP^^%p`1@Q`;}1_x=T^* zYPE4-`L;<1!tJ>*^x2YTMzi033xqwCr_1i=!~;fF6ze&F511K49AVGE!B(WVav%M3 zXeYSu*ZMqTjnu~_r*B!76rK)7cg~NYxy_W~=`7$d zJ4_gs`8!O>g#+earJ^RYy&2{J!Imppor@K|O3n&Any>Dp2=kIyd2bpBm94^iHt>)% zu(z9EO^NX%w^D#B#&!3yEee{io`u|DD3>+snzV{UfsL}FFSdZ(>8;^ynl#p%fzK$W zs#gwJITI>UC8I8|hwQ-Ew~XDRyX?CUXiqlQh&Z3=AJ$6#NSj`v6Nd#~hiZN$u5meP z+Tr(49t8YrxUj^jH`U(+B9@nRaa2I1(|Wl_6!SED@M*WDW}O<$st_(aMj{H1s8z@_ zVaw){%0!rkVV17=_8e8)`&P{K9K{U#wz~#Lt%``$*HqD*9F+bw@7&60=j;B97|d!2 zXBrVvSg?W-e_=;rU_aUP2zR1Tk5!`4v06`g(E$>Eih=Ji9<0%k7)tBh|jqm~f(fHThkl z%JsN;&GDO4Vk433eWF_r^27xur|cpP65CU*N2$TZrvckg$fU01Ff$M#=e{)VgZ$WJ{b-^10z zy5XR1?6ov{G0#+0-=%feh3WD#T79;cWxb55m)4r<>uUNt&u3DnGdp}DtZ&*VEtBFO zOp4=wX9tHM4fTr@v4E4ewg`mNiXm}vOw>srjYQl|>91`Z(z+ANco+>iw!G-p07&d0 zhU}u51$O@6dH=*gX9V=P@TRVaPE?BS~vPrSil=6#n)ru;&fwM;aUVk>=kE*Z(^@ZFKieWN$f3&qO>M)nVL! z;_)=7&*do?%v9>s*?Cq>eF*B?vuzV%2wp=LWoQVYkRse_UoUb#J3^2qmtZtB8;kd0 z(ccb`^sa7oX=Cl8NqRM2#$Q*b4%J>m#w8qLBPAkd#givz_Iz7aMZ|AiF~m)@OKbbt zuzRg}_(QjOIeIz8&Z)7GbMO;?9S;+B#WsMxM38FO#rdZ#UNFBvVuqwI?~oqz6;P)Z^NAe~&BF%3U6-U#GW&hD_5)XoQ|;4) zl6cYeiLykPHrd~hG}r2yDJByGUHd~z6^aAKT|^rOjm^S|AGRSC`h`7bIsE0Qa8@B% zI9lx(4bX3~J>rhbbg(+9jHro+U~#1P=92|?kMWui8PQBE;_K}kw0iV0BUKHc1Z#KE zUQ)#DQfD10%OYoeXW=hFnw(ZSqpe=<{-=BLl#nme%!Gxl(2bZrjVpNvw0nu>51eJV zCV3tl2lZ;T0UQ~H)21K4bT~4;m)$pAGk4zFm1>EK!&EBM|ZXjb;EhK<9Q{()@9f=|<@cLU8Z zaA8R49u%uBHiT%N^t|--*sY&VaOBcAF)5o>qN-nF=`+JWBRA4933{?-)y$ZsO_VeK z>7b-;{8OT7zuXZJCx9^&%3a;_rNJ1PcBOTBbnLXt{-VX(d#2kMb&zJ!fDwup5b#ws zjEgu?OE#>%1zR7!l}ll-Yi|iXZ6A30rcD~V-vN>i8+2*2D(X1vp3W>p>N@nGb^Lln z&7Pq@SKWSY-G+hhp`KGO4d^TI+(5FH@V#TCS+G=VQpruP5;E)(Nm|bvftv^8WD`qh zxN%i3-?Fj1!sl!GBPYD8622!h`C#>jqFapIpM;Q0IVKs3 z9Bf_=Q@W5&4r8{1suXfw5%GS@V05NRd(+9avn;KitPJG^2dd8Q)DA#4-us^ zTb9q>;Ef&<)CgXiJYKeTyl^lLHE^MU989#tM(y@F2>4HFf@Cwq=J05@Jv#5uKkp2T zn1kIZ@p>-6Mm?W*s)Emj=gvJj`U!%dg`i_8ox{F7{kkfQaBC%|rV?eUH;v7gI(itQ z6A*2?4ouu^ntPtQG>%NGqymf9W`n=IR%Ve?F&X*P!@`~Y+pUA^%G9oiEr!zqvls8= zqT^|d&8p@NSonD<)x9!dGv$nC@NRDA36fOSLgJf)aAv22`N^7~f0K8?TaTUJIeDS; z(g4xO+sodra~<@t&@CPKW|_g-Fv8ED2&(spV^GNu^cQ(}t&3~uJcNAQ*>txL)sk_w zO^YybguaESq};94ck~2tsY-{b6~3x8v4Dp}WL!vOzC$HTgHY8lM9m=GNYl+|(aCAa zLO^BOCk*32^`nhZbwd_RO}~6+O&df#Fq$}-nsUlT3ss>uJCB{0P_F(q$egj}t0Y|8 zraYG#Z^+2M*>b{nyZJeZ-%iv&m%=I28B%PXzBb4%Mm-BK5vuAer_oroSQL z*oV(dZ_;62=N_+hwvnuS4}Ett#S;Gpim!2u7>!McZz(qp-oq&iOV(yh(dJc08iU|c z;Cz6@4J`=w2=G?#53`v|TnGXx8;V7E+1(CSuM0}|j5`$`^l~1=yhi&Y6fCBcU6eom zgf`e24K@vAp$sX`FrsX}=4eIcPQ)p{MG~r}Zv^eJu*z1h(9qGw&^w)(5rhJv-iCpH zh6o7>gsvgQ{Gq;xNV`l+t6#Rj_Sk1w-gOdyiF;;(yuQ=zUW^=a3e|sHawju^)B1G+ zxi|eS)2DEM=(`mfT4_Wji-=K`l(L1HAGqR|+@ES1aM=um^4E(GXcm#6xlIFJuhYdU z(_ui9pKm{J9i(mrXVg;Y-PcRSY!+HQV#~(G#^{k1QY`(>hlpvZ6(%e!iTJs1Eu_AI z;$mT<$$JRuLS5*HcuHJeC@BPX(qNItxm82(!`e1#$f|4dVJU~FrJe9J{UVz{_04b) zWNiLuwtagXfa1j?v$|4D8M}XuJlKql*v;6ZD`)o)W^OQ+dEox>3AnPLJ@~#I=?0SI zFsgQjHS_IGP0i{%4GkMvQet`>kx=Iah&k;=wLV9F6Fs5aM6!&qUExpw0gmiib|D0%?UvvwK+{?X#me z5JcaLv+hs@IU1c4)-ulOgJdvdD1y&Y#&dJr%4y6$8r2Q5Bj&{5-f2?#Dv}shPVP>7 zPJ?<5#j5p{zoS(iQ60e4LCMs$8Kfr*vIT`x2fdjQjAn=o z!0T*91D#Yk^7R3DU8ELw8*;Qbn*#u^lbz{pmD1c?6=rB#21sBBoLdp$uUQ^`I%9G0 z|2xE91K@SE#hK?;c_?cDye_i11JFfS1K@S(vVg6H9p{yQ@w(m>a=@P9bJ`EQ4xp5x z?Jr&j=n}U5#p`-nr93t@|Ap59PW@Qx|woLwCGcf?;-|@QtD<>=gmM8(75D#=x z2RK0maN_9GSp&d{kKuouDEp5SW&d%a;lG@q1nl{b6H5PaLg_zFSpF|gr~{k;DEpTa zlmHw4HS^&_I;{wFe+vJSOl%44;TE9*AytTmcT!%M#uj`SsYS-LYL{k8e!vp|wQUO2?69CBhJN9K5BecN^CgM8(R!K64 zjjCwod&|IYhMA?H-o}cgWS)yJYBU()Ai*5qo_FXwHb+lhTe3rJ?apk)DFTg}mgnA2 zYL6G{$6ZZn2K6K?B$U?WqJng*yQ^!Nvo5OA6yiw`dR1MxZ>^x&3Y8gDy&=8jGs^)# z+tW$S#ceWd+XY6$uU4*Q{uxLl^iSG5dNl&+&A+6QRE;1rBq)~#4W7=gmajRZ+`~SS zWb>G|{d>@dk*)(oOPFr+^oU{)2Wpf(5tBX638!&0g&ib5- z9)0&^SUUdLm-v*j1+Rl?c%Gh{Ko};W>;s*{g#z2A+y1o zLq?fXK4nKrbOT^tTi?p5$jdA5!G8C;`t`iTyGNo(aMxWU`GoTi7e%9$%>xeT&;3o^ z9!`tu+Y_5B?JT3By$CSsSY9-&KI{>iMQ&n3&_O8C z0H~y)eF*|cB1&M70B`@)L{)8>OY6GZ;{Fix7`HduLgB7tdZi1&kK48BHbxA*^MmaE zZf;!C$en3EzM(x=u5>UT=H{YyV+MlDTv7>k7jS}0+{-sM1Q$O?M;0=ZZz!69mCP(oFGmdL-_ic$s4 z++{CQ_SWHK->dz3}r&9g?k?gLdW`!}6ue5(7_)Az7xc@N(i|s8c zyui+Ah>wp!^m$nvvnt|fZ!ngSMPuN|m&6^$ zg{%S)K1MjOx)+bnsIt}sCc-~-;PD|6t1LNSW^{Gvo8dsiRQA6jbnylGaKQLqIAiH< z#6*HR;1qB3;zDv?uvK3j_wq7B-64TDY?D`CvB?sg#EwgYj?r?!P*ai2=w`!#jt)6s zsPyp%`2fMaDn0xLt*wE2pV@=5 zc1C7Tr-PW$N;5WFhg9bp+_QLJ1d88Bu6cjw{YC+|A_52nq8Il4Espsw-ln) z_Suv=a8Xx!(RiH%L-S$$*AGBEDQbQatr*Z#x%Y^Oy~oQlx9{ zrnFs8IK#ebM67Yto#D&_68p8eb3T9hcRJC;^l!eeHveSy=l_%0Us(ur5xEB15Bd!= z#`_Err1BWk!8Rgtk}6)2T!qoleJp+$ZLtcfX8p5WR$^-k=V`o*%GH3`$+{|X>*VA> z*w;1uoB=8lyaD^8x_P5x&m5~~^mVm0&N%1g@OAdbEK4tUYgveG0Lc$EHolw?H9HJk z;qpkE{N`*t)PgKg!x?FmdXL4$+;Z%o)!q*HcYXlQ@ATGI=7^?U6u>*!b3eRHSkwkV z>x4XG*>KXoBAv^lCHX#1{-MRwY(#uvjNHWJMCAO_4Pg4o>Kr>;K;Wue3+OqE1&-u# zYO|FkT#;Pp9Dx3LBOXZ9D|*#9!=2w0Eq}SJ7lW#}B(F?FgS>_i0W-mIu#40!=zgA&bG2fdptS`~Yn3DmIeG zwzJQ*>HFL3=;5)sM!Ayq=j39tdDycdSfK7XCe4P2<>b)`yy^( zovV@3`>MUBZcAZ82sy%&?@8wQt7jv{`Pv-|gTNdK+fx@Fhjv`(sR5)@N|Kx5QzGNX zo>gi^kC9gwxbi(fL7-ONfx5Y~u)l)s#u8csMHuJ(AD0+*#cu|GDGK}Wn#)xy>r7Ad zE}G|-c7PuDq}D3up}R`vMcu*kV(*j!2%7i{I&qJnEOg@7)ba$4Dp0T>Ct}@tK9Kg1 z^$Y%CKs^CP)N@P%=;n^+cpxVJ8V-NPXz|AMkRL&PKNrv>QbenkheP<>=IhjSIcnUf z9IGQK0uov(Z{&YFxS)N?T@UBHwha4(wZve%a>{yWv2`sg6yXtdmX0nyK^>;6*>fAX0#gXt8ED`4JX~mF=#DDfm3jQsGIKu^8*Ua9IuoHVngi8l%@#t zE7iuYoiHJYd@@o zH@_pLg$7@G4cLR&tZ`T*erm>q|Nfkkm9`Clz|jFUYQT~ovR~iRGIE2t-4VwMau3fG z>?Ng=zx!>Gk)(1%WN>G6d-LlcOrJSQ^t`s!a<*@^D;#H@wtL+R(oub1_IL&`JmwWr zx6Ub9SdD+CtEZKbB<;riL7&LR6RITEw%?he;qV*big#!C42eQ2G;-a!z`0rWpCIOe z86t|rmo0L(>wID=h2Zh5_I-3KELE&?vUhZt)S=6Ezu!qBh^J{ruLDk4_7gwRKhYaK zc8ZsTPqJVFWFPB}5en)r7kr6Ed_*H83meR@{aPRY{~HY;Jetwi(jBxH{h`mFpG}_= z9?SsG!beV&KeH_<)6@U$22JAd{)A^A#NKQ7{)h4(s-#C!C|X@pwgRJ0eiaR#^tX1$ zV3E6wn=e{n&tn$?M-5DHRK~zf>GI=1iU#pI%vz6;oY;`#tGIOaUvk~KJCeS@1vt-x zg~kvjp>F>A0``voot>sb(M0IWNoLFK960&@J3{cy-8Nm)m)Tkpx6`^d^ITFx`ff?9Rc(i1|Wb) zan1|C`q!<>u1Dx2eeS<$Y;mK zXM`q9j@;+I#|hpcKrNkj2=J?-{(^`hq>hbJtuUDZDV5bXw~IQuLRe#bn@hue8`mL( zd4k5i9b_4OvaEMa_rpnf2`TRH^k8!74rstG<)fW2M@-g4o;ngzoz&M443Hau0d_^` zq=L3aUT-Nb%F40-Z^H#fixma7Xt6CTC;@KRHce!DJ`AvkpsGLmHZ#xE4NdU+uSI#X zNRkqAzi#<`mXnwu+xS8i>pIa`Lbbm<1nz-7oDJabUR&kRt!2ho+|E(1Ft+nNaT+VH@}wU}&wnH=2X zi`nr`86BVt=Ha52GOVl&IF4?=OpnCe{^xh@e!vkp@5;Cl0bbnzZ20dPhJECk=$Sta z~j8t#QZbBl%Vs z@wVhawrX#SN zxjkBBf|F;mJN2GyLa%(U%i4Lv^6Rf^OX348P|PQaqU<*lnQx-k3`-l5)Up zm1~XeM9a*^6C`lTZ?s@E=QWo=_O&+`YTl7%(Y6Ka)6}00Tpiuq^x#Xb7;p@t&#Gb) zeRV4=k1c9}NIx`b1VWk;l5+YGD6^mu@R)HwANLVtB{frvjIrBQ0x1a`8UWwa%f}ZN zW#kHSSvK262Y+=z@I_}9i$G@u{HPv&BKwkouhJBG)ism90@b*vf( z2EXM?LRS6Erx?mMl904Hm>`qOO7k;asi0rl=ojCC3VriTWp;x=8A=t~54crKluWf8 zRtRQX%>p*m{NL(>*+i*kO3+Fw`VblC2|S(Rh(U3+pc(O7MAS_jX6*gqVRVcX65};8 zakUM-H^ols)Y^iRmZfG=8HWu|E5gW7>OyX+&hJ!_ z1t@QvnhpI)_)%%vgtSaLTMOF5@2nPC7q=x~*Dx_^7o$|JhR7eu2OH|KEqqF7_NtzK z;>)B?WhsEBOyr$fUce1!%9BVS3WV>d#S*zhB79{hwoG5nR-H--{)59PD|p(ibPEXI zSU7!L9u-nF8gbCQbgK(`n_){7N*-OwY$d!=Uz+S>PpAw|IbM8Iw|JvW9+v?RP9H#dk4zsi`=yUMZs*ZM4Tufe#xzLN))&NF0+(Lj;%ykLOeY+T26{cSezL?EZ(gC ziBO@`wBd(LiQl2Ld9ea)f|_J`j@+LiW(70UoIvq08Bbi95>fw|}YN7yl3^jK`ux6{`RoSP!uJ!-7v_A1fDIANv3*YuW%N zb5R4F1k~%N{0WiykK~LQ+8bQ4g1(F%6OWgJN{R4YNhlF`qSV0?IrsSgsaJ=c=@ubpCxzSBI-ObEE2^!*gn-b3N zAM0jK3Lk5LPx(JRz^7aT@G1XL_Q$5AI$OH804>J6X(l-CKL-G|sT%!D0UH%;66Hqr zrX2IT4KySG?Ib(@EY2{ve(2v^uh^8EeaZTl3el2xaY}!=-hwYBfPLOdy#*h(KyT)M ztZ2D^>;uRoCIw1V1Qi5IfJX}V7R+_Y|0Ah3wxtaOD3M{2?01SRRNdEG;26xdT0{wl zN1G5j?Nz$9u_;%=*86uNc$y`@Pu5SO9S@(rNn-Hjd9@Lqj3>kO6nz=qVm)|Lp7YbS z0#Qh2sNeS!O#i~=!w!pUa!<2H&BDlF?!fOS*JV6h9e1xTgYDMC;?+;iXr@2ak)-+n zY&|uS&AVquTsFH}I40zlSEC|hasjIlaccjCGSMxJ9}XJmTa+fOWHV3S$6Y} zOpQh7zTHn_BPl9ZjMlpBw6o6VQF~q;KUY(>mm1}7Sxox1yf`w{%TSen+d3Ro`2A_Y zSYRv-FdoVv z0G!YJs{R_1TZ?v34wkq_rrm{+ULGHPY?DEyaemGQIr^XaqjBE^1`|#GO!DOGV+%%B ztnzcP@Z!UtEY#~$p~!PKd>dx8w>Vj-frZ;&SgOd-XZ#Uq3G{u=S8g~d8rDJN}Z)0c4yu`NBELj!^y$h!Ypbm zdNNn9PK6}j`t#fHm7RIULIozIz4;3{G!4xTqVvx!U!0TKdgW;?DK};g)s`A%M)+pc zqf_4r7OTd&=^_YJ>UwP|RQad(-B;%AfJATj{rSL2t1)sK1vHEK(9xWq>eE(It;{EL z`vwPtRwulyaLMXN!d4a6w&7i6sM_6=@2cO=$cr;XaQo?}#eyLSV8!#}VWNPZng6St z>f|s(_{$RC8CJcc=a}Flvj6lf>@XRayG<1tY zFuIY><2mlMsBeW~?j?pksF%X<4j&6_Ds<0Pg|1(K!ObEwX89pVkewWr+1OM~>La3{ zW?Pt!W4^Bu!X+dSu|`Q$rDa@#yC#>{2B6|uL<|ZFi+E4qkJSOSIhjFWs>lhjari85D>D3Xb3` zqR~6N&MFrbom*?hhPa+WL|RW*HG*~`#ZvZfL`XE)MgEU~r%#;Td%)8U^Ot($r-1c@ zTy7HiDL@g_Xdt z7@iz~iqj{egT0BEE?Xt_@h$iLhlb_;2DQnoDNt!1uTI-;25pq*3>7H%-(0G}`m5x=oq0wQ?G` zlMnX-TQ#^7WdF3X`uV(Wx5qXRZ4;z@cM!`)=Hw*Aa{~5x^?Jo`@3bF@z^N7Y{f&ut zJ7+f=I-t+E-<6Ax)GNWDfVcXdIh{@y0x5w{{zgXMfWmpR=X%xzcb2Q<>!rb0_ARum zpue@q7kS;3e+P&lgXg|6!Tzf#EaV(8u?UE1TFjSFj;%K5S#A~%VJDN@mXlMR1^k9h zV~7j-`bE6=x=d<7Uq@m|;nS~tX23|7f>JpQH{!!DONyb~cWTg?6Ex3t;@xDBRkn)0 z9&ij0jj>bEaLuLXskz2ekQEdRrrJtMm@!u7_e8z0D=Rv9JnV)tgol>C9{`}BlP>uSS8)HmhvB#w+MI$plGXNG^}tiZ>dd>N>Wzes$F3V-y*=dOQ5 z5>^KTlPl#ms@J551II#9)&@L{(%)`HQ6Ze|9^9yb1>vvk2&PQ;n{U_nap=M z*IZ~rPx~@XtSW$m@MA_KM`z}d5|RjTP-IIE4*K49z&urGky?CXncLop&$Mk1&jzQz zG)A`k_fNU}Luu71O5yjjao2^r|&4APVxk zn;DJVAPqH7neP9kZnn>V)y)Rf`-n#Joth@w(WQF?lWzm$qzDz*43mfmsr=woeo^eB zkI1QK3;i)&81tJz56Bgzmn6{<2MeV*=y{GYsL2M(J4;@>$-m>3EzNNfXo_=~XkI zmW!#++~Q$b@n<uqwX9Zkd8D7Q%(G%OaOp{zw|@&2ME`_6I^PF>T}|k3mcP3*`z2 zrC|XRdBL)<;jeh%0-Mp|_=Ke^&^21heECPmiHcm1T;nWgrii2nEz_*!DoWG^Eb*|s zROq&s{stsdUR8T_1GtHNsRhiAibXOW*9B5%Z;Q-vV9y)&F7=klsSw_bPk^k@_oj~& z!~-xOM0BoEK2DO9>t{NGh?*8lsDeG0AyW)3m=QzGP?!`;K%(UUysjFoZ(DaKsv2C( zH3FclukuolOQ0~b5C0)qI%osqX70AOgBh#-RSvYftVtj z9RvAbMn=;#EWhP!Ic7c9CmB zMeJWsG}KSmo>eqIEJfTwrf5>tP7Rz?zL&r@Atd)T8m0kT7>_AmR5RxN)*?K!$(;IJ95M@~GzFMwbcPN#*78qxlpGlWkD zLTG~V1|zhY5e3wk9JGt*7bY~pd=)IXF?q#;Th&2ZdMr!(C0k-R54PKefhJhlI+JD{-xo9N^*Dk3Qic}9cxvMar@n{! zjl{x2cR`tQ@-2$7HXxtVe8=R(6n50Z5ETF>SlL0xvm`&BX2uc^k7NRxe;CFHon$1E zpa9iJRD~vR%hYzQFQ}HDH=%f0kn19&lS^b+P#r-qrRZB`ekh@Jy zWmbS-ENIxbUgbU48!iL!SCUg}G44i)PF*oA`~AIX zh>2e9_$w%@RExKi8mfY)uoy}9?-7pBI$Hr=CE9|#H3Ef6Ag7^eaIkNRCig+pGPw?2 z2+`5vrbGLU0;rgvEAdAlwUCO@caSr(J)uCu$?=iDJPm|*5llsZu8Mn#d7>kosl27i zNq8y06cj{as>&5b)DwHBm4M{(q?7!~ZVdER`F4_^7E|a7@m-#)x)5kmu|2g#4RSO- z7ww;%-BchSlXB9Qmm@4e=@;6UF+nvHouJ#m!T>*;9fPS#9i%Th#q8f+IC@RR_P2a)T440N^uuh9R~3 zG-Jgv;@VgT{Anyga}lG=ZjvJhJXr=_Qi|FETGvcie7j8Gt@Yw4LHv`ORz*vpTME@- z@bYwaxJmem)rNJ&t@ur!tW@t+&@oS<~3%lmcFcL3HhDrI!eRV z`*GYMx6w zx0L)Hzn;S-9BtgwNWWUzRcJ8mi84vtK#wGSA`635gKfI)L=<%>ywMt?CGlETeyJdc&|nOa`Ll!+ZrEm*iB;??i=ATWX)^t;5yHHwz4&3tJgk0@0;fR zqq*MTdW@zQpjf>HV_R8YdE35_SBEpIVhc-KtFVnVt8m%?TeT68NtYmraqF_@BEfV3 z+7G#fFkN(;{FgwGw$^_jSSw{p}OYSDV6auJfx*Ye4ex$#;E=Io(l= z+wi1_e?VA_i+2!KDe&JQY_ecYg3S!yUl7)a8C0-)9RR`-HrZZyQsW`~D&?#gkuY5; zrQ5yry9yz+F2%l$;VWB9F>Gv&ZUtVd?Nl3uu%Nv&SWG}aXfpKrcKQDO?7TAq>L~gG zmfjkl+6aliQDDU(ZEHW(61s4CmRr5+{6U39XSvd1k%x6KO;Lxg){CO)b4;fWgO=A8 zPA(Pc**De}3$uC-kI9!|{~tkjF{-^!7-}sDnrcimk^74Ax77k?Ba;JnFIwQ18o2Z5 zB51ABk>p@!lx$wrWH7h)?;(Tbj$R+N*q4cB#r!#AqFN{?G!+% z{QBZS_~Cb6d;6q-Wvj^(68u-eCDL7t2s+oYU?$@c>y>N8k{KzAyjf;?))9_+RQ0G+ zUJkBDbw~%Hn$IPC!deOZtJupqID@ws9g+2u5ZSPOcSFrA`w7~G5wxZBn&@(aBd%#} z&Wb2Un*`_R&1H&8;gy0W0z8;+fs*tTtBV%xTz zlZhv`ZD(TJwrx)^aWXO9WS+Utz3cnqTkD+a>Rna8-o1LSy?S?7Rbx!UfNtsVaYzab z=qPa+F(k{RnlOGHrGY&Y1it298Y|k?G&XG?7DD<(IB$uRV<>2rdp ztvimUTo0x=GWXQ<(m%&Fhu+q#ZaTKrXZP5)VL!BGi(X!shug*RldC^U?Lc4L%FBxlNve9D@RijgD zartF4pp~K&{de6Oh;=;4p?esl?IP3cZfg2&MoLGJ#D;d4jA_lvS=s?J#{d|6xKhDG zY6em8z{PP-UNH-CaD$Ove1$E@a+%Wd6Adegr`8?ZcSClmiPX1zg;|7Q{bZQaL<wR%`{6RigHI*tdR9WmwDq7^qDVW_pw9${=Nz}|yADlU+2h@j@^ZlB8~jvL!bGJ7+$cZT6Tpk68ASJSt9RMb3B z@O2+gMj(O&I%b{fswmjG;CZ_F;jXHzJ~b7%armeQ8y|8ym9ig> zNv;MTkuKz{EOm9@<_%wX76NuyZR0_3bvh(P(#&dBR zZg6x8OZ0rbr!?MK56ShMS4WTF{kPbK%&nu>bGREYPn>^rlK7h79l93l0wMC}g!AgR zR2Rm^&xZkw?J~X5?9|CFAdTaf@Q;Gy_~jG6>*%w_bMYe8R&hh$`Xq9w=lllVFa243 z@G!wQ>W|5_x;EOg!UuZ0*U5s2j>@txTo-sEf9Oro_1+cXL=uRmACnzbx!&_`=z(Op z-W5g4Z|MKlrnukp?C_7D&@+8z9?=Py{}!1(lsJ>b2YTZ~)|KkBnm6{=d6Q!uM=<*m?o)gF^t%G zVht8~KpBOUsi<9K%Y3V@Ewc=ZU~eY$&O^ehR{%-U$gY=9Mv&x=iEk{8KFuu%lr^F| z%V{;LlwUpZ-UyCGD6#ckr-S5Iqq-ba%!&@XsVL zZ6d&`iSH=wi5z8tVO2D!vaR51^@hiLdzrNE8J{d-{*p45c%M*|=l6#FSmVP*!=+$I$WtSXG-T$yx68~m{iyBf_yYo32CM(|BRO*U zcd*do)gJz=_s5U#|9+(n*_AZ}(Y-&#f5ZRJ{)Yd1At<)4g@THIY#lIyz5Q?azs=TF z(Ign0hWn1vH#NZSG}uEnfvuUZ-lWq1eHFct>>Q{^N2 zpQursv|6Vm4SkWi!X&6;wzVRzfw^Lg!tE5qU(6g3hZ0MdKxy{p587yTRAQ@qQN$0r z1i{#2Axs^Lcw-f{-0`sQR5}z&cDdu^^vyaP&*kwNleA0M*kuhqW-_OPYAU2RJ7pzt z-`j}@oDHO7JJJw5{)Bd1clPVYS17|PE866M{Pi^?mPSmjT%S$ULhx>Nlv1+|#Sf@l zryBF%X&9|gSSEQJD7&kfVQdwyTe1N__PtfpD!rOC2BUatmb^&G%53}YQ~oS5qOg)^ zkq%~Oxl3~BL<^b1<+pYpsFsr^tD*=lt`%#M;V*|44J5V|6`C+Rr6V z;-Q)uOvq-SLgpA%rf8%x0&fDZI%)UP#Wh;~h6Mvek`FAAC}uaeSnY3CgvaQ)c`rz~ zfM0o#o_v*@$2Tdl<9WYms9(>})U=nSqva$Q3-cCk4Eq1g#*hH!KL5VvGhKM}HclAz z(wjcj;bZ+iTG%P!C*>wD_z|3ylNZyq^yTWLvre}kR#AhiG=hnzI(60LFv|o^-oX9^ zBdK$5a`1-}UL_u@YwM&FNKvH}p%E$O>%1 z+cud-KAI~3E2zKTSg#DeLyt(M=+K96NnBB%L0bhHpFvyIA&>&h`IETXCX5IF(kx>6 zy?mx)@c5r}47@=)XxPa!yS&l9p`|1{w^bbR6l4ibT%2sBhU*VWV~5YfS+UtZ9CO=Q zG}c3fJLECZAqJq>!ZwX6m$9r3SY}%FfaaQ))W|Fci<7^BTZNy2TYJYV&>Z&RbUFPNO5Fmo{xhPI zvi=s9?GSUf81OI@M(}K7Uxvrj37nxgkEwY(g|aSlqbmX)rR(l%XU>vvs1q_-&vbAI z1T`}@-?uiK*oSPWJ>IhA7=J4lo^QI*baF;G>5yvOg*LrVNpMPJw5o|r$RklR7xd;D zN@zWABm-@cK(Pr-3M(FxaOERne`Cjr^akR;tZc@O$JI4(NSH}YokSB8OTnF)$vqX1 zn(XfV;d4xX^eEH1IR7P|Lx+ICYXS6XPa#R96mlOZtRhB^&CXbB0aOVXXAq~#J;ru6 zt+{8nP00K=DAmX{Y>%ZM&J{5oxx7Y!Gk(Vdm3B<65RlYbLIJsi8oF)$gQr8yo#D2h zM(+DIcyh_}AV1UWyX^>^avNuD^5seyeiuw!mqY%t*0XI)_^zBu+{;&I{i?Rq9&OyQ zC}~kBj>*1Uy!F?r+KqRvpU-+?CvV4z=xwz$${_F+(fQV9j;659W@3-D!!AK6;YV(R{gs~0^2LU!kG-V`zd3&i7j)`hTF6mbr1`8zL*5*Wab<=0*80X zKEe?c78&RMa;JR?7?fMivnXRF2)n-n>Y$3>guZs*CxfAO#!#7N%UJ2BVDNE81%S?m zt0sYGX7rJ(UstWFk?xDgMt1Wg)m|&z%k|YB7uIYczjbPJzFcT)3?}8c+WsHwN3a;$|71q`0c!A3rr6(x;CM z*Ml6i+F-THgHu~Qb86@v)Dm&E_#$vH*f(TWf$(&a(IWBbFu}gBI}Yn>8jt1t3JH{| zvk8*wO_>{qlE^qmgcR#op2hF`#{67e82&53zEC3*!9i`{vVhtSc_@x91ae0lz2cUb zc?mCYTWslbxt7D0B_7NVbAlw{cLj#3GdU)PW=kFTi10VVhv^OHT{yVDz{>B{ASu(} zI;daWMJlBD@tor^!oW8Q;&~$J1A%o`OU|?tywSF7u8N$cghMvGdVDt#`_BpBjsUA@ zi7Ko%^NZw_6$}DLz2;-Sf@+=&hy+Ju8vIZ!{vXS-*x)ZME2{|GX1ZGb>Nr3T<2IJ^ z#Sp-}H(1#7WxzmF>qSA4_z24_@wU@zg1(cu-=cX@&Bx~tk+r;N4s&J3VolA=sV-0T zva}>X!`2^5hqoRrkqAt}-w1~D8z=WNV?o!cHYt7qwS8;f!P&-isAoV73GLQJk_Iy* zl4n80Fd(uI__odM5-x!%qr^~BOD~a#&sfq+-d6xarovF-Cy@vlr_5-!7*&hF5_0R` zRir0-S8kq^h*RO<&6d42Dz|2-Fh>X*7V9(>?16k_}bp8g?1<_6fgTsXkpC zVUslOwJ|sN+040g5!Mw6Azh`#mS;o!xS5yMlGfZ{$6j1CuasRV>~9INtB$GH7B8B0 zaWN>4aW+YUmRJH)f!W3>5IT{iv5^x`(}aPxN7WG)cde9ol9rDLIy6usbir<*g(=CC z0P5dpje+A`BI!e!Cjq)Bi2<5jFOQkEQoE331V(5&G0YRq2$NV20{x{xMbni;dh-)lA+f+?)Mwjf46A@^2-Ia3#AEF92Q+mV-O&V^<~rv8+2+R9Hg+E;2EY{ zFpsg1B0s96wF>bmR*wRJiO;IW6Lvnt^p5BJhmo&Q;p5NL-QQ_7Qj0)s2cx7~9|(9B z)^V(`=aJ(iN!DJ;rakg3Dn$ z>jQ)D@Xxi4U(qo@R^Q>r@XrN}Um>5rYP`2);g`JIv-hAS`t)A@I{5krT-=Rr5D5MV z(wRNffQyBT_8-slv(S5^Z z$Fhk0pHYQ;*$LV6=rFI4(|b$jFI5WIJYl`R<~f1e^qRYv$J5Te1r27$tV8E2f@U5=E4hkn*z-C6{d0Fb9#MyF!7K!u7_D`uFE1 z?&_nqwhl0k1?U)Rcl{s_hx~0<*NI#K#L+n zA2_Q5WC~qq#&81IfD#51u{OAQ)L%-j zTJ~IGRJ&(~+tu;smvi!g%?n@iHBt6Cq){^2*mV*1qq7=T->U`RH>~L1gF3a9i?e~e zoTJsV5jTn8y40py!VI(J2OlK#7%ZpsRfkMYkul5zh0tmE$j3$n*ThBw3!dz3Gp+S; z4G-`!1(?1C?&O5f(5VT{FI00p8!PD)Mw`Vi)My$~p<9p(k6zB~k4}HK3RnG>fS8I$ zHfu{H5U+dU*N(5g2Fad#Cv9!WzP%_LU|R1SuU75zlz6NZPFM(GAKTEf?bfG3}J9rdk0`XhxPGwg^~ks0yqp zE;M?cLWtMPx6{0RI2Xwfx4qVTXFXOhZZ;`4w*IYaRb#lL#Arpf!dQqUYDOp8JG?a9 z59j3-;U4ML;V%S{9T$e_m8-KnpUR9=>l4kTF94m(qS*hP8%NR}kwJV?na;LOQ{!H?l|gZFKhxA#=U5)e+`x!ugi&?zQ|p3}b8G zxJ2bxB|7{_udMujh*^=&XBAT4l4^}?s6Z*oCH#tQAc919yi!%20RD{WVpkUNo zKsByqkCb|Zt0RKsH*JVSoM5`tH4qr+u(gn45&*Q98?7Qnwi+wuK$xlBY8D#nj;zJ{ z;-HTkq9j1Ute$8LhPi#ri1`P>MHJ?~0uAX8sEbO>ozR$2NH+i|NIUl<(1mTpzrTPl zfE;_96?!0Inge)qBL^s2gw`@_5ccvM0?f@u6Vr)B)fd37>$|j+P(B-ZY_tgvb$Lz# z+D?|4f-?yHp#|cA4FEeqx7BC9`kId|kSmb(&LZPP+xZc8hVC|Oob8PdJN0@) zMO^xiD#l0k%ik7gG<$%e7Xk`sE+E0&Xfz2k^;rqVf{lHb3XoY&WgJ&F#~|I{6ruAc z%|((DcmA|J*PHqr=$kqpkQpjt{Mz%P0|AuE#;x zi*v{TfXzop4!f!wfM3_`Kb_}#ga`uM`}ehd*x`n&N|){h0`5USsy%;Oh!Ua3*sMv5 zi9ZRv=|qE8-;ywnWTLfXBSJ>1#fx2QnvMu5N}#0{O#S*tdCSwGZLL%-1peG>{~Dit%UQ#Y)m@^$i2uxwhm#AVfK148OF z3(?G)BxxsWm7&SWKVn%>xg1nUO>3MhD2r{-()n7Gdu>>(WRPq~$kZJ{#?VVG`@dJ> zIFq`jD=u4L7HX=Pb)_*v78rI^wOk5j}oBj?74d+|SFSy(s~0fkC- ze@qLU>@zk)NcK275JyH`ex6R>;&f@m^61Dx79zREunncX>=j&cjc-7;@aT>ayQuZr zV6~nRSbQY7LZ6F2&*RiNI?#$mJFS+1s(=thIDIBy|Ee)Q)`sva2jBhN41{;N3!Cse z#lZS+2qK=4W?fXj((b7`NZQzhLgyI`@$+jbelKsG);Z z25KV%P`#fMG>M{AXz<7Zvg-)81n5tNIThJeO16_569SE7RiRe)73FJ&SV*S54M;C` z(9Nph+9X0dnl{CIszq2{CZ0e`2t?Y{y$!C&#M)&zoV^Wqh(y{}{zyBT+}Hxmi$hRL zk_K)FHK;=2Ar&FZVgHv*7a`On&VUd#5*bo|5-Tz4e4>xTCZ4KmG)a5g(6q}CTq$=O zh;*s{lAo0QRwC`H{Z?n@P*<9P$B0#^SDJ`b4c0JMn)jGhD)qj>F%?iNVgDsmqwGSB zM8?0X2N7yf3AGSw8_IwKtVM=ZubPOBsXs;3`OpE@XLitkgV^-LfmdetB%mHTS5sDlk7(9i4-A0u=iP>*lysXmf?&C4R~~P^c-%4HuP4>TBCv z$8zU=2PIYgxr!TwCilKe-`G;7Ae~XxbIOzO% zg#zep6PZy%7#o-5^P#DIIzrY1Q6BLKqsTnRcRYEZwiO7~(?oc!Kf zD6X)ad~8tM$P3+de`@#VNM0)CnKdIQ#oVyXJ^>=sutzpXVJe{@ih>ZKuulSG38Ns6 z7>J@E&W$C6qG;g$jZg$d@f+dUZ>YQ&$JKA2e4-7Uf;jN)UyDlsG0d_3bMQX^Y01C( zP^5V=Fp9)5l>TV{&VJP!r!s?>`Y3A7w!W?tR5W!GZvxf+A38nwLfz_@4Ju$+C z^27L&8+Cg+nYA3ZXe~cN)L&v4Dv8&1O?|`>rIIVDXGlTH)CS@cXT33K1O-JH5G8EC zeXtnC5&cpA5pHNie`hc_#gunHi~^ng5W%#j0E~hV!LWa%Hj)s6(lCYyg0h{mpTMNv z_rJo`8JNG<{}G`yAvnc;0ui{`j}h?y7=h0QoaZnKs>ARMV_aj2AuKkL{;$C(ThKqO z%OV8-gc*>3LdOwA{{-Qve=;8TPfW#!whyr8SKb~k&NL$UJ7ZEiewt=)w5C=NKC9!4f(sdxz{xFtBv1jAK-fQ$82}}~h2yIXx*JIdWC6(u67!3e z5Qq{ahUh<}#M3S%QWlVc5r_aOI^2EOd>Sg((|#BhOMnr8-$4M2i_Ze#=_6hTk~BMf8@ zBq)eL`(Giqrr_uGzrqh9t^_3%Mo<7Hv^s;}7Xvf*w-sBg02I|3VT4&aM=-((EusHw zurl~RSeqz*F-)2Q|Acg$eld>2|JqLwi~huf@nQFi`O@U`uZhuuZ+~w|o(QUhfc3-J z{GU3?EYfG!N;sbXX;Q7Cee`dR#4iTK!=IplxIXj~?&CgRWq9Bb6em{HQluym6lK2r za)dn<{}FS3ar8k?PQD0;cV$RZVin-O{OP-I3Z~x*=;7Bz@rc#*i<<-!kXWFiC?Oy! ziJz8M8Svz*8IC@dMu>A>e7_x0c{q!wj{Iin_;PWLt3ohKqOX&+(f`I&lL3ip;G+hG zwW?nl=AWi-7!QM#98y4TL>Ncr*{>T@F1g9yd4FcJokiaP?is$Zu(6umHkNOH@B|#| z_Cg!+#&zQ-#eX@8c55|_1#o&ZJ+53TajRT1+mZ3~nuCAQTtL1cqMHcB2O5crUuY77 z^w~;o0MtQsxs7mjULNWzbc8E5%@=nv591O=eYIaZ*clKZx>TlI>Sze_F4h+gs_<(( zwH~V005e%3SezhpotSrX?X+1^uD9Zq${yZhgq_%$abdE;yZ?Ah)6C(|89?&YR%fb>#`S;Zk3A zNT^yp*3?l0x};n8A(Ml9b}1e&qp_dg5puP~cKF{wTpuXY`7E?jRe&?mzRTSblXCx2 zD|k1q?6)u2(nB|R`Mnz6SlbbD(?1z3^328{@ z6-Xs?Ga19GTb@;~#e)`8%i@x43spu?{3u|BE9ZwCSSX&&{4Dd@(@m(z_?xq7_(4Zo z)c|GITNCzUKU857K__?HS@Gl1CK9j@^s8?*_)5pg+n$9O`J2f$9r8jdp3FLh;|19} z<5&NdboKuIuFy6(|FMxk{EEF1qM0OL3U~HPHIV_ks=dBH+}Y9b3U?+h9k(G|j_0`8 zN(!SCilEswF|!FPG-@bX$Vw;zST%(d_dhA(9Z(CMX<08DT`)yvPNn7GYOL#kIjA=p z$$b^XcoApguNg`qHlb+p$%B%PLphP>kh@pr8aV}dbLFCck{|5w!ME2aipnW7vs0AP znkq;OM65JY_`;D}hQ$;mKo+rFs(F zQ*Nz2c-bF_@J-16IrWhgS;!8BKU}FG^(k$PSC`r#>4q_7!d4bOBmpWFKAWMNbvDaV zh9E=3cDB&HAO2W|%jFbFTbENN_HlSajc)Izr?IL#3V=x_<#M)%pl-RuwLF!IU5qIuJI9Ob`*we@Z+ zgQ(Zdq+0^KE1y;!E`s(H<0;F$;9Qz2;dSD zCrtIN;ocL9{@6I@CSCr|SL496Q8SIc^QzthDVF$npU!6WkIW!yBXQ4ufCEuAZv6Ib zrjCp4l`>SH2LfC~A&ENDbLXTUc()bDG5qo?Ipl{9RaP2(OVF>h1g4i-i%i8 z{Kt#^hqKa`BJT16G%eDw7btw5q<(H(x6pAo8Hf05 zEzdR3!_dKubI{H3i1IYQRA7RMjNZlS>r7n#Fk_)<0;5S)z$&8&V5Cdb*MV>_Fmr+@ zv)P_YRhyzV&PW={2G&R@0=jLOk*q%j;gijlmi~FQt)Qrj?mZv1mE4IHcnjG@FIo7R~=T|WR7t%(;@YGF_(lVl*JJK=|Wv5_NZ<~Rn zKc>1XwHO&GO5LzPsJ9xSulKx>fu{d2129w%F(53cDaJ;-%QEtKP}pHWV@EwTA+itnM{%Cnh_M zYp(f2qRRNuH-rz!01PBU@eo47pa3}vk_;@l?VMc!yx`!#Vt`rj&BI`1-w}<5LEJmF ze=lA6eG-l+EDUR)u7z=oJ!dGijj)>%B|~LC(c_VrLNEQ-Kh2^nwiu6Gq2pwB$(y6F zyMKDxj2-1fG?S3l2}rnYv9y(hsp zt=8?>EvE3psjcs}p2&p(2iX>Ovt9cYI`kXekz~Kqk9spbkc~tou)fY*oLsyhJ(kgI zPjqoz4+mz4=l91<`!xsu6dqbfcmggq^|4kmu>Jq9U%f?GPHYWBd z!%d6kb(I@mG7d!Q36})KVa|T*j1t_Aad(-mJ)TReZ6r=cc@sF}6X#O4cSEnE6DJ6?I*`b(%)o~0%HG>5=bFZc*1>rd9C#1)Dor8Edg^NVd%#m zhwKc4L&-=1f0?$f^~DjGxTqQewRM$xj&`0SAN)c8_@6hE z%Bx|Ba@KKOqr0aOld5AuKe4QhLe9?DQBO;gUrvqGr`XhxU8$={_Pb6H!~(b2<4J~% zD0PK2mj9S&Vl5ah`5z<2yuGmBg$^n1m=deXsHjen)zm*V66P>Wr5LrsR%R#9d5k|o zc%B{zhS-4}n3ZLFHP-0yw|vOpe@U$Mp*%4_LQ>8(exb3^s%CDGX&qQ5Q$M}UpRH@H zudQVBnV<#b%-)CKcSC19eC&zKU1_fy{X=fqlDQ-gR%m2dB93&NavMcAftVNtBZDM$ zP(XRe8&t#yH1u|`kR+BvLyb{74`r^&2~zq11$4ly59WJceP#((KZ-M5AS%#M?+K=C zM8*LURd)ppAmyLWI?`A3qz@BEpK#^SF{NtO*yy(6+3Q z0*&ytxs_sr6;uNiUl3>6n!zW}>2vX?Gbuy&;_z}kISB!lf-~$+jkL?sZkgq`H)Rro zilbX2SLt>6P2|Nm=NL*~^Hi*5M+y}>1T9u)D(nq?zYXCq`@>v3-_iM_hdk0C75bp(FBJuBFf&R-16ZOYG%%MD zsjYNX^X+%NT^{r4Z|{EN(v;|g5V|;|OdXD>-n_K4F)W&2`lJR;F=Gmrsk%^BrT!PB z6vX+wu}L}pWE2${Iw4b=edizU1ck#yf)HHBg5G={iMEJY0qF7Z%N?hbmUSm>b@l!1 zQW2xl#KK=DiMz<{zN{aJvA5p(KYjnIk9_f>Wp@=W=4fzfjZOMAq1Uel!t&`(up?7V zaj(u1cB0&$$Ik(>NTr|t$7n)vJp=5D4 zB=86{-^%$NX+8TPn0gFD7|!d=``d zxltc7urs%U2T{M;Cg6LGlp)>pWhNcW;!P+xt>ccgTLv>QhGjGxvNs<`i`LL)*dH}n zlX9JKo)%6ytx^=?su4og`=W9&SDUEPg?o%cjd&41CzM3iD(mp`1cLN39RGd?HZjOm zzKW4hma#~i%`Ns#E^m+D6Ua-PceZ=?J&EX#&g{hRArn&@id7xE!W@7bFS|yg`2OLW zP}4N5&?@KiS`DsEyt7?+-d4;?ZT=(fH>DW1qw5=`@N~|pciI8WpfbRDhBb&A>mDf^ zHR;;I#O&8M$$H8Q%g--{_n1F5AO4Zv4{vvuq#G!Xh@#YW(^AOIv^M>9i(D(ei>dbe z8~F0^1L=$E$}_d4le1(}{`yBIeE3IhUBkxyQmVk3?ndU4&{>(e{oD)_>9xOp3&f@! z-a!gAb-bQJN4Kg1;3Kw0e$}T z`A{JjPIZ8=vcd!peQ)X(vt8}aGuvLHjp!X+A}sgB9Uomn)Zpy6HUvO%CqghKq2WF3 z^S0rBAH42(ZmD@hf#|Id?lA#wBgYC zkM5gZ3iB-93>-VyneBoTXATbK@CjCoBdrmI#tT{H)(e+k+?1f`QEivU+sz{%yV;@T zY?5_H^1dOuPPdkt(tUk{R5!1%MM%_yr6)Nxg^(`MxbK7BGZ9xXJ`7QxVMA;rTMO&eh5NEKVoR!~La9YhGsiI0X^3hq5Kt(^O*x z{2UdTGlPIh?~M#QLR@0r6M;mY-9$zObP8kpb$2kyEXOvx-yJI!ef zt)OFw8qvym`xoPE5o#LTEfBS=AT?$vIn}t+d4GjN9if(kYTz8;`LR?|*5(QnV41Sb zyYv0XdjBcuhx4s=A-zlZ3T$xN{ zB5wzQ6pN{x*kl%8IW-i+@7sdwg5uJ~4wRBo^{>Zt2JOE37w1TP6SmdMVXc-?T*59Q zE+(aAz=~=%;fo6j@bjwkszr@y3^p5i4hyJ|^u$6gCS_&d3QM%7k`|ikL!yZyi6*7x z@Cqw?Hcy}$#=)a7N{f`r8o;2;$~sG%q$AF<&Sp1Z+@O@_Y;#~yfnjaX)NLXIDxB;x zQAI6Zq@9{l8ReDdH-anM(k4TtMU`|_esIFA&FiZ4+@1;pFj@L$n{qmGM%CQAt~8th zjWA7EKTD$g+G^MhgYo4Hg4${v*x8C1*CQi8Iaf0P-igeRaa-L6?ANXzxEqRwAjmdC z(sjD0vtEeEZo(^~{lWp zM$WYF=py11Qd}G66&NS*BG}F>OQZ&F^`m+}n0!OW@!&j}HqDctDas-nuQh$Qjjk%R za(EzB=J?1lYm(w;sc9P$OiF=Y@oaB*t$5sq?M`y>c*a%mr|_<^FrH6y1x{Rt%)a*U zZj99h+jCyLuLv{HN8g|BkTR-QeQ{+ zeFou(-01}R%W<{c2;75X)ajtM<15QZuvhdLVlms4C0b}1u`ih|yL)>D*@Ww51GhV( zGFQJ8;kiMm_QBCq0grdX#2P@LF;_1X4Ni1hru-OyqcPRTm*@Na!$hC8>{*_>NIyGh z)DQ+usXAkj0X&>iUAo8B)l3cDgeRlp*DSgToUudye6i|Ejpe!N&`CrA-yCikQijqC;Jf{@h=QA zac!sIv3903@Cz&3qI1aE1($q(r)LVr>Lb`wU?v=yl(&=Nhw+r)X=frSb|dn8ZBVR{ zXX$-w$vQ4&^~Cu;%tUR<@BJpltJw2h%G&}cp=Z$T%BoVa3X7N}O44(@zjl$m$%wcK z?5`J%leaW=CFK+2ax&%aQ;AD!)4-K~D*JUuzO2P=JJ__;u%sTJr#w0XtQA%?$mCr? zi@2-7l3`w!yV_Tq`>AhmL$Y+2RELHS+l)dd0b?kd8NQ2d9=&DdvSKk0Z>6s}t; zsnVKzL4MbkJoq-cgzuIe;a%b=8#Pk5I33@%j@s-1du0OG;U0C`O6-onxO6!0g)?X- zIzrkSQyf$xHq&^C?#uF}rX8_?ft!Ou4tJ2#HiD|ywLvJ(B$WPa87vE{_At>9KxX)M zJ6%DPAM)mp?}mI$jQWz!05w~{_^r7`J%=~y*GPoyOWZ~N_v@@|Ut=*VLnvjXXK#rS zH@c-M$bjStN7%?qMcZ&&P_MHHtuZht3+#2FzA|fT_?4Q-J45SSV1>a7z6h<&wZ=Cx{tjXi86PHj!Y!Jz6&{C8NFKg_m-8>aSFz{-Xn5WF|i@f8L)NlhTu z{#rlPG8|wvBsu<7tLZhXsZEM9cvGA8-|3Cil8w*}Hye8^bGS)6_UY~oPlN=com}Bt zW-`ylj>0&Ve+k?>9G=3sE1xj90&G(Uv`YhYFijc>6jx!|{P+^}u+*{5+c3l@-dtu`JDi{4PdJ``W10~=dG8bz{d zGGbOP-;fD&xj_O;tF?k4>e7Y{ zi+-kdagZuvpG@hhHnXabaWdcyzje9C3z7`De0tmc%Ee%-KNJpc$eTWG*M55b-?41m zVK)Uuv(!cMmt1?7fuzenzF*|)!G~r;E-X4p3=&N_>B*J)NUp$NdlmF#acr9xBFq!t zP!6W5kbS;;vyP}sJ@RmRJ0-m=VK%dE8F6%|^nV+@74hrfaQARr-HN0+Zz7Z^Z=5e? z?v&@`y_kf6Q^TF827;h8(oyiBCZRpBcTX_t8y9SUifDN=REy`dS&T1PV{k&);*wJR zlgy7Xe&)PSfM?4_{9Klv*=Q^_F1S7}L`#~omwd-Ij?+ITmCF274%(M$Oi~=b3U|gf{SwD1m8t}cC!<7LkyYqWH@*UN!H(bZmS%Lw z)s)U@2J1%A$m65~I~kPf??K_}<5hi&8i>aQO2eD&+$!unl;6pGlIuq?iRU z&rueeG03wRmSnww@&(1$WHLqR87F9hi5=PA1`KVO2{-BMgYv>ea(s#D(ExipGD)U) zzpdvz=DLL9Ks>NWlpXt=H(AUeBKvY+;c{d=i$Ax7<@;dQWbE36A~&*q+|zxu%M&8E zqEvId@%@G4@7oPPKhB5o)4ef3a}1Y}JZA8C%WIX>kvq-Fo?HSIzoobP+6jYimI2bV5Ao76;i4~HT|XdBrFRPi668xTqk;@h#Zh0 zmHwn$5O=DB0u-S{!#`S4zko53wo*V2s&XKxAG0cG)#HAweShch!&zRd5dpDkBrFyA z^&$IN^)nC0Tx+{q8EkPsl>&0~Q$JqBthUH55cD#woFmUD$674B+p2aqWR+-P1qSkx zl~e007>;!-o_N2=8MB-#x{&mh?Dfq`8LoT5Q=`majs^Q$B)Dy5*vDDE+F|I*n7LG;4B1I?tq2#bblW4jI zQxJhNVDh9VS?U^=w%;sz!gV*9c?%=tbAG37A{E}%n(*rS>;(%QX8Vd2 z-c7f*uTDP4Lx4V1k5bKfU2^~YbTmuXww|H<6(D}gYEwWa&DrwS79W#?qf=I641U@J z3dAF)q6#BRl9JNQ`EBpFOx-xBW`0J^eXB&eT{?zo>lsVq_S0R3HTekac`;LJGQN5%chg7l!Y>!p%Y1Kw`esP_2 zAzk18yN7)I1FrGuWt}LHp-m`tznm}BoV$b)M7{L2 zIat`S7DC2bVtLne)8uJX@UI_thGH)0!kVCCcpm;s;!mT^u9q^p*(9p2uP4DiRAxTP z1M?!2RaE=mBwa}~(RmcWOR{0IUJ$v!RM7j{)<&|kOAQe??MjWs#zHW@eN7S!i`|Z& z)Jj={N#*fxXB@+(~DlLddfcz2>8!yDqa$$CFGhD-onIEweCLt{CU{?qQmS6P8wwz}n$(VXbPBvpel_D-AX!o&Q+@F-O^O)pRig3$X#Xva;1 zc02|+@#hq-9X&9JfgG{-P%t=0$k3lqY;MwC&+-K8{`1CzP_Rj@O3Kx}Zzuvyc)ukq z;WfQ;;&tqe5Hbn+*kFWLd`&M)`bd=na>{1eN)bSCLK16#wpD|F$x(5^qK0;=j^yQ= zPGfNq4CIU{HHpmjk+5#=q9C9)rBTC*`G{nob^WDRB%92p~HMhyi>Y6^0Ys|Q6Seoat*$)fYM zYr8cAuvc%Dy>=EY6>D^=c;r_j@H-H-bHun2Q%jWWhvyW+3hT*PUx$+8Eo_;6J{Jj0 zYQbLjL~7JXu#f^F_6KGe6|rDjm)%lX(nZZcT3#g%H*N;8=!efmYObEPv&C$k@9pR{ z=jhVt2|U)0Ior4?D;-k4#(9qsJOtxEXfjY;@IF_!KW&Yxuwif!P?>9sgu z5E>kYg@Tnt%NO3(;Az;W-02L|Xx>NfQ~G zNdsA;p`w`qZ3v5u6ufyT%H(0j_p=mu?MF&GyAYp~dh5R9gza~iHw9cPi&EJhSz<{x ze@|Kv-sHbU7IWmezg00x9_}uW7MtJ!V*Q7=#6>&R6XE{>}ES>@oSI;;uWm<6tk|@Q=2@ zpvW%`{EDw8oo{Jt!5z^CeO8o3YXLHQM|g+mtGEO!q419li$lJfw7ISTO7qe=5RtD( zloU$n!T$5^9iL134l3!w2u&msOz7XAfvJ&*pQEvb8PDG$06|n!NV%$x7XR<_ASGYY zZNe^ES_&d%`nTC64({7}9V{JGV!cTzf2obHGvQ#3iUO{n5!ZQYxTyzZWy`~Jc{9cA z;wEp6uUKBvY;V*$sGqbn41}F%25qEbW}JRTOx7l_WElUUUi^cy(mlJ6DdhUmmVMNkX-uGR7z3{oG z^W*b;w0QDh9XY?2J~GNK?#AZ#(|eLzV}-+89t~*#5mC?QJB6nz)<8h~IBNg;+Im^6 ze_kQacDllZTKYaGEN0c!pSCGnb4UpVb8!w2>LuhAV0s{7u^}?^>%Rc*-t({+1XJ;E za_9oYu^zb==ASc}hZw5p7U$9d)_lOUuUCaMP{Vv_>Ha+sHIhY~UD6A3-l)*?^!ado^X>T+}&dEnZ_d(r{ zuO3(iMwz0DJ*!t@L9!tVP_jV*Q+Qs; z4AY1jSufdemRv6+9&^>HHN+lGR5@5iPczKF3R6|@zls7bmbxu>)u^TnNET*UZhDMa zS}T{cjW{N}iH#_K+)7HbjfkTLs8nU&ZtMH|^8J|PN54MyIxxaJ2IX_cP1ZKHY;Yc( z<$fHTkm9_VQ4jt$(ZTSqXPVvLeEl3H(7gRaruCj-h(1_XH`zOHXs_0>-A&@3FS6WM zAm1*WlGLMdDJ933^6+Zl-||z2|B|2n);RPJQ>eKU@$KY+Wz*>VJ8&^rqBr| z0oD@x31*=gBoVODJq)7LXyEn@A+DnVs&y)XJy1ytjg;|1@t$Xq@GOSG?-Q1J8lvqu zGgoP8;yBBMGL^J*;v4EpZwwu+qQivt<|PJp98YgU1o!9PXyASej}+2?iIpbnLKG}= zP%qdtD2SgcC&6|7R;MhHW}8!}M;&h$B1-(IR*caHHeh2^12Di((s=2-Uh8kPL0$i!>U4&kiji{f{Mp9oL405?pTKX5?c#krrnk zm1c)sW?QOtdllkSSk5~Qc8x2J3|7)REet0y_td}yL;J@{81V*3&7=%L*EWzAF#tl) zQ}Q1Jg}oe!FG-4mz8$QGEG6seM`4)V=uRCfgXDb^$yTYFWl)M|wIW~)Rp53Mb>qs1 z{>KW9GE{7*N@>uVl736j7QDj<$nAlS!Hn9R`-x?k-u1I>8plL`o2T(GZ4p9(kkmvmibS9F@XG-(vJi%GvN zB@G({6-jYNipqrc6GS2aM-Zc0sG#o=2|~ne!3J z=6lRt+L!cXv?#XNiuW-h)1tUtn&P;t5q3> z5HD_C}_e?5j0i~D&y@&q5l>A?D%=Tx&Yl?%E=KS!(PgO z{R`t2=056&6nPh6fqq;p8avU~fwGvhkU{Eka1KqSPt3ctz_7nGChx7b+0FY4&s4O1 zUSiEV>xJxVN_*pfPtY5UQ%UX-zv_Nu>67>;fw#S=ixZSiGQ^+=%P|HJZ+$%{&DMRY zTzUG!VSUK?mvelIAGD~g(Gh5DF>`X=pk!$YF2DKyKL7ZC6Bib6F>&XYTL|OH`P0Yk z^ZeVxt*njD&Ixhx=1-Qg&dxvOB@MIqsOTByoxW(Ds;l2UPiP{&BWLvWT$~POb+wk% z!z;if=cMC%ET_kgzGt znYpxWtt$3yY;OkeE{3^Q-A^Irbgi!v#-qal&P?o)rJ6;_|G`p-xP82>`^Qpf_+}|2 z|NpQQT)NK7p%>L{yVr|i!0g@1ZnuGz z)P@+fBx|Vz=M5CSU0hqNWM$pm*rSwqN8yYI_i7yRik(t97fn`kRFOh2h=&ACrUFdB z&6U{Z*(_*H7vk(oYptMcPJ7hgC4Isce&~T}(4&#`SrMzje&?gr=nIlz%0r|rk`xTA z-!bljTZ3MN#u1JDknVzYqYeKRsf6d}lL)uLE=`XrxXGG09A|k+nkg#`bqr-m!uB$@ z(pZJ@SHVWJ;LB(fx*@GWl9=0jsV+SQuoSvXC$}0246SASe+tG30+4xobyxqRrcTk4Sxg7R^}yNhF*tD}KtN>CPc%d}Bhg7<6@&WD8) zgH(BA!jUZJlfhE9z>TC-!1~VtPrn)y8jqS#6+BS|8VcmlB7vM#5#Cn%c3;R;$%G${ zh3k)0KElWM47I>YUvbMB&@b_$@3L56rT$>?*2L%rvH36c>ifwlS1IA1(0(8Z_?5;| zW+20U{6y_G$=b)yChO^2;w0;S-#k|ex#Im@vY<)XqN=$RXgioOkakzxUJ$ty9St?W zpdfZiuTrCu#?O+PbG{imqCXN06>00dqpHE)mKzw&;C3P7Ew25CiX#_(QI+KVmHESt z)^ItGzl7q15YZzmU<}zN+K!|z$l6o?VahKN^g0hS_(_}$^+%||0rwiyNw0j8^$?dV z;WCULfAj)D05|`st2Z$Xt=>pH=I}?>hn^0JcgGIp=*fdK#UsBFMqM0}r)jyTdVySi z`=_j*!R3=Oy8cgPy|X%v(&=zp{84txK#Eb!5*jD+zeFoJ^YdfnIsRK(4r1#S1fCD! z9(!qJGe;pVY$sofZwhcR)@Zsqpe1XTEnD7fze-9tFi!o_cz>NUT_F02`7!?L$v4XE zdmUa1S$qYYvg2|?k0lV3^`r?4tSZ=7X;@yYFqD0GP#P!sJh`)|F_QhZDDtEy?x;aqkNurNDyAV`K>tyhAgHh;iriX> zP2wVOS%c`}O`>YL{yt$1#NiJczjJ86{;vD|gimZKhPhM5#Exa95OFkrv^o0b6-9S^ zcz-DdI=(%HJy8KIiit8v29Z+=N$$lmOS`?Y%C}xfp6gEC)hO0Dd!E2Bguwqb$2i;9bq!Xj(+2C zhl=t>PbfRA&F}^gs$p=fC81$sTR60TFY1@r~g&({g%{|7F88RL*|q{mU$bwoOVUr4H~ z!VuAIs$ng(G{nbM#ZXNytpkXd#x|WGmLQ&7K5x*Tp_Nqx1Y(y}eNS{I+>~BV7xVel zmv9BmYci;u7&Mm@73Ub}>IZ_)|95~X44yy6Mpk8SC4^O3{&viH^zsfQTIo)V&3gQV zC7ip--oM($N|x=#@FXyIcE_xK$xkcpbkozr@mhRc80er&4>fb1bw57(ILmjd{w4hHNM(pV2r5dsqHgNxn0V^wW zcelW|YVAH+A7eAU29`S`dycz=yq$8lz@OFBy%x{YYwgId&~xk)F3~?vaK54SDrAyA z7x*IUvTum7YKBSoZhMYBeZkib>5e_M`Xm)PwYtX#{?OVBx6en`UOKgUWyUVU<>{?v zBY^bKr(x7CV@1wwEiO~ObxkZ~_~jasaE_z9h`{YttZxIb4#DJ0D)RFLS7u8k1Bcx= zf5$H4S57B0fzspQ&`?UU#LnLU$tpCw#9M`}mUx$JlNO>1WUER0DTfJp|oH47D@ z6FXe(_e|6+$bk(&YSoF%(zYG$H#GV`;_lf1APVT_pN6rAzu=578FUuaGyf|f?%1<7 zJg3`iA&jJ;k9_|3T2bs1b4Bw9(3;nszz2?6^n+uFbM!8}G(Ps{YD%A#skK?RFN@Mj zI%;71E2@#BdYU!Ti3}JCwx%OI>bup`3(?MtWb(sj)EI)wZBQy z=1bBXolyCz)Ski`wn1>z zf;1w3d?iDld)k&81}w&q!Yr0*aDOT;!}p;y;btu9ZQ~BkY$Ap$^AigwwRAxT6UmYY znq)|WYsp7^=gYX#jeWXge6F`CiB@K~kzvwUw!}OBi?)V7(#+0k7kEc~pyuon5ciEk z&O85Er*KALl8~``GPcRJb~CmCXJ1)HwaYy-8LXu5qeq_gbAZ*IW|3XoXX83brd<05 zD|JO#?9essQoMUEWTLdgT6P@9>QUCV7m+iXlF!>^M?B6p0L>SYD^1H;@Wv@k+qR*) z#P(9^^M-C#ORW_!t;%tYzxysH#np#%X7S9I(|HUo2_S@$1sOmXkm437waC7>;Tahg z^>|yL@~?&kZjv}!CXH&ZdLyAvO#s}xIYaRz> z%grb>vaNHbhZyS2vyJjoP|mzYVJvIbO#QJ*xuh&xT9qAa zU=^PT4&C}Gs8zI9E#@;rw{*jx^T25# zEQ5Y#7QS#OY$_@#?9-jBk8b?M%!bwN(P>xYYwT*Hbs)KVB-(_F@1u`V`~+cZDfGy~ zr5sa|p(u(Y{>zz((*~cns0jf2I62F2)SuGP1k2Zv)V+~kr(8UIF6a7lEeZ1-XMB!n zPWu`_aMw?R^Y<@nIM8Oj!@~L0!`~mOm6R-32+F_e&4hgF64}>~&1@G_(pRXgk-Df% zZ5MOiZR^aQ4#)wcIQ<;dVwH^Hnza~yf{5U9>@%Mkc!s0$ zur0G(|BaPl)s>`3*E8DE{s{(hlXfA$=nCj!C;ix}c_(fOPk#re==>Y{Dct*|^#u&0 ze%56Y2C_g{^X{sO{M#Re7BTLNX%374y*KGtOH;%YH+$9KNK2i4CYKo?z;3pUq^IsW z^O?c&aaES(YQj=rZ5A;x+F8pYGMAR7I$l&XLY>xFFZ{DFyQM}cjcuqACC#Yb!Cu1$ z$Aq#4;LXo0xw3vd99-LMGG&t6PEtY!F;0nqqNAvxU{=9uk`+|%+`|PDWUL)a9AsQA zqK%}Zd8}ks@ortbJ^$lC1v$$Yw~9E=*xPaqNmukpBlO*F23@K+!UCU10-uCCE)7@L zB`PS1#n=|=_^(^&rKQ6LE4o`dr$_)FhKqCS5}gz^tJ+OYz0N+!JUTFNT~-h=$a!r6 zDfG9!r;?3YV}r7r^2DSGhboT)wnlx^kPI|h#<#c8JL7+O8@0GVMTj@UFtBqj;=SY1+@^8e|WpU&(+#mH=q8jm#%gpZS~l+9!9v}QmLT+g6Ikn zM6{f+v%u>eRc5Bi8mF>vTJf^)iy(HTtf@@AwaC8m#@}#u_7n5S+zB{ZgNDk05{$8$ z&y(wY6D6pI{l6{IAtRNBzfa1h*y@hqnD z&8=RVl$!$-%toPDNClL6Tl0A+64Wywb@wdxA)nT@4>L}<%!m(?YJhfJ&8)}Y6X>dk zXo;%JCLJ-zJP#}c`D^l7-Wa~cexbM4PF|FQjA@)9`Y}MPZVSj}8d)3OOl^1*zl~Fj zQJvi`6j!1z!I$xE4-e0sk|#2C&1R(1H^5WXV>pP1ta;9DZp)%uB5IvDDzjaaw$u6M z(h50NRHJGiaxE`hK<8OcNumk}B|{Jt;c$&+y?3XhBtZvFc0HoEQHo>;K-2b@i4`g6 zi77HD#3Dw#v3}#7k&cqNkQB-QY$Fp}^?FkGQ}Kl;WK)}xSXVMB>lTA*J1Q4g(O2t{ z&owAM4WJVQ@~voS{b9L(S9~i<+!YwOjLAmHnd(NH@yr;d5HdH1BifOcS$)~)wT1hu z%l9-{P-*;}$GaB|Y^Exo#%tJ?$=q$6*;0t$ZF2eZCpnYYm{!lmFb?7`u*%H_=`z=5 zjJ0E)t=18=`DyX)P5&Ij2CgK|s9~fV2AC@oDeGIHy^>stQ00rQ4}qYn2xSb_Rmb-7S|+Nbk1n=r&JCKzQLy0+gy3&q%)~z*76T_!iCFKA`Q>Rk)Jv@ ze1k$=)@9@|ZPw-3yc#z=-QcKOE5|Aw&qj)4rAzC}@$h%Yr#kmW3g^FONrkR)w^Sn? z16`2&xS}!-1Soo0<8dFI-DZ95Ix<9wva!SnY@l_Z#H^$ec%>dX*#~$PxQKRBEe4ar z4=iXrgW`$FF+CI4fIy(xS-C&B_AB{6yV@&>G^eoSiU6qorn{r1xGWeAs42h{_Enq_n>N+m9u~kCdXV6LSx1_4y>d+;t7wrDf{;X)q zBhEC^EnH&KR1U5~*L>1Ux2on^RguwI81I2&4+Sy(s^Q zquou&B@RJ8W!pXyFEP2B@|au{K4aaGH>P`;?NyS_>=CvG*|)))2eH|D3MDP!DU?Wz zf7B5~&=Ly>;G@*^{W7QpIr#M6U`0XEHBeDyF5qF#h{e|C+*}KA!00}k6xcCj3X^L- zc0?(AJ@g=!t~5IX6I|IEe+e$76ru2jOy5bk!O{}p zW>?z#^^+`CS0(}8dr=n`Cnq^;6G^9#>QsNdtd=%?qwz$F<`hYa+m+;KG& zjpE~~Ck$8Ohw4Np-|)!N&Bkm-KiON{XLuaJ_|naaS z@3Y|yzsU8ol;2$1l=_3knZ339TG>q%YhZzsRV`t`fs2ed!; z20qti{U-=CDUDx$m+5Sob@}K2KA{v=yoHn~7XUYGa7tmsMfsKlfBRJpZ*n~ilTB{w zpN&UMo?7DReTi%(e)tg#IyRU2Hr_Mru3{ozAbgm;y7Tf;cC#o8XpmjKQlF5-o8DO8 zDy;OZoow9u)s-}Vs#q-{=H0CnW|jg|zsU;3*D@p#&1uG|F5*)%b4eMwN2LiF5PABw z6^Is@gdYy}7sQ3n+Itkycj@-$-Frw`C{E`^u~7?nUA|J>VxV#~%M?6rSB#9f-Y!`U zL8ha+9*(07#WZ`wWMQF4H^ur#9u_3|p)gbO0rRK-20kp{77lZ(KOFkq#Nr}SwGlv^ zoN#n|L;B^V>+Aq!%M6Ct#}8e1UX8*hG46oHi~KYE=9ARXG{3=NrRPD=`ceaDLIeeo znZETroZTK%Aa`+HCEerJVq%7CeLRt$jDLshp@ATdJfbU968EgJiC`iw4zy>A5)4U; z@3t=&b$XQQsAT6{8 zsZ5b8RlWvqZ}z*n z3suK`h_k}6w2Rp2D>?$%O|Q+9B|boQS4Ws$f8vF`VS|p%VAT{{9eMQnVTIOy!X#hq z$pro~2>_p?&4{UU;hvxroecO9v`*w?@#i56OGHk|?1m-x#LddQ{Cdi>hF@EGsi994 zz?3m7q^aoyEWI5zzlDRVy;JX1FQxi=IaNORb3{_}0dGTK7Ci|MkzD)PH3@GoWA$x^ zRPt)7F8VTZMAm@K-E~f&`n?Zd+W77EL;a+BWTeT67Qc= z^0SSX3`SOM$Glp}7b0vb!HwCruREGrp22o{AxSrNgr=^y&xx1M-H%;zd?ZX;Wf(iG zR2ERoNtT?Ij(g2fC=(r}n8Q956rn-BzEp=_KF?Q}-K>k^vZW+II?ye(9!0s^uqd;A z{Ap!`SlVaGHBXcv)o67dc}H%D+_)G`3xYAzud55u z8{Rka<#@Eya%EQ%S7}Kh1Vp@mAiFd&;$sZzo!(?hP>GSrzRWvmgNk?~AawT}fIrxG z=i1yJ-Z9eEv5)TO^Q~4vOg+0cN_dM}am%6XajVUxUTfplw3{^lYcUbwF>c~G%@HvD zw-GL=up1>qfG~5t(%3%9|L(5Gnk8YN`o0PJBkc!g&bLh|+Ekr729fERc}pK(xmhx8 zUd*nHLbOB(J5G_P!x-M(OFu>1giC#J!S=EW`XlPlf9agI;#7A4euO%n@r0;AUFOxj zk+6V`3>WB^|L)sNk5w~j&B8^8f?TPL+yS%x&F-NgQ^`F?zc0nCeD99#qe^jk$k3U^ z(Vj&=7NQXcfhxwSNAs*vPl#9{k4K+bPDblbq8O^rXphbd%1W!G;T@O}jL0too0^-4 z9%>c6FAjg4*w$!TmRBI)e{J}kMY{DPqwOwv?0QYEp_V_xn%)QM$gXqamkgCwdND4S zYo%o!Oy1OzUUxtz?Wf%B8;3#CB>WpO-E! zC>WE|v8$V%6!CQDy1M0@a%P|ad(Qx)?m2dWjffYCYM=IOebGbJHHD^p0>^XLLo@^u z7%Wt=;*xwRCEt(=xvQgSxG5`L6Zq_dN_opIsl%0`Q|A5le);lox7T@uxD>9^swJ0N z?Y|H=PRXsjn)J0AY`VYcXn8I4#&@mWWDdAnz)xXC^m2VOB0DVSVdx>aKmGfcN#7UF z=RpHiir!qM+EdyL&EAU5Jkg3~CF*;NU>se=Qs|L_EGb)>-*z-K()BbITa``d7~s+* zP#*)x-RdrNZSQOOzD8VK8Ux*%mW&_Uf|09}_e%{_4_eXx;uHa4#m0aZ6n>(*e2PCyr&Ts^~ignpo$H!GH?tZVO*gFfGI&H2LzsxBJRUo*XqwD(R4+S9MT&ZN&>;#|r zs_x3!FThg_H%74l*j0evhDnVwKtWx$(g&RkNfZD`bsD!S2-Xsuk_zw&@+5*8TRj?a zb=OihKCx^SHu5=iS(!=$S<+T|3Gx!@LeDOAbs8}SbXdA1H>)t>e?R#_Bffch z2*4Z-`2>_o7eSw_oVsI}GQG#k5zl7+&Tb_I(~jEtT{Ez3>^T=^u(2~GZ0f{9&sQhI zMESzux>GXoao@O^*_wimX{iL@IWf%NJz!>W)>Tq9cj01XonfgCGm&n@?^(zmYs-2a zIE$=*7?53yv~;|tXqU9#Ve@XG>i6E)W$fcoa(u>O;C`>eF+Ej}PklK|pR`X7Uhr7r z_2??Ia_F-ctSYbM{|w%GBA*MY^sDvsae zu#_!dEk8MqdB$?tFjcV`*tU*9(AHXEspM;Rw)ls?>5Aq2yq;mf+^ot}AqTs(X_6oJ zyX(;6=R->|>;iwrcVjS1$@h|Zk$%yO`3ZnDo1~NuEb^>I*mP*{qx#M8H;ze;BL*Kc!oTu^YD~+YUkl<4eOKFT69(GcEHDBBqcUlbdQ-# z{}okE&v!W8BiEoj-Bps8T`w>ut1D8W%73HZcn90;g$Vvz;J;JOaPAlM<5 z>V&Q;$hV?$&{CqBMQ-VC}ww=r*hR=AH!Drz^k=tizW1oH zmpsv%le+QK$f4fpkCtj!@KbYvOIht9*Ic$48;>8JGTwimHMwEyT{bkirTL{HQ%TZj zN!xkC@i=ANDNB7@YHdwV;MTL|BbwCOWa2at8HChmNi}0hg&^RrQk_gf+>;G(hF5iP zN~RdgTr}z6O>FJlm2%dUF6zk_j&9s3A3V_)_}7$t3GCgKVt1@-7k^78O0sF@odB$j zd3;s2lZB<(rc7)ZrV2ow@U-$gDXf2a7QLhFm`tP=q=0~bXO^nlwV$|k(5N7jH=*4% z9RodaJ!m2mY!%}`cMB$lZ(d8SdX(hVczD7~DP{P=3$p(#2s{UZ{xzyyPH8Ne#Um;%{q`(X;=>OSg-uV45WAJzBuET^(4rIB0%yW8Mqkz?(6x>86_76H`MHzbr!+W|1r9cQx0UT&9)RVjl((!5kMc$bh!HgISTD7mlM0 z4#yUE=#ZpiO(3*VMxK5cg2F;dz21H9xDDSRGMB0F|d$G!5bO`-;L zR!g)SWYQWPc>5;;P#+I{oFJV~n5+%Uxl2rX`$MYM&b+R0xnwG$J72i*a6tPw1|x)h23ea|!yUb?wZK8>A}cBOi!3-CpSkdFDW3@F7VacVaef zeh$i2N9kTsBP&Lhp1o|#qB=w2@Og9EJQ2ifrp$;{H)02$_xxGIs>{MkiN}3*^pu+4 zU#BH$gbWS>%+X^hOq;LY-S(+d6pe|1Dz})p3-1STn zdZIByO>pX=pLE$;VX2n)10%W}^VrVUHmV}?AcJ)Mbi5g?Kp|J0;^h;>8~5@kz=wZE zu7~lLePFOt3;xyKk37#`wN?Dx`?J)dC>e;G(k^IqBU!%z7H7 zfTaGpMsHSEJgju<^kFm|P>xVRSXw^S0=nq~eBkNNLkLHBzejz=hiO!3K}-XP3Wa0UDT~4mvt1XDGd_EP0C4Dt#;+T&U5B?XyYuQr6?{Us%h~a zsUT;TQMfspq2vfP#M8*e%)>~szLOs{QTha1AKz9&=U0VAt9Vcg*_ulgvNU49Am=J1 zX>iWc*B(pyJotic)4{Bb?^YM}0M!#m1)d!svDV)3c*E9f=!SQzK61%R+EnGNF@xcC z+`$O6&S`O`4_M=;Vfoy_F=gyNDzsiB)J;cxXRUy?i${vVw2AYxVfaJ!%Fx0ELS5sR z2$?S}*3@iBV_V~D>u_ds7nn`uL-c{l9+nl3uzEcPo)84YHxB$CjkG294=L1imUmbI z6MM(fz~*L)7DDeh|7ll{>UPqC1>kiL^S^6T{vB+$sn36{q=~lSfHZTD5N3-#?L8+UX3GDNOI@A*a-gr*y!gZ0|@$pp=D}Krg^8im*P7gSz zN968uK<3iyin`~L*M0_dAVZvC>@f(rBUFR=2aB{fAbGsOPdMYD!XH|~8!(F!_YQiY z`Nf_2XcOg{>N*0`=NQa+q5SCAi18a>kwrQJZ>;j-Od+ZJ*?xvsc5Ba1xxu>0N79)6 zzyk^4T>1MVZDxxV^^`J$v;g@#d)pMPIrVzf!u5lt_&jaJ9=AUGVNJ|={-OW;KYEr> zokK(<3(Y_NGM{O7*|Ld;Dbn!mZA__rw-&y`8MiV~%Wxcn?Xz-5LC;fL3lXIZT_BJ& zcP+FB6xxS8MxR8DJx14hmK|`VE3{3}kxM+mA<#&TzC z=^Is_Yv(LSbVfIn9e42mSZV4sEj(V+a8^0fjvVWJpr;ev64TOj>Dcny_dV0r`gh~s zW3MeQoySUhN9tEVf_&MTFRfF$df?*(PNTiAThlqNiA<&9Py^#A)f+?_tT6_I3%-%J zZ4Ep&akcUZZhz;B!5WX*t=batBRtN6nJ;d>UU%zR^@ew_G4Mcpcf;KeyKO9+I)(z1 znvs*=oEc0_l?JFx!id2{Q71FgMr*d#`2f*CYw{=h^}niipI?iEgYCCEJD!WWpz_Cp=k|j4 zn(T|zZ>%h-AkR2&k8UDG+a+=+R~D{@BS*GI81L(k7;dL%8Qmy>PfVq*-GBItP9B?8 zXBCTE)_0YyG(mE`aCd5Z{Z2i%mi!WtKs-EiJ$P7}qLlW(^{3pbdSA|{s@`aMn%n2T zE!rY^dOg_xn)$?^PQEomEYsyh#B@h>KhcL+;Yr>U-Q<%>^5tuhc;)VJQ2)HWEGAq( zbNIN$w10`kd~@dbVD~n;*zy)A9euEUeB+qvYL|j*&f7*p$luGZTpbzW{VHEo56SxPxketlBEK4m%?IUKQIg%=rTyHxU_w53 zU(`a#^%FZ{nz1v;nWyh$3VV3_LnB8lrQ>seSGFNkB41HX*kbZ&<^;dqNagaDC^Bdf z1y_Xu?mdJ~Ot`l^8FKSjY+`sjM8fBqc=C8ps)jbpfi^}pn?r|NwWk~81;J`ZFwcf7wp{VNtOvtgWN0`x`&fjHPts zuO;*2lO$|QnwoLUyGp$_G3Xk`@!q5yJ_|iJ0Sy+>ww9Cdj1x|LUX+qJSt2lsg=7x8E1|*u`5zf9F#i{$=(~=^iTU)75i4@ z=Jm;P5s!WQYl3rT2X#EJx$q~D{*HhPKY^y>U;G7x?F(t`foH!K-VEVRAng$nIF7IV zQiWd)@9*=sENNa1UGMX8NI!f84MviyJIDCj5g8=Jh~djV1r($~!O(z!fS`chwUrbU z2IMZpfPsLTK!AWSzrS_1v~{(yw6kV3wzo60G*>otVPf#GwMj})lia>U_ov97;_p~2bHSRz!>&w0VI-a3gIx_IO1|6rU!7Kih?nLWhisnO&PLI zRR`!x2<_}_%v3I_>H2hGH_1{Nz?+vM)M}kv62m?|hY-~w^{~;^GTi?@xvWeLrSL<$ z#EmlCIdoMuYNwRMw!ynDjmlYz+g6M|)H_8)d#h`$;RtcMYEws@z6fqhQ})}_c~6n> zr(I~i;_|O;E396`zh-4Ka6HcA16~|&IlPp<3Q=y7cBMids$RBMqt_}q$`^8xUZ*%! zo`GHd^U;egu(tM-+s-uUfWf=JcCg~aP$um^R%8dZNjOhtB85H(apSip(s6~p*5Ler z|L4#L3ym;(eGhr|_l5KSIrNftX7>L^zrMD5ctVj%nx1BIe5ziRWu8?*Nn%2JQhsDy zx=EFWUUIHcp{{AK&T(=|dQ1jUj{as`daP+rNkK4-3XBXR>6!enXqDy!)BG^`(B#nc zjIz%J{yqSMikg!m#UvS6H4!bTh-L-6u&59NxKfh6Zsu18XoD!>1P;*ujF{QQr!o`{ z2q=9Q2#D~%M{Mq7=wM-KY-l5C=VIz)W@v2sFYJS?4d)CAlc?i=gOL+`g0L_<;zAP^XJ_`(6gfx&#B9n`{h|T`KH?t0}ik|S%f|4=wK>Oq4U;F zfK!va%b5E72l{uMbqc!Ve!fk3@EBhB?MRNWW0q8RZn=~<ICA)U-vpW?1{p_O;syL7YW{pXj<99&&8Cho z2T)`xZC!TC$y1Vqq7Gj9YXodQhb9>cERa78KVDfMXUv9*{;^x-N)x^5z#R7z*9zDnR)dUIUnM8L>|lMH`IvLdA#|fn*VA>8 z6B8a={h)bs?9|DUm80Cc_&$Am>T5j;R-q($Kvu25^Vnn66lrq!Z^J!sg4$J@8lt3* z#SO4&$9A&p0rq38t3>8WQ~k-)$;R_)b`;~#@0*F2X6l)|(2JS3OU>=7hFbAip*h)4 zwG0RX*C*&#H&sr=sz&A5i6Be9GryUR`(fCQCyA%~P%+jw7VLbW#J$|`g~BDG+2TmH zA@|tJA49POK@P~SlrC~jcJopP>8=cX)aZI={B4b=87elfsyI;C$bEIuica}4u4&3h&y*fY)_HD=U6;?+YOXa}(V8f2_z7gg3BkL#m2JxA{+v4D3=di` zM}L9k9$5v5ccDSq$#Q|3z&7->>`+{b9!Z!P8+u!6K>+iR%h(Xgj*%JohnSW%*$K zy5{)mW>YKTwmPAzoR4xlP10&!Y?B_7Yd<`6)ppgQD&nN&K9a{;iCkd#?hV$F|3eepwUt>igw#4PxRLcojse z=~V?_k=wikpiB{&{U&!*HM5MdH{wHC|MFc4S*w85G6yDvBq!UEEIKNK8- z1%5haW4>dpH&~Tn-QIyNG#ES>+FYR&g+ezS+Wfr4y!hrA>T(%=pF7jF(@3Bgmm*xX zT;rOTXvLig@;ojFAlo>eT|Fa*JBn<*KF-qlOKs#F&Z1{HAt4AA@F$c;S_+13>ZgU{ zctQe5;{dVNbbUdAAih%x?YU?9514tnU#*G2jIP$ng&;jYoi1P&s@1BV0$R8aka)5` zwYkHnl*y|{&S!2c8zdlRK(iS8RO%A2j!DwFv0GhCYm6h%R2G*KMcGM6CWlNwJ zhQU;|CKAM5W+}K9Y=i(|bEH2HsG^Wrf06)`)gDtA486}5OuP0Q6he5bq(`WsFqCKv zReLB|VgQfjUqL;cGVF=3TyRZ2T4C`riPa=WeyN&Xfq!$sV9dfocx#-F`2xJ>S0Chn z>Fgv)s6xTyplwUUx~(=*SN<7IGlyMMRqeBe+8kwkd4D}Do6sbTi4OQ#RMZxZiAm6G#hmS{e{A~T}F5aPGjCohdE}(vY zzAr7|rrZNY7|OJ}oW@7tOFKZEdC|+ZFh-*hhrSf`ySrJ*tN1Ao?pkO zqe9wPy1X{+J`?*#LW(GWjN{!~+i73hO3ZGuq$%!U%Ix6qeNzd{Z)rP%4n%?BPhaAm z?Vrjzs?-A~EG3)CMws9^)`H>4X&Si6L}Jm+U^T;Tx8g!6q*Nw2xgiB|1esLubw&uK zbK8aykVif^m2e1DGhm32G*DHL-Vn_IX2ZknZI`K_Bvx}rhgS2R-n4p7&V_n|opDX7 zv(om5%v8>?arC5jV@h`qV9-Os4)<`hc+aExUzF3ib#fmgQfruk<_JmnIN`<^e$e;K zo5WqMpym-FjOhHv2 B=E&&ifW}wIUmy)4Z^Gog(gTX!F&F%+-e5Hf-5ntGX?DS0 z7o0EJ0b#5)1Ro!$yy!};8&s6pM^<-9y&5BD)YraD`LjqJVZ18DP^{B?~ zDn<1?80KaV_qDhbM#LkdA_GhfE=N)H*|=5UX4E_nJQBi!hFD8~nBLOhu#{5a%Ip|! zSKV(01{&G8@0xHJxkCq)T|X{E>g%1-o1)o^CaiDb$OfkQe_trkW7a(GwUx?L+!e$L z!iMRSM#kxPL!MS0wApCP87C5mqB3Rn;KT z8wj8ik2Z%Q(c1x4*g%yG$CCair`O=HSTC~rquxDLkUA zkup{dim3dIO8lb~6iNA6aH>KR>@pj|wiS?jm#@IaiVKgMF^1;Diejz-Spb#ail8x7 zeU-ZZOG}2r#6!?z>5P{$S@-OLry}9gLUI!<33rY9O~#DA+-J!^c=(LPnsztIuzr}gQBOw%7dlh!+1IjGIfO%&K{-z8Au zaKt&axBoV=>H%RoUud1pXeIobHj$w!Ta$=sisDS_R&fq+B^j?;U8&R#ss&;2kgO=1 z_t;kFzEbn{pHVS%c=1?+AOpRf#HghFYL<}bh@D9+n2K0b#xF&zOF}VEkua(SpV%-b zzdJAlQh5mBAjbYst^(*O3b-OH>~fdp6pza6;VgXMv7>**6GdTHD)pk1k08p&X$}q< zz>{Y{&|ppgIKX2HpOi3B1OW0(^cui1NRS}u6Uz>KaCl;4JeQZhR3dUxcI7P(eOb

(YQ>fBV&7ixI#4GMK454Izk=mjjUD*D*6jSK_Px*I$Lq#}Qg^)i@7##n{nZIh za!k`b-ACIau5LNZ-A!j2vdD60(?22q9>Ls!hPzr8w%FUCkqaki$cy{y2s;F2FudStJ}@rdrs!~ zSpkp+c(tusej-8s@FTq%pINEY!)iArpN_}_5G*5$ta&ySq$3~vR11oNESn~5F?F9J zH?_fa3mEn2SRd;KI8zQr#EQ)ej);yF+$F`^(;T3go`gP%?NFQKjuG5Sbv1lH1Z4g= zL_vj$rL$*S2FrFl)bR~N=N|SWAL7FzqG}-RQ;ufX zEFDeEtnBFpt<2u*KSfF5j}8CT@N}SmK$Zr)5VnU>c6gu)G(IhdRXC9zkgZV>ig{bv zKU_763}!yoJp%p9xbvyiQt^xKH9%s#KnvyXM2VQ`n^;-fJD3^1b+oau1KQhL+x=I{ zdSzsW`|0U=WsvA-DJZ09>4xYlf7SQxi$E_O|F9T8SiTNHlh-qSENR0>>L6Y2poQXh z`edw4%nSvs^etW8fOh|V;7)txhh>}wqz4L$rD);)GkV{M%8U}yO|l8VCW<3e*q^E6 zZc7`n1gVMwEpL9OPR`l^X#amu)lV-;i}asrAVR2TIWaKvw#YU~zT|an`-oiF*(;$) zQ(0a>GN=g4D1urVQhI(TI}!1j(g>TXEP0SZJ<#%x`Gvna-&+}B;s0JJ?3Jz4Z*&U1 zpq|~_p51`~i`yeEdfw-#G^odQK{_Hq3q5H0_r%y=TGW6BZw;+&fcEditR1b4{*SK- zSb14ExgmN9+HmK7`ax+)8gMG){|xE35}AK>Khsz~zN%+oLqkx01&asn{|_>IBC1`j&yE-@Ue z3gTCgYS+tUCKq%h2do?wGi2c3^PBQmA52;H#F_c-=RKInmMPgCeLV-La;4%G*cd)> zx!)wFYFu|d94v=31$atV?L5r5@bta3;}``Hrz&P43+5)F0~OpPhiYIS5?PPED-MAX zSJZ2{)kysb;Um2g1jwAgD|w1?mPY|vv%*{>SbLcP^(l1NM0_Rtua^a+VRgGLY&cpu zW%9;`sh-3SYung3fvF;Ks?xeGdfArKXj-$cvvw7&MV|5YMwRYO}w{u3vbt1i#yRY8^(FH$Vr4R zH3-JfXE(y_PFOPC7AKCnE*zNf_8}L!MrGiI>WJjX4S!BceeZlVKr@$pjh4Za@lyQt z6ny|fafU8N(pn19!=o9_NgU!4oHEDM(N4X!?JkKwTRo0<(}Ngi_PREovWdi?^@;^B zon=24p!i*kcZo>9aPwRBZsl&DtJnJDlA(vVrgM-N9Y zyLq*UNx4eUgG^AWiS!XP#$-Pzvz#bi1Fd6t8=dds%BaXUh=U*nN?Rx*(_HA`b9g_p z_nRzr21gTdR)hqxW*HgDgu?XYGcpHtvKlYpcx3hdSP9v;XZXg+ng>9AV5&eUxXNb? zLF!e;VmSgv6@ZtTZQ)JKzhjV2_I@+HayCd{haD@A-IGM12d^tSru#J@Z&&pToLYBn zI#?i#R4F-osT94gDCR>AZGTNBeM@M}k$h$XuDHm2Hpgfw-wNPXXnSq~D|#W<3US58 zt;W9Rwd*f_zZm>NF#fD7R}T8Pjc zG4aw-Ls29)ED<4#$)wI|rP)$czYDJ0Jf?9wYYkHw47Tn#9YrKzDY-yQ62QTM=pCv5 zNj9g=-rkUFBR8kBm0B3@YBpHZK}%AqZfZ@s7gXs~W~#E9aiXx6x8uh#jx)H}b5o`V zCUSYGSeoXHTT=%K;YA4hB4o~unE!>sT+g=WsaVgapGsMbCupA3weQOiGt040t^R6#`Rx;lKGh0FZiDeQ+GVpZFb(;FW@L4Zb`5S12D|UmK3#)Dz7~Lg z9HVQXFFK~eILT&`-I&3&AK!6vlR=H1;&z}$iBbhFhmh}z>ZMs_MF6CJM#58=_?O-) zNW${(iwGnLoL&xISTPV^;>P>Sp#;9B3tSO#fe^)1qxu%u3>Vt$jzb3yX`b%hy*PAu z+bQ?4boXOv0Pl3w8_Y(6gZ@>!ds=-4XTy_KY#{Q~3z1}g%(Ifzr0C9lL>ln@%9(Vqtg9wdTMi7UC0^|TMF<54lFe0w%8$wYUbA@;w7Y1qk>R=wT36RgTZbn0 ze&m?j+o`CR7YRd${G~(s>uVmH4BFlgV;yIG_AtO+EO&m-!ZuBBwn=32nif%f>1Lz$ z%}DIdsMO*m+NCy4c@zf6&!59iw&i5*HaXH&)6o^E_^2 zLk#Z#h)hFZZQ$_H>yHq&p~tZ4zIUVW)!+1X%C}Zy-%>Exnd1+*4<+5$ts}{ zDGg-bq?c08roGK$*%^B@NPh7{)4y)T#T24|VDJV@4eAfi%Sz^n;+r8)zckmz6b1;Lz% zWrpI?+cj%#xJ*Z(_MBQxdGQCYm$1I$O6AtqwAFN7)MS>_BX?Q!o86mFfm%vlpBXbZui&dm>)==36W^| zA4bTjR_WS&5%srAGZ<{~)zjBO(;4ms*ZAu0N}Pw5OLluZA)JxOZ^P3ukw+8s?!$2b z6xUL9Q`+joWxP^){o_(Pk!-L%RW0*VjO|7bbr8RI8y49s`@!j0tUY z(Ebhg?{iLc`4g61yy*BF^**2DE?ebZ;FP6|{p=mCCdb7qRk_OQAL)|37YmNLsaM5r zuj#WXsXQt0VgDdF9H|ybTCb|1jOYrjT@>039LeQ%t;v??s_A>#tHgErKUDf^9k?<> zFX+aav~rw5yk6ym?{)jhu>A{>{g;-rTdHLav?yPCBC3VXgRnsoX=GwgQp z#hd{|=soB!J;y|C$=|g2H=I*ZHk`A~pVp<9n06T6Uy?-#*!#zZ z*!Q~*LfE%D8_sn-$EC#Nk;{w44_;_(P1A0VN-0MK5~tWpE6Yf;v`NloHRCMS5J6!q z$02m$IOEN)sym^u%ye^Hqqano*!`V9NSt$#N}P*LMuOH8K6lPhz4<%Jk`@oeWQkqxbgP}s#(}F zq9IBfyN`T_Fc4E?=tmnQeM ztm#NciI2-1OV9HwJR=Mya3h*oyQf_zEUoxIj!u5d4rfhUpILg`3g_h<=H2^zozl%U ztQkiOb^2M}R0QwBEkDCI0N87^91+%?J@E6FyYNqQ3!{#Khl}W7U|U;YU|7Eno}A6B zjI5pQ|GEc%sH5dPUt8&QTsCrMXhHZDED^ji`araE2$-HDnir$*LpZf72q{GJ!WW!EbSsr=$iRZB(dyQ9M$^4S46zAgSb zY;Kd+!*%t&VN2^BtG$vn^U0@q!vX8P;;b{83-9Kd3n!DhW}u#;8tbQ()?P0 z%6q=2?Wc7`s$w*54-7m@E*A#X{7pYHmb=`mkhk3<$eH1BB0OY~hsD-?k*mJA^J5bXiFFsb zcNaN(ai)dxhyBDqEJ?X->g_c>ogi2!I(q+LYWdUAfrA$x5BXC9phJfjt4O>W8{U4g z0lmAsqbww^mOV{2Vms3N?$UIZr0=+}thOs%Eavv@ouNYrIZN9@h{YNFa;+DcDv~Sr z!mI|Ck2l}OgNs979#KLilaladz*) z#@RTI?Ct$))WI{@!dS~4xQHN1kDjR!x6TRr&upR^Pd)*2@jrKo16A0Y=t|P zV2CR{-v@PMZx`gEMMTQ zfHi}Su-7e%YP&o7R5|UGIm~IY-r?YOYD^hM}VvOwNv?Q)7D<{N}v_Ecujx@GcNXF?-E~R25;mKu)b(pp2A6s3!afr z{3ZOp-cZA=VOCcu5oaO%Z(;4o9nk4BRom~?VAEQG*k4nxO4y6mr{RdC4~;^iW)#&k zbVK-vmS1BEQWMC85(3I!-%=)s>++CIp^l0nw4ccX3|?P-&4Nxj3t591&-& zRDq5D`h$SGs*9z!_+cneYmro7$N|Mp0ILoDJg_qi0s-S|B%%)xBd8+5urMWo`0Il#-I% z>{d#pIjuFzDvIF|Hj~=GncffmSFl|?MfsA*q2xMTu4p>JZ%s5&=a!*kvCz4EaL-~b ztjTAl+bhU|RuH+w4|IauV3AY;N5P*@lfUYa$GTTpnlz4DbPTk%_=Brt_eFtB&z004yazjcJl3U zsq`x$jWhYY@_i5~>ZT2q@*7etQ+uWQ=|R3$HnXyB)fKyYzAL|V31oNMn;xChq!ykF z{A{Epf3&rNs^U7W2*o%C*^h7RM9~z|Y=YGu9(uq+)qH6C{bA7L~X${YQ3<+AS%2?tL3 zrV@X%9dUEOLYYlZ#Bi3@5ItRxgY{7Gn+ydUS2jTC@!MOb0I>2pg}GP5}rNXe7PgY3~e7 zT||6?-mHh}n)!~ZJIxwYi)cugPe8i+W5gFICd=>$u<5BOnV~9Zw9*#a z5RsT(;|2<^c)34X@@YJ>fddzf#&5+u*(uI9&`I2Dc&}eCEEeveA7PJFn-OW?i%Q8 zLwTI8#9>**s8Q{h^0KnOzpWI;c;DsmE@sM}(Wt36wL4a_1t-v|K&7T;EU;VE3@(YH zCxte)!;-{}iO96XS44gex4%#y8HFFeNc$YiBRJKnNiy<$ycXZ9xn;Z?P#K)_YKCpJ zG?=@BjmjGDNfvQs z$@JV?3R@{@*)d4%=n2Kz%3R6HZALGmp{}f|RcS|5W;85lPpM7j;lNp;%(vYfbXaZl z`>=nhqbI+h5U5ErKjJ1d1GCvO9xkg-0NZyH&F8KY<>{)b!S?cJA_52Nfk5af1<`b7 zB+T5opogKhaxs4A9MgT6J*<64ZE`i&8LAtsoC_Fx^mcD8P)^XhIBC`VQRu2nf#D^s+>R+ zog$j78*P}Y+op#!!?4Eb2ivP+7g4hxv6L?NTg_iY<$z(Ico}98aFn)5S#BmJYr;1B zUMCu8JI2Ui3NEL$^#y2KT=gj_^L+hY8zH)hu^H4m;ycaOucq#vDa)|lD48CTC>2=V zkNFmM)?-K~8sI7H`bzOKj185a(%(~?ebzpkFt>2#FeIJNv`A<|g)25JGF{gZ=sQc4 zmp#ETAF>?aiZ`QRYnd1+(g2OqjCN(<+$&11A+sTH7pk!=Hn^QMU7GB{4v!;~uTlrl zHx%NKZ(-4kn<2qubHiBo)ajW0mX{sMPKu`bdAV0h4x9}bDwK|Av!j;v4#o+o>w!JYuI2TDP;J zEG_bqNmw+}l}<%WFlHo!;7*lX(0F}n^av&5X);yjvJfR+0*$G~9a+uaWrcg_<^=AO z)yYiN3?HfP(<$cCha2R|Q0m##$=hSw#=gjG_wF z-g>D@muNKew)>IgSKccc4bQvLixT7O(+p6TT0xtgi3=5t4DM43E^$2gyj25PMM()@vC$+cpWPix z)2rRVjVPT{9ZS_IF?5y@Pbw1>i%3>)ibo9Qs2epQ#v9n8><#(aryx0{W~aV7W7b2| z84_IdrH1(jQfzk&oSi;6i5}vTph2K;*I5&;{$x1}IF?wA0B&!z|K^?_Jk+>3i81kt zW6T|y#XPs?8+%0!N7#}xT_!AzeyHBoy2E{VuzV(hf(6!4xk-LwHqsa_Dg8bn=gPJ(xX_UTx89oUQJ;8mJ^hUpYs2UC?5p@y zr}?Re>_=;bl>`4Pbj`0QRKr~;n!}IUa{i~rhtdtwWjXbQ#+mripTC5WfOSI!I>s2% z6UIlfKfe3G*jqjcFMSq^6(~qpxyTamfsK>GVy0tot+)uGnf-cSn#Eh#ou;=4%Al!x zKEH(~7lpJqo+f#BrO@WnbvZ*A z;}yy(J$?z2Vr2{q=YWA+vSXyIlRi7Ai!JJLnZ6SPv{X*64bOaEvB8ZRy30ojdtuFv z&+&cjN*(xT?Gv&nx;$SU1tiTKvZ8)m@NgWA*I_Ef^Rf~YS84XeDwB}ATg$n>!OYs` zuPiKQ+t;hwCb3VU;r=9unt^VN9%elFq7p(tvM|R_MxVXFtrC`%VG3pTYisM8t#Pbo zx#e;!b0^=&wJ0Y(v5L=()Rmc_cgvTv9~N`=G|+3Wq1r$8){LME;e?X=$BQSUzjYY> z%ya^lTE5Dt?qG0X3@eQPjt0G^I1vhPw3Dd8le z8ZMiSbi*tbZ_uWsdKP%V(N`_ssIx44_Mol5B(GJ)@oq#AVzx8BmN+yY54kvuMoi?$ zRQ-{~#0&IUB$>C&Q$vaP$D|#etb!;W>FVr6Jw0Rmp^2k9x)Jpd6aeC*(3IT4fCh;U zEm*&sq!|W2nl=MUPNa%cqXu#)2@&)s*0$ot6%tk5F*zV9vJ;gr5W0^+CXqMC%I?A* zd<$hyc$1h`zbkJ*DWT>a^BE+jR@A`PxqVZ=5Ua66lX_ErPkYGvz@2!|GZ3QCd#cBw z*Z>`5Oy4Wx>x)~nbigi<{IPo|K+l5l9ZW-2>es4;d^H<|R^X4KCI$ZSsu%!F9flfl zjIm4ir6Xj&1PCO&doxPk4ZmLr_fc>Yv+zxE{1@xqWVSs)rqw|uj;i98aKbhLBFC6i z{ti%Lkv?5MB&iQR=nwnIp zc~gc(j_MD!@Y1g`7VEo?ti;ip+&DCx716`gr3_YmII!EvU^MOIkN>}p_0%K1LajfWaWe$ z8wXckinI#AV7~3ahye^pmyw_}@s{458)!*?$Kcc()C+fQIprIxt?rbE;0-{i+4Mz? zoRV!!!6lV>X;Dbie{rji8uS$__(iyE_*5YL$G7rpbXt6P$eVT(3PX2Tv{lvMXVL38 zR|;|Zkb=Anxr3!lNVez18)5~^<)}MeKw#@s=O@H5}hk9GH`XzzGw-W z7T~o8TF`xY#l_X97gEX0NH~SG^=X8Q`Xx4gzrZ8}t-*D0>u!~v!mBf)gHj8%QtVXC z>bh0qLPY=Y%E^z6BZoTG+@YS3p^h=1OBn#LDriRxPUl$rWZ63U#jU2ZcwJVghIpG@ z(xIeK3XA#&TZ|Y@l1XY<(l0a{I%e3vs^ZdLKyyGndtD*{WefD)YVs_d@rlw;1`cs){- zO<UGw~>J3FiF_1Wp|n3(J+1YO!-wM+*mqhkVOPkuh^e%Us^pPCeWeE5ha z+1(u-9jU8F-J9XZI{FXl{lk%m1>6YW?S6cYl5|K zu2syrpX;*}w!kK2oIg!c#g3YXCC-62A~8nfP)9+S*DYAA#tx@fH#$uR6tz3BC3~4e z(>T=N=^)Zznj=eePZqvx=Gg3Ay0{n&71zrh{8;Cnch-o$SwrzN{;;CiyRyamN4*GAgA`%Zq}^x%*~ax?oA_freT z8zml34Fq|ZpOk4{G>;U3n6=#|gE9(-n(ZmxS-S8AB3Dmm1{YP!bd2M7$Z2R=!y((9 z0+_>TnBL7>UbhEc{Bcf>6Ce{Q z4IcM zy5M!=y{Sv-KiXYUK0-{-rb`1XmEG7~K6VOLJXFkZV%_upyqCXC>E5w8b-PV_bbaF; za3=hCn|`*S`#`RI$4h;DIZS>1Bf+;_%PirJmnO}sKe2^24PW`Xys?|V|MqnI{-GfB z6z2B+dV1Se{qp?EkdZ%vw!z2uT^}A`(;3F(y4FP-@$ss&g&Lnv`@=nH&7--42NU1t zu&dzg>=@>-M;8Z|`kbcAh%F(TVjlEkz6dn}mTEUsN(9got9F`FSG~MV(hc|zZh7H1 zZ0aLPD((@|*!gA}v-IbJpoouu=zAmISp|+D&%J%e?S%dfiQA0ZB=|OK7UsGTl{PG1 zoc|t_69*2;fBQ2l?rBmOPbZ|{3S<$ag#!aa1x*S+70~Lxik7f7D9y>r;hnN8$o`}A zWUhG*h;QugF#{c80u2TR|F6UT1dxON(K|b!r9C~})9+soe9Fgj;loWd0`1uX+70I) z2R1;0fxQPh=!2X_`k?GQJD`Fc$bDqzUMvj(1VNgpvKfx!A^FaE~E)d2C_IX1x68{Dx zYGmf{r)TlG9vMS*vTTrm0g#?2N9I%cQx5~EG5&2!`?F6OSXvue7=hf7cKYw1RQk` z{5R6T$Ovex?`Y}pA6@ndV#MIZrKtiAw&8^KEb=}~ze1j!T{)*0X&hwPXzd8KDzi@t^K=~`|DL~KN%YVbb6MljH#>@Pi z^xWqAH;E|m7t&u|$KRNKpA(;ZbpIyS{f_uQId-38pIdAH#;Se(jnMzWX#1S{+!FgY z_40SrX9n5lwCA?fziH`7ztQ+l6YF!>bKmLTFzV#r!2Wj^>T~#Wr|94CsbAs$@Qpra mJilT3Hv_fc7lF@ipDIX0gWfBiuBg~x2B0e$S=-a);r{{KZ8kjs literal 0 HcmV?d00001 diff --git a/simscape_subsystems/index.org b/simscape_subsystems/index.org index d8911e7..18ffef6 100644 --- a/simscape_subsystems/index.org +++ b/simscape_subsystems/index.org @@ -108,6 +108,69 @@ These functions are defined below. save('./mat/conf_simscape.mat', 'conf_simscape'); #+end_src +* Logging Configuration +:PROPERTIES: +:header-args:matlab+: :tangle ../src/initializeLoggingConfiguration.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: +<> + +** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: +#+begin_src matlab + function [] = initializeLoggingConfiguration(args) +#+end_src + +** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: +#+begin_src matlab + arguments + args.log char {mustBeMember(args.log,{'none', 'all'})} = 'none' + args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-3 + end +#+end_src + +** Structure initialization +:PROPERTIES: +:UNNUMBERED: t +:END: +#+begin_src matlab + conf_log = struct(); +#+end_src + +** Add Type +:PROPERTIES: +:UNNUMBERED: t +:END: +#+begin_src matlab + switch args.log + case 'none' + conf_log.type = 0; + case 'all' + conf_log.type = 1; + end +#+end_src + +** Sampling Time +:PROPERTIES: +:UNNUMBERED: t +:END: +#+begin_src matlab + conf_log.Ts = args.Ts; +#+end_src + +** Save the Structure +:PROPERTIES: +:UNNUMBERED: t +:END: +#+begin_src matlab + save('./mat/conf_log.mat', 'conf_log'); +#+end_src + * Ground :PROPERTIES: :header-args:matlab+: :tangle ../src/initializeGround.m diff --git a/simulink_project/index.org b/simulink_project/index.org index 9d3ce3c..82f6586 100644 --- a/simulink_project/index.org +++ b/simulink_project/index.org @@ -74,7 +74,7 @@ The startup script is defined below and is exported to the =project_startup.m= s 'createDir', true); %% Load the Simscape Configuration - load('mat/conf_simscape.mat'); + load('mat/conf_simulink.mat'); #+end_src When the project closes, it runs the =project_shutdown.m= script defined below. diff --git a/src/project_startup.m b/src/project_startup.m index 0cca35e..c635e75 100644 --- a/src/project_startup.m +++ b/src/project_startup.m @@ -15,4 +15,4 @@ Simulink.fileGenControl('set',... 'createDir', true); %% Load the Simscape Configuration -load('mat/conf_simscape.mat'); +load('mat/conf_simulink.mat');