Show code cell content
import jax.numpy as jnp
import matplotlib.pyplot as plt
plt.style.use("https://github.com/mlefkir/beauxgraphs/raw/main/beautifulgraphs_colblind.mplstyle")
Modelling with a power spectral density#
The power spectral density function of the time series is represented by the object PowerSpectralDensity
. More details about this class and the implemented models can be found psd
. We will describe how to use, combine and create models for the power spectral density function in the following sections.
A first model#
We show how to use the models implemented in pioran.psd
to compute the power spectrum at given frequencies. We first define an instance of the chosen class. In this example, we create instances of the classes Lorentzian
and Gaussian
.
The values of the parameters of the models are given as a list of floats, during instantiation.
from pioran.psd import Lorentzian, Gaussian
Lore = Lorentzian([0,1, 0.5])
Gauss = Gaussian([0,1.2, 0.5])
A PowerSpectralDensity
object has a field parameters
which an object of the class ParametersModel
storing for the parameters of the model. We can inspect the values of the parameters of the model by printing the PowerSpectralDensity
object.
print(Lore)
Power spectrum: lorentzian
Number of parameters: 3
============================================================================
CID ID Name Value Status Linked Type
1 1 position 0 Free No Hyper-parameter
1 2 amplitude 1 Free No Hyper-parameter
1 3 halfwidth 0.5 Free No Hyper-parameter
Number of free parameters : 3
If we want to change the values of the parameters of the model, we can use the method set_free_values
on the attributePowerSpectralDensity.parameters
. The method takes as input a list of floats, which are the values of the free parameters of the model. Currently, it is not possible to change the values of the fixed parameters of the model after instantiation. To do so, we need to create a new instance of the model and set the parameters as free or fixed using the keyword argument free_parameters
. More details about the class ParametersModel
can be found in the API.
Lore.parameters.set_free_values([0.9,2.2, 1.5])
print(Lore)
Power spectrum: lorentzian
Number of parameters: 3
============================================================================
CID ID Name Value Status Linked Type
1 1 position 0.9 Free No Hyper-parameter
1 2 amplitude 2.2 Free No Hyper-parameter
1 3 halfwidth 1.5 Free No Hyper-parameter
Number of free parameters : 3
We can evaluate the PSD at given frequencies by calling the method calculate
of the PowerSpectralDensity
object. The method calculate
takes as input a list of floats representing the frequencies at which the PSD is evaluated. The method returns a list of floats representing the values of the PSD at the given frequencies.
Show code cell source
t = jnp.linspace(0, 10, 1000)
fig, ax = plt.subplots(1, 1, figsize=(7, 4))
ax.plot(t, Gauss.calculate(t), label="Gaussian")
ax.plot(t, Lore.calculate(t), label="Lorentzian")
ax.set_xlabel(r'$f$')
ax.set_ylabel(r'$\tt{PSD.calculate}(f)$')
ax.legend()
fig.tight_layout()

Combining PSD models#
In this section, we show how to combine power spectral density functions via arithmetic operations.
In this example we create instances of the classes Gaussian
and Lorentzian
.
from pioran.psd import Lorentzian, Gaussian
Lore = Lorentzian([3,1, 1.5])
Gauss = Gaussian([0,1.2, 0.5])
Gauss2 = Gaussian([6,1.4, 2.5])
Sum of PSD functions#
We can create a model which is the sum of the three components by using the +
operator. The result is a new instance of the class PowerSpectralDensity
. We can inspect the parameters of the model by printing the object.
Model = Lore + Gauss + Gauss2
print(Model)
Power spectrum: lorentzian + gaussian + gaussian
Number of parameters: 9
============================================================================
CID ID Name Value Status Linked Type
1 1 position 3 Free No Hyper-parameter
1 2 amplitude 1 Free No Hyper-parameter
1 3 halfwidth 1.5 Free No Hyper-parameter
2 4 position 0 Free No Hyper-parameter
2 5 amplitude 1.2 Free No Hyper-parameter
2 6 sigma 0.5 Free No Hyper-parameter
3 7 position 6 Free No Hyper-parameter
3 8 amplitude 1.4 Free No Hyper-parameter
3 9 sigma 2.5 Free No Hyper-parameter
Number of free parameters : 9
Because several parameters have identical names it is necessary to use the indices of the parameters to access them. CID
gives the component index and ID
gives the parameter index in the whole model.
print(Model.parameters[5])
2 5 amplitude 1.2 Free No Hyper-parameter
Show code cell source
t = jnp.linspace(0, 10, 1000)
fig, ax = plt.subplots(1, 1, figsize=(7, 4))
ax.plot(t, Model.calculate(t), label="Sum of the three")
ax.plot(t, Gauss.calculate(t), label="Gaussian", lw=2,ls="--")
ax.plot(t, Lore.calculate(t), label="Lorentzian", lw=2,ls="--")
ax.plot(t, Gauss2.calculate(t), label="Gaussian2", lw=2,ls="--")
ax.set_xlabel(r'$f$')
ax.set_ylabel(r'$\tt{PSD.calculate}(f)$')
ax.legend()
fig.tight_layout()

Product of PSD functions#
We can create a model which is a product of PSD functions by using the *
operator. The result is a new instance of the class PowerSpectralDensity
. We show an example with the product of the two first components plus the third component.
Lore = Lorentzian([3,1, 1.5])
Gauss = Gaussian([0,3.2, 3.5])
Gauss2 = Gaussian([2,1.4, 2.5])
Model = Lore + Gauss * Gauss2
print(Model)
Power spectrum: lorentzian + gaussian * gaussian
Number of parameters: 9
============================================================================
CID ID Name Value Status Linked Type
1 1 position 3 Free No Hyper-parameter
1 2 amplitude 1 Free No Hyper-parameter
1 3 halfwidth 1.5 Free No Hyper-parameter
2 4 position 0 Free No Hyper-parameter
2 5 amplitude 3.2 Free No Hyper-parameter
2 6 sigma 3.5 Free No Hyper-parameter
3 7 position 2 Free No Hyper-parameter
3 8 amplitude 1.4 Free No Hyper-parameter
3 9 sigma 2.5 Free No Hyper-parameter
Number of free parameters : 9
Show code cell source
t = jnp.linspace(0, 10, 1000)
fig, ax = plt.subplots(1, 1, figsize=(7, 4))
ax.plot(t, Model.calculate(t), label="Lore + Gauss * Gauss2", lw=2)
ax.plot(t, Gauss.calculate(t), label="Gaussian", lw=2,ls="--")
ax.plot(t, Lore.calculate(t), label="Lorentzian", lw=2,ls="--")
ax.plot(t, Gauss2.calculate(t), label="Gaussian2", lw=2,ls="--")
ax.set_xlabel(r'$f$')
ax.set_ylabel(r'$\tt{PSD.calculate}(f)$')
ax.legend()
fig.tight_layout()

Conversion to an autocovariance function#
To use PSD models which have no analytical expression for the autocovariance function we have to compute the Fourier Transform of the PSD. This is done using the class PSDToACV
. The class takes as input a PowerSpectralDensity
object and computes the Fourier Transform of the PSD. The class has a method calculate
which takes as input a list of floats representing the time lags at which the autocovariance function is evaluated. The method returns a list of floats representing the values of the autocovariance function at the given time lags.
We first define a PSD model, here a Lorentzian. We then create an instance of the class PSDToACV
, four other values are necessary to do so. The total duration of the time series \(T\), \(\Delta T\) the minimal time step between two consecutive points in the time series, \(S_\mathrm{low}\) and \(S_\mathrm{high}\) two factors to extend the grid of frequencies used to compute the Fourier Transform.
The extended grid of frequencies is then given by \(f_0 = f_\mathrm{min}/S_\mathrm{low} = \Delta f\) to \(f_N = f_\mathrm{max}S_\mathrm{high}=N \Delta f\), where \(f_\mathrm{min}=1/T\) and \(f_\mathrm{max}=1/2\Delta T\). More details about these two factors can be found in the Notebook on the FFT.