#+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: #+HTML_HEAD: #+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

This report is also available as a pdf.


#+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: - [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) - [ ] Check what are the used Matlab functions - [ ] 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]] - [ ] 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]] * Introduction :ignore: In this document, a test-bench is used to characterize the struts of the nano-hexapod. Each strut includes (Figure ref:fig:picture_strut_top_view): - 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 ...). #+name: fig:picture_strut_top_view #+caption: One strut including two flexible joints, an amplified piezoelectric actuator and an encoder #+attr_latex: :width 0.8\linewidth [[file:figs/picture_strut_top_view.jpg]] Then the struts are mounted (procedure described in Section ref:sec:test_bench_struts_mounting), and are fixed to the same measurement bench. The goals are to: - Section ref:sec:test_bench_struts_dynamical_meas: Identify the dynamics from the generated DAC voltage to: - 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) - Section ref:sec:test_bench_struts_simscape: Compare the measurements with the Simscape model of the struts and tune the models 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. #+name: tab:test_bench_struts_section_matlab_code #+caption: Report sections and corresponding Matlab files #+attr_latex: :environment tabularx :width 0.6\linewidth :align lX #+attr_latex: :center t :booktabs t | *Sections* | *Matlab File* | |----------------------------------+------------------------| | Section ref:sec:test_bench_struts_ | =test_bench_struts_1_.m= | * Mounting Procedure <> ** 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. A CAD view of the mounting bench is shown in Figure ref:fig:strut_mounting_bench_first_concept. #+name: fig:strut_mounting_bench_first_concept #+caption: CAD view of the mounting bench #+attr_latex: :width \linewidth [[file:figs/strut_mounting_bench_first_concept.png]] The main part of the bench is here to ensure both the correct strut length and strut coaxiality as shown in Figure ref:fig:strut_mounting_step_0. #+name: fig:strut_mounting_step_0 #+caption: Useful features of the main mounting element #+attr_latex: :width \linewidth [[file:figs/strut_mounting_step_0.jpg]] The tight tolerances of this element has been verified as shown in Figure ref:fig:strut_mounting_bench_first_concept and were found to comply with the requirements. #+name: fig:strut_mounting_bench_first_concept #+caption: Dimensional verifications of the mounting bench tolerances #+attr_latex: :width \linewidth [[file:figs/check_dimensions_bench.jpg]] The flexible joints are rigidly fixed to cylindrical tools shown in Figure ref:fig:cylindrical_mounting_part which are then mounted on the mounting tool shown in Figure ref:fig:strut_mounting_step_0. This cylindrical tool is here to protect the flexible joints when tightening the screws and therefore applying large torque. #+name: fig:cylindrical_mounting_part #+caption: Cylindrical mounting elements #+attr_latex: :width \linewidth [[file:figs/cylindrical_mounting_part.jpg]] ** Mounting Procedure The mounting procedure is as follows: 1. Screw flexible joints inside the cylindrical interface element shown in Figure ref:fig:cylindrical_mounting_part (Figure ref:fig:strut_mounting_step_1) 2. Fix the two interface elements. One of the two should be clamped, the other one should have its axial rotation free. Visually align the clamped one horizontally. (Figure ref:fig:strut_mounting_step_2) 3. Put cylindrical washers, APA and interface pieces on top of the flexible joints (Figure ref:fig:strut_mounting_step_3) 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 8. (optional) Put the APA horizontally and fix the encoder and align it to maximize the contrast (Figure ref:fig:strut_mounting_step_4) #+name: fig:strut_mounting_step_1 #+caption: Step 1 - Flexible joints fixed on the cylindrical interface elements #+attr_latex: :width 0.5\linewidth [[file:figs/strut_mounting_step_1.jpg]] #+name: fig:strut_mounting_step_2 #+caption: Step 2 - Cylindrical elements fixed on the bench #+attr_latex: :width \linewidth [[file:figs/strut_mounting_step_2.jpg]] #+name: fig:strut_mounting_step_3 #+caption: Step 3 - Mount the nuts, washers and APA #+attr_latex: :width \linewidth [[file:figs/strut_mounting_step_3.jpg]] #+name: fig:strut_mounting_step_4 #+caption: Last step - Align the encoder on the strut #+attr_latex: :width \linewidth [[file:figs/strut_mounting_step_4.jpg]] ** Mounted Struts After removing the strut from the mounting bench, we obtain a strut with ensured coaxiality between the two flexible joint's interfaces (Figure ref:fig:mounted_strut). #+name: fig:mounted_strut #+caption: Mounted Strut with ensured coaxiality #+attr_latex: :width \linewidth [[file:figs/mounted_strut.jpg]] * Spurious resonances :PROPERTIES: :header-args:matlab: :tangle matlab/basic_meas_spurious_res_struts.m :header-args:matlab+: :comments no :END: <> ** Introduction Similarly as in Section ref:sec:spurious_resonances, the spurious modes of the struts (Figure ref:fig:apa_mode_shapes_ter) are measured. These modes are present when flexible joints are fixed to the ends of the APA300ML. To experimentally measure the frequency of these modes, the struts are mounted (both with and without the encoder). Then, each end of the strut is fixed to a vertically guided stage as shown in Figure ref:fig:meas_spur_res_struts_1_enc. ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab colors = colororder; #+end_src #+begin_src matlab :tangle no addpath('matlab/'); addpath('matlab/mat/'); #+end_src #+begin_src matlab :eval no addpath('mat/'); #+end_src ** Measurement Setup A Laser vibrometer is measuring the difference of motion between two points (Figure ref:fig:meas_spur_res_struts_1_enc). The APA is excited with an instrumented hammer and the transfer function from the hammer to the measured rotation is computed. #+begin_note The instrumentation used are: - Laser Doppler Vibrometer Polytec OFV512 - Instrumented hammer #+end_note The "X-bending" mode is measured as shown in Figure ref:fig:meas_spur_res_struts_1_enc. The "Y-bending" mode is measured as shown in Figure ref:fig:meas_spur_res_struts_2 with the encoder and in Figure ref:fig:meas_spur_res_struts_2_encoder with the encoder. Finally, the "Z-torsion" is measured as shown in Figure ref:fig:meas_spur_res_struts_3. #+name: fig:meas_spur_res_struts_1_enc #+caption: Measurement setup for the X-Bending measurement (with the encoder) #+attr_latex: :width \linewidth [[file:figs/meas_spur_res_struts_1_enc.jpg]] #+name: fig:meas_spur_res_struts_2 #+caption: Measurement setup for the Y-Bending measurement #+attr_latex: :width \linewidth [[file:figs/meas_spur_res_struts_2.jpg]] #+name: fig:meas_spur_res_struts_2_encoder #+caption: Measurement setup for the Y-Bending measurement (with the encoder) #+attr_latex: :width \linewidth [[file:figs/meas_spur_res_struts_2_encoder.jpg]] #+name: fig:meas_spur_res_struts_3 #+caption: Measurement setup for the Z-Torsion measurement #+attr_latex: :width 0.8\linewidth [[file:figs/meas_spur_res_struts_3.jpg]] ** Without Encoder When the encoder is not fixed to the strut, the obtained FRF are shown in Figure ref:fig:struts_spur_res_without_enc. #+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'); #+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') text(337, 6e-5,{'337Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center') 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]) legend('location', 'northwest'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/struts_spur_res_without_enc.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:struts_spur_res_without_enc #+caption: Obtained FRF for the struts without the encoder #+RESULTS: [[file:figs/struts_spur_res_without_enc.png]] ** With Encoder Then, one encoder is fixed to the strut and the FRF are measured again and shown in Figure ref:fig:struts_spur_res_with_enc. #+begin_src matlab :exports none %% 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'); #+end_src #+begin_src matlab :exports none %% Plot the responses (with the encoder) 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'); xlim([50, 8e2]); ylim([5e-7, 2e-4]) legend('location', 'northwest'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/struts_spur_res_with_enc.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:struts_spur_res_with_enc #+caption: Obtained FRF for the struts with encoder #+RESULTS: [[file:figs/struts_spur_res_with_enc.png]] ** Conclusion Table ref:tab:strut_measured_modes_freq summarizes the measured resonance frequencies as well as the computed ones using the Finite Element Model. #+begin_important From the values in Table ref:tab:strut_measured_modes_freq, it is shown that: - 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 #+end_important #+name: tab:strut_measured_modes_freq #+caption: Measured frequency of the strut spurious modes #+attr_latex: :environment tabularx :width 0.45\linewidth :align cccc #+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 <> ** Introduction :ignore: The same bench used in Section ref:sec:dynamical_meas_apa is here used with the strut instead of only the APA. The bench is shown in Figure ref:fig:test_bench_leg_overview. Measurements are performed either when no encoder is fixed to the strut (Figure ref:fig:test_bench_leg_front) or when one encoder is fixed to the strut (Figure ref:fig:test_bench_leg_coder). #+name: fig:test_bench_leg_overview #+caption: Test Bench with Strut - Overview #+attr_latex: :width 0.5\linewidth [[file:figs/test_bench_leg_overview.jpg]] #+name: fig:test_bench_leg_front #+caption: Test Bench with Strut - Zoom on the strut #+attr_latex: :width 0.5\linewidth [[file:figs/test_bench_leg_front.jpg]] #+name: fig:test_bench_leg_coder #+caption: Test Bench with Strut - Zoom on the strut with the encoder #+attr_latex: :width 0.5\linewidth [[file:figs/test_bench_leg_coder.jpg]] Variables are named the same as in Section ref:sec:dynamical_meas_apa. First, only one strut is measured in details (Section ref:sec:meas_strut_1), and then all the struts are measured and compared (Section ref:sec:meas_all_struts). ** Measurement on Strut 1 :PROPERTIES: :header-args:matlab: :tangle matlab/strut_meas_analysis_1.m :header-args:matlab+: :comments no :END: <> *** Introduction :ignore: Measurements are first performed on one of the strut that contains: - the Amplified Piezoelectric Actuator (APA) number 1 - flexible joints 1 and 2 In Section ref:sec:meas_strut_1_no_encoder, the dynamics of the strut is measured without the encoder attached to it. Then in Section ref:sec:meas_strut_1_encoder, the encoder is attached to the struts, and the dynamic is identified. *** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab colors = colororder; #+end_src #+begin_src matlab :tangle no addpath('./matlab/mat/'); addpath('./matlab/src/'); addpath('./matlab/'); #+end_src #+begin_src matlab :eval no addpath('./mat/'); addpath('./src/'); #+end_src *** Without Encoder <> **** FRF Identification - Setup Similarly to what was done for the identification of the APA, the identification is performed in three steps: 1. White noise excitation with small amplitude. This is used to determine the main resonance of the system. 2. Sweep sine excitation with the amplitude lowered around the resonance. The sweep sine is from 10Hz to 400Hz. 3. High frequency noise. The noise is band-passed between 300Hz and 2kHz. Then, the result of the second identification is used between 10Hz and 350Hz and the result of the third identification if used between 350Hz and 2kHz. #+begin_src matlab %% Load Data leg_sweep = load(sprintf('frf_data_leg_%i_sweep.mat', 1), 't', 'Va', 'Vs', 'de', 'da'); leg_noise_hf = load(sprintf('frf_data_leg_%i_noise_hf.mat', 1), 't', 'Va', 'Vs', 'de', 'da'); #+end_src The time is the same for all measurements. #+begin_src matlab %% Time vector t = leg_sweep.t - leg_sweep.t(1) ; % Time vector [s] %% Sampling frequency/time Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s] Fs = 1/Ts; % Sampling Frequency [Hz] #+end_src Then we defined a "Hanning" windows that will be used for the spectral analysis: #+begin_src matlab win = hanning(ceil(0.5*Fs)); % Hannning Windows #+end_src We get the frequency vector that will be the same for all the frequency domain analysis. #+begin_src matlab % Only used to have the frequency vector "f" [~, f] = tfestimate(leg_sweep.Va, leg_sweep.de, win, [], [], 1/Ts); i_lf = f <= 350; % Indices used for the low frequency i_hf = f > 350; % Indices used for the low frequency #+end_src **** FRF Identification - Interferometer In this section, the dynamics from the excitation voltage $V_a$ to the interferometer $d_a$ is identified. We compute the coherence for 2nd and 3rd identification and combine them. #+begin_src matlab %% Compute the coherence for both excitation signals [int_coh_sweep, ~] = mscohere(leg_sweep.Va, leg_sweep.da, win, [], [], 1/Ts); [int_coh_noise_hf, ~] = mscohere(leg_noise_hf.Va, leg_noise_hf.da, win, [], [], 1/Ts); %% Combine the coherence int_coh = [int_coh_sweep(i_lf); int_coh_noise_hf(i_hf)]; #+end_src The combined coherence is shown in Figure ref:fig:strut_1_frf_dvf_plant_coh, and is found to be very good up to at least 1kHz. #+begin_src matlab :exports none %% Plot the coherence figure; hold on; plot(f, int_coh(:, 1), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:strut_1_frf_dvf_plant_coh #+caption: Obtained coherence for the plant from $V_a$ to $d_a$ #+RESULTS: [[file:figs/strut_1_frf_dvf_plant_coh.png]] The transfer function from $V_a$ to the interferometer measured displacement $d_a$ is estimated and shown in Figure ref:fig:strut_1_frf_dvf_plant_tf. #+begin_src matlab %% Compute FRF function from Va to da [frf_sweep, ~] = tfestimate(leg_sweep.Va, leg_sweep.da, win, [], [], 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_noise_hf.Va, leg_noise_hf.da, win, [], [], 1/Ts); %% Combine the FRF int_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the measured FRF figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(int_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-9, 1e-3]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(int_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_frf_dvf_plant_tf #+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the interferometer $d_a$) #+RESULTS: [[file:figs/strut_1_frf_dvf_plant_tf.png]] **** FRF Identification - IFF In this section, the dynamics from $V_a$ to $V_s$ is identified. First the coherence is computed and shown in Figure ref:fig:strut_1_frf_iff_plant_coh. The coherence is very nice from 10Hz to 2kHz. It is only dropping near a zeros at 40Hz, and near the resonance at 95Hz (the excitation amplitude being lowered). #+begin_src matlab %% Compute the coherence for both excitation signals [iff_coh_sweep, ~] = mscohere(leg_sweep.Va, leg_sweep.Vs, win, [], [], 1/Ts); [iff_coh_noise_hf, ~] = mscohere(leg_noise_hf.Va, leg_noise_hf.Vs, win, [], [], 1/Ts); %% Combine the coherence iff_coh = [iff_coh_sweep(i_lf); iff_coh_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; plot(f, iff_coh, 'k-'); hold off; xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_frf_iff_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:strut_1_frf_iff_plant_coh #+caption: Obtained coherence for the IFF plant #+RESULTS: [[file:figs/strut_1_frf_iff_plant_coh.png]] Then the FRF are estimated and shown in Figure ref:fig:strut_1_frf_iff_plant_tf #+begin_src matlab %% Compute the FRF [frf_sweep, ~] = tfestimate(leg_sweep.Va, leg_sweep.Vs, win, [], [], 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_noise_hf.Va, leg_noise_hf.Vs, win, [], [], 1/Ts); %% Combine the FRF iff_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the measured FRF figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(iff_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(iff_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_frf_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_frf_iff_plant_tf #+caption:Identified IFF Plant for the Strut 1 #+RESULTS: [[file:figs/strut_1_frf_iff_plant_tf.png]] *** With Encoder <> **** Introduction :ignore: Now the encoder is fixed to the strut and the identification is performed. **** Measurement Data The measurements are loaded. #+begin_src matlab %% Load data leg_enc_sweep = load(sprintf('frf_data_leg_coder_badly_align_%i_noise.mat', 1), 't', 'Va', 'Vs', 'de', 'da'); leg_enc_noise_hf = load(sprintf('frf_data_leg_coder_badly_align_%i_noise_hf.mat', 1), 't', 'Va', 'Vs', 'de', 'da'); #+end_src **** FRF Identification - Interferometer In this section, the dynamics from $V_a$ to $d_a$ is identified. First, the coherence is computed and shown in Figure ref:fig:strut_1_int_with_enc_frf_dvf_plant_coh. #+begin_src matlab %% Compute the coherence for both excitation signals [int_coh_sweep, ~] = mscohere(leg_enc_sweep.Va, leg_enc_sweep.da, win, [], [], 1/Ts); [int_coh_noise_hf, ~] = mscohere(leg_enc_noise_hf.Va, leg_enc_noise_hf.da, win, [], [], 1/Ts); %% Combine the coherinte int_coh = [int_coh_sweep(i_lf); int_coh_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; plot(f, int_coh(:, 1), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_int_with_enc_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:strut_1_int_with_enc_frf_dvf_plant_coh #+caption: Obtained coherence for the plant from $V_a$ to $d_a$ #+RESULTS: [[file:figs/strut_1_int_with_enc_frf_dvf_plant_coh.png]] Then the FRF are computed and shown in Figure ref:fig:strut_1_int_with_enc_frf_dvf_plant_tf. #+begin_src matlab %% Compute FRF function from Va to da [frf_sweep, ~] = tfestimate(leg_enc_sweep.Va, leg_enc_sweep.da, win, [], [], 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.Va, leg_enc_noise_hf.da, win, [], [], 1/Ts); %% Combine the FRF int_with_enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the FRF from Va to de figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(int_with_enc_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-7, 1e-3]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(int_with_enc_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_int_with_enc_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_int_with_enc_frf_dvf_plant_tf #+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$) #+RESULTS: [[file:figs/strut_1_int_with_enc_frf_dvf_plant_tf.png]] The obtained FRF is very close to the one that was obtained when no encoder was fixed to the struts as shown in Figure ref:fig:strut_leg_compare_int_frf. #+begin_src matlab :exports none %% Plot the FRF from Va to da with and without the encoder figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(int_with_enc_frf), '-', 'DisplayName', 'With encoder'); plot(f, abs(int_frf), '-', 'DisplayName', 'Without encoder'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-7, 1e-3]); legend('location', 'northeast') ax2 = nexttile; hold on; plot(f, 180/pi*angle(int_with_enc_frf), '-'); plot(f, 180/pi*angle(int_frf), '-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_leg_compare_int_frf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_leg_compare_int_frf #+caption: Comparison of the measured FRF from $V_a$ to $d_a$ with and without the encoders fixed to the struts #+RESULTS: [[file:figs/strut_leg_compare_int_frf.png]] **** FRF Identification - Encoder In this section, the dynamics from $V_a$ to $d_e$ (encoder) is identified. The coherence is computed and shown in Figure ref:fig:strut_1_enc_frf_dvf_plant_coh. #+begin_src matlab %% Compute the coherence for both excitation signals [enc_coh_sweep, ~] = mscohere(leg_enc_sweep.Va, leg_enc_sweep.de, win, [], [], 1/Ts); [enc_coh_noise_hf, ~] = mscohere(leg_enc_noise_hf.Va, leg_enc_noise_hf.de, win, [], [], 1/Ts); %% Combine the coherence enc_coh = [enc_coh_sweep(i_lf); enc_coh_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; plot(f, enc_coh(:, 1), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_enc_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:strut_1_enc_frf_dvf_plant_coh #+caption: Obtained coherence for the plant from $V_a$ to $d_e$ and from $V_a$ to $d_a$ #+RESULTS: [[file:figs/strut_1_enc_frf_dvf_plant_coh.png]] The FRF from $V_a$ to the encoder measured displacement $d_e$ is computed and shown in Figure ref:fig:strut_1_enc_frf_dvf_plant_tf. #+begin_src matlab %% Compute FRF function from Va to da [frf_sweep, ~] = tfestimate(leg_enc_sweep.Va, leg_enc_sweep.de, win, [], [], 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.Va, leg_enc_noise_hf.de, win, [], [], 1/Ts); %% Combine the FRF enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the FRF from Va to de figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(enc_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-7, 1e-3]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(enc_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_enc_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_enc_frf_dvf_plant_tf #+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$) #+RESULTS: [[file:figs/strut_1_enc_frf_dvf_plant_tf.png]] The transfer functions from $V_a$ to $d_e$ (encoder) and to $d_a$ (interferometer) are compared in Figure ref:fig:strut_1_comp_enc_int. #+begin_src matlab :exports none figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(enc_frf), 'DisplayName', 'Encoder'); plot(f, abs(int_with_enc_frf), 'DisplayName', 'Interferometer'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2); ylim([1e-8, 1e-3]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(enc_frf)); plot(f, 180/pi*angle(int_with_enc_frf)); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_comp_enc_int.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_comp_enc_int #+caption: Comparison of the transfer functions from excitation voltage $V_a$ to either the encoder $d_e$ or the interferometer $d_a$ #+RESULTS: [[file:figs/strut_1_comp_enc_int.png]] #+begin_important The dynamics from the excitation voltage $V_a$ 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:strut_1_comp_enc_int). It will be further investigated why the two dynamics as so different and what are causing all these resonances. #+end_important **** APA Resonances Frequency As shown in Figure ref:fig:strut_1_spurious_resonances, we can clearly see three spurious resonances at 197Hz, 290Hz and 376Hz. #+begin_src matlab :exports none %% Transfer function from Vs to de with indicated resonances figure; hold on; plot(f, abs(enc_frf), 'k-'); 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') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); xlabel('Frequency [Hz]'); hold off; ylim([1e-7, 1e-3]); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_spurious_resonances.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_spurious_resonances #+caption: Magnitude of the transfer function from excitation voltage $V_a$ to encoder measurement $d_e$. The frequency of the resonances are noted. #+RESULTS: [[file:figs/strut_1_spurious_resonances.png]] These resonances correspond to parasitic resonances of the strut itself. They are very close to what was estimated using a finite element model of the strut (Figure ref:fig:apa_mode_shapes_bis): - Mode in X-bending at 189Hz - Mode in Y-bending at 285Hz - Mode in Z-torsion at 400Hz #+name: fig:apa_mode_shapes_bis #+caption: Spurious resonances. a) X-bending mode at 189Hz. b) Y-bending mode at 285Hz. c) Z-torsion mode at 400Hz #+attr_latex: :width \linewidth [[file:figs/apa_mode_shapes.gif]] #+begin_important The resonances seen by the encoder in Figure ref:fig:strut_1_spurious_resonances are indeed corresponding to the modes of the strut as shown in Figure ref:fig:apa_mode_shapes_bis. #+end_important **** FRF Identification - Force Sensor In this section, the dynamics from $V_a$ to $V_s$ is identified. First the coherence is computed and shown in Figure ref:fig:strut_1_frf_iff_with_enc_plant_coh. The coherence is very nice from 10Hz to 2kHz. It is only dropping near a zeros at 40Hz, and near the resonance at 95Hz (the excitation amplitude being lowered). #+begin_src matlab %% Compute the coherence for both excitation signals [iff_coh_sweep, ~] = mscohere(leg_enc_sweep.Va, leg_enc_sweep.Vs, win, [], [], 1/Ts); [iff_coh_noise_hf, ~] = mscohere(leg_enc_noise_hf.Va, leg_enc_noise_hf.Vs, win, [], [], 1/Ts); %% Combine the coherence iff_coh = [iff_coh_sweep(i_lf); iff_coh_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; plot(f, iff_coh, 'k-'); hold off; xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_frf_iff_with_enc_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:strut_1_frf_iff_with_enc_plant_coh #+caption: Obtained coherence for the IFF plant #+RESULTS: [[file:figs/strut_1_frf_iff_with_enc_plant_coh.png]] Then the FRF are estimated and shown in Figure ref:fig:strut_1_enc_frf_iff_plant_tf #+begin_src matlab %% Compute FRF function from Va to da [frf_sweep, ~] = tfestimate(leg_enc_sweep.Va, leg_enc_sweep.Vs, win, [], [], 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.Va, leg_enc_noise_hf.Vs, win, [], [], 1/Ts); %% Combine the FRF iff_with_enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; #+end_src #+begin_src matlab :exports none %% Plot FRF of the transfer function from Va to Vs figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(iff_with_enc_frf), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(iff_with_enc_frf), 'k'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_enc_frf_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_enc_frf_iff_plant_tf #+caption:Identified IFF Plant #+RESULTS: [[file:figs/strut_1_enc_frf_iff_plant_tf.png]] Let's now compare the IFF plants whether the encoders are fixed to the APA or not (Figure ref:fig:strut_1_frf_iff_comp_enc). #+begin_src matlab :exports none %% Compare the IFF plant with and without the encoders figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(iff_with_enc_frf), 'DisplayName', 'With Encoder'); plot(f, abs(iff_frf), 'DisplayName', 'Without Encoder'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8); ylim([1e-2, 1e2]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(iff_with_enc_frf)); plot(f, 180/pi*angle(iff_frf)); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_1_frf_iff_effect_enc.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:strut_1_frf_iff_comp_enc #+caption: Effect of the encoder on the IFF plant #+RESULTS: [[file:figs/strut_1_frf_iff_effect_enc.png]] #+begin_important The transfer function from the excitation voltage $V_a$ to the generated voltage $V_s$ by the sensor stack is not influence by the fixation of the encoder. This means that the IFF control strategy should be as effective whether or not the encoders are fixed to the struts. #+end_important **** TODO Non-Minimum phase zero? In order to determine if the complex conjugate zero of Figure ref:fig:strut_1_enc_frf_iff_plant_tf is minimum phase or non-minimum phase, longer measurements are performed. #+begin_src matlab long_sweep = load('frf_struts_align_3_sweep_long.mat', 't', 'Va', 'Vs'); long_noise = load('frf_struts_align_3_noise_long.mat', 't', 'Va', 'Vs'); #+end_src #+begin_src matlab Ts = (long_sweep.t(end) - long_sweep.t(1))/(length(long_sweep.t)-1); % Sampling Time [s] Fs = 1/Ts; #+end_src #+begin_src matlab win = hanning(ceil(50*Fs)); % Hannning Windows #+end_src #+begin_src matlab %% Transfer function estimation [coh_sweep, f] = mscohere(long_sweep.Va, long_sweep.Vs, win, [], [], 1/Ts); [coh_noise, ~] = mscohere(long_noise.Va, long_noise.Vs, win, [], [], 1/Ts); #+end_src #+begin_src matlab :exports none %% Bode plot of the FRF from Va to de figure; hold on; plot(f, coh_sweep, '.'); plot(f, coh_noise, '.'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); hold off; xlim([38, 45]); ylim([0, 1]); #+end_src Remove time delay #+begin_src matlab long_sweep.Va(end) = []; long_noise.Va(end) = []; long_sweep.Vs(1) = []; long_noise.Vs(1) = []; #+end_src #+begin_src matlab %% Transfer function estimation [frf_sweep, f] = tfestimate(long_sweep.Va, long_sweep.Vs, win, [], [], 1/Ts); [frf_noise, ~] = tfestimate(long_noise.Va, long_noise.Vs, win, [], [], 1/Ts); #+end_src #+begin_src matlab :exports none %% Bode plot of the FRF from Va to de figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(frf_sweep), '.'); plot(f, abs(frf_noise), '.'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2); ax2 = nexttile; hold on; plot(f, 180/pi*angle(frf_sweep), '.'); plot(f, 180/pi*angle(frf_noise), '.'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 0]); linkaxes([ax1,ax2],'x'); xlim([38, 45]); #+end_src ** Comparison of all the Struts :PROPERTIES: :header-args:matlab: :tangle matlab/strut_meas_analysis_all.m :header-args:matlab+: :comments no :END: <> *** Introduction :ignore: Now all struts are measured using the same procedure and test bench as in Section ref:sec:meas_strut_1. *** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab colors = colororder; #+end_src #+begin_src matlab :tangle no addpath('./matlab/mat/'); addpath('./matlab/src/'); addpath('./matlab/'); #+end_src #+begin_src matlab :eval no addpath('./mat/'); addpath('./src/'); #+end_src *** FRF Identification - Setup The identification of the struts dynamics is performed in two steps: 1. The excitation signal is a white noise with small amplitude. This is used to estimate the low frequency dynamics. 2. Then a high frequency noise band-passed between 300Hz and 2kHz is used to estimate the high frequency dynamics. Then, the result of the first identification is used between 10Hz and 350Hz and the result of the second identification if used between 350Hz and 2kHz. Here are the leg numbers that have been measured. #+begin_src matlab %% Numnbers of the measured legs leg_nums = [1 2 3 4 5]; #+end_src The data are loaded for both the first and second identification: #+begin_src matlab %% First identification (low frequency noise) leg_noise = {}; for i = 1:length(leg_nums) leg_noise(i) = {load(sprintf('frf_data_leg_coder_%i_noise.mat', leg_nums(i)), 't', 'Va', 'Vs', 'de', 'da')}; end %% Second identification (high frequency noise) leg_noise_hf = {}; for i = 1:length(leg_nums) leg_noise_hf(i) = {load(sprintf('frf_data_leg_coder_%i_noise_hf.mat', leg_nums(i)), 't', 'Va', 'Vs', 'de', 'da')}; end #+end_src The time is the same for all measurements. #+begin_src matlab %% Time vector t = leg_noise{1}.t - leg_noise{1}.t(1) ; % Time vector [s] %% Sampling Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s] Fs = 1/Ts; % Sampling Frequency [Hz] #+end_src Then we defined a "Hanning" windows that will be used for the spectral analysis: #+begin_src matlab win = hanning(ceil(0.5*Fs)); % Hannning Windows #+end_src We get the frequency vector that will be the same for all the frequency domain analysis. #+begin_src matlab % Only used to have the frequency vector "f" [~, f] = tfestimate(leg_noise{1}.Va, leg_noise{1}.de, win, [], [], 1/Ts); i_lf = f <= 350; i_hf = f > 350; #+end_src *** FRF Identification - Encoder In this section, the dynamics from $V_a$ to $d_e$ (encoder) is identified. The coherence is computed and shown in Figure ref:fig:struts_frf_dvf_plant_coh for all the measured struts. #+begin_src matlab %% Coherence computation coh_enc = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) [coh_lf, ~] = mscohere(leg_noise{i}.Va, leg_noise{i}.de, win, [], [], 1/Ts); [coh_hf, ~] = mscohere(leg_noise_hf{i}.Va, leg_noise_hf{i}.de, win, [], [], 1/Ts); coh_enc(:, i) = [coh_lf(i_lf); coh_hf(i_hf)]; end #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; for i = 1:length(leg_nums) plot(f, coh_enc(:, i)); end; hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/struts_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:struts_frf_dvf_plant_coh #+caption: Obtained coherence for the plant from $V_a$ to $d_e$ #+RESULTS: [[file:figs/struts_frf_dvf_plant_coh.png]] Then, the transfer function from the DAC output voltage $V_a$ to the measured displacement by the encoder $d_e$ is computed: #+begin_src matlab %% Transfer function estimation enc_frf = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) [frf_lf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.de, win, [], [], 1/Ts); [frf_hf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.de, win, [], [], 1/Ts); enc_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)]; end #+end_src The obtained transfer functions are shown in Figure ref:fig:struts_frf_dvf_plant_tf. #+begin_src matlab :exports none %% Bode plot of the FRF from Va to de figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(leg_nums) plot(f, abs(enc_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', leg_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2); ylim([1e-8, 1e-3]); ax2 = nexttile; hold on; for i = 1:length(leg_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_frf_dvf_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:struts_frf_dvf_plant_tf #+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$) #+RESULTS: [[file:figs/struts_frf_dvf_plant_tf.png]] #+begin_important There is a very large variability of the dynamics as measured by the encoder as shown in Figure ref:fig:struts_frf_dvf_plant_tf. 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. All of this will be explained in Section ref:sec:simscape_bench_struts thanks to the Simscape model. #+end_important *** FRF Identification - Interferometer In this section, the dynamics from $V_a$ to $d_a$ (interferometer) is identified. The coherence is computed and shown in Figure ref:fig:struts_frf_int_plant_coh. #+begin_src matlab %% Coherence computation coh_int = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) [coh_lf, ~] = mscohere(leg_noise{i}.Va, leg_noise{i}.da, win, [], [], 1/Ts); [coh_hf, ~] = mscohere(leg_noise_hf{i}.Va, leg_noise_hf{i}.da, win, [], [], 1/Ts); coh_int(:, i) = [coh_lf(i_lf); coh_hf(i_hf)]; end #+end_src #+begin_src matlab :exports none %% Plot coherence figure; hold on; for i = 1:length(leg_nums) plot(f, coh_int(:, i)); end; hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/struts_frf_int_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:struts_frf_int_plant_coh #+caption: Obtained coherence for the plant from $V_a$ to $d_e$ #+RESULTS: [[file:figs/struts_frf_int_plant_coh.png]] Then, the transfer function from the DAC output voltage $V_a$ to the measured displacement by the Attocube is computed for all the struts and shown in Figure ref:fig:struts_frf_int_plant_tf. All the struts are giving very similar FRF. #+begin_src matlab %% Transfer function estimation int_frf = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) [frf_lf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.da, win, [], [], 1/Ts); [frf_hf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.da, win, [], [], 1/Ts); int_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)]; end #+end_src #+begin_src matlab :exports none %% Plot the FRF from Va to de (interferometer) figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(leg_nums) plot(f, abs(int_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', leg_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2); ylim([1e-9, 1e-3]); ax2 = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(int_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_frf_int_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:struts_frf_int_plant_tf #+caption: Estimated FRF for the DVF plant (transfer function from $V_a$ to the encoder $d_e$) #+RESULTS: [[file:figs/struts_frf_int_plant_tf.png]] *** FRF Identification - Force Sensor In this section, the dynamics from $V_a$ to $V_s$ is identified. First the coherence is computed and shown in Figure ref:fig:struts_frf_iff_plant_coh. #+begin_src matlab %% Coherence coh_iff = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) [coh_lf, ~] = mscohere(leg_noise{i}.Va, leg_noise{i}.Vs, win, [], [], 1/Ts); [coh_hf, ~] = mscohere(leg_noise_hf{i}.Va, leg_noise_hf{i}.Vs, win, [], [], 1/Ts); coh_iff(:, i) = [coh_lf(i_lf); coh_hf(i_hf)]; end #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; for i = 1:length(leg_nums) plot(f, coh_iff(:, i)); end; hold off; xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/struts_frf_iff_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:struts_frf_iff_plant_coh #+caption: Obtained coherence for the IFF plant #+RESULTS: [[file:figs/struts_frf_iff_plant_coh.png]] Then the FRF are estimated and shown in Figure ref:fig:struts_frf_iff_plant_tf. They are also shown all to be very similar. #+begin_src matlab %% FRF estimation of the transfer function from Va to Vs iff_frf = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) [frf_lf, ~] = tfestimate(leg_noise{i}.Va, leg_noise{i}.Vs, win, [], [], 1/Ts); [frf_hf, ~] = tfestimate(leg_noise_hf{i}.Va, leg_noise_hf{i}.Vs, win, [], [], 1/Ts); iff_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)]; end #+end_src #+begin_src matlab :exports none %% Plot the FRF from Va to Vs figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(leg_nums) plot(f, abs(iff_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', leg_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); ax2 = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(iff_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_frf_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:struts_frf_iff_plant_tf #+caption:Identified IFF Plant #+RESULTS: [[file:figs/struts_frf_iff_plant_tf.png]] *** 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 '); #+end_src #+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 #+RESULTS: | *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 | 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. #+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 #+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 | The differences of the measured distances on each side corresponds to the misalignment on that same side (Table ref:tab:meas_misalignment_struts_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', '3', '4', '5'}, {'*Strut*', '*Top*', '*Bot*'}, ' %.3f '); #+end_src #+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 | #+begin_important The misalignment of the APA and flexible joints is quite large and variable from one strut to the other. #+end_important *** Conclusion #+begin_important All the struts are giving very consistent behavior from the excitation voltage $V_a$ to the force sensor generated voltage $V_s$ and to the interferometer measured displacement $d_a$. However, the dynamics from $V_a$ 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. #+end_important The measured FRF are now saved for further use. #+begin_src matlab :tangle no :exports none save('matlab/mat/meas_struts_frf.mat', 'f', 'Ts', 'enc_frf', 'int_frf', 'iff_frf', 'leg_nums', 'apa_align'); #+end_src #+begin_src matlab :eval no %% Save the estimated FRF for further analysis save('mat/meas_struts_frf.mat', 'f', 'Ts', 'enc_frf', 'int_frf', 'iff_frf', 'leg_nums', 'apa_align'); #+end_src ** Comparison of all the (re-aligned) Struts :PROPERTIES: :header-args:matlab: :tangle matlab/strut_aligned_meas_analysis_all.m :header-args:matlab+: :comments no :END: <> *** Introduction :ignore: The struts are re-aligned and measured using the same test bench. *** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab colors = colororder; #+end_src #+begin_src matlab :tangle no addpath('./matlab/mat/'); addpath('./matlab/src/'); addpath('./matlab/'); #+end_src #+begin_src matlab :eval no addpath('./mat/'); addpath('./src/'); #+end_src *** 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 leg_nums = [1 2 3 4 5 6]; #+end_src #+begin_src matlab %% First identification (low frequency noise) leg_noise = {}; for i = 1:length(leg_nums) leg_noise(i) = {load(sprintf('frf_struts_align_%i_noise.mat', leg_nums(i)), 't', 'Va', 'Vs', 'de')}; end #+end_src The time is the same for all measurements. #+begin_src matlab %% Time vector t = leg_noise{1}.t - leg_noise{1}.t(1) ; % Time vector [s] %% Sampling Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s] Fs = 1/Ts; % Sampling Frequency [Hz] #+end_src Then we defined a "Hanning" windows that will be used for the spectral analysis: #+begin_src matlab win = hanning(ceil(0.5*Fs)); % Hannning Windows #+end_src We get the frequency vector that will be the same for all the frequency domain analysis. #+begin_src matlab % Only used to have the frequency vector "f" [~, f] = tfestimate(leg_noise{1}.Va, leg_noise{1}.de, win, [], [], 1/Ts); #+end_src *** FRF Identification - Encoder In this section, the dynamics from $V_a$ to $d_e$ (encoder) is identified. The coherence is computed and shown in Figure ref:fig:struts_align_frf_dvf_plant_coh for all the measured struts. #+begin_src matlab %% Coherence computation coh_enc = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) coh_enc(:, i) = mscohere(leg_noise{i}.Va, leg_noise{i}.de, win, [], [], 1/Ts); end #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; for i = 1:length(leg_nums) plot(f, coh_enc(:, i)); end; hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/struts_align_frf_dvf_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:struts_align_frf_dvf_plant_coh #+caption: Obtained coherence for the plant from $V_a$ to $d_e$ #+RESULTS: [[file:figs/struts_align_frf_dvf_plant_coh.png]] Then, the transfer function from the DAC output voltage $V_a$ to the measured displacement by the encoder $d_e$ is computed: #+begin_src matlab %% Transfer function estimation enc_frf = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) enc_frf(:, i) = tfestimate(leg_noise{i}.Va, leg_noise{i}.de, win, [], [], 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 Va to de figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(leg_nums) plot(f, abs(enc_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', leg_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2); ylim([1e-8, 1e-3]); ax2 = nexttile; hold on; for i = 1:length(leg_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 $V_a$ 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 $V_a$ to $d_e$. #+end_important *** FRF Identification - Force Sensor In this section, the dynamics from $V_a$ to $V_s$ is identified. First the coherence is computed and shown in Figure ref:fig:struts_frf_iff_plant_coh. #+begin_src matlab %% Coherence coh_iff = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) coh_iff(:, i) = mscohere(leg_noise{i}.Va, leg_noise{i}.Vs, win, [], [], 1/Ts); end #+end_src #+begin_src matlab :exports none %% Plot the coherence figure; hold on; for i = 1:length(leg_nums) plot(f, coh_iff(:, i)); end; hold off; xlabel('Frequency [Hz]'); ylabel('Coherence [-]'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlim([10, 2e3]); ylim([0, 1]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/struts_align_frf_iff_plant_coh.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:struts_align_frf_iff_plant_coh #+caption: Obtained coherence for the IFF plant #+RESULTS: [[file:figs/struts_align_frf_iff_plant_coh.png]] Then the FRF are estimated and shown in Figure ref:fig:struts_frf_iff_plant_tf. They are also shown all to be very similar. #+begin_src matlab %% FRF estimation of the transfer function from Va to Vs iff_frf = zeros(length(f), length(leg_nums)); for i = 1:length(leg_nums) iff_frf(:, i) = tfestimate(leg_noise{i}.Va, leg_noise{i}.Vs, win, [], [], 1/Ts); end #+end_src #+begin_src matlab :exports none %% Plot the FRF from Va to Vs figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(leg_nums) plot(f, abs(iff_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', leg_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); ax2 = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(iff_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_iff_plant_tf.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:struts_align_frf_iff_plant_tf #+caption:Identified IFF Plant #+RESULTS: [[file:figs/struts_align_frf_iff_plant_tf.png]] *** 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. #+begin_src matlab :tangle no :exports none save('matlab/mat/meas_aligned_struts_frf.mat', 'f', 'Ts', 'enc_frf', 'iff_frf', 'leg_nums', 'strut_align'); #+end_src #+begin_src matlab :eval no %% Save the estimated FRF for further analysis save('mat/meas_struts_frf.mat', 'f', 'Ts', 'enc_frf', 'iff_frf', 'leg_nums', 'strut_align'); #+end_src ** TODO Noise measurement :noexport: #+begin_src matlab %% Nothing connected to the actuator stacks open_circuit = load('frf_struts_align_3_huddle_open_circuit.mat', 't', 'Vs', 'de'); %% PD200 connected but its input short-circuited mid_voltage = load('frf_struts_align_3_huddle_mid_voltage_dac.mat', 't', 'Vs', 'de'); %% PD200 connected to the DAC that outputs 0V zero_voltage = load('frf_struts_align_3_huddle_dac_zero.mat', 't', 'Vs', 'de'); %% PD200 connected to the DAC that outputs 3.25V short_circuit = load('frf_struts_align_3_huddle_amp_short_circuit.mat', 't', 'Vs', 'de'); #+end_src #+begin_src matlab %% Time vector t = open_circuit.t - open_circuit.t(1) ; % Time vector [s] %% Sampling Ts = (t(end) - t(1))/(length(t)-1); % Sampling Time [s] Fs = 1/Ts; % Sampling Frequency [Hz] #+end_src Then we defined a "Hanning" windows that will be used for the spectral analysis: #+begin_src matlab win = hanning(ceil(1*Fs)); % Hannning Windows #+end_src #+begin_src matlab [pxx_oc, f] = pwelch(open_circuit.Vs, win, 0, [], Fs); [pxx_mv, ~] = pwelch(mid_voltage.Vs, win, 0, [], Fs); [pxx_zv, ~] = pwelch(zero_voltage.Vs, win, 0, [], Fs); [pxx_sc, ~] = pwelch(short_circuit.Vs, win, 0, [], Fs); #+end_src #+begin_src matlab figure; hold on; plot(f, sqrt(pxx_oc), 'DisplayName', 'Open Circuit') plot(f, sqrt(pxx_sc), 'DisplayName', 'Amp Short-Circuited') plot(f, sqrt(pxx_zv), 'DisplayName', 'Zero Voltage (DAC)') plot(f, sqrt(pxx_mv), 'DisplayName', 'Mid Voltage (DAC)') hold off; xlabel('Frequency [Hz]'); ylabel('ASD [$V/\sqrt{Hz}$]'); set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); legend('location', 'northeast'); xlim([1, 5e3]); #+end_src #+begin_src matlab [pxx_oc, f] = pwelch(open_circuit.de, win, 0, [], Fs); [pxx_mv, ~] = pwelch(mid_voltage.de, win, 0, [], Fs); [pxx_zv, ~] = pwelch(zero_voltage.de, win, 0, [], Fs); [pxx_sc, ~] = pwelch(short_circuit.de, win, 0, [], Fs); #+end_src #+begin_src matlab figure; hold on; plot(f, sqrt(pxx_oc), 'DisplayName', 'Open Circuit') plot(f, sqrt(pxx_sc), 'DisplayName', 'Amp Short-Circuited') plot(f, sqrt(pxx_zv), 'DisplayName', 'Zero Voltage (DAC)') plot(f, sqrt(pxx_mv), 'DisplayName', 'Mid Voltage (DAC)') hold off; xlabel('Frequency [Hz]'); ylabel('ASD [$m/\sqrt{Hz}$]'); set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); legend('location', 'northeast'); #+end_src * Simscape Model :PROPERTIES: :HEADER-ARGS:matlab+: :tangle matlab/test_bench_struts_1_simscape_model_comp.m :END: <> ** Introduction :ignore: The same simscape model that was presented in Section ref:sec:simscape_bench_apa is here used. However, now the full strut is put instead of only the APA (see Figure ref:fig:simscape_model_bench_struts). #+name: fig:simscape_model_bench_struts #+caption: Screenshot of the Simscape model of the strut fixed to the bench #+attr_latex: :width \linewidth [[file:figs/simscape_model_bench_struts.png]] 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: - Section ref:sec:struts_comp_2dof: the measured FRF are compared with the 2DoF APA model. - Section ref:sec: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 $V_a$ to $d_e$. - Section ref:sec:struts_effect_joint_stiffness: the effect of the flexible joint's stiffness on the dynamics is studied. 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$. ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab :tangle no %% Add useful folders to the path addpath('matlab/'); addpath('matlab/test_bench_struts/'); addpath('matlab/mat/'); addpath('matlab/src/'); addpath('matlab/png/'); #+end_src #+begin_src matlab :eval no %% Add useful folders to the path addpath('test_bench_struts/'); addpath('png/'); addpath('mat/'); addpath('src/'); #+end_src #+begin_src matlab %% Frequency vector used for many plots freqs = 2*logspace(0, 3, 1000); #+end_src #+begin_src matlab %% Options for Linearized options = linearizeOptions; options.SampleTime = 0; %% Name of the Simulink File mdl = 'test_bench_struts'; %% Open the Simulink File open(mdl) #+end_src ** Comparison with the 2-DoF Model <> *** First Identification The strut is initialized with default parameters (optimized parameters identified from previous experiments). #+begin_src matlab %% Initialize structure containing data for the Simscape model n_hexapod = struct(); n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof'); n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof'); n_hexapod.actuator = initializeAPA('type', '2dof'); #+end_src The inputs and outputs of the model are defined. #+begin_src matlab %% Input/Output definition clear io; io_i = 1; io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage io(io_i) = linio([mdl, '/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 The dynamics is identified and shown in Figure ref:fig:strut_bench_model_bode. #+begin_src matlab %% Run the linearization Gs = linearize(mdl, io, 0.0, options); Gs.InputName = {'Va'}; Gs.OutputName = {'Vs', 'de', 'da'}; #+end_src #+begin_src matlab :exports none %% Bode plot of the transfer functions figure; tiledlayout(3, 2, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(freqs, abs(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Encoder') plot(freqs, abs(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz'))), 'DisplayName', 'Interferometer') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'southwest'); ax1b = nexttile([2,1]); plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), 'k-') set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ax2 = nexttile; hold on; plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz')))) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz')))) set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:45:360); ylim([-180, 180]) ax2b = nexttile; hold on; plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), 'k-') set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:45:360); ylim([0, 180]) linkaxes([ax1,ax2,ax1b,ax2b],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_bench_model_bode.pdf', 'width', 'full', 'height', 'tall'); #+end_src #+name: fig:strut_bench_model_bode #+caption: Identified transfer function from $V_a$ to $V_s$ and from $V_a$ to $d_e,d_a$ using the simple 2DoF model for the APA #+RESULTS: [[file:figs/strut_bench_model_bode.png]] *** Comparison with the experimental Data The experimentally measured FRF are loaded. #+begin_src matlab %% Load measured FRF #+end_src #+begin_src matlab %% Add time delay to the Simscape model Gs = exp(-s*Ts)*Gs; #+end_src The FRF from $V_a$ to $d_a$ as well as from $V_a$ to $V_s$ are shown in Figure ref:fig:comp_strut_plant_after_opt and compared with the model. They are both found to match quite well with the model. #+begin_src matlab :exports none %% Compare the FRF and identified dynamics from Va to Vs and da figure; tiledlayout(3, 2, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(int_frf(:, 1)), 'color', [0,0,0,0.2], ... 'DisplayName', 'Meas. FRF'); for i = 2:length(leg_nums) plot(f, abs(int_frf(:, i)), 'color', [0,0,0,0.2], ... 'HandleVisibility', 'off'); end set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz'))), '-', ... 'DisplayName', 'Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'northeast'); ax1b = nexttile([2,1]); hold on; plot(f, abs(iff_frf(:, i)), 'color', [0,0,0,0.2], ... 'DisplayName', 'Meas. FRF'); for i = 1:length(leg_nums) plot(f, abs(iff_frf(:, i)), 'color', [0,0,0,0.2], ... 'HandleVisibility', 'off'); end set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), '-', ... 'DisplayName', 'Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); legend('location', 'southeast'); ax2 = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(int_frf(:, i)), 'color', [0,0,0,0.2]); end set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz'))), '-') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); ax2b = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(iff_frf(:, i)), 'color', [0,0,0,0.2]); end set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), '-') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2,ax1b,ax2b],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/comp_strut_plant_after_opt.pdf', 'width', 'full', 'height', 'tall'); #+end_src #+name: fig:comp_strut_plant_after_opt #+caption: Comparison of the measured FRF and the optimized model #+RESULTS: [[file:figs/comp_strut_plant_after_opt.png]] The measured FRF from $V_a$ to $d_e$ (encoder) is compared with the model in Figure ref:fig:comp_strut_plant_iff_after_opt. #+begin_src matlab :exports none %% Compare the FRF and identified dynamics from Va to de figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(enc_frf(:, 1)), 'color', [0,0,0,0.2], ... 'DisplayName', 'Meas. FRF'); for i = 2:length(leg_nums) plot(f, abs(enc_frf(:, i)), 'color', [0,0,0,0.2], ... 'HandleVisibility', 'off'); end set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz'))), '-', ... 'DisplayName', 'Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'northeast'); ax2 = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(enc_frf(:, i)), 'color', [0,0,0,0.2]); end set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz'))), '-') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([20, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/comp_strut_plant_iff_after_opt.pdf', 'width', 'normal', 'height', 'tall'); #+end_src #+name: fig:comp_strut_plant_iff_after_opt #+caption: Comparison of the measured FRF and the optimized model #+RESULTS: [[file:figs/comp_strut_plant_iff_after_opt.png]] #+begin_important The 2-DoF model is quite effective in modelling the transfer function from actuator to force sensor and from actuator to interferometer (Figure ref:fig:comp_strut_plant_after_opt). But it is not effective in modeling the transfer function from actuator to encoder (Figure ref:fig:comp_strut_plant_iff_after_opt). This is due to the fact that resonances greatly affecting the encoder reading are not modelled. In the next section, flexible model of the APA will be used to model such resonances. #+end_important ** Comparison with the Flexible Model <> *** First Identification The strut is initialized with default parameters (optimized parameters identified from previous experiments). #+begin_src matlab %% Initialize structure containing data for the Simscape model n_hexapod = struct(); n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof'); n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof'); n_hexapod.actuator = initializeAPA('type', 'flexible'); #+end_src The inputs and outputs of the model are defined. #+begin_src matlab %% Input/Output definition clear io; io_i = 1; io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage io(io_i) = linio([mdl, '/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 The dynamics is identified and shown in Figure ref:fig:strut_bench_model_bode. #+begin_src matlab %% Run the linearization Gs = linearize(mdl, io, 0.0, options); Gs.InputName = {'Va'}; Gs.OutputName = {'Vs', 'de', 'da'}; #+end_src *** Comparison with the experimental Data The experimentally measured FRF are loaded. #+begin_src matlab %% Load measured FRF load('meas_struts_frf.mat', 'f', 'Ts', 'enc_frf', 'int_frf', 'iff_frf', 'leg_nums'); #+end_src #+begin_src matlab %% Add time delay to the Simscape model Gs = exp(-s*Ts)*Gs; #+end_src The FRF from $V_a$ to $d_a$ as well as from $V_a$ to $V_s$ are shown in Figure ref:fig:comp_strut_plant_after_opt and compared with the model. They are both found to match quite well with the model. #+begin_src matlab :exports none %% Compare the FRF and identified dynamics from Va to Vs and da figure; tiledlayout(3, 2, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(enc_frf(:, 1)), 'color', [colors(2,:), 0.5], ... 'DisplayName', 'FRF - Encoder'); plot(f, abs(int_frf(:, 1)), 'color', [0,0,0, 0.2], ... 'DisplayName', 'FRF - Interferometer'); for i = 2:length(leg_nums) plot(f, abs(int_frf(:, i)), 'color', [0,0,0, 0.2], ... 'HandleVisibility', 'off'); end set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz'))), '--', ... 'DisplayName', 'Model - Interferometer') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'southwest'); ax1b = nexttile([2,1]); hold on; plot(f, abs(iff_frf(:, i)), 'color', [colors(2,:), 0.2], ... 'DisplayName', 'Meas. FRF'); for i = 1:length(leg_nums) plot(f, abs(iff_frf(:, i)), 'color', [0,0,0, 0.2], ... 'HandleVisibility', 'off'); end set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), '--', ... 'DisplayName', 'Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); legend('location', 'southeast'); ax2 = nexttile; hold on; plot(f, 180/pi*angle(enc_frf(:, 1)), 'color', [colors(2,:), 0.5], ... 'HandleVisibility', 'off'); for i = 1:length(leg_nums) plot(f, 180/pi*(angle(int_frf(:, i)) - angle(squeeze(freqresp(exp(-s*2*Ts), f, 'Hz')))), 'color', [0,0,0, 0.2]); end set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz'))), '--') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); ax2b = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(iff_frf(:, i)), 'color', [0,0,0, 0.2]); end set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('Vs', 'Va'), freqs, 'Hz'))), '--') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2,ax1b,ax2b],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/strut_meas_frf_model_int_force.pdf', 'width', 1500, 'height', 'tall'); #+end_src #+name: fig:strut_meas_frf_model_int_force #+caption: #+RESULTS: [[file:figs/strut_meas_frf_model_int_force.png]] #+begin_src matlab #+end_src ** Effect of a misalignment of the APA and flexible joints on the transfer function from actuator to encoder <> *** Introduction :ignore: As shown in Figure ref:fig:struts_frf_dvf_plant_tf, 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:apa_mode_shapes) can be excited differently. #+name: fig:apa_mode_shapes #+caption: Spurious resonances. a) X-bending mode at 189Hz. b) Y-bending mode at 285Hz. c) Z-torsion mode at 400Hz #+attr_latex: :width \linewidth [[file:figs/apa_mode_shapes.gif]] For instance, consider Figure ref:fig:strut_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:strut_misalign_schematic #+caption: Mis-alignement between the joints and the APA #+attr_latex: :width 0.8\linewidth [[file:figs/strut_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. But first, the measured FRF of the struts are loaded. #+begin_src matlab %% Load measured FRF of the struts load('meas_struts_frf.mat', 'f', 'Ts', 'enc_frf', 'int_frf', 'iff_frf', 'leg_nums'); #+end_src *** 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 #+begin_src matlab %% Input/Output definition clear io; io_i = 1; io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage io(io_i) = linio([mdl, '/de'], 1, 'openoutput'); io_i = io_i + 1; % Encoder io(io_i) = linio([mdl, '/da'], 1, 'openoutput'); io_i = io_i + 1; % Encoder #+end_src The transfer function is identified and shown in Figure ref:fig:comp_enc_frf_align_perfect. #+begin_src matlab %% Identification Gs = exp(-s*Ts)*linearize(mdl, io, 0.0, options); Gs.InputName = {'Va'}; Gs.OutputName = {'de', 'da'}; #+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; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(enc_frf(:, i)), 'color', [0,0,0,0.2], ... 'DisplayName', 'Meas. FRF'); for i = 2:length(leg_nums) plot(f, abs(enc_frf(:, i)), 'color', [0,0,0,0.2], ... 'HandleVisibility', 'off'); end set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz'))), '-', ... 'DisplayName', 'Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'northeast'); ax2 = nexttile; hold on; for i = 1:length(leg_nums) plot(f, 180/pi*angle(enc_frf(:, i)), 'color', [0,0,0,0.2]); end set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz'))), '-') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/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) n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align', [0; dy_aligns(i); 0]); G = exp(-s*Ts)*linearize(mdl, io, 0.0, options); G.InputName = {'Va'}; G.OutputName = {'de'}; 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; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(dy_aligns) plot(freqs, abs(squeeze(freqresp(Gs_align{i}('de', 'Va'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$d_y = %.1f$ [mm]', 1e3*dy_aligns(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'northeast'); ax2 = nexttile; hold on; for i = 1:length(dy_aligns) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_align{i}('de', 'Va'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([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) n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align', [dx_aligns(i); 0; 0]); G = exp(-s*Ts)*linearize(mdl, io, 0.0, options); G.InputName = {'Va'}; G.OutputName = {'de'}; 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; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(dx_aligns) plot(freqs, abs(squeeze(freqresp(Gs_align{i}('de', 'Va'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$d_x = %.2f$ [mm]', 1e3*dx_aligns(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'northeast'); ax2 = nexttile; hold on; for i = 1:length(dx_aligns) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_align{i}('de', 'Va'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([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 *** 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)); G = exp(-s*Ts)*linearize(mdl, io, 0.0, options); G.InputName = {'Va'}; G.OutputName = {'de', 'da'}; 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))); plot(freqs, abs(squeeze(freqresp(Gs_align{1}('de', 'Va'), 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', 'Va'), 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', 'Va'), 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', 'Va'), 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', 'Va'), 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 #+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; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); 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 plot(freqs, abs(squeeze(freqresp(Gs_align{1}('de', 'Va'), freqs, 'Hz'))), '--', 'color', colors(1,:), ... 'DisplayName', 'Model - $d_{e,i}/V_{a,i}$') for i = 2:5 plot(freqs, abs(squeeze(freqresp(Gs_align{i}('de', 'Va'), freqs, 'Hz'))), '--', 'color', colors(1,:), ... 'HandleVisibility', 'off'); end plot(freqs, abs(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz'))), '--', 'color', colors(2,:), ... '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]); plot(f, 180/pi*(angle(int_frf(:, i)) - angle(squeeze(freqresp(exp(-s*2*Ts), f, 'Hz')))), 'color', [colors(2,:),0.2]); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_align{i}('de', 'Va'), freqs, 'Hz'))), '--', 'color', colors(1,:)); end plot(freqs, 180/pi*angle(squeeze(freqresp(Gs('da', 'Va'), freqs, 'Hz'))), '--', 'color', colors(2,:)); 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]] #+begin_src matlab :exports none %% Comparison of the plants (encoder output) when tuning the misalignment freqs = 2*logspace(0, 3, 1000); colors = colororder; figure; tiledlayout(2, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile(); hold on; plot(f, abs(enc_frf(:, 5))); plot(freqs, abs(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz'))), 'k-'); plot(freqs, abs(squeeze(freqresp(Gs_align{5}('de', 'Va'), freqs, 'Hz'))), 'color', colors(2,:)); 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(:, 3)), 'DisplayName', 'Measured FRF'); plot(freqs, abs(squeeze(freqresp(Gs('de', 'Va'), freqs, 'Hz'))), 'k-', ... 'DisplayName', 'Perfectly Aligned'); plot(freqs, abs(squeeze(freqresp(Gs_align{3}('de', 'Va'), freqs, 'Hz'))), 'color', colors(2,:), ... 'DisplayName', 'Tuned Model'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); legend('location', 'southwest', 'FontSize', 8); linkaxes([ax1,ax2],'xy'); xlim([20, 2e3]); ylim([1e-8, 1e-3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/frf_model_encoder_strut.pdf', 'width', 'normal', 'height', 'full'); #+end_src #+name: fig:frf_model_encoder_strut #+caption: #+RESULTS: [[file:figs/frf_model_encoder_strut.png]] ** Effect of flexible joint's characteristics <> *** 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 The studied dynamics is between $V_a$ and the encoder displacement $d_e$. #+begin_src matlab %% Input/Output definition clear io; io_i = 1; io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage io(io_i) = linio([mdl, '/de'], 1, 'openoutput'); io_i = io_i + 1; % Encoder #+end_src *** Effect of bending stiffness of the flexible joints <> Let's initialize an APA which is a little bit misaligned. #+begin_src matlab %% APA Initialization n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align', [0.1e-3; 0.5e-3; 0]); #+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)); G = exp(-s*Ts)*linearize(mdl, io, 0.0, options); G.InputName = {'Va'}; G.OutputName = {'de'}; 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; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(kRs) plot(freqs, abs(squeeze(freqresp(Gs{i}('de', 'Va'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$k_R = %.0f$ [Nm/rad]', kRs(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'northeast'); ax2 = nexttile; hold on; for i = 1:length(kRs) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('de', 'Va'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([20, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/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 The bending stiffness of the joints has little impact on the transfer function from $V_a$ to $d_e$. #+end_important *** Effect of axial stiffness of the flexible 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)); G = exp(-s*Ts)*linearize(mdl, io, 0.0, options); G.InputName = {'Va'}; G.OutputName = {'de'}; 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; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(kzs) plot(freqs, abs(squeeze(freqresp(Gs{i}('de', 'Va'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$k_z = %.1e$ [N/m]', kzs(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'northeast'); ax2 = nexttile; hold on; for i = 1:length(kzs) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('de', 'Va'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([20, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/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 <> 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)); G = exp(-s*Ts)*linearize(mdl, io, 0.0, options); G.InputName = {'Va'}; G.OutputName = {'de'}; Gs(i) = {G}; end #+end_src 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; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(cRs) plot(freqs, abs(squeeze(freqresp(Gs{i}('de', 'Va'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$c_R = %.3f\\,[\\frac{Nm}{rad/s}]$', cRs(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/V_a$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'southwest'); ax2 = nexttile; hold on; for i = 1:length(cRs) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('de', 'Va'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([20, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/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]] #+begin_important Adding damping in bending for the flexible joints could be a nice way to reduce the effects of the spurious resonances of the struts. #+end_important #+begin_question How to effectively add damping to the flexible joints? One idea would be to introduce a sheet of damping material inside the flexible joint. Not sure is would be effect though. #+end_question ** TODO 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 %% Input/Output definition clear io; io_i = 1; io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage io(io_i) = linio([mdl, '/de'], 1, 'openoutput'); io_i = io_i + 1; % Encoder #+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*Ts)*linearize(mdl, io, 0.0, options); G.InputName = {'Va'}; G.OutputName = {'de'}; 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', 'Va'), 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', 'Va'), 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', 'Va'), 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', 'Va'), 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', 'Va'), 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 * Conclusion <> * 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 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 #+END_SRC ** Initialize other elements #+NAME: m-init-other #+BEGIN_SRC matlab %% Colors for the figures colors = colororder; #+END_SRC ** =initializeBotFlexibleJoint= - Initialize Flexible Joint :PROPERTIES: :header-args:matlab+: :tangle matlab/src/initializeBotFlexibleJoint.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** 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: :header-args:matlab+: :tangle matlab/src/initializeTopFlexibleJoint.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** 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: :header-args:matlab+: :tangle matlab/src/initializeAPA.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** 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 args.k (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.38e6 args.ke (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*1.75e6 args.ka (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*3e7 args.c (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*3e1 args.ce (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*2e1 args.ca (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*2e1 args.Leq (6,1) double {mustBeNumeric} = ones(6,1)*0.056 % Force Flexible APA args.xi (1,1) double {mustBeNumeric, mustBePositive} = 0.01 args.d_align (3,1) double {mustBeNumeric} = zeros(3,1) % [m] 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' actuator.Ga = -30.0; case 'flexible frame' actuator.Ga = 1; % TODO case 'flexible' actuator.Ga = 23.4; end else actuator.Ga = args.Ga; % Actuator gain [N/V] end #+end_src #+begin_src matlab if args.Gs == 0 switch args.type case '2dof' actuator.Gs = 0.098; case 'flexible frame' actuator.Gs = 1; % TODO case 'flexible' actuator.Gs = -4674824; end else actuator.Gs = args.Gs; % Sensor gain [V/m] end #+end_src *** 2DoF parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab actuator.k = args.k; % [N/m] actuator.ke = args.ke; % [N/m] actuator.ka = args.ka; % [N/m] actuator.c = args.c; % [N/(m/s)] actuator.ce = args.ce; % [N/(m/s)] actuator.ca = args.ca; % [N/(m/s)] actuator.Leq = args.Leq; % [m] #+end_src *** Flexible frame and fully flexible :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab switch args.type case 'flexible frame' actuator.K = readmatrix('APA300ML_b_mat_K.CSV'); % Stiffness Matrix actuator.M = readmatrix('APA300ML_b_mat_M.CSV'); % Mass Matrix actuator.P = extractNodes('APA300ML_b_out_nodes_3D.txt'); % Node coordinates [m] case 'flexible' actuator.K = readmatrix('full_APA300ML_K.CSV'); % Stiffness Matrix actuator.M = readmatrix('full_APA300ML_M.CSV'); % Mass Matrix actuator.P = extractNodes('full_APA300ML_out_nodes_3D.txt'); % Node coordiantes [m] actuator.d_align = args.d_align; 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 ** =generateSweepExc=: Generate sweep sinus excitation :PROPERTIES: :header-args:matlab+: :tangle ./matlab/src/generateSweepExc.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** Function description :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab function [U_exc] = generateSweepExc(args) % generateSweepExc - Generate a Sweep Sine excitation signal % % Syntax: [U_exc] = generateSweepExc(args) % % Inputs: % - args - Optinal arguments: % - Ts - Sampling Time - [s] % - f_start - Start frequency of the sweep - [Hz] % - f_end - End frequency of the sweep - [Hz] % - V_mean - Mean value of the excitation voltage - [V] % - V_exc - Excitation Amplitude for the Sweep, could be numeric or TF - [V] % - t_start - Time at which the sweep begins - [s] % - exc_duration - Duration of the sweep - [s] % - sweep_type - 'logarithmic' or 'linear' - [-] % - smooth_ends - 'true' or 'false': smooth transition between 0 and V_mean - [-] #+end_src *** Optional Parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab arguments args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-4 args.f_start (1,1) double {mustBeNumeric, mustBePositive} = 1 args.f_end (1,1) double {mustBeNumeric, mustBePositive} = 1e3 args.V_mean (1,1) double {mustBeNumeric} = 0 args.V_exc = 1 args.t_start (1,1) double {mustBeNumeric, mustBeNonnegative} = 5 args.exc_duration (1,1) double {mustBeNumeric, mustBePositive} = 10 args.sweep_type char {mustBeMember(args.sweep_type,{'log', 'lin'})} = 'lin' args.smooth_ends logical {mustBeNumericOrLogical} = true end #+end_src *** Sweep Sine part :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab t_sweep = 0:args.Ts:args.exc_duration; if strcmp(args.sweep_type, 'log') V_exc = sin(2*pi*args.f_start * args.exc_duration/log(args.f_end/args.f_start) * (exp(log(args.f_end/args.f_start)*t_sweep/args.exc_duration) - 1)); elseif strcmp(args.sweep_type, 'lin') V_exc = sin(2*pi*(args.f_start + (args.f_end - args.f_start)/2/args.exc_duration*t_sweep).*t_sweep); else error('sweep_type should either be equal to "log" or to "lin"'); end #+end_src #+begin_src matlab if isnumeric(args.V_exc) V_sweep = args.V_mean + args.V_exc*V_exc; elseif isct(args.V_exc) if strcmp(args.sweep_type, 'log') V_sweep = args.V_mean + abs(squeeze(freqresp(args.V_exc, args.f_start*(args.f_end/args.f_start).^(t_sweep/args.exc_duration), 'Hz')))'.*V_exc; elseif strcmp(args.sweep_type, 'lin') V_sweep = args.V_mean + abs(squeeze(freqresp(args.V_exc, args.f_start+(args.f_end-args.f_start)/args.exc_duration*t_sweep, 'Hz')))'.*V_exc; end end #+end_src *** Smooth Ends :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab if args.t_start > 0 t_smooth_start = args.Ts:args.Ts:args.t_start; V_smooth_start = zeros(size(t_smooth_start)); V_smooth_end = zeros(size(t_smooth_start)); if args.smooth_ends Vd_max = args.V_mean/(0.7*args.t_start); V_d = zeros(size(t_smooth_start)); V_d(t_smooth_start < 0.2*args.t_start) = t_smooth_start(t_smooth_start < 0.2*args.t_start)*Vd_max/(0.2*args.t_start); V_d(t_smooth_start > 0.2*args.t_start & t_smooth_start < 0.7*args.t_start) = Vd_max; V_d(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) = Vd_max - (t_smooth_start(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) - 0.7*args.t_start)*Vd_max/(0.2*args.t_start); V_smooth_start = cumtrapz(V_d)*args.Ts; V_smooth_end = args.V_mean - V_smooth_start; end else V_smooth_start = []; V_smooth_end = []; end #+end_src *** Combine Excitation signals :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab V_exc = [V_smooth_start, V_sweep, V_smooth_end]; t_exc = args.Ts*[0:1:length(V_exc)-1]; #+end_src #+begin_src matlab U_exc = [t_exc; V_exc]; #+end_src ** =generateShapedNoise=: Generate Shaped Noise excitation :PROPERTIES: :header-args:matlab+: :tangle ./matlab/src/generateShapedNoise.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** Function description :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab function [U_exc] = generateShapedNoise(args) % generateShapedNoise - Generate a Shaped Noise excitation signal % % Syntax: [U_exc] = generateShapedNoise(args) % % Inputs: % - args - Optinal arguments: % - Ts - Sampling Time - [s] % - V_mean - Mean value of the excitation voltage - [V] % - V_exc - Excitation Amplitude, could be numeric or TF - [V rms] % - t_start - Time at which the noise begins - [s] % - exc_duration - Duration of the noise - [s] % - smooth_ends - 'true' or 'false': smooth transition between 0 and V_mean - [-] #+end_src *** Optional Parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab arguments args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-4 args.V_mean (1,1) double {mustBeNumeric} = 0 args.V_exc = 1 args.t_start (1,1) double {mustBeNumeric, mustBePositive} = 5 args.exc_duration (1,1) double {mustBeNumeric, mustBePositive} = 10 args.smooth_ends logical {mustBeNumericOrLogical} = true end #+end_src *** Shaped Noise :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab t_noise = 0:args.Ts:args.exc_duration; #+end_src #+begin_src matlab if isnumeric(args.V_exc) V_noise = args.V_mean + args.V_exc*sqrt(1/args.Ts/2)*randn(length(t_noise), 1)'; elseif isct(args.V_exc) V_noise = args.V_mean + lsim(args.V_exc, sqrt(1/args.Ts/2)*randn(length(t_noise), 1), t_noise)'; end #+end_src *** Smooth Ends :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab t_smooth_start = args.Ts:args.Ts:args.t_start; V_smooth_start = zeros(size(t_smooth_start)); V_smooth_end = zeros(size(t_smooth_start)); if args.smooth_ends Vd_max = args.V_mean/(0.7*args.t_start); V_d = zeros(size(t_smooth_start)); V_d(t_smooth_start < 0.2*args.t_start) = t_smooth_start(t_smooth_start < 0.2*args.t_start)*Vd_max/(0.2*args.t_start); V_d(t_smooth_start > 0.2*args.t_start & t_smooth_start < 0.7*args.t_start) = Vd_max; V_d(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) = Vd_max - (t_smooth_start(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) - 0.7*args.t_start)*Vd_max/(0.2*args.t_start); V_smooth_start = cumtrapz(V_d)*args.Ts; V_smooth_end = args.V_mean - V_smooth_start; end #+end_src *** Combine Excitation signals :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab V_exc = [V_smooth_start, V_noise, V_smooth_end]; t_exc = args.Ts*[0:1:length(V_exc)-1]; #+end_src #+begin_src matlab U_exc = [t_exc; V_exc]; #+end_src ** =generateSinIncreasingAmpl=: Generate Sinus with increasing amplitude :PROPERTIES: :header-args:matlab+: :tangle ./matlab/src/generateSinIncreasingAmpl.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** Function description :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab function [U_exc] = generateSinIncreasingAmpl(args) % generateSinIncreasingAmpl - Generate Sinus with increasing amplitude % % Syntax: [U_exc] = generateSinIncreasingAmpl(args) % % Inputs: % - args - Optinal arguments: % - Ts - Sampling Time - [s] % - V_mean - Mean value of the excitation voltage - [V] % - sin_ampls - Excitation Amplitudes - [V] % - sin_freq - Excitation Frequency - [Hz] % - sin_num - Number of period for each amplitude - [-] % - t_start - Time at which the excitation begins - [s] % - smooth_ends - 'true' or 'false': smooth transition between 0 and V_mean - [-] #+end_src *** Optional Parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab arguments args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-4 args.V_mean (1,1) double {mustBeNumeric} = 0 args.sin_ampls double {mustBeNumeric, mustBePositive} = [0.1, 0.2, 0.3] args.sin_period (1,1) double {mustBeNumeric, mustBePositive} = 1 args.sin_num (1,1) double {mustBeNumeric, mustBePositive, mustBeInteger} = 3 args.t_start (1,1) double {mustBeNumeric, mustBePositive} = 5 args.smooth_ends logical {mustBeNumericOrLogical} = true end #+end_src *** Sinus excitation :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab t_noise = 0:args.Ts:args.sin_period*args.sin_num; sin_exc = []; #+end_src #+begin_src matlab for sin_ampl = args.sin_ampls sin_exc = [sin_exc, args.V_mean + sin_ampl*sin(2*pi/args.sin_period*t_noise)]; end #+end_src *** Smooth Ends :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab t_smooth_start = args.Ts:args.Ts:args.t_start; V_smooth_start = zeros(size(t_smooth_start)); V_smooth_end = zeros(size(t_smooth_start)); if args.smooth_ends Vd_max = args.V_mean/(0.7*args.t_start); V_d = zeros(size(t_smooth_start)); V_d(t_smooth_start < 0.2*args.t_start) = t_smooth_start(t_smooth_start < 0.2*args.t_start)*Vd_max/(0.2*args.t_start); V_d(t_smooth_start > 0.2*args.t_start & t_smooth_start < 0.7*args.t_start) = Vd_max; V_d(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) = Vd_max - (t_smooth_start(t_smooth_start > 0.7*args.t_start & t_smooth_start < 0.9*args.t_start) - 0.7*args.t_start)*Vd_max/(0.2*args.t_start); V_smooth_start = cumtrapz(V_d)*args.Ts; V_smooth_end = args.V_mean - V_smooth_start; end #+end_src *** Combine Excitation signals :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab V_exc = [V_smooth_start, sin_exc, V_smooth_end]; t_exc = args.Ts*[0:1:length(V_exc)-1]; #+end_src #+begin_src matlab U_exc = [t_exc; V_exc]; #+end_src