phd-test-bench-struts/test-bench-struts.org

2656 lines
96 KiB
Org Mode
Raw Normal View History

2024-03-19 15:18:57 +01:00
#+TITLE: Test Bench - Nano-Hexapod Struts
: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 ""
#+LaTeX_CLASS: scrreprt
#+LaTeX_CLASS_OPTIONS: [a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc]
#+LaTeX_HEADER_EXTRA: \input{preamble.tex}
#+LATEX_HEADER_EXTRA: \bibliography{test-bench-struts.bib}
#+BIND: org-latex-bib-compiler "biber"
#+PROPERTY: header-args:matlab :session *MATLAB*
#+PROPERTY: header-args:matlab+ :comments org
#+PROPERTY: header-args:matlab+ :exports none
#+PROPERTY: header-args:matlab+ :results none
#+PROPERTY: header-args:matlab+ :eval no-export
#+PROPERTY: header-args:matlab+ :noweb yes
#+PROPERTY: header-args:matlab+ :mkdirp yes
#+PROPERTY: header-args:matlab+ :output-dir figs
#+PROPERTY: header-args:matlab+ :tangle no
#+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-struts.pdf">pdf</a>.</p>
<hr>
#+end_export
#+latex: \clearpage
* Build :noexport:
#+NAME: startblock
#+BEGIN_SRC emacs-lisp :results none :tangle no
(add-to-list 'org-latex-classes
'("scrreprt"
"\\documentclass{scrreprt}"
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
))
;; Remove automatic org heading labels
(defun my-latex-filter-removeOrgAutoLabels (text backend info)
"Org-mode automatically generates labels for headings despite explicit use of `#+LABEL`. This filter forcibly removes all automatically generated org-labels in headings."
(when (org-export-derived-backend-p backend 'latex)
(replace-regexp-in-string "\\\\label{sec:org[a-f0-9]+}\n" "" text)))
(add-to-list 'org-export-filter-headline-functions
'my-latex-filter-removeOrgAutoLabels)
;; Remove all org comments in the output LaTeX file
(defun delete-org-comments (backend)
(loop for comment in (reverse (org-element-map (org-element-parse-buffer)
'comment 'identity))
do
(setf (buffer-substring (org-element-property :begin comment)
(org-element-property :end comment))
"")))
(add-hook 'org-export-before-processing-hook 'delete-org-comments)
;; Use no package by default
(setq org-latex-packages-alist nil)
(setq org-latex-default-packages-alist nil)
;; Do not include the subtitle inside the title
(setq org-latex-subtitle-separate t)
(setq org-latex-subtitle-format "\\subtitle{%s}")
(setq org-export-before-parsing-hook '(org-ref-glossary-before-parsing
org-ref-acronyms-before-parsing))
#+END_SRC
* Notes :noexport:
2024-03-25 10:55:31 +01:00
Prefix for figures/section/tables =test_struts=
2024-03-19 17:29:51 +01:00
To integrate:
2024-03-19 17:02:38 +01:00
- [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-strut-mounting/test-bench-strut-mounting.org][test-bench-strut-mounting]]
- [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-apa300ml/test-bench-apa300ml.org][test-bench-apa300ml]]
- [X] Dynamical measurements (Section 5)
- [X] Simscape model (Section 6)
2024-03-25 16:33:38 +01:00
- [X] Check what are the used Matlab functions
2024-03-25 10:55:31 +01:00
- [X] check [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-apa300ml/test-bench-apa300ml.org::*Compare with the FEM/Simscape Model][Compare with the FEM/Simscape Model]]
*no, it is only for the APA and not the strut*
- [X] Check [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-apa300ml/test-bench-apa300ml.org::*New Measurements - IFF Root Locus][New Measurements - IFF Root Locus]]
*no, it is only for the APA and not the strut*
2024-03-27 14:35:55 +01:00
** TODO [#C] Add schematic of the test bench with signals
here: [[*Introduction][Introduction]]
- $u$
- $d_e$
- $d_a$
2024-03-25 16:39:31 +01:00
** TODO [#B] Rework mounting procedure section
2024-03-25 16:33:38 +01:00
- [X] Use smaller images, maybe one subfigure for all the steps
2024-03-25 16:39:31 +01:00
- [ ] Add some notes to the figure ref:fig:test_struts_mounting_bench_first_concept
2024-03-25 16:33:38 +01:00
- [ ] Explain clearly the mounting goals (coaxiality, etc.)
2024-03-27 14:35:55 +01:00
- [ ] Speak about the "pin" that is used to align the APA with respect to the flexible joints (initially not used)
2024-03-25 16:33:38 +01:00
2024-03-25 16:39:31 +01:00
** DONE [#B] Rework flexible mode measurements
CLOSED: [2024-03-25 Mon 16:35]
2024-03-25 16:33:38 +01:00
2024-03-25 16:39:31 +01:00
- [X] Use smaller images, one subfigure for all measurements
2024-03-25 16:33:38 +01:00
** DONE [#B] Make the simscape model work
CLOSED: [2024-03-25 Mon 15:09]
2024-03-19 15:18:57 +01:00
* Introduction :ignore:
2024-03-19 17:02:38 +01:00
In this document, a test-bench is used to characterize the struts of the nano-hexapod.
2024-03-25 10:55:31 +01:00
Each strut includes (Figure ref:fig:test_struts_picture_strut):
2024-03-19 17:02:38 +01:00
- 2 flexible joints at each ends.
These flexible joints have been characterized in a separate test bench (see ...).
- 1 Amplified Piezoelectric Actuator (APA300ML) (described in Section ...).
Two stacks are used as an actuator and one stack as a (force) sensor.
- 1 encoder (Renishaw Vionic) that has been characterized in a separate test bench (see ...).
2024-03-25 10:55:31 +01:00
#+name: fig:test_struts_picture_strut
2024-03-19 17:02:38 +01:00
#+caption: One strut including two flexible joints, an amplified piezoelectric actuator and an encoder
#+attr_latex: :width 0.8\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_picture_strut.jpg]]
2024-03-19 17:02:38 +01:00
2024-03-25 10:55:31 +01:00
Then the struts are mounted (procedure described in Section ref:sec:test_struts_mounting), and are fixed to the same measurement bench.
2024-03-19 17:02:38 +01:00
The goals are to:
2024-03-25 10:55:31 +01:00
- Section ref:sec:test_struts_dynamical_meas: Identify the dynamics from the generated DAC voltage to:
2024-03-19 17:02:38 +01:00
- the sensors stack generated voltage
- the measured displacement by the encoder
- the measured displacement by the interferometer (representing encoders that would be fixed to the nano-hexapod's plates instead of the struts)
2024-03-25 10:55:31 +01:00
- Section ref:sec:test_struts_simscape: Compare the measurements with the Simscape model of the struts and tune the models
2024-03-19 17:02:38 +01:00
The final goal of the work presented in this document is to have an accurate Simscape model of the struts that can then be included in the Simscape model of the nano-hexapod.
2024-03-25 10:55:31 +01:00
#+name: tab:test_struts_section_matlab_code
2024-03-19 15:18:57 +01:00
#+caption: Report sections and corresponding Matlab files
#+attr_latex: :environment tabularx :width 0.6\linewidth :align lX
#+attr_latex: :center t :booktabs t
2024-03-25 10:55:31 +01:00
| *Sections* | *Matlab File* |
|--------------------------------------------+----------------------------------|
| Section ref:sec:test_struts_flexible_modes | =test_struts_1_flexible_modes.m= |
| Section ref:sec:test_struts_dynamical_meas | =test_struts_2_dynamical_meas.m= |
2024-03-25 16:33:38 +01:00
| Section ref:sec:test_struts_simscape | =test_struts_3_simscape_model.m= |
2024-03-19 15:18:57 +01:00
2024-03-19 17:02:38 +01:00
* Mounting Procedure
2024-03-25 10:55:31 +01:00
<<sec:test_struts_mounting>>
2024-03-19 17:02:38 +01:00
** Introduction :ignore:
** Mounting Bench
A mounting bench is used to greatly simply the mounting of the struts as well as ensuring the correct strut length and coaxiality of the flexible joint's interfaces.
This is very important in order to not loose any stroke when the struts will be mounted on the nano-hexapod.
2024-03-25 10:55:31 +01:00
A CAD view of the mounting bench is shown in Figure ref:fig:test_struts_mounting_bench_first_concept.
2024-03-19 17:02:38 +01:00
2024-03-25 18:13:22 +01:00
Faro arm[fn:1]
2024-03-25 10:55:31 +01:00
#+name: fig:test_struts_mounting_bench_first_concept
2024-03-19 17:02:38 +01:00
#+caption: CAD view of the mounting bench
2024-03-25 16:33:38 +01:00
#+attr_latex: :width 0.6\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_mounting_bench_first_concept.png]]
2024-03-19 17:02:38 +01:00
2024-03-25 10:55:31 +01:00
The main part of the bench is here to ensure both the correct strut length and strut coaxiality as shown in Figure ref:fig:test_struts_mounting_step_0.
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
#+name: fig:test_struts_mounting_base_part
#+caption: Caption..., add foot note with Faro arm
2024-03-27 14:35:55 +01:00
#+attr_latex: :options [htbp]
2024-03-25 16:33:38 +01:00
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_0}Useful features of the main mounting element}
#+attr_latex: :options {0.56\textwidth}
#+begin_subfigure
#+attr_latex: :height 4.5cm
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_mounting_step_0.jpg]]
2024-03-25 16:33:38 +01:00
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_check_dimensions_bench}Dimensional check}
#+attr_latex: :options {0.43\textwidth}
#+begin_subfigure
#+attr_latex: :height 4.5cm
[[file:figs/test_struts_check_dimensions_bench.jpg]]
#+end_subfigure
#+end_figure
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
The tight tolerances of this element has been verified as shown in Figure ref:fig:test_struts_check_dimensions_bench and were found to comply with the requirements.
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
The flexible joints are rigidly fixed to cylindrical tools shown in Figures ref:fig:test_struts_cylindrical_mounting_part_top and ref:fig:test_struts_cylindrical_mounting_part_bot which are then mounted on the mounting tool shown in Figure ref:fig:test_struts_mounting_step_0.
2024-03-19 17:02:38 +01:00
This cylindrical tool is here to protect the flexible joints when tightening the screws and therefore applying large torque.
** Mounting Procedure
The mounting procedure is as follows:
2024-03-25 16:33:38 +01:00
1. Screw flexible joints inside the cylindrical interface element shown in Figure ref:fig:test_struts_cylindrical_mounting
2024-03-19 17:02:38 +01:00
2. Fix the two interface elements. One of the two should be clamped, the other one should have its axial rotation free.
2024-03-25 16:33:38 +01:00
Visually align the clamped one horizontally. (Figure ref:fig:test_struts_mounting_step_1)
3. Put cylindrical washers, APA and interface pieces on top of the flexible joints (Figure ref:fig:test_struts_mounting_step_2)
2024-03-19 17:02:38 +01:00
4. Put the 4 screws just in contact such that everything is correctly positioned and such that the "free" flexible joint is correctly oriented
5. Put the 8 lateral screws in contact
6. Tighten the 4 screws to fix the APA on the two flexible joints (using a torque screwdriver)
7. Remove the 4 laterals screws
2024-03-25 16:33:38 +01:00
8. (optional) Put the APA horizontally and fix the encoder and align it to maximize the contrast (Figure ref:fig:test_struts_mounting_step_3)
9. Disassemble to have an properly mounted strut (Figure ref:fig:test_struts_mounting_step_4) for which the coaxiality between the two flexible joint's interfaces is good
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
#+name: fig:test_struts_cylindrical_mounting
#+caption: Preparation of the flexible joints by fixing them in their cylindrical interface
2024-03-27 14:35:55 +01:00
#+attr_latex: :options [htbp]
2024-03-25 16:33:38 +01:00
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_cylindrical_mounting_part_top}Cylindral Interface (Top)}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :height 4.5cm
[[file:figs/test_struts_cylindrical_mounting_part_top.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_cylindrical_mounting_part_bot}Cylindrlcal Interface (Bottom)}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :height 4.5cm
[[file:figs/test_struts_cylindrical_mounting_part_bot.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_joints}Mounted flexible joints}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :height 4.5cm
[[file:figs/test_struts_mounting_joints.jpg]]
#+end_subfigure
#+end_figure
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
#+name: fig:test_struts_mounting_steps
#+caption: Steps for mounting the struts.
2024-03-27 14:35:55 +01:00
#+attr_latex: :options [htbp]
2024-03-25 16:33:38 +01:00
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_1}Step 1}
#+attr_latex: :options {0.5\textwidth}
#+begin_subfigure
2024-03-27 14:35:55 +01:00
#+attr_latex: :width 0.95\linewidth
2024-03-25 16:33:38 +01:00
[[file:figs/test_struts_mounting_step_1.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_2}Step 2}
#+attr_latex: :options {0.5\textwidth}
#+begin_subfigure
2024-03-27 14:35:55 +01:00
#+attr_latex: :width 0.95\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_mounting_step_2.jpg]]
2024-03-25 16:33:38 +01:00
#+end_subfigure
2024-03-27 14:35:55 +01:00
\bigskip
2024-03-25 16:33:38 +01:00
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_3}Step 3}
#+attr_latex: :options {0.5\textwidth}
#+begin_subfigure
2024-03-27 14:35:55 +01:00
#+attr_latex: :width 0.95\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_mounting_step_3.jpg]]
2024-03-25 16:33:38 +01:00
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_4}Step 4}
#+attr_latex: :options {0.5\textwidth}
#+begin_subfigure
2024-03-27 14:35:55 +01:00
#+attr_latex: :width 0.95\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_mounting_step_4.jpg]]
2024-03-25 16:33:38 +01:00
#+end_subfigure
#+end_figure
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
* Measurement of flexible modes
2024-03-19 17:02:38 +01:00
:PROPERTIES:
2024-03-25 10:55:31 +01:00
:header-args:matlab+: :tangle matlab/test_struts_1_flexible_modes.m
2024-03-19 17:02:38 +01:00
:END:
2024-03-25 10:55:31 +01:00
<<sec:test_struts_flexible_modes>>
2024-03-19 17:02:38 +01:00
** Introduction
2024-03-27 14:35:55 +01:00
From a Finite Element Model of the struts, it have been found that three main resonances are foreseen to be problematic for the control of the APA300ML (Figure ref:fig:test_struts_mode_shapes): an "X-bending" mode at 189Hz, a "Y-bending" mode at 285Hz and a "Z-torsion" mode at 400Hz.
2024-03-25 10:55:31 +01:00
#+name: fig:test_struts_mode_shapes
2024-03-25 16:33:38 +01:00
#+caption: Spurious resonances of the struts estimated from a Finite Element Model
2024-03-27 14:35:55 +01:00
#+attr_latex: :options [htbp]
2024-03-25 16:33:38 +01:00
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mode_shapes_3}X-bending mode (189Hz)}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_mode_shapes_1.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mode_shapes_3}Y-bending mode (285Hz)}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_mode_shapes_2.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_mode_shapes_3}Z-torsion mode (400Hz)}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_mode_shapes_3.png]]
#+end_subfigure
#+end_figure
2024-03-25 10:55:31 +01:00
** Matlab Init :noexport:ignore:
2024-03-19 17:02:38 +01:00
#+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
2024-03-25 10:55:31 +01:00
#+begin_src matlab :tangle no :noweb yes
<<m-init-path>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 10:55:31 +01:00
#+begin_src matlab :eval no :noweb yes
<<m-init-path-tangle>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 10:55:31 +01:00
#+begin_src matlab :noweb yes
<<m-init-other>>
2024-03-19 17:02:38 +01:00
#+end_src
** Measurement Setup
2024-03-25 16:33:38 +01:00
A Laser vibrometer is measuring the difference of motion between two beam path (red points in Figure ref:fig:test_struts_meas_modes).
The strut is excited with an instrumented hammer and the transfer function from the hammer to the measured rotation is computed.
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
The "X-bending" mode is measured as shown in Figure ref:fig:test_struts_meas_x_bending.
The "Y-bending" mode is measured as shown in Figure ref:fig:test_struts_meas_y_bending.
Finally, the "Z-torsion" is measured as shown in Figure ref:fig:test_struts_meas_z_torsion.
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
This is done with and without the encoder fixed to the strut.
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
#+name: fig:test_struts_meas_modes
#+caption: Measurement of strut flexible modes
2024-03-27 14:35:55 +01:00
#+attr_latex: :options [htbp]
2024-03-25 16:33:38 +01:00
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_meas_x_bending}X-bending mode}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_meas_x_bending.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_meas_y_bending}Y-bending mode}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_meas_y_bending.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_meas_z_torsion}Z-torsion mode}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_meas_z_torsion.jpg]]
#+end_subfigure
#+end_figure
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
** Measured results
The obtained frequency response functions are shown in Figure ref:fig:test_struts_spur_res_frf.
2024-03-19 17:02:38 +01:00
#+begin_src matlab :exports none
%% Load Data (without the encoder)
bending_X = load('strut_spur_res_x_bending.mat');
bending_Y = load('strut_spur_res_y_bending.mat');
torsion_Z = load('strut_spur_res_z_torsion.mat');
2024-03-27 14:35:55 +01:00
%% Load Data (with the encoder)
bending_X_enc = load('strut_spur_res_x_bending_enc.mat');
bending_Y_enc = load('strut_spur_res_y_bending_enc.mat');
torsion_Z_enc = load('strut_spur_res_z_torsion_enc.mat');
2024-03-19 17:02:38 +01:00
#+end_src
#+begin_src matlab :exports none
%% Plot the responses (without the encoder)
figure;
hold on;
plot(bending_X.FFT1_AvSpc_1_RMS_X_Val, bending_X.FFT1_AvSpc_1_RMS_Y_Val, ...
'DisplayName', 'X-Bending')
plot(bending_Y.FFT1_AvSpc_1_RMS_X_Val, bending_Y.FFT1_AvSpc_1_RMS_Y_Val, ...
'DisplayName', 'Y-Bending')
plot(torsion_Z.FFT1_AvSpc_1_RMS_X_Val, torsion_Z.FFT1_AvSpc_1_RMS_Y_Val, ...
'DisplayName', 'Z-torsion');
text(226, 1.5e-4,{'226Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
2024-03-27 14:35:55 +01:00
text(310, 6e-5,{'337Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
2024-03-19 17:02:38 +01:00
text(398, 1.5e-4,{'398Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
hold off;
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
xlabel('Frequency [Hz]'); ylabel('Amplitude');
xlim([50, 8e2]); ylim([5e-7, 3e-4])
2024-03-27 14:35:55 +01:00
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1);
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_spur_res_frf_no_enc.pdf', 'width', 'half', 'height', 'normal');
2024-03-19 17:02:38 +01:00
#+end_src
#+begin_src matlab :exports none
2024-03-27 14:35:55 +01:00
%% Plot the responses (with the encoder)
2024-03-19 17:02:38 +01:00
figure;
hold on;
plot(bending_X_enc.FFT1_AvSpc_1_RMS_X_Val, bending_X_enc.FFT1_AvSpc_1_RMS_Y_Val, ...
'DisplayName', 'X-Bending')
plot(bending_Y_enc.FFT1_AvSpc_1_RMS_X_Val, bending_Y_enc.FFT1_AvSpc_1_RMS_Y_Val, ...
'DisplayName', 'Y-Bending')
plot(torsion_Z_enc.FFT1_AvSpc_1_RMS_X_Val, torsion_Z_enc.FFT1_AvSpc_1_RMS_Y_Val, ...
'DisplayName', 'Z-torsion');
text(198, 4e-5,{'198Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
text(293, 6e-5,{'293Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
text(381, 1e-4,{'381Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center')
hold off;
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
xlabel('Frequency [Hz]'); ylabel('Amplitude');
2024-03-27 14:35:55 +01:00
xlim([50, 8e2]); ylim([5e-7, 3e-4])
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1);
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_spur_res_frf_enc.pdf', 'width', 'half', 'height', 'normal');
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+name: fig:test_struts_spur_res_frf
#+caption: Measured frequency response functions without the encoder ref:fig:test_struts_spur_res_frf and with the encoder ref:fig:test_struts_spur_res_frf_enc
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_spur_res_frf_no_enc}without encoder}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width \linewidth
[[file:figs/test_struts_spur_res_frf_no_enc.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_spur_res_frf_enc}with the encoder}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width \linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_spur_res_frf_enc.png]]
2024-03-27 14:35:55 +01:00
#+end_subfigure
#+end_figure
2024-03-19 17:02:38 +01:00
2024-03-25 16:33:38 +01:00
** Conclusion :ignore:
2024-03-19 17:02:38 +01:00
2024-03-25 10:55:31 +01:00
Table ref:tab:test_struts_spur_mode_freqs summarizes the measured resonance frequencies as well as the computed ones using the Finite Element Model.
2024-03-27 14:35:55 +01:00
It is shown that:
2024-03-19 17:02:38 +01:00
- the resonance frequencies of the 3 modes are only slightly increasing when the encoder is removed
- the computed resonance frequencies from the FEM are very close to the measured one when the encoder is fixed to the strut
2024-03-25 10:55:31 +01:00
#+name: tab:test_struts_spur_mode_freqs
2024-03-19 17:02:38 +01:00
#+caption: Measured frequency of the strut spurious modes
2024-03-25 16:33:38 +01:00
#+attr_latex: :environment tabularx :width 0.7\linewidth :align Xccc
2024-03-19 17:02:38 +01:00
#+attr_latex: :center t :booktabs t :float t
| *Mode* | *Struts (FEM)* | *Struts (exp)* | *Plates (exp)* |
|-----------+----------------+----------------+----------------|
| X-Bending | 189Hz | 198Hz | 226Hz |
| Y-Bending | 285Hz | 293Hz | 337Hz |
| Z-Torsion | 400Hz | 381Hz | 398Hz |
* Dynamical measurements
:PROPERTIES:
2024-03-25 10:55:31 +01:00
:header-args:matlab+: :tangle matlab/test_struts_2_dynamical_meas.m
2024-03-19 17:02:38 +01:00
:END:
2024-03-25 10:55:31 +01:00
<<sec:test_struts_dynamical_meas>>
** Introduction :ignore:
The bench is shown in Figure ref:fig:test_struts_bench_leg_overview.
Measurements are performed either when no encoder is fixed to the strut (Figure ref:fig:test_struts_bench_leg_front) or when one encoder is fixed to the strut (Figure ref:fig:test_struts_bench_leg_coder).
#+name: fig:test_struts_bench_leg
#+caption: Experimental setup to measured the dynamics of the struts.
2024-03-27 14:35:55 +01:00
#+attr_latex: :options [htbp]
2024-03-25 10:55:31 +01:00
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_bench_leg_overview}Overview}
#+attr_latex: :options {0.35\textwidth}
#+begin_subfigure
2024-03-27 14:35:55 +01:00
#+attr_latex: :width 0.9\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_bench_leg_overview.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_bench_leg_front}Strut without encoder}
#+attr_latex: :options {0.31\textwidth}
#+begin_subfigure
2024-03-27 14:35:55 +01:00
#+attr_latex: :width 0.9\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_bench_leg_front.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_bench_leg_coder}Strut with encoder}
#+attr_latex: :options {0.31\textwidth}
#+begin_subfigure
2024-03-27 14:35:55 +01:00
#+attr_latex: :width 0.9\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_bench_leg_coder.jpg]]
#+end_subfigure
#+end_figure
2024-03-27 14:35:55 +01:00
First, the effect of the encoder on the measured dynamics is studied in Section ref:ssec:test_struts_effect_encoder.
Then, the dynamics seen by the encoder and by the interferometers are compared in Section ref:ssec:test_struts_comp_enc_int.
Finally, all the measured struts are compared in terms of dynamics in Section ref:ssec:test_struts_comp_all_struts.
2024-03-25 10:55:31 +01:00
** Matlab Init :noexport:ignore:
2024-03-19 17:02:38 +01:00
#+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
2024-03-25 10:55:31 +01:00
#+begin_src matlab :tangle no :noweb yes
<<m-init-path>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 10:55:31 +01:00
#+begin_src matlab :eval no :noweb yes
<<m-init-path-tangle>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 10:55:31 +01:00
#+begin_src matlab :noweb yes
<<m-init-other>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
** Effect of the Encoder on the measured dynamics
<<ssec:test_struts_effect_encoder>>
2024-03-19 17:02:38 +01:00
#+begin_src matlab
2024-03-25 16:33:38 +01:00
%% Parameters for Frequency Analysis
2024-03-25 10:55:31 +01:00
Ts = 1e-4; % Sampling Time [s]
2024-03-25 16:33:38 +01:00
Nfft = floor(1/Ts); % Number of points for the FFT computation
win = hanning(Nfft); % Hanning window
Noverlap = floor(Nfft/2); % Overlap between frequency analysis
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
%% Measure FRF for Strut 1 - No encoder
% Load Data
2024-03-25 14:42:03 +01:00
leg_sweep = load('frf_data_leg_1_sweep.mat', 'u', 'Vs', 'de', 'da');
leg_noise_hf = load('frf_data_leg_1_noise_hf.mat', 'u', 'Vs', 'de', 'da');
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
% We get the frequency vector that will be the same for all the frequency domain analysis.
2024-03-25 14:42:03 +01:00
[~, f] = tfestimate(leg_sweep.u, leg_sweep.de, win, Noverlap, Nfft, 1/Ts);
i_lf = f <= 350; % Indices used for the low frequency
2024-03-25 16:33:38 +01:00
i_hf = f > 350; % Indices used for the high frequency
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
% Compute FRF function from u to da (interferometer)
2024-03-25 14:42:03 +01:00
[frf_sweep, ~] = tfestimate(leg_sweep.u, leg_sweep.da, win, Noverlap, Nfft, 1/Ts);
[frf_noise_hf, ~] = tfestimate(leg_noise_hf.u, leg_noise_hf.da, win, Noverlap, Nfft, 1/Ts);
2024-03-27 14:35:55 +01:00
int_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF
% Compute FRF function from u to Vs (force sensor)
[frf_sweep, ~] = tfestimate(leg_sweep.u, leg_sweep.Vs, win, Noverlap, Nfft, 1/Ts);
[frf_noise_hf, ~] = tfestimate(leg_noise_hf.u, leg_noise_hf.Vs, win, Noverlap, Nfft, 1/Ts);
iff_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF
%% Measure FRF for Strut 1 - With encoder
% Load Data
leg_enc_sweep = load('frf_data_leg_coder_1_noise.mat', 'u', 'Vs', 'de', 'da');
leg_enc_noise_hf = load('frf_data_leg_coder_1_noise_hf.mat', 'u', 'Vs', 'de', 'da');
% Compute FRF function from u to da (interferometer)
[frf_sweep, ~] = tfestimate(leg_enc_sweep.u, leg_enc_sweep.da, win, Noverlap, Nfft, 1/Ts);
[frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.u, leg_enc_noise_hf.da, win, Noverlap, Nfft, 1/Ts);
int_with_enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
% Compute FRF function from u to Vs (force sensor)
[frf_sweep, ~] = tfestimate(leg_enc_sweep.u, leg_enc_sweep.Vs, win, Noverlap, Nfft, 1/Ts);
[frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.u, leg_enc_noise_hf.Vs, win, Noverlap, Nfft, 1/Ts);
iff_with_enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF
% Compute FRF function from u to de (encoder)
[frf_sweep, ~] = tfestimate(leg_enc_sweep.u, leg_enc_sweep.de, win, Noverlap, Nfft, 1/Ts);
[frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.u, leg_enc_noise_hf.de, win, Noverlap, Nfft, 1/Ts);
enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
Figure ref:fig:test_struts_effect_encoder_int
Same goes for the transfer function from excitation voltage $u$ to the axial motion of the strut $d_a$ as measured by the interferometer ().
The transfer function from the excitation voltage $u$ to the generated voltage $V_s$ by the sensor stack is not influence by the fixation of the encoder (Figure ref:fig:test_struts_effect_encoder_iff).
This means that the IFF control strategy should be as effective whether or not the encoders are fixed to the struts.
2024-03-19 17:02:38 +01:00
#+begin_src matlab :exports none
2024-03-27 14:35:55 +01:00
%% Plot the FRF from u to da with and without the encoder
2024-03-19 17:02:38 +01:00
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
ax1 = nexttile([]);
2024-03-19 17:02:38 +01:00
hold on;
2024-03-27 14:35:55 +01:00
plot(f, abs(int_with_enc_frf), '-', 'DisplayName', 'With encoder');
plot(f, abs(int_frf), '-', 'DisplayName', 'Without encoder');
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-27 14:35:55 +01:00
ylabel('Amplitude $d_a/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
2024-03-27 14:35:55 +01:00
ylim([1e-7, 1e-3]);
legend('location', 'northeast')
2024-03-19 17:02:38 +01:00
ax2 = nexttile;
hold on;
2024-03-27 14:35:55 +01:00
plot(f, 180/pi*angle(int_with_enc_frf), '-');
plot(f, 180/pi*angle(int_frf), '-');
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_effect_encoder_int.pdf', 'width', 'half', 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
#+begin_src matlab :exports none
2024-03-27 14:35:55 +01:00
%% Compare the IFF plant with and without the encoders
2024-03-19 17:02:38 +01:00
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
2024-03-27 14:35:55 +01:00
plot(f, abs(iff_with_enc_frf), 'DisplayName', 'With Encoder');
plot(f, abs(iff_frf), 'DisplayName', 'Without Encoder');
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $V_s/u$ [V/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
2024-03-27 14:35:55 +01:00
legend('location', 'northeast', 'FontSize', 8);
2024-03-19 17:02:38 +01:00
ylim([1e-2, 1e2]);
ax2 = nexttile;
hold on;
2024-03-27 14:35:55 +01:00
plot(f, 180/pi*angle(iff_with_enc_frf));
plot(f, 180/pi*angle(iff_frf));
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_effect_encoder_iff.pdf', 'width', 'half', 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+name: fig:test_struts_effect_encoder
#+caption: Effect of having the encoder fixed to the struts on the measured dynamics from $u$ to $d_a$ (\subref{fig:test_struts_effect_encoder_int}) and from $u$ to $V_s$ cref:fig:test_struts_effect_encoder_iff
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_encoder_int}$u$ to $d_a$}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/test_struts_effect_encoder_int.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_encoder_iff}$u$ to $V_s$}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/test_struts_effect_encoder_iff.png]]
#+end_subfigure
#+end_figure
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
** Comparison of the encoder and interferometer
<<ssec:test_struts_comp_enc_int>>
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
The dynamics as measured by the encoder and by the interferometers are compared in Figure ref:fig:test_struts_comp_enc_int.
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
The dynamics from the excitation voltage $u$ to the measured displacement by the encoder $d_e$ presents much more complicated behavior than the transfer function to the displacement as measured by the Interferometer (compared in Figure ref:fig:test_struts_comp_enc_int).
It will be further investigated why the two dynamics as so different and what are causing all these resonances.
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
As shown in Figure ref:fig:test_struts_comp_enc_int, we can clearly see three spurious resonances at 197Hz, 290Hz and 376Hz.
These resonances correspond to parasitic resonances of the strut itself that was estimated using a finite element model of the strut (Figure ref:fig:test_struts_mode_shapes):
- Mode in X-bending at 189Hz
- Mode in Y-bending at 285Hz
- Mode in Z-torsion at 400Hz
The good news is that these resonances are not seen on the interferometer (they are therefore not impacting the axial motion of the strut).
But these resonances are making the use of encoder fixed to the strut difficult.
2024-03-19 17:02:38 +01:00
#+begin_src matlab :exports none
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
2024-03-27 14:35:55 +01:00
plot(f, abs(enc_frf), 'DisplayName', 'Encoder');
plot(f, abs(int_with_enc_frf), 'DisplayName', 'Interferometer');
text(93, 4e-4, {'93Hz'}, 'VerticalAlignment','bottom','HorizontalAlignment','center')
text(200, 1.3e-4,{'197Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
text(300, 4e-6, {'290Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
text(400, 1.4e-6,{'376Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center')
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-27 14:35:55 +01:00
ylabel('Amplitude $d/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
2024-03-27 14:35:55 +01:00
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1);
ylim([1e-8, 1e-3]);
2024-03-19 17:02:38 +01:00
ax2 = nexttile;
hold on;
2024-03-27 14:35:55 +01:00
plot(f, 180/pi*angle(enc_frf));
plot(f, 180/pi*angle(int_with_enc_frf));
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
2024-03-27 14:35:55 +01:00
exportFig('figs/test_struts_comp_enc_int.pdf', 'width', 'wide', 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+name: fig:test_struts_comp_enc_int
#+caption: Comparison of the transfer functions from excitation voltage $u$ to either the encoder $d_e$ or the interferometer $d_a$
2024-03-19 17:02:38 +01:00
#+RESULTS:
2024-03-27 14:35:55 +01:00
[[file:figs/test_struts_comp_enc_int.png]]
** Comparison of all the Struts
<<ssec:test_struts_comp_all_struts>>
2024-03-19 17:02:38 +01:00
#+begin_src matlab
2024-03-27 14:35:55 +01:00
%% Numbers of the measured legs
strut_nums = [1 2 3 4 5];
%% Load the measurement data
% First identification (low frequency noise)
leg_noise = {};
for i = 1:length(strut_nums)
leg_noise(i) = {load(sprintf('frf_data_leg_coder_%i_noise.mat', strut_nums(i)), 'u', 'Vs', 'de', 'da')};
end
% Second identification (high frequency noise)
leg_noise_hf = {};
for i = 1:length(strut_nums)
leg_noise_hf(i) = {load(sprintf('frf_data_leg_coder_%i_noise_hf.mat', strut_nums(i)), 'u', 'Vs', 'de', 'da')};
end
%% Compute FRF - From u to de (encoder)
enc_frf = zeros(length(f), length(strut_nums));
for i = 1:length(strut_nums)
[frf_lf, ~] = tfestimate(leg_noise{i}.u, detrend(leg_noise{i}.de, 0), win, Noverlap, Nfft, 1/Ts);
[frf_hf, ~] = tfestimate(leg_noise_hf{i}.u, detrend(leg_noise_hf{i}.de, 0), win, Noverlap, Nfft, 1/Ts);
enc_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)];
end
%% Compute FRF - From u to da (interferometer)
int_frf = zeros(length(f), length(strut_nums));
for i = 1:length(strut_nums)
[frf_lf, ~] = tfestimate(leg_noise{i}.u, leg_noise{i}.da, win, Noverlap, Nfft, 1/Ts);
[frf_hf, ~] = tfestimate(leg_noise_hf{i}.u, leg_noise_hf{i}.da, win, Noverlap, Nfft, 1/Ts);
int_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)];
end
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
%% Compute FRF - From u to Vs (force sensor)
iff_frf = zeros(length(f), length(strut_nums));
for i = 1:length(strut_nums)
[frf_lf, ~] = tfestimate(leg_noise{i}.u, leg_noise{i}.Vs, win, Noverlap, Nfft, 1/Ts);
[frf_hf, ~] = tfestimate(leg_noise_hf{i}.u, leg_noise_hf{i}.Vs, win, Noverlap, Nfft, 1/Ts);
iff_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)];
end
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
Then, the transfer function from the DAC output voltage $u$ to the measured displacement by the Attocube is computed for all the struts and shown in Figure ref:fig:test_struts_comp_interf_plants.
All the struts are giving very similar FRF.
2024-03-19 17:02:38 +01:00
#+begin_src matlab :exports none
2024-03-27 14:35:55 +01:00
%% Plot the FRF from u to de (interferometer)
2024-03-19 17:02:38 +01:00
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
2024-03-27 14:35:55 +01:00
for i = 1:length(strut_nums)
plot(f, abs(int_frf(:, i)), ...
'DisplayName', sprintf('Leg %i', strut_nums(i)));
end
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-27 14:35:55 +01:00
ylabel('Amplitude $d_a/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
2024-03-27 14:35:55 +01:00
legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
ylim([1e-9, 1e-3]);
2024-03-19 17:02:38 +01:00
ax2 = nexttile;
hold on;
2024-03-27 14:35:55 +01:00
for i = 1:length(strut_nums)
plot(f, 180/pi*angle(int_frf(:, i)));
end
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
2024-03-27 14:35:55 +01:00
yticks(-360:90:360); ylim([-180 180]);
2024-03-19 17:02:38 +01:00
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_comp_interf_plants.pdf', 'width', 'half', 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
#+begin_src matlab :exports none
2024-03-27 14:35:55 +01:00
%% Plot the FRF from u to Vs
2024-03-19 17:02:38 +01:00
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
2024-03-27 14:35:55 +01:00
for i = 1:length(strut_nums)
plot(f, abs(iff_frf(:, i)), ...
'DisplayName', sprintf('Leg %i', strut_nums(i)));
end
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-27 14:35:55 +01:00
ylabel('Amplitude $V_s/u$ [V/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
2024-03-27 14:35:55 +01:00
ylim([1e-2, 1e2]);
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2);
2024-03-19 17:02:38 +01:00
ax2 = nexttile;
hold on;
2024-03-27 14:35:55 +01:00
for i = 1:length(strut_nums)
plot(f, 180/pi*angle(iff_frf(:, i)));
end
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
2024-03-27 14:35:55 +01:00
yticks(-360:90:360); ylim([-180 180]);
2024-03-19 17:02:38 +01:00
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_comp_iff_plants.pdf', 'width', 'half', 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+name: fig:test_struts_comp_plants
#+caption: Comparison of the measured plants
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_interf_plants}$u$ to $d_a$}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width \linewidth
[[file:figs/test_struts_comp_interf_plants.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_iff_plants}$u$ to $V_s$}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width \linewidth
[[file:figs/test_struts_comp_iff_plants.png]]
#+end_subfigure
#+end_figure
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
There is a very large variability of the dynamics as measured by the encoder as shown in Figure ref:fig:test_struts_comp_enc_plants.
Even-though the same peaks are seen for all of the struts (95Hz, 200Hz, 300Hz, 400Hz), the amplitude of the peaks are not the same.
Moreover, the location or even the presence of complex conjugate zeros is changing from one strut to the other.
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
All of this will be studied in Section ref:sec:test_struts_simscape using the Simscape model.
2024-03-19 17:02:38 +01:00
#+begin_src matlab :exports none
2024-03-27 14:35:55 +01:00
%% Bode plot of the FRF from u to de
2024-03-19 17:02:38 +01:00
figure;
2024-03-27 14:35:55 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]);
2024-03-19 17:02:38 +01:00
hold on;
2024-03-27 14:35:55 +01:00
for i = 1:length(strut_nums)
plot(f, abs(enc_frf(:, i)), ...
'DisplayName', sprintf('Leg %i', strut_nums(i)));
end
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-27 14:35:55 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
hold off;
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
ylim([1e-8, 1e-3]);
ax2 = nexttile;
hold on;
for i = 1:length(strut_nums)
plot(f, 180/pi*angle(enc_frf(:, i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
2024-03-19 17:02:38 +01:00
hold off;
2024-03-27 14:35:55 +01:00
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
2024-03-19 17:02:38 +01:00
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
2024-03-27 14:35:55 +01:00
exportFig('figs/test_struts_comp_enc_plants.pdf', 'width', 'wide', 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+name: fig:test_struts_comp_enc_plants
#+caption: Estimated FRF for the DVF plant (transfer function from $u$ to the encoder $d_e$)
2024-03-19 17:02:38 +01:00
#+RESULTS:
2024-03-27 14:35:55 +01:00
[[file:figs/test_struts_comp_enc_plants.png]]
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
** Conclusion :ignore:
2024-03-19 17:02:38 +01:00
#+begin_important
2024-03-27 14:35:55 +01:00
All the struts are giving very consistent behavior from the excitation voltage $u$ to the force sensor generated voltage $V_s$ and to the interferometer measured displacement $d_a$.
However, the dynamics from $u$ to the encoder measurement $d_e$ is much more complex and variable from one strut to the other most likely due to poor alignment of the APA with respect to the flexible joints.
2024-03-25 14:42:03 +01:00
#+end_important
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports none
%% Save the estimated FRF for further analysis
save('./matlab/mat/meas_struts_frf.mat', 'f', 'enc_frf', 'int_frf', 'iff_frf', 'strut_nums');
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :eval no
%% Save the estimated FRF for further analysis
save('./mat/meas_struts_frf.mat', 'f', 'enc_frf', 'int_frf', 'iff_frf', 'strut_nums');
2024-03-19 17:02:38 +01:00
#+end_src
* Simscape Model
:PROPERTIES:
2024-03-25 10:55:31 +01:00
:header-args:matlab+: :tangle matlab/test_struts_3_simscape_model.m
2024-03-19 17:02:38 +01:00
:END:
2024-03-25 10:55:31 +01:00
<<sec:test_struts_simscape>>
2024-03-19 17:02:38 +01:00
** Introduction :ignore:
2024-03-25 10:55:31 +01:00
However, now the full strut is put instead of only the APA (see Figure ref:fig:test_struts_simscape_model).
2024-03-19 17:02:38 +01:00
2024-03-25 10:55:31 +01:00
#+name: fig:test_struts_simscape_model
2024-03-19 17:02:38 +01:00
#+caption: Screenshot of the Simscape model of the strut fixed to the bench
2024-03-25 16:33:38 +01:00
#+attr_latex: :width 0.7\linewidth
2024-03-25 10:55:31 +01:00
[[file:figs/test_struts_simscape_model.png]]
2024-03-19 17:02:38 +01:00
This Simscape model is used to:
- compare the measured FRF with the modelled FRF
- help the correct understanding/interpretation of the results
- tune the model of the struts (APA, flexible joints, encoder)
This study is structured as follow:
2024-03-25 14:42:03 +01:00
- Section ref:ssec:test_struts_comp_model: the measured FRF are compared with the Simscape model.
- Section ref:ssec:test_struts_effect_misalignment: the flexible APA model is used, and the effect of a misalignment of the APA and flexible joints is studied.
It is found that the misalignment has a large impact on the dynamics from $u$ to $d_e$.
- Section ref:ssec:test_struts_effect_joint_stiffness: the effect of the flexible joint's stiffness on the dynamics is studied.
2024-03-19 17:02:38 +01:00
It is found that the axial stiffness of the joints has a large impact on the location of the zeros on the transfer function from $V_s$ to $d_e$.
2024-03-25 14:42:03 +01:00
** Matlab Init :noexport:ignore:
2024-03-19 17:02:38 +01:00
#+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
2024-03-25 14:42:03 +01:00
#+begin_src matlab :tangle no :noweb yes
<<m-init-path>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 14:42:03 +01:00
#+begin_src matlab :eval no :noweb yes
<<m-init-path-tangle>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 14:42:03 +01:00
#+begin_src matlab :tangle no :noweb yes
<<m-init-path-simscape>>
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 14:42:03 +01:00
#+begin_src matlab :eval no :noweb yes
<<m-init-path-simscape-tangle>>
#+end_src
2024-03-19 17:02:38 +01:00
2024-03-25 14:42:03 +01:00
#+begin_src matlab :noweb yes
<<m-init-other>>
#+end_src
#+begin_src matlab :exports none
%% Input/Output definition of the Model
clear io; io_i = 1;
io(io_i) = linio([mdl, '/u'], 1, 'openinput'); io_i = io_i + 1; % DAC Voltage
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage
io(io_i) = linio([mdl, '/de'], 1, 'openoutput'); io_i = io_i + 1; % Encoder
io(io_i) = linio([mdl, '/da'], 1, 'openoutput'); io_i = io_i + 1; % Interferometer
#+end_src
2024-03-19 17:02:38 +01:00
2024-03-25 14:42:03 +01:00
#+begin_src matlab
2024-03-27 14:35:55 +01:00
freqs = logspace(1, log10(2000), 1000);
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-25 14:42:03 +01:00
** Comparison with the Model
<<ssec:test_struts_comp_model>>
2024-03-19 17:02:38 +01:00
#+begin_src matlab
2024-03-27 14:35:55 +01:00
%% Load measured FRF for comparison
load('meas_struts_frf.mat', 'f', 'enc_frf', 'int_frf', 'iff_frf', 'strut_nums');
%% Initialize strut with 2DoF model for the APA300ML and identify the dynamics
2024-03-19 17:02:38 +01:00
n_hexapod = struct();
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof');
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof');
n_hexapod.actuator = initializeAPA('type', '2dof');
2024-03-25 14:42:03 +01:00
c_granite = 0; % Do not take into account damping added by the air bearing
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
% Run the linearization
Gs_2dof = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
Gs_2dof.InputName = {'u'};
Gs_2dof.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
%% Initialize strut with "flexible" model for the APA300ML and identify the dynamics
n_hexapod = struct();
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof');
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof');
n_hexapod.actuator = initializeAPA('type', 'flexible');
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
c_granite = 100; % Do not take into account damping added by the air bearing
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
% Run the linearization
Gs_flex = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
Gs_flex.InputName = {'u'};
Gs_flex.OutputName = {'Vs', 'de', 'da'};
#+end_src
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
Two models of the APA300ML are used here for comparison:
- a simple two degrees of freedom model
- a model using a super element extracted from a finite element model
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
These two models of the APA300ML were tuned to best match measured frequency response functions of the APA alone.
The flexible joints are here modelled with the 4DoF model (axial stiffness, two bending stiffnesses and one torsion stiffness).
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
These two models are compared with the measured frequency responses in Figure ref:fig:test_struts_comp_frf_flexible_model.
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
The model dynamics from DAC voltage $u$ to the axial motion of the strut $d_a$ (Figure ref:fig:test_struts_comp_frf_flexible_model_int) and from DAC voltage $u$ to the force sensor voltage $V_s$ (Figure ref:fig:test_struts_comp_frf_flexible_model_iff) are well matching the experimental identification.
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
However, the transfer function from $u$ to encoder displacement $d_e$ are not well matching for both models.
For the 2DoF model, this is normal as the resonances affecting the dynamics are not modelled at all (the APA300ML is modelled as infinitely rigid in all directions except the translation along it's actuation axis).
For the flexible model, it will be shown in the next section that by adding some misalignment betwen the flexible joints and the APA300ML, this model can better represent the observed dynamics.
2024-03-19 17:02:38 +01:00
#+begin_src matlab :exports none
2024-03-25 14:42:03 +01:00
%% Compare the FRF and identified dynamics from u to Vs and da
2024-03-19 17:02:38 +01:00
figure;
2024-03-27 14:35:55 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
ax1a = nexttile([2,1]);
2024-03-19 17:02:38 +01:00
hold on;
plot(f, abs(int_frf(:, 1)), 'color', [0,0,0,0.2], ...
2024-03-27 14:35:55 +01:00
'DisplayName', 'FRF');
2024-03-25 14:42:03 +01:00
for i = 2:length(strut_nums)
2024-03-19 17:02:38 +01:00
plot(f, abs(int_frf(:, i)), 'color', [0,0,0,0.2], ...
'HandleVisibility', 'off');
end
2024-03-27 14:35:55 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_2dof('da', 'u'), freqs, 'Hz'))), '-', ...
'color', colors(1,:), 'DisplayName', '2DoF Model')
plot(freqs, abs(squeeze(freqresp(Gs_flex('da', 'u'), freqs, 'Hz'))), '-', ...
'color', colors(2,:), 'DisplayName', 'Flex. Model')
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_a/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
2024-03-27 14:35:55 +01:00
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1);
leg.ItemTokenSize(1) = 15
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
ax2a = nexttile;
2024-03-19 17:02:38 +01:00
hold on;
2024-03-25 14:42:03 +01:00
for i = 1:length(strut_nums)
2024-03-19 17:02:38 +01:00
plot(f, 180/pi*angle(int_frf(:, i)), 'color', [0,0,0,0.2]);
end
2024-03-27 14:35:55 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_2dof('da', 'u'), freqs, 'Hz'))), '-', 'color', colors(1,:))
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('da', 'u'), freqs, 'Hz'))), '-', 'color', colors(2,:))
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
2024-03-27 14:35:55 +01:00
linkaxes([ax1a,ax2a],'x');
2024-03-19 17:02:38 +01:00
xlim([10, 2e3]);
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_comp_frf_flexible_model_int.pdf', 'width', 400, 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
#+begin_src matlab :exports none
2024-03-27 14:35:55 +01:00
%% Compare the FRF and identified dynamics from u to Vs and da
2024-03-19 17:02:38 +01:00
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
ax1a = nexttile([2,1]);
2024-03-19 17:02:38 +01:00
hold on;
plot(f, abs(enc_frf(:, 1)), 'color', [0,0,0,0.2], ...
2024-03-27 14:35:55 +01:00
'DisplayName', 'FRF');
2024-03-25 14:42:03 +01:00
for i = 2:length(strut_nums)
2024-03-19 17:02:38 +01:00
plot(f, abs(enc_frf(:, i)), 'color', [0,0,0,0.2], ...
'HandleVisibility', 'off');
end
2024-03-27 14:35:55 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_2dof('de', 'u'), freqs, 'Hz'))), '-', ...
'color', colors(1,:), 'DisplayName', '2DoF Model')
plot(freqs, abs(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), '-', ...
'color', colors(2,:), 'DisplayName', 'Flex. Model')
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
2024-03-27 14:35:55 +01:00
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1);
leg.ItemTokenSize(1) = 15
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
ax2a = nexttile;
2024-03-19 17:02:38 +01:00
hold on;
2024-03-25 14:42:03 +01:00
for i = 1:length(strut_nums)
2024-03-19 17:02:38 +01:00
plot(f, 180/pi*angle(enc_frf(:, i)), 'color', [0,0,0,0.2]);
end
2024-03-27 14:35:55 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_2dof('de', 'u'), freqs, 'Hz'))), '-', 'color', colors(1,:))
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), '-', 'color', colors(2,:))
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
2024-03-27 14:35:55 +01:00
linkaxes([ax1a,ax2a],'x');
xlim([10, 2e3]);
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_comp_frf_flexible_model_enc.pdf', 'width', 400, 'height', 'tall');
2024-03-19 17:02:38 +01:00
#+end_src
#+begin_src matlab :exports none
2024-03-25 14:42:03 +01:00
%% Compare the FRF and identified dynamics from u to Vs and da
2024-03-19 17:02:38 +01:00
figure;
2024-03-27 14:35:55 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
ax1a = nexttile([2,1]);
2024-03-19 17:02:38 +01:00
hold on;
2024-03-27 14:35:55 +01:00
plot(f, abs(iff_frf(:, i)), 'color', [0,0,0,0.2], ...
'DisplayName', 'FRF');
2024-03-25 14:42:03 +01:00
for i = 1:length(strut_nums)
2024-03-27 14:35:55 +01:00
plot(f, abs(iff_frf(:, i)), 'color', [0,0,0,0.2], ...
2024-03-19 17:02:38 +01:00
'HandleVisibility', 'off');
end
2024-03-27 14:35:55 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_2dof('Vs', 'u'), freqs, 'Hz'))), '-', ...
'color', colors(1,:), 'DisplayName', '2DoF Model')
plot(freqs, abs(squeeze(freqresp(Gs_flex('Vs', 'u'), freqs, 'Hz'))), '-', ...
'color', colors(2,:), 'DisplayName', 'Flex. Model')
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $V_s/u$ [V/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-2, 1e2]);
2024-03-27 14:35:55 +01:00
leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1);
leg.ItemTokenSize(1) = 15
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
ax2a = nexttile;
2024-03-19 17:02:38 +01:00
hold on;
2024-03-25 14:42:03 +01:00
for i = 1:length(strut_nums)
2024-03-27 14:35:55 +01:00
plot(f, 180/pi*angle(iff_frf(:, i)), 'color', [0,0,0,0.2]);
2024-03-19 17:02:38 +01:00
end
set(gca,'ColorOrderIndex',1);
2024-03-27 14:35:55 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_2dof('Vs', 'u'), freqs, 'Hz'))), '-', 'color', colors(1,:))
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('Vs', 'u'), freqs, 'Hz'))), '-', 'color', colors(2,:))
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
2024-03-27 14:35:55 +01:00
linkaxes([ax1a,ax2a],'x');
2024-03-19 17:02:38 +01:00
xlim([10, 2e3]);
#+end_src
2024-03-27 14:35:55 +01:00
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/test_struts_comp_frf_flexible_model_iff.pdf', 'width', 400, 'height', 'tall');
#+end_src
#+name: fig:test_struts_comp_frf_flexible_model
#+caption: Comparison of the measured dynamics and of the Simscape dynamics using the "flexible" APA300ML model (Super-Element extracted from a Finite Element Model).
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_frf_flexible_model_int}$u$ to $d_a$}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_comp_frf_flexible_model_int.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_frf_flexible_model_enc}$u$ to $d_e$}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_comp_frf_flexible_model_enc.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_frf_flexible_model_iff}$u$ to $V_s$}
#+attr_latex: :options {0.33\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.9\linewidth
[[file:figs/test_struts_comp_frf_flexible_model_iff.png]]
#+end_subfigure
#+end_figure
** Effect of a misalignment of the APA and flexible joints on the transfer function from actuator to encoder
<<ssec:test_struts_effect_misalignment>>
*** Introduction :ignore:
As shown in Figure ref:fig:test_struts_comp_enc_plants, the dynamics from actuator to encoder for all the struts is very different.
This could be explained by a large variability in the alignment of the flexible joints and the APA (at the time, the alignment pins were not used).
Depending on the alignment, the spurious resonances of the struts (Figure ref:fig:test_struts_mode_shapes) can be excited differently.
For instance, consider Figure ref:fig:test_struts_misalign_schematic where there is a misalignment in the $y$ direction.
In such case, the mode at 200Hz is foreseen to be more excited as the misalignment $d_y$ increases and therefore the dynamics from the actuator to the encoder should also change around 200Hz.
#+name: fig:test_struts_misalign_schematic
#+caption: Mis-alignement between the joints and the APA
#+attr_latex: :width 0.8\linewidth
[[file:figs/test_struts_misalign_schematic.png]]
If the misalignment is in the $x$ direction, the mode at 285Hz should be more affected whereas a misalignment in the $z$ direction should not affect these resonances.
Such statement is studied in this section.
*** Measured misalignment of the APA and flexible joints
The misalignment between the two flexible joints and the APA has been measured for all the struts:
- the strut is fixed to the mounting bench
- using an indicator, the height difference from the flexible joints and the APA is measured both for the top and bottom joints and on both sides
- then it is possible to obtain the misalignment for both flexible joints
The raw measurements are shown in Table ref:tab:meas_misalignment_struts_raw.
As the flexible joint's "thickness" is 1mm larger than the APA "thickness", ideally (i.e. if it were perfectly centered) we would measure =-0.50mm= each time.
#+begin_src matlab
strut_nums = [1, 2, 3, 4, 5];
% R Top B Top R Bot B Bot
strut_align = [[-0.40, -0.60, -0.16, -0.82] % Strut 1
[-0.67, -0.30, -0.34, -0.63] % Strut 2
[-0.07, -0.88, -0.16, -0.79] % Strut 3
[-0.48, -0.46, 0.07, -1.00] % Strut 4
[-0.33, -0.64, -0.48, -0.52]]; % Strut 5
#+end_src
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable(strut_align, {'1', '2', '3', '4', '5'}, {'*Strut*', '*R Top*', '*B Top*', '*R Bot*', '*B Bot*'}, ' %.2f ');
2024-03-19 17:02:38 +01:00
#+end_src
2024-03-27 14:35:55 +01:00
#+name: tab:meas_misalignment_struts_raw
#+caption: Measured misalignments of the struts (=R= means "red" side, and =B= means "black side") in [mm]
#+attr_latex: :environment tabularx :width 0.4\linewidth :align cllll
#+attr_latex: :center t :booktabs t :float t
2024-03-19 17:02:38 +01:00
#+RESULTS:
2024-03-27 14:35:55 +01:00
| *Strut* | *R Top* | *B Top* | *R Bot* | *B Bot* |
|---------+---------+---------+---------+---------|
| 1 | -0.4 | -0.6 | -0.16 | -0.82 |
| 2 | -0.67 | -0.3 | -0.34 | -0.63 |
| 3 | -0.07 | -0.88 | -0.16 | -0.79 |
| 4 | -0.48 | -0.46 | 0.07 | -1.0 |
| 5 | -0.33 | -0.64 | -0.48 | -0.52 |
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
Also, the sum of the measured distances on each side should be 1mm (equal to the thickness difference between the flexible joint and the APA).
This is verified in Table ref:tab:meas_misalignment_struts_thickness.
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable([strut_align(:,1) + strut_align(:,2), strut_align(:,3) + strut_align(:,4)], {'1', '2', '3', '4', '5'}, {'*Strut*', '*Top*', '*Bot*'}, ' %.2f ');
#+end_src
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
#+name: tab:meas_misalignment_struts_thickness
#+caption: Measured thickness difference between the flexible joints and the APA in [mm]
#+attr_latex: :environment tabularx :width 0.2\linewidth :align cll
#+attr_latex: :center t :booktabs t :float t
#+RESULTS:
| *Strut* | *Top* | *Bot* |
|---------+-------+-------|
| 1 | -1.0 | -0.98 |
| 2 | -0.97 | -0.97 |
| 3 | -0.95 | -0.95 |
| 4 | -0.94 | -0.93 |
| 5 | -0.97 | -1.0 |
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
The differences of the measured distances on each side corresponds to the misalignment on that same side (Table ref:tab:meas_misalignment_struts_results).
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable([(strut_align(:,1) - strut_align(:,2))/2, (strut_align(:,3) - strut_align(:,4))/2], {'1', '2', '3', '4', '5'}, {'*Strut*', '*Top*', '*Bot*'}, ' %.3f ');
#+end_src
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
#+name: tab:meas_misalignment_struts_results
#+caption: Measured thickness difference between the flexible joints and the APA in [mm]
#+attr_latex: :environment tabularx :width 0.25\linewidth :align cll
#+attr_latex: :center t :booktabs t :float t
#+RESULTS:
| *Strut* | *Top* | *Bot* |
|---------+--------+-------|
| 1 | 0.1 | 0.33 |
| 2 | -0.185 | 0.145 |
| 3 | 0.405 | 0.315 |
| 4 | -0.01 | 0.535 |
| 5 | 0.155 | 0.02 |
2024-03-19 17:02:38 +01:00
2024-03-27 14:35:55 +01:00
#+begin_important
The misalignment of the APA and flexible joints is quite large and variable from one strut to the other.
#+end_important
2024-03-19 17:02:38 +01:00
*** Perfectly aligned APA
Let's first consider that the strut is perfectly mounted such that the two flexible joints and the APA are aligned.
#+begin_src matlab
%% Initialize Simscape data
n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof');
n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof');
n_hexapod.actuator = initializeAPA('type', 'flexible');
#+end_src
And define the inputs and outputs of the models:
- Input: voltage generated by the DAC
- Output: measured displacement by the encoder
The transfer function is identified and shown in Figure ref:fig:comp_enc_frf_align_perfect.
#+begin_src matlab
%% Identification
2024-03-25 14:42:03 +01:00
Gs = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
Gs.InputName = {'u'};
Gs.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
#+end_src
From Figure ref:fig:comp_enc_frf_align_perfect, it is clear that:
1. The model with perfect alignment is not matching the measured FRF
2. The mode at 200Hz is not present in the identified dynamics of the Simscape model
3. The measured FRF have different shapes
#+begin_src matlab :exports none
%% Measured FRF from Vs to de and identified dynamics using the flexible APA
freqs = 2*logspace(0, 3, 1000);
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
plot(f, abs(enc_frf(:, i)), 'color', [0,0,0,0.2], ...
'DisplayName', 'Meas. FRF');
2024-03-25 14:42:03 +01:00
for i = 2:length(strut_nums)
2024-03-19 17:02:38 +01:00
plot(f, abs(enc_frf(:, i)), 'color', [0,0,0,0.2], ...
'HandleVisibility', 'off');
end
set(gca,'ColorOrderIndex',1);
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs('de', 'u'), freqs, 'Hz'))), '-', ...
2024-03-19 17:02:38 +01:00
'DisplayName', 'Model')
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
legend('location', 'northeast');
ax2 = nexttile;
hold on;
2024-03-25 14:42:03 +01:00
for i = 1:length(strut_nums)
2024-03-19 17:02:38 +01:00
plot(f, 180/pi*angle(enc_frf(:, i)), 'color', [0,0,0,0.2]);
end
set(gca,'ColorOrderIndex',1);
2024-03-25 14:42:03 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('de', 'u'), freqs, 'Hz'))), '-')
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/comp_enc_frf_align_perfect.pdf', 'width', 'wide', 'height', 'tall');
#+end_src
#+name: fig:comp_enc_frf_align_perfect
#+caption: Comparison of the model with a perfectly aligned APA and flexible joints with the measured FRF from actuator to encoder
#+RESULTS:
[[file:figs/comp_enc_frf_align_perfect.png]]
#+begin_question
Why is the flexible mode of the strut at 200Hz is not seen in the model in Figure ref:fig:comp_enc_frf_align_perfect?
Probably because the presence of this mode is not due because of the "unbalanced" mass of the encoder, but rather because of the misalignment of the APA with respect to the two flexible joints.
This will be verified in the next sections.
#+end_question
*** Effect of a misalignment in y
Let's compute the transfer function from output DAC voltage $V_s$ to the measured displacement by the encoder $d_e$ for several misalignment in the $y$ direction:
#+begin_src matlab
%% Considered misalignments
dy_aligns = [-0.5, -0.1, 0, 0.1, 0.5]*1e-3; % [m]
#+end_src
#+begin_src matlab
%% Transfer functions from u to de for all the misalignment in y direction
Gs_align = {zeros(length(dy_aligns), 1)};
for i = 1:length(dy_aligns)
2024-03-25 14:42:03 +01:00
n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_bot', [0; dy_aligns(i); 0], 'd_align_top', [0; dy_aligns(i); 0]);
2024-03-19 17:02:38 +01:00
2024-03-25 14:42:03 +01:00
G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
G.InputName = {'u'};
G.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
Gs_align(i) = {G};
end
#+end_src
The obtained dynamics are shown in Figure ref:fig:effect_misalignment_y.
#+begin_src matlab :exports none
%% Transfer function from Vs to de - effect of x-misalignment
freqs = 2*logspace(0, 3, 1000);
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
for i = 1:length(dy_aligns)
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{i}('de', 'u'), freqs, 'Hz'))), ...
2024-03-19 17:02:38 +01:00
'DisplayName', sprintf('$d_y = %.1f$ [mm]', 1e3*dy_aligns(i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
legend('location', 'northeast');
ax2 = nexttile;
hold on;
for i = 1:length(dy_aligns)
2024-03-25 14:42:03 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_align{i}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/effect_misalignment_y.pdf', 'width', 'wide', 'height', 'tall');
#+end_src
#+name: fig:effect_misalignment_y
#+caption: Effect of a misalignement in the $y$ direction
#+RESULTS:
[[file:figs/effect_misalignment_y.png]]
#+begin_important
The alignment of the APA with the flexible joints as a *huge* influence on the dynamics from actuator voltage to measured displacement by the encoder.
The misalignment in the $y$ direction mostly influences:
- the presence of the flexible mode at 200Hz
- the location of the complex conjugate zero between the first two resonances:
- if $d_y < 0$: there is no zero between the two resonances and possibly not even between the second and third ones
- if $d_y > 0$: there is a complex conjugate zero between the first two resonances
- the location of the high frequency complex conjugate zeros at 500Hz (secondary effect, as the axial stiffness of the joint also has large effect on the position of this zero)
#+end_important
*** Effect of a misalignment in x
Let's compute the transfer function from output DAC voltage to the measured displacement by the encoder for several misalignment in the $x$ direction:
#+begin_src matlab
%% Considered misalignments
dx_aligns = [-0.1, -0.05, 0, 0.05, 0.1]*1e-3; % [m]
#+end_src
#+begin_src matlab
%% Transfer functions from u to de for all the misalignment in x direction
Gs_align = {zeros(length(dx_aligns), 1)};
for i = 1:length(dx_aligns)
2024-03-25 14:42:03 +01:00
n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_bot', [dx_aligns(i); 0; 0], 'd_align_top', [dx_aligns(i); 0; 0]);
2024-03-19 17:02:38 +01:00
2024-03-25 14:42:03 +01:00
G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
G.InputName = {'u'};
G.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
Gs_align(i) = {G};
end
#+end_src
The obtained dynamics are shown in Figure ref:fig:effect_misalignment_x.
#+begin_src matlab :exports none
%% Transfer function from Vs to de - effect of x-misalignment
freqs = 2*logspace(0, 3, 1000);
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
for i = 1:length(dx_aligns)
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{i}('de', 'u'), freqs, 'Hz'))), ...
2024-03-19 17:02:38 +01:00
'DisplayName', sprintf('$d_x = %.2f$ [mm]', 1e3*dx_aligns(i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
legend('location', 'northeast');
ax2 = nexttile;
hold on;
for i = 1:length(dx_aligns)
2024-03-25 14:42:03 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_align{i}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/effect_misalignment_x.pdf', 'width', 'wide', 'height', 'tall');
#+end_src
#+name: fig:effect_misalignment_x
#+caption: Effect of a misalignement in the $x$ direction
#+RESULTS:
[[file:figs/effect_misalignment_x.png]]
#+begin_important
The misalignment in the $x$ direction mostly influences the presence of the flexible mode at 300Hz.
#+end_important
2024-03-25 14:42:03 +01:00
*** Comparison with identified misalignment
#+begin_src matlab
strut_align = 1e-3*[[-0.60, -0.82, -0.40, -0.16]
[-0.30, -0.63, -0.67, -0.34]
[-0.88, -0.79, -0.07, -0.16]
[-0.48, 0.07, -0.46, -1.00]
[-0.33, -0.48, -0.64, -0.52]
[-0.34, -0.42, -0.63, -0.57]];
#+end_src
#+begin_src matlab
%% Idenfity the transfer function from actuator to encoder for all cases
Gs_align = {zeros(size(strut_align,1), 1)};
for i = 1:size(strut_align,1)
n_hexapod.actuator = initializeAPA('type', 'flexible', ...
'd_align_bot', [0; strut_align(i, 2) - strut_align(i, 4); 0], ...
'd_align_top', [0; strut_align(i, 1) - strut_align(i, 3); 0]);
G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
G.InputName = {'u'};
G.OutputName = {'Vs', 'de', 'da'};
Gs_align(i) = {G};
end
#+end_src
#+begin_src matlab :exports none
%% Comparison of the plants (encoder output) when tuning the misalignment
freqs = 2*logspace(0, 3, 1000);
figure;
tiledlayout(2, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile();
hold on;
plot(f, abs(enc_frf(:, 1)));
plot(freqs, abs(squeeze(freqresp(Gs_align{1}('de', 'u'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/V]');
ax2 = nexttile();
hold on;
plot(f, abs(enc_frf(:, 2)));
plot(freqs, abs(squeeze(freqresp(Gs_align{2}('de', 'u'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
ax3 = nexttile(4);
hold on;
plot(f, abs(enc_frf(:, 3)), 'DisplayName', 'Meas.');
plot(freqs, abs(squeeze(freqresp(Gs_align{3}('de', 'u'), freqs, 'Hz'))), ...
'DisplayName', 'Model');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]');
legend('location', 'southwest', 'FontSize', 8);
ax4 = nexttile(5);
hold on;
plot(f, abs(enc_frf(:, 4)));
plot(freqs, abs(squeeze(freqresp(Gs_align{4}('de', 'u'), freqs, 'Hz'))));
hold off;
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ax5 = nexttile(6);
hold on;
plot(f, abs(enc_frf(:, 5)));
plot(freqs, abs(squeeze(freqresp(Gs_align{5}('de', 'u'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
linkaxes([ax1,ax2,ax3,ax4,ax5],'xy');
xlim([20, 2e3]); ylim([1e-8, 1e-3]);
#+end_src
2024-03-19 17:02:38 +01:00
*** Find the misalignment of each strut
From the previous analysis on the effect of a $x$ and $y$ misalignment, it is possible to estimate the $x,y$ misalignment of the measured struts.
The misalignment that gives the best match for the FRF are defined below.
#+begin_src matlab
%% Tuned misalignment [m]
d_aligns = [[-0.05, -0.3, 0];
[ 0, 0.5, 0];
[-0.1, -0.3, 0];
[ 0, 0.3, 0];
[-0.05, 0.05, 0]]'*1e-3;
#+end_src
For each misalignment, the dynamics from the DAC voltage to the encoder measurement is identified.
#+begin_src matlab
%% Idenfity the transfer function from actuator to encoder for all cases
Gs_align = {zeros(size(d_aligns,2), 1)};
for i = 1:5
n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_top', d_aligns(:,i), 'd_align_bot', d_aligns(:,i));
2024-03-25 14:42:03 +01:00
G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
G.InputName = {'u'};
G.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
Gs_align(i) = {G};
end
#+end_src
The results are shown in Figure ref:fig:comp_all_struts_corrected_misalign.
#+begin_src matlab :exports none
%% Comparison of the plants (encoder output) when tuning the misalignment
freqs = 2*logspace(0, 3, 1000);
figure;
tiledlayout(2, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile();
hold on;
plot(f, abs(enc_frf(:, 1)));
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{1}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/V]');
ax2 = nexttile();
hold on;
plot(f, abs(enc_frf(:, 2)));
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{2}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
2024-03-25 14:42:03 +01:00
ax3 = nexttile();
2024-03-19 17:02:38 +01:00
hold on;
plot(f, abs(enc_frf(:, 3)), 'DisplayName', 'Meas.');
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{3}('de', 'u'), freqs, 'Hz'))), ...
2024-03-19 17:02:38 +01:00
'DisplayName', 'Model');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]');
legend('location', 'southwest', 'FontSize', 8);
ax4 = nexttile(5);
hold on;
plot(f, abs(enc_frf(:, 4)));
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{4}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
hold off;
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ax5 = nexttile(6);
hold on;
plot(f, abs(enc_frf(:, 5)));
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{5}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
linkaxes([ax1,ax2,ax3,ax4,ax5],'xy');
xlim([20, 2e3]); ylim([1e-8, 1e-3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/comp_all_struts_corrected_misalign.pdf', 'width', 'full', 'height', 'tall');
#+end_src
#+name: fig:comp_all_struts_corrected_misalign
#+caption: Comparison (model and measurements) of the FRF from DAC voltage u to measured displacement by the encoders for all the struts
#+RESULTS:
[[file:figs/comp_all_struts_corrected_misalign.png]]
#+begin_important
By tuning the misalignment of the APA with respect to the flexible joints, it is possible to obtain a good fit between the model and the measurements (Figure ref:fig:comp_all_struts_corrected_misalign).
If encoders are to be used when fixed on the struts, it is therefore very important to properly align the APA and the flexible joints when mounting the struts.
In the future, a "pin" will be used to better align the APA with the flexible joints.
We can expect the amplitude of the spurious resonances to decrease.
#+end_important
*** Paper :noexport:
#+begin_src matlab :exports none
%% Comparison of the plants (encoder output) when tuning the misalignment
freqs = 2*logspace(0, 3, 1000);
colors = colororder;
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
plot(f, abs(enc_frf(:,1)), 'color', [colors(1,:),0.2], ...
'DisplayName', 'FRF - $d_{e,i}/V_{a,i}$')
for i = 2:5
plot(f, abs(enc_frf(:,i)), 'color', [colors(1,:),0.2], ...
'HandleVisibility', 'off');
end
plot(f, abs(int_frf(:,1)), 'color', [colors(2,:),0.2], ...
'DisplayName', 'FRF - $d_{a,i}/V_{a,i}$')
for i = 2:5
plot(f, abs(int_frf(:,i)), 'color', [colors(2,:),0.2], ...
'HandleVisibility', 'off');
end
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{1}('de', 'u'), freqs, 'Hz'))), '--', 'color', colors(1,:), ...
2024-03-19 17:02:38 +01:00
'DisplayName', 'Model - $d_{e,i}/V_{a,i}$')
for i = 2:5
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs_align{i}('de', 'u'), freqs, 'Hz'))), '--', 'color', colors(1,:), ...
2024-03-19 17:02:38 +01:00
'HandleVisibility', 'off');
end
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs('da', 'u'), freqs, 'Hz'))), '--', 'color', colors(2,:), ...
2024-03-19 17:02:38 +01:00
'DisplayName', 'Model - $d_{a,i}/V_{a,i}$')
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/V]');
ylim([1e-8, 1e-3]);
legend('location', 'southwest')
ax2 = nexttile;
hold on;
for i = 1:5
plot(f, 180/pi*angle(enc_frf(:,i)), 'color', [colors(1,:),0.2]);
2024-03-25 14:42:03 +01:00
plot(f, 180/pi*(angle(int_frf(:, i)) - angle(squeeze(freqresp(exp(-s*2*1e-4), f, 'Hz')))), 'color', [colors(2,:),0.2]);
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_align{i}('de', 'u'), freqs, 'Hz'))), '--', 'color', colors(1,:));
2024-03-19 17:02:38 +01:00
end
2024-03-25 14:42:03 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('da', 'u'), freqs, 'Hz'))), '--', 'color', colors(2,:));
2024-03-19 17:02:38 +01:00
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
ylabel('Phase [deg]'); xlabel('Frequency [Hz]');
ylim([-180, 180]);
yticks([-180, -90, 0, 90, 180]);
linkaxes([ax1,ax2],'x');
xlim([20, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/frf_struts_enc_int.pdf', 'width', 'normal', 'height', 'full');
#+end_src
#+name: fig:frf_struts_enc_int
#+caption:
#+RESULTS:
[[file:figs/frf_struts_enc_int.png]]
2024-03-27 14:35:55 +01:00
** TODO Comparison of all the (re-aligned) Struts
<<sec:test_struts_meas_all_aligned_struts>>
- [ ] Should this be included here?
*** Introduction :ignore:
The struts are re-aligned and measured using the same test bench.
*** Measured misalignment of the APA and flexible joints
The misalignment between the APA and the flexible joints are measured.
The results are defined below and summarized in Table ref:tab:meas_misalignment_struts_new_raw.
#+begin_src matlab
% R Top B Top R Bot B Bot
strut_align = [[-0.54, -0.50, -0.50, -0.52] % strut 1
[-0.44, -0.55, -0.49, -0.49] % strut 2
[-0.48, -0.50, -0.50, -0.46] % strut 3
[-0.45, -0.51, -0.51, -0.45] % strut 4
[-0.50, -0.50, -0.50, -0.50] % strut 5
[-0.50, -0.49, -0.43, -0.54]]; % strut 6
#+end_src
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable(strut_align, {'1', '2', '3', '4', '5', '6'}, {'*Strut*', '*R Top*', '*B Top*', '*R Bot*', '*B Bot*'}, ' %.2f ');
#+end_src
#+name: tab:meas_misalignment_struts_new_raw
#+caption: Measured misalignments of the struts (=R= means "red" side, and =B= means "black side") in [mm]
#+attr_latex: :environment tabularx :width 0.45\linewidth :align cllll
#+attr_latex: :center t :booktabs t :float t
#+RESULTS:
| *Strut* | *R Top* | *B Top* | *R Bot* | *B Bot* |
|---------+---------+---------+---------+---------|
| 1 | -0.54 | -0.5 | -0.5 | -0.52 |
| 2 | -0.44 | -0.55 | -0.49 | -0.49 |
| 3 | -0.48 | -0.5 | -0.5 | -0.46 |
| 4 | -0.45 | -0.51 | -0.51 | -0.45 |
| 5 | -0.5 | -0.5 | -0.5 | -0.5 |
| 6 | -0.5 | -0.49 | -0.43 | -0.54 |
Also, the sum of the measured distances on each side should be 1mm (equal to the thickness difference between the flexible joint and the APA).
This is verified in Table ref:tab:meas_misalignment_struts_new_thickness.
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable([strut_align(:,1) + strut_align(:,2), strut_align(:,3) + strut_align(:,4)], {'1', '2', '4', '5', '6', '8'}, {'*APA*', '*Top*', '*Bot*'}, ' %.2f ');
#+end_src
#+name: tab:meas_misalignment_struts_new_thickness
#+caption: Measured thickness difference between the flexible joints and the APA in [mm]
#+attr_latex: :environment tabularx :width 0.2\linewidth :align cll
#+attr_latex: :center t :booktabs t :float t
#+RESULTS:
| *APA* | *Top* | *Bot* |
|-------+-------+-------|
| 1 | -1.04 | -1.02 |
| 2 | -0.99 | -0.98 |
| 4 | -0.98 | -0.96 |
| 5 | -0.96 | -0.96 |
| 6 | -1.0 | -1.0 |
| 8 | -0.99 | -0.97 |
The differences of the measured distances on each side corresponds to the misalignment on that same side (Table ref:tab:meas_misalignment_struts_new_results).
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable([(strut_align(:,1) - strut_align(:,2))/2, (strut_align(:,3) - strut_align(:,4))/2], {'1', '2', '4', '5', '6', '8'}, {'*APA*', '*Top*', '*Bot*'}, ' %.3f ');
#+end_src
#+name: tab:meas_misalignment_struts_new_results
#+caption: Measured thickness difference between the flexible joints and the APA in [mm]
#+attr_latex: :environment tabularx :width 0.25\linewidth :align cll
#+attr_latex: :center t :booktabs t :float t
#+RESULTS:
| *APA* | *Top* | *Bot* |
|-------+--------+-------|
| 1 | -0.02 | 0.01 |
| 2 | 0.055 | 0.0 |
| 4 | 0.01 | -0.02 |
| 5 | 0.03 | -0.03 |
| 6 | 0.0 | 0.0 |
| 8 | -0.005 | 0.055 |
#+begin_important
After using the alignment pins, the misalignment of the APA and flexible joints are much smaller ($< 50\,\mu m$ for all the struts).
#+end_important
*** FRF Identification - Setup
The excitation signal is a low pass filtered white noise.
Both the encoder and the force sensor voltage are measured.
Here are the leg numbers that have been measured.
#+begin_src matlab
%% Numnbers of the measured legs
strut_nums = [1 2 3 4 5 6];
#+end_src
#+begin_src matlab
%% First identification (low frequency noise)
leg_noise = {};
for i = 1:length(strut_nums)
leg_noise(i) = {load(sprintf('frf_struts_align_%i_noise.mat', strut_nums(i)), 'u', 'Vs', 'de')};
end
#+end_src
#+begin_src matlab
Ts = 1e-4; % Sampling Time [s]
Nfft = floor(1/Ts);
win = hanning(Nfft);
Noverlap = floor(Nfft/2);
#+end_src
We get the frequency vector that will be the same for all the frequency domain analysis.
#+begin_src matlab
% Only used to have the frequency vector "f"
[~, f] = tfestimate(leg_noise{1}.u, leg_noise{1}.de, win, Noverlap, Nfft, 1/Ts);
#+end_src
*** FRF Identification - Encoder
In this section, the dynamics from $u$ to $d_e$ (encoder) is identified.
Then, the transfer function from the DAC output voltage $u$ to the measured displacement by the encoder $d_e$ is computed:
#+begin_src matlab
%% Transfer function estimation
enc_frf = zeros(length(f), length(strut_nums));
for i = 1:length(strut_nums)
enc_frf(:, i) = tfestimate(leg_noise{i}.u, leg_noise{i}.de, win, Noverlap, Nfft, 1/Ts);
end
%% Transfer function estimation
iff_frf = zeros(length(f), length(strut_nums));
for i = 1:length(strut_nums)
iff_frf(:, i) = tfestimate(leg_noise{i}.u, leg_noise{i}.Vs, win, Noverlap, Nfft, 1/Ts);
end
#+end_src
The obtained transfer functions are shown in Figure ref:fig:struts_align_frf_dvf_plant_tf.
#+begin_src matlab :exports none
%% Bode plot of the FRF from u to de
figure;
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]);
hold on;
for i = 1:length(strut_nums)
plot(f, abs(enc_frf(:, i)), ...
'DisplayName', sprintf('Leg %i', strut_nums(i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
hold off;
legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2);
ylim([1e-8, 1e-3]);
ax2 = nexttile;
hold on;
for i = 1:length(strut_nums)
plot(f, 180/pi*angle(enc_frf(:, i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([10, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/struts_align_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall');
#+end_src
#+name: fig:struts_align_frf_dvf_plant_tf
#+caption: Estimated FRF for the DVF plant (transfer function from $u$ to the encoder $d_e$)
#+RESULTS:
[[file:figs/struts_align_frf_dvf_plant_tf.png]]
#+begin_important
Even though the struts are much better aligned, we still observe high variability between the struts for the transfer function from $u$ to $d_e$.
#+end_important
*** Conclusion
#+begin_important
Having the struts well aligned does not change significantly the obtained dynamics.
#+end_important
The measured FRF are now saved for further use.
2024-03-19 17:02:38 +01:00
** Effect of flexible joint's characteristics
2024-03-25 14:42:03 +01:00
<<ssec:test_struts_effect_joint_stiffness>>
2024-03-19 17:02:38 +01:00
*** Introduction :ignore:
As the struts are composed of one APA and two flexible joints, it is obvious that the flexible joint characteristics will change the dynamic behavior of the struts.
Using the Simscape model, the effect of the flexible joint's characteristics on the dynamics as measured on the test bench are studied:
- Section ref:sec:struts_effect_bending_stiff_joints: the effects of a change of bending stiffness is studied
- Section ref:sec:struts_effect_axial_stiff_joints: the effects of a change of axial stiffness is studied
- Section ref:sec:struts_effect_bending_damping_joints: the effects of a change of bending damping is studied
2024-03-25 14:42:03 +01:00
The studied dynamics is between $u$ and the encoder displacement $d_e$.
2024-03-19 17:02:38 +01:00
*** Effect of bending stiffness of the flexible joints
<<sec:struts_effect_bending_stiff_joints>>
Let's initialize an APA which is a little bit misaligned.
#+begin_src matlab
%% APA Initialization
2024-03-25 14:42:03 +01:00
n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_bot', [0.1e-3; 0.5e-3; 0], 'd_align_top', [0.1e-3; 0.5e-3; 0]);
2024-03-19 17:02:38 +01:00
#+end_src
The bending stiffnesses for which the dynamics is identified are defined below.
#+begin_src matlab
%% Tested bending stiffnesses [Nm/rad]
kRs = [3, 4, 5, 6, 7];
#+end_src
Then the identification is performed for all the values of the bending stiffnesses.
#+begin_src matlab
%% Idenfity the transfer function from actuator to encoder for all bending stiffnesses
Gs = {zeros(length(kRs), 1)};
for i = 1:length(kRs)
n_hexapod.flex_bot = initializeBotFlexibleJoint(...
'type', '4dof', ...
'kRx', kRs(i), ...
'kRy', kRs(i));
n_hexapod.flex_top = initializeTopFlexibleJoint(...
'type', '4dof', ...
'kRx', kRs(i), ...
'kRy', kRs(i));
2024-03-25 14:42:03 +01:00
G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
G.InputName = {'u'};
G.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
Gs(i) = {G};
end
#+end_src
The obtained dynamics from DAC voltage to encoder measurements are compared in Figure ref:fig:effect_enc_bending_stiff.
#+begin_src matlab :exports none
%% Plot the obtained transfer functions for all the bending stiffnesses
freqs = 2*logspace(1, 3, 1000);
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
for i = 1:length(kRs)
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs{i}('de', 'u'), freqs, 'Hz'))), ...
2024-03-19 17:02:38 +01:00
'DisplayName', sprintf('$k_R = %.0f$ [Nm/rad]', kRs(i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
legend('location', 'northeast');
ax2 = nexttile;
hold on;
for i = 1:length(kRs)
2024-03-25 14:42:03 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([20, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/effect_enc_bending_stiff.pdf', 'width', 'wide', 'height', 'tall');
#+end_src
#+name: fig:effect_enc_bending_stiff
#+caption: Dynamics from DAC output to encoder for several bending stiffnesses
#+RESULTS:
[[file:figs/effect_enc_bending_stiff.png]]
#+begin_important
2024-03-25 14:42:03 +01:00
The bending stiffness of the joints has little impact on the transfer function from $u$ to $d_e$.
2024-03-19 17:02:38 +01:00
#+end_important
*** Effect of axial stiffness of the flexible joints
<<sec:struts_effect_axial_stiff_joints>>
The axial stiffnesses for which the dynamics is identified are defined below.
#+begin_src matlab
%% Tested axial stiffnesses [N/m]
kzs = [5e7 7.5e7 1e8 2.5e8];
#+end_src
Then the identification is performed for all the values of the bending stiffnesses.
#+begin_src matlab
%% Idenfity the transfer function from actuator to encoder for all bending stiffnesses
Gs = {zeros(length(kzs), 1)};
for i = 1:length(kzs)
n_hexapod.flex_bot = initializeBotFlexibleJoint(...
'type', '4dof', ...
'kz', kzs(i));
n_hexapod.flex_top = initializeTopFlexibleJoint(...
'type', '4dof', ...
'kz', kzs(i));
2024-03-25 14:42:03 +01:00
G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
G.InputName = {'u'};
G.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
Gs(i) = {G};
end
#+end_src
The obtained dynamics from DAC voltage to encoder measurements are compared in Figure ref:fig:effect_enc_axial_stiff.
#+begin_src matlab :exports none
%% Plot the obtained transfer functions for all the axial stiffnesses
freqs = 2*logspace(1, 3, 1000);
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
for i = 1:length(kzs)
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs{i}('de', 'u'), freqs, 'Hz'))), ...
2024-03-19 17:02:38 +01:00
'DisplayName', sprintf('$k_z = %.1e$ [N/m]', kzs(i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
legend('location', 'northeast');
ax2 = nexttile;
hold on;
for i = 1:length(kzs)
2024-03-25 14:42:03 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([20, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/effect_enc_axial_stiff.pdf', 'width', 'wide', 'height', 'tall');
#+end_src
#+name: fig:effect_enc_axial_stiff
#+caption: Dynamics from DAC output to encoder for several axial stiffnesses
#+RESULTS:
[[file:figs/effect_enc_axial_stiff.png]]
#+begin_important
The axial stiffness of the flexible joint has a large impact on the frequency of the complex conjugate zero.
Using the measured FRF on the test-bench, if is therefore possible to estimate the axial stiffness of the flexible joints from the location of the zero.
This method gives nice match between the measured FRF and the one extracted from the simscape model, however it could give not so accurate values of the joint's axial stiffness as other factors are also influencing the location of the zero.
Using this method, an axial stiffness of $70 N/\mu m$ is found to give good results (and is reasonable based on the finite element models).
#+end_important
*** Effect of bending damping
<<sec:struts_effect_bending_damping_joints>>
Now let's study the effect of the bending damping of the flexible joints.
The tested bending damping are defined below:
#+begin_src matlab
%% Tested bending dampings [Nm/(rad/s)]
cRs = [1e-3, 5e-3, 1e-2, 5e-2, 1e-1];
#+end_src
Then the identification is performed for all the values of the bending damping.
#+begin_src matlab
%% Idenfity the transfer function from actuator to encoder for all bending dampins
Gs = {zeros(length(cRs), 1)};
for i = 1:length(cRs)
n_hexapod.flex_bot = initializeBotFlexibleJoint(...
'type', '4dof', ...
'cRx', cRs(i), ...
'cRy', cRs(i));
n_hexapod.flex_top = initializeTopFlexibleJoint(...
'type', '4dof', ...
'cRx', cRs(i), ...
'cRy', cRs(i));
2024-03-19 15:18:57 +01:00
2024-03-25 14:42:03 +01:00
G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts);
G.InputName = {'u'};
G.OutputName = {'Vs', 'de', 'da'};
2024-03-19 17:02:38 +01:00
Gs(i) = {G};
end
2024-03-19 15:18:57 +01:00
#+end_src
2024-03-19 17:02:38 +01:00
The results are shown in Figure ref:fig:effect_enc_bending_damp.
#+begin_src matlab :exports none
%% Plot the obtained transfer functions for all the bending stiffnesses
freqs = 2*logspace(1, 3, 1000);
figure;
2024-03-25 14:42:03 +01:00
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
2024-03-19 17:02:38 +01:00
ax1 = nexttile([2,1]);
hold on;
for i = 1:length(cRs)
2024-03-25 14:42:03 +01:00
plot(freqs, abs(squeeze(freqresp(Gs{i}('de', 'u'), freqs, 'Hz'))), ...
2024-03-19 17:02:38 +01:00
'DisplayName', sprintf('$c_R = %.3f\\,[\\frac{Nm}{rad/s}]$', cRs(i)));
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
2024-03-25 14:42:03 +01:00
ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]);
2024-03-19 17:02:38 +01:00
hold off;
ylim([1e-8, 1e-3]);
legend('location', 'southwest');
ax2 = nexttile;
hold on;
for i = 1:length(cRs)
2024-03-25 14:42:03 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('de', 'u'), freqs, 'Hz'))));
2024-03-19 17:02:38 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
yticks(-360:90:360); ylim([-180, 180]);
linkaxes([ax1,ax2],'x');
xlim([20, 2e3]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/effect_enc_bending_damp.pdf', 'width', 'wide', 'height', 'tall');
#+end_src
#+name: fig:effect_enc_bending_damp
#+caption: Dynamics from DAC output to encoder for several bending damping
#+RESULTS:
[[file:figs/effect_enc_bending_damp.png]]
2024-03-25 16:33:38 +01:00
** Conclusion :ignore:
2024-03-19 17:02:38 +01:00
2024-03-19 15:18:57 +01:00
* Conclusion
2024-03-25 10:55:31 +01:00
<<sec:test_struts_conclusion>>
2024-03-19 15:18:57 +01:00
* Bibliography :ignore:
#+latex: \printbibliography[heading=bibintoc,title={Bibliography}]
* Helping Functions :noexport:
** Initialize Path
#+NAME: m-init-path
#+BEGIN_SRC matlab
%% Path for functions, data and scripts
addpath('./matlab/mat/'); % Path for data
2024-03-25 10:55:31 +01:00
addpath('./matlab/src/'); % Path for functions
2024-03-19 15:18:57 +01:00
addpath('./matlab/'); % Path for scripts
#+END_SRC
#+NAME: m-init-path-tangle
#+BEGIN_SRC matlab
%% Path for functions, data and scripts
addpath('./mat/'); % Path for data
2024-03-25 10:55:31 +01:00
addpath('./src/'); % Path for functions
2024-03-19 15:18:57 +01:00
#+END_SRC
2024-03-25 14:42:03 +01:00
** Initialize Simscape
#+NAME: m-init-path-simscape
#+BEGIN_SRC matlab
addpath('./matlab/STEPS/'); % Path for Simscape Model
%% Linearization options
opts = linearizeOptions;
opts.SampleTime = 0;
%% Open Simscape Model
mdl = 'test_struts_simscape'; % Name of the Simulink File
open(mdl); % Open Simscape Model
#+END_SRC
#+NAME: m-init-path-simscape-tangle
#+BEGIN_SRC matlab
addpath('./STEPS/'); % Path for Simscape Model
%% Linearization options
opts = linearizeOptions;
opts.SampleTime = 0;
%% Open Simscape Model
mdl = 'test_struts_simscape'; % Name of the Simulink File
open(mdl); % Open Simscape Model
#+END_SRC
2024-03-19 15:18:57 +01:00
** Initialize other elements
#+NAME: m-init-other
#+BEGIN_SRC matlab
%% Colors for the figures
colors = colororder;
#+END_SRC
2024-03-19 17:02:38 +01:00
** =initializeBotFlexibleJoint= - Initialize Flexible Joint
:PROPERTIES:
2024-03-19 17:29:51 +01:00
:header-args:matlab: :tangle matlab/src/initializeBotFlexibleJoint.m
2024-03-19 17:02:38 +01:00
:header-args:matlab+: :comments none :mkdirp yes :eval no
:END:
<<sec:initializeBotFlexibleJoint>>
*** Function description
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
function [flex_bot] = initializeBotFlexibleJoint(args)
% initializeBotFlexibleJoint -
%
% Syntax: [flex_bot] = initializeBotFlexibleJoint(args)
%
% Inputs:
% - args -
%
% Outputs:
% - flex_bot -
#+end_src
*** Optional Parameters
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
arguments
args.type char {mustBeMember(args.type,{'2dof', '3dof', '4dof'})} = '2dof'
args.kRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
args.kRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
args.kRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*260
args.kz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*7e7
args.cRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
args.cRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
args.cRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
args.cz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
end
#+end_src
*** Initialize the structure
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
flex_bot = struct();
#+end_src
*** Set the Joint's type
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
switch args.type
case '2dof'
flex_bot.type = 1;
case '3dof'
flex_bot.type = 2;
case '4dof'
flex_bot.type = 3;
end
#+end_src
*** Set parameters
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
flex_bot.kRx = args.kRx;
flex_bot.kRy = args.kRy;
flex_bot.kRz = args.kRz;
flex_bot.kz = args.kz;
#+end_src
#+begin_src matlab
flex_bot.cRx = args.cRx;
flex_bot.cRy = args.cRy;
flex_bot.cRz = args.cRz;
flex_bot.cz = args.cz;
#+end_src
** =initializeTopFlexibleJoint= - Initialize Flexible Joint
:PROPERTIES:
2024-03-19 17:29:51 +01:00
:header-args:matlab: :tangle matlab/src/initializeTopFlexibleJoint.m
2024-03-19 17:02:38 +01:00
:header-args:matlab+: :comments none :mkdirp yes :eval no
:END:
<<sec:initializeTopFlexibleJoint>>
*** Function description
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
function [flex_top] = initializeTopFlexibleJoint(args)
% initializeTopFlexibleJoint -
%
% Syntax: [flex_top] = initializeTopFlexibleJoint(args)
%
% Inputs:
% - args -
%
% Outputs:
% - flex_top -
#+end_src
*** Optional Parameters
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
arguments
args.type char {mustBeMember(args.type,{'2dof', '3dof', '4dof'})} = '2dof'
args.kRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
args.kRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5
args.kRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*260
args.kz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*7e7
args.cRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
args.cRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
args.cRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
args.cz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001
end
#+end_src
*** Initialize the structure
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
flex_top = struct();
#+end_src
*** Set the Joint's type
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
switch args.type
case '2dof'
flex_top.type = 1;
case '3dof'
flex_top.type = 2;
case '4dof'
flex_top.type = 3;
end
#+end_src
*** Set parameters
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
flex_top.kRx = args.kRx;
flex_top.kRy = args.kRy;
flex_top.kRz = args.kRz;
flex_top.kz = args.kz;
#+end_src
#+begin_src matlab
flex_top.cRx = args.cRx;
flex_top.cRy = args.cRy;
flex_top.cRz = args.cRz;
flex_top.cz = args.cz;
#+end_src
** =initializeAPA= - Initialize APA
:PROPERTIES:
2024-03-25 14:42:03 +01:00
:header-args:matlab+: :tangle matlab/src/initializeAPA.m
2024-03-19 17:02:38 +01:00
:header-args:matlab+: :comments none :mkdirp yes :eval no
:END:
<<sec:initializeAPA>>
*** Function description
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
function [actuator] = initializeAPA(args)
% initializeAPA -
%
% Syntax: [actuator] = initializeAPA(args)
%
% Inputs:
% - args -
%
% Outputs:
% - actuator -
#+end_src
*** Optional Parameters
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
arguments
args.type char {mustBeMember(args.type,{'2dof', 'flexible frame', 'flexible'})} = '2dof'
% Actuator and Sensor constants
args.Ga (1,1) double {mustBeNumeric} = 0
args.Gs (1,1) double {mustBeNumeric} = 0
% For 2DoF
2024-03-25 14:42:03 +01:00
args.k (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*380000
args.ke (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*4952605
args.ka (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*2476302
2024-03-19 17:02:38 +01:00
2024-03-25 14:42:03 +01:00
args.c (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*20
args.ce (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*200
args.ca (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*100
2024-03-19 17:02:38 +01:00
args.Leq (6,1) double {mustBeNumeric} = ones(6,1)*0.056
% Force Flexible APA
args.xi (1,1) double {mustBeNumeric, mustBePositive} = 0.01
args.d_align_bot (3,1) double {mustBeNumeric} = zeros(3,1) % [m]
args.d_align_top (3,1) double {mustBeNumeric} = zeros(3,1) % [m]
% For Flexible Frame
args.ks (1,1) double {mustBeNumeric, mustBePositive} = 235e6
args.cs (1,1) double {mustBeNumeric, mustBePositive} = 1e1
end
#+end_src
*** Initialize Structure
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
actuator = struct();
#+end_src
*** Type
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
switch args.type
case '2dof'
actuator.type = 1;
case 'flexible frame'
actuator.type = 2;
case 'flexible'
actuator.type = 3;
end
#+end_src
*** Actuator/Sensor Constants
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
if args.Ga == 0
switch args.type
case '2dof'
2024-03-25 14:42:03 +01:00
actuator.Ga = -2.5796;
2024-03-19 17:02:38 +01:00
case 'flexible frame'
actuator.Ga = 1; % TODO
case 'flexible'
2024-03-25 14:42:03 +01:00
actuator.Ga = 23.2;
2024-03-19 17:02:38 +01:00
end
else
actuator.Ga = args.Ga; % Actuator gain [N/V]
end
#+end_src
#+begin_src matlab
if args.Gs == 0
switch args.type
case '2dof'
2024-03-25 14:42:03 +01:00
actuator.Gs = 466664;
2024-03-19 17:02:38 +01:00
case 'flexible frame'
actuator.Gs = 1; % TODO
case 'flexible'
2024-03-25 14:42:03 +01:00
actuator.Gs = -4898341;
2024-03-19 17:02:38 +01:00
end
else
actuator.Gs = args.Gs; % Sensor gain [V/m]
end
#+end_src
*** 2DoF parameters
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
actuator.k = args.k; % [N/m]
actuator.ke = args.ke; % [N/m]
actuator.ka = args.ka; % [N/m]
actuator.c = args.c; % [N/(m/s)]
actuator.ce = args.ce; % [N/(m/s)]
actuator.ca = args.ca; % [N/(m/s)]
actuator.Leq = args.Leq; % [m]
#+end_src
*** Flexible frame and fully flexible
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
switch args.type
case 'flexible frame'
actuator.K = readmatrix('APA300ML_b_mat_K.CSV'); % Stiffness Matrix
actuator.M = readmatrix('APA300ML_b_mat_M.CSV'); % Mass Matrix
actuator.P = extractNodes('APA300ML_b_out_nodes_3D.txt'); % Node coordinates [m]
case 'flexible'
actuator.K = readmatrix('full_APA300ML_K.CSV'); % Stiffness Matrix
actuator.M = readmatrix('full_APA300ML_M.CSV'); % Mass Matrix
actuator.P = extractNodes('full_APA300ML_out_nodes_3D.txt'); % Node coordiantes [m]
actuator.d_align_bot = args.d_align_bot;
actuator.d_align_top = args.d_align_top;
end
actuator.xi = args.xi; % Damping ratio
actuator.ks = args.ks; % Stiffness of one stack [N/m]
actuator.cs = args.cs; % Damping of one stack [N/m]
#+end_src
2024-03-25 18:13:22 +01:00
* Footnotes
[fn:1]Faro Arm Platinum 4ft, accuracy of $\pm 13\mu m$