6063 lines
196 KiB
Org Mode
6063 lines
196 KiB
Org Mode
#+TITLE: Amplifier Piezoelectric Actuator APA300ML - Test Bench
|
|
:DRAWER:
|
|
#+LANGUAGE: en
|
|
#+EMAIL: dehaeze.thomas@gmail.com
|
|
#+AUTHOR: Dehaeze Thomas
|
|
|
|
#+HTML_LINK_HOME: ../index.html
|
|
#+HTML_LINK_UP: ../index.html
|
|
|
|
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://research.tdehaeze.xyz/css/style.css"/>
|
|
#+HTML_HEAD: <script type="text/javascript" src="https://research.tdehaeze.xyz/js/script.js"></script>
|
|
|
|
#+BIND: org-latex-image-default-option "scale=1"
|
|
#+BIND: org-latex-image-default-width ""
|
|
#+BIND: org-latex-bib-compiler "biber"
|
|
|
|
#+LaTeX_CLASS: scrreprt
|
|
#+LaTeX_CLASS_OPTIONS: [a4paper, 10pt, DIV=12, parskip=full]
|
|
#+LaTeX_HEADER_EXTRA: \input{preamble.tex}
|
|
#+LATEX_HEADER_EXTRA: \addbibresource{ref.bib}
|
|
|
|
#+PROPERTY: header-args:matlab :session *MATLAB*
|
|
#+PROPERTY: header-args:matlab+ :comments org
|
|
#+PROPERTY: header-args:matlab+ :exports both
|
|
#+PROPERTY: header-args:matlab+ :results none
|
|
#+PROPERTY: header-args:matlab+ :eval no-export
|
|
#+PROPERTY: header-args:matlab+ :noweb yes
|
|
#+PROPERTY: header-args:matlab+ :tangle no
|
|
#+PROPERTY: header-args:matlab+ :mkdirp yes
|
|
#+PROPERTY: header-args:matlab+ :output-dir figs
|
|
|
|
#+PROPERTY: header-args:latex :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/tikz/org/}{config.tex}")
|
|
#+PROPERTY: header-args:latex+ :imagemagick t :fit yes
|
|
#+PROPERTY: header-args:latex+ :iminoptions -scale 100% -density 150
|
|
#+PROPERTY: header-args:latex+ :imoutoptions -quality 100
|
|
#+PROPERTY: header-args:latex+ :results file raw replace
|
|
#+PROPERTY: header-args:latex+ :buffer no
|
|
#+PROPERTY: header-args:latex+ :tangle no
|
|
#+PROPERTY: header-args:latex+ :eval no-export
|
|
#+PROPERTY: header-args:latex+ :exports results
|
|
#+PROPERTY: header-args:latex+ :mkdirp yes
|
|
#+PROPERTY: header-args:latex+ :output-dir figs
|
|
#+PROPERTY: header-args:latex+ :post pdf2svg(file=*this*, ext="png")
|
|
:END:
|
|
|
|
#+begin_export html
|
|
<hr>
|
|
<p>This report is also available as a <a href="./test-bench-apa300ml.pdf">pdf</a>.</p>
|
|
<hr>
|
|
#+end_export
|
|
|
|
#+latex: \clearpage
|
|
|
|
* Introduction :ignore:
|
|
|
|
The goal of this test bench is to extract all the important parameters of the Amplified Piezoelectric Actuator APA300ML.
|
|
|
|
This include:
|
|
- Stroke
|
|
- Stiffness
|
|
- Hysteresis
|
|
- Gain from the applied voltage $V_a$ to the generated Force $F_a$
|
|
- Gain from the sensor stack strain $\delta L$ to the generated voltage $V_s$
|
|
- Dynamical behavior
|
|
|
|
#+name: fig:apa300ML
|
|
#+caption: Picture of the APA300ML
|
|
#+attr_latex: :width 0.8\linewidth
|
|
[[file:figs/apa300ML.png]]
|
|
|
|
* Model of an Amplified Piezoelectric Actuator and Sensor
|
|
|
|
Consider a schematic of the Amplified Piezoelectric Actuator in Figure [[fig:apa_model_schematic]].
|
|
|
|
#+name: fig:apa_model_schematic
|
|
#+caption: Amplified Piezoelectric Actuator Schematic
|
|
[[file:figs/apa_model_schematic.png]]
|
|
|
|
A voltage $V_a$ applied to the actuator stacks will induce an actuator force $F_a$:
|
|
\begin{equation}
|
|
F_a = g_a \cdot V_a
|
|
\end{equation}
|
|
|
|
A change of length $dl$ of the sensor stack will induce a voltage $V_s$:
|
|
\begin{equation}
|
|
V_s = g_s \cdot dl
|
|
\end{equation}
|
|
|
|
We wish here to experimental measure $g_a$ and $g_s$.
|
|
|
|
The block-diagram model of the piezoelectric actuator is then as shown in Figure [[fig:apa-model-simscape-schematic]].
|
|
|
|
#+begin_src latex :file apa-model-simscape-schematic.pdf
|
|
\begin{tikzpicture}
|
|
\node[block={2.0cm}{2.0cm}, align=center] (model) at (0,0){Simscape\\Model};
|
|
\node[block, left=1.0 of model] (ga){$g_a(s)$};
|
|
\node[block, right=1.0 of model] (gs){$g_s(s)$};
|
|
|
|
\draw[<-] (ga.west) -- node[midway, above]{$V_a$} node[midway, below]{$[V]$} ++(-1.0, 0);
|
|
\draw[->] (ga.east) --node[midway, above]{$F_a$} node[midway, below]{$[N]$} (model.west);
|
|
\draw[->] (model.east) --node[midway, above]{$dl$} node[midway, below]{$[m]$} (gs.west);
|
|
\draw[->] (gs.east) -- node[midway, above]{$V_s$} node[midway, below]{$[V]$} ++(1.0, 0);
|
|
\end{tikzpicture}
|
|
#+end_src
|
|
|
|
#+name: fig:apa-model-simscape-schematic
|
|
#+caption: Model of the APA with Simscape/Simulink
|
|
#+RESULTS:
|
|
[[file:figs/apa-model-simscape-schematic.png]]
|
|
|
|
* First Basic Measurements
|
|
<<sec:first_measurements>>
|
|
** Introduction :ignore:
|
|
|
|
- Section [[sec:geometrical_measurements]]:
|
|
- Section [[sec:electrical_measurements]]:
|
|
- Section [[sec:stroke_measurements]]:
|
|
- Section [[sec:spurious_resonances]]:
|
|
|
|
** Geometrical Measurements
|
|
<<sec:geometrical_measurements>>
|
|
*** Introduction :ignore:
|
|
|
|
The received APA are shown in Figure [[fig:received_apa]].
|
|
|
|
#+name: fig:received_apa
|
|
#+caption: Received APA
|
|
#+attr_latex: :width 0.6\linewidth
|
|
[[file:figs/IMG_20210224_143500.jpg]]
|
|
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('./matlab/mat/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
#+end_src
|
|
|
|
*** Measurement Setup
|
|
|
|
The flatness corresponding to the two interface planes are measured as shown in Figure [[fig:flatness_meas_setup]].
|
|
|
|
#+name: fig:flatness_meas_setup
|
|
#+caption: Measurement Setup
|
|
#+attr_latex: :width 0.6\linewidth
|
|
[[file:figs/IMG_20210224_143809.jpg]]
|
|
|
|
*** Measurement Results
|
|
|
|
The height (Z) measurements at the 8 locations (4 points by plane) are defined below.
|
|
#+begin_src matlab
|
|
apa1 = 1e-6*[0, -0.5 , 3.5 , 3.5 , 42 , 45.5, 52.5 , 46];
|
|
apa2 = 1e-6*[0, -2.5 , -3 , 0 , -1.5 , 1 , -2 , -4];
|
|
apa3 = 1e-6*[0, -1.5 , 15 , 17.5 , 6.5 , 6.5 , 21 , 23];
|
|
apa4 = 1e-6*[0, 6.5 , 14.5 , 9 , 16 , 22 , 29.5 , 21];
|
|
apa5 = 1e-6*[0, -12.5, 16.5 , 28.5 , -43 , -52 , -22.5, -13.5];
|
|
apa6 = 1e-6*[0, -8 , -2 , 5 , -57.5, -62 , -55.5, -52.5];
|
|
apa7 = 1e-6*[0, 19.5 , -8 , -29.5, 75 , 97.5, 70 , 48];
|
|
apa7b = 1e-6*[0, 9 , -18.5, -30 , 31 , 46.5, 16.5 , 7.5];
|
|
apa = {apa1, apa2, apa3, apa4, apa5, apa6, apa7b};
|
|
#+end_src
|
|
|
|
The X/Y Positions of the 8 measurement points are defined below.
|
|
#+begin_src matlab
|
|
W = 20e-3; % Width [m]
|
|
L = 61e-3; % Length [m]
|
|
d = 1e-3; % Distance from border [m]
|
|
l = 15.5e-3; % [m]
|
|
|
|
pos = [[-L/2 + d; W/2 - d], [-L/2 + l - d; W/2 - d], [-L/2 + l - d; -W/2 + d], [-L/2 + d; -W/2 + d], [L/2 - l + d; W/2 - d], [L/2 - d; W/2 - d], [L/2 - d; -W/2 + d], [L/2 - l + d; -W/2 + d]];
|
|
#+end_src
|
|
|
|
Finally, the flatness is estimated by fitting a plane through the 8 points using the =fminsearch= command.
|
|
#+begin_src matlab
|
|
apa_d = zeros(1, 7);
|
|
for i = 1:7
|
|
fun = @(x)max(abs(([pos; apa{i}]-[0;0;x(1)])'*([x(2:3);1]/norm([x(2:3);1]))));
|
|
x0 = [0;0;0];
|
|
[x, min_d] = fminsearch(fun,x0);
|
|
apa_d(i) = min_d;
|
|
end
|
|
#+end_src
|
|
|
|
The obtained flatness are shown in Table [[tab:flatness_meas]].
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
|
|
data2orgtable(1e6*apa_d', {'APA 1', 'APA 2', 'APA 3', 'APA 4', 'APA 5', 'APA 6', 'APA 7'}, {'*Flatness* $[\mu m]$'}, ' %.1f ');
|
|
#+end_src
|
|
|
|
#+name: tab:flatness_meas
|
|
#+caption: Estimated flatness
|
|
#+attr_latex: :environment tabularx :width 0.25\linewidth :align lc
|
|
#+attr_latex: :center t :booktabs t :float t
|
|
#+RESULTS:
|
|
| | *Flatness* $[\mu m]$ |
|
|
|-------+----------------------|
|
|
| APA 1 | 8.9 |
|
|
| APA 2 | 3.1 |
|
|
| APA 3 | 9.1 |
|
|
| APA 4 | 3.0 |
|
|
| APA 5 | 1.9 |
|
|
| APA 6 | 7.1 |
|
|
| APA 7 | 18.7 |
|
|
|
|
** Electrical Measurements
|
|
<<sec:electrical_measurements>>
|
|
|
|
#+begin_note
|
|
The capacitance of the stacks is measure with the [[https://www.gwinstek.com/en-global/products/detail/LCR-800][LCR-800 Meter]] ([[file:doc/DS_LCR-800_Series_V2_E.pdf][doc]])
|
|
#+end_note
|
|
|
|
#+name: fig:LCR_meter
|
|
#+caption: LCR Meter used for the measurements
|
|
#+attr_latex: :width 0.9\linewidth
|
|
[[file:figs/IMG_20210312_120337.jpg]]
|
|
|
|
The excitation frequency is set to be 1kHz.
|
|
|
|
#+name: tab:apa300ml_capacitance
|
|
#+caption: Capacitance measured with the LCR meter. The excitation signal is a sinus at 1kHz
|
|
#+attr_latex: :environment tabularx :width 0.5\linewidth :align lcc
|
|
#+attr_latex: :center t :booktabs t :float t
|
|
| | *Sensor Stack* | *Actuator Stacks* |
|
|
|-------+----------------+-------------------|
|
|
| APA 1 | 5.10 | 10.03 |
|
|
| APA 2 | 4.99 | 9.85 |
|
|
| APA 3 | 1.72 | 5.18 |
|
|
| APA 4 | 4.94 | 9.82 |
|
|
| APA 5 | 4.90 | 9.66 |
|
|
| APA 6 | 4.99 | 9.91 |
|
|
| APA 7 | 4.85 | 9.85 |
|
|
|
|
#+begin_warning
|
|
There is clearly a problem with APA300ML number 3
|
|
#+end_warning
|
|
|
|
The APA number 3 has ben sent back to Cedrat, and a new APA300ML has been shipped back.
|
|
|
|
** Stroke measurement
|
|
<<sec:stroke_measurements>>
|
|
*** Introduction :ignore:
|
|
|
|
We here wish to estimate the stroke of the APA.
|
|
|
|
To do so, one side of the APA is fixed, and a displacement probe is located on the other side as shown in Figure [[fig:stroke_test_bench]].
|
|
|
|
Then, a voltage is applied on either one or two stacks using a DAC and a voltage amplifier.
|
|
|
|
#+begin_note
|
|
Here are the documentation of the equipment used for this test bench:
|
|
- *Voltage Amplifier*: [[file:doc/PD200-V7-R1.pdf][PD200]] with a gain of 20
|
|
- *16bits DAC*: [[file:doc/IO131-OEM-Datasheet.pdf][IO313 Speedgoat card]]
|
|
- *Displacement Probe*: [[file:doc/Millimar--3723046--BA--C1208-C1216-C1240--FR--2016-11-08.pdf][Millimar C1216 electronics]] and [[file:doc/tmp3m0cvmue_7888038c-cdc8-48d8-a837-35de02760685.pdf][Millimar 1318 probe]]
|
|
#+end_note
|
|
|
|
#+name: fig:stroke_test_bench
|
|
#+caption: Bench to measured the APA stroke
|
|
#+attr_latex: :width 0.9\linewidth
|
|
[[file:figs/CE0EF55E-07B7-461B-8CDB-98590F68D15B.jpeg]]
|
|
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('./matlab/mat/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
#+end_src
|
|
|
|
*** Voltage applied on one stack
|
|
|
|
Let's first look at the relation between the voltage applied to *one* stack to the displacement of the APA as measured by the displacement probe.
|
|
|
|
#+begin_src matlab :exports none
|
|
apa300ml_1s = {};
|
|
for i = 1:7
|
|
apa300ml_1s(i) = {load(['mat/stroke_apa_1stacks_' num2str(i) '.mat'], 't', 'V', 'd')};
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
for i = 1:7
|
|
t = apa300ml_1s{i}.t;
|
|
apa300ml_1s{i}.d = apa300ml_1s{i}.d - mean(apa300ml_1s{i}.d(t > 1.9 & t < 2.0));
|
|
apa300ml_1s{i}.d = apa300ml_1s{i}.d(t > 2.0 & t < 10.0);
|
|
apa300ml_1s{i}.V = apa300ml_1s{i}.V(t > 2.0 & t < 10.0);
|
|
apa300ml_1s{i}.t = apa300ml_1s{i}.t(t > 2.0 & t < 10.0);
|
|
end
|
|
#+end_src
|
|
|
|
The applied voltage is shown in Figure [[fig:apa_stroke_voltage_time]].
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
plot(apa300ml_1s{1}.t, 20*apa300ml_1s{1}.V)
|
|
xlabel('Time [s]'); ylabel('Voltage [V]');
|
|
ylim([-20,160]); yticks([-20 0 20 40 60 80 100 120 140 160]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_stroke_voltage_time.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_stroke_voltage_time
|
|
#+caption: Applied voltage as a function of time
|
|
#+RESULTS:
|
|
[[file:figs/apa_stroke_voltage_time.png]]
|
|
|
|
The obtained displacement is shown in Figure [[fig:apa_stroke_time_1s]].
|
|
The displacement is set to zero at initial time when the voltage applied is -20V.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
for i = 1:7
|
|
plot(apa300ml_1s{i}.t, 1e6*apa300ml_1s{i}.d, 'DisplayName', sprintf('APA %i', i))
|
|
end
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('Displacement [$\mu m$]')
|
|
legend('location', 'southeast', 'FontSize', 8)
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_stroke_time_1s.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_stroke_time_1s
|
|
#+caption: Displacement as a function of time for all the APA300ML
|
|
#+RESULTS:
|
|
[[file:figs/apa_stroke_time_1s.png]]
|
|
|
|
Finally, the displacement is shown as a function of the applied voltage in Figure [[fig:apa_d_vs_V_1s]].
|
|
We can clearly see that there is a problem with the APA 3.
|
|
Also, there is a large hysteresis.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
for i = 1:7
|
|
plot(20*apa300ml_1s{i}.V, 1e6*apa300ml_1s{i}.d, 'DisplayName', sprintf('APA %i', i))
|
|
end
|
|
hold off;
|
|
xlabel('Voltage [V]'); ylabel('Displacement [$\mu m$]')
|
|
legend('location', 'southwest', 'FontSize', 8)
|
|
xlim([-20, 160]); ylim([-140, 0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_d_vs_V_1s.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_d_vs_V_1s
|
|
#+caption: Displacement as a function of the applied voltage
|
|
#+RESULTS:
|
|
[[file:figs/apa_d_vs_V_1s.png]]
|
|
|
|
#+begin_important
|
|
We can clearly see from Figure [[fig:apa_d_vs_V_1s]] that there is a problem with the APA number 3.
|
|
#+end_important
|
|
|
|
*** Voltage applied on two stacks
|
|
|
|
Now look at the relation between the voltage applied to the *two* other stacks to the displacement of the APA as measured by the displacement probe.
|
|
|
|
#+begin_src matlab :exports none
|
|
apa300ml_2s = {};
|
|
for i = 1:7
|
|
apa300ml_2s(i) = {load(['mat/stroke_apa_2stacks_' num2str(i) '.mat'], 't', 'V', 'd')};
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
for i = 1:7
|
|
t = apa300ml_2s{i}.t;
|
|
apa300ml_2s{i}.d = apa300ml_2s{i}.d - mean(apa300ml_2s{i}.d(t > 1.9 & t < 2.0));
|
|
apa300ml_2s{i}.d = apa300ml_2s{i}.d(t > 2.0 & t < 10.0);
|
|
apa300ml_2s{i}.V = apa300ml_2s{i}.V(t > 2.0 & t < 10.0);
|
|
apa300ml_2s{i}.t = apa300ml_2s{i}.t(t > 2.0 & t < 10.0);
|
|
end
|
|
#+end_src
|
|
|
|
The obtained displacement is shown in Figure [[fig:apa_stroke_time_2s]].
|
|
The displacement is set to zero at initial time when the voltage applied is -20V.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
for i = 1:7
|
|
plot(apa300ml_2s{i}.t, 1e6*apa300ml_2s{i}.d, 'DisplayName', sprintf('APA %i', i))
|
|
end
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('Displacement [$\mu m$]')
|
|
legend('location', 'southeast', 'FontSize', 8)
|
|
ylim([-250, 0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_stroke_time_2s.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_stroke_time_2s
|
|
#+caption: Displacement as a function of time for all the APA300ML
|
|
#+RESULTS:
|
|
[[file:figs/apa_stroke_time_2s.png]]
|
|
|
|
Finally, the displacement is shown as a function of the applied voltage in Figure [[fig:apa_d_vs_V_2s]].
|
|
We can clearly see that there is a problem with the APA 3.
|
|
Also, there is a large hysteresis.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
for i = 1:7
|
|
plot(20*apa300ml_2s{i}.V, 1e6*apa300ml_2s{i}.d, 'DisplayName', sprintf('APA %i', i))
|
|
end
|
|
hold off;
|
|
xlabel('Voltage [V]'); ylabel('Displacement [$\mu m$]')
|
|
legend('location', 'southwest', 'FontSize', 8)
|
|
xlim([-20, 160]); ylim([-250, 0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_d_vs_V_2s.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_d_vs_V_2s
|
|
#+caption: Displacement as a function of the applied voltage
|
|
#+RESULTS:
|
|
[[file:figs/apa_d_vs_V_2s.png]]
|
|
|
|
*** Voltage applied on all three stacks
|
|
|
|
Finally, we can combine the two measurements to estimate the relation between the displacement and the voltage applied to the *three* stacks (Figure [[fig:apa_d_vs_V_3s]]).
|
|
|
|
#+begin_src matlab :exports none
|
|
apa300ml_3s = {};
|
|
for i = 1:7
|
|
apa300ml_3s(i) = apa300ml_1s(i);
|
|
apa300ml_3s{i}.d = apa300ml_1s{i}.d + apa300ml_2s{i}.d;
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
for i = 1:7
|
|
plot(20*apa300ml_3s{i}.V, 1e6*apa300ml_3s{i}.d, 'DisplayName', sprintf('APA %i', i))
|
|
end
|
|
hold off;
|
|
xlabel('Voltage [V]'); ylabel('Displacement [$\mu m$]')
|
|
legend('location', 'southwest', 'FontSize', 8)
|
|
xlim([-20, 160]); ylim([-400, 0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_d_vs_V_3s.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_d_vs_V_3s
|
|
#+caption: Displacement as a function of the applied voltage
|
|
#+RESULTS:
|
|
[[file:figs/apa_d_vs_V_3s.png]]
|
|
|
|
The obtained maximum stroke for all the APA are summarized in Table [[tab:apa_measured_stroke]].
|
|
|
|
#+begin_src matlab :exports none
|
|
apa300ml_stroke = zeros(1, 7);
|
|
for i = 1:7
|
|
apa300ml_stroke(i) = max(apa300ml_3s{i}.d) - min(apa300ml_3s{i}.d);
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
|
|
data2orgtable(1e6*apa300ml_stroke', {'APA 1', 'APA 2', 'APA 3', 'APA 4', 'APA 5', 'APA 6', 'APA 7'}, {'*Stroke* $[\mu m]$'}, ' %.1f ');
|
|
#+end_src
|
|
|
|
#+name: tab:apa_measured_stroke
|
|
#+caption: Measured maximum stroke
|
|
#+attr_latex: :environment tabularx :width 0.25\linewidth :align lc
|
|
#+attr_latex: :center t :booktabs t :float t
|
|
#+RESULTS:
|
|
| | *Stroke* $[\mu m]$ |
|
|
|-------+--------------------|
|
|
| APA 1 | 373.2 |
|
|
| APA 2 | 365.5 |
|
|
| APA 3 | 181.7 |
|
|
| APA 4 | 359.7 |
|
|
| APA 5 | 361.5 |
|
|
| APA 6 | 363.9 |
|
|
| APA 7 | 358.4 |
|
|
|
|
** Spurious resonances
|
|
<<sec:spurious_resonances>>
|
|
*** Introduction
|
|
|
|
Three main resonances are foreseen to be problematic for the control of the APA300ML (Figure [[fig:apa_mode_shapes]]):
|
|
- Mode in X-bending at 189Hz
|
|
- Mode in Y-bending at 285Hz
|
|
- Mode in Z-torsion at 400Hz
|
|
|
|
#+name: fig:apa_mode_shapes
|
|
#+caption: Spurious resonances. a) X-bending mode at 189Hz. b) Y-bending mode at 285Hz. c) Z-torsion mode at 400Hz
|
|
#+attr_latex: :width \linewidth
|
|
[[file:figs/apa_mode_shapes.gif]]
|
|
|
|
These modes are present when flexible joints are fixed to the ends of the APA300ML.
|
|
|
|
In this section, we try to find the resonance frequency of these modes when one end of the APA is fixed and the other is free.
|
|
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('matlab/');
|
|
addpath('matlab/mat/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('mat/');
|
|
#+end_src
|
|
|
|
*** Setup
|
|
|
|
The measurement setup is shown in Figure [[fig:measurement_setup_torsion]].
|
|
A Laser vibrometer is measuring the difference of motion of two points.
|
|
The APA is excited with an instrumented hammer and the transfer function from the hammer to the measured rotation is computed.
|
|
|
|
#+begin_note
|
|
- Laser Doppler Vibrometer Polytec OFV512
|
|
- Instrumented hammer
|
|
#+end_note
|
|
|
|
#+name: fig:measurement_setup_torsion
|
|
#+caption: Measurement setup with a Laser Doppler Vibrometer and one instrumental hammer
|
|
#+attr_latex: :width 0.7\linewidth
|
|
[[file:figs/measurement_setup_torsion.jpg]]
|
|
|
|
*** Bending - X
|
|
|
|
The setup to measure the X-bending motion is shown in Figure [[fig:measurement_setup_X_bending]].
|
|
The APA is excited with an instrumented hammer having a solid metallic tip.
|
|
The impact point is on the back-side of the APA aligned with the top measurement point.
|
|
|
|
#+name: fig:measurement_setup_X_bending
|
|
#+caption: X-Bending measurement setup
|
|
#+attr_latex: :width 0.7\linewidth
|
|
[[file:figs/measurement_setup_X_bending.jpg]]
|
|
|
|
The data is loaded.
|
|
#+begin_src matlab
|
|
bending_X = load('apa300ml_bending_X_top.mat');
|
|
#+end_src
|
|
|
|
The config for =tfestimate= is performed:
|
|
#+begin_src matlab
|
|
Ts = bending_X.Track1_X_Resolution; % Sampling frequency [Hz]
|
|
win = hann(ceil(1/Ts));
|
|
#+end_src
|
|
|
|
The transfer function from the input force to the output "rotation" (difference between the two measured distances).
|
|
#+begin_src matlab
|
|
[G_bending_X, f] = tfestimate(bending_X.Track1, bending_X.Track2, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
The result is shown in Figure [[fig:apa300ml_meas_freq_bending_x]].
|
|
|
|
The can clearly observe a nice peak at 280Hz, and then peaks at the odd "harmonics" (third "harmonic" at 840Hz, and fifth "harmonic" at 1400Hz).
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, abs(G_bending_X), 'k-');
|
|
hold off;
|
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('Amplitude');
|
|
xlim([50, 2e3]); ylim([1e-5, 2e-1]);
|
|
text(280, 5.5e-2,{'280Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(840, 2.0e-3,{'840Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(1400, 7.0e-3,{'1400Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_meas_freq_bending_x.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_meas_freq_bending_x
|
|
#+caption: Obtained FRF for the X-bending
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_meas_freq_bending_x.png]]
|
|
|
|
*** Bending - Y
|
|
|
|
The setup to measure the Y-bending is shown in Figure [[fig:measurement_setup_Y_bending]].
|
|
|
|
The impact point of the instrumented hammer is located on the back surface of the top interface (on the back of the 2 measurements points).
|
|
|
|
#+name: fig:measurement_setup_Y_bending
|
|
#+caption: Y-Bending measurement setup
|
|
#+attr_latex: :width 0.7\linewidth
|
|
[[file:figs/measurement_setup_Y_bending.jpg]]
|
|
|
|
The data is loaded, and the transfer function from the force to the measured rotation is computed.
|
|
#+begin_src matlab
|
|
bending_Y = load('apa300ml_bending_Y_top.mat');
|
|
[G_bending_Y, ~] = tfestimate(bending_Y.Track1, bending_Y.Track2, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
The results are shown in Figure [[fig:apa300ml_meas_freq_bending_y]].
|
|
The main resonance is at 412Hz, and we also see the third "harmonic" at 1220Hz.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, abs(G_bending_Y), 'k-');
|
|
hold off;
|
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('Amplitude');
|
|
xlim([50, 2e3]); ylim([1e-5, 3e-2])
|
|
text(412, 1.5e-2,{'412Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(1218, 1.5e-2,{'1220Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_meas_freq_bending_y.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_meas_freq_bending_y
|
|
#+caption: Obtained FRF for the Y-bending
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_meas_freq_bending_y.png]]
|
|
|
|
*** Torsion - Z
|
|
|
|
Finally, we measure the Z-torsion resonance as shown in Figure [[fig:measurement_setup_torsion_bis]].
|
|
|
|
The excitation is shown on the other side of the APA, on the side to excite the torsion motion.
|
|
|
|
#+name: fig:measurement_setup_torsion_bis
|
|
#+caption: Z-Torsion measurement setup
|
|
#+attr_latex: :width 0.7\linewidth
|
|
[[file:figs/measurement_setup_torsion_bis.jpg]]
|
|
|
|
The data is loaded, and the transfer function computed.
|
|
#+begin_src matlab
|
|
torsion = load('apa300ml_torsion_left.mat');
|
|
[G_torsion, ~] = tfestimate(torsion.Track1, torsion.Track2, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
The results are shown in Figure [[fig:apa300ml_meas_freq_torsion_z]].
|
|
We observe a first peak at 267Hz, which corresponds to the X-bending mode that was measured at 280Hz.
|
|
And then a second peak at 415Hz, which corresponds to the X-bending mode that was measured at 412Hz.
|
|
The mode in pure torsion is probably at higher frequency (peak around 1kHz?).
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, abs(G_torsion), 'k-');
|
|
hold off;
|
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('Amplitude');
|
|
xlim([50, 2e3]); ylim([1e-5, 2e-2])
|
|
text(415, 4.3e-3,{'415Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(267, 8e-4,{'267Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
|
|
text(800, 6e-4,{'800Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_meas_freq_torsion_z.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_meas_freq_torsion_z
|
|
#+caption: Obtained FRF for the Z-torsion
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_meas_freq_torsion_z.png]]
|
|
|
|
In order to verify that, the APA is excited on the top part such that the torsion mode should not be excited.
|
|
#+begin_src matlab
|
|
torsion = load('apa300ml_torsion_top.mat');
|
|
[G_torsion_top, ~] = tfestimate(torsion.Track1, torsion.Track2, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
The two FRF are compared in Figure [[fig:apa300ml_meas_freq_torsion_z_comp]].
|
|
It is clear that the first two modes does not correspond to the torsional mode.
|
|
Maybe the resonance at 800Hz, or even higher resonances. It is difficult to conclude here.
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, abs(G_torsion), 'k-', 'DisplayName', 'Left excitation');
|
|
plot(f, abs(G_torsion_top), '-', 'DisplayName', 'Top excitation');
|
|
hold off;
|
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('Amplitude');
|
|
xlim([50, 2e3]); ylim([1e-5, 2e-2])
|
|
text(415, 4.3e-3,{'415Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(267, 8e-4,{'267Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
|
|
text(800, 2e-3,{'800Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
|
|
legend('location', 'northwest');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_meas_freq_torsion_z_comp.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_meas_freq_torsion_z_comp
|
|
#+caption: Obtained FRF for the Z-torsion
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_meas_freq_torsion_z_comp.png]]
|
|
|
|
*** Compare
|
|
The three measurements are shown in Figure [[fig:apa300ml_meas_freq_compare]].
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, abs(G_torsion), 'DisplayName', 'Torsion');
|
|
plot(f, abs(G_bending_X), 'DisplayName', 'Bending - X');
|
|
plot(f, abs(G_bending_Y), 'DisplayName', 'Bending - Y');
|
|
hold off;
|
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('Amplitude');
|
|
xlim([50, 2e3]); ylim([1e-5, 1e-1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_meas_freq_compare.pdf', 'width', 'full', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_meas_freq_compare
|
|
#+caption: Obtained FRF - Comparison
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_meas_freq_compare.png]]
|
|
|
|
*** Conclusion
|
|
|
|
When two flexible joints are fixed at each ends of the APA, the APA is mostly in a free/free condition in terms of bending/torsion (the bending/torsional stiffness of the joints being very small).
|
|
|
|
In the current tests, the APA are in a fixed/free condition.
|
|
Therefore, it is quite obvious that we measured higher resonance frequencies than what is foreseen for the struts.
|
|
It is however quite interesting that there is a factor $\approx \sqrt{2}$ between the two (increased of the stiffness by a factor 2?).
|
|
|
|
#+name: tab:apa300ml_measured_modes_freq
|
|
#+caption: Measured frequency of the modes
|
|
#+attr_latex: :environment tabularx :width 0.6\linewidth :align ccc
|
|
#+attr_latex: :center t :booktabs t :float t
|
|
| Mode | Strut Mode | Measured Frequency |
|
|
|-----------+------------+--------------------|
|
|
| X-Bending | 189Hz | 280Hz |
|
|
| Y-Bending | 285Hz | 410Hz |
|
|
| Z-Torsion | 400Hz | ? |
|
|
|
|
* Dynamical measurements - APA
|
|
<<sec:dynamical_meas_apa>>
|
|
** Introduction :ignore:
|
|
|
|
In this section, a measurement test bench is used to identify the dynamics of the APA.
|
|
|
|
The bench is shown in Figure [[fig:picture_apa_bench]], and a zoom picture on the APA and encoder is shown in Figure [[fig:picture_apa_bench_encoder]].
|
|
|
|
#+name: fig:picture_apa_bench
|
|
#+caption: Picture of the test bench
|
|
#+attr_latex: :width 0.5\linewidth
|
|
[[file:figs/picture_apa_bench.png]]
|
|
|
|
#+name: fig:picture_apa_bench_encoder
|
|
#+caption: Zoom on the APA with the encoder
|
|
#+attr_latex: :width 0.5\linewidth
|
|
[[file:figs/picture_apa_bench_encoder.png]]
|
|
|
|
#+begin_note
|
|
Here are the documentation of the equipment used for this test bench:
|
|
- Voltage Amplifier: [[file:doc/PD200-V7-R1.pdf][PD200]]
|
|
- Amplified Piezoelectric Actuator: [[file:doc/APA300ML.pdf][APA300ML]]
|
|
- DAC/ADC: Speedgoat [[file:doc/IO131-OEM-Datasheet.pdf][IO313]]
|
|
- Encoder: [[file:doc/L-9517-9678-05-A_Data_sheet_VIONiC_series_en.pdf][Renishaw Vionic]] and used [[file:doc/L-9517-9862-01-C_Data_sheet_RKLC_EN.pdf][Ruler]]
|
|
- Interferometer: [[https://www.attocube.com/en/products/laser-displacement-sensor/displacement-measuring-interferometer][Attocube IDS3010]]
|
|
#+end_note
|
|
|
|
The bench is schematically shown in Figure [[fig:test_bench_apa_alone]] and the signal used are summarized in Table [[tab:test_bench_apa_variables]].
|
|
|
|
#+name: fig:test_bench_apa_alone
|
|
#+caption: Schematic of the Test Bench
|
|
#+attr_latex: :width 0.8\linewidth
|
|
[[file:figs/test_bench_apa_alone.png]]
|
|
|
|
#+name: tab:test_bench_apa_variables
|
|
#+caption: Variables used during the measurements
|
|
#+attr_latex: :environment tabularx :width 0.8\linewidth :align lXXX
|
|
#+attr_latex: :center t :booktabs t :float t
|
|
| Variable | Description | Unit | Hardware |
|
|
|----------+------------------------------+------+-------------------------------|
|
|
| =Va= | Output DAC voltage | [V] | DAC - Ch. 1 => PD200 => APA |
|
|
| =Vs= | Measured stack voltage (ADC) | [V] | APA => ADC - Ch. 1 |
|
|
| =de= | Encoder Measurement | [m] | PEPU Ch. 1 - IO318(1) - Ch. 1 |
|
|
| =da= | Attocube Measurement | [m] | PEPU Ch. 2 - IO318(1) - Ch. 2 |
|
|
| =t= | Time | [s] | |
|
|
|
|
This section is structured as follows:
|
|
- Section [[sec:meas_apa_speedgoat_setup]]: the Speedgoat setup is described (excitation signals, saved signals, etc.)
|
|
- Section [[sec:meas_one_apa]]: the measurements are first performed on one APA.
|
|
- Section [[sec:meas_all_apa]]: the same measurements are performed on all the APA and are compared.
|
|
|
|
** Speedgoat Setup
|
|
<<sec:meas_apa_speedgoat_setup>>
|
|
*** Introduction :ignore:
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('./matlab/src/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
*** =frf_setup.m= - Measurement Setup
|
|
:PROPERTIES:
|
|
:header-args:matlab: :tangle matlab/frf_setup.m
|
|
:header-args:matlab+: :comments no
|
|
:END:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no :exports none
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
First is defined the sampling frequency:
|
|
#+begin_src matlab
|
|
%% Simulation configuration
|
|
Fs = 10e3; % Sampling Frequency [Hz]
|
|
Ts = 1/Fs; % Sampling Time [s]
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Data record configuration
|
|
Trec_start = 5; % Start time for Recording [s]
|
|
Trec_dur = 100; % Recording Duration [s]
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
Tsim = 2*Trec_start + Trec_dur; % Simulation Time [s]
|
|
#+end_src
|
|
|
|
A white noise excitation signal can be very useful in order to obtain a first idea of the plant FRF.
|
|
The gain can be gradually increased until satisfactory output is obtained.
|
|
#+begin_src matlab
|
|
%% Shaped Noise
|
|
V_noise = generateShapedNoise('Ts', 1/Fs, ...
|
|
'V_mean', 3.25, ...
|
|
't_start', Trec_start, ...
|
|
'exc_duration', Trec_dur, ...
|
|
'smooth_ends', true, ...
|
|
'V_exc', 0.05/(1 + s/2/pi/10));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :tangle no
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'Normal', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(V_noise(1,:), V_noise(2,:));
|
|
xlabel('Time [s]'); ylabel('Amplitude [V]');
|
|
|
|
ax2 = nexttile;
|
|
win = hanning(floor(length(V_noise)/8));
|
|
[pxx, f] = pwelch(V_noise(2,:), win, 0, [], Fs);
|
|
plot(f, pxx)
|
|
xlabel('Frequency [Hz]'); ylabel('Power Spectral Density [$V^2/Hz$]');
|
|
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
|
|
xlim([1, Fs/2]); ylim([1e-10, 1e0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/frf_meas_noise_excitation.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:frf_meas_noise_excitation
|
|
#+caption: Example of Shaped noise excitation signal
|
|
#+RESULTS:
|
|
[[file:figs/frf_meas_noise_excitation.png]]
|
|
|
|
The maximum excitation voltage at resonance is 9Vrms, therefore corresponding to 0.6V of output DAC voltage.
|
|
#+begin_src matlab
|
|
%% Sweep Sine
|
|
gc = 0.1;
|
|
xi = 0.5;
|
|
wn = 2*pi*94.3;
|
|
|
|
% Notch filter at the resonance of the APA
|
|
G_sweep = 0.2*(s^2 + 2*gc*xi*wn*s + wn^2)/(s^2 + 2*xi*wn*s + wn^2);
|
|
|
|
V_sweep = generateSweepExc('Ts', Ts, ...
|
|
'f_start', 10, ...
|
|
'f_end', 400, ...
|
|
'V_mean', 3.25, ...
|
|
't_start', Trec_start, ...
|
|
'exc_duration', Trec_dur, ...
|
|
'sweep_type', 'log', ...
|
|
'V_exc', G_sweep*1/(1 + s/2/pi/500));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :tangle no
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'Normal', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(V_sweep(1,:), V_sweep(2,:));
|
|
xlabel('Time [s]'); ylabel('Amplitude [V]');
|
|
|
|
ax2 = nexttile;
|
|
win = hanning(floor(length(V_sweep(2,:))/80));
|
|
[pxx, f] = pwelch(V_sweep(2,:), win, 0, [], Fs);
|
|
plot(f, pxx)
|
|
xlabel('Frequency [Hz]'); ylabel('Power Spectral Density [$V^2/Hz$]');
|
|
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
|
|
xlim([1, Fs/2]); ylim([1e-10, 1e0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/frf_meas_sweep_excitation.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:frf_meas_sweep_excitation
|
|
#+caption: Example of Sweep Sin excitation signal
|
|
#+RESULTS:
|
|
[[file:figs/frf_meas_sweep_excitation.png]]
|
|
|
|
In order to better estimate the high frequency dynamics, a band-limited noise can be used (Figure [[fig:frf_meas_noise_hf_exc]]).
|
|
The frequency content of the noise can be precisely controlled.
|
|
#+begin_src matlab
|
|
%% High Frequency Shaped Noise
|
|
[b,a] = cheby1(10, 2, 2*pi*[300 2e3], 'bandpass', 's');
|
|
wL = 0.005*tf(b, a);
|
|
|
|
V_noise_hf = generateShapedNoise('Ts', 1/Fs, ...
|
|
'V_mean', 3.25, ...
|
|
't_start', Trec_start, ...
|
|
'exc_duration', Trec_dur, ...
|
|
'smooth_ends', true, ...
|
|
'V_exc', wL);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :tangle no
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'Normal', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(V_noise_hf(1,:), V_noise_hf(2,:));
|
|
xlabel('Time [s]'); ylabel('Amplitude [V]');
|
|
|
|
ax2 = nexttile;
|
|
win = hanning(floor(length(V_noise_hf(2,:))/80));
|
|
[pxx, f] = pwelch(V_noise_hf(2,:), win, 0, [], Fs);
|
|
plot(f, pxx)
|
|
xlabel('Frequency [Hz]'); ylabel('Power Spectral Density [$V^2/Hz$]');
|
|
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
|
|
xlim([1, Fs/2]); ylim([1e-10, 1e0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/frf_meas_noise_hf_exc.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:frf_meas_noise_hf_exc
|
|
#+caption: Example of band-limited noise excitation signal
|
|
#+RESULTS:
|
|
[[file:figs/frf_meas_noise_hf_exc.png]]
|
|
|
|
|
|
Then a sinus excitation can be used to estimate the hysteresis.
|
|
#+begin_src matlab
|
|
%% Sinus excitation with increasing amplitude
|
|
V_sin = generateSinIncreasingAmpl('Ts', 1/Fs, ...
|
|
'V_mean', 3.25, ...
|
|
'sin_ampls', [0.1, 0.2, 0.4, 1, 2, 4], ...
|
|
'sin_period', 1, ...
|
|
'sin_num', 5, ...
|
|
't_start', Trec_start, ...
|
|
'smooth_ends', true);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :tangle no
|
|
figure;
|
|
plot(V_sin(1,:), V_sin(2,:));
|
|
xlabel('Time [s]'); ylabel('Amplitude [V]');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/frf_meas_sin_excitation.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:frf_meas_sin_excitation
|
|
#+caption: Example of Shaped noise excitation signal
|
|
#+RESULTS:
|
|
[[file:figs/frf_meas_sin_excitation.png]]
|
|
|
|
Then, we select the wanted excitation signal.
|
|
#+begin_src matlab
|
|
%% Select the excitation signal
|
|
V_exc = timeseries(V_noise(2,:), V_noise(1,:));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :eval no
|
|
%% Plot
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'Normal', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(V_exc(1,:), V_exc(2,:));
|
|
xlabel('Time [s]'); ylabel('Amplitude [V]');
|
|
|
|
ax2 = nexttile;
|
|
win = hanning(floor(length(V_exc)/8));
|
|
[pxx, f] = pwelch(V_exc(2,:), win, 0, [], Fs);
|
|
plot(f, pxx)
|
|
xlabel('Frequency [Hz]'); ylabel('Power Spectral Density [$V^2/Hz$]');
|
|
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
|
|
xlim([1, Fs/2]); ylim([1e-10, 1e0]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Save data that will be loaded in the Simulink file
|
|
save('./frf_data.mat', 'Fs', 'Ts', 'Tsim', 'Trec_start', 'Trec_dur', 'V_exc');
|
|
#+end_src
|
|
|
|
*** =frf_save.m= - Save Data
|
|
:PROPERTIES:
|
|
:header-args: :tangle matlab/frf_save.m
|
|
:header-args:matlab+: :comments no
|
|
:END:
|
|
|
|
First, we get data from the Speedgoat:
|
|
#+begin_src matlab
|
|
tg = slrt;
|
|
|
|
f = SimulinkRealTime.openFTP(tg);
|
|
mget(f, 'data/data.dat');
|
|
close(f);
|
|
#+end_src
|
|
|
|
And we load the data on the Workspace:
|
|
#+begin_src matlab
|
|
data = SimulinkRealTime.utils.getFileScopeData('data/data.dat').data;
|
|
|
|
da = data(:, 1); % Excitation Voltage (input of PD200) [V]
|
|
de = data(:, 2); % Measured voltage (force sensor) [V]
|
|
Vs = data(:, 3); % Measurment displacement (encoder) [m]
|
|
Va = data(:, 4); % Measurement displacement (attocube) [m]
|
|
t = data(:, end); % Time [s]
|
|
#+end_src
|
|
|
|
And we save this to a =mat= file:
|
|
#+begin_src matlab
|
|
apa_number = 1;
|
|
|
|
save(sprintf('mat/frf_data_%i_huddle.mat', apa_number), 't', 'Va', 'Vs', 'de', 'da');
|
|
#+end_src
|
|
|
|
** Measurements on APA 1
|
|
<<sec:meas_one_apa>>
|
|
*** Introduction :ignore:
|
|
Measurements are first performed on only *one* APA.
|
|
Once the measurement procedure is validated, it is performed on all the other APA.
|
|
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('./matlab/mat/');
|
|
addpath('./matlab/src/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
*** Excitation Signal
|
|
For this first measurement, a basic logarithmic sweep is used between 10Hz and 2kHz.
|
|
|
|
The data are loaded.
|
|
#+begin_src matlab
|
|
apa_sweep = load(sprintf('mat/frf_data_%i_sweep.mat', 1), 't', 'Va', 'Vs', 'da', 'de');
|
|
#+end_src
|
|
|
|
The initial time is set to zero.
|
|
#+begin_src matlab
|
|
%% Time vector
|
|
t = apa_sweep.t - apa_sweep.t(1) ; % Time vector [s]
|
|
#+end_src
|
|
|
|
The excitation signal is shown in Figure [[fig:apa_bench_exc_sweep]].
|
|
It is a sweep sine from 10Hz up to 2kHz filtered with a notch centered with the main resonance of the system and a low pass filter.
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
plot(t, apa_sweep.Va)
|
|
xlabel('Time [s]'); ylabel('Excitation Voltage $V_a$ [V]');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_bench_exc_sweep.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_bench_exc_sweep
|
|
#+caption: Excitation voltage
|
|
#+RESULTS:
|
|
[[file:figs/apa_bench_exc_sweep.png]]
|
|
|
|
*** FRF Identification - Setup
|
|
Let's define the sampling time/frequency.
|
|
#+begin_src matlab
|
|
%% Sampling
|
|
Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s]
|
|
Fs = 1/Ts; % Sampling Frequency [Hz]
|
|
#+end_src
|
|
|
|
Then we defined a "Hanning" windows that will be used for the spectral analysis:
|
|
#+begin_src matlab
|
|
win = hanning(ceil(1*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
We get the frequency vector that will be the same for all the frequency domain analysis.
|
|
#+begin_src matlab
|
|
% Only used to have the frequency vector "f"
|
|
[~, f] = tfestimate(apa_sweep.Va, apa_sweep.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
*** FRF Identification - Displacement
|
|
In this section, the transfer function from the excitation voltage $V_a$ to the encoder measured displacement $d_e$ and interferometer measurement $d_a$.
|
|
|
|
The coherence from $V_a$ to $d_e$ is computed and shown in Figure [[fig:apa_1_coh_dvf]].
|
|
It is quite good from 10Hz up to 500Hz.
|
|
#+begin_src matlab
|
|
%% TF - Encoder
|
|
[coh_sweep, ~] = mscohere(apa_sweep.Va, apa_sweep.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_sweep, 'k-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_1_coh_dvf.pdf', 'width', 'normal', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_1_coh_dvf
|
|
#+caption: Coherence for the identification from $V_a$ to $d_e$
|
|
#+RESULTS:
|
|
[[file:figs/apa_1_coh_dvf.png]]
|
|
|
|
The transfer functions are then estimated and shown in Figure [[fig:apa_1_frf_dvf]].
|
|
#+begin_src matlab
|
|
%% TF - Encoder
|
|
[dvf_sweep, ~] = tfestimate(apa_sweep.Va, apa_sweep.de, win, [], [], 1/Ts);
|
|
|
|
%% TF - Interferometer
|
|
[int_sweep, ~] = tfestimate(apa_sweep.Va, apa_sweep.da, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f, abs(dvf_sweep), 'color', colors(1, :), ...
|
|
'DisplayName', 'Encoder');
|
|
plot(f, abs(int_sweep), 'color', colors(2, :), ...
|
|
'DisplayName', 'Interferometer');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'northeast');
|
|
ylim([1e-9, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, 180/pi*angle(dvf_sweep), 'color', colors(1, :));
|
|
plot(f, 180/pi*angle(int_sweep), 'color', colors(2, :));
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_1_frf_dvf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_1_frf_dvf
|
|
#+caption: Obtained transfer functions from $V_a$ to both $d_e$ and $d_a$
|
|
#+RESULTS:
|
|
[[file:figs/apa_1_frf_dvf.png]]
|
|
|
|
#+begin_important
|
|
It seems that using the interferometer, we have a lot more time delay than when using the encoder.
|
|
#+end_important
|
|
|
|
*** FRF Identification - Force Sensor
|
|
Now the dynamics from excitation voltage $V_a$ to the force sensor stack voltage $V_s$ is identified.
|
|
|
|
The coherence is computed and shown in Figure [[fig:apa_1_coh_iff]] and found very good from 10Hz up to 2kHz.
|
|
#+begin_src matlab
|
|
%% TF - Encoder
|
|
[coh_sweep, ~] = mscohere(apa_sweep.Va, apa_sweep.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_sweep, 'k-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_1_coh_iff.pdf', 'width', 'normal', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_1_coh_iff
|
|
#+caption: Coherence for the identification from $V_a$ to $V_s$
|
|
#+RESULTS:
|
|
[[file:figs/apa_1_coh_iff.png]]
|
|
|
|
The transfer function is estimated and shown in Figure [[fig:apa_1_frf_iff]].
|
|
#+begin_src matlab
|
|
%% Transfer function estimation
|
|
[iff_sweep, ~] = tfestimate(apa_sweep.Va, apa_sweep.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f, abs(iff_sweep), 'k-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, 180/pi*angle(iff_sweep), 'k-');
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_1_frf_iff.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_1_frf_iff
|
|
#+caption: Obtained transfer functions from $V_a$ to $V_s$
|
|
#+RESULTS:
|
|
[[file:figs/apa_1_frf_iff.png]]
|
|
|
|
*** Hysteresis
|
|
We here wish to visually see the amount of hysteresis present in the APA.
|
|
|
|
To do so, a quasi static sinusoidal excitation $V_a$ at different voltages is used.
|
|
|
|
The offset is 65V, and the sin amplitude is ranging from 1V up to 80V.
|
|
|
|
For each excitation amplitude, the vertical displacement $d$ of the mass is measured.
|
|
|
|
Then, $d$ is plotted as a function of $V_a$ for all the amplitudes.
|
|
|
|
We expect to obtained something like the hysteresis shown in Figure [[fig:expected_hysteresis]].
|
|
|
|
#+name: fig:expected_hysteresis
|
|
#+caption: Expected Hysteresis cite:poel10_explor_activ_hard_mount_vibrat
|
|
#+attr_latex: :width 0.8\linewidth
|
|
[[file:figs/expected_hysteresis.png]]
|
|
|
|
The data is loaded.
|
|
#+begin_src matlab
|
|
apa_hyst = load('frf_data_1_hysteresis.mat', 't', 'Va', 'de');
|
|
% Initial time set to zero
|
|
apa_hyst.t = apa_hyst.t - apa_hyst.t(1);
|
|
#+end_src
|
|
|
|
The excitation voltage amplitudes are:
|
|
#+begin_src matlab
|
|
ampls = [0.1, 0.2, 0.4, 1, 2, 4]; % Excitation voltage amplitudes
|
|
#+end_src
|
|
|
|
The excitation voltage and the measured displacement are shown in Figure [[fig:hyst_exc_signal_time]].
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(apa_hyst.t, apa_hyst.Va)
|
|
xlabel('Time [s]'); ylabel('Output Voltage [V]');
|
|
|
|
ax2 = nexttile;
|
|
plot(apa_hyst.t, apa_hyst.de)
|
|
xlabel('Time [s]'); ylabel('Measured Displacement [m]');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/hyst_exc_signal_time.pdf', 'width', 'full', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:hyst_exc_signal_time
|
|
#+caption: Excitation voltage and measured displacement
|
|
#+RESULTS:
|
|
[[file:figs/hyst_exc_signal_time.png]]
|
|
|
|
For each amplitude, we only take the last sinus in order to reduce possible transients.
|
|
Also, it is centered on zero.
|
|
|
|
The measured displacement at a function of the output voltage are shown in Figure [[fig:hyst_results_multi_ampl]].
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(1, 3, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([1,2]);
|
|
hold on;
|
|
for i = flip(1:6)
|
|
i_lim = apa_hyst.t > i*5-1 & apa_hyst.t < i*5;
|
|
plot(apa_hyst.Va(i_lim) - mean(apa_hyst.Va(i_lim)), apa_hyst.de(i_lim) - mean(apa_hyst.de(i_lim)), ...
|
|
'DisplayName', sprintf('$V_a = %.1f [V]$', ampls(i)))
|
|
end
|
|
hold off;
|
|
xlabel('Output Voltage [V]'); ylabel('Measured Displacement [m]');
|
|
legend('location', 'northeast');
|
|
xlim([-4, 4]); ylim([-1.2e-4, 1.2e-4]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = flip(1:6)
|
|
i_lim = apa_hyst.t > i*5-1 & apa_hyst.t < i*5;
|
|
plot(apa_hyst.Va(i_lim) - mean(apa_hyst.Va(i_lim)), apa_hyst.de(i_lim) - mean(apa_hyst.de(i_lim)))
|
|
end
|
|
hold off;
|
|
xlim([-0.4, 0.4]); ylim([-0.8e-5, 0.8e-5]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/hyst_results_multi_ampl.pdf', 'width', 'full', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:hyst_results_multi_ampl
|
|
#+caption: Obtained hysteresis for multiple excitation amplitudes
|
|
#+RESULTS:
|
|
[[file:figs/hyst_results_multi_ampl.png]]
|
|
|
|
#+begin_important
|
|
It is quite clear that hysteresis is increasing with the excitation amplitude.
|
|
|
|
Also, no hysteresis is found on the sensor stack voltage.
|
|
#+end_important
|
|
|
|
*** Estimation of the APA axial stiffness
|
|
In order to estimate the stiffness of the APA, a weight with known mass $m_a$ is added on top of the suspended granite and the deflection $d_e$ is measured using the encoder.
|
|
The APA stiffness is then:
|
|
\begin{equation}
|
|
k_{\text{apa}} = \frac{m_a g}{d}
|
|
\end{equation}
|
|
|
|
Here, a mass of 6.4 kg is used:
|
|
#+begin_src matlab
|
|
added_mass = 6.4; % Added mass [kg]
|
|
#+end_src
|
|
|
|
The data is loaded, and the measured displacement is shown in Figure [[fig:apa_1_meas_stiffness]].
|
|
#+begin_src matlab
|
|
apa_mass = load(sprintf('frf_data_%i_add_mass_closed_circuit.mat', 1), 't', 'de');
|
|
apa_mass.de = apa_mass.de - mean(apa_mass.de(apa_mass.t<11));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
plot(apa_mass.t, apa_mass.de, 'k-');
|
|
xlabel('Time [s]'); ylabel('Displacement $d_e$ [m]');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_1_meas_stiffness.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_1_meas_stiffness
|
|
#+caption: Measured displacement when adding the mass and removing the mass
|
|
#+RESULTS:
|
|
[[file:figs/apa_1_meas_stiffness.png]]
|
|
|
|
There is some imprecision in the measurement as there are some drifts that are probably due to some creep.
|
|
|
|
The stiffness is then computed as follows:
|
|
#+begin_src matlab
|
|
k = 9.8 * added_mass / (mean(apa_mass.de(apa_mass.t > 12 & apa_mass.t < 12.5)) - mean(apa_mass.de(apa_mass.t > 20 & apa_mass.t < 20.5)));
|
|
#+end_src
|
|
|
|
And the stiffness obtained is very close to the one specified in the documentation ($k = 1.794\,[N/\mu m]$).
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
sprintf('k = %.2f [N/um]', 1e-6*k);
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: k = 1.68 [N/um]
|
|
|
|
*** Stiffness change due to electrical connections
|
|
We wish here to see if the stiffness changes when the actuator stacks are not connected to the amplifier and the sensor stacks are not connected to the ADC.
|
|
|
|
Note here that the resistor in parallel to the sensor stack is present in both cases.
|
|
|
|
First, the data are loaded.
|
|
#+begin_src matlab
|
|
add_mass_oc = load(sprintf('frf_data_%i_add_mass_open_circuit.mat', 1), 't', 'de');
|
|
add_mass_cc = load(sprintf('frf_data_%i_add_mass_closed_circuit.mat', 1), 't', 'de');
|
|
#+end_src
|
|
|
|
And the initial displacement is set to zero.
|
|
#+begin_src matlab
|
|
add_mass_oc.de = add_mass_oc.de - mean(add_mass_oc.de(add_mass_oc.t<11));
|
|
add_mass_cc.de = add_mass_cc.de - mean(add_mass_cc.de(add_mass_cc.t<11));
|
|
#+end_src
|
|
|
|
The measured displacements are shown in Figure [[fig:apa_meas_k_time_oc_cc]].
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(add_mass_oc.t, add_mass_oc.de, 'DisplayName', 'Not connected');
|
|
plot(add_mass_cc.t, add_mass_cc.de, 'DisplayName', 'Connected');
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('Displacement $d_e$ [m]');
|
|
legend('location', 'northeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_meas_k_time_oc_cc.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_meas_k_time_oc_cc
|
|
#+caption: Measured displacement
|
|
#+RESULTS:
|
|
[[file:figs/apa_meas_k_time_oc_cc.png]]
|
|
|
|
|
|
And the stiffness is estimated in both case.
|
|
The results are shown in Table [[tab:APA_measured_k_oc_cc]].
|
|
#+begin_src matlab
|
|
apa_k_oc = 9.8 * added_mass / (mean(add_mass_oc.de(add_mass_oc.t > 12 & add_mass_oc.t < 12.5)) - mean(add_mass_oc.de(add_mass_oc.t > 20 & add_mass_oc.t < 20.5)));
|
|
apa_k_cc = 9.8 * added_mass / (mean(add_mass_cc.de(add_mass_cc.t > 12 & add_mass_cc.t < 12.5)) - mean(add_mass_cc.de(add_mass_cc.t > 20 & add_mass_cc.t < 20.5)));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
|
|
data2orgtable(1e-6*[apa_k_oc; apa_k_cc], {'Not connected', 'Connected'}, {'$k [N/\mu m]$'}, ' %.1f ');
|
|
#+end_src
|
|
|
|
#+name: tab:APA_measured_k_oc_cc
|
|
#+caption: Measured stiffnesses on "open" and "closed" circuits
|
|
#+attr_latex: :environment tabularx :width 0.3\linewidth :align cc
|
|
#+attr_latex: :center t :booktabs t :float t
|
|
#+RESULTS:
|
|
| | $k [N/\mu m]$ |
|
|
|---------------+---------------|
|
|
| Not connected | 2.3 |
|
|
| Connected | 1.7 |
|
|
|
|
#+begin_important
|
|
Clearly, connecting the actuator stacks to the amplified (basically equivalent as to short circuiting them) lowers the stiffness.
|
|
#+end_important
|
|
|
|
*** Effect of the resistor on the IFF Plant
|
|
A resistor $R \approx 80.6\,k\Omega$ is added in parallel with the sensor stack.
|
|
This has the effect to form a high pass filter with the capacitance of the stack.
|
|
|
|
We here measured the low frequency transfer function from $V_a$ to $V_s$ with and without this resistor.
|
|
|
|
#+begin_src matlab
|
|
% With the resistor
|
|
wi_k = load('frf_data_1_sweep_lf_with_R.mat', 't', 'Vs', 'Va');
|
|
|
|
% Without the resistor
|
|
wo_k = load('frf_data_1_sweep_lf.mat', 't', 'Vs', 'Va');
|
|
#+end_src
|
|
|
|
We use a very long "Hanning" window for the spectral analysis in order to estimate the low frequency behavior.
|
|
#+begin_src matlab
|
|
win = hanning(ceil(50*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
And we estimate the transfer function from $V_a$ to $V_s$ in both cases:
|
|
#+begin_src matlab
|
|
[frf_wo_k, f] = tfestimate(wo_k.Va, wo_k.Vs, win, [], [], 1/Ts);
|
|
[frf_wi_k, ~] = tfestimate(wi_k.Va, wi_k.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
With the following values of the resistor and capacitance, we obtain a first order high pass filter with a crossover frequency equal to:
|
|
#+begin_src matlab
|
|
C = 5.1e-6; % Sensor Stack capacitance [F]
|
|
R = 80.6e3; % Parallel Resistor [Ohm]
|
|
|
|
f0 = 1/(2*pi*R*C); % Crossover frequency of RC HPF [Hz]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
sprintf('f0 = %.2f [Hz]', f0)
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: f0 = 0.39 [Hz]
|
|
|
|
The transfer function of the corresponding high pass filter is:
|
|
#+begin_src matlab
|
|
G_hpf = 0.6*(s/2*pi*f0)/(1 + s/2*pi*f0);
|
|
#+end_src
|
|
|
|
Let's compare the transfer function from actuator stack to sensor stack with and without the added resistor in Figure [[fig:frf_iff_effect_R]].
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f, abs(frf_wo_k), 'DisplayName', 'Without $k$');
|
|
plot(f, abs(frf_wi_k), 'DisplayName', 'With $k$');
|
|
plot(f, abs(squeeze(freqresp(G_hpf, f, 'Hz'))), 'k--', 'DisplayName', sprintf('HPF $f_o = %.2f [Hz]$', f0));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_{out}/V_{in}$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-1, 1e0]);
|
|
legend('location', 'southeast')
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, 180/pi*angle(frf_wo_k));
|
|
plot(f, 180/pi*angle(frf_wi_k));
|
|
plot(f, 180/pi*angle(squeeze(freqresp(G_hpf, f, 'Hz'))), 'k--');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360); ylim([-45, 90]);
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([0.2, 8]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/frf_iff_effect_R.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:frf_iff_effect_R
|
|
#+caption: Transfer function from $V_a$ to $V_s$ with and without the resistor $k$
|
|
#+RESULTS:
|
|
[[file:figs/frf_iff_effect_R.png]]
|
|
|
|
#+begin_important
|
|
The added resistor has indeed the expected effect.
|
|
#+end_important
|
|
|
|
** Comparison of all the APA
|
|
<<sec:meas_all_apa>>
|
|
*** Introduction :ignore:
|
|
The same measurements that was performed in Section [[sec:meas_one_apa]] are now performed on all the APA and then compared.
|
|
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('./matlab/mat/');
|
|
addpath('./matlab/src/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
*** Axial Stiffnesses - Comparison
|
|
Let's first compare the APA axial stiffnesses.
|
|
|
|
The added mass is:
|
|
#+begin_src matlab
|
|
added_mass = 6.4; % Added mass [kg]
|
|
#+end_src
|
|
|
|
Here are the number of the APA that have been measured:
|
|
#+begin_src matlab
|
|
apa_nums = [1 2 4 5 6 7 8];
|
|
#+end_src
|
|
|
|
The data are loaded.
|
|
#+begin_src matlab
|
|
apa_mass = {};
|
|
for i = 1:length(apa_nums)
|
|
apa_mass(i) = {load(sprintf('frf_data_%i_add_mass_closed_circuit.mat', apa_nums(i)), 't', 'de')};
|
|
% The initial displacement is set to zero
|
|
apa_mass{i}.de = apa_mass{i}.de - mean(apa_mass{i}.de(apa_mass{i}.t<11));
|
|
end
|
|
#+end_src
|
|
|
|
The raw measurements are shown in Figure [[fig:apa_meas_k_time]].
|
|
All the APA seems to have similar stiffness except the APA 7 which should have an higher stiffness.
|
|
|
|
#+begin_question
|
|
It is however strange that the displacement $d_e$ when the mass is removed is higher for the APA 7 than for the other APA.
|
|
What could cause that?
|
|
#+end_question
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(apa_mass{i}.t, apa_mass{i}.de, 'DisplayName', sprintf('APA %i', apa_nums(i)));
|
|
end
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('Displacement $d_e$ [m]');
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_meas_k_time.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_meas_k_time
|
|
#+caption: Raw measurements for all the APA. A mass of 6.4kg is added at arround 15s and removed at arround 22s
|
|
#+RESULTS:
|
|
[[file:figs/apa_meas_k_time.png]]
|
|
|
|
The stiffnesses are computed for all the APA and are summarized in Table [[tab:APA_measured_k]].
|
|
|
|
#+begin_src matlab :exports none
|
|
apa_k = zeros(length(apa_nums), 1);
|
|
for i = 1:length(apa_nums)
|
|
apa_k(i) = 9.8 * added_mass / (mean(apa_mass{i}.de(apa_mass{i}.t > 12 & apa_mass{i}.t < 12.5)) - mean(apa_mass{i}.de(apa_mass{i}.t > 20 & apa_mass{i}.t < 20.5)));
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
|
|
data2orgtable(1e-6*apa_k, cellstr(num2str(apa_nums')), {'APA Num', '$k [N/\mu m]$'}, ' %.2f ');
|
|
#+end_src
|
|
|
|
#+name: tab:APA_measured_k
|
|
#+caption: Measured stiffnesses
|
|
#+attr_latex: :environment tabularx :width 0.3\linewidth :align cc
|
|
#+attr_latex: :center t :booktabs t :float t
|
|
#+RESULTS:
|
|
| APA Num | $k [N/\mu m]$ |
|
|
|---------+---------------|
|
|
| 1 | 1.68 |
|
|
| 2 | 1.69 |
|
|
| 4 | 1.7 |
|
|
| 5 | 1.7 |
|
|
| 6 | 1.7 |
|
|
| 7 | 1.93 |
|
|
| 8 | 1.73 |
|
|
|
|
#+begin_important
|
|
The APA300ML manual specifies the nominal stiffness to be $1.8\,[N/\mu m]$ which is very close to what have been measured.
|
|
Only the APA number 7 is a little bit off.
|
|
#+end_important
|
|
|
|
*** FRF Identification - Setup
|
|
The identification is performed in three steps:
|
|
1. White noise excitation with small amplitude.
|
|
This is used to determine the main resonance of the system.
|
|
2. Sweep sine excitation with the amplitude lowered around the resonance.
|
|
The sweep sine is from 10Hz to 400Hz.
|
|
3. High frequency noise.
|
|
The noise is band-passed between 300Hz and 2kHz.
|
|
|
|
Then, the result of the second identification is used between 10Hz and 350Hz and the result of the third identification if used between 350Hz and 2kHz.
|
|
|
|
Here are the APA numbers that have been measured.
|
|
#+begin_src matlab
|
|
apa_nums = [1 2 4 5 6 7 8];
|
|
#+end_src
|
|
|
|
The data are loaded for both the second and third identification:
|
|
#+begin_src matlab
|
|
%% Second identification
|
|
apa_sweep = {};
|
|
for i = 1:length(apa_nums)
|
|
apa_sweep(i) = {load(sprintf('frf_data_%i_sweep.mat', apa_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
|
|
%% Third identification
|
|
apa_noise_hf = {};
|
|
for i = 1:length(apa_nums)
|
|
apa_noise_hf(i) = {load(sprintf('frf_data_%i_noise_hf.mat', apa_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
#+end_src
|
|
|
|
The time is the same for all measurements.
|
|
#+begin_src matlab
|
|
%% Time vector
|
|
t = apa_sweep{1}.t - apa_sweep{1}.t(1) ; % Time vector [s]
|
|
|
|
%% Sampling
|
|
Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s]
|
|
Fs = 1/Ts; % Sampling Frequency [Hz]
|
|
#+end_src
|
|
|
|
Then we defined a "Hanning" windows that will be used for the spectral analysis:
|
|
#+begin_src matlab
|
|
win = hanning(ceil(0.5*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
We get the frequency vector that will be the same for all the frequency domain analysis.
|
|
#+begin_src matlab
|
|
% Only used to have the frequency vector "f"
|
|
[~, f] = tfestimate(apa_sweep{1}.Va, apa_sweep{1}.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
*** FRF Identification - DVF
|
|
In this section, the dynamics from excitation voltage $V_a$ to encoder measured displacement $d_e$ is identified.
|
|
|
|
We compute the coherence for 2nd and 3rd identification:
|
|
#+begin_src matlab
|
|
%% Coherence computation
|
|
coh_sweep = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[coh, ~] = mscohere(apa_sweep{i}.Va, apa_sweep{i}.de, win, [], [], 1/Ts);
|
|
coh_sweep(:, i) = coh;
|
|
end
|
|
|
|
coh_noise_hf = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[coh, ~] = mscohere(apa_noise_hf{i}.Va, apa_noise_hf{i}.de, win, [], [], 1/Ts);
|
|
coh_noise_hf(:, i) = coh;
|
|
end
|
|
#+end_src
|
|
|
|
The coherence is shown in Figure [[fig:apa_frf_dvf_plant_coh]].
|
|
It is clear that the Sweep sine gives good coherence up to 400Hz and that the high frequency noise excitation signal helps increasing a little bit the coherence at high frequency.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_noise_hf(:, 1), 'color', [colors(1, :), 0.5], ...
|
|
'DisplayName', 'HF Noise');
|
|
plot(f, coh_sweep(:, 1), 'color', [colors(2, :), 0.5], ...
|
|
'DisplayName', 'Sweep');
|
|
for i = 2:length(apa_nums)
|
|
plot(f, coh_noise_hf(:, i), 'color', [colors(1, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
plot(f, coh_sweep(:, i), 'color', [colors(2, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
end;
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_frf_dvf_plant_coh
|
|
#+caption: Obtained coherence for the plant from $V_a$ to $d_e$
|
|
#+RESULTS:
|
|
[[file:figs/apa_frf_dvf_plant_coh.png]]
|
|
|
|
|
|
Then, the transfer function from the DAC output voltage $V_a$ to the measured displacement by the encoders is computed:
|
|
#+begin_src matlab
|
|
%% Transfer function estimation
|
|
dvf_sweep = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_sweep{i}.Va, apa_sweep{i}.de, win, [], [], 1/Ts);
|
|
dvf_sweep(:, i) = frf;
|
|
end
|
|
|
|
dvf_noise_hf = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_noise_hf{i}.Va, apa_noise_hf{i}.de, win, [], [], 1/Ts);
|
|
dvf_noise_hf(:, i) = frf;
|
|
end
|
|
#+end_src
|
|
|
|
The obtained transfer functions are shown in Figure [[fig:apa_frf_dvf_plant_tf]].
|
|
They are all superimposed except for the APA7.
|
|
|
|
#+begin_question
|
|
Why is the APA7 off?
|
|
We could think that the APA7 is stiffer, but also the mass line is off.
|
|
|
|
It seems that there is a "gain" problem.
|
|
The encoder seems fine (it measured the same as the Interferometer).
|
|
Maybe it could be due to the amplifier?
|
|
#+end_question
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), abs(dvf_noise_hf(f> 350, i)), 'color', colors(i, :), ...
|
|
'DisplayName', sprintf('APA %i', apa_nums(i)));
|
|
plot(f(f<=350), abs(dvf_sweep( f<=350, i)), 'color', colors(i, :), ...
|
|
'HandleVisibility', 'off');
|
|
end
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
ylim([1e-9, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), 180/pi*angle(dvf_noise_hf(f> 350, i)), 'color', colors(i, :));
|
|
plot(f(f<=350), 180/pi*angle(dvf_sweep( f<=350, i)), 'color', colors(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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_frf_dvf_plant_tf
|
|
#+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$)
|
|
#+RESULTS:
|
|
[[file:figs/apa_frf_dvf_plant_tf.png]]
|
|
|
|
A zoom on the main resonance is shown in Figure [[fig:apa_frf_dvf_zoom_res_plant_tf]].
|
|
It is clear that expect for the APA 7, the response around the resonances are well matching for all the APA.
|
|
|
|
It is also clear that there is not a single resonance but two resonances, a first one at 95Hz and a second one at 105Hz.
|
|
|
|
#+begin_question
|
|
Why is there a double resonance at around 94Hz?
|
|
#+end_question
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f<=350), abs(dvf_sweep( f<=350, i)), 'color', colors(i, :), ...
|
|
'DisplayName', sprintf('APA %i', apa_nums(i)));
|
|
end
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
ylim([2e-5, 4e-4]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f<=350), 180/pi*angle(dvf_sweep( f<=350, i)), 'color', colors(i, :));
|
|
end
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360);
|
|
ylim([-10, 180]);
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([80, 120]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_frf_dvf_zoom_res_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_frf_dvf_zoom_res_plant_tf
|
|
#+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$) - Zoom on the main resonance
|
|
#+RESULTS:
|
|
[[file:figs/apa_frf_dvf_zoom_res_plant_tf.png]]
|
|
|
|
*** FRF Identification - IFF
|
|
In this section, the dynamics from $V_a$ to $V_s$ is identified.
|
|
|
|
First the coherence is computed and shown in Figure [[fig:apa_frf_iff_plant_coh]].
|
|
The coherence is very nice from 10Hz to 2kHz.
|
|
It is only dropping near a zeros at 40Hz, and near the resonance at 95Hz (the excitation amplitude being lowered).
|
|
|
|
#+begin_src matlab
|
|
%% Coherence
|
|
coh_sweep = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[coh, ~] = mscohere(apa_sweep{i}.Va, apa_sweep{i}.Vs, win, [], [], 1/Ts);
|
|
coh_sweep(:, i) = coh;
|
|
end
|
|
|
|
coh_noise_hf = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[coh, ~] = mscohere(apa_noise_hf{i}.Va, apa_noise_hf{i}.Vs, win, [], [], 1/Ts);
|
|
coh_noise_hf(:, i) = coh;
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_noise_hf(:, 1), 'color', [colors(1, :), 0.5], 'DisplayName', 'HF Noise');
|
|
plot(f, coh_sweep( :, 1), 'color', [colors(2, :), 0.5], 'DisplayName', 'Sweep');
|
|
for i = 2:length(apa_nums)
|
|
plot(f, coh_noise_hf(:, i), 'color', [colors(1, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
plot(f, coh_sweep( :, i), 'color', [colors(2, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
end;
|
|
hold off;
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_frf_iff_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_frf_iff_plant_coh
|
|
#+caption: Obtained coherence for the IFF plant
|
|
#+RESULTS:
|
|
[[file:figs/apa_frf_iff_plant_coh.png]]
|
|
|
|
Then the FRF are estimated and shown in Figure [[fig:apa_frf_iff_plant_tf]]
|
|
#+begin_src matlab
|
|
%% FRF estimation of the transfer function from Va to Vs
|
|
iff_sweep = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_sweep{i}.Va, apa_sweep{i}.Vs, win, [], [], 1/Ts);
|
|
iff_sweep(:, i) = frf;
|
|
end
|
|
|
|
iff_noise_hf = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_noise_hf{i}.Va, apa_noise_hf{i}.Vs, win, [], [], 1/Ts);
|
|
iff_noise_hf(:, i) = frf;
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350, i)), 'color', colors(i, :), ...
|
|
'DisplayName', sprintf('APA %i', apa_nums(i)));
|
|
plot(f(f<=350), abs(iff_sweep( f<=350, i)), 'color', colors(i, :), ...
|
|
'HandleVisibility', 'off');
|
|
end
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350, i)), 'color', colors(i, :));
|
|
plot(f(f<=350), 180/pi*angle(iff_sweep( f<=350, i)), 'color', colors(i, :));
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_frf_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_frf_iff_plant_tf
|
|
#+caption:Identified IFF Plant
|
|
#+RESULTS:
|
|
[[file:figs/apa_frf_iff_plant_tf.png]]
|
|
|
|
* Dynamical measurements - Struts
|
|
<<sec:dynamical_meas_struts>>
|
|
** Introduction :ignore:
|
|
|
|
The same bench used in Section [[sec:dynamical_meas_apa]] is here used with the strut instead of only the APA.
|
|
|
|
The bench is shown in Figure [[fig:test_bench_leg_overview]].
|
|
Measurements are performed either when no encoder is fixed to the strut (Figure [[fig:test_bench_leg_front]]) or when one encoder is fixed to the strut (Figure [[fig:test_bench_leg_overview]]).
|
|
|
|
#+name: fig:test_bench_leg_overview
|
|
#+caption: Test Bench with Strut - Overview
|
|
#+attr_latex: :width 0.5\linewidth
|
|
[[file:figs/test_bench_leg_overview.png]]
|
|
|
|
#+name: fig:test_bench_leg_front
|
|
#+caption: Test Bench with Strut - Zoom on the strut
|
|
#+attr_latex: :width 0.5\linewidth
|
|
[[file:figs/test_bench_leg_front.png]]
|
|
|
|
#+name: fig:test_bench_leg_overview
|
|
#+caption: Test Bench with Strut - Zoom on the strut with the encoder
|
|
#+attr_latex: :width 0.5\linewidth
|
|
[[file:figs/test_bench_leg_coder.png]]
|
|
|
|
** Measurement on Strut 1
|
|
<<sec:meas_strut_1>>
|
|
*** Introduction :ignore:
|
|
Measurements are first performed on the strut 1 that contains:
|
|
- APA 1
|
|
- flex 1 and flex 2
|
|
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('./matlab/mat/');
|
|
addpath('./matlab/src/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
*** Without Encoder
|
|
<<sec:meas_strut_1_no_encoder>>
|
|
**** FRF Identification - Setup
|
|
The identification is performed in three steps:
|
|
1. White noise excitation with small amplitude.
|
|
This is used to determine the main resonance of the system.
|
|
2. Sweep sine excitation with the amplitude lowered around the resonance.
|
|
The sweep sine is from 10Hz to 400Hz.
|
|
3. High frequency noise.
|
|
The noise is band-passed between 300Hz and 2kHz.
|
|
|
|
Then, the result of the second identification is used between 10Hz and 350Hz and the result of the third identification if used between 350Hz and 2kHz.
|
|
|
|
#+begin_src matlab
|
|
leg_sweep = load(sprintf('frf_data_leg_%i_sweep.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
leg_noise_hf = load(sprintf('frf_data_leg_%i_noise_hf.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
#+end_src
|
|
|
|
The time is the same for all measurements.
|
|
#+begin_src matlab
|
|
%% Time vector
|
|
t = leg_sweep.t - leg_sweep.t(1) ; % Time vector [s]
|
|
|
|
%% Sampling
|
|
Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s]
|
|
Fs = 1/Ts; % Sampling Frequency [Hz]
|
|
#+end_src
|
|
|
|
Then we defined a "Hanning" windows that will be used for the spectral analysis:
|
|
#+begin_src matlab
|
|
win = hanning(ceil(0.5*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
We get the frequency vector that will be the same for all the frequency domain analysis.
|
|
#+begin_src matlab
|
|
% Only used to have the frequency vector "f"
|
|
[~, f] = tfestimate(leg_sweep.Va, leg_sweep.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
**** FRF Identification - Displacement
|
|
In this section, the dynamics from the excitation voltage $V_a$ to the interferometer $d_a$ is identified.
|
|
|
|
We compute the coherence for 2nd and 3rd identification:
|
|
#+begin_src matlab
|
|
[coh_sweep, ~] = mscohere(leg_sweep.Va, leg_sweep.da, win, [], [], 1/Ts);
|
|
[coh_noise_hf, ~] = mscohere(leg_noise_hf.Va, leg_noise_hf.da, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_noise_hf(:, 1), 'color', colors(1, :), ...
|
|
'DisplayName', 'HF Noise');
|
|
plot(f, coh_sweep(:, 1), 'color', colors(2, :), ...
|
|
'DisplayName', 'Sweep');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_frf_dvf_plant_coh
|
|
#+caption: Obtained coherence for the plant from $V_a$ to $d_a$
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_frf_dvf_plant_coh.png]]
|
|
|
|
The transfer function from $V_a$ to the interferometer measured displacement $d_a$ is estimated and shown in Figure [[fig:strut_1_frf_dvf_plant_tf]].
|
|
#+begin_src matlab
|
|
[dvf_sweep, ~] = tfestimate(leg_sweep.Va, leg_sweep.da, win, [], [], 1/Ts);
|
|
[dvf_noise_hf, ~] = tfestimate(leg_noise_hf.Va, leg_noise_hf.da, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(dvf_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(dvf_sweep( f<=350)), 'k-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-9, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(dvf_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), 180/pi*angle(dvf_sweep( f<=350)), 'k-');
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_frf_dvf_plant_tf
|
|
#+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the interferometer $d_a$)
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_frf_dvf_plant_tf.png]]
|
|
|
|
**** FRF Identification - IFF
|
|
In this section, the dynamics from $V_a$ to $V_s$ is identified.
|
|
|
|
First the coherence is computed and shown in Figure [[fig:strut_1_frf_iff_plant_coh]].
|
|
The coherence is very nice from 10Hz to 2kHz.
|
|
It is only dropping near a zeros at 40Hz, and near the resonance at 95Hz (the excitation amplitude being lowered).
|
|
|
|
#+begin_src matlab
|
|
[coh_sweep, ~] = mscohere(leg_sweep.Va, leg_sweep.Vs, win, [], [], 1/Ts);
|
|
[coh_noise_hf, ~] = mscohere(leg_noise_hf.Va, leg_noise_hf.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_noise_hf, 'DisplayName', 'HF Noise');
|
|
plot(f, coh_sweep, 'DisplayName', 'Sweep');
|
|
hold off;
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_frf_iff_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_frf_iff_plant_coh
|
|
#+caption: Obtained coherence for the IFF plant
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_frf_iff_plant_coh.png]]
|
|
|
|
Then the FRF are estimated and shown in Figure [[fig:strut_1_frf_iff_plant_tf]]
|
|
#+begin_src matlab
|
|
[iff_sweep, ~] = tfestimate(leg_sweep.Va, leg_sweep.Vs, win, [], [], 1/Ts);
|
|
[iff_noise_hf, ~] = tfestimate(leg_noise_hf.Va, leg_noise_hf.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(iff_sweep( f<=350)), 'k-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), 180/pi*angle(iff_sweep( f<=350)), 'k-');
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_frf_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_frf_iff_plant_tf
|
|
#+caption:Identified IFF Plant for the Strut 1
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_frf_iff_plant_tf.png]]
|
|
|
|
*** With Encoder
|
|
<<sec:meas_strut_1_encoder>>
|
|
**** Measurement Data
|
|
#+begin_src matlab
|
|
leg_enc_sweep = load(sprintf('frf_data_leg_coder_badly_align_%i_noise.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
leg_enc_noise_hf = load(sprintf('frf_data_leg_coder_badly_align_%i_noise_hf.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
#+end_src
|
|
|
|
**** FRF Identification - DVF
|
|
In this section, the dynamics from $V_a$ to $d_e$ is identified.
|
|
|
|
We compute the coherence for 2nd and 3rd identification:
|
|
#+begin_src matlab
|
|
[coh_enc_sweep, ~] = mscohere(leg_enc_sweep.Va, leg_enc_sweep.de, win, [], [], 1/Ts);
|
|
[coh_enc_noise_hf, ~] = mscohere(leg_enc_noise_hf.Va, leg_enc_noise_hf.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_enc_noise_hf(:, 1), 'color', colors(1, :), ...
|
|
'DisplayName', 'HF Noise');
|
|
plot(f, coh_enc_sweep(:, 1), 'color', colors(2, :), ...
|
|
'DisplayName', 'Sweep');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
% xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_enc_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_enc_frf_dvf_plant_coh
|
|
#+caption: Obtained coherence for the plant from $V_a$ to $d_e$
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_enc_frf_dvf_plant_coh.png]]
|
|
|
|
#+begin_src matlab
|
|
[dvf_enc_sweep, ~] = tfestimate(leg_enc_sweep.Va, leg_enc_sweep.de, win, [], [], 1/Ts);
|
|
[dvf_enc_noise_hf, ~] = tfestimate(leg_enc_noise_hf.Va, leg_enc_noise_hf.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
[dvf_int_sweep, ~] = tfestimate(leg_enc_sweep.Va, leg_enc_sweep.da, win, [], [], 1/Ts);
|
|
[dvf_int_noise_hf, ~] = tfestimate(leg_enc_noise_hf.Va, leg_enc_noise_hf.da, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
The obtained transfer functions are shown in Figure [[fig:strut_1_enc_frf_dvf_plant_tf]].
|
|
|
|
They are all superimposed except for the APA7.
|
|
|
|
#+begin_question
|
|
Why is the APA7 off?
|
|
We could think that the APA7 is stiffer, but also the mass line is off.
|
|
|
|
It seems that there is a "gain" problem.
|
|
The encoder seems fine (it measured the same as the Interferometer).
|
|
Maybe it could be due to the amplifier?
|
|
#+end_question
|
|
|
|
#+begin_question
|
|
Why is there a double resonance at around 94Hz?
|
|
#+end_question
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(dvf_enc_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(dvf_enc_sweep( f<=350)), 'k-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-7, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(dvf_enc_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), 180/pi*angle(dvf_enc_sweep( f<=350)), 'k-');
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_enc_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_enc_frf_dvf_plant_tf
|
|
#+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$)
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_enc_frf_dvf_plant_tf.png]]
|
|
|
|
**** Comparison of the Encoder and Interferometer
|
|
The interferometer could here represent the case where the encoders are fixed to the plates and not the APA.
|
|
|
|
The dynamics from $V_a$ to $d_e$ and from $V_a$ to $d_a$ are compared in Figure [[fig:strut_1_comp_enc_int]].
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(dvf_enc_noise_hf(f> 350)), 'color', colors(1, :), ...
|
|
'DisplayName', 'Encoder');
|
|
plot(f(f<=350), abs(dvf_enc_sweep( f<=350)), 'color', colors(1, :), ...
|
|
'HandleVisibility', 'off');
|
|
plot(f(f> 350), abs(dvf_int_noise_hf(f> 350)), 'color', colors(2, :), ...
|
|
'DisplayName', 'Interferometer');
|
|
plot(f(f<=350), abs(dvf_int_sweep( f<=350)), 'color', colors(2, :), ...
|
|
'HandleVisibility', 'off');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
ylim([1e-8, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(dvf_enc_noise_hf(f> 350)), 'color', colors(1, :));
|
|
plot(f(f<=350), 180/pi*angle(dvf_enc_sweep( f<=350)), 'color', colors(1, :));
|
|
plot(f(f> 350), 180/pi*angle(dvf_int_noise_hf(f> 350)), 'color', colors(2, :));
|
|
plot(f(f<=350), 180/pi*angle(dvf_int_sweep( f<=350)), 'color', colors(2, :));
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_comp_enc_int.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_comp_enc_int
|
|
#+caption: Comparison of the transfer functions from excitation voltage $V_a$ to either the encoder $d_e$ or the interferometer $d_a$
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_comp_enc_int.png]]
|
|
|
|
#+begin_important
|
|
It will clearly be difficult to do something (except some low frequency positioning) with the encoders fixed to the APA.
|
|
#+end_important
|
|
|
|
**** APA Resonances Frequency
|
|
As shown in Figure [[fig:strut_1_spurious_resonances]], we can clearly see three spurious resonances at 197Hz, 290Hz and 376Hz.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f(f> 350), abs(dvf_enc_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(dvf_enc_sweep( f<=350)), 'k-');
|
|
|
|
text(93, 4e-4, {'93Hz'}, 'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(197, 1.3e-4,{'197Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(290, 4e-6, {'290Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
text(376, 1.4e-6,{'376Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); xlabel('Frequency [Hz]');
|
|
hold off;
|
|
ylim([1e-7, 1e-3]); xlim([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_spurious_resonances.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_spurious_resonances
|
|
#+caption: Magnitude of the transfer function from excitation voltage $V_a$ to encoder measurement $d_e$. The frequency of the resonances are noted.
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_spurious_resonances.png]]
|
|
|
|
|
|
These resonances correspond to parasitic resonances of the APA itself.
|
|
They are very close to what was estimated using the FEM (Figure [[fig:apa_mode_shapes_bis]]):
|
|
- Mode in X-bending at 189Hz
|
|
- Mode in Y-bending at 285Hz
|
|
- Mode in Z-torsion at 400Hz
|
|
|
|
#+name: fig:apa_mode_shapes_bis
|
|
#+caption: Spurious resonances. a) X-bending mode at 189Hz. b) Y-bending mode at 285Hz. c) Z-torsion mode at 400Hz
|
|
#+attr_latex: :width \linewidth
|
|
[[file:figs/apa_mode_shapes.gif]]
|
|
|
|
#+begin_important
|
|
The resonances are indeed due to limited stiffness of the APA.
|
|
#+end_important
|
|
|
|
**** TODO Estimated Flexible Joint axial stiffness
|
|
#+begin_src matlab
|
|
load(sprintf('frf_data_leg_coder_%i_add_mass_closed_circuit.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
de = de - de(1);
|
|
da = da - da(1);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(t, de, 'DisplayName', 'Encoder')
|
|
plot(t, da, 'DisplayName', 'Interferometer')
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('Displacement [m]');
|
|
legend('location', 'northeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
de_steps = [mean(de(t > 13 & t < 14));
|
|
mean(de(t > 19 & t < 20));
|
|
mean(de(t > 24 & t < 25));
|
|
mean(de(t > 28.5 & t < 29.5));
|
|
mean(de(t > 49 & t < 50))] - mean(de(t > 13 & t < 14));
|
|
|
|
da_steps = [mean(da(t > 13 & t < 14));
|
|
mean(da(t > 19 & t < 20));
|
|
mean(da(t > 24 & t < 25));
|
|
mean(da(t > 28.5 & t < 29.5));
|
|
mean(da(t > 49 & t < 50))] - mean(da(t > 13 & t < 14));
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
added_mass = [0; 1; 2; 3; 4];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
lin_fit = (added_mass\abs(de_steps-da_steps) - abs(de_steps(1)-da_steps(1)));
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(added_mass, abs(de_steps-da_steps) - abs(de_steps(1)-da_steps(1)), 'ok')
|
|
plot(added_mass, added_mass*lin_fit, '-r')
|
|
hold off;
|
|
#+end_src
|
|
|
|
#+begin_question
|
|
What is strange is that the encoder is measuring a larger displacement than the interferometer.
|
|
That should be the opposite.
|
|
Maybe is is caused by the fact that the APA is experiencing some bending and therefore a larger motion is measured on the encoder.
|
|
#+end_question
|
|
|
|
**** FRF Identification - IFF
|
|
In this section, the dynamics from $V_a$ to $V_s$ is identified.
|
|
|
|
First the coherence is computed and shown in Figure [[fig:strut_1_frf_iff_plant_coh]].
|
|
The coherence is very nice from 10Hz to 2kHz.
|
|
It is only dropping near a zeros at 40Hz, and near the resonance at 95Hz (the excitation amplitude being lowered).
|
|
|
|
#+begin_src matlab
|
|
[coh_enc_sweep, ~] = mscohere(leg_enc_sweep.Va, leg_enc_sweep.Vs, win, [], [], 1/Ts);
|
|
[coh_enc_noise_hf, ~] = mscohere(leg_enc_noise_hf.Va, leg_enc_noise_hf.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_enc_noise_hf, 'color', colors(1, :), 'DisplayName', 'HF Noise');
|
|
plot(f, coh_enc_sweep, 'color', colors(2, :), 'DisplayName', 'Sweep');
|
|
hold off;
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_frf_iff_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_frf_iff_plant_coh
|
|
#+caption: Obtained coherence for the IFF plant
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_frf_iff_plant_coh.png]]
|
|
|
|
Then the FRF are estimated and shown in Figure [[fig:strut_1_enc_frf_iff_plant_tf]]
|
|
#+begin_src matlab
|
|
[iff_enc_sweep, ~] = tfestimate(leg_enc_sweep.Va, leg_enc_sweep.Vs, win, [], [], 1/Ts);
|
|
[iff_enc_noise_hf, ~] = tfestimate(leg_enc_noise_hf.Va, leg_enc_noise_hf.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(iff_enc_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(iff_enc_sweep( f<=350)), 'k-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(iff_enc_noise_hf(f> 350)), 'k');
|
|
plot(f(f<=350), 180/pi*angle(iff_enc_sweep( f<=350)), 'k');
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_enc_frf_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_enc_frf_iff_plant_tf
|
|
#+caption:Identified IFF Plant
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_enc_frf_iff_plant_tf.png]]
|
|
|
|
Let's now compare the IFF plants whether the encoders are fixed to the APA or not (Figure [[fig:strut_1_frf_iff_comp_enc]]).
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(iff_enc_noise_hf(f> 350)), 'color', colors(1, :), ...
|
|
'DisplayName', 'Encoder');
|
|
plot(f(f<=350), abs(iff_enc_sweep( f<=350)), 'color', colors(1, :), ...
|
|
'HandleVisibility', 'off');
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350)), 'color', colors(2, :), ...
|
|
'DisplayName', 'Without Encoder');
|
|
plot(f(f<=350), abs(iff_sweep( f<=350)), 'color', colors(2, :), ...
|
|
'HandleVisibility', 'off');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(iff_enc_noise_hf(f> 350)), 'color', colors(1, :));
|
|
plot(f(f<=350), 180/pi*angle(iff_enc_sweep( f<=350)), 'color', colors(1, :));
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350)), 'color', colors(2, :));
|
|
plot(f(f<=350), 180/pi*angle(iff_sweep( f<=350)), 'color', colors(2, :));
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_1_frf_iff_effect_enc.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_1_frf_iff_comp_enc
|
|
#+caption: Effect of the encoder on the IFF plant
|
|
#+RESULTS:
|
|
[[file:figs/strut_1_frf_iff_effect_enc.png]]
|
|
|
|
#+begin_important
|
|
We can see that the IFF does not change whether of not the encoder are fixed to the struts.
|
|
#+end_important
|
|
|
|
** Comparison of all the Struts
|
|
<<sec:meas_all_struts>>
|
|
*** Introduction :ignore:
|
|
Now all struts are measured using the same procedure and test bench.
|
|
|
|
*** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
colors = colororder;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('./matlab/mat/');
|
|
addpath('./matlab/src/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
*** FRF Identification - Setup
|
|
The identification is performed in two steps:
|
|
1. White noise excitation with small amplitude.
|
|
This is used to estimate the low frequency dynamics.
|
|
2. High frequency noise.
|
|
The noise is band-passed between 300Hz and 2kHz.
|
|
|
|
Then, the result of the first identification is used between 10Hz and 350Hz and the result of the second identification if used between 350Hz and 2kHz.
|
|
|
|
Here are the LEG numbers that have been measured.
|
|
#+begin_src matlab
|
|
leg_nums = [1 2 3 4 5];
|
|
#+end_src
|
|
|
|
The data are loaded for both the first and second identification:
|
|
#+begin_src matlab
|
|
%% Second identification
|
|
leg_noise = {};
|
|
for i = 1:length(leg_nums)
|
|
leg_noise(i) = {load(sprintf('frf_data_leg_coder_%i_noise.mat', leg_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
|
|
%% Third identification
|
|
leg_noise_hf = {};
|
|
for i = 1:length(leg_nums)
|
|
leg_noise_hf(i) = {load(sprintf('frf_data_leg_coder_%i_noise_hf.mat', leg_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
#+end_src
|
|
|
|
The time is the same for all measurements.
|
|
#+begin_src matlab
|
|
%% Time vector
|
|
t = leg_noise{1}.t - leg_noise{1}.t(1) ; % Time vector [s]
|
|
|
|
%% Sampling
|
|
Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s]
|
|
Fs = 1/Ts; % Sampling Frequency [Hz]
|
|
#+end_src
|
|
|
|
Then we defined a "Hanning" windows that will be used for the spectral analysis:
|
|
#+begin_src matlab
|
|
win = hanning(ceil(0.5*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
We get the frequency vector that will be the same for all the frequency domain analysis.
|
|
#+begin_src matlab
|
|
% Only used to have the frequency vector "f"
|
|
[~, f] = tfestimate(leg_noise{1}.Va, leg_noise{1}.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
*** FRF Identification - DVF
|
|
In this section, the dynamics from $V_a$ to $d_e$ is identified.
|
|
|
|
We compute the coherence for 2nd and 3rd identification:
|
|
#+begin_src matlab
|
|
%% Coherence computation
|
|
coh_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[coh, ~] = mscohere(leg_noise{i}.Va, leg_noise{i}.de, win, [], [], 1/Ts);
|
|
coh_noise(:, i) = coh;
|
|
end
|
|
|
|
coh_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[coh, ~] = mscohere(leg_noise_hf{i}.Va, leg_noise_hf{i}.de, win, [], [], 1/Ts);
|
|
coh_noise_hf(:, i) = coh;
|
|
end
|
|
#+end_src
|
|
|
|
The coherence is shown in Figure [[fig:struts_frf_dvf_plant_coh]].
|
|
It is clear that the Noise sine gives good coherence up to 400Hz and that the high frequency noise excitation signal helps increasing a little bit the coherence at high frequency.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_noise_hf(:, 1), 'color', [colors(1, :), 0.5], ...
|
|
'DisplayName', 'HF Noise');
|
|
plot(f, coh_noise(:, 1), 'color', [colors(2, :), 0.5], ...
|
|
'DisplayName', 'Noise');
|
|
for i = 2:length(leg_nums)
|
|
plot(f, coh_noise_hf(:, i), 'color', [colors(1, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
plot(f, coh_noise(:, i), 'color', [colors(2, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
end;
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/struts_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:struts_frf_dvf_plant_coh
|
|
#+caption: Obtained coherence for the plant from $V_a$ to $d_e$
|
|
#+RESULTS:
|
|
[[file:figs/struts_frf_dvf_plant_coh.png]]
|
|
|
|
|
|
Then, the transfer function from the DAC output voltage $V_a$ to the measured displacement by the encoders is computed:
|
|
#+begin_src matlab
|
|
%% Transfer function estimation
|
|
dvf_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.de, win, [], [], 1/Ts);
|
|
dvf_noise(:, i) = frf;
|
|
end
|
|
|
|
dvf_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.de, win, [], [], 1/Ts);
|
|
dvf_noise_hf(:, i) = frf;
|
|
end
|
|
#+end_src
|
|
|
|
The obtained transfer functions are shown in Figure [[fig:struts_frf_dvf_plant_tf]].
|
|
|
|
They are all superimposed except for the LEG7.
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), abs(dvf_noise_hf(f> 350, i)), 'color', colors(i, :), ...
|
|
'DisplayName', sprintf('Leg %i', leg_nums(i)));
|
|
plot(f(f<=350), abs(dvf_noise( f<=350, i)), 'color', colors(i, :), ...
|
|
'HandleVisibility', 'off');
|
|
end
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
ylim([1e-9, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), 180/pi*angle(dvf_noise_hf(f> 350, i)), 'color', colors(i, :));
|
|
plot(f(f<=350), 180/pi*angle(dvf_noise( f<=350, i)), 'color', colors(i, :));
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/struts_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:struts_frf_dvf_plant_tf
|
|
#+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$)
|
|
#+RESULTS:
|
|
[[file:figs/struts_frf_dvf_plant_tf.png]]
|
|
|
|
#+begin_important
|
|
Depending on how the APA are mounted with the flexible joints, the dynamics can change a lot as shown in Figure [[fig:struts_frf_dvf_plant_tf]].
|
|
In the future, a "pin" will be used to better align the APA with the flexible joints.
|
|
We can expect the amplitude of the spurious resonances to decrease.
|
|
#+end_important
|
|
|
|
*** FRF Identification - DVF with interferometer
|
|
In this section, the dynamics from $V_a$ to $d_a$ is identified.
|
|
|
|
We compute the coherence.
|
|
#+begin_src matlab
|
|
%% Coherence computation
|
|
coh_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[coh, ~] = mscohere(leg_noise{i}.Va, leg_noise{i}.da, win, [], [], 1/Ts);
|
|
coh_noise(:, i) = coh;
|
|
end
|
|
|
|
coh_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[coh, ~] = mscohere(leg_noise_hf{i}.Va, leg_noise_hf{i}.da, win, [], [], 1/Ts);
|
|
coh_noise_hf(:, i) = coh;
|
|
end
|
|
#+end_src
|
|
|
|
The coherence is shown in Figure [[fig:struts_frf_int_plant_coh]].
|
|
It is clear that the Noise sine gives good coherence up to 400Hz and that the high frequency noise excitation signal helps increasing a little bit the coherence at high frequency.
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_noise_hf(:, 1), 'color', [colors(1, :), 0.5], ...
|
|
'DisplayName', 'HF Noise');
|
|
plot(f, coh_noise(:, 1), 'color', [colors(2, :), 0.5], ...
|
|
'DisplayName', 'Noise');
|
|
for i = 2:length(leg_nums)
|
|
plot(f, coh_noise_hf(:, i), 'color', [colors(1, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
plot(f, coh_noise(:, i), 'color', [colors(2, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
end;
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/struts_frf_int_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:struts_frf_int_plant_coh
|
|
#+caption: Obtained coherence for the plant from $V_a$ to $d_e$
|
|
#+RESULTS:
|
|
[[file:figs/struts_frf_int_plant_coh.png]]
|
|
|
|
Then, the transfer function from the DAC output voltage $V_a$ to the measured displacement by the Attocube is computed:
|
|
#+begin_src matlab
|
|
%% Transfer function estimation
|
|
dvf_a_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.da, win, [], [], 1/Ts);
|
|
dvf_a_noise(:, i) = frf;
|
|
end
|
|
|
|
dvf_a_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.da, win, [], [], 1/Ts);
|
|
dvf_a_noise_hf(:, i) = frf;
|
|
end
|
|
#+end_src
|
|
|
|
The obtained transfer functions are shown in Figure [[fig:struts_frf_int_plant_tf]].
|
|
|
|
They are all superimposed except for the LEG7.
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), abs(dvf_a_noise_hf(f> 350, i)), 'color', colors(i, :), ...
|
|
'DisplayName', sprintf('Leg %i', leg_nums(i)));
|
|
plot(f(f<=350), abs(dvf_a_noise( f<=350, i)), 'color', colors(i, :), ...
|
|
'HandleVisibility', 'off');
|
|
end
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
|
|
ylim([1e-9, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), 180/pi*angle(dvf_a_noise_hf(f> 350, i)), 'color', colors(i, :));
|
|
plot(f(f<=350), 180/pi*angle(dvf_a_noise( f<=350, i)), 'color', colors(i, :));
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/struts_frf_int_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:struts_frf_int_plant_tf
|
|
#+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$)
|
|
#+RESULTS:
|
|
[[file:figs/struts_frf_int_plant_tf.png]]
|
|
|
|
*** FRF Identification - IFF
|
|
In this section, the dynamics from $V_a$ to $V_s$ is identified.
|
|
|
|
First the coherence is computed and shown in Figure [[fig:struts_frf_iff_plant_coh]].
|
|
The coherence is very nice from 10Hz to 2kHz.
|
|
It is only dropping near a zeros at 40Hz, and near the resonance at 95Hz (the excitation amplitude being lowered).
|
|
|
|
#+begin_src matlab
|
|
%% Coherence
|
|
coh_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[coh, ~] = mscohere(leg_noise{i}.Va, leg_noise{i}.Vs, win, [], [], 1/Ts);
|
|
coh_noise(:, i) = coh;
|
|
end
|
|
|
|
coh_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[coh, ~] = mscohere(leg_noise_hf{i}.Va, leg_noise_hf{i}.Vs, win, [], [], 1/Ts);
|
|
coh_noise_hf(:, i) = coh;
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_noise_hf(:, 1), 'color', [colors(1, :), 0.5], 'DisplayName', 'HF Noise');
|
|
plot(f, coh_noise( :, 1), 'color', [colors(2, :), 0.5], 'DisplayName', 'Noise');
|
|
for i = 2:length(leg_nums)
|
|
plot(f, coh_noise_hf(:, i), 'color', [colors(1, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
plot(f, coh_noise( :, i), 'color', [colors(2, :), 0.5], ...
|
|
'HandleVisibility', 'off');
|
|
end;
|
|
hold off;
|
|
xlabel('Frequency [Hz]'); ylabel('Coherence [-]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlim([5, 5e3]); ylim([0, 1]);
|
|
legend('location', 'southeast');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/struts_frf_iff_plant_coh.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:struts_frf_iff_plant_coh
|
|
#+caption: Obtained coherence for the IFF plant
|
|
#+RESULTS:
|
|
[[file:figs/struts_frf_iff_plant_coh.png]]
|
|
|
|
Then the FRF are estimated and shown in Figure [[fig:struts_frf_iff_plant_tf]]
|
|
#+begin_src matlab
|
|
%% FRF estimation of the transfer function from Va to Vs
|
|
iff_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.Vs, win, [], [], 1/Ts);
|
|
iff_noise(:, i) = frf;
|
|
end
|
|
|
|
iff_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.Vs, win, [], [], 1/Ts);
|
|
iff_noise_hf(:, i) = frf;
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350, i)), 'color', colors(i, :), ...
|
|
'DisplayName', sprintf('Leg %i', leg_nums(i)));
|
|
plot(f(f<=350), abs(iff_noise( f<=350, i)), 'color', colors(i, :), ...
|
|
'HandleVisibility', 'off');
|
|
end
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350, i)), 'color', colors(i, :));
|
|
plot(f(f<=350), 180/pi*angle(iff_noise( f<=350, i)), 'color', colors(i, :));
|
|
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([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/struts_frf_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:struts_frf_iff_plant_tf
|
|
#+caption:Identified IFF Plant
|
|
#+RESULTS:
|
|
[[file:figs/struts_frf_iff_plant_tf.png]]
|
|
|
|
* TODO Compare with the FEM/Simscape Model :noexport:
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/APA300ML.m
|
|
:END:
|
|
|
|
** Introduction :ignore:
|
|
In this section, the Amplified Piezoelectric Actuator APA300ML ([[file:doc/APA300ML.pdf][doc]]) is modeled using a Finite Element Software.
|
|
Then a /super element/ is exported and imported in Simscape where its dynamic is studied.
|
|
|
|
A 3D view of the Amplified Piezoelectric Actuator (APA300ML) is shown in Figure [[fig:apa300ml_ansys]].
|
|
The remote point used are also shown in this figure.
|
|
|
|
#+name: fig:apa300ml_ansys
|
|
#+caption: Ansys FEM of the APA300ML
|
|
[[file:figs/apa300ml_ansys.jpg]]
|
|
|
|
** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
addpath('matlab/');
|
|
addpath('matlab/APA300ML/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('APA300ML/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
open('APA300ML.slx');
|
|
#+end_src
|
|
|
|
** Import Mass Matrix, Stiffness Matrix, and Interface Nodes Coordinates
|
|
We first extract the stiffness and mass matrices.
|
|
#+begin_src matlab
|
|
K = readmatrix('APA300ML_mat_K.CSV');
|
|
M = readmatrix('APA300ML_mat_M.CSV');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no
|
|
data2orgtable(K(1:10, 1:10), {}, {}, ' %.1g ');
|
|
#+end_src
|
|
|
|
#+caption: First 10x10 elements of the Stiffness matrix
|
|
#+RESULTS:
|
|
| 200000000.0 | 30000.0 | -20000.0 | -70.0 | 300000.0 | 40.0 | 10000000.0 | 10000.0 | -6000.0 | 30.0 |
|
|
| 30000.0 | 30000000.0 | 2000.0 | -200000.0 | 60.0 | -10.0 | 4000.0 | 2000000.0 | -500.0 | 9000.0 |
|
|
| -20000.0 | 2000.0 | 7000000.0 | -10.0 | -30.0 | 10.0 | 6000.0 | 900.0 | -500000.0 | 3 |
|
|
| -70.0 | -200000.0 | -10.0 | 1000.0 | -0.1 | 0.08 | -20.0 | -9000.0 | 3 | -30.0 |
|
|
| 300000.0 | 60.0 | -30.0 | -0.1 | 900.0 | 0.1 | 30000.0 | 20.0 | -10.0 | 0.06 |
|
|
| 40.0 | -10.0 | 10.0 | 0.08 | 0.1 | 10000.0 | 20.0 | 9 | -5 | 0.03 |
|
|
| 10000000.0 | 4000.0 | 6000.0 | -20.0 | 30000.0 | 20.0 | 200000000.0 | 10000.0 | 9000.0 | 50.0 |
|
|
| 10000.0 | 2000000.0 | 900.0 | -9000.0 | 20.0 | 9 | 10000.0 | 30000000.0 | -500.0 | 200000.0 |
|
|
| -6000.0 | -500.0 | -500000.0 | 3 | -10.0 | -5 | 9000.0 | -500.0 | 7000000.0 | -2 |
|
|
| 30.0 | 9000.0 | 3 | -30.0 | 0.06 | 0.03 | 50.0 | 200000.0 | -2 | 1000.0 |
|
|
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no
|
|
data2orgtable(M(1:10, 1:10), {}, {}, ' %.1g ');
|
|
#+end_src
|
|
|
|
#+caption: First 10x10 elements of the Mass matrix
|
|
#+RESULTS:
|
|
| 0.01 | -2e-06 | 1e-06 | 6e-09 | 5e-05 | -5e-09 | -0.0005 | -7e-07 | 6e-07 | -3e-09 |
|
|
| -2e-06 | 0.01 | 8e-07 | -2e-05 | -8e-09 | 2e-09 | -9e-07 | -0.0002 | 1e-08 | -9e-07 |
|
|
| 1e-06 | 8e-07 | 0.009 | 5e-10 | 1e-09 | -1e-09 | -5e-07 | 3e-08 | 6e-05 | 1e-10 |
|
|
| 6e-09 | -2e-05 | 5e-10 | 3e-07 | 2e-11 | -3e-12 | 3e-09 | 9e-07 | -4e-10 | 3e-09 |
|
|
| 5e-05 | -8e-09 | 1e-09 | 2e-11 | 6e-07 | -4e-11 | -1e-06 | -2e-09 | 1e-09 | -8e-12 |
|
|
| -5e-09 | 2e-09 | -1e-09 | -3e-12 | -4e-11 | 1e-07 | -2e-09 | -1e-09 | -4e-10 | -5e-12 |
|
|
| -0.0005 | -9e-07 | -5e-07 | 3e-09 | -1e-06 | -2e-09 | 0.01 | 1e-07 | -3e-07 | -2e-08 |
|
|
| -7e-07 | -0.0002 | 3e-08 | 9e-07 | -2e-09 | -1e-09 | 1e-07 | 0.01 | -4e-07 | 2e-05 |
|
|
| 6e-07 | 1e-08 | 6e-05 | -4e-10 | 1e-09 | -4e-10 | -3e-07 | -4e-07 | 0.009 | -2e-10 |
|
|
| -3e-09 | -9e-07 | 1e-10 | 3e-09 | -8e-12 | -5e-12 | -2e-08 | 2e-05 | -2e-10 | 3e-07 |
|
|
|
|
|
|
Then, we extract the coordinates of the interface nodes.
|
|
#+begin_src matlab
|
|
[int_xyz, int_i, n_xyz, n_i, nodes] = extractNodes('APA300ML_out_nodes_3D.txt');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
|
|
data2orgtable([[1:length(int_i)]', int_i, int_xyz], {}, {'Node i', 'Node Number', 'x [m]', 'y [m]', 'z [m]'}, ' %f ');
|
|
#+end_src
|
|
|
|
#+caption: Coordinates of the interface nodes
|
|
#+RESULTS:
|
|
| Node i | Node Number | x [m] | y [m] | z [m] |
|
|
|--------+-------------+---------+-------+--------|
|
|
| 1.0 | 697783.0 | 0.0 | 0.0 | -0.015 |
|
|
| 2.0 | 697784.0 | 0.0 | 0.0 | 0.015 |
|
|
| 3.0 | 697785.0 | -0.0325 | 0.0 | 0.0 |
|
|
| 4.0 | 697786.0 | -0.0125 | 0.0 | 0.0 |
|
|
| 5.0 | 697787.0 | -0.0075 | 0.0 | 0.0 |
|
|
| 6.0 | 697788.0 | 0.0125 | 0.0 | 0.0 |
|
|
| 7.0 | 697789.0 | 0.0325 | 0.0 | 0.0 |
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no
|
|
data2orgtable([length(n_i); length(int_i); size(M,1) - 6*length(int_i); size(M,1)], {'Total number of Nodes', 'Number of interface Nodes', 'Number of Modes', 'Size of M and K matrices'}, {}, ' %.0f ');
|
|
#+end_src
|
|
|
|
#+caption: Some extracted parameters of the FEM
|
|
#+RESULTS:
|
|
| Total number of Nodes | 7 |
|
|
| Number of interface Nodes | 7 |
|
|
| Number of Modes | 120 |
|
|
| Size of M and K matrices | 162 |
|
|
|
|
Using =K=, =M= and =int_xyz=, we can now use the =Reduced Order Flexible Solid= simscape block.
|
|
|
|
** Piezoelectric parameters
|
|
#+begin_src matlab
|
|
Ga = 1; % [N/V]
|
|
Gs = 1; % [V/m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
m = 0.1; % [kg]
|
|
#+end_src
|
|
|
|
** Simscape Model
|
|
The flexible element is imported using the =Reduced Order Flexible Solid= simscape block.
|
|
|
|
Let's say we use two stacks as a force sensor and one stack as an actuator:
|
|
- A =Relative Motion Sensor= block is added between the nodes A and C
|
|
- An =Internal Force= block is added between the remote points E and B
|
|
|
|
The interface nodes are shown in Figure [[fig:apa300ml_ansys]].
|
|
|
|
One mass is fixed at one end of the piezo-electric stack actuator (remove point F), the other end is fixed to the world frame (remote point G).
|
|
|
|
** Identification of the APA Characteristics
|
|
*** Stiffness
|
|
#+begin_src matlab :exports none
|
|
m = 0.0001;
|
|
#+end_src
|
|
|
|
The transfer function from vertical external force to the relative vertical displacement is identified.
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;
|
|
|
|
G = linearize(mdl, io);
|
|
#+end_src
|
|
|
|
The inverse of its DC gain is the axial stiffness of the APA:
|
|
#+begin_src matlab :results replace value
|
|
1e-6/dcgain(G) % [N/um]
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: 1.753
|
|
|
|
The specified stiffness in the datasheet is $k = 1.8\, [N/\mu m]$.
|
|
|
|
*** Resonance Frequency
|
|
The resonance frequency is specified to be between 650Hz and 840Hz.
|
|
This is also the case for the FEM model (Figure [[fig:apa300ml_resonance]]).
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(2, 4, 5000);
|
|
|
|
figure;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G, freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('Amplitude');
|
|
hold off;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_resonance.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_resonance
|
|
#+caption: First resonance is around 800Hz
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_resonance.png]]
|
|
|
|
*** Amplification factor
|
|
The amplification factor is the ratio of the vertical displacement to the stack displacement.
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/d'], 1, 'openoutput'); io_i = io_i + 1;
|
|
|
|
G = linearize(mdl, io);
|
|
#+end_src
|
|
|
|
The ratio of the two displacement is computed from the FEM model.
|
|
#+begin_src matlab :results replace value
|
|
abs(dcgain(G(1,1))./dcgain(G(2,1)))
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: 5.0749
|
|
|
|
This is actually correct and approximately corresponds to the ratio of the piezo height and length:
|
|
#+begin_src matlab :results replace value
|
|
75/15
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: 5
|
|
|
|
*** Stroke
|
|
|
|
Estimation of the actuator stroke:
|
|
\[ \Delta H = A n \Delta L \]
|
|
with:
|
|
- $\Delta H$ Axial Stroke of the APA
|
|
- $A$ Amplification factor (5 for the APA300ML)
|
|
- $n$ Number of stack used
|
|
- $\Delta L$ Stroke of the stack (0.1% of its length)
|
|
|
|
#+begin_src matlab :results replace value
|
|
1e6 * 5 * 3 * 20e-3 * 0.1e-2
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: 300
|
|
|
|
This is exactly the specified stroke in the data-sheet.
|
|
|
|
*** TODO Stroke BIS
|
|
- [ ] Identified the stroke form the transfer function from V to z
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/V'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/d'], 1, 'openoutput'); io_i = io_i + 1;
|
|
|
|
G = linearize(mdl, io);
|
|
|
|
1e6*170*abs(dcgain(G))
|
|
#+end_src
|
|
|
|
** Identification of the Dynamics from actuator to replace displacement
|
|
We first set the mass to be approximately zero.
|
|
#+begin_src matlab :exports none
|
|
m = 0.01;
|
|
#+end_src
|
|
|
|
The dynamics is identified from the applied force to the measured relative displacement.
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;
|
|
|
|
Gh = -linearize(mdl, io);
|
|
#+end_src
|
|
|
|
The same dynamics is identified for a payload mass of 10Kg.
|
|
#+begin_src matlab
|
|
m = 10;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;
|
|
|
|
Ghm = -linearize(mdl, io);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(0, 4, 5000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Gh, freqs, 'Hz'))), '-');
|
|
plot(freqs, abs(squeeze(freqresp(Ghm, freqs, 'Hz'))), '-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Gh, freqs, 'Hz')))), '-', ...
|
|
'DisplayName', '$m = 0kg$');
|
|
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Ghm, freqs, 'Hz')))), '-', ...
|
|
'DisplayName', '$m = 10kg$');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
yticks(-360:90:360);
|
|
ylim([-360 0]);
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([freqs(1), freqs(end)]);
|
|
legend('location', 'southwest');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_plant_dynamics.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_plant_dynamics
|
|
#+caption: Transfer function from forces applied by the stack to the axial displacement of the APA
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_plant_dynamics.png]]
|
|
|
|
The root locus corresponding to Direct Velocity Feedback with a mass of 10kg is shown in Figure [[fig:apa300ml_dvf_root_locus]].
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
|
|
gains = logspace(0, 5, 500);
|
|
|
|
hold on;
|
|
plot(real(pole(Ghm)), imag(pole(G)), 'kx');
|
|
plot(real(tzero(Ghm)), imag(tzero(G)), 'ko');
|
|
for k = 1:length(gains)
|
|
cl_poles = pole(feedback(Ghm, gains(k)*s));
|
|
plot(real(cl_poles), imag(cl_poles), 'k.');
|
|
end
|
|
hold off;
|
|
axis square;
|
|
xlim([-500, 10]); ylim([0, 510]);
|
|
|
|
xlabel('Real Part'); ylabel('Imaginary Part');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_dvf_root_locus.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_dvf_root_locus
|
|
#+caption: Root Locus for Direct Velocity Feedback
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_dvf_root_locus.png]]
|
|
|
|
** Identification of the Dynamics from actuator to force sensor
|
|
Let's use 2 stacks as a force sensor and 1 stack as force actuator.
|
|
|
|
The transfer function from actuator voltage to sensor voltage is identified and shown in Figure [[fig:apa300ml_iff_plant]].
|
|
#+begin_src matlab :exports none
|
|
m = 10;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1;
|
|
|
|
Giff = -linearize(mdl, io);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(0, 4, 5000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Giff, freqs, 'Hz'))), '-');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Giff, freqs, 'Hz')))), '-');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
yticks(-360:90:360);
|
|
ylim([-180 180]);
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([freqs(1), freqs(end)]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_iff_plant.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_iff_plant
|
|
#+caption: Transfer function from actuator to force sensor
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_iff_plant.png]]
|
|
|
|
For root locus corresponding to IFF is shown in Figure [[fig:apa300ml_iff_root_locus]].
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
|
|
gains = logspace(0, 5, 500);
|
|
|
|
hold on;
|
|
plot(real(pole(Giff)), imag(pole(Giff)), 'kx');
|
|
plot(real(tzero(Giff)), imag(tzero(Giff)), 'ko');
|
|
for k = 1:length(gains)
|
|
cl_poles = pole(feedback(Giff, gains(k)/s));
|
|
plot(real(cl_poles), imag(cl_poles), 'k.');
|
|
end
|
|
hold off;
|
|
axis square;
|
|
xlim([-500, 10]); ylim([0, 510]);
|
|
|
|
xlabel('Real Part'); ylabel('Imaginary Part');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_iff_root_locus.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_iff_root_locus
|
|
#+caption: Root Locus for IFF
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_iff_root_locus.png]]
|
|
|
|
** Identification for a simpler model
|
|
The goal in this section is to identify the parameters of a simple APA model from the FEM.
|
|
This can be useful is a lower order model is to be used for simulations.
|
|
|
|
The presented model is based on cite:souleille18_concep_activ_mount_space_applic.
|
|
|
|
The model represents the Amplified Piezo Actuator (APA) from Cedrat-Technologies (Figure [[fig:souleille18_model_piezo]]).
|
|
The parameters are shown in the table below.
|
|
|
|
#+name: fig:souleille18_model_piezo
|
|
#+caption: Picture of an APA100M from Cedrat Technologies. Simplified model of a one DoF payload mounted on such isolator
|
|
[[file:./figs/souleille18_model_piezo.png]]
|
|
|
|
#+caption:Parameters used for the model of the APA 100M
|
|
| | Meaning |
|
|
|-------+----------------------------------------------------------------|
|
|
| $k_e$ | Stiffness used to adjust the pole of the isolator |
|
|
| $k_1$ | Stiffness of the metallic suspension when the stack is removed |
|
|
| $k_a$ | Stiffness of the actuator |
|
|
| $c_1$ | Added viscous damping |
|
|
|
|
The goal is to determine $k_e$, $k_a$ and $k_1$ so that the simplified model fits the FEM model.
|
|
|
|
\[ \alpha = \frac{x_1}{f}(\omega=0) = \frac{\frac{k_e}{k_e + k_a}}{k_1 + \frac{k_e k_a}{k_e + k_a}} \]
|
|
\[ \beta = \frac{x_1}{F}(\omega=0) = \frac{1}{k_1 + \frac{k_e k_a}{k_e + k_a}} \]
|
|
|
|
If we can fix $k_a$, we can determine $k_e$ and $k_1$ with:
|
|
\[ k_e = \frac{k_a}{\frac{\beta}{\alpha} - 1} \]
|
|
\[ k_1 = \frac{1}{\beta} - \frac{k_e k_a}{k_e + k_a} \]
|
|
|
|
#+begin_src matlab :exports none
|
|
m = 10;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput'); io_i = io_i + 1; % External Vertical Force [N]
|
|
io(io_i) = linio([mdl, '/w'], 1, 'openinput'); io_i = io_i + 1; % Base Motion [m]
|
|
io(io_i) = linio([mdl, '/Fa'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force [N]
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1; % Vertical Displacement [m]
|
|
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensor [V]
|
|
io(io_i) = linio([mdl, '/d'], 1, 'openoutput'); io_i = io_i + 1; % Stack Displacement [m]
|
|
|
|
G = linearize(mdl, io);
|
|
|
|
G.InputName = {'Fd', 'w', 'Fa'};
|
|
G.OutputName = {'y', 'Fs', 'd'};
|
|
#+end_src
|
|
|
|
From the identified dynamics, compute $\alpha$ and $\beta$
|
|
#+begin_src matlab
|
|
alpha = abs(dcgain(G('y', 'Fa')));
|
|
beta = abs(dcgain(G('y', 'Fd')));
|
|
#+end_src
|
|
|
|
$k_a$ is estimated using the following formula:
|
|
#+begin_src matlab
|
|
ka = 0.8/abs(dcgain(G('y', 'Fa')));
|
|
#+end_src
|
|
The factor can be adjusted to better match the curves.
|
|
|
|
Then $k_e$ and $k_1$ are computed.
|
|
#+begin_src matlab
|
|
ke = ka/(beta/alpha - 1);
|
|
k1 = 1/beta - ke*ka/(ke + ka);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
|
|
data2orgtable(1e-6*[ka; ke; k1], {'ka', 'ke', 'k1'}, {'Value [N/um]'}, ' %.1f ');
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
| | Value [N/um] |
|
|
|----+--------------|
|
|
| ka | 40.5 |
|
|
| ke | 1.5 |
|
|
| k1 | 0.4 |
|
|
|
|
The damping in the system is adjusted to match the FEM model if necessary.
|
|
#+begin_src matlab
|
|
c1 = 1e2;
|
|
#+end_src
|
|
|
|
The analytical model of the simpler system is defined below:
|
|
#+begin_src matlab
|
|
Ga = 1/(m*s^2 + k1 + c1*s + ke*ka/(ke + ka)) * ...
|
|
[ 1 , k1 + c1*s + ke*ka/(ke + ka) , ke/(ke + ka) ;
|
|
-ke*ka/(ke + ka), ke*ka/(ke + ka)*m*s^2 , -ke/(ke + ka)*(m*s^2 + c1*s + k1)];
|
|
|
|
Ga.InputName = {'Fd', 'w', 'Fa'};
|
|
Ga.OutputName = {'y', 'Fs'};
|
|
#+end_src
|
|
|
|
And the DC gain is adjusted for the force sensor:
|
|
#+begin_src matlab
|
|
F_gain = dcgain(G('Fs', 'Fd'))/dcgain(Ga('Fs', 'Fd'));
|
|
#+end_src
|
|
|
|
The dynamics of the FEM model and the simpler model are compared in Figure [[fig:apa300ml_comp_simpler_model]].
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(0, 5, 1000);
|
|
|
|
figure;
|
|
tiledlayout(2, 3, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'y', 'w'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Ga('y', 'w'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]);
|
|
ylabel('$x_1/w$ [m/m]');
|
|
ylim([1e-6, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fa'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Ga('y', 'Fa'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]);
|
|
ylabel('$x_1/f$ [m/N]');
|
|
ylim([1e-14, 1e-6]);
|
|
|
|
ax3 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fd'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Ga('y', 'Fd'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]);
|
|
ylabel('$x_1/F$ [m/N]');
|
|
ylim([1e-14, 1e-4]);
|
|
|
|
ax4 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'w'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(F_gain*Ga('Fs', 'w'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]');
|
|
ylabel('$F_s/w$ [m/m]');
|
|
ylim([1e2, 1e8]);
|
|
|
|
ax5 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fa'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(F_gain*Ga('Fs', 'Fa'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]');
|
|
ylabel('$F_s/f$ [m/N]');
|
|
ylim([1e-4, 1e1]);
|
|
|
|
ax6 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fd'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(F_gain*Ga('Fs', 'Fd'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]');
|
|
ylabel('$F_s/F$ [m/N]');
|
|
ylim([1e-7, 1e2]);
|
|
|
|
linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_comp_simpler_model.pdf', 'width', 'full', 'height', 'full');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_comp_simpler_model
|
|
#+caption: Comparison of the Dynamics between the FEM model and the simplified one
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_comp_simpler_model.png]]
|
|
|
|
The simplified model has also been implemented in Simscape.
|
|
|
|
The dynamics of the Simscape simplified model is identified and compared with the FEM one in Figure [[fig:apa300ml_comp_simpler_simscape]].
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML_simplified';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput'); io_i = io_i + 1; % External Vertical Force [N]
|
|
io(io_i) = linio([mdl, '/w'], 1, 'openinput'); io_i = io_i + 1; % Base Motion [m]
|
|
io(io_i) = linio([mdl, '/Fa'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force [N]
|
|
io(io_i) = linio([mdl, '/y'], 1, 'openoutput'); io_i = io_i + 1; % Vertical Displacement [m]
|
|
io(io_i) = linio([mdl, '/Fs'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensor [V]
|
|
|
|
Gs = linearize(mdl, io);
|
|
|
|
Gs.InputName = {'Fd', 'w', 'Fa'};
|
|
Gs.OutputName = {'y', 'Fs'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(0, 5, 1000);
|
|
|
|
figure;
|
|
tiledlayout(2, 3, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'y', 'w'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Gs('y', 'w'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]);
|
|
ylabel('$x_1/w$ [m/m]');
|
|
ylim([1e-6, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fa'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Gs('y', 'Fa'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]);
|
|
ylabel('$x_1/f$ [m/N]');
|
|
ylim([1e-14, 1e-6]);
|
|
|
|
ax3 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fd'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Gs('y', 'Fd'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]);
|
|
ylabel('$x_1/F$ [m/N]');
|
|
ylim([1e-14, 1e-4]);
|
|
|
|
ax4 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'w'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(F_gain*Gs('Fs', 'w'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]');
|
|
ylabel('$F_s/w$ [m/m]');
|
|
ylim([1e2, 1e8]);
|
|
|
|
ax5 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fa'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(F_gain*Gs('Fs', 'Fa'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]');
|
|
ylabel('$F_s/f$ [m/N]');
|
|
ylim([1e-4, 1e1]);
|
|
|
|
ax6 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fd'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(F_gain*Gs('Fs', 'Fd'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]');
|
|
ylabel('$F_s/F$ [m/N]');
|
|
ylim([1e-7, 1e2]);
|
|
|
|
linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa300ml_comp_simpler_simscape.pdf', 'width', 'full', 'height', 'full');
|
|
#+end_src
|
|
|
|
#+name: fig:apa300ml_comp_simpler_simscape
|
|
#+caption: Comparison of the Dynamics between the FEM model and the simplified simscape model
|
|
#+RESULTS:
|
|
[[file:figs/apa300ml_comp_simpler_simscape.png]]
|
|
|
|
** Integral Force Feedback
|
|
In this section, Integral Force Feedback control architecture is applied on the APA300ML.
|
|
|
|
First, the plant (dynamics from voltage actuator to voltage sensor is identified).
|
|
#+begin_src matlab :exports none
|
|
Kiff = tf(0);
|
|
#+end_src
|
|
|
|
The payload mass is set to 10kg.
|
|
#+begin_src matlab
|
|
m = 10;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Name of the Simulink File
|
|
mdl = 'APA300ML_IFF';
|
|
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/w'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/APA300ML'], 1, 'openoutput'); io_i = io_i + 1;
|
|
|
|
G_ol = linearize(mdl, io);
|
|
G_ol.InputName = {'w', 'f', 'F'};
|
|
G_ol.OutputName = {'x1', 'Fs'};
|
|
|
|
G = G_ol({'Fs'}, {'f'});
|
|
#+end_src
|
|
|
|
The obtained dynamics is shown in Figure [[fig:piezo_amplified_iff_plant]].
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(1, 5, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G, freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G, freqs, 'Hz')))));
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
yticks(-360:90:360);
|
|
ylim([-390 30]);
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([freqs(1), freqs(end)]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/piezo_amplified_iff_plant.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:piezo_amplified_iff_plant
|
|
#+caption: IFF Plant
|
|
#+RESULTS:
|
|
[[file:figs/piezo_amplified_iff_plant.png]]
|
|
|
|
The controller is defined below and the loop gain is shown in Figure [[fig:piezo_amplified_iff_loop_gain]].
|
|
#+begin_src matlab
|
|
Kiff = -1e3/s;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(1, 5, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G*Kiff, freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G*Kiff, freqs, 'Hz')))));
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
yticks(-360:90:360);
|
|
ylim([-180 180]);
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([freqs(1), freqs(end)]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/piezo_amplified_iff_loop_gain.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:piezo_amplified_iff_loop_gain
|
|
#+caption: IFF Loop Gain
|
|
#+RESULTS:
|
|
[[file:figs/piezo_amplified_iff_loop_gain.png]]
|
|
|
|
Now the closed-loop system is identified again and compare with the open loop system in Figure [[fig:piezo_amplified_iff_comp]].
|
|
|
|
It is the expected behavior as shown in the Figure [[fig:souleille18_results]] (from cite:souleille18_concep_activ_mount_space_applic).
|
|
|
|
#+begin_src matlab :exports none
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/w'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;
|
|
io(io_i) = linio([mdl, '/APA300ML'], 1, 'output'); io_i = io_i + 1;
|
|
|
|
Giff = linearize(mdl, io);
|
|
Giff.InputName = {'w', 'f', 'F'};
|
|
Giff.OutputName = {'x1', 'Fs'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(0, 3, 1000);
|
|
|
|
figure;
|
|
tiledlayout(2, 3, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_ol('x1', 'w'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Giff('x1', 'w'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]); ylabel('$x_1/w$ [m/m]')
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_ol('x1', 'f'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Giff('x1', 'f'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]); ylabel('$x_1/f$ [m/N]');
|
|
|
|
ax3 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_ol('x1', 'F'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Giff('x1', 'F'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
set(gca, 'XTickLabel',[]); ylabel('$x_1/F$ [m/N]');
|
|
|
|
ax4 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_ol('Fs', 'w'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Giff('Fs', 'w'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('$F_s/w$ [N/m]');
|
|
|
|
ax5 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_ol('Fs', 'f'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Giff('Fs', 'f'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('$F_s/f$ [N/N]');
|
|
|
|
ax6 = nexttile;
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_ol('Fs', 'F'), freqs, 'Hz'))));
|
|
plot(freqs, abs(squeeze(freqresp(Giff('Fs', 'F'), freqs, 'Hz'))));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
xlabel('Frequency [Hz]'); ylabel('$F_s/F$ [N/N]');
|
|
|
|
linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/piezo_amplified_iff_comp.pdf', 'width', 'full', 'height', 'full');
|
|
#+end_src
|
|
|
|
#+name: fig:piezo_amplified_iff_comp
|
|
#+caption: OL and CL transfer functions
|
|
#+RESULTS:
|
|
[[file:figs/piezo_amplified_iff_comp.png]]
|
|
|
|
#+name: fig:souleille18_results
|
|
#+caption: Results obtained in cite:souleille18_concep_activ_mount_space_applic
|
|
[[file:figs/souleille18_results.png]]
|
|
|
|
* Test Bench APA300ML - Simscape Model
|
|
** Introduction
|
|
|
|
A simscape model (Figure [[fig:model_bench_apa]]) of the measurement bench is used.
|
|
|
|
#+name: fig:model_bench_apa
|
|
#+caption: Screenshot of the Simscape model
|
|
#+attr_latex: :width 0.5\linewidth
|
|
[[file:figs/model_bench_apa.png]]
|
|
|
|
** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
%% Add useful folders to the path
|
|
addpath('matlab/');
|
|
addpath('matlab/test_bench_apa300ml/');
|
|
addpath('matlab/mat/');
|
|
addpath('matlab/src/');
|
|
addpath('matlab/png/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
%% Add useful folders to the path
|
|
addpath('test_bench_apa300ml/');
|
|
addpath('png/');
|
|
addpath('mat/');
|
|
addpath('src/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Frequency vector used for many plots
|
|
freqs = 2*logspace(0, 3, 1000);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Open Simscape Model
|
|
options = linearizeOptions;
|
|
options.SampleTime = 0;
|
|
|
|
% Name of the Simulink File
|
|
mdl = 'test_bench_apa300ml';
|
|
|
|
open(mdl)
|
|
#+end_src
|
|
|
|
** First Identification
|
|
The APA is first initialized with default parameters and the transfer function from excitation voltage $V_a$ (before the amplification of 20 due to the PD200 amplifier) to the sensor stack voltage $V_s$, encoder $d_L$ and interferometer $z$ is identified.
|
|
#+begin_src matlab
|
|
%% Initialize the structure containing the data used in the model
|
|
n_hexapod = struct();
|
|
n_hexapod.actuator = initializeAPA('type', '2dof');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage
|
|
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage
|
|
io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Relative Motion Outputs
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1; % Vertical Motion
|
|
|
|
%% Run the linearization
|
|
Ga = linearize(mdl, io, 0.0, options);
|
|
Ga.InputName = {'Va'};
|
|
Ga.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
The obtain dynamics are shown in Figure [[fig:apa_model_bench_bode_vs]] and [[fig:apa_model_bench_bode_dl_z]].
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to taum
|
|
freqs = logspace(1, 3, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Ga('Vs', 'Va'), freqs, 'Hz'))), 'k-')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Ga('Vs', 'Va'), freqs, 'Hz'))), 'k-')
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([0, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_model_bench_bode_vs.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_model_bench_bode_vs
|
|
#+caption: Bode plot of the transfer function from $V_a$ to $V_s$
|
|
#+RESULTS:
|
|
[[file:figs/apa_model_bench_bode_vs.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to dLm and dZm
|
|
freqs = logspace(1, 3, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Ga('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Encoder')
|
|
plot(freqs, abs(squeeze(freqresp(Ga('z', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Interferometer')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southwest');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Ga('dL', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Ga('z', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_model_bench_bode_dl_z.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_model_bench_bode_dl_z
|
|
#+caption: Bode plot of the transfer function from $V_a$ to $d_L$ and to $z$
|
|
#+RESULTS:
|
|
[[file:figs/apa_model_bench_bode_dl_z.png]]
|
|
|
|
** Identify Sensor/Actuator constants and compare with measured FRF
|
|
*** How to identify these constants?
|
|
**** Piezoelectric Actuator Constant
|
|
|
|
Using the measurement test-bench, it is rather easy the determine the static gain between the applied voltage $V_a$ to the induced displacement $d$.
|
|
\begin{equation}
|
|
d = g_{d/V_a} \cdot V_a
|
|
\end{equation}
|
|
|
|
Using the Simscape model of the APA, it is possible to determine the static gain between the actuator force $F_a$ to the induced displacement $d$:
|
|
\begin{equation}
|
|
d = g_{d/F_a} \cdot F_a
|
|
\end{equation}
|
|
|
|
From the two gains, it is then easy to determine $g_a$:
|
|
\begin{equation}
|
|
g_a = \frac{F_a}{V_a} = \frac{F_a}{d} \cdot \frac{d}{V_a} = \frac{g_{d/V_a}}{g_{d/F_a}}
|
|
\end{equation}
|
|
|
|
**** Piezoelectric Sensor Constant
|
|
|
|
Similarly, it is easy to determine the gain from the excitation voltage $V_a$ to the voltage generated by the sensor stack $V_s$:
|
|
\begin{equation}
|
|
V_s = g_{V_s/V_a} V_a
|
|
\end{equation}
|
|
|
|
Note here that there is an high pass filter formed by the piezo capacitor and parallel resistor.
|
|
|
|
The gain can be computed from the dynamical identification and taking the gain at the wanted frequency (above the first resonance).
|
|
|
|
Using the simscape model, compute the gain at the same frequency from the actuator force $F_a$ to the strain of the sensor stack $dl$:
|
|
\begin{equation}
|
|
dl = g_{dl/F_a} F_a
|
|
\end{equation}
|
|
|
|
Then, the "sensor" constant is:
|
|
\begin{equation}
|
|
g_s = \frac{V_s}{dl} = \frac{V_s}{V_a} \cdot \frac{V_a}{F_a} \cdot \frac{F_a}{dl} = \frac{g_{V_s/V_a}}{g_a \cdot g_{dl/F_a}}
|
|
\end{equation}
|
|
|
|
*** Identification Data
|
|
#+begin_src matlab
|
|
%% Load the identification Data
|
|
leg_sweep = load(sprintf('frf_data_%i_sweep.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
leg_noise_hf = load(sprintf('frf_data_%i_noise_hf.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
#+end_src
|
|
|
|
The time is the same for all measurements.
|
|
#+begin_src matlab
|
|
%% Time vector
|
|
t = leg_sweep.t - leg_sweep.t(1) ; % Time vector [s]
|
|
|
|
%% Sampling Time / Frequency
|
|
Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s]
|
|
Fs = 1/Ts; % Sampling Frequency [Hz]
|
|
#+end_src
|
|
|
|
Then we defined a "Hanning" windows that will be used for the spectral analysis:
|
|
#+begin_src matlab
|
|
%% Window used for spectral analysis
|
|
win = hanning(ceil(0.5*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
We get the frequency vector that will be the same for all the frequency domain analysis.
|
|
#+begin_src matlab
|
|
%% Get the frequency vector "f" common to all further spectral data
|
|
[~, f] = tfestimate(leg_sweep.Va, leg_sweep.de, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Estimate the transfer function from u to dLm
|
|
[dvf_sweep, ~] = tfestimate(leg_sweep.Va, leg_sweep.da, win, [], [], 1/Ts);
|
|
[dvf_noise_hf, ~] = tfestimate(leg_noise_hf.Va, leg_noise_hf.da, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Estimate the transfer function from u to taum
|
|
[iff_sweep, ~] = tfestimate(leg_sweep.Va, leg_sweep.Vs, win, [], [], 1/Ts);
|
|
[iff_noise_hf, ~] = tfestimate(leg_noise_hf.Va, leg_noise_hf.Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
*** 2DoF APA
|
|
**** 2DoF APA
|
|
#+begin_src matlab
|
|
%% Initialize a 2DoF APA with Ga=Gs=1
|
|
n_hexapod.actuator = initializeAPA('type', '2dof', 'ga', 1, 'gs', 1);
|
|
#+end_src
|
|
|
|
**** Identification without actuator or sensor constants
|
|
#+begin_src matlab
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage
|
|
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage
|
|
io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Relative Motion Outputs
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1; % Vertical Motion
|
|
|
|
%% Identification
|
|
Gs = linearize(mdl, io, 0.0, options);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
**** Actuator Constant
|
|
#+begin_src matlab
|
|
%% Estimated Actuator Constant
|
|
ga = -mean(abs(dvf_sweep(f>10 & f<20)))./dcgain(Gs('dL', 'Va')); % [N/V]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
sprintf('ga = %.1f [N/V]', ga);
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: ga = -32.1 [N/V]
|
|
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.Ga = ones(6,1)*ga; % Actuator gain [N/V]
|
|
#+end_src
|
|
|
|
**** Sensor Constant
|
|
#+begin_src matlab
|
|
%% Estimated Sensor Constant
|
|
gs = -mean(abs(iff_sweep(f>400 & f<500)))./(ga*abs(squeeze(freqresp(Gs('Vs', 'Va'), 1e3, 'Hz')))); % [V/m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
sprintf('gs = %.3f [V/m]', gs);
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: gs = 0.085 [V/m]
|
|
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.Gs = ones(6,1)*gs; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
**** Comparison
|
|
Identify the dynamics with included constants.
|
|
#+begin_src matlab
|
|
%% Identify again the dynamics with correct Ga,Gs
|
|
Gs = linearize(mdl, io, 0.0, options);
|
|
Gs = Gs*exp(-Ts*s);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to dLm (both Simscape and measured FRF)
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(dvf_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(dvf_sweep( f<=350)), 'k-');
|
|
plot(freqs, abs(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d\mathcal{L}_m/u$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-8, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(dvf_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), 180/pi*angle(dvf_sweep( f<=350)), 'k-');
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_act_constant_comp.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_act_constant_comp
|
|
#+caption: Comparison of the experimental data and Simscape model ($u$ to $d\mathcal{L}_m$)
|
|
#+RESULTS:
|
|
[[file:figs/apa_act_constant_comp.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to taum (both Simscape and measured FRF)
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(iff_sweep( f<=350)), 'k-');
|
|
plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $\tau_m/u$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), 180/pi*angle(iff_sweep( f<=350)), 'k-');
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_sens_constant_comp.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_sens_constant_comp
|
|
#+caption: Comparison of the experimental data and Simscape model ($V_a$ to $V_s$)
|
|
#+RESULTS:
|
|
[[file:figs/apa_sens_constant_comp.png]]
|
|
|
|
*** Flexible APA
|
|
**** Flexible APA
|
|
#+begin_src matlab
|
|
%% Initialize the APA as a flexible body
|
|
n_hexapod.actuator = initializeAPA('type', 'flexible', 'ga', 1, 'gs', 1);
|
|
#+end_src
|
|
|
|
**** Identification without actuator or sensor constants
|
|
#+begin_src matlab
|
|
%% Identify the dynamics
|
|
Gs = linearize(mdl, io, 0.0, options);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
**** Actuator Constant
|
|
#+begin_src matlab
|
|
%% Actuator Constant
|
|
ga = -mean(abs(dvf_sweep(f>10 & f<20)))./dcgain(Gs('dL', 'Va')); % [N/V]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
sprintf('ga = %.1f [N/V]', ga);
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: ga = 23.4 [N/V]
|
|
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.Ga = ones(6,1)*ga; % Actuator gain [N/V]
|
|
#+end_src
|
|
|
|
**** Sensor Constant
|
|
#+begin_src matlab
|
|
%% Sensor Constant
|
|
gs = -mean(abs(iff_sweep(f>400 & f<500)))./(ga*abs(squeeze(freqresp(Gs('Vs', 'Va'), 1e3, 'Hz')))); % [V/m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results :tangle no
|
|
sprintf('gs = %.3f [V/m]', gs);
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: gs = -4674826.805 [V/m]
|
|
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.Gs = ones(6,1)*gs; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
**** Comparison
|
|
#+begin_src matlab
|
|
%% Identify with updated constants
|
|
Gs = linearize(mdl, io, 0.0, options);
|
|
Gs = Gs*exp(-Ts*s);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to dLm (both Simscape and measured FRF)
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(dvf_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(dvf_sweep( f<=350)), 'k-');
|
|
plot(freqs, abs(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d\mathcal{L}_m/u$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-9, 1e-3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(dvf_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), 180/pi*angle(dvf_sweep( f<=350)), 'k-');
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_act_constant_comp_flex.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_act_constant_comp_flex
|
|
#+caption: Comparison of the experimental data and Simscape model ($u$ to $d\mathcal{L}_m$)
|
|
#+RESULTS:
|
|
[[file:figs/apa_act_constant_comp_flex.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to taum (both Simscape and measured FRF)
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), abs(iff_sweep( f<=350)), 'k-');
|
|
plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $\tau_m/u$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350)), 'k-');
|
|
plot(f(f<=350), 180/pi*angle(iff_sweep( f<=350)), 'k-');
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_sens_constant_comp_flex.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_sens_constant_comp_flex
|
|
#+caption: Comparison of the experimental data and Simscape model ($u$ to $\tau_m$)
|
|
#+RESULTS:
|
|
[[file:figs/apa_sens_constant_comp_flex.png]]
|
|
|
|
** Optimize 2-DoF model to fit the experimental Data
|
|
#+begin_src matlab
|
|
%% Optimized parameters
|
|
n_hexapod.actuator = initializeAPA('type', '2dof', ...
|
|
'Ga', -30.0, ...
|
|
'Gs', 0.098, ...
|
|
'k', ones(6,1)*0.38e6, ...
|
|
'ke', ones(6,1)*1.75e6, ...
|
|
'ka', ones(6,1)*3e7, ...
|
|
'c', ones(6,1)*1.3e2, ...
|
|
'ce', ones(6,1)*1e1, ...
|
|
'ca', ones(6,1)*1e1 ...
|
|
);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage
|
|
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage
|
|
io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Relative Motion Outputs
|
|
|
|
%% Identification with optimized parameters
|
|
Gs = exp(-s*Ts)*linearize(mdl, io, 0.0, options);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'dL'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
apa_nums = [1 2 4 5 6 8];
|
|
|
|
%% Second identification
|
|
apa_sweep = {};
|
|
for i = 1:length(apa_nums)
|
|
apa_sweep(i) = {load(sprintf('frf_data_%i_sweep.mat', apa_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
|
|
%% Third identification
|
|
apa_noise_hf = {};
|
|
for i = 1:length(apa_nums)
|
|
apa_noise_hf(i) = {load(sprintf('frf_data_%i_noise_hf.mat', apa_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
|
|
%% Time vector
|
|
t = apa_sweep{1}.t - apa_sweep{1}.t(1) ; % Time vector [s]
|
|
|
|
%% Sampling
|
|
Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s]
|
|
Fs = 1/Ts; % Sampling Frequency [Hz]
|
|
|
|
win = hanning(ceil(0.5*Fs)); % Hannning Windows
|
|
% Only used to have the frequency vector "f"
|
|
[~, f] = tfestimate(apa_sweep{1}.Va, apa_sweep{1}.de, win, [], [], 1/Ts);
|
|
|
|
%% Transfer function estimation
|
|
dvf_sweep = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_sweep{i}.Va, apa_sweep{i}.de, win, [], [], 1/Ts);
|
|
dvf_sweep(:, i) = frf;
|
|
end
|
|
|
|
dvf_noise_hf = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_noise_hf{i}.Va, apa_noise_hf{i}.de, win, [], [], 1/Ts);
|
|
dvf_noise_hf(:, i) = frf;
|
|
end
|
|
|
|
%% FRF estimation of the transfer function from Va to Vs
|
|
iff_sweep = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_sweep{i}.Va, apa_sweep{i}.Vs, win, [], [], 1/Ts);
|
|
iff_sweep(:, i) = frf;
|
|
end
|
|
|
|
iff_noise_hf = zeros(length(f), length(apa_nums));
|
|
for i = 1:length(apa_nums)
|
|
[frf, ~] = tfestimate(apa_noise_hf{i}.Va, apa_noise_hf{i}.Vs, win, [], [], 1/Ts);
|
|
iff_noise_hf(:, i) = frf;
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Comparison of the experimental data and Simscape Model
|
|
freqs = 5*logspace(0, 3, 1000);
|
|
figure;
|
|
tiledlayout(3, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), abs(dvf_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), abs(dvf_sweep( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, abs(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-8, 1e-3]);
|
|
|
|
ax1b = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), abs(iff_sweep( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), 180/pi*angle(dvf_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), 180/pi*angle(dvf_sweep( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
ax2b = nexttile;
|
|
hold on;
|
|
for i = 1:length(apa_nums)
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), 180/pi*angle(iff_sweep( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))))
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
linkaxes([ax1,ax2,ax1b,ax2b],'x');
|
|
xlim([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/comp_apa_plant_after_opt.pdf', 'width', 'full', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:comp_apa_plant_after_opt
|
|
#+caption: Comparison of the measured FRF and the optimized model
|
|
#+RESULTS:
|
|
[[file:figs/comp_apa_plant_after_opt.png]]
|
|
|
|
** Compare 2-DoF with flexible :noexport:
|
|
APA - 2 DoF
|
|
#+begin_src matlab
|
|
n_hexapod.actuator = initializeAPA('type', '2dof');
|
|
|
|
G_2dof = linearize(mdl, io, 0.0, options);
|
|
G_2dof.InputName = {'Va'};
|
|
G_2dof.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
APA - Fully Flexible
|
|
#+begin_src matlab
|
|
n_hexapod.actuator = initializeAPA('type', 'flexible');
|
|
|
|
G_flex = linearize(mdl, io, 0.0, options);
|
|
G_flex.InputName = {'Va'};
|
|
G_flex.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
Comparison
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(1, 4, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_2dof('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', '2DoF')
|
|
plot(freqs, abs(squeeze(freqresp(G_flex('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Flexible')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southeast');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(G_2dof('Vs', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(G_flex('Vs', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_effect_joint_comp_vs.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_effect_joint_comp_vs
|
|
#+caption: Effect of the joint's flexibility on the transfer function from $V_a$ to $V_s$
|
|
#+RESULTS:
|
|
[[file:figs/apa_effect_joint_comp_vs.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(1, 4, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_2dof('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', '2DoF')
|
|
plot(freqs, abs(squeeze(freqresp(G_flex('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Flexible')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_L/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southwest');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(G_2dof('dL', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(G_flex('dL', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_effect_joint_comp_dl.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_effect_joint_comp_dl
|
|
#+caption: Effect of the joint's flexibility on the transfer function from $V_a$ to $d_L$ (encoder)
|
|
#+RESULTS:
|
|
[[file:figs/apa_effect_joint_comp_dl.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(1, 4, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(G_2dof('z', 'Va'), freqs, 'Hz'))), 'DisplayName', '2DoF')
|
|
plot(freqs, abs(squeeze(freqresp(G_flex('z', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Flexible')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $z/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southwest');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(G_2dof('z', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(G_flex('z', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/apa_effect_joint_comp_z.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:apa_effect_joint_comp_z
|
|
#+caption: Effect of the joint's flexibility on the transfer function from $V_a$ to $z$ (interferometer)
|
|
#+RESULTS:
|
|
[[file:figs/apa_effect_joint_comp_z.png]]
|
|
|
|
* Test Bench Struts - Simscape Model
|
|
** Introduction
|
|
** Matlab Init :noexport:ignore:
|
|
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
|
|
<<matlab-dir>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none :results silent :noweb yes
|
|
<<matlab-init>>
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no
|
|
%% Add useful folders to the path
|
|
addpath('matlab/');
|
|
addpath('matlab/test_bench_struts/');
|
|
addpath('matlab/mat/');
|
|
addpath('matlab/src/');
|
|
addpath('matlab/png/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
%% Add useful folders to the path
|
|
addpath('test_bench_struts/');
|
|
addpath('png/');
|
|
addpath('mat/');
|
|
addpath('src/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Frequency vector used for many plots
|
|
freqs = 2*logspace(0, 3, 1000);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Options for Linearized
|
|
options = linearizeOptions;
|
|
options.SampleTime = 0;
|
|
|
|
%% Name of the Simulink File
|
|
mdl = 'test_bench_struts';
|
|
|
|
%% Open the Simulink File
|
|
open(mdl)
|
|
#+end_src
|
|
|
|
** First Identification
|
|
The object containing all the data is created.
|
|
#+begin_src matlab
|
|
%% Initialize structure containing data for the Simscape model
|
|
n_hexapod = struct();
|
|
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '2dof');
|
|
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '2dof');
|
|
n_hexapod.actuator = initializeAPA('type', '2dof');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage
|
|
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage
|
|
io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Relative Motion Outputs
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1; % Vertical Motion
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Run the linearization
|
|
Gs = linearize(mdl, io, 0.0, options);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to taum
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), 'k-')
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), 'k-')
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([0, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_bench_model_iff_bode.pdf', 'width', 'wide', 'height', 'normal');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_bench_model_iff_bode
|
|
#+caption: Identified transfer function from $V_a$ to $V_s$
|
|
#+RESULTS:
|
|
[[file:figs/strut_bench_model_iff_bode.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Bode plot of the transfer function from u to dLm and dZm
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Encoder')
|
|
plot(freqs, abs(squeeze(freqresp(Gs('z', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Interferometer')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southwest');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('dL', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('z', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_bench_model_dvf_bode.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_bench_model_dvf_bode
|
|
#+caption: Identified transfer function from $V_a$ to $d_L$
|
|
#+RESULTS:
|
|
[[file:figs/strut_bench_model_dvf_bode.png]]
|
|
|
|
** Effect of flexible joints
|
|
Perfect
|
|
#+begin_src matlab
|
|
%% Perfect Joints
|
|
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '2dof');
|
|
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '3dof');
|
|
|
|
Gp = linearize(mdl, io, 0.0, options);
|
|
Gp.InputName = {'Va'};
|
|
Gp.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
Top Flexible
|
|
#+begin_src matlab
|
|
%% Top joint with Axial stiffness
|
|
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '2dof');
|
|
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof');
|
|
|
|
Gt = linearize(mdl, io, 0.0, options);
|
|
Gt.InputName = {'Va'};
|
|
Gt.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
Bottom Flexible
|
|
#+begin_src matlab
|
|
%% Bottom joint with Axial stiffness
|
|
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof');
|
|
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '3dof');
|
|
|
|
Gb = linearize(mdl, io, 0.0, options);
|
|
Gb.InputName = {'Va'};
|
|
Gb.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
Both Flexible
|
|
#+begin_src matlab
|
|
%% Both joints with Axial stiffness
|
|
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof');
|
|
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof');
|
|
|
|
Gf = linearize(mdl, io, 0.0, options);
|
|
Gf.InputName = {'Va'};
|
|
Gf.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
Comparison in Figures [[fig:strut_effect_joint_comp_vs]], [[fig:strut_effect_joint_comp_dl]] and [[fig:strut_effect_joint_comp_z]].
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Transfer function from u to taum - Effect of flexible joints
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Gp('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Perfect')
|
|
plot(freqs, abs(squeeze(freqresp(Gt('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Top')
|
|
plot(freqs, abs(squeeze(freqresp(Gb('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Bot')
|
|
plot(freqs, abs(squeeze(freqresp(Gf('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Flex')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southeast');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gp('Vs', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gt('Vs', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gb('Vs', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gf('Vs', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_effect_joint_comp_vs.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_effect_joint_comp_vs
|
|
#+caption: Effect of the joint's flexibility on the transfer function from $V_a$ to $V_s$
|
|
#+RESULTS:
|
|
[[file:figs/strut_effect_joint_comp_vs.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Transfer function from u to dLm - Effect of flexible joints
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Gp('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Perfect')
|
|
plot(freqs, abs(squeeze(freqresp(Gt('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Top')
|
|
plot(freqs, abs(squeeze(freqresp(Gb('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Bot')
|
|
plot(freqs, abs(squeeze(freqresp(Gf('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Flex')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_L/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southwest');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gp('dL', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gt('dL', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gb('dL', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gf('dL', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_effect_joint_comp_dl.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_effect_joint_comp_dl
|
|
#+caption: Effect of the joint's flexibility on the transfer function from $V_a$ to $d_L$ (encoder)
|
|
#+RESULTS:
|
|
[[file:figs/strut_effect_joint_comp_dl.png]]
|
|
|
|
#+begin_src matlab :exports none
|
|
%% Transfer function from u to dZm - Effect of flexible joints
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Gp('z', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Perfect')
|
|
plot(freqs, abs(squeeze(freqresp(Gt('z', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Top')
|
|
plot(freqs, abs(squeeze(freqresp(Gb('z', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Bot')
|
|
plot(freqs, abs(squeeze(freqresp(Gf('z', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Flex')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $z/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
legend('location', 'southwest');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gp('z', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gt('z', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gb('z', 'Va'), freqs, 'Hz'))))
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gf('z', 'Va'), freqs, 'Hz'))))
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:45:360);
|
|
ylim([-180, 180])
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/strut_effect_joint_comp_z.pdf', 'width', 'wide', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:strut_effect_joint_comp_z
|
|
#+caption: Effect of the joint's flexibility on the transfer function from $V_a$ to $z$ (interferometer)
|
|
#+RESULTS:
|
|
[[file:figs/strut_effect_joint_comp_z.png]]
|
|
|
|
#+begin_important
|
|
Imperfection of the flexible joints has the largest impact on the transfer function from $V_a$ to $d_L$.
|
|
However, it has relatively small impact on the transfer functions from $V_a$ to $V_s$ and to $z$.
|
|
#+end_important
|
|
|
|
** Integral Force Feedback
|
|
*** Initialize the system
|
|
#+begin_src matlab
|
|
%% Initialize typical system
|
|
n_hexapod = struct();
|
|
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '2dof');
|
|
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '3dof');
|
|
n_hexapod.actuator = initializeAPA('type', '2dof');
|
|
#+end_src
|
|
|
|
*** Plant Identification
|
|
#+begin_src matlab
|
|
%% Identify th edynamics
|
|
G = linearize(mdl, io, 0.0, options);
|
|
G.InputName = {'Va'};
|
|
G.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% IFF Plant (transfer function from u to taum)
|
|
Giff = G('Vs', 'Va');
|
|
#+end_src
|
|
|
|
*** Root Locus
|
|
\begin{equation}
|
|
K_{\text{IFF}} = \frac{g}{s + \omega_c}
|
|
\end{equation}
|
|
|
|
#+begin_src matlab
|
|
%% Cut-off frequency of the LPF
|
|
wc = 2*pi*20;
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
% Gains used for the Root Locus plot
|
|
gains = logspace(1, 5, 300);
|
|
|
|
%% Root Locus for the IFF
|
|
figure;
|
|
|
|
hold on;
|
|
% Pure Integrator
|
|
set(gca,'ColorOrderIndex',1);
|
|
plot(real(pole(Giff)), imag(pole(Giff)), 'x', 'DisplayName', '$g = 0$');
|
|
set(gca,'ColorOrderIndex',1);
|
|
plot(real(tzero(Giff)), imag(tzero(Giff)), 'o', 'HandleVisibility', 'off');
|
|
for g = gains
|
|
clpoles = pole(feedback(Giff, (g/(s + wc))));
|
|
set(gca,'ColorOrderIndex',1);
|
|
plot(real(clpoles), imag(clpoles), '.', 'HandleVisibility', 'off');
|
|
end
|
|
|
|
g = 2e2;
|
|
clpoles = pole(feedback(Giff, (g/(s + wc))));
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(real(clpoles), imag(clpoles), 'x', 'DisplayName', sprintf('$g=%.0f$', g));
|
|
axis square;
|
|
xlim([-700, 0]); ylim([-0, 700]);
|
|
xlabel('Real Part'); ylabel('Imaginary Part');
|
|
legend('location', 'northwest');
|
|
#+end_src
|
|
|
|
** Comparison with the experimental Data
|
|
#+begin_src matlab :exports none
|
|
%% Measured dynamics
|
|
leg_nums = [1 2 3 4 5];
|
|
|
|
% Second identification
|
|
leg_noise = {};
|
|
for i = 1:length(leg_nums)
|
|
leg_noise(i) = {load(sprintf('frf_data_leg_coder_%i_noise.mat', leg_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
|
|
% Third identification
|
|
leg_noise_hf = {};
|
|
for i = 1:length(leg_nums)
|
|
leg_noise_hf(i) = {load(sprintf('frf_data_leg_coder_%i_noise_hf.mat', leg_nums(i)), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
|
|
t = leg_noise{1}.t - leg_noise{1}.t(1) ; % Time vector [s]
|
|
Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s]
|
|
Fs = 1/Ts; % Sampling Frequency [Hz]
|
|
|
|
win = hanning(ceil(0.5*Fs)); % Hannning Windows
|
|
|
|
% Only used to have the frequency vector "f"
|
|
[~, f] = tfestimate(leg_noise{1}.Va, leg_noise{1}.de, win, [], [], 1/Ts);
|
|
|
|
% Transfer function estimation
|
|
dvf_a_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.da, win, [], [], 1/Ts);
|
|
dvf_a_noise(:, i) = frf;
|
|
end
|
|
|
|
dvf_a_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.da, win, [], [], 1/Ts);
|
|
dvf_a_noise_hf(:, i) = frf;
|
|
end
|
|
|
|
% FRF estimation of the transfer function from Va to Vs
|
|
iff_noise = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.Vs, win, [], [], 1/Ts);
|
|
iff_noise(:, i) = frf;
|
|
end
|
|
|
|
iff_noise_hf = zeros(length(f), length(leg_nums));
|
|
for i = 1:length(leg_nums)
|
|
[frf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.Vs, win, [], [], 1/Ts);
|
|
iff_noise_hf(:, i) = frf;
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Initialize Simscape data
|
|
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof');
|
|
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof');
|
|
n_hexapod.actuator = initializeAPA('type', '2dof');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Input/Output definition
|
|
clear io; io_i = 1;
|
|
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage
|
|
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage
|
|
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1; % Relative Motion Outputs
|
|
|
|
%% Identification
|
|
Gs = exp(-s*Ts)*linearize(mdl, io, 0.0, options);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'z'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = 5*logspace(0, 3, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), abs(dvf_a_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), abs(dvf_a_noise( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, abs(squeeze(freqresp(Gs('z', 'Va'), freqs, 'Hz'))), '-')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-8, 1e-3]);
|
|
|
|
ax1b = nexttile([2,1]);
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), abs(iff_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), abs(iff_noise( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), '-')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-2, 1e2]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), 180/pi*angle(dvf_a_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), 180/pi*angle(dvf_a_noise( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('z', 'Va'), freqs, 'Hz'))), '-')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
ax2b = nexttile;
|
|
hold on;
|
|
for i = 1:length(leg_nums)
|
|
plot(f(f> 350), 180/pi*angle(iff_noise_hf(f> 350, i)), 'color', [0,0,0,0.2]);
|
|
plot(f(f<=350), 180/pi*angle(iff_noise( f<=350, i)), 'color', [0,0,0,0.2]);
|
|
end
|
|
set(gca,'ColorOrderIndex',2);
|
|
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), '-')
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
|
hold off;
|
|
yticks(-360:90:360); ylim([-180, 180]);
|
|
|
|
linkaxes([ax1,ax2,ax1b,ax2b],'x');
|
|
xlim([10, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :tangle no :exports results :results file replace
|
|
exportFig('figs/comp_strut_plant_after_opt.pdf', 'width', 'full', 'height', 'tall');
|
|
#+end_src
|
|
|
|
#+name: fig:comp_strut_plant_after_opt
|
|
#+caption: Comparison of the measured FRF and the optimized model
|
|
#+RESULTS:
|
|
[[file:figs/comp_strut_plant_after_opt.png]]
|
|
|
|
* Function
|
|
** =initializeBotFlexibleJoint= - Initialize Flexible Joint
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/src/initializeBotFlexibleJoint.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:initializeBotFlexibleJoint>>
|
|
|
|
*** Function description
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
function [flex_bot] = initializeBotFlexibleJoint(args)
|
|
% initializeBotFlexibleJoint -
|
|
%
|
|
% Syntax: [flex_bot] = initializeBotFlexibleJoint(args)
|
|
%
|
|
% Inputs:
|
|
% - args -
|
|
%
|
|
% Outputs:
|
|
% - flex_bot -
|
|
#+end_src
|
|
|
|
*** Optional Parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
args.type char {mustBeMember(args.type,{'2dof', '3dof', '4dof'})} = '2dof'
|
|
|
|
args.kRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
|
|
args.kRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
|
|
args.kRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*260
|
|
args.kz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*1e8
|
|
|
|
args.cRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.1
|
|
args.cRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.1
|
|
args.cRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.1
|
|
args.cz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*1e2
|
|
end
|
|
#+end_src
|
|
|
|
*** Initialize the structure
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
flex_bot = struct();
|
|
#+end_src
|
|
|
|
*** Set the Joint's type
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
switch args.type
|
|
case '2dof'
|
|
flex_bot.type = 1;
|
|
case '3dof'
|
|
flex_bot.type = 2;
|
|
case '4dof'
|
|
flex_bot.type = 3;
|
|
end
|
|
#+end_src
|
|
|
|
*** Set parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
flex_bot.kRx = args.kRx;
|
|
flex_bot.kRy = args.kRy;
|
|
flex_bot.kRz = args.kRz;
|
|
flex_bot.kz = args.kz;
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
flex_bot.cRx = args.cRx;
|
|
flex_bot.cRy = args.cRy;
|
|
flex_bot.cRz = args.cRz;
|
|
flex_bot.cz = args.cz;
|
|
#+end_src
|
|
|
|
** =initializeTopFlexibleJoint= - Initialize Flexible Joint
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/src/initializeTopFlexibleJoint.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:initializeTopFlexibleJoint>>
|
|
|
|
*** Function description
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
function [flex_top] = initializeTopFlexibleJoint(args)
|
|
% initializeTopFlexibleJoint -
|
|
%
|
|
% Syntax: [flex_top] = initializeTopFlexibleJoint(args)
|
|
%
|
|
% Inputs:
|
|
% - args -
|
|
%
|
|
% Outputs:
|
|
% - flex_top -
|
|
#+end_src
|
|
|
|
*** Optional Parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
args.type char {mustBeMember(args.type,{'2dof', '3dof', '4dof'})} = '2dof'
|
|
|
|
args.kRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
|
|
args.kRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
|
|
args.kRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*260
|
|
args.kz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*1e8
|
|
|
|
args.cRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.1
|
|
args.cRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.1
|
|
args.cRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.1
|
|
args.cz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*1e2
|
|
end
|
|
#+end_src
|
|
|
|
*** Initialize the structure
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
flex_top = struct();
|
|
#+end_src
|
|
|
|
*** Set the Joint's type
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
switch args.type
|
|
case '2dof'
|
|
flex_top.type = 1;
|
|
case '3dof'
|
|
flex_top.type = 2;
|
|
case '4dof'
|
|
flex_top.type = 3;
|
|
end
|
|
#+end_src
|
|
|
|
*** Set parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
flex_top.kRx = args.kRx;
|
|
flex_top.kRy = args.kRy;
|
|
flex_top.kRz = args.kRz;
|
|
flex_top.kz = args.kz;
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
flex_top.cRx = args.cRx;
|
|
flex_top.cRy = args.cRy;
|
|
flex_top.cRz = args.cRz;
|
|
flex_top.cz = args.cz;
|
|
#+end_src
|
|
|
|
** =initializeAPA= - Initialize APA
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle matlab/src/initializeAPA.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:initializeAPA>>
|
|
|
|
*** Function description
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
function [actuator] = initializeAPA(args)
|
|
% initializeAPA -
|
|
%
|
|
% Syntax: [actuator] = initializeAPA(args)
|
|
%
|
|
% Inputs:
|
|
% - args -
|
|
%
|
|
% Outputs:
|
|
% - actuator -
|
|
#+end_src
|
|
|
|
*** Optional Parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
args.type char {mustBeMember(args.type,{'2dof', 'flexible frame', 'flexible'})} = '2dof'
|
|
|
|
args.Ga (1,1) double {mustBeNumeric} = 0
|
|
args.Gs (1,1) double {mustBeNumeric} = 0
|
|
|
|
% For 2DoF
|
|
args.k (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.38e6
|
|
args.ke (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*1.75e6
|
|
args.ka (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*3e7
|
|
|
|
args.c (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*3e1
|
|
args.ce (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*2e1
|
|
args.ca (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*2e1
|
|
|
|
args.Leq (6,1) double {mustBeNumeric} = ones(6,1)*0.056
|
|
|
|
% Force Flexible APA
|
|
args.xi (1,1) double {mustBeNumeric, mustBePositive} = 0.5
|
|
|
|
% For Flexible Frame
|
|
args.ks (1,1) double {mustBeNumeric, mustBePositive} = 235e6
|
|
args.cs (1,1) double {mustBeNumeric, mustBePositive} = 1e1
|
|
end
|
|
#+end_src
|
|
|
|
*** Initialize Structure
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
actuator = struct();
|
|
#+end_src
|
|
|
|
*** Type
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
switch args.type
|
|
case '2dof'
|
|
actuator.type = 1;
|
|
case 'flexible frame'
|
|
actuator.type = 2;
|
|
case 'flexible'
|
|
actuator.type = 3;
|
|
end
|
|
#+end_src
|
|
|
|
*** Actuator/Sensor Constants
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
if args.Ga == 0
|
|
switch args.type
|
|
case '2dof'
|
|
actuator.Ga = -30.0;
|
|
case 'flexible frame'
|
|
actuator.Ga = 1; % TODO
|
|
case 'flexible'
|
|
actuator.Ga = 23.4;
|
|
end
|
|
else
|
|
actuator.Ga = args.Ga; % Actuator gain [N/V]
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
if args.Gs == 0
|
|
switch args.type
|
|
case '2dof'
|
|
actuator.Gs = 0.098;
|
|
case 'flexible frame'
|
|
actuator.Gs = 1; % TODO
|
|
case 'flexible'
|
|
actuator.Gs = -4674824;
|
|
end
|
|
else
|
|
actuator.Gs = args.Gs; % Sensor gain [V/m]
|
|
end
|
|
#+end_src
|
|
|
|
*** 2DoF parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
actuator.k = args.k; % [N/m]
|
|
actuator.ke = args.ke; % [N/m]
|
|
actuator.ka = args.ka; % [N/m]
|
|
|
|
actuator.c = args.c; % [N/(m/s)]
|
|
actuator.ce = args.ce; % [N/(m/s)]
|
|
actuator.ca = args.ca; % [N/(m/s)]
|
|
|
|
actuator.Leq = args.Leq; % [m]
|
|
#+end_src
|
|
|
|
*** Flexible frame and fully flexible
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
switch args.type
|
|
case 'flexible frame'
|
|
actuator.K = readmatrix('APA300ML_b_mat_K.CSV'); % Stiffness Matrix
|
|
actuator.M = readmatrix('APA300ML_b_mat_M.CSV'); % Mass Matrix
|
|
actuator.P = extractNodes('APA300ML_b_out_nodes_3D.txt'); % Node coordinates [m]
|
|
case 'flexible'
|
|
actuator.K = readmatrix('full_APA300ML_K.CSV'); % Stiffness Matrix
|
|
actuator.M = readmatrix('full_APA300ML_M.CSV'); % Mass Matrix
|
|
actuator.P = extractNodes('full_APA300ML_out_nodes_3D.txt'); % Node coordiantes [m]
|
|
end
|
|
|
|
actuator.xi = args.xi; % Damping ratio
|
|
|
|
actuator.ks = args.ks; % Stiffness of one stack [N/m]
|
|
actuator.cs = args.cs; % Damping of one stack [N/m]
|
|
#+end_src
|
|
|
|
** =generateSweepExc=: Generate sweep sinus excitation
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle ./matlab/src/generateSweepExc.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:generateSweepExc>>
|
|
|
|
*** Function description
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
function [U_exc] = generateSweepExc(args)
|
|
% generateSweepExc - Generate a Sweep Sine excitation signal
|
|
%
|
|
% Syntax: [U_exc] = generateSweepExc(args)
|
|
%
|
|
% Inputs:
|
|
% - args - Optinal arguments:
|
|
% - Ts - Sampling Time - [s]
|
|
% - f_start - Start frequency of the sweep - [Hz]
|
|
% - f_end - End frequency of the sweep - [Hz]
|
|
% - V_mean - Mean value of the excitation voltage - [V]
|
|
% - V_exc - Excitation Amplitude for the Sweep, could be numeric or TF - [V]
|
|
% - t_start - Time at which the sweep begins - [s]
|
|
% - exc_duration - Duration of the sweep - [s]
|
|
% - sweep_type - 'logarithmic' or 'linear' - [-]
|
|
% - smooth_ends - 'true' or 'false': smooth transition between 0 and V_mean - [-]
|
|
#+end_src
|
|
|
|
*** Optional Parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-4
|
|
args.f_start (1,1) double {mustBeNumeric, mustBePositive} = 1
|
|
args.f_end (1,1) double {mustBeNumeric, mustBePositive} = 1e3
|
|
args.V_mean (1,1) double {mustBeNumeric} = 0
|
|
args.V_exc = 1
|
|
args.t_start (1,1) double {mustBeNumeric, mustBeNonnegative} = 5
|
|
args.exc_duration (1,1) double {mustBeNumeric, mustBePositive} = 10
|
|
args.sweep_type char {mustBeMember(args.sweep_type,{'log', 'lin'})} = 'lin'
|
|
args.smooth_ends logical {mustBeNumericOrLogical} = true
|
|
end
|
|
#+end_src
|
|
|
|
*** Sweep Sine part
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
t_sweep = 0:args.Ts:args.exc_duration;
|
|
|
|
if strcmp(args.sweep_type, 'log')
|
|
V_exc = sin(2*pi*args.f_start * args.exc_duration/log(args.f_end/args.f_start) * (exp(log(args.f_end/args.f_start)*t_sweep/args.exc_duration) - 1));
|
|
elseif strcmp(args.sweep_type, 'lin')
|
|
V_exc = sin(2*pi*(args.f_start + (args.f_end - args.f_start)/2/args.exc_duration*t_sweep).*t_sweep);
|
|
else
|
|
error('sweep_type should either be equal to "log" or to "lin"');
|
|
end
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
if isnumeric(args.V_exc)
|
|
V_sweep = args.V_mean + args.V_exc*V_exc;
|
|
elseif isct(args.V_exc)
|
|
if strcmp(args.sweep_type, 'log')
|
|
V_sweep = args.V_mean + abs(squeeze(freqresp(args.V_exc, args.f_start*(args.f_end/args.f_start).^(t_sweep/args.exc_duration), 'Hz')))'.*V_exc;
|
|
elseif strcmp(args.sweep_type, 'lin')
|
|
V_sweep = args.V_mean + abs(squeeze(freqresp(args.V_exc, args.f_start+(args.f_end-args.f_start)/args.exc_duration*t_sweep, 'Hz')))'.*V_exc;
|
|
end
|
|
end
|
|
#+end_src
|
|
|
|
*** Smooth Ends
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
if args.t_start > 0
|
|
t_smooth_start = args.Ts:args.Ts:args.t_start;
|
|
|
|
V_smooth_start = zeros(size(t_smooth_start));
|
|
V_smooth_end = zeros(size(t_smooth_start));
|
|
|
|
if args.smooth_ends
|
|
Vd_max = args.V_mean/(0.7*args.t_start);
|
|
|
|
V_d = zeros(size(t_smooth_start));
|
|
V_d(t_smooth_start < 0.2*args.t_start) = t_smooth_start(t_smooth_start < 0.2*args.t_start)*Vd_max/(0.2*args.t_start);
|
|
V_d(t_smooth_start > 0.2*args.t_start & t_smooth_start < 0.7*args.t_start) = Vd_max;
|
|
V_d(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) = Vd_max - (t_smooth_start(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) - 0.7*args.t_start)*Vd_max/(0.2*args.t_start);
|
|
|
|
V_smooth_start = cumtrapz(V_d)*args.Ts;
|
|
|
|
V_smooth_end = args.V_mean - V_smooth_start;
|
|
end
|
|
else
|
|
V_smooth_start = [];
|
|
V_smooth_end = [];
|
|
end
|
|
#+end_src
|
|
|
|
*** Combine Excitation signals
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
V_exc = [V_smooth_start, V_sweep, V_smooth_end];
|
|
t_exc = args.Ts*[0:1:length(V_exc)-1];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
U_exc = [t_exc; V_exc];
|
|
#+end_src
|
|
|
|
** =generateShapedNoise=: Generate Shaped Noise excitation
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle ./matlab/src/generateShapedNoise.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:generateShapedNoise>>
|
|
|
|
*** Function description
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
function [U_exc] = generateShapedNoise(args)
|
|
% generateShapedNoise - Generate a Shaped Noise excitation signal
|
|
%
|
|
% Syntax: [U_exc] = generateShapedNoise(args)
|
|
%
|
|
% Inputs:
|
|
% - args - Optinal arguments:
|
|
% - Ts - Sampling Time - [s]
|
|
% - V_mean - Mean value of the excitation voltage - [V]
|
|
% - V_exc - Excitation Amplitude, could be numeric or TF - [V rms]
|
|
% - t_start - Time at which the noise begins - [s]
|
|
% - exc_duration - Duration of the noise - [s]
|
|
% - smooth_ends - 'true' or 'false': smooth transition between 0 and V_mean - [-]
|
|
#+end_src
|
|
|
|
*** Optional Parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-4
|
|
args.V_mean (1,1) double {mustBeNumeric} = 0
|
|
args.V_exc = 1
|
|
args.t_start (1,1) double {mustBeNumeric, mustBePositive} = 5
|
|
args.exc_duration (1,1) double {mustBeNumeric, mustBePositive} = 10
|
|
args.smooth_ends logical {mustBeNumericOrLogical} = true
|
|
end
|
|
#+end_src
|
|
|
|
*** Shaped Noise
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
t_noise = 0:args.Ts:args.exc_duration;
|
|
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
if isnumeric(args.V_exc)
|
|
V_noise = args.V_mean + args.V_exc*sqrt(1/args.Ts/2)*randn(length(t_noise), 1)';
|
|
elseif isct(args.V_exc)
|
|
V_noise = args.V_mean + lsim(args.V_exc, sqrt(1/args.Ts/2)*randn(length(t_noise), 1), t_noise)';
|
|
end
|
|
#+end_src
|
|
|
|
*** Smooth Ends
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
t_smooth_start = args.Ts:args.Ts:args.t_start;
|
|
|
|
V_smooth_start = zeros(size(t_smooth_start));
|
|
V_smooth_end = zeros(size(t_smooth_start));
|
|
|
|
if args.smooth_ends
|
|
Vd_max = args.V_mean/(0.7*args.t_start);
|
|
|
|
V_d = zeros(size(t_smooth_start));
|
|
V_d(t_smooth_start < 0.2*args.t_start) = t_smooth_start(t_smooth_start < 0.2*args.t_start)*Vd_max/(0.2*args.t_start);
|
|
V_d(t_smooth_start > 0.2*args.t_start & t_smooth_start < 0.7*args.t_start) = Vd_max;
|
|
V_d(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) = Vd_max - (t_smooth_start(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) - 0.7*args.t_start)*Vd_max/(0.2*args.t_start);
|
|
|
|
V_smooth_start = cumtrapz(V_d)*args.Ts;
|
|
|
|
V_smooth_end = args.V_mean - V_smooth_start;
|
|
end
|
|
#+end_src
|
|
|
|
*** Combine Excitation signals
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
V_exc = [V_smooth_start, V_noise, V_smooth_end];
|
|
t_exc = args.Ts*[0:1:length(V_exc)-1];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
U_exc = [t_exc; V_exc];
|
|
#+end_src
|
|
|
|
** =generateSinIncreasingAmpl=: Generate Sinus with increasing amplitude
|
|
:PROPERTIES:
|
|
:header-args:matlab+: :tangle ./matlab/src/generateSinIncreasingAmpl.m
|
|
:header-args:matlab+: :comments none :mkdirp yes :eval no
|
|
:END:
|
|
<<sec:generateSinIncreasingAmpl>>
|
|
|
|
*** Function description
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
function [U_exc] = generateSinIncreasingAmpl(args)
|
|
% generateSinIncreasingAmpl - Generate Sinus with increasing amplitude
|
|
%
|
|
% Syntax: [U_exc] = generateSinIncreasingAmpl(args)
|
|
%
|
|
% Inputs:
|
|
% - args - Optinal arguments:
|
|
% - Ts - Sampling Time - [s]
|
|
% - V_mean - Mean value of the excitation voltage - [V]
|
|
% - sin_ampls - Excitation Amplitudes - [V]
|
|
% - sin_freq - Excitation Frequency - [Hz]
|
|
% - sin_num - Number of period for each amplitude - [-]
|
|
% - t_start - Time at which the excitation begins - [s]
|
|
% - smooth_ends - 'true' or 'false': smooth transition between 0 and V_mean - [-]
|
|
#+end_src
|
|
|
|
*** Optional Parameters
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
arguments
|
|
args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-4
|
|
args.V_mean (1,1) double {mustBeNumeric} = 0
|
|
args.sin_ampls double {mustBeNumeric, mustBePositive} = [0.1, 0.2, 0.3]
|
|
args.sin_period (1,1) double {mustBeNumeric, mustBePositive} = 1
|
|
args.sin_num (1,1) double {mustBeNumeric, mustBePositive, mustBeInteger} = 3
|
|
args.t_start (1,1) double {mustBeNumeric, mustBePositive} = 5
|
|
args.smooth_ends logical {mustBeNumericOrLogical} = true
|
|
end
|
|
#+end_src
|
|
|
|
*** Sinus excitation
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
t_noise = 0:args.Ts:args.sin_period*args.sin_num;
|
|
sin_exc = [];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
for sin_ampl = args.sin_ampls
|
|
sin_exc = [sin_exc, args.V_mean + sin_ampl*sin(2*pi/args.sin_period*t_noise)];
|
|
end
|
|
#+end_src
|
|
|
|
*** Smooth Ends
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
t_smooth_start = args.Ts:args.Ts:args.t_start;
|
|
|
|
V_smooth_start = zeros(size(t_smooth_start));
|
|
V_smooth_end = zeros(size(t_smooth_start));
|
|
|
|
if args.smooth_ends
|
|
Vd_max = args.V_mean/(0.7*args.t_start);
|
|
|
|
V_d = zeros(size(t_smooth_start));
|
|
V_d(t_smooth_start < 0.2*args.t_start) = t_smooth_start(t_smooth_start < 0.2*args.t_start)*Vd_max/(0.2*args.t_start);
|
|
V_d(t_smooth_start > 0.2*args.t_start & t_smooth_start < 0.7*args.t_start) = Vd_max;
|
|
V_d(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) = Vd_max - (t_smooth_start(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) - 0.7*args.t_start)*Vd_max/(0.2*args.t_start);
|
|
|
|
V_smooth_start = cumtrapz(V_d)*args.Ts;
|
|
|
|
V_smooth_end = args.V_mean - V_smooth_start;
|
|
end
|
|
#+end_src
|
|
|
|
*** Combine Excitation signals
|
|
:PROPERTIES:
|
|
:UNNUMBERED: t
|
|
:END:
|
|
|
|
#+begin_src matlab
|
|
V_exc = [V_smooth_start, sin_exc, V_smooth_end];
|
|
t_exc = args.Ts*[0:1:length(V_exc)-1];
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
U_exc = [t_exc; V_exc];
|
|
#+end_src
|
|
|
|
* Bibliography :ignore:
|
|
#+latex: \printbibliography
|