spectral-analysis/index.org

1082 lines
40 KiB
Org Mode
Raw Normal View History

2019-12-02 15:47:40 +01:00
#+TITLE: Spectral Analysis using Matlab
2019-08-17 10:51:53 +02:00
:DRAWER:
#+LANGUAGE: en
#+EMAIL: dehaeze.thomas@gmail.com
#+AUTHOR: Dehaeze Thomas
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="./css/htmlize.css"/>
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="./css/readtheorg.css"/>
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="./css/zenburn.css"/>
#+HTML_HEAD: <script type="text/javascript" src="./js/jquery.min.js"></script>
#+HTML_HEAD: <script type="text/javascript" src="./js/bootstrap.min.js"></script>
#+HTML_HEAD: <script type="text/javascript" src="./js/jquery.stickytableheaders.min.js"></script>
#+HTML_HEAD: <script type="text/javascript" src="./js/readtheorg.js"></script>
#+PROPERTY: header-args:latex :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/thesis/latex/}{config.tex}")
2019-08-17 10:51:53 +02:00
#+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 raw replace :buffer no
#+PROPERTY: header-args:latex+ :eval no-export
#+PROPERTY: header-args:latex+ :exports both
#+PROPERTY: header-args:latex+ :mkdirp yes
#+PROPERTY: header-args:latex+ :output-dir figs
#+PROPERTY: header-args:latex+ :post pdf2svg(file=*this*, ext="png")
#+PROPERTY: header-args:matlab :session *MATLAB*
#+PROPERTY: header-args:matlab+ :tangle filters.m
#+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
:END:
* Introduction :ignore:
This document presents the mathematics as well as the matlab scripts to do various spectral analysis on a measured signal.
2019-08-17 10:51:53 +02:00
Some matlab documentation about Spectral Analysis can be found [[https://fr.mathworks.com/help/signal/ug/spectral-analysis.html][here]].
First, in section [[sec:spectral_analysis_basics]], some basics of spectral analysis are presented.
In some cases, we want to generate a time domain signal with defined Power Spectral Density.
Two methods are presented in sections [[sec:approximate_tf]] and [[sec:approximate_ifft]].
Finally, some notes are done on how to compute the noise level and signal level from a given Power Spectral Density in section [[sec:compute_psd_levels]].
* Spectral Analysis - Basics
2019-12-02 15:47:40 +01:00
:PROPERTIES:
:header-args:matlab+: :tangle matlab/spectral_analysis_basics.m
:header-args:matlab+: :comments org :mkdirp yes
:END:
<<sec:spectral_analysis_basics>>
2019-12-02 15:47:40 +01:00
** ZIP file containing the data and matlab files :ignore:
#+begin_src bash :exports none :results none
if [ matlab/spectral_analysis_basics.m -nt data/spectral_analysis_basics.zip ]; then
cp matlab/spectral_analysis_basics.m spectral_analysis_basics.m;
zip data/spectral_analysis_basics \
mat/data_028.mat \
spectral_analysis_basics.m
rm spectral_analysis_basics.m;
fi
#+end_src
#+begin_note
All the files (data and Matlab scripts) are accessible [[file:data/spectral_analysis_basics.zip][here]].
#+end_note
** Introduction :ignore:
2019-12-02 15:47:40 +01:00
In this section, the basics of spectral analysis is presented with the associated Matlab commands.
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
This include:
- how to compute the Power Spectral Density (PSD) and the Amplitude Spectral Density (ASD)
- how to take into account the sensitivity of the sensor and of the electronics
- how to compute the Cumulative Power Spectrum (CPS) and the Cumulative Amplitude Spectrum (CAS)
2019-08-17 10:51:53 +02:00
** Matlab Init :noexport:ignore:
2019-08-17 10:51:53 +02:00
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>>
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
<<matlab-init>>
#+end_src
** Sensitivity of the instrumentation
2019-12-02 15:47:40 +01:00
A typical measurement setup is shown in figure [[fig:velocity_to_voltage]] where we measure a physical signal which is here a velocity $v(t)$ using a geophone.
The geophone has some dynamics that we represent with $G_g(s)$, its output a voltage.
The output of the geophone is then amplified by a voltage amplifier with a transfer function $G_a(s)$.
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
Finally, the signal is discretised with an ADC and we obtain $x(k\Delta t)$.
To obtain the real physical quantity $v(t)$ as measured by the sensor from the obtained signal $x(k\Delta t)$, one have to know the sensitivity of the sensors and electronics used ($G_g(s)$ and $G_a(s)$).
2019-08-17 10:51:53 +02:00
#+begin_src latex :file velocity_to_voltage.pdf :post pdf2svg(file=*this*, ext="png") :exports results
\begin{tikzpicture}
\node[block] (geophone) at (0, 0) {$G_g(s)$};
\node[above] at (geophone.north) {Geophone};
\node[block, right=1 of geophone] (ampli) {$G_a(s)$};
\node[above] at (ampli.north) {Amplifier};
\node[ADC, right=1 of ampli] (adc) {ADC};
\draw[double, <-] (geophone.west) -- node[midway, above]{$v$ [m/s]} ++(-1.4, 0);
\draw[->] (geophone.east) -- node[midway, above]{[V]} (ampli.west);
\draw[->] (ampli.east) -- node[midway, above]{[V]} (adc.west);
\draw[->] (adc.east) -- node[sloped]{$/$}node[midway, above]{$x$ [V]} ++(1.4, 0);
\end{tikzpicture}
#+end_src
#+NAME: fig:velocity_to_voltage
#+CAPTION: Schematic of the instrumentation used for the measurement
#+RESULTS: fig:velocity_to_voltage
[[file:figs/velocity_to_voltage.png]]
Let's say, we know that the sensitivity of the geophone used is
\[ G_g(s) = G_0 \frac{\frac{s}{2\pi f_0}}{1 + \frac{s}{2\pi f_0}} \quad \left[\frac{V}{m/s}\right] \]
2019-12-02 15:47:40 +01:00
The parameters are defined below.
2019-08-17 10:51:53 +02:00
#+begin_src matlab
G0 = 88; % Sensitivity [V/(m/s)]
f0 = 2; % Cut-off frequency [Hz]
Gg = G0*(s/2/pi/f0)/(1+s/2/pi/f0);
#+end_src
2019-12-02 15:47:40 +01:00
And the dynamics of the amplifier in the bandwidth of interest is just a gain: $G_a(s) = 1000$.
2019-08-17 10:51:53 +02:00
#+begin_src matlab
2019-12-02 15:47:40 +01:00
Ga = 1000;
2019-08-17 10:51:53 +02:00
#+end_src
2019-12-02 15:47:40 +01:00
** Convert the time domain from volts to velocity
Let's here try to obtain the time domain signal $v(t)$ from the measurement $x$.
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
If ${G_a(s)}^{-1} {G_g(s)}^{-1}$ is proper, we can simulate this dynamical system to go from the voltage $x$ to the velocity $v$ as shown in figure [[fig:voltage_to_velocity]].
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
If ${G_a(s)}^{-1} {G_g(s)}^{-1}$ is not proper, we add low pass filters at high frequency to make the system proper.
2019-08-17 10:51:53 +02:00
#+begin_src latex :file voltage_to_velocity.pdf :post pdf2svg(file=*this*, ext="png") :exports results
\begin{tikzpicture}
\node[block] (ampli) at (0, 0) {${G_a(s)}^{-1}$};
\node[above] at (ampli.north) {Amplifier};
\node[block, right=1 of ampli] (geophone) {${G_g(s)}^{-1}$};
\node[above] at (geophone.north) {Geophone};
\draw[<-] (ampli.west) -- node[midway, above]{$x$ [V]}node[sloped]{$/$} ++(-1.4, 0);
\draw[->] (ampli.east) -- node[midway, above]{[V]}node[sloped]{$/$} (geophone.west);
\draw[->] (geophone.east) -- node[midway, above]{$v$ [m/s]}node[sloped]{$/$} ++(1.4, 0);
\end{tikzpicture}
#+end_src
#+NAME: fig:voltage_to_velocity
#+CAPTION: Schematic of the instrumentation used for the measurement
#+RESULTS: fig:voltage_to_velocity
[[file:figs/voltage_to_velocity.png]]
2019-12-02 15:47:40 +01:00
Let's load the measured $x$.
2019-08-17 10:51:53 +02:00
#+begin_src matlab
2019-12-02 15:47:40 +01:00
data = load('mat/data_028.mat', 'data'); data = data.data;
t = data(:, 3); % Time vector [s]
x = data(:, 1)-mean(data(:, 1)); % The offset if removed (coming from the voltage amplifier) [v]
dt = t(2)-t(1); % Sampling Time [s]
Fs = 1/dt; % Sampling Frequency [Hz]
2019-08-17 10:51:53 +02:00
#+end_src
2019-12-02 15:47:40 +01:00
We simulate this system with matlab using the =lsim= command.
2019-08-17 10:51:53 +02:00
#+begin_src matlab
2019-12-02 15:47:40 +01:00
v = lsim(inv(Gg*Ga), x, t);
#+end_src
And we plot the obtained velocity
#+begin_src matlab :exports none
2019-08-17 10:51:53 +02:00
figure;
plot(t, v);
2019-12-02 15:47:40 +01:00
xlabel("Time [s]");
ylabel("Velocity [m/s]");
2019-08-17 10:51:53 +02:00
#+end_src
#+NAME: fig:velocity_time
#+HEADER: :tangle no :exports results :results value raw replace :noweb yes
2019-12-02 15:47:40 +01:00
#+begin_src matlab :var filepath="figs/velocity_time.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
2019-08-17 10:51:53 +02:00
<<plt-matlab>>
#+end_src
#+NAME: fig:velocity_time
2019-12-02 15:47:40 +01:00
#+CAPTION: Computed Velocity from the measured Voltage
2019-08-17 10:51:53 +02:00
#+RESULTS: fig:velocity_time
[[file:figs/velocity_time.png]]
** Power Spectral Density and Amplitude Spectral Density
2019-12-02 15:47:40 +01:00
From the Matlab documentation:
#+begin_quote
The goal of spectral estimation is to describe the distribution (over frequency) of the power contained in a signal, based on a finite set of data.
#+end_quote
We now have the velocity $v(t)\ [m/s]$ in the time domain.
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
The Power Spectral Density (PSD) $S_v(f)$ of the time domain $v(t)$ can be computed using the following equation:
\[ S_v(f) = \frac{1}{f_s} \sum_{m=-\infty}^{\infty} R_{xx}(m) e^{-j 2 \pi m f / f_s} \ \left[\frac{(m/s)^2}{Hz}\right] \]
where
- $f_s$ is the sampling frequency in Hz
- $R_{xx}$ is the autocorrelation
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
The PSD represents the distribution of the (average) signal power over frequency.
$S_v(f)df$ is the infinitesimal power in the band $(f-df/2, f+df/2)$ and the total power in the signal is obtained by integrating these infinitesimal contributions.
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
To compute the Power Spectral Density with matlab, we use the =pwelch= function ([[https://fr.mathworks.com/help/signal/ref/pwelch.html?s_tid=doc_ta][documentation]]).
The use of the =pwelch= function is:
=[pxx,w] = pwelch(x,window,noverlap,nfft, fs)=
with:
- =x= is the discrete time signal
- =window= is a window that is used to smooth the obtained PSD
- =overlap= can be used to have some overlap from section to section
- =nfft= specifies the number of FFT points for the PSD
- =fs= is the sampling frequency of the data =x= in Hertz
As explained in cite:schmid12_how_to_use_fft_matlab, it is recommended to use the =pwelch= function the following way:
First, define a window (preferably the =hanning= one) by specifying the averaging factor =na=.
2019-08-17 10:51:53 +02:00
#+begin_src matlab
2019-12-02 15:47:40 +01:00
nx = length(v);
na = 8;
win = hanning(floor(nx/na));
2019-08-17 10:51:53 +02:00
#+end_src
2019-12-02 15:47:40 +01:00
Then, compute the power spectral density $S_v$ and the associated frequency vector $f$ with no overlap.
2019-08-17 10:51:53 +02:00
#+begin_src matlab
2019-12-02 15:47:40 +01:00
[Sv, f] = pwelch(v, win, 0, [], Fs);
2019-08-17 10:51:53 +02:00
#+end_src
2019-12-02 15:47:40 +01:00
The obtained PSD is shown in figure [[fig:psd_velocity]].
#+begin_src matlab :exports none
2019-08-17 10:51:53 +02:00
figure;
2019-12-02 15:47:40 +01:00
plot(f, Sv);
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
2019-08-17 10:51:53 +02:00
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density $\left[\frac{(m/s)^2}{Hz}\right]$')
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
2019-08-17 10:51:53 +02:00
#+end_src
#+NAME: fig:psd_velocity
#+HEADER: :tangle no :exports results :results value raw replace :noweb yes
2019-12-02 15:47:40 +01:00
#+begin_src matlab :var filepath="figs/psd_velocity.pdf" :var figsize="wide-tall" :post pdf2svg(file=*this*, ext="png")
2019-08-17 10:51:53 +02:00
<<plt-matlab>>
#+end_src
#+NAME: fig:psd_velocity
#+CAPTION: Power Spectral Density of the measured velocity
#+RESULTS: fig:psd_velocity
2019-12-02 15:47:40 +01:00
[[file:figs/psd_velocity.png]]
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
The Amplitude Spectral Density (ASD) is defined as the square root of the Power Spectral Density and is shown in figure [[fig:asd_velocity]].
2019-08-17 10:51:53 +02:00
\begin{equation}
\Gamma_{vv}(f) = \sqrt{S_{vv}(f)} \quad \left[ \frac{m/s}{\sqrt{Hz}} \right]
2019-08-17 10:51:53 +02:00
\end{equation}
2019-12-02 15:47:40 +01:00
#+begin_src matlab :exports none
2019-08-17 10:51:53 +02:00
figure;
2019-12-02 15:47:40 +01:00
plot(f, sqrt(Sv));
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
2019-08-17 10:51:53 +02:00
xlabel('Frequency [Hz]');
ylabel('Amplitude Spectral Density $\left[\frac{m/s}{\sqrt{Hz}}\right]$')
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
2019-08-17 10:51:53 +02:00
#+end_src
#+NAME: fig:asd_velocity
#+HEADER: :tangle no :exports results :results value raw replace :noweb yes
2019-12-02 15:47:40 +01:00
#+begin_src matlab :var filepath="figs/asd_velocity.pdf" :var figsize="wide-tall" :post pdf2svg(file=*this*, ext="png")
2019-08-17 10:51:53 +02:00
<<plt-matlab>>
#+end_src
#+NAME: fig:asd_velocity
#+CAPTION: Power Spectral Density of the measured velocity
#+RESULTS: fig:asd_velocity
2019-12-02 15:47:40 +01:00
[[file:figs/asd_velocity.png]]
2019-08-17 10:51:53 +02:00
** Modification of a signal's Power Spectral Density when going through an LTI system
2019-12-02 15:47:40 +01:00
Instead of computing the time domain velocity before computing the Power Spectral Density, we could have directly computed the PSD of the measured voltage $x$ and then take into account the sensitivity of the measurement devices to have the PSD of the velocity.
To do so, we use the fact that a signal $u$ with a PSD $S_{uu}$ going through a LTI system $G_(s)$ (figure [[fig:velocity_to_voltage_psd]]) will generate a signal $y$ with a PSD:
\begin{equation}
S_{yy}(\omega) = \left|G(j\omega)\right|^2 S_{uu}(\omega)
\end{equation}
2019-08-17 10:51:53 +02:00
#+begin_src latex :file velocity_to_voltage_psd.pdf :post pdf2svg(file=*this*, ext="png") :exports results
\begin{tikzpicture}
\node[block] (G) at (0, 0) {$G(s)$};
2019-12-02 15:47:40 +01:00
\draw[<-] (G.west) -- node[midway, above]{$u$} ++(-1.4, 0);
2019-08-17 10:51:53 +02:00
\draw[->] (G.east) -- node[midway, above]{$y$} ++(1.4, 0);
\end{tikzpicture}
#+end_src
#+NAME: fig:velocity_to_voltage_psd
#+CAPTION: Schematic of the instrumentation used for the measurement
#+RESULTS: fig:velocity_to_voltage_psd
[[file:figs/velocity_to_voltage_psd.png]]
2019-12-02 15:47:40 +01:00
Similarly, the ASD of $y$ is:
2019-08-17 10:51:53 +02:00
\begin{equation}
2019-12-02 15:47:40 +01:00
\Gamma_{yy}(\omega) = \left|G(j\omega)\right| \Gamma_{uu}(\omega)
2019-08-17 10:51:53 +02:00
\end{equation}
2019-12-02 15:47:40 +01:00
Thus, we could have computed the PSD of $x$ and then obtain the PSD of the velocity with:
\[ S_{v}(\omega) = |G_a(j\omega) G_g(j\omega)|^{-1} S_{x}(\omega) \]
The PSD of $x$ is computed below.
#+begin_src matlab
nx = length(x);
na = 8;
win = hanning(floor(nx/na));
[Sx, f] = pwelch(x, win, 0, [], Fs);
#+end_src
And the PSD of $v$ is obtained with the below code.
#+begin_src matlab
Svv = Sx.*squeeze(abs(freqresp(inv(Gg*Ga), f, 'Hz'))).^2;
#+end_src
The result is compare with the PSD computed from the $v$ signal obtained with the =lsim= command in figure [[fig:psd_velocity_lti_method]].
#+begin_src matlab :exports none
figure;
hold on;
plot(f, Sv, 'DisplayName', 'lsim technique');
plot(f, Svv, 'DisplayName', 'LTI technique');
hold off;
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density $\left[\frac{(m/s)^2}{Hz}\right]$');
xlim([0.1, 500]);
legend('location', 'southwest');
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/psd_velocity_lti_method.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
#+NAME: fig:psd_velocity_lti_method
#+CAPTION: Obtain PSD of the velocity using the formula ([[./figs/psd_velocity_lti_method.png][png]], [[./figs/psd_velocity_lti_method.pdf][pdf]])
[[file:figs/psd_velocity_lti_method.png]]
2019-08-17 10:51:53 +02:00
** From PSD of the velocity to the PSD of the displacement
2019-12-02 15:47:40 +01:00
Similarly to what has been done in the last section, we can consider the displacement $d$ can be obtained from the velocity $v$ by going through an LTI system $1/s$ as shown in figure [[fig:velocity_to_displacement_psd]].
2019-08-17 10:51:53 +02:00
#+begin_src latex :file velocity_to_displacement_psd.pdf :post pdf2svg(file=*this*, ext="png") :exports results
\begin{tikzpicture}
\node[block] (G) at (0, 0) {$\frac{1}{s}$};
\draw[<-] (G.west) -- node[midway, above]{$v$} ++(-1, 0);
2019-12-02 15:47:40 +01:00
\draw[->] (G.east) -- node[midway, above]{$d$} ++(1, 0);
2019-08-17 10:51:53 +02:00
\end{tikzpicture}
#+end_src
#+NAME: fig:velocity_to_displacement_psd
#+CAPTION: Schematic of the instrumentation used for the measurement
#+RESULTS: fig:velocity_to_displacement_psd
[[file:figs/velocity_to_displacement_psd.png]]
2019-12-02 15:47:40 +01:00
We then have the relation between the PSD of $d$ and the PSD of $v$:
2019-08-17 10:51:53 +02:00
\begin{equation}
2019-12-02 15:47:40 +01:00
S_{dd}(\omega) = \left|\frac{1}{j \omega}\right|^2 S_{vv}(\omega)
2019-08-17 10:51:53 +02:00
\end{equation}
2019-12-02 15:47:40 +01:00
Using a frequency variable $f$ in Hz:
2019-08-17 10:51:53 +02:00
\begin{equation}
2019-12-02 15:47:40 +01:00
S_{dd}(f) = \left| \frac{1}{j 2\pi f} \right|^2 S_{vv}(f)
2019-08-17 10:51:53 +02:00
\end{equation}
For the Amplitude Spectral Density:
\begin{equation}
2019-12-02 15:47:40 +01:00
\Gamma_{dd}(f) = \frac{1}{2\pi f} \Gamma_{vv}(f)
2019-08-17 10:51:53 +02:00
\end{equation}
2019-12-02 15:47:40 +01:00
Note here that the PSD (and ASD) of one variable and its derivatives/integrals are equal at one particular frequency $f = 1\ rad/s \approx 0.16\ Hz$:
\begin{equation}
S_{xx}(\omega = 1) = S_{vv}(\omega = 1)
\end{equation}
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
With Matlab, the PSD of the displacement can be computed from the PSD of the velocity with the following code.
#+begin_src matlab
Sd = Sv.*(1./(2*pi*f)).^2;
#+end_src
The obtained PSD of the displacement can be seen in figure [[fig:psd_velocity_displacement]].
#+begin_src matlab :exports none
figure;
hold on;
plot(f, Sd, 'DisplayName', '$S_d$ in $\left[\frac{m^2}{Hz}\right]$');
plot(f, Sv, 'DisplayName', '$S_v$ in $\left[\frac{(m/s)^2}{Hz}\right]$');
hold off;
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density');
xlim([0.1, 500]);
legend('location', 'southwest');
#+end_src
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/psd_velocity_displacement.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
#+NAME: fig:psd_velocity_displacement
#+CAPTION: PSD of the Velocity and Displacement ([[./figs/psd_velocity_displacement.png][png]], [[./figs/psd_velocity_displacement.pdf][pdf]])
[[file:figs/psd_velocity_displacement.png]]
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
** Cumulative Power/Amplitude Spectrum
The Cumulative Power Spectrum is the cumulative integral of the Power Spectral Density:
#+NAME: eq:cps
\begin{equation}
CPS_v(f) = \int_0^f PSD_v(\nu) d\nu \quad [(m/s)^2]
\end{equation}
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
It is also possible to integrate from high frequency to low frequency:
#+NAME: eq:cps_inv
\begin{equation}
CPS_v(f) = \int_f^\infty PSD_v(\nu) d\nu \quad [(m/s)^2]
\end{equation}
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
The Cumulative Power Spectrum taken at frequency $f$ thus represent the power in the signal in the frequency band $0$ to $f$ or $f$ to $\infty$ depending on the above definition taken.
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
The choice of the integral direction depends on the shape of the PSD.
If the power is mostly present at low frequencies, it is preferable to use equation [[eq:cps_inv]].
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
The Cumulative Amplitude Spectrum is defined as the square root of the Cumulative Power Spectrum:
2019-08-17 10:51:53 +02:00
\[ CAS_v(f) = \sqrt{CPS_v(f)} = \sqrt{\int_f^\infty PSD_v(\nu) d\nu} \quad [m/s] \]
2019-12-02 15:47:40 +01:00
The Root Mean Square value of the velocity corresponds to the Cumulative Amplitude Spectrum when integrated at all frequencies:
\[ v_{\text{rms}} = \sqrt{\int_0^\infty PSD_v(\nu) d\nu} = CAS_v(0) \quad [m/s \ \text{rms}] \]
With Matlab, the Cumulative Power Spectrum can be computed with the below formulas and the results are shown in figure [[fig:cps_integral_comp]].
#+begin_src matlab
CPS_v = cumtrapz(f, Sv); % Cumulative Power Spectrum from low to high frequencies
CPS_vv = flip(-cumtrapz(flip(f), flip(Sv))); % Cumulative Power Spectrum from high to low frequencies
#+end_src
2019-08-17 10:51:53 +02:00
#+begin_src matlab :results none
figure;
2019-12-02 15:47:40 +01:00
ax1 = subplot(1, 2, 1);
hold on;
2019-12-02 15:47:40 +01:00
plot(f, CPS_v);
hold off;
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
xlabel('Frequency [Hz]'); ylabel('Cumulative Power Spectrum [$(m/s)^2$]')
2019-12-02 15:47:40 +01:00
ax2 = subplot(1, 2, 2);
hold on;
2019-12-02 15:47:40 +01:00
plot(f, CPS_vv);
hold off;
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
2019-12-02 15:47:40 +01:00
xlabel('Frequency [Hz]');
linkaxes([ax1,ax2],'xy');
xlim([0.1, 500]); ylim([1e-15, 1e-11]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/cps_integral_comp.pdf" :var figsize="full-tall" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
2019-12-02 15:47:40 +01:00
#+NAME: fig:cps_integral_comp
#+CAPTION: Cumulative Power Spectrum ([[./figs/cps_integral_comp.png][png]], [[./figs/cps_integral_comp.pdf][pdf]])
[[file:figs/cps_integral_comp.png]]
* Time domain signal that approximate a PSD - TF technique
:PROPERTIES:
:header-args:matlab+: :tangle matlab/approximate_psd_tf.m
:header-args:matlab+: :comments org :mkdirp yes
:END:
<<sec:approximate_tf>>
2019-12-02 15:47:40 +01:00
** ZIP file containing the data and matlab files :ignore:
#+begin_src bash :exports none :results none
if [ matlab/approximate_psd_tf.m -nt data/approximate_psd_tf.zip ]; then
cp matlab/approximate_psd_tf.m approximate_psd_tf.m;
zip data/approximate_psd_tf \
mat/dist_psd.mat \
approximate_psd_tf.m
rm approximate_psd_tf.m;
fi
#+end_src
#+begin_note
All the files (data and Matlab scripts) are accessible [[file:data/approximate_psd_tf.zip][here]].
#+end_note
** Introduction :ignore:
** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>>
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
<<matlab-init>>
#+end_src
** Signal's PSD
We load the PSD of the signal we wish to replicate.
#+begin_src matlab
load('./mat/dist_psd.mat', 'dist_f');
#+end_src
We remove the first value with very high PSD.
#+begin_src matlab
dist_f.f = dist_f.f(3:end);
dist_f.psd_gm = dist_f.psd_gm(3:end);
#+end_src
The PSD of the signal is shown on figure ref:fig:psd_ground_motion.
#+begin_src matlab :exports none
figure;
hold on;
plot(dist_f.f, dist_f.psd_gm)
hold off;
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density');
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/psd_ground_motion.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
#+NAME: fig:psd_ground_motion
#+CAPTION: PSD of the signal ([[./figs/psd_ground_motion.png][png]], [[./figs/psd_ground_motion.pdf][pdf]])
[[file:figs/psd_ground_motion.png]]
** Transfer Function that approximate the ASD
2019-12-02 15:47:40 +01:00
Using =sisotool= or any other tool, we create a transfer function $G$ such that its magnitude is close to the Amplitude Spectral Density $\Gamma_x = \sqrt{S_x}$:
\[ |G(j\omega)| \approx \Gamma_x(\omega) \]
#+begin_src matlab
G_gm = 0.002*(s^2 + 3.169*s + 27.74)/(s*(s+32.73)*(s+8.829)*(s+7.983)^2);
#+end_src
2019-12-02 15:47:40 +01:00
We compare the ASD $\Gamma_x(\omega)$ and the magnitude of the generated transfer function $|G(j\omega)|$ in figure [[]].
#+begin_src matlab :exports none
figure;
hold on;
plot(dist_f.f, sqrt(dist_f.psd_gm))
plot(dist_f.f, abs(squeeze(freqresp(G_gm, dist_f.f, 'Hz'))))
hold off;
xlabel('Frequency [Hz]');
2019-12-02 15:47:40 +01:00
ylabel('Amplitude Spectral Density');
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/asd_and_tf_compare.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
2019-12-02 15:47:40 +01:00
#+NAME: fig:asd_and_tf_compare
#+CAPTION: Comparison of the ASD and of the transfer function's magnitude ([[./figs/asd_and_tf_compare.png][png]], [[./figs/asd_and_tf_compare.pdf][pdf]])
[[file:figs/asd_and_tf_compare.png]]
** Generated Time domain signal
2019-12-02 15:47:40 +01:00
We know that a signal $u$ going through a LTI system $G$ (figure [[fig:velocity_to_voltage_psd_bis]]) will have its ASD modified according to the following equation:
\begin{equation}
\Gamma_{yy}(\omega) = \left|G(j\omega)\right| \Gamma_{uu}(\omega)
\end{equation}
#+NAME: fig:velocity_to_voltage_psd_bis
#+CAPTION: Schematic of the instrumentation used for the measurement
[[file:figs/velocity_to_voltage_psd.png]]
Thus, if we create a random signal with an ASD equal to one at all frequency and we pass this signal through the previously defined LTI transfer function =G_gm=, we should obtain a signal with an ASD that approximate the original ASD.
To obtain a random signal with an ASD equal to one, we use the following code.
#+begin_src matlab
2019-12-02 15:47:40 +01:00
Fs = 2*dist_f.f(end); % Sampling Frequency [Hz]
Ts = 1/Fs; % Sampling Time [s]
2019-12-02 15:47:40 +01:00
t = 0:Ts:500; % Time Vector [s]
u = sqrt(Fs/2)*randn(length(t), 1); % Signal with an ASD equal to one
#+end_src
2019-12-02 15:47:40 +01:00
We then use =lsim= to compute $y$ as shown in figure [[fig:velocity_to_voltage_psd_bis]].
#+begin_src matlab
2019-12-02 15:47:40 +01:00
y = lsim(G_gm, u, t);
#+end_src
2019-12-02 15:47:40 +01:00
The obtained time domain signal is shown in figure [[fig:time_domain_u]].
#+begin_src matlab :exports none
figure;
2019-12-02 15:47:40 +01:00
plot(t, y);
xlabel('Time [s]');
ylabel('Amplitude');
#+end_src
2019-12-02 15:47:40 +01:00
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/time_domain_u.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
#+NAME: fig:time_domain_u
#+CAPTION: Obtained time domain signal $y(t)$ ([[./figs/time_domain_u.png][png]], [[./figs/time_domain_u.pdf][pdf]])
[[file:figs/time_domain_u.png]]
** Comparison of the Power Spectral Densities
2019-12-02 15:47:40 +01:00
We now compute the Power Spectral Density of the computed time domain signal $y$.
2019-08-17 10:51:53 +02:00
#+begin_src matlab
2019-12-02 15:47:40 +01:00
nx = length(y);
na = 16;
win = hanning(floor(nx/na));
2019-08-17 10:51:53 +02:00
2019-12-02 15:47:40 +01:00
[pxx, f] = pwelch(y, win, 0, [], Fs);
#+end_src
Finally, we compare the PSD of the original signal and the obtained signal on figure ref:fig:psd_comparison.
#+begin_src matlab :exports none
figure;
hold on;
plot(dist_f.f, dist_f.psd_gm, 'DisplayName', 'Original PSD')
plot(f, pxx, 'DisplayName', 'Computed')
hold off;
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density');
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
legend('location', 'northeast');
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/compare_psd_tf_technique.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
2019-12-02 15:47:40 +01:00
#+NAME: fig:compare_psd_tf_technique
#+CAPTION: Comparison of the original PSD and the PSD of the computed time domain signal ([[./figs/compare_psd_tf_technique.png][png]], [[./figs/compare_psd_tf_technique.pdf][pdf]])
[[file:figs/compare_psd_tf_technique.png]]
** Simulink
2019-12-02 15:47:40 +01:00
One advantage of this technique is that it can be easily integrated into simulink.
The corresponding schematic is shown in figure [[fig:simulink_psd_generate]] where the block =Band-Limited White Noise= is used to generate a random signal with a PSD equal to one (parameter =Noise Power= is set to 1).
Then, the signal generated pass through the transfer function representing the wanted ASD.
#+name: fig:simulink_psd_generate
#+caption: Simulink Schematic
[[file:figs/simulink_psd_generate.png]]
2019-12-02 15:47:40 +01:00
We simulate the system shown in figure [[fig:simulink_psd_generate]].
#+begin_src matlab
out = sim('matlab/generate_signal_psd.slx');
#+end_src
2019-12-02 15:47:40 +01:00
And we compute the PSD of the generated signal.
#+begin_src matlab
nx = length(out.u_gm.Data);
na = 8;
win = hanning(floor(nx/na));
[pxx, f] = pwelch(out.u_gm.Data, win, 0, [], 1e3);
#+end_src
2019-12-02 15:47:40 +01:00
Finally, we compare the PSD of the generated signal with the original PSD in figure [[fig:compare_psd_original_simulink]].
#+begin_src matlab :exports none
figure;
hold on;
plot(dist_f.f, dist_f.psd_gm, 'DisplayName', 'Original PSD')
2019-12-02 15:47:40 +01:00
plot(f, pxx, 'DisplayName', 'Computed from Simulink')
hold off;
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density');
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
legend('location', 'northeast');
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/compare_psd_original_simulink.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
2019-12-02 15:47:40 +01:00
#+NAME: fig:compare_psd_original_simulink
#+CAPTION: Comparison of the obtained signal's PSD and original PSD ([[./figs/compare_psd_original_simulink.png][png]], [[./figs/compare_psd_original_simulink.pdf][pdf]])
[[file:figs/compare_psd_original_simulink.png]]
* Time domain signal that approximate a PSD - IFFT technique
:PROPERTIES:
:header-args:matlab+: :tangle matlab/approximate_psd_ifft.m
:header-args:matlab+: :comments org :mkdirp yes
:END:
<<sec:approximate_ifft>>
2019-12-02 15:47:40 +01:00
** ZIP file containing the data and matlab files :ignore:
#+begin_src bash :exports none :results none
if [ matlab/approximate_psd_ifft.m -nt data/approximate_psd_ifft.zip ]; then
cp matlab/approximate_psd_ifft.m approximate_psd_ifft.m;
zip data/approximate_psd_ifft \
mat/dist_psd.mat \
approximate_psd_ifft.m
rm approximate_psd_ifft.m;
fi
#+end_src
#+begin_note
All the files (data and Matlab scripts) are accessible [[file:data/approximate_psd_ifft.zip][here]].
#+end_note
** Introduction :ignore:
The technique comes from cite:preumont94_random_vibrat_spect_analy (section 12.11).
2019-12-02 15:47:40 +01:00
It is used to compute a periodic signal that has any Power Spectral Density defined.
It makes used of the Unversed Fast Fourier Transform (IFFT).
** 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
** Signal's PSD
We load the PSD of the signal we wish to replicate.
#+begin_src matlab
load('./mat/dist_psd.mat', 'dist_f');
#+end_src
We remove the first value with very high PSD.
#+begin_src matlab
dist_f.f = dist_f.f(3:end);
dist_f.psd_gm = dist_f.psd_gm(3:end);
#+end_src
The PSD of the signal is shown on figure ref:fig:psd_original.
#+begin_src matlab :exports none
figure;
hold on;
plot(dist_f.f, dist_f.psd_gm)
hold off;
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density');
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/psd_original.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
#+NAME: fig:psd_original
#+CAPTION: PSD of the original signal ([[./figs/psd_original.png][png]], [[./figs/psd_original.pdf][pdf]])
[[file:figs/psd_original.png]]
** Algorithm
2019-12-02 15:47:40 +01:00
We define some parameters that will be used in the algorithm.
#+begin_src matlab
2019-12-02 15:47:40 +01:00
Fs = 2*dist_f.f(end); % Sampling Frequency of data is twice the maximum frequency of the PSD vector [Hz]
N = 2*length(dist_f.f); % Number of Samples match the one of the wanted PSD
T0 = N/Fs; % Signal Duration [s]
df = 1/T0; % Frequency resolution of the DFT [Hz]
% Also equal to (dist_f.f(2)-dist_f.f(1))
#+end_src
We then specify the wanted PSD.
#+begin_src matlab
phi = dist_f.psd_gm;
#+end_src
2019-12-02 15:47:40 +01:00
We create amplitudes corresponding to wanted PSD.
#+begin_src matlab
C = zeros(N/2,1);
for i = 1:N/2
C(i) = sqrt(phi(i)*df);
end
#+end_src
2019-12-02 15:47:40 +01:00
Finally, we add some random phase to =C=.
#+begin_src matlab
theta = 2*pi*rand(N/2,1); % Generate random phase [rad]
Cx = [0 ; C.*complex(cos(theta),sin(theta))];
Cx = [Cx; flipud(conj(Cx(2:end)))];;
#+end_src
** Obtained Time Domain Signal
The time domain data is generated by an inverse FFT.
2019-12-02 15:47:40 +01:00
The =ifft= Matlab does not take into account the sampling frequency, thus we need to normalize the signal.
#+begin_src matlab
2019-12-02 15:47:40 +01:00
u = N/sqrt(2)*ifft(Cx); % Normalisation of the IFFT
t = linspace(0, T0, N+1); % Time Vector [s]
#+end_src
#+begin_src matlab :exports none
figure;
plot(t, u)
xlabel('Time [s]');
ylabel('Amplitude');
xlim([t(1), t(end)]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/signal_time_domain.pdf" :var figsize="normal-wide" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
#+NAME: fig:signal_time_domain
#+CAPTION: Obtained signal in the time domain ([[./figs/signal_time_domain.png][png]], [[./figs/signal_time_domain.pdf][pdf]])
[[file:figs/signal_time_domain.png]]
** PSD Comparison
We duplicate the time domain signal to have a longer signal and thus a more precise PSD result.
#+begin_src matlab
u_rep = repmat(u, 10, 1);
#+end_src
We compute the PSD of the obtained signal with the following commands.
#+begin_src matlab
nx = length(u_rep);
na = 16;
win = hanning(floor(nx/na));
[pxx, f] = pwelch(u_rep, win, 0, [], Fs);
#+end_src
Finally, we compare the PSD of the original signal and the obtained signal on figure ref:fig:psd_comparison.
#+begin_src matlab :exports none
figure;
hold on;
plot(dist_f.f, dist_f.psd_gm, 'DisplayName', 'Original PSD')
plot(f, pxx, 'DisplayName', 'Computed')
hold off;
xlabel('Frequency [Hz]');
ylabel('Power Spectral Density');
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
legend('location', 'northeast');
2019-12-02 15:47:40 +01:00
xlim([0.1, 500]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/psd_comparison.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
#+NAME: fig:psd_comparison
#+CAPTION: Comparison of the PSD of the original signal and the PSD of the obtained signal ([[./figs/psd_comparison.png][png]], [[./figs/psd_comparison.pdf][pdf]])
[[file:figs/psd_comparison.png]]
2019-12-02 15:47:40 +01:00
* Compute the Noise level and Signal level from PSD
:PROPERTIES:
:header-args:matlab+: :tangle matlab/compute_psd_levels.m
:header-args:matlab+: :comments org :mkdirp yes
:END:
<<sec:compute_psd_levels>>
2019-12-02 15:47:40 +01:00
** ZIP file containing the data and matlab files :ignore:
#+begin_src bash :exports none :results none
if [ matlab/compute_psd_levels.m -nt data/compute_psd_levels.zip ]; then
cp matlab/compute_psd_levels.m compute_psd_levels.m;
zip data/compute_psd_levels \
compute_psd_levels.m
rm compute_psd_levels.m;
fi
#+end_src
#+begin_note
All the files (data and Matlab scripts) are accessible [[file:data/compute_psd_levels.zip][here]].
#+end_note
** Introduction :ignore:
2019-12-02 15:47:40 +01:00
We here make use of the Power Spectral Density to estimate either the noise level or the amplitude of a deterministic signal.
Everything is explained in cite:schmid12_how_to_use_fft_matlab sections 5 and 6.
** 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
2019-12-02 15:47:40 +01:00
** Time Domain Signal
Let's first define the number of sample and the sampling time.
#+begin_src matlab
2019-12-02 15:47:40 +01:00
N = 10000; % Number of Sample
dt = 0.001; % Sampling Time [s]
2019-12-02 15:47:40 +01:00
t = dt*(0:1:N-1)'; % Time vector [s]
#+end_src
2019-12-02 15:47:40 +01:00
We generate of signal that consist of:
- a white noise with an RMS value equal to =anoi=
- two sinusoidal signals
The parameters are defined below.
#+begin_src matlab
2019-12-02 15:47:40 +01:00
asig = 0.1; % Amplitude of the signal [V]
fsig = 10; % Frequency of the signal [Hz]
2019-12-02 15:47:40 +01:00
ahar = 0.5; % Amplitude of the harmonic [V]
fhar = 50; % Frequency of the harmonic [Hz]
2019-12-02 15:47:40 +01:00
anoi = 1e-3; % RMS value of the noise
#+end_src
2019-12-02 15:47:40 +01:00
The signal $x$ is generated with the following code and is shown in figure [[fig:time_domain_x_zoom]].
#+begin_src matlab
2019-12-02 15:47:40 +01:00
x = anoi*randn(N, 1) + asig*sin((2*pi*fsig)*t) + ahar*sin((2*pi*fhar)*t);
#+end_src
#+begin_src matlab :exports none
figure;
plot(t, x);
2019-12-02 15:47:40 +01:00
xlabel('Time [s]');
ylabel('Amplitude');
xlim([0, 1]);
#+end_src
#+HEADER: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/time_domain_x_zoom.pdf" :var figsize="wide-normal" :post pdf2svg(file=*this*, ext="png")
<<plt-matlab>>
#+end_src
2019-12-02 15:47:40 +01:00
#+NAME: fig:time_domain_x_zoom
#+CAPTION: Time Domain Signal ([[./figs/time_domain_x_zoom.png][png]], [[./figs/time_domain_x_zoom.pdf][pdf]])
[[file:figs/time_domain_x_zoom.png]]
** Estimation of the magnitude of a deterministic signal
Let's compute the PSD of the signal using the =blackmanharris= window.
#+begin_src matlab
nx = length(x);
na = 8;
win = blackmanharris(floor(nx/na));
[pxx, f] = pwelch(x, win, 0, [], 1/dt);
#+end_src
Normalization of the PSD.
#+begin_src matlab
CG = sum(win)/(nx/na);
NG = sum(win.^2)/(nx/na);
fbin = f(2) - f(1);
2019-12-02 15:47:40 +01:00
pxx_norm = pxx*(NG*fbin/CG^2);
#+end_src
2019-12-02 15:47:40 +01:00
We determine the frequency bins corresponding to the frequency of the signals.
#+begin_src matlab
isig = round(fsig/fbin)+1;
2019-12-02 15:47:40 +01:00
ihar = round(fhar/fbin)+1;
#+end_src
2019-12-02 15:47:40 +01:00
The theoretical RMS value of the signal is:
#+begin_src matlab
2019-12-02 15:47:40 +01:00
srmt = asig/sqrt(2); % Theoretical value of signal magnitude
#+end_src
2019-12-02 15:47:40 +01:00
And we estimate the RMS value of the signal by either integrating the PSD around the frequency of the signal or by just taking the maximum value.
#+begin_src matlab
2019-12-02 15:47:40 +01:00
srms = sqrt(sum(pxx(isig-5:isig+5)*fbin)); % Signal spectrum integrated
srmsp = sqrt(pxx_norm(isig) * NG*fbin/CG^2); % Maximum read off spectrum
#+end_src
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable([srmt, srms, srmsp]', {'Theoretical', 'Integrated', 'Maximum'}, {'Signal Magnitude [rms]'}, ' %.4f ');
#+end_src
#+RESULTS:
| | Signal Magnitude [rms] |
|-------------+------------------------|
| Theoretical | 0.0707 |
| Integrated | 0.0707 |
| Maximum | 0.0529 |
2019-12-02 15:47:40 +01:00
We see that the integrated value gives a good approximate of the true RMS value whereas the maximum value give an poor approximate.
This effect is called /scallop loss/.
Thus, always the integrated method should be used.
2019-12-02 15:47:40 +01:00
** Estimation of the noise level
The noise level can also be computed using the integration method.
The theoretical RMS noise value is.
#+begin_src matlab
nth = anoi/sqrt(max(f)) % Theoretical value [V/sqrt(Hz)]
#+end_src
2019-12-02 15:47:40 +01:00
We can estimate this RMS value by integrating the PSD at frequencies where the power of the noise signal is above the power of the other signals.
#+begin_src matlab
2019-12-02 15:47:40 +01:00
navg = sqrt(mean(pxx_norm([ihar+10:end]))) % pwelch output averaged
#+end_src
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable([nth, navg]', {'Theoretical', 'Average'}, {'test'}, ' %.3e ');
#+end_src
#+RESULTS:
| | test |
|-------------+-----------|
| Theoretical | 4.472e-05 |
| Average | 4.337e-05 |
The estimate of the noise level is quite good.
* Further Notes
** PSD of ADC quantization noise
This is taken from [[https://www.allaboutcircuits.com/technical-articles/quantization-nois-amplitude-quantization-error-analog-to-digital-converters/][here]].
Let's note:
- $q$ is the corresponding value in [V] of the least significant bit (LSB)
- $\Delta V$ is the full range of the ADC in [V]
- $n$ is the number of ADC's bits
- $f_s$ is the sample frequency in [Hz]
Let's suppose that the ADC is ideal.
The only noise comes from the quantization error.
Interestingly, the noise amplitude is uniformly distributed.
The quantization noise can take a value between $\pm q/2$, and the probability density function is constant in this range (i.e., its a uniform distribution).
Since the integral of the probability density function is equal to one, its value will be $1/q$ for $-q/2 < e < q/2$ (Fig. [[fig:probability_density_function_adc]]).
#+begin_src latex :file probability_density_function_adc.pdf :post pdf2svg(file=*this*, ext="png") :exports results
\begin{tikzpicture}
\path[fill=black!20!white] (-1, 0) |- (1, 1) |- (-1, 0);
\draw[->] (-2, 0) -- (2, 0) node[above left]{$e$};
\draw[->] (0, -0.5) -- (0, 2) node[below right]{$p(e)$};
\node[below] at (1, 0){$\frac{q}{2}$};
\node[below] at (-1, 0){$-\frac{q}{2}$};
\node[right] at (1, 1){$\frac{1}{q}$};
\end{tikzpicture}
2019-08-17 10:51:53 +02:00
#+end_src
2019-12-02 15:47:40 +01:00
#+name: fig:probability_density_function_adc
#+caption: Probability density function $p(e)$ of the ADC error $e$
#+RESULTS:
[[file:figs/probability_density_function_adc.png]]
Now, we can calculate the time average power of the quantization noise as
\begin{equation}
P_q = \int_{-q/2}^{q/2} e^2 p(e) de = \frac{q^2}{12}
\end{equation}
The other important parameter of a noise source is the power spectral density (PSD), which indicates how the noise power spreads in different frequency bands.
To find the power spectral density, we need to calculate the Fourier transform of the autocorrelation function of the noise.
Assuming that the noise samples are not correlated with one another, we can approximate the autocorrelation function with a delta function in the time domain.
Since the Fourier transform of a delta function is equal to one, the *power spectral density will be frequency independent*.
Therefore, the quantization noise is white noise with total power equal to $P_q = \frac{q^2}{12}$.
Thus, the two-sided PSD (from $\frac{-f_s}{2}$ to $\frac{f_s}{2}$), we should divide the noise power $P_q$ by $f_s$:
\begin{equation}
\int_{-f_s/2}^{f_s/2} \Gamma(f) d f = f_s \Gamma = \frac{q^2}{12}
\end{equation}
Finally:
\begin{equation}
\begin{aligned}
\Gamma &= \frac{q^2}{12 f_s} \\
&= \frac{\left(\frac{\Delta V}{2^n}\right)^2}{12 f_s} \text{ in } \left[ \frac{V^2}{Hz} \right]
\end{aligned}
\end{equation}
2019-08-17 10:51:53 +02:00
* Bibliography :ignore:
bibliographystyle:unsrt
bibliography:ref.bib