diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..18fb59c
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "matlab/nass-simscape"]
+ path = matlab/nass-simscape
+ url = https://git.tdehaeze.xyz/tdehaeze/nass-simscape
diff --git a/figs/enc_struts_dvf_comp_offdiag_simscape.pdf b/figs/enc_struts_dvf_comp_offdiag_simscape.pdf
new file mode 100644
index 0000000..b9103b3
Binary files /dev/null and b/figs/enc_struts_dvf_comp_offdiag_simscape.pdf differ
diff --git a/figs/enc_struts_dvf_comp_offdiag_simscape.png b/figs/enc_struts_dvf_comp_offdiag_simscape.png
new file mode 100644
index 0000000..9bddc7d
Binary files /dev/null and b/figs/enc_struts_dvf_comp_offdiag_simscape.png differ
diff --git a/figs/enc_struts_dvf_comp_simscape.pdf b/figs/enc_struts_dvf_comp_simscape.pdf
new file mode 100644
index 0000000..e4347e1
Binary files /dev/null and b/figs/enc_struts_dvf_comp_simscape.pdf differ
diff --git a/figs/enc_struts_dvf_comp_simscape.png b/figs/enc_struts_dvf_comp_simscape.png
new file mode 100644
index 0000000..68f4030
Binary files /dev/null and b/figs/enc_struts_dvf_comp_simscape.png differ
diff --git a/figs/enc_struts_iff_comp_offdiag_simscape.pdf b/figs/enc_struts_iff_comp_offdiag_simscape.pdf
new file mode 100644
index 0000000..d85653f
Binary files /dev/null and b/figs/enc_struts_iff_comp_offdiag_simscape.pdf differ
diff --git a/figs/enc_struts_iff_comp_offdiag_simscape.png b/figs/enc_struts_iff_comp_offdiag_simscape.png
new file mode 100644
index 0000000..09f08ca
Binary files /dev/null and b/figs/enc_struts_iff_comp_offdiag_simscape.png differ
diff --git a/figs/enc_struts_iff_comp_simscape.pdf b/figs/enc_struts_iff_comp_simscape.pdf
new file mode 100644
index 0000000..07aa0d3
Binary files /dev/null and b/figs/enc_struts_iff_comp_simscape.pdf differ
diff --git a/figs/enc_struts_iff_comp_simscape.png b/figs/enc_struts_iff_comp_simscape.png
new file mode 100644
index 0000000..f3de62c
Binary files /dev/null and b/figs/enc_struts_iff_comp_simscape.png differ
diff --git a/figs/nano_hexapod_signals.pdf b/figs/nano_hexapod_signals.pdf
new file mode 100644
index 0000000..79da50f
Binary files /dev/null and b/figs/nano_hexapod_signals.pdf differ
diff --git a/figs/nano_hexapod_signals.png b/figs/nano_hexapod_signals.png
new file mode 100644
index 0000000..2625655
Binary files /dev/null and b/figs/nano_hexapod_signals.png differ
diff --git a/figs/nano_hexapod_signals.svg b/figs/nano_hexapod_signals.svg
new file mode 100644
index 0000000..c71e6f1
Binary files /dev/null and b/figs/nano_hexapod_signals.svg differ
diff --git a/matlab/nano_hexapod_simscape.slx b/matlab/nano_hexapod_simscape.slx
new file mode 100644
index 0000000..e05103a
Binary files /dev/null and b/matlab/nano_hexapod_simscape.slx differ
diff --git a/matlab/nass-simscape b/matlab/nass-simscape
new file mode 160000
index 0000000..ef7d7a5
--- /dev/null
+++ b/matlab/nass-simscape
@@ -0,0 +1 @@
+Subproject commit ef7d7a54d507b329d9bf23f1a3495ed7d5618a2d
diff --git a/test-bench-nano-hexapod.org b/test-bench-nano-hexapod.org
index e609e3a..b09457a 100644
--- a/test-bench-nano-hexapod.org
+++ b/test-bench-nano-hexapod.org
@@ -46,7 +46,11 @@
#+end_export
+\clearpage
+
* Introduction :ignore:
+In this document, the dynamics of the nano-hexapod shown in Figure [[fig:picture_bench_granite_nano_hexapod]] is identified.
+
#+begin_note
Here are the documentation of the equipment used for this test bench:
- Voltage Amplifier: PiezoDrive [[file:doc/PD200-V7-R1.pdf][PD200]]
@@ -66,6 +70,73 @@ Here are the documentation of the equipment used for this test bench:
#+attr_latex: :width \linewidth
[[file:figs/IMG_20210608_154722.jpg]]
+#+begin_src latex :file nano_hexapod_signals.pdf
+\definecolor{instrumentation}{rgb}{0, 0.447, 0.741}
+\definecolor{mechanics}{rgb}{0.8500, 0.325, 0.098}
+
+\begin{tikzpicture}
+ % Blocs
+ \node[block={4.0cm}{3.0cm}, fill=mechanics!20!white] (nano_hexapod) {Mechanics};
+ \coordinate[] (inputF) at (nano_hexapod.west);
+ \coordinate[] (outputL) at ($(nano_hexapod.south east)!0.8!(nano_hexapod.north east)$);
+ \coordinate[] (outputF) at ($(nano_hexapod.south east)!0.2!(nano_hexapod.north east)$);
+
+ \node[block, left= 0.8 of inputF, fill=instrumentation!20!white, align=center] (F_stack) {\tiny Actuator \\ \tiny stacks};
+ \node[block, left= 0.8 of F_stack, fill=instrumentation!20!white] (PD200) {PD200};
+ \node[DAC, left= 0.8 of PD200, fill=instrumentation!20!white] (F_DAC) {DAC};
+ \node[block, right=0.8 of outputF, fill=instrumentation!20!white, align=center] (Fm_stack){\tiny Sensor \\ \tiny stack};
+ \node[ADC, right=0.8 of Fm_stack,fill=instrumentation!20!white] (Fm_ADC) {ADC};
+ \node[block, right=0.8 of outputL, fill=instrumentation!20!white] (encoder) {\tiny Encoder};
+
+ % Connections and labels
+ \draw[->] ($(F_DAC.west)+(-0.8,0)$) node[above right]{$\bm{u}$} node[below right]{$[V]$} -- node[sloped]{$/$} (F_DAC.west);
+ \draw[->] (F_DAC.east) -- node[midway, above]{$\tilde{\bm{u}}$}node[midway, below]{$[V]$} (PD200.west);
+ \draw[->] (PD200.east) -- node[midway, above]{$\bm{u}_a$}node[midway, below]{$[V]$} (F_stack.west);
+ \draw[->] (F_stack.east) -- (inputF) node[above left]{$\bm{\tau}$}node[below left]{$[N]$};
+
+ \draw[->] (outputF) -- (Fm_stack.west) node[above left]{$\bm{\epsilon}$} node[below left]{$[m]$};
+ \draw[->] (Fm_stack.east) -- node[midway, above]{$\tilde{\bm{\tau}}_m$}node[midway, below]{$[V]$} (Fm_ADC.west);
+ \draw[->] (Fm_ADC.east) -- node[sloped]{$/$} ++(0.8, 0)coordinate(end) node[above left]{$\bm{\tau}_m$}node[below left]{$[V]$};
+
+ \draw[->] (outputL) -- (encoder.west) node[above left]{$d\bm{\mathcal{L}}$} node[below left]{$[m]$};
+ \draw[->] (encoder.east) -- node[sloped]{$/$} (encoder-|end) node[above left]{$d\bm{\mathcal{L}}_m$}node[below left]{$[m]$};
+
+ % Nano-Hexapod
+ \begin{scope}[on background layer]
+ \node[fit={(F_stack.west|-nano_hexapod.south) (Fm_stack.east|-nano_hexapod.north)}, fill=black!20!white, draw, inner sep=2pt] (system) {};
+ \node[above] at (system.north) {Nano-Hexapod};
+ \end{scope}
+\end{tikzpicture}
+#+end_src
+
+#+name: fig:nano_hexapod_signals
+#+caption: Block diagram of the system with named signals
+#+attr_latex: :scale 1
+#+RESULTS:
+[[file:figs/nano_hexapod_signals.png]]
+
+#+name: tab:list_signals
+#+caption: List of signals
+#+attr_latex: :environment tabularx :width \linewidth :align Xllll
+#+attr_latex: :center t :booktabs t :float t
+| | *Unit* | *Matlab* | *Vector* | *Elements* |
+|------------------------------------+-----------+-----------+-----------------------+----------------------|
+| Control Input (wanted DAC voltage) | =[V]= | =u= | $\bm{u}$ | $u_i$ |
+| DAC Output Voltage | =[V]= | =u= | $\tilde{\bm{u}}$ | $\tilde{u}_i$ |
+| PD200 Output Voltage | =[V]= | =ua= | $\bm{u}_a$ | $u_{a,i}$ |
+| Actuator applied force | =[N]= | =tau= | $\bm{\tau}$ | $\tau_i$ |
+|------------------------------------+-----------+-----------+-----------------------+----------------------|
+| Strut motion | =[m]= | =dL= | $d\bm{\mathcal{L}}$ | $d\mathcal{L}_i$ |
+| Encoder measured displacement | =[m]= | =dLm= | $d\bm{\mathcal{L}}_m$ | $d\mathcal{L}_{m,i}$ |
+|------------------------------------+-----------+-----------+-----------------------+----------------------|
+| Force Sensor strain | =[m]= | =epsilon= | $\bm{\epsilon}$ | $\epsilon_i$ |
+| Force Sensor Generated Voltage | =[V]= | =taum= | $\tilde{\bm{\tau}}_m$ | $\tilde{\tau}_{m,i}$ |
+| Measured Generated Voltage | =[V]= | =taum= | $\bm{\tau}_m$ | $\tau_{m,i}$ |
+|------------------------------------+-----------+-----------+-----------------------+----------------------|
+| Motion of the top platform | =[m,rad]= | =dX= | $d\bm{\mathcal{X}}$ | $d\mathcal{X}_i$ |
+| Metrology measured displacement | =[m,rad]= | =dXm= | $d\bm{\mathcal{X}}_m$ | $d\mathcal{X}_{m,i}$ |
+
+*
* Encoders fixed to the Struts
** Introduction
In this section, the encoders are fixed to the struts.
@@ -90,7 +161,8 @@ addpath('./mat/');
addpath('./src/');
#+end_src
-** Load Data
+** Identification of the dynamics
+*** Load Data
#+begin_src matlab
meas_data_lf = {};
@@ -100,7 +172,7 @@ for i = 1:6
end
#+end_src
-** Spectral Analysis - Setup
+*** Spectral Analysis - Setup
#+begin_src matlab
% Sampling Time [s]
Ts = (meas_data_lf{1}.t(end) - (meas_data_lf{1}.t(1)))/(length(meas_data_lf{1}.t)-1);
@@ -122,7 +194,7 @@ i_lf = f < 250; % Points for low frequency excitation
i_hf = f > 250; % Points for high frequency excitation
#+end_src
-** DVF Plant
+*** DVF Plant
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
@@ -244,7 +316,7 @@ exportFig('figs/enc_struts_dvf_frf.pdf', 'width', 'wide', 'height', 'tall');
[[file:figs/enc_struts_dvf_frf.png]]
-** IFF Plant
+*** IFF Plant
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
@@ -365,11 +437,11 @@ exportFig('figs/enc_struts_iff_frf.pdf', 'width', 'wide', 'height', 'tall');
#+RESULTS:
[[file:figs/enc_struts_iff_frf.png]]
-** Jacobian
+** Jacobian :noexport:
*** Introduction :ignore:
The Jacobian is used to transform the excitation force in the cartesian frame as well as the displacements.
-Consider the plant shown in Figure [[fig:nano_hexapod_decentralized_schematic]] with:
+Consider the plant shown in Figure [[fig:schematic_jacobian_in_out]] with:
- $\tau$ the 6 input voltages (going to the PD200 amplifier and then to the APA)
- $d\mathcal{L}$ the relative motion sensor outputs (encoders)
- $\bm{\tau}_m$ the generated voltage of the force sensor stacks
@@ -540,3 +612,337 @@ exportFig('figs/enc_struts_iff_cart_frf.pdf', 'width', 'wide', 'height', 'tall')
#+caption: Measured FRF for the IFF plant in the cartesian frame
#+RESULTS:
[[file:figs/enc_struts_iff_cart_frf.png]]
+
+** Comparison with the Simscape Model
+*** Introduction :ignore:
+In this section, the measured dynamics is compared with the dynamics estimated from the Simscape model.
+
+*** Initialize :noexport:
+#+begin_src matlab :tangle no
+addpath('matlab/')
+addpath('matlab/nass-simscape/matlab/nano_hexapod/')
+addpath('matlab/nass-simscape/STEPS/nano_hexapod/')
+addpath('matlab/nass-simscape/STEPS/png/')
+addpath('matlab/nass-simscape/src/')
+addpath('matlab/nass-simscape/mat/')
+#+end_src
+
+#+begin_src matlab :eval no
+addpath('nass-simscape/matlab/nano_hexapod/')
+addpath('nass-simscape/STEPS/nano_hexapod/')
+addpath('nass-simscape/STEPS/png/')
+addpath('nass-simscape/src/')
+addpath('nass-simscape/mat/')
+#+end_src
+
+#+begin_src matlab
+mdl = 'nano_hexapod_simscape';
+
+options = linearizeOptions;
+options.SampleTime = 0;
+
+open(mdl)
+#+end_src
+
+*** Dynamics from Actuator to Force Sensors
+#+begin_src matlab
+n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '3dof', ...
+ 'flex_top_type', '2dof', ...
+ 'motion_sensor_type', 'struts', ...
+ 'actuator_type', '2dof');
+#+end_src
+
+#+begin_src matlab
+%% Input/Output definition
+clear io; io_i = 1;
+io(io_i) = linio([mdl, '/F'], 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 = 20*exp(-s*Ts)*linearize(mdl, io, 0.0, options);
+#+end_src
+
+#+begin_src matlab :exports none
+freqs = 2*logspace(1, 3, 1000);
+
+figure;
+tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
+
+ax1 = nexttile([2,1]);
+hold on;
+plot(freqs, abs(squeeze(freqresp(Giff(1,1), freqs, 'Hz'))), '-', ...
+ 'DisplayName', '$\tau_{m,i}/u_i$ - Model')
+plot(f(i_lf), abs(G_iff_lf(i_lf,1, 1)), ...
+ 'DisplayName', '$\tau_{m,i}/u_i$ - FRF')
+for i = 2:6
+ set(gca,'ColorOrderIndex',1);
+ plot(freqs, abs(squeeze(freqresp(Giff(i,i), freqs, 'Hz'))), '-', ...
+ 'HandleVisibility', 'off');
+end
+for i = 2:6
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_lf), abs(G_iff_lf(i_lf,i, i)), ...
+ 'HandleVisibility', 'off');
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_hf), abs(G_iff_hf(i_hf,i, i)), ...
+ 'HandleVisibility', 'off');
+end
+hold off;
+set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
+ylabel('Amplitude [V/V]'); set(gca, 'XTickLabel',[]);
+legend('location', 'southeast');
+
+ax2 = nexttile;
+hold on;
+for i = 1:6
+ set(gca,'ColorOrderIndex',1);
+ plot(freqs, 180/pi*angle(squeeze(freqresp(Giff(i,i), freqs, 'Hz'))), '-');
+end
+for i = 1:6
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_lf), 180/pi*angle(G_iff_lf(i_lf,i, i)));
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_hf), 180/pi*angle(G_iff_hf(i_hf,i, 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]);
+
+linkaxes([ax1,ax2],'x');
+xlim([freqs(1), freqs(end)]);
+#+end_src
+
+#+begin_src matlab :tangle no :exports results :results file replace
+exportFig('figs/enc_struts_iff_comp_simscape.pdf', 'width', 'wide', 'height', 'tall');
+#+end_src
+
+#+name: fig:enc_struts_iff_comp_simscape
+#+caption: Diagonal elements of the IFF Plant
+#+RESULTS:
+[[file:figs/enc_struts_iff_comp_simscape.png]]
+
+#+begin_src matlab :exports none
+freqs = 2*logspace(1, 3, 1000);
+
+figure;
+hold on;
+% Off diagonal terms
+set(gca,'ColorOrderIndex',1);
+plot(freqs, abs(squeeze(freqresp(Giff(1, 2), freqs, 'Hz'))), ...
+ 'DisplayName', '$\tau_{m,i}/u_j$ - Model')
+for i = 1:5
+ for j = i+1:6
+ set(gca,'ColorOrderIndex',1);
+ plot(freqs, abs(squeeze(freqresp(Giff(i, j), freqs, 'Hz'))), ...
+ 'HandleVisibility', 'off');
+ end
+end
+set(gca,'ColorOrderIndex',2);
+plot(f(i_lf), abs(G_iff_lf(i_lf, 1, 2)), ...
+ 'DisplayName', '$\tau_{m,i}/u_j$ - FRF')
+for i = 1:5
+ for j = i+1:6
+ set(gca,'ColorOrderIndex',2);
+ plot(f(i_lf), abs(G_iff_lf(i_lf, i, j)), ...
+ 'HandleVisibility', 'off');
+ set(gca,'ColorOrderIndex',2);
+ plot(f(i_hf), abs(G_iff_hf(i_hf, i, j)), ...
+ 'HandleVisibility', 'off');
+ end
+end
+hold off;
+set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
+xlabel('Frequency [Hz]'); ylabel('Amplitude [V/V]');
+xlim([freqs(1), freqs(end)]); ylim([1e-3, 1e2]);
+legend('location', 'northeast');
+#+end_src
+
+#+begin_src matlab :tangle no :exports results :results file replace
+exportFig('figs/enc_struts_iff_comp_offdiag_simscape.pdf', 'width', 'wide', 'height', 'normal');
+#+end_src
+
+#+name: fig:enc_struts_iff_comp_offdiag_simscape
+#+caption: Off diagonal elements of the IFF Plant
+#+RESULTS:
+[[file:figs/enc_struts_iff_comp_offdiag_simscape.png]]
+
+*** Dynamics from Actuator to Encoder
+#+begin_src matlab
+n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '3dof', ...
+ 'flex_top_type', '2dof', ...
+ 'motion_sensor_type', 'struts', ...
+ 'actuator_type', '2dof');
+#+end_src
+
+#+begin_src matlab
+%% Input/Output definition
+clear io; io_i = 1;
+io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs
+io(io_i) = linio([mdl, '/D'], 1, 'openoutput'); io_i = io_i + 1; % Encoders
+
+Gdvf = 20*exp(-s*Ts)*linearize(mdl, io, 0.0, options);
+#+end_src
+
+#+begin_src matlab :exports none
+freqs = 2*logspace(1, 3, 1000);
+
+figure;
+tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
+
+ax1 = nexttile([2,1]);
+hold on;
+plot(freqs, abs(squeeze(freqresp(Gdvf(1,1), freqs, 'Hz'))), '-', ...
+ 'DisplayName', '$d\mathcal{L}_{m,i}/u_i$ - Model')
+plot(f(i_lf), abs(G_dvf_lf(i_lf,1, 1)), ...
+ 'DisplayName', '$d\mathcal{L}_{m,i}/u_i$ - FRF')
+for i = 2:6
+ set(gca,'ColorOrderIndex',1);
+ plot(freqs, abs(squeeze(freqresp(Gdvf(i,i), freqs, 'Hz'))), '-', ...
+ 'HandleVisibility', 'off');
+end
+for i = 2:6
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_lf), abs(G_dvf_lf(i_lf,i, i)), ...
+ 'HandleVisibility', 'off');
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_hf), abs(G_dvf_hf(i_hf,i, i)), ...
+ 'HandleVisibility', 'off');
+end
+hold off;
+set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
+ylabel('Amplitude [m/V]'); set(gca, 'XTickLabel',[]);
+legend('location', 'northeast');
+ylim([1e-8, 1e-3]);
+
+ax2 = nexttile;
+hold on;
+for i = 1:6
+ set(gca,'ColorOrderIndex',1);
+ plot(freqs, 180/pi*angle(squeeze(freqresp(Gdvf(i,i), freqs, 'Hz'))), '-');
+end
+for i = 1:6
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_lf), 180/pi*angle(G_dvf_lf(i_lf,i, i)));
+ set(gca,'ColorOrderIndex',2)
+ plot(f(i_hf), 180/pi*angle(G_dvf_hf(i_hf,i, 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]);
+
+linkaxes([ax1,ax2],'x');
+xlim([freqs(1), freqs(end)]);
+#+end_src
+
+#+begin_src matlab :tangle no :exports results :results file replace
+exportFig('figs/enc_struts_dvf_comp_simscape.pdf', 'width', 'wide', 'height', 'tall');
+#+end_src
+
+#+name: fig:enc_struts_dvf_comp_simscape
+#+caption: Diagonal elements of the DVF Plant
+#+RESULTS:
+[[file:figs/enc_struts_dvf_comp_simscape.png]]
+
+#+begin_src matlab :exports none
+freqs = 2*logspace(1, 3, 1000);
+
+figure;
+hold on;
+% Off diagonal terms
+set(gca,'ColorOrderIndex',1);
+plot(freqs, abs(squeeze(freqresp(Gdvf(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',1);
+ plot(freqs, abs(squeeze(freqresp(Gdvf(i, j), freqs, 'Hz'))), ...
+ 'HandleVisibility', 'off');
+ end
+end
+set(gca,'ColorOrderIndex',2);
+plot(f(i_lf), abs(G_dvf_lf(i_lf, 1, 2)), ...
+ 'DisplayName', '$d\mathcal{L}_{m,i}/u_j$ - FRF')
+for i = 1:5
+ for j = i+1:6
+ set(gca,'ColorOrderIndex',2);
+ plot(f(i_lf), abs(G_dvf_lf(i_lf, i, j)), ...
+ 'HandleVisibility', 'off');
+ set(gca,'ColorOrderIndex',2);
+ plot(f(i_hf), abs(G_dvf_hf(i_hf, i, j)), ...
+ 'HandleVisibility', 'off');
+ end
+end
+hold off;
+set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
+xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]');
+xlim([freqs(1), freqs(end)]); ylim([1e-8, 1e-3]);
+legend('location', 'northeast');
+#+end_src
+
+#+begin_src matlab :tangle no :exports results :results file replace
+exportFig('figs/enc_struts_dvf_comp_offdiag_simscape.pdf', 'width', 'wide', 'height', 'normal');
+#+end_src
+
+#+name: fig:enc_struts_dvf_comp_offdiag_simscape
+#+caption: Off diagonal elements of the DVF Plant
+#+RESULTS:
+[[file:figs/enc_struts_dvf_comp_offdiag_simscape.png]]
+
+** TODO Integral Force Feedback
+*** Plant
+#+begin_src matlab :exports none
+figure;
+tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
+
+ax1 = nexttile([2,1]);
+hold on;
+for i = 1:5
+ for j = i+1:6
+ plot(f(i_lf), abs(G_iff_lf(i_lf, i, j)), 'color', [0, 0, 0, 0.2], ...
+ 'HandleVisibility', 'off');
+ plot(f(i_hf), abs(G_iff_hf(i_hf, i, j)), 'color', [0, 0, 0, 0.2], ...
+ 'HandleVisibility', 'off');
+ end
+end
+for i =1:6
+ set(gca,'ColorOrderIndex',i)
+ plot(f(i_lf), abs(G_iff_lf(i_lf,i, i)), ...
+ 'DisplayName', sprintf('$G_{iff}(%i,%i)$', i, i));
+ set(gca,'ColorOrderIndex',i)
+ plot(f(i_hf), abs(G_iff_hf(i_hf,i, i)), ...
+ 'HandleVisibility', 'off');
+end
+plot(f(i_lf), abs(G_iff_lf(i_lf, 1, 2)), 'color', [0, 0, 0, 0.2], ...
+ 'DisplayName', '$G_{iff}(i,j)$');
+hold off;
+set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
+ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
+legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 3);
+ylim([1e-3, 1e2]);
+
+ax2 = nexttile;
+hold on;
+for i =1:6
+ set(gca,'ColorOrderIndex',i)
+ plot(f(i_lf), 180/pi*angle(G_iff_lf(i_lf,i, i)));
+ set(gca,'ColorOrderIndex',i)
+ plot(f(i_hf), 180/pi*angle(G_iff_hf(i_hf,i, i)));
+end
+hold off;
+set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
+xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
+hold off;
+yticks(-360:90:360);
+
+linkaxes([ax1,ax2],'x');
+xlim([20, 2e3]);
+#+end_src
+
+*** Root Locus
+
+*** Gains
+
+*** Experimental Results
diff --git a/test-bench-nano-hexapod.pdf b/test-bench-nano-hexapod.pdf
index 8b00a26..e60de65 100644
Binary files a/test-bench-nano-hexapod.pdf and b/test-bench-nano-hexapod.pdf differ