From a86d9ea9fdb7e5e4f63adfa12047c8045ee86e7f Mon Sep 17 00:00:00 2001 From: Thomas Dehaeze Date: Fri, 2 Jul 2021 14:56:02 +0200 Subject: [PATCH] Rework analysis: encoders fixed to the plates --- figs/control_architecture_iff.pdf | Bin 82956 -> 79778 bytes figs/control_architecture_iff.png | Bin 8537 -> 7848 bytes figs/control_architecture_iff.svg | Bin 28850 -> 25934 bytes test-bench-nano-hexapod.org | 748 ++++++++++++++++-------------- 4 files changed, 392 insertions(+), 356 deletions(-) diff --git a/figs/control_architecture_iff.pdf b/figs/control_architecture_iff.pdf index 67e4fe8a822ef5650c92c25f52f25bcb75c9c9b7..95e53161ad5a4b230e1deb2101692338245184e9 100644 GIT binary patch delta 5845 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

SU%Sf#=A5W@Sfu#_HEG%;?fIVaP~pWx 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 diff --git a/test-bench-nano-hexapod.org b/test-bench-nano-hexapod.org index 67c3755..63f8067 100644 --- a/test-bench-nano-hexapod.org +++ b/test-bench-nano-hexapod.org @@ -208,7 +208,7 @@ i_lf = f < 250; % Points for low frequency excitation i_hf = f > 250; % Points for high frequency excitation #+end_src -*** DVF Plant +*** Transfer function from Actuator to Encoder First, let's compute the coherence from the excitation voltage and the displacement as measured by the encoders (Figure [[fig:enc_struts_dvf_coh]]). #+begin_src matlab @@ -321,7 +321,7 @@ exportFig('figs/enc_struts_dvf_frf.pdf', 'width', 'wide', 'height', 'tall'); #+RESULTS: [[file:figs/enc_struts_dvf_frf.png]] -*** IFF Plant +*** Transfer function from Actuator to Force Sensor First, let's compute the coherence from the excitation voltage and the displacement as measured by the encoders (Figure [[fig:enc_struts_iff_coh]]). #+begin_src matlab @@ -1666,25 +1666,25 @@ The control architecture is shown in Figure [[fig:control_architecture_iff_strut The system as then a new input $\bm{u}^\prime$, and the transfer function from $\bm{u}^\prime$ to $d\bm{\mathcal{L}}_m$ should be easier to control than the initial transfer function from $\bm{u}$ to $d\bm{\mathcal{L}}_m$. #+begin_src latex :file control_architecture_iff_struts.pdf - \begin{tikzpicture} - % Blocs - \node[block={3.0cm}{2.0cm}] (P) {Plant}; - \coordinate[] (inputF) at ($(P.south west)!0.5!(P.north west)$); - \coordinate[] (outputF) at ($(P.south east)!0.7!(P.north east)$); - \coordinate[] (outputL) at ($(P.south east)!0.3!(P.north east)$); +\begin{tikzpicture} + % Blocs + \node[block={3.0cm}{2.0cm}] (P) {Plant}; + \coordinate[] (inputF) at ($(P.south west)!0.5!(P.north west)$); + \coordinate[] (outputF) at ($(P.south east)!0.7!(P.north east)$); + \coordinate[] (outputL) at ($(P.south east)!0.3!(P.north east)$); - \node[block, above=0.4 of P] (Kiff) {$\bm{K}_\text{IFF}$}; - \node[addb, left= of inputF] (addF) {}; + \node[block, above=0.4 of P] (Kiff) {$\bm{K}_\text{IFF}$}; + \node[addb, left= of inputF] (addF) {}; - % Connections and labels - \draw[->] (outputF) -- ++(1, 0) node[below left]{$\bm{\tau}_m$}; - \draw[->] (outputL) -- ++(1, 0) node[below left]{$d\bm{\mathcal{L}}_m$}; + % Connections and labels + \draw[->] (outputF) -- ++(1, 0) node[below left]{$\bm{\tau}_m$}; + \draw[->] (outputL) -- ++(1, 0) node[below left]{$d\bm{\mathcal{L}}_m$}; - \draw[->] ($(outputF) + (0.6, 0)$)node[branch]{} |- (Kiff.east); - \draw[->] (Kiff.west) -| (addF.north); - \draw[->] (addF.east) -- (inputF) node[above left]{$\bm{u}$}; - \draw[<-] (addF.west) -- ++(-1, 0) node[above right]{$\bm{u}^\prime$}; - \end{tikzpicture} + \draw[->] ($(outputF) + (0.6, 0)$)node[branch]{} |- (Kiff.east); + \draw[->] (Kiff.west) -| (addF.north); + \draw[->] (addF.east) -- (inputF) node[above left]{$\bm{u}$}; + \draw[<-] (addF.west) -- ++(-1, 0) node[above right]{$\bm{u}^\prime$}; +\end{tikzpicture} #+end_src #+name: fig:control_architecture_iff_struts @@ -2167,7 +2167,6 @@ exportFig('figs/comp_undamped_opt_iff_gain_diagonal.pdf', 'width', 'wide', 'heig *** Experimental Results - Damped Plant with Optimal gain <> - **** Introduction :ignore: Let's now look at the $6 \times 6$ damped plant with the optimal gain $g = 400$. @@ -3126,15 +3125,17 @@ In this section, the encoders are fixed to the plates rather than to the struts [[file:figs/IMG_20210625_083801.jpg]] It is structured as follow: -- Section [[sec:enc_plates_plant_id]]: The dynamics of the nano-hexapod is identified -- Section [[sec:enc_plates_comp_simscape]]: The identified dynamics is compared with the Simscape model -- Section [[sec:enc_plates_iff]]: The Integral Force Feedback (IFF) control strategy is applied and the dynamics of the damped nano-hexapod is identified and compare with the Simscape model -- Section [[sec:hac_iff_struts]]: The High Authority Control (HAC) in the frame of the struts is developed -- Section [[sec:hac_iff_struts_ref_track]]: Some reference tracking tests are performed in order to experimentally validate the HAC-LAC control strategy. +- Section [[sec:enc_plates_plant_id]]: The dynamics of the nano-hexapod is identified. +- Section [[sec:enc_plates_comp_simscape]]: The identified dynamics is compared with the Simscape model. +- Section [[sec:enc_plates_iff]]: The Integral Force Feedback (IFF) control strategy is applied and the dynamics of the damped nano-hexapod is identified and compare with the Simscape model. ** Identification of the dynamics <> *** Introduction :ignore: +In this section, the dynamics of the nano-hexapod with the encoders fixed to the plates is identified. + +First, the measurement data are loaded in Section [[sec:enc_plates_plant_id_setup]], then the transfer function matrix from the actuators to the encoders are estimated in Section [[sec:enc_plates_plant_id_dvf]]. +Finally, the transfer function matrix from the actuators to the force sensors is estimated in Section [[sec:enc_plates_plant_id_iff]]. *** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) @@ -3156,7 +3157,11 @@ addpath('./mat/'); addpath('./src/'); #+end_src -*** Load Measurement Data +*** Data Loading and Spectral Analysis Setup +<> + +The actuators are excited one by one using a low pass filtered white noise. +For each excitation, the 6 force sensors and 6 encoders are measured and saved. #+begin_src matlab %% Load Identification Data meas_data_lf = {}; @@ -3166,8 +3171,7 @@ for i = 1:6 end #+end_src -*** Spectral Analysis - Setup -#+begin_src matlab +#+begin_src matlab :exports none %% Setup useful variables % Sampling Time [s] Ts = (meas_data_lf{1}.t(end) - (meas_data_lf{1}.t(1)))/(length(meas_data_lf{1}.t)-1); @@ -3182,9 +3186,10 @@ win = hanning(ceil(1*Fs)); [~, f] = tfestimate(meas_data_lf{1}.Va, meas_data_lf{1}.de, win, [], [], 1/Ts); #+end_src -*** DVF Plant -First, let's compute the coherence from the excitation voltage and the displacement as measured by the encoders (Figure [[fig:enc_plates_dvf_coh]]). +*** Transfer function from Actuator to Encoder +<> +Let's compute the coherence from the excitation voltage $\bm{u}$ and the displacement $d\bm{\mathcal{L}}_m$ as measured by the encoders. #+begin_src matlab %% Coherence coh_dvf = zeros(length(f), 6, 6); @@ -3194,6 +3199,8 @@ for i = 1:6 end #+end_src +The obtained coherence shown in Figure [[fig:enc_plates_dvf_coh]] is quite good up to 400Hz. + #+begin_src matlab :exports none %% Coherence for the transfer function from u to dLm figure; @@ -3227,7 +3234,7 @@ exportFig('figs/enc_plates_dvf_coh.pdf', 'width', 'wide', 'height', 'normal'); #+RESULTS: [[file:figs/enc_plates_dvf_coh.png]] -Then the 6x6 transfer function matrix is estimated (Figure [[fig:enc_plates_dvf_frf]]). +Then the 6x6 transfer function matrix is estimated. #+begin_src matlab %% DVF Plant (transfer function from u to dLm) G_dvf = zeros(length(f), 6, 6); @@ -3237,6 +3244,7 @@ for i = 1:6 end #+end_src +The diagonal and off-diagonal terms of this transfer function matrix are shown in Figure [[fig:enc_plates_dvf_frf]]. #+begin_src matlab :exports none %% Bode plot for the transfer function from u to dLm figure; @@ -3291,9 +3299,18 @@ exportFig('figs/enc_plates_dvf_frf.pdf', 'width', 'wide', 'height', 'tall'); #+RESULTS: [[file:figs/enc_plates_dvf_frf.png]] -*** IFF Plant -First, let's compute the coherence from the excitation voltage and the displacement as measured by the encoders (Figure [[fig:enc_plates_iff_coh]]). +#+begin_important +From Figure [[fig:enc_plates_dvf_frf]], we can draw few conclusions on the transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ when the encoders are fixed to the plates: +- the decoupling is rather good at low frequency (below the first suspension mode). + The low frequency gain is constant for the off diagonal terms, whereas when the encoders where fixed to the struts, the low frequency gain of the off-diagonal terms were going to zero (Figure [[fig:enc_struts_dvf_frf]]). +- the flexible modes of the struts at 226Hz and 337Hz are indeed shown in the transfer functions, but their amplitudes are rather low. +- the diagonal terms have alternating poles and zeros up to at least 600Hz: the flexible modes of the struts are not affecting the alternating pole/zero pattern. This what not the case when the encoders were fixed to the struts (Figure [[fig:enc_struts_dvf_frf]]). +#+end_important +*** Transfer function from Actuator to Force Sensor +<> + +Let's now compute the coherence from the excitation voltage $\bm{u}$ and the voltage $\bm{\tau}_m$ generated by the Force senors. #+begin_src matlab %% Coherence for the IFF plant coh_iff = zeros(length(f), 6, 6); @@ -3303,6 +3320,7 @@ for i = 1:6 end #+end_src +The coherence is shown in Figure [[fig:enc_plates_iff_coh]], and is very good for from 10Hz up to 2kHz. #+begin_src matlab :exports none %% Coherence of the IFF Plant (transfer function from u to taum) figure; @@ -3336,7 +3354,7 @@ exportFig('figs/enc_plates_iff_coh.pdf', 'width', 'wide', 'height', 'normal'); #+RESULTS: [[file:figs/enc_plates_iff_coh.png]] -Then the 6x6 transfer function matrix is estimated (Figure [[fig:enc_plates_iff_frf]]). +Then the 6x6 transfer function matrix is estimated. #+begin_src matlab %% IFF Plant G_iff = zeros(length(f), 6, 6); @@ -3346,6 +3364,7 @@ for i = 1:6 end #+end_src +The bode plot of the diagonal and off-diagonal terms are shown in Figure [[fig:enc_plates_iff_frf]]. #+begin_src matlab :exports none %% Bode plot of the IFF Plant (transfer function from u to taum) figure; @@ -3397,19 +3416,27 @@ exportFig('figs/enc_plates_iff_frf.pdf', 'width', 'wide', 'height', 'tall'); #+RESULTS: [[file:figs/enc_plates_iff_frf.png]] +#+begin_important +It is shown in Figure [[fig:enc_plates_iff_comp_simscape_all]] that: +- The IFF plant has alternating poles and zeros +- The first flexible mode of the struts as 235Hz is appearing, and therefore is should be possible to add some damping to this mode using IFF +- The decoupling is quite good at low frequency (below the first model) as well as high frequency (above the last suspension mode, except near the flexible modes of the top plate) +#+end_important + *** Save Identified Plants -#+begin_src matlab :tangle no +The identified dynamics is saved for further use. +#+begin_src matlab :exports none :tangle no save('matlab/mat/identified_plants_enc_plates.mat', 'f', 'Ts', 'G_iff', 'G_dvf') #+end_src -#+begin_src matlab :exports none :eval no +#+begin_src matlab :eval no save('mat/identified_plants_enc_plates.mat', 'f', 'Ts', 'G_iff', 'G_dvf') #+end_src ** Comparison with the Simscape Model <> *** Introduction :ignore: -In this section, the measured dynamics is compared with the dynamics estimated from the Simscape model. +In this section, the measured dynamics done in Section [[sec:enc_plates_plant_id]] is compared with the dynamics estimated from the Simscape model. *** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) @@ -3449,6 +3476,11 @@ addpath('nass-simscape/src/') addpath('nass-simscape/mat/') #+end_src +#+begin_src matlab +%% Load identification data +load('identified_plants_enc_plates.mat', 'f', 'Ts', 'G_iff', 'G_dvf') +#+end_src + #+begin_src matlab %% Open Simulink Model mdl = 'nano_hexapod_simscape'; @@ -3461,13 +3493,8 @@ Rx = zeros(1, 7); open(mdl) #+end_src -*** Load measured FRF -#+begin_src matlab -%% Load data -load('identified_plants_enc_plates.mat', 'f', 'Ts', 'G_iff', 'G_dvf') -#+end_src - -*** Dynamics from Actuator to Force Sensors +*** Identification Setup +The nano-hexapod is initialized with the APA taken as flexible models. #+begin_src matlab %% Initialize Nano-Hexapod n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... @@ -3476,6 +3503,8 @@ n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... 'actuator_type', 'flexible'); #+end_src +*** Dynamics from Actuator to Force Sensors +Then the transfer function from $\bm{u}$ to $\bm{\tau}_m$ is identified using the Simscape model. #+begin_src matlab %% Identify the IFF Plant (transfer function from u to taum) clear io; io_i = 1; @@ -3485,6 +3514,11 @@ io(io_i) = linio([mdl, '/dum'], 1, 'openoutput'); io_i = io_i + 1; % Force Sens Giff = exp(-s*Ts)*linearize(mdl, io, 0.0, options); #+end_src +The identified dynamics is compared with the measured FRF: +- Figure [[fig:enc_plates_iff_comp_simscape_all]]: the individual transfer function from $u_1$ (the DAC voltage for the first actuator) to the force sensors of all 6 struts are compared +- Figure [[fig:enc_plates_iff_comp_simscape]]: all the diagonal elements are compared +- Figure [[fig:enc_plates_iff_comp_offdiag_simscape]]: all the off-diagonal elements are compared + #+begin_src matlab :exports none %% Comparison of the plants (encoder output) when tuning the misalignment freqs = 2*logspace(1, 3, 1000); @@ -3663,14 +3697,7 @@ exportFig('figs/enc_plates_iff_comp_offdiag_simscape.pdf', 'width', 'wide', 'hei [[file:figs/enc_plates_iff_comp_offdiag_simscape.png]] *** Dynamics from Actuator to Encoder -#+begin_src matlab -%% Initialization of the Nano-Hexapod -n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... - 'flex_top_type', '4dof', ... - 'motion_sensor_type', 'plates', ... - 'actuator_type', 'flexible'); -#+end_src - +Now, the dynamics from the DAC voltage $\bm{u}$ to the encoders $d\bm{\mathcal{L}}_m$ is estimated using the Simscape model. #+begin_src matlab %% Identify the DVF Plant (transfer function from u to dLm) clear io; io_i = 1; @@ -3680,6 +3707,11 @@ io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Encoders Gdvf = exp(-s*Ts)*linearize(mdl, io, 0.0, options); #+end_src +The identified dynamics is compared with the measured FRF: +- Figure [[fig:enc_plates_dvf_comp_simscape_all]]: the individual transfer function from $u_3$ (the DAC voltage for the actuator number 3) to the six encoders +- Figure [[fig:enc_plates_dvf_comp_simscape]]: all the diagonal elements are compared +- Figure [[fig:enc_plates_dvf_comp_offdiag_simscape]]: all the off-diagonal elements are compared + #+begin_src matlab :exports none %% Comparison of the plants (encoder output) when tuning the misalignment freqs = 2*logspace(1, 3, 1000); @@ -3858,32 +3890,44 @@ exportFig('figs/enc_plates_dvf_comp_offdiag_simscape.pdf', 'width', 'wide', 'hei #+RESULTS: [[file:figs/enc_plates_dvf_comp_offdiag_simscape.png]] +*** Conclusion +#+begin_important +The Simscape model is quite accurate for the transfer function matrices from $\bm{u}$ to $\bm{\tau}_m$ and from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ except at frequencies of the flexible modes of the top-plate. +The Simscape model can therefore be used to develop the control strategies. +#+end_important + ** Integral Force Feedback <> *** Introduction :ignore: +In this section, the Integral Force Feedback (IFF) control strategy is applied to the nano-hexapod in order to add damping to the suspension modes. + +The control architecture is shown in Figure [[fig:control_architecture_iff]]: +- $\bm{\tau}_m$ is the measured voltage of the 6 force sensors +- $\bm{K}_{\text{IFF}}$ is the $6 \times 6$ diagonal controller +- $\bm{u}$ is the plant input (voltage generated by the 6 DACs) +- $\bm{u}^\prime$ is the new plant inputs with added damping + #+begin_src latex :file control_architecture_iff.pdf - \begin{tikzpicture} - % Blocs - \node[block={3.0cm}{3.0cm}] (P) {Plant}; - \coordinate[] (inputF) at ($(P.south west)!0.5!(P.north west)$); - \coordinate[] (outputF) at ($(P.south east)!0.8!(P.north east)$); - \coordinate[] (outputX) at ($(P.south east)!0.5!(P.north east)$); - \coordinate[] (outputL) at ($(P.south east)!0.2!(P.north east)$); +\begin{tikzpicture} + % Blocs + \node[block={3.0cm}{2.0cm}] (P) {Plant}; + \coordinate[] (inputF) at ($(P.south west)!0.5!(P.north west)$); + \coordinate[] (outputF) at ($(P.south east)!0.7!(P.north east)$); + \coordinate[] (outputL) at ($(P.south east)!0.3!(P.north east)$); - \node[block, above=0.4 of P] (Kiff) {$\bm{K}_\text{IFF}$}; - \node[addb={+}{}{-}{}{}, left= of inputF] (addF) {}; + \node[block, above=0.4 of P] (Kiff) {$\bm{K}_\text{IFF}$}; + \node[addb, left= of inputF] (addF) {}; - % Connections and labels - \draw[->] (outputF) -- ++(1, 0) node[below left]{$\bm{\tau}_m$}; - \draw[->] (outputL) -- ++(1, 0) node[above left]{$d\bm{\mathcal{L}}$}; - \draw[->] (outputX) -- ++(1, 0) node[above left]{$\bm{\mathcal{X}}$}; + % Connections and labels + \draw[->] (outputF) -- ++(1, 0) node[below left]{$\bm{\tau}_m$}; + \draw[->] (outputL) -- ++(1, 0) node[below left]{$d\bm{\mathcal{L}}_m$}; - \draw[->] ($(outputF) + (0.6, 0)$)node[branch]{} |- (Kiff.east); - \draw[->] (Kiff.west) -| (addF.north); - \draw[->] (addF.east) -- (inputF) node[above left]{$\bm{u}$}; - \draw[<-] (addF.west) -- ++(-1, 0) node[above right]{$\bm{u}^\prime$}; - \end{tikzpicture} + \draw[->] ($(outputF) + (0.6, 0)$)node[branch]{} |- (Kiff.east); + \draw[->] (Kiff.west) -| (addF.north); + \draw[->] (addF.east) -- (inputF) node[above left]{$\bm{u}$}; + \draw[<-] (addF.west) -- ++(-1, 0) node[above right]{$\bm{u}^\prime$}; +\end{tikzpicture} #+end_src #+name: fig:control_architecture_iff @@ -3891,6 +3935,8 @@ exportFig('figs/enc_plates_dvf_comp_offdiag_simscape.pdf', 'width', 'wide', 'hei #+RESULTS: [[file:figs/control_architecture_iff.png]] +- Section [[sec:enc_struts_effect_iff_plant]] + *** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> @@ -3947,36 +3993,10 @@ Rx = zeros(1, 7); colors = colororder; #+end_src -*** Identification of the IFF Plant -#+begin_src matlab -%% Initialize Nano-Hexapod -n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... - 'flex_top_type', '4dof', ... - 'motion_sensor_type', 'plates', ... - 'actuator_type', '2dof'); -#+end_src - -#+begin_src matlab -%% Identify the IFF Plant (transfer function from u to taum) -clear io; io_i = 1; -io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs -io(io_i) = linio([mdl, '/Fm'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensors - -Giff = exp(-s*Ts)*linearize(mdl, io, 0.0, options); -#+end_src - *** Effect of IFF on the plant - Simscape Model -#+begin_src matlab -load('Kiff.mat', 'Kiff') -#+end_src - -#+begin_src matlab -%% Identify the (damped) transfer function from u to dLm for different values of the IFF gain -clear io; io_i = 1; -io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs -io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Plate Displacement (encoder) -#+end_src +<> +The nano-hexapod is initialized with flexible APA and the encoders fixed to the struts. #+begin_src matlab %% Initialize the Simscape model in closed loop n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... @@ -3985,10 +4005,27 @@ n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... 'actuator_type', 'flexible'); #+end_src +The same controller as the one developed when the encoder were fixed to the struts is used. #+begin_src matlab +%% Optimal IFF controller +load('Kiff.mat', 'Kiff') +#+end_src + +The transfer function from $\bm{u}^\prime$ to $d\bm{\mathcal{L}}_m$ is identified. +#+begin_src matlab +%% Identify the (damped) transfer function from u to dLm for different values of the IFF gain +clear io; io_i = 1; +io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs +io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Plate Displacement (encoder) +#+end_src + +First in Open-Loop: +#+begin_src matlab +%% Transfer function from u to dL (open-loop) Gd_ol = exp(-s*Ts)*linearize(mdl, io, 0.0, options); #+end_src +And then with the IFF controller: #+begin_src matlab %% Initialize the Simscape model in closed loop n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... @@ -3996,19 +4033,21 @@ n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... 'motion_sensor_type', 'plates', ... 'actuator_type', 'flexible', ... 'controller_type', 'iff'); -#+end_src -#+begin_src matlab +%% Transfer function from u to dL (IFF) Gd_iff = exp(-s*Ts)*linearize(mdl, io, 0.0, options); #+end_src -#+begin_src matlab :results value replace :exports results :tangle no +It is first verified that the system is stable: +#+begin_src matlab :results value replace :exports both :tangle no isstable(Gd_iff) #+end_src #+RESULTS: : 1 +The diagonal and off-diagonal terms of the $6 \times 6$ transfer function matrices identified are compared in Figure [[fig:enc_plates_iff_gains_effect_dvf_plant]]. +It is shown, as was the case when the encoders were fixed to the struts, that the IFF control strategy is very effective in damping the suspension modes of the nano-hexapod. #+begin_src matlab :exports none %% Bode plot of the transfer function from u to dLm for tested values of the IFF gain freqs = 2*logspace(1, 3, 1000); @@ -4083,11 +4122,11 @@ exportFig('figs/enc_plates_iff_gains_effect_dvf_plant.pdf', 'width', 'wide', 'he #+RESULTS: [[file:figs/enc_plates_iff_gains_effect_dvf_plant.png]] -*** Experimental Results - Damped Plant with Optimal gain -**** Introduction :ignore: -Let's now look at the $6 \times 6$ damped plant with the optimal gain $g = 400$. +*** Effect of IFF on the plant - FRF +The IFF control strategy is experimentally implemented. +The (damped) transfer function from $\bm{u}^\prime$ to $d\bm{\mathcal{L}}_m$ is experimentally identified. -**** Load Data +The identification data are loaded: #+begin_src matlab %% Load Identification Data meas_iff_plates = {}; @@ -4097,15 +4136,11 @@ for i = 1:6 end #+end_src -**** Spectral Analysis - Setup +And the parameters used for the transfer function estimation are defined below. #+begin_src matlab -%% Setup useful variables % Sampling Time [s] Ts = (meas_iff_plates{1}.t(end) - (meas_iff_plates{1}.t(1)))/(length(meas_iff_plates{1}.t)-1); -% Sampling Frequency [Hz] -Fs = 1/Ts; - % Hannning Windows win = hanning(ceil(1*Fs)); @@ -4113,34 +4148,9 @@ win = hanning(ceil(1*Fs)); [~, f] = tfestimate(meas_iff_plates{1}.Va, meas_iff_plates{1}.de, win, [], [], 1/Ts); #+end_src -**** Simscape Model +The estimation is performed using the =tfestimate= command. #+begin_src matlab -load('Kiff.mat', 'Kiff') -#+end_src - -#+begin_src matlab -%% Initialize the Simscape model in closed loop -n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... - 'flex_top_type', '4dof', ... - 'motion_sensor_type', 'plates', ... - 'actuator_type', 'flexible', ... - 'controller_type', 'iff'); -#+end_src - -#+begin_src matlab -%% Identify the (damped) transfer function from u to dLm for different values of the IFF gain -clear io; io_i = 1; -io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs -io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Plate Displacement (encoder) -#+end_src - -#+begin_src matlab -Gd_iff_opt = exp(-s*Ts)*linearize(mdl, io, 0.0, options); -#+end_src - -**** DVF Plant -#+begin_src matlab -%% IFF Plant +%% Estimation of the transfer function matrix from u to dL when IFF is applied G_enc_iff_opt = zeros(length(f), 6, 6); for i = 1:6 @@ -4148,223 +4158,7 @@ for i = 1:6 end #+end_src -#+begin_src matlab :exports none -%% Comparison of the plants (encoder output) when tuning the misalignment -freqs = 2*logspace(1, 3, 1000); - -i_input = 1; - -figure; -tiledlayout(2, 3, 'TileSpacing', 'Compact', 'Padding', 'None'); - -ax1 = nexttile(); -hold on; -plot(f, abs(G_enc_iff_opt(:, 1, i_input))); -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(1, i_input), freqs, 'Hz')))); -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/V]'); -title(sprintf('$d\\tau_{m1}/u_{%i}$', i_input)); - -ax2 = nexttile(); -hold on; -plot(f, abs(G_enc_iff_opt(:, 2, i_input))); -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(2, i_input), freqs, 'Hz')))); -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]); -title(sprintf('$d\\tau_{m2}/u_{%i}$', i_input)); - -ax3 = nexttile(); -hold on; -plot(f, abs(G_enc_iff_opt(:, 3, i_input)), ... - 'DisplayName', 'Meas.'); -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(3, i_input), freqs, 'Hz'))), ... - 'DisplayName', 'Model'); -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]); -legend('location', 'southeast', 'FontSize', 8); -title(sprintf('$d\\tau_{m3}/u_{%i}$', i_input)); - -ax4 = nexttile(); -hold on; -plot(f, abs(G_enc_iff_opt(:, 4, i_input))); -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(4, i_input), freqs, 'Hz')))); -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); -title(sprintf('$d\\tau_{m4}/u_{%i}$', i_input)); - -ax5 = nexttile(); -hold on; -plot(f, abs(G_enc_iff_opt(:, 5, i_input))); -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(5, i_input), freqs, 'Hz')))); -hold off; -xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -title(sprintf('$d\\tau_{m5}/u_{%i}$', i_input)); - -ax6 = nexttile(); -hold on; -plot(f, abs(G_enc_iff_opt(:, 6, i_input))); -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(6, i_input), freqs, 'Hz')))); -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); -title(sprintf('$d\\tau_{m6}/u_{%i}$', i_input)); - -linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'xy'); -xlim([20, 2e3]); ylim([1e-8, 1e-4]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/enc_plates_opt_iff_comp_simscape_all.pdf', 'width', 'full', 'height', 'tall'); -#+end_src - -#+name: fig:enc_plates_opt_iff_comp_simscape_all -#+caption: FRF from one actuator to all the encoders when the plant is damped using IFF -#+RESULTS: -[[file:figs/enc_plates_opt_iff_comp_simscape_all.png]] - -#+begin_src matlab :exports none -%% Bode plot for the transfer function from u to dLm -freqs = 2*logspace(1, 3, 1000); - -figure; -tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); - -ax1 = nexttile([2,1]); -hold on; -% Diagonal Elements FRF -plot(f, abs(G_enc_iff_opt(:,1,1)), 'color', [colors(1,:), 0.2], ... - 'DisplayName', '$d\mathcal{L}_{m,i}/u_i$ - FRF') -for i = 2:6 - plot(f, abs(G_enc_iff_opt(:,i,i)), 'color', [colors(1,:), 0.2], ... - 'HandleVisibility', 'off'); -end - -% Diagonal Elements Model -set(gca,'ColorOrderIndex',2) -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(1,1), freqs, 'Hz'))), '-', ... - 'DisplayName', '$d\mathcal{L}_{m,i}/u_i$ - Model') -for i = 2:6 - set(gca,'ColorOrderIndex',2) - plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(i,i), freqs, 'Hz'))), '-', ... - 'HandleVisibility', 'off'); -end - -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude $d_e/V_{exc}$ [m/V]'); set(gca, 'XTickLabel',[]); -ylim([1e-8, 1e-4]); -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 3); - -ax2 = nexttile; -hold on; -for i =1:6 - plot(f, 180/pi*angle(G_enc_iff_opt(:,i,i)), 'color', [colors(1,:), 0.2]); - set(gca,'ColorOrderIndex',2) - plot(freqs, 180/pi*angle(squeeze(freqresp(Gd_iff_opt(i,i), freqs, 'Hz')))); -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); -xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); -hold off; -yticks(-360:90:360); -ylim([-180, 180]); - -linkaxes([ax1,ax2],'x'); -xlim([20, 2e3]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/damped_iff_plates_plant_comp_diagonal.pdf', 'width', 'wide', 'height', 'tall'); -#+end_src - -#+name: fig:damped_iff_plates_plant_comp_diagonal -#+caption: Comparison of the diagonal elements of the transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ with active damping (IFF) applied with an optimal gain $g = 400$ -#+RESULTS: -[[file:figs/damped_iff_plates_plant_comp_diagonal.png]] - -#+begin_src matlab :exports none -%% Bode plot for the transfer function from u to dLm -freqs = 2*logspace(1, 3, 1000); - -figure; -tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); - -ax1 = nexttile([2,1]); -hold on; -% Off diagonal FRF -plot(f, abs(G_enc_iff_opt(:,1,2)), 'color', [colors(1,:), 0.2], ... - 'DisplayName', '$d\mathcal{L}_{m,i}/u_j$ - FRF') -for i = 1:5 - for j = i+1:6 - plot(f, abs(G_enc_iff_opt(:,i,j)), 'color', [colors(1,:), 0.2], ... - 'HandleVisibility', 'off'); - end -end - -% Off diagonal Model -set(gca,'ColorOrderIndex',2) -plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(1,2), freqs, 'Hz'))), '-', ... - 'DisplayName', '$d\mathcal{L}_{m,i}/u_j$ - Model') -for i = 1:5 - for j = i+1:6 - set(gca,'ColorOrderIndex',2) - plot(freqs, abs(squeeze(freqresp(Gd_iff_opt(i,j), freqs, 'Hz'))), ... - 'HandleVisibility', 'off'); - end -end - -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude $d_e/V_{exc}$ [m/V]'); set(gca, 'XTickLabel',[]); -ylim([1e-8, 1e-4]); -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 3); - -ax2 = nexttile; -hold on; -% Off diagonal FRF -for i = 1:5 - for j = i+1:6 - plot(f, 180/pi*angle(G_enc_iff_opt(:,i,j)), 'color', [colors(1,:), 0.2]); - end -end - -% Off diagonal Model -for i = 1:5 - for j = i+1:6 - set(gca,'ColorOrderIndex',2) - plot(freqs, 180/pi*angle(squeeze(freqresp(Gd_iff_opt(i,j), freqs, 'Hz')))); - end -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); -xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); -hold off; -yticks(-360:90:360); -ylim([-180, 180]); - -linkaxes([ax1,ax2],'x'); -xlim([20, 2e3]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/damped_iff_plates_plant_comp_off_diagonal.pdf', 'width', 'wide', 'height', 'tall'); -#+end_src - -#+name: fig:damped_iff_plates_plant_comp_off_diagonal -#+caption: Comparison of the off-diagonal elements of the transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ with active damping (IFF) applied with an optimal gain $g = 400$ -#+RESULTS: -[[file:figs/damped_iff_plates_plant_comp_off_diagonal.png]] - -*** Effect of IFF on the plant - FRF -#+begin_src matlab :tangle no -load('identified_plants_enc_plates.mat', 'f', 'G_dvf'); -#+end_src - +The obtained diagonal and off-diagonal elements of the transfer function from $\bm{u}^\prime$ to $d\bm{\mathcal{L}}_m$ are shown in Figure [[fig:enc_plant_plates_effect_iff]] both without and with IFF. #+begin_src matlab :exports none %% Bode plot of the transfer function from u to dLm for tested values of the IFF gain freqs = 2*logspace(1, 3, 1000); @@ -4437,17 +4231,259 @@ exportFig('figs/enc_plant_plates_effect_iff.pdf', 'width', 'wide', 'height', 'ta #+RESULTS: [[file:figs/enc_plant_plates_effect_iff.png]] +#+begin_important +As was predicted with the Simscape model, the IFF control strategy is very effective in damping the suspension modes of the nano-hexapod. +Little damping is also applied on the first flexible mode of the strut at 235Hz. +However, no damping is applied on other modes, such as the flexible modes of the top plate. +#+end_important + +*** Comparison of the measured FRF and the Simscape model +Let's now compare the obtained damped plants obtained experimentally with the one extracted from Simscape: +- Figure [[fig:enc_plates_opt_iff_comp_simscape_all]]: the individual transfer function from $u_1^\prime$ to the six encoders are comapred +- Figure [[fig:damped_iff_plates_plant_comp_diagonal]]: all the diagonal elements are compared +- Figure [[fig:damped_iff_plates_plant_comp_off_diagonal]]: all the off-diagonal elements are compared + +#+begin_src matlab :exports none +%% Comparison of the plants (encoder output) when tuning the misalignment +freqs = 2*logspace(1, 3, 1000); + +i_input = 1; + +figure; +tiledlayout(2, 3, 'TileSpacing', 'Compact', 'Padding', 'None'); + +ax1 = nexttile(); +hold on; +plot(f, abs(G_enc_iff_opt(:, 1, i_input))); +plot(freqs, abs(squeeze(freqresp(Gd_iff(1, i_input), freqs, 'Hz')))); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/V]'); +title(sprintf('$d\\tau_{m1}/u_{%i}$', i_input)); + +ax2 = nexttile(); +hold on; +plot(f, abs(G_enc_iff_opt(:, 2, i_input))); +plot(freqs, abs(squeeze(freqresp(Gd_iff(2, i_input), freqs, 'Hz')))); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]); +title(sprintf('$d\\tau_{m2}/u_{%i}$', i_input)); + +ax3 = nexttile(); +hold on; +plot(f, abs(G_enc_iff_opt(:, 3, i_input)), ... + 'DisplayName', 'Meas.'); +plot(freqs, abs(squeeze(freqresp(Gd_iff(3, i_input), freqs, 'Hz'))), ... + 'DisplayName', 'Model'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]); +legend('location', 'southeast', 'FontSize', 8); +title(sprintf('$d\\tau_{m3}/u_{%i}$', i_input)); + +ax4 = nexttile(); +hold on; +plot(f, abs(G_enc_iff_opt(:, 4, i_input))); +plot(freqs, abs(squeeze(freqresp(Gd_iff(4, i_input), freqs, 'Hz')))); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); +title(sprintf('$d\\tau_{m4}/u_{%i}$', i_input)); + +ax5 = nexttile(); +hold on; +plot(f, abs(G_enc_iff_opt(:, 5, i_input))); +plot(freqs, abs(squeeze(freqresp(Gd_iff(5, i_input), freqs, 'Hz')))); +hold off; +xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +title(sprintf('$d\\tau_{m5}/u_{%i}$', i_input)); + +ax6 = nexttile(); +hold on; +plot(f, abs(G_enc_iff_opt(:, 6, i_input))); +plot(freqs, abs(squeeze(freqresp(Gd_iff(6, i_input), freqs, 'Hz')))); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); +title(sprintf('$d\\tau_{m6}/u_{%i}$', i_input)); + +linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'xy'); +xlim([20, 2e3]); ylim([1e-8, 1e-4]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/enc_plates_opt_iff_comp_simscape_all.pdf', 'width', 'full', 'height', 'tall'); +#+end_src + +#+name: fig:enc_plates_opt_iff_comp_simscape_all +#+caption: FRF from one actuator to all the encoders when the plant is damped using IFF +#+RESULTS: +[[file:figs/enc_plates_opt_iff_comp_simscape_all.png]] + +#+begin_src matlab :exports none +%% Bode plot for the transfer function from u to dLm +freqs = 2*logspace(1, 3, 1000); + +figure; +tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); + +ax1 = nexttile([2,1]); +hold on; +% Diagonal Elements FRF +plot(f, abs(G_enc_iff_opt(:,1,1)), 'color', [colors(1,:), 0.2], ... + 'DisplayName', '$d\mathcal{L}_{m,i}/u_i$ - FRF') +for i = 2:6 + plot(f, abs(G_enc_iff_opt(:,i,i)), 'color', [colors(1,:), 0.2], ... + 'HandleVisibility', 'off'); +end + +% Diagonal Elements Model +set(gca,'ColorOrderIndex',2) +plot(freqs, abs(squeeze(freqresp(Gd_iff(1,1), freqs, 'Hz'))), '-', ... + 'DisplayName', '$d\mathcal{L}_{m,i}/u_i$ - Model') +for i = 2:6 + set(gca,'ColorOrderIndex',2) + plot(freqs, abs(squeeze(freqresp(Gd_iff(i,i), freqs, 'Hz'))), '-', ... + 'HandleVisibility', 'off'); +end + +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude $d_e/V_{exc}$ [m/V]'); set(gca, 'XTickLabel',[]); +ylim([1e-8, 1e-4]); +legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 3); + +ax2 = nexttile; +hold on; +for i =1:6 + plot(f, 180/pi*angle(G_enc_iff_opt(:,i,i)), 'color', [colors(1,:), 0.2]); + set(gca,'ColorOrderIndex',2) + plot(freqs, 180/pi*angle(squeeze(freqresp(Gd_iff(i,i), freqs, 'Hz')))); +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); +hold off; +yticks(-360:90:360); +ylim([-180, 180]); + +linkaxes([ax1,ax2],'x'); +xlim([20, 2e3]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/damped_iff_plates_plant_comp_diagonal.pdf', 'width', 'wide', 'height', 'tall'); +#+end_src + +#+name: fig:damped_iff_plates_plant_comp_diagonal +#+caption: Comparison of the diagonal elements of the transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ with active damping (IFF) applied with an optimal gain $g = 400$ +#+RESULTS: +[[file:figs/damped_iff_plates_plant_comp_diagonal.png]] + +#+begin_src matlab :exports none +%% Bode plot for the transfer function from u to dLm +freqs = 2*logspace(1, 3, 1000); + +figure; +tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); + +ax1 = nexttile([2,1]); +hold on; +% Off diagonal FRF +plot(f, abs(G_enc_iff_opt(:,1,2)), 'color', [colors(1,:), 0.2], ... + 'DisplayName', '$d\mathcal{L}_{m,i}/u_j$ - FRF') +for i = 1:5 + for j = i+1:6 + plot(f, abs(G_enc_iff_opt(:,i,j)), 'color', [colors(1,:), 0.2], ... + 'HandleVisibility', 'off'); + end +end + +% Off diagonal Model +set(gca,'ColorOrderIndex',2) +plot(freqs, abs(squeeze(freqresp(Gd_iff(1,2), freqs, 'Hz'))), '-', ... + 'DisplayName', '$d\mathcal{L}_{m,i}/u_j$ - Model') +for i = 1:5 + for j = i+1:6 + set(gca,'ColorOrderIndex',2) + plot(freqs, abs(squeeze(freqresp(Gd_iff(i,j), freqs, 'Hz'))), ... + 'HandleVisibility', 'off'); + end +end + +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude $d_e/V_{exc}$ [m/V]'); set(gca, 'XTickLabel',[]); +ylim([1e-8, 1e-4]); +legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 3); + +ax2 = nexttile; +hold on; +% Off diagonal FRF +for i = 1:5 + for j = i+1:6 + plot(f, 180/pi*angle(G_enc_iff_opt(:,i,j)), 'color', [colors(1,:), 0.2]); + end +end + +% Off diagonal Model +for i = 1:5 + for j = i+1:6 + set(gca,'ColorOrderIndex',2) + plot(freqs, 180/pi*angle(squeeze(freqresp(Gd_iff(i,j), freqs, 'Hz')))); + end +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); +hold off; +yticks(-360:90:360); +ylim([-180, 180]); + +linkaxes([ax1,ax2],'x'); +xlim([20, 2e3]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/damped_iff_plates_plant_comp_off_diagonal.pdf', 'width', 'wide', 'height', 'tall'); +#+end_src + +#+name: fig:damped_iff_plates_plant_comp_off_diagonal +#+caption: Comparison of the off-diagonal elements of the transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ with active damping (IFF) applied with an optimal gain $g = 400$ +#+RESULTS: +[[file:figs/damped_iff_plates_plant_comp_off_diagonal.png]] + +#+begin_important +From Figures [[fig:damped_iff_plates_plant_comp_diagonal]] and [[fig:damped_iff_plates_plant_comp_off_diagonal]], it is clear that the Simscape model very well represents the dynamics of the nano-hexapod. +This is true to around 400Hz, then the dynamics depends on the flexible modes of the top plate which are not modelled. +#+end_important + *** Save Damped Plant -#+begin_src matlab :tangle no +The experimentally identified plant is saved for further use. +#+begin_src matlab :exports none:tangle no save('matlab/mat/damped_plant_enc_plates.mat', 'f', 'Ts', 'G_enc_iff_opt') #+end_src -#+begin_src matlab :exports none :eval no +#+begin_src matlab :eval no save('mat/damped_plant_enc_plates.mat', 'f', 'Ts', 'G_enc_iff_opt') #+end_src ** Conclusion -* HAC-IFF +#+begin_important +In this section, the dynamics of the nano-hexapod with the encoders fixed to the plates is studied. + +It has been found that: +- The measured dynamics is in agreement with the dynamics of the simscape model, up to the flexible modes of the top plate. + See figures [[fig:enc_plates_iff_comp_simscape]] and [[fig:enc_plates_iff_comp_offdiag_simscape]] for the transfer function to the force sensors and Figures [[fig:enc_plates_dvf_comp_simscape]] and [[fig:enc_plates_dvf_comp_offdiag_simscape]]for the transfer functions to the encoders +- The Integral Force Feedback strategy is very effective in damping the suspension modes of the nano-hexapod (Figure [[fig:enc_plant_plates_effect_iff]]). +- The transfer function from $\bm{u}^\prime$ to $d\bm{\mathcal{L}}_m$ show nice dynamical properties and is a much better candidate for the high-authority-control than when the encoders were fixed to the struts. + At least up to the flexible modes of the top plate, the diagonal elements of the transfer function matrix have alternating poles and zeros, and the phase is moving smoothly. + Only the flexible modes of the top plates seems to be problematic for control. +#+end_important + +* High Authority Control with Integral Force Feedback <> ** Introduction :ignore: