#+TITLE: Encoder Renishaw Vionic - Test Bench
:DRAWER:
#+LANGUAGE: en
#+EMAIL: dehaeze.thomas@gmail.com
#+AUTHOR: Dehaeze Thomas

#+HTML_LINK_HOME: ../index.html
#+HTML_LINK_UP:   ../index.html

#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://research.tdehaeze.xyz/css/style.css"/>
#+HTML_HEAD: <script type="text/javascript" src="https://research.tdehaeze.xyz/js/script.js"></script>

#+BIND: org-latex-image-default-option "scale=1"
#+BIND: org-latex-image-default-width ""

#+LaTeX_CLASS: scrreprt
#+LaTeX_CLASS_OPTIONS: [a4paper, 10pt, DIV=12, parskip=full]
#+LaTeX_HEADER_EXTRA: \input{preamble.tex}
#+EXPORT_FILE_NAME: test-bench-vionic.tex

#+PROPERTY: header-args:matlab  :session *MATLAB*
#+PROPERTY: header-args:matlab+ :comments org
#+PROPERTY: header-args:matlab+ :exports both
#+PROPERTY: header-args:matlab+ :results none
#+PROPERTY: header-args:matlab+ :eval no-export
#+PROPERTY: header-args:matlab+ :noweb yes
#+PROPERTY: header-args:matlab+ :mkdirp yes
#+PROPERTY: header-args:matlab+ :output-dir figs

#+PROPERTY: header-args:latex  :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/tikz/org/}{config.tex}")
#+PROPERTY: header-args:latex+ :imagemagick t :fit yes
#+PROPERTY: header-args:latex+ :iminoptions -scale 100% -density 150
#+PROPERTY: header-args:latex+ :imoutoptions -quality 100
#+PROPERTY: header-args:latex+ :results file raw replace
#+PROPERTY: header-args:latex+ :buffer no
#+PROPERTY: header-args:latex+ :tangle no
#+PROPERTY: header-args:latex+ :eval no-export
#+PROPERTY: header-args:latex+ :exports results
#+PROPERTY: header-args:latex+ :mkdirp yes
#+PROPERTY: header-args:latex+ :output-dir figs
#+PROPERTY: header-args:latex+ :post pdf2svg(file=*this*, ext="png")
:END:

#+begin_export html
  <hr>
  <p>This report is also available as a <a href="./test-bench-vionic.pdf">pdf</a>.</p>
  <hr>
#+end_export

* Introduction                                                        :ignore:

#+begin_note
You can find below the document of:
- [[file:doc/L-9517-9678-05-A_Data_sheet_VIONiC_series_en.pdf][Vionic Encoder]]
- [[file:doc/L-9517-9862-01-C_Data_sheet_RKLC_EN.pdf][Linear Scale]]
#+end_note

We would like to characterize the encoder measurement system.

In particular, we would like to measure:
- Power Spectral Density of the measurement noise
- Bandwidth of the sensor
- Linearity of the sensor

#+name: fig:encoder_vionic
#+caption: Picture of the Vionic Encoder
#+attr_latex: :width 0.6\linewidth
[[file:figs/encoder_vionic.png]]

* Encoder Model
The Encoder is characterized by its dynamics $G_m(s)$ from the "true" displacement $y$ to measured displacement $y_m$.
Ideally, this dynamics is constant over a wide frequency band with very small phase drop.

It is also characterized by its measurement noise $n$ that can be described by its Power Spectral Density (PSD).

The model of the encoder is shown in Figure [[fig:encoder-model-schematic]].

#+begin_src latex :file encoder-model-schematic.pdf
  \begin{tikzpicture}
    \node[block] (G) at (0,0){$G_m(s)$};
    \node[addb, left=0.8 of G] (add){};

    \draw[<-] (add.west) -- ++(-1.0, 0) node[above right]{$y$};
    \draw[->] (add.east) -- (G.west);
    \draw[->] (G.east) -- ++(1.0, 0) node[above left]{$y_m$};
    \draw[<-] (add.north) -- ++(0, 0.6) node[below right](n){$n$};

    \begin{scope}[on background layer]
      \node[fit={(add.west|-G.south) (n.north-|G.east)}, inner sep=8pt, draw, dashed, fill=black!20!white] (P) {};
      \node[below left] at (P.north east) {Encoder};
    \end{scope}
  \end{tikzpicture}
#+end_src

#+name: fig:encoder-model-schematic
#+caption: Model of the Encoder
#+RESULTS:
[[file:figs/encoder-model-schematic.png]]

We can also use a transfer function $G_n(s)$ to shape a noise $\tilde{n}$ with unity ASD as shown in Figure [[fig:vionic_expected_noise]].

#+begin_src latex :file encoder-model-schematic-with-asd.pdf
  \begin{tikzpicture}
    \node[block] (G) at (0,0){$G_m(s)$};
    \node[addb, left=0.8 of G] (add){};
    \node[block, above=0.5 of add] (Gn) {$G_n(s)$};

    \draw[<-] (add.west) -- ++(-1.0, 0) node[above right]{$y$};
    \draw[->] (add.east) -- (G.west);
    \draw[->] (G.east) -- ++(1.0, 0) node[above left]{$y_m$};
    \draw[->] (Gn.south) -- (add.north) node[above right]{$n$};
    \draw[<-] (Gn.north) -- ++(0, 0.6) node[below right](n){$\tilde{n}$};

    \begin{scope}[on background layer]
      \node[fit={(Gn.west|-G.south) (n.north-|G.east)}, inner sep=8pt, draw, dashed, fill=black!20!white] (P) {};
      \node[below left] at (P.north east) {Encoder};
    \end{scope}
  \end{tikzpicture}
#+end_src

#+RESULTS:
[[file:figs/encoder-model-schematic-with-asd.png]]

#+name: tab:vionic_characteristics_manual
#+caption: Characteristics of the Vionic Encoder
#+attr_latex: :environment tabularx :width \linewidth :align lXX
#+attr_latex: :center t :booktabs t :float t
| <l>                  |      <c>       |       <c>        |
| *Characteristics*    |    *Manual*    | *Specifications* |
|----------------------+----------------+------------------|
| Range                |  Ruler length  |    > 200 [um]    |
| Resolution           |    2.5 [nm]    |  < 50 [nm rms]   |
| Sub-Divisional Error | $< \pm 15\,nm$ |                  |
| Bandwidth            | To be checked  |    > 5 [kHz]     |

#+name: fig:vionic_expected_noise
#+attr_latex: :width \linewidth
#+caption: Expected interpolation errors for the Vionic Encoder
[[file:./figs/vionic_expected_noise.png]]


* Noise Measurement
<<sec:noise_measurement>>
** Test Bench

To measure the noise $n$ of the encoder, one can rigidly fix the head and the ruler together such that no motion should be measured.
Then, the measured signal $y_m$ corresponds to the noise $n$.

** Matlab Init                                              :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>>
#+end_src

#+begin_src matlab :exports none :results silent :noweb yes
<<matlab-init>>
#+end_src

#+begin_src matlab :tangle no
addpath('./matlab/mat/');
addpath('./matlab/');
#+end_src

#+begin_src matlab :eval no
addpath('./mat/');
#+end_src

** Results
First we load the data.
#+begin_src matlab
load('noise_meas_100s_20kHz.mat', 't', 'x');
x = x - mean(x);
#+end_src

The time domain data are shown in Figure [[fig:vionic_noise_time]].
#+begin_src matlab :exports none
figure;
hold on;
plot(t, 1e9*x, '.', 'DisplayName', 'Raw');
plot(t, 1e9*lsim(1/(1 + s/2/pi/500), x, t), 'DisplayName', 'LPF - 500Hz')
hold off;
xlabel('Time [s]');
ylabel('Displacement [nm]');
legend('location', 'northeast');
#+end_src

#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/vionic_noise_time.pdf', 'width', 'wide', 'height', 'normal');
#+end_src

#+name: fig:vionic_noise_time
#+caption: Time domain measurement (raw data and low pass filtered data)
#+RESULTS:
[[file:figs/vionic_noise_time.png]]
The amplitude spectral density is computed and shown in Figure [[fig:vionic_noise_asd]].

#+begin_src matlab :exports none
% Compute sampling Frequency
Ts = (t(end) - t(1))/(length(t)-1);
Fs = 1/Ts;
#+end_src

#+begin_src matlab :exports none
% Hannning Windows
win = hanning(ceil(0.5*Fs));

[pxx, f] = pwelch(x, win, [], [], Fs);
#+end_src

#+begin_src matlab :exports none
figure;
plot(f, sqrt(pxx));
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('ASD [$m/\sqrt{Hz}$]');
xlim([1, Fs/2]);
ylim([1e-11, 1e-9]);
#+end_src

#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/vionic_noise_asd.pdf', 'width', 'wide', 'height', 'normal');
#+end_src

#+name: fig:vionic_noise_asd
#+caption: Amplitude Spectral Density of the measured signal
#+RESULTS:
[[file:figs/vionic_noise_asd.png]]

Let's create a transfer function that approximate the measured noise of the encoder.
#+begin_src matlab
Gn_e = 1.8e-11/(1 + s/2/pi/5e3);
#+end_src

The amplitude of the transfer function and the measured ASD are shown in Figure [[fig:vionic_noise_asd_model]].

#+begin_src matlab :exports none
figure;
hold on;
plot(f, sqrt(pxx));
plot(f, abs(squeeze(freqresp(Gn_e, f, 'Hz'))), 'k--');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('ASD [$m/\sqrt{Hz}$]');
xlim([1, Fs/2]);
ylim([1e-11, 1e-9]);
#+end_src

#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/vionic_noise_asd_model.pdf', 'width', 'wide', 'height', 'normal');
#+end_src

#+name: fig:vionic_noise_asd_model
#+caption: Measured ASD of the noise and modelled one
#+RESULTS:
[[file:figs/vionic_noise_asd_model.png]]
* Linearity Measurement
<<sec:linearity_measurement>>
** Test Bench
In order to measure the linearity, we have to compare the measured displacement with a reference sensor with a known linearity.
An interferometer or capacitive sensor should work fine.
An actuator should also be there so impose a displacement.

One idea is to use the test-bench shown in Figure [[fig:test_bench_encoder_calibration]].

The APA300ML is used to excite the mass in a broad bandwidth.
The motion is measured at the same time by the Vionic Encoder and by an interferometer (most likely an Attocube).

As the interferometer has a very large bandwidth, we should be able to estimate the bandwidth of the encoder if it is less than the Nyquist frequency that can be around 10kHz.

#+name: fig:test_bench_encoder_calibration
#+caption: Schematic of the test bench
[[file:figs/test_bench_encoder_calibration.png]]

** Matlab Init                                              :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>>
#+end_src

#+begin_src matlab :exports none :results silent :noweb yes
<<matlab-init>>
#+end_src

#+begin_src matlab :tangle no
addpath('./matlab/mat/');
addpath('./matlab/');
#+end_src

#+begin_src matlab :eval no
addpath('./mat/');
#+end_src

** Results

* Dynamical Measurement
<<sec:dynamical_measurement>>
** Test Bench

** Matlab Init                                              :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>>
#+end_src

#+begin_src matlab :exports none :results silent :noweb yes
<<matlab-init>>
#+end_src

#+begin_src matlab :tangle no
addpath('./matlab/mat/');
addpath('./matlab/');
#+end_src

#+begin_src matlab :eval no
addpath('./mat/');
#+end_src

** Results
