3535 lines
111 KiB
Org Mode
3535 lines
111 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
|
|
|
|
* 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]]
|
|
|
|
* 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 :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
|
|
|
|
#+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
|
|
|
|
* Stroke measurement
|
|
** 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 :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 |
|
|
|
|
* TODO Stiffness measurement
|
|
** 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/mat/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
#+end_src
|
|
|
|
** APA test
|
|
#+begin_src matlab
|
|
load('meas_stiff_apa_1_x.mat', 't', 'F', 'd');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
plot(t, F)
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Automatic Zero of the force
|
|
F = F - mean(F(t > 0.1 & t < 0.3));
|
|
|
|
%% Start measurement at t = 0.2 s
|
|
d = d(t > 0.2);
|
|
F = F(t > 0.2);
|
|
t = t(t > 0.2); t = t - t(1);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
i_l_start = find(F > 0.3, 1, 'first');
|
|
[~, i_l_stop] = max(F);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
F_l = F(i_l_start:i_l_stop);
|
|
d_l = d(i_l_start:i_l_stop);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
fit_l = polyfit(F_l, d_l, 1);
|
|
|
|
% %% Reset displacement based on fit
|
|
% d = d - fit_l(2);
|
|
% fit_s(2) = fit_s(2) - fit_l(2);
|
|
% fit_l(2) = 0;
|
|
|
|
% %% Estimated Stroke
|
|
% F_max = fit_s(2)/(fit_l(1) - fit_s(1));
|
|
% d_max = fit_l(1)*F_max;
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
h^2/fit_l(1)
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
figure;
|
|
hold on;
|
|
plot(F,d,'k')
|
|
plot(F_l, d_l)
|
|
plot(F_l, F_l*fit_l(1) + fit_l(2), '--')
|
|
#+end_src
|
|
* Test-Bench Description
|
|
|
|
#+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
|
|
|
|
#+name: fig:test_bench_apa_alone
|
|
#+caption: Schematic of the Test Bench
|
|
[[file:figs/test_bench_apa_alone.png]]
|
|
|
|
* Measurement Procedure
|
|
<<sec:measurement_procedure>>
|
|
** Introduction :ignore:
|
|
|
|
** Stroke Measurement
|
|
|
|
Using the PD200 amplifier, output a voltage:
|
|
\[ V_a = 65 + 85 \sin(2\pi \cdot t) \]
|
|
To have a quasi-static excitation between -20 and 150V.
|
|
|
|
As the gain of the PD200 amplifier is 20, the DAC output voltage should be:
|
|
\[ V_{dac}(t) = 3.25 + 4.25\sin(2\pi \cdot t) \]
|
|
|
|
Verify that the voltage offset of the PD200 is zero!
|
|
|
|
Measure the output vertical displacement $d$ using the interferometer.
|
|
|
|
Then, plot $d$ as a function of $V_a$, and perform a linear regression.
|
|
Conclude on the obtained stroke.
|
|
|
|
** Stiffness Measurement
|
|
|
|
Add some (known) weight $\delta m g$ on the suspended mass and measure the deflection $\delta d$.
|
|
This can be tested when the piezoelectric stacks are open-circuit.
|
|
|
|
As the stiffness will be around $k \approx 10^6 N/m$, an added mass of $m \approx 100g$ will induce a static deflection of $\approx 1\mu m$ which should be large enough for a precise measurement using the interferometer.
|
|
|
|
Then the obtained stiffness is:
|
|
\begin{equation}
|
|
k = \frac{\delta m g}{\delta d}
|
|
\end{equation}
|
|
|
|
** Hysteresis measurement
|
|
|
|
Supply a quasi static sinusoidal excitation $V_a$ at different voltages.
|
|
|
|
The offset should be 65V, and the sin amplitude can range from 1V up to 85V.
|
|
|
|
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.
|
|
|
|
#+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]]
|
|
|
|
** 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$.
|
|
Use a quasi static (1Hz) excitation signal $V_a$ on the piezoelectric stack and measure the vertical displacement $d$.
|
|
Perform a linear regression to obtain:
|
|
\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
|
|
|
|
From a quasi static excitation of the piezoelectric stack, measure the gain from $V_a$ to $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 excitation frequency should then be in between the cut-off frequency of this high pass filter and the first resonance.
|
|
|
|
Alternatively, the gain can be computed from the dynamical identification and taking the gain at the wanted frequency.
|
|
|
|
Using the simscape model, compute the static gain 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 static gain from the sensor stack strain $dl$ to the general voltage $V_s$ 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}
|
|
|
|
Alternatively, we could impose an external force to add strain in the APA that should be equally present in all the 3 stacks and equal to 1/5 of the vertical strain.
|
|
This external force can be some weight added, or a piezo in parallel.
|
|
|
|
** Capacitance Measurement
|
|
|
|
Measure the capacitance of the 3 stacks individually using a precise multi-meter.
|
|
|
|
** Dynamical Behavior
|
|
|
|
Perform a system identification from $V_a$ to the measured displacement $d$ by the interferometer and by the encoder, and to the generated voltage $V_s$.
|
|
|
|
This can be performed using different excitation signals.
|
|
|
|
This can also be performed with and without the encoder fixed to the APA.
|
|
|
|
** Compare the results obtained for all 7 APA300ML
|
|
|
|
Compare all the obtained parameters for all the test APA.
|
|
|
|
* FRF measurement
|
|
** Introduction :ignore:
|
|
|
|
- [ ] Schematic of the measurement
|
|
|
|
| Variable | | 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] | |
|
|
|
|
** 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/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
|
|
|
|
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', 1e3, ...
|
|
'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]]
|
|
|
|
|
|
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]]
|
|
|
|
#+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', 10, ...
|
|
'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
|
|
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
|
|
: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
|
|
*** Introduction :ignore:
|
|
Measurements are first performed on the APA number 1.
|
|
|
|
*** 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/mat/');
|
|
addpath('./matlab/src/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./mat/');
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
*** Huddle Test
|
|
#+begin_src matlab
|
|
load(sprintf('frf_data_%i_huddle.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(t, da, 'DisplayName', '$d_a$ - Attocube')
|
|
plot(t, de, 'DisplayName', '$d_e$ - Encoder')
|
|
hold off;
|
|
xlabel('Time [s]');
|
|
ylabel('Displacement [m]');
|
|
legend('location', 'northeast')
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(t, Vs, 'DisplayName', '$V_s$ - Force Sensor')
|
|
hold off;
|
|
xlabel('Time [s]');
|
|
ylabel('Voltage [V]');
|
|
legend('location', 'northeast')
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
%% Parameter for Spectral analysis
|
|
Ts = (t(end) - t(1))/(length(t)-1);
|
|
Fs = 1/Ts;
|
|
|
|
win = hanning(ceil(10*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
[phh_da, f] = pwelch(da - mean(da), win, [], [], 1/Ts);
|
|
[phh_de, ~] = pwelch(de - mean(de), win, [], [], 1/Ts);
|
|
[phh_Vs, ~] = pwelch(Vs - mean(Vs), win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(f, phh_da, 'DisplayName', '$d_a$ - Attocube')
|
|
plot(f, phh_de, 'DisplayName', '$d_e$ - Encoder')
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('ASD [$m/\sqrt{Hz}$]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
legend('location', 'northeast')
|
|
xlim([5e-1, 5e3]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, phh_Vs, 'DisplayName', '$V_s$ - Force Sensor')
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('ASD [$V/\sqrt{Hz}$]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
legend('location', 'northeast')
|
|
xlim([5e-1, 5e3]);
|
|
#+end_src
|
|
|
|
*** First identification with Noise
|
|
#+begin_src matlab
|
|
load(sprintf('mat/frf_data_%i_noise.mat', 1), 't', 'Va', 'Vs', 'da', 'de')
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
[pxx_da, f] = pwelch(da, win, [], [], 1/Ts);
|
|
[pxx_de, ~] = pwelch(de, win, [], [], 1/Ts);
|
|
[pxx_Vs, ~] = pwelch(Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(f, sqrt(phh_da), 'DisplayName', 'Huddle')
|
|
plot(f, sqrt(pxx_da), 'DisplayName', 'Noise')
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('ASD Attocube [$m/\sqrt{Hz}$]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
legend('location', 'northeast')
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, sqrt(phh_Vs), 'DisplayName', 'Huddle')
|
|
plot(f, sqrt(pxx_Vs), 'DisplayName', 'Noise')
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('ASD [$V/\sqrt{Hz}$]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
legend('location', 'northeast')
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([5e-1, 5e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
[G_dvf, f] = tfestimate(Va, de, win, [], [], 1/Ts);
|
|
[G_d, ~] = tfestimate(Va, da, win, [], [], 1/Ts);
|
|
[G_iff, ~] = tfestimate(Va, Vs, win, [], [], 1/Ts);
|
|
|
|
[coh_dvf, ~] = mscohere(Va, de, win, [], [], 1/Ts);
|
|
[coh_d, ~] = mscohere(Va, da, win, [], [], 1/Ts);
|
|
[coh_iff, ~] = mscohere(Va, Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%%
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_dvf);
|
|
plot(f, coh_d);
|
|
plot(f, coh_iff);
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlim([1, 5e3]); ylim([0, 1]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%%
|
|
figure;
|
|
tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(f, abs(G_d), 'DisplayName', 'Attocube');
|
|
plot(f, abs(G_dvf), 'DisplayName', 'Encoder');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-8, 1e-3]);
|
|
legend('location', 'northeast');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, 180/pi*angle(G_d));
|
|
plot(f, 180/pi*angle(G_dvf));
|
|
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([5e-1, 5e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%%
|
|
figure;
|
|
tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(f, abs(G_iff));
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
plot(f, 180/pi*angle(G_iff));
|
|
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([1, 2e3]);
|
|
#+end_src
|
|
|
|
*** Second identification with Sweep
|
|
#+begin_src matlab
|
|
load(sprintf('mat/frf_data_%i_sweep.mat', 1), 't', 'Va', 'Vs', 'da', 'de')
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
[pxx_da, f] = pwelch(da, win, [], [], 1/Ts);
|
|
[pxx_de, ~] = pwelch(de, win, [], [], 1/Ts);
|
|
[pxx_Vs, ~] = pwelch(Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(1, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(f, sqrt(phh_da), 'DisplayName', 'Huddle')
|
|
plot(f, sqrt(pxx_da), 'DisplayName', 'Noise')
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('ASD Attocube [$m/\sqrt{Hz}$]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
legend('location', 'northeast')
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, sqrt(phh_Vs), 'DisplayName', 'Huddle')
|
|
plot(f, sqrt(pxx_Vs), 'DisplayName', 'Noise')
|
|
hold off;
|
|
xlabel('Time [s]'); ylabel('ASD [$V/\sqrt{Hz}$]');
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
legend('location', 'northeast')
|
|
|
|
linkaxes([ax1,ax2],'x');
|
|
xlim([1e1, 2e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
[G_dvf, f] = tfestimate(Va, de, win, [], [], 1/Ts);
|
|
[G_d, ~] = tfestimate(Va, da, win, [], [], 1/Ts);
|
|
[G_iff, ~] = tfestimate(Va, Vs, win, [], [], 1/Ts);
|
|
|
|
[coh_dvf, ~] = mscohere(Va, de, win, [], [], 1/Ts);
|
|
[coh_d, ~] = mscohere(Va, da, win, [], [], 1/Ts);
|
|
[coh_iff, ~] = mscohere(Va, Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%%
|
|
figure;
|
|
hold on;
|
|
plot(f, coh_dvf);
|
|
plot(f, coh_d);
|
|
plot(f, coh_iff);
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
|
xlim([10, 2e3]); ylim([0, 1]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
%%
|
|
figure;
|
|
tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(f, abs(G_d), 'DisplayName', 'Attocube');
|
|
plot(f, abs(G_dvf), 'DisplayName', 'Encoder');
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $d/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([1e-8, 1e-3]);
|
|
legend('location', 'northeast');
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, 180/pi*angle(G_d));
|
|
plot(f, 180/pi*angle(G_dvf));
|
|
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 :exports none
|
|
%%
|
|
figure;
|
|
tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(f, abs(G_iff));
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
|
|
ax2 = nexttile;
|
|
plot(f, 180/pi*angle(G_iff));
|
|
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
|
|
|
|
*** Extract Parameters
|
|
|
|
Quasi static gain between $d$ and $V_a$:
|
|
#+begin_src matlab
|
|
g_d_Va = mean(abs(G_dvf(f > 10 & f < 15)));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results
|
|
sprintf('g_d_Va = %.1e [m/V]', g_d_Va)
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: g_d_Va = 1.7e-05 [m/V]
|
|
|
|
Quasi static gain between $V_s$ and $V_a$:
|
|
#+begin_src matlab
|
|
g_Vs_Va = mean(abs(G_iff(f > 10 & f < 15)));
|
|
#+end_src
|
|
|
|
#+begin_src matlab :results value replace :exports results
|
|
sprintf('g_Vs_Va = %.1e [V/V]', g_Vs_Va)
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: g_Vs_Va = 5.7e-01 [V/V]
|
|
|
|
** Comparison of all APA
|
|
:PROPERTIES:
|
|
:header-args: :tangle matlab/frf_analyze.m
|
|
:END:
|
|
|
|
*** 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/src/');
|
|
addpath('./matlab/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('./src/');
|
|
#+end_src
|
|
|
|
*** Test with one APA
|
|
#+begin_src matlab
|
|
%% Load measurement data for APA number 1
|
|
load(sprintf('mat/frf_data_%i.mat', 1), 't', 'Va', 'Vs', 'de', 'da');
|
|
#+end_src
|
|
|
|
Time domain data:
|
|
#+begin_src matlab
|
|
figure;
|
|
plot(t, de);
|
|
#+end_src
|
|
|
|
Compute transfer functions:
|
|
#+begin_src matlab
|
|
Ts = (t(end) - t(1))/(length(t)-1);
|
|
Fs = 1/Ts;
|
|
|
|
win = hanning(ceil(0.5*Fs)); % Hannning Windows
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
[G_dvf, f] = tfestimate(Va, de, win, [], [], 1/Ts);
|
|
[G_d, ~] = tfestimate(Va, da, win, [], [], 1/Ts);
|
|
[G_iff, ~] = tfestimate(Va, Vs, win, [], [], 1/Ts);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
hold on;
|
|
plot(f, abs(G_dvf));
|
|
plot(f, abs(G_d));
|
|
hold off;
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_{out}/V_{in}$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([10, 30]);
|
|
|
|
ax2 = nexttile;
|
|
hold on;
|
|
plot(f, 180/pi*angle(G_dvf));
|
|
plot(f, 180/pi*angle(G_d));
|
|
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([5, 5e3]);
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
figure;
|
|
tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile;
|
|
plot(f, abs(G_iff));
|
|
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
|
ylabel('Amplitude $V_{out}/V_{in}$ [V/V]'); set(gca, 'XTickLabel',[]);
|
|
hold off;
|
|
ylim([10, 30]);
|
|
|
|
ax2 = nexttile;
|
|
plot(f, 180/pi*angle(G_iff));
|
|
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([5, 5e3]);
|
|
#+end_src
|
|
|
|
*** Comparison of all APA
|
|
#+begin_src matlab :exports none
|
|
%% Load all the measurements
|
|
meas_data = {};
|
|
for i = 1:7
|
|
meas_data(i) = {load(sprintf('mat/frf_data_%i.mat', i), 't', 'Va', 'Vs', 'de', 'da')};
|
|
end
|
|
#+end_src
|
|
|
|
* Measurement Results
|
|
|
|
* 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
|
|
** 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/test_bench_apa300ml/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('test_bench_apa300ml/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
open('test_bench_apa300ml.slx')
|
|
#+end_src
|
|
|
|
** Nano Hexapod object
|
|
#+begin_src matlab
|
|
n_hexapod = struct();
|
|
#+end_src
|
|
|
|
*** APA - 2 DoF
|
|
#+begin_src matlab
|
|
n_hexapod.actuator = struct();
|
|
|
|
n_hexapod.actuator.type = 1;
|
|
|
|
n_hexapod.actuator.k = ones(6,1)*0.35e6; % [N/m]
|
|
n_hexapod.actuator.ke = ones(6,1)*1.5e6; % [N/m]
|
|
n_hexapod.actuator.ka = ones(6,1)*43e6; % [N/m]
|
|
|
|
n_hexapod.actuator.c = ones(6,1)*3e1; % [N/(m/s)]
|
|
n_hexapod.actuator.ce = ones(6,1)*1e1; % [N/(m/s)]
|
|
n_hexapod.actuator.ca = ones(6,1)*1e1; % [N/(m/s)]
|
|
|
|
n_hexapod.actuator.Leq = ones(6,1)*0.056; % [m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*1; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*1; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
*** APA - Flexible Frame
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.type = 2;
|
|
|
|
n_hexapod.actuator.K = readmatrix('APA300ML_b_mat_K.CSV'); % Stiffness Matrix
|
|
n_hexapod.actuator.M = readmatrix('APA300ML_b_mat_M.CSV'); % Mass Matrix
|
|
n_hexapod.actuator.xi = 0.01; % Damping ratio
|
|
n_hexapod.actuator.P = extractNodes('APA300ML_b_out_nodes_3D.txt'); % Node coordinates [m]
|
|
|
|
n_hexapod.actuator.ks = 235e6; % Stiffness of one stack [N/m]
|
|
n_hexapod.actuator.cs = 1e1; % Stiffness of one stack [N/m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*1; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*1; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
*** APA - Fully Flexible
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.type = 3;
|
|
|
|
n_hexapod.actuator.K = readmatrix('APA300ML_full_mat_K.CSV'); % Stiffness Matrix
|
|
n_hexapod.actuator.M = readmatrix('APA300ML_full_mat_M.CSV'); % Mass Matrix
|
|
n_hexapod.actuator.xi = 0.01; % Damping ratio
|
|
n_hexapod.actuator.P = extractNodes('APA300ML_full_out_nodes_3D.txt'); % Node coordiantes [m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*1; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*1; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
** Identification
|
|
#+begin_src matlab
|
|
%% Options for Linearized
|
|
options = linearizeOptions;
|
|
options.SampleTime = 0;
|
|
|
|
%% Name of the Simulink File
|
|
mdl = 'test_bench_apa300ml';
|
|
|
|
%% 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
|
|
|
|
#+begin_src matlab :exports none
|
|
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'))), 'DisplayName', '')
|
|
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('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 :exports none
|
|
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
|
|
|
|
** Compare 2-DoF with flexible
|
|
*** APA - 2 DoF
|
|
#+begin_src matlab
|
|
n_hexapod = struct();
|
|
|
|
n_hexapod.actuator = struct();
|
|
|
|
n_hexapod.actuator.type = 1;
|
|
|
|
n_hexapod.actuator.k = ones(6,1)*0.35e6; % [N/m]
|
|
n_hexapod.actuator.ke = ones(6,1)*1.5e6; % [N/m]
|
|
n_hexapod.actuator.ka = ones(6,1)*43e6; % [N/m]
|
|
|
|
n_hexapod.actuator.c = ones(6,1)*3e1; % [N/(m/s)]
|
|
n_hexapod.actuator.ce = ones(6,1)*1e1; % [N/(m/s)]
|
|
n_hexapod.actuator.ca = ones(6,1)*1e1; % [N/(m/s)]
|
|
|
|
n_hexapod.actuator.Leq = ones(6,1)*0.056; % [m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*-2.15; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*2.305e-08; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
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 = struct();
|
|
|
|
n_hexapod.actuator.type = 3;
|
|
|
|
n_hexapod.actuator.K = readmatrix('APA300ML_full_mat_K.CSV'); % Stiffness Matrix
|
|
n_hexapod.actuator.M = readmatrix('APA300ML_full_mat_M.CSV'); % Mass Matrix
|
|
n_hexapod.actuator.xi = 0.01; % Damping ratio
|
|
n_hexapod.actuator.P = extractNodes('APA300ML_full_out_nodes_3D.txt'); % Node coordiantes [m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*1; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*1; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
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', '$G_a$')
|
|
plot(freqs, abs(squeeze(freqresp(G_flex('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', '$G_s$')
|
|
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(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 :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', '$G_a$')
|
|
plot(freqs, abs(squeeze(freqresp(G_flex('dL', 'Va'), freqs, 'Hz'))), 'DisplayName', '$G_s$')
|
|
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 :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', '$G_a$')
|
|
plot(freqs, abs(squeeze(freqresp(G_flex('z', 'Va'), freqs, 'Hz'))), 'DisplayName', '$G_s$')
|
|
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
|
|
|
|
* 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
|
|
addpath('matlab/');
|
|
addpath('matlab/test_bench_struts/');
|
|
addpath('matlab/png/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab :eval no
|
|
addpath('test_bench_struts/');
|
|
addpath('png/');
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
open('test_bench_struts.slx')
|
|
#+end_src
|
|
|
|
** Nano Hexapod object
|
|
#+begin_src matlab
|
|
n_hexapod = struct();
|
|
#+end_src
|
|
|
|
*** Flexible Joint - Bot
|
|
#+begin_src matlab
|
|
n_hexapod.flex_bot = struct();
|
|
|
|
n_hexapod.flex_bot.type = 1; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
|
|
n_hexapod.flex_bot.kRx = ones(6,1)*5; % X bending stiffness [Nm/rad]
|
|
n_hexapod.flex_bot.kRy = ones(6,1)*5; % Y bending stiffness [Nm/rad]
|
|
n_hexapod.flex_bot.kRz = ones(6,1)*260; % Torsionnal stiffness [Nm/rad]
|
|
n_hexapod.flex_bot.kz = ones(6,1)*1e8; % Axial stiffness [N/m]
|
|
|
|
n_hexapod.flex_bot.cRx = ones(6,1)*0.1; % [Nm/(rad/s)]
|
|
n_hexapod.flex_bot.cRy = ones(6,1)*0.1; % [Nm/(rad/s)]
|
|
n_hexapod.flex_bot.cRz = ones(6,1)*0.1; % [Nm/(rad/s)]
|
|
n_hexapod.flex_bot.cz = ones(6,1)*1e2; %[N/(m/s)]
|
|
#+end_src
|
|
|
|
*** Flexible Joint - Top
|
|
#+begin_src matlab
|
|
n_hexapod.flex_top = struct();
|
|
|
|
n_hexapod.flex_top.type = 2; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
|
|
n_hexapod.flex_top.kRx = ones(6,1)*5; % X bending stiffness [Nm/rad]
|
|
n_hexapod.flex_top.kRy = ones(6,1)*5; % Y bending stiffness [Nm/rad]
|
|
n_hexapod.flex_top.kRz = ones(6,1)*260; % Torsionnal stiffness [Nm/rad]
|
|
n_hexapod.flex_top.kz = ones(6,1)*1e8; % Axial stiffness [N/m]
|
|
|
|
n_hexapod.flex_top.cRx = ones(6,1)*0.1; % [Nm/(rad/s)]
|
|
n_hexapod.flex_top.cRy = ones(6,1)*0.1; % [Nm/(rad/s)]
|
|
n_hexapod.flex_top.cRz = ones(6,1)*0.1; % [Nm/(rad/s)]
|
|
n_hexapod.flex_top.cz = ones(6,1)*1e2; %[N/(m/s)]
|
|
#+end_src
|
|
|
|
*** APA - 2 DoF
|
|
#+begin_src matlab
|
|
n_hexapod.actuator = struct();
|
|
|
|
n_hexapod.actuator.type = 1;
|
|
|
|
n_hexapod.actuator.k = ones(6,1)*0.35e6; % [N/m]
|
|
n_hexapod.actuator.ke = ones(6,1)*1.5e6; % [N/m]
|
|
n_hexapod.actuator.ka = ones(6,1)*43e6; % [N/m]
|
|
|
|
n_hexapod.actuator.c = ones(6,1)*3e1; % [N/(m/s)]
|
|
n_hexapod.actuator.ce = ones(6,1)*1e1; % [N/(m/s)]
|
|
n_hexapod.actuator.ca = ones(6,1)*1e1; % [N/(m/s)]
|
|
|
|
n_hexapod.actuator.Leq = ones(6,1)*0.056; % [m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*1; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*1; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
*** APA - Flexible Frame
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.type = 2;
|
|
|
|
n_hexapod.actuator.K = readmatrix('APA300ML_b_mat_K.CSV'); % Stiffness Matrix
|
|
n_hexapod.actuator.M = readmatrix('APA300ML_b_mat_M.CSV'); % Mass Matrix
|
|
n_hexapod.actuator.xi = 0.01; % Damping ratio
|
|
n_hexapod.actuator.P = extractNodes('APA300ML_b_out_nodes_3D.txt'); % Node coordinates [m]
|
|
|
|
n_hexapod.actuator.ks = 235e6; % Stiffness of one stack [N/m]
|
|
n_hexapod.actuator.cs = 1e1; % Stiffness of one stack [N/m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*1; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*1; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
*** APA - Fully Flexible
|
|
#+begin_src matlab
|
|
n_hexapod.actuator.type = 3;
|
|
|
|
n_hexapod.actuator.K = readmatrix('APA300ML_full_mat_K.CSV'); % Stiffness Matrix
|
|
n_hexapod.actuator.M = readmatrix('APA300ML_full_mat_M.CSV'); % Mass Matrix
|
|
n_hexapod.actuator.xi = 0.01; % Damping ratio
|
|
n_hexapod.actuator.P = extractNodes('APA300ML_full_out_nodes_3D.txt'); % Node coordiantes [m]
|
|
|
|
n_hexapod.actuator.Ga = ones(6,1)*1; % Actuator gain [N/V]
|
|
n_hexapod.actuator.Gs = ones(6,1)*1; % Sensor gain [V/m]
|
|
#+end_src
|
|
|
|
|
|
** Identification
|
|
#+begin_src matlab
|
|
%% Options for Linearized
|
|
options = linearizeOptions;
|
|
options.SampleTime = 0;
|
|
|
|
%% Name of the Simulink File
|
|
mdl = 'test_bench_struts';
|
|
|
|
%% 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
|
|
Gs = linearize(mdl, io, 0.0, options);
|
|
Gs.InputName = {'Va'};
|
|
Gs.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
#+begin_src matlab :exports none
|
|
freqs = logspace(1, 3, 1000);
|
|
|
|
figure;
|
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
|
|
|
ax1 = nexttile([2,1]);
|
|
hold on;
|
|
plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), 'DisplayName', '')
|
|
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('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 :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(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
|
|
|
|
** Compare flexible joints
|
|
*** Perfect
|
|
#+begin_src matlab
|
|
n_hexapod.flex_bot.type = 1; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
n_hexapod.flex_top.type = 2; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
Gp = linearize(mdl, io, 0.0, options);
|
|
Gp.InputName = {'Va'};
|
|
Gp.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
*** Top Flexible
|
|
#+begin_src matlab
|
|
n_hexapod.flex_bot.type = 1; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
n_hexapod.flex_top.type = 3; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
Gt = linearize(mdl, io, 0.0, options);
|
|
Gt.InputName = {'Va'};
|
|
Gt.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
*** Bottom Flexible
|
|
#+begin_src matlab
|
|
n_hexapod.flex_bot.type = 3; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
n_hexapod.flex_top.type = 2; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
Gb = linearize(mdl, io, 0.0, options);
|
|
Gb.InputName = {'Va'};
|
|
Gb.OutputName = {'Vs', 'dL', 'z'};
|
|
#+end_src
|
|
|
|
*** Both Flexible
|
|
#+begin_src matlab
|
|
n_hexapod.flex_bot.type = 3; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
n_hexapod.flex_top.type = 3; % 1: 2dof / 2: 3dof / 3: 4dof
|
|
#+end_src
|
|
|
|
#+begin_src matlab
|
|
Gf = linearize(mdl, io, 0.0, options);
|
|
Gf.InputName = {'Va'};
|
|
Gf.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(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', 'southwest');
|
|
|
|
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 :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(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 :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(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
|
|
|
|
* Resonance frequencies - APA300ML
|
|
** Introduction
|
|
|
|
Three main resonances are foreseen to be problematic for the control of the APA300ML:
|
|
- Mode in X-bending at 189Hz (Figure [[fig:mode_bending_x]])
|
|
- Mode in Y-bending at 285Hz (Figure [[fig:mode_bending_y]])
|
|
- Mode in Z-torsion at 400Hz (Figure [[fig:mode_torsion_z]])
|
|
|
|
#+name: fig:mode_bending_x
|
|
#+caption: X-bending mode (189Hz)
|
|
#+attr_latex: :width 0.9\linewidth
|
|
[[file:figs/mode_bending_x.gif]]
|
|
|
|
#+name: fig:mode_bending_y
|
|
#+caption: Y-bending mode (285Hz)
|
|
#+attr_latex: :width 0.9\linewidth
|
|
[[file:figs/mode_bending_y.gif]]
|
|
|
|
#+name: fig:mode_torsion_z
|
|
#+caption: Z-torsion mode (400Hz)
|
|
#+attr_latex: :width 0.9\linewidth
|
|
[[file:figs/mode_torsion_z.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 :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 | ? |
|
|
|
|
* Function
|
|
** =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
|