Time-Frequency-Polarization analysis: tutorial
This tutorial aims at demonstrating different tools available within the
timefrequency module of BiSPy. The examples provided here come
along with the paper
Julien Flamant, Nicolas Le Bihan, Pierre Chainais: “Time-frequency analysis of bivariate signals”, In press, Applied and Computational Harmonic Analysis, 2017; arXiv:1609.0246, doi:10.1016/j.acha.2017.05.007.
The paper contains theoretical results and several applications that can be reproduced with the following tutorial. A Jupyter notebook version can be downloaded here.
Load bispy and necessary modules
import numpy as np
import matplotlib.pyplot as plt
import quaternion # load the quaternion module
import bispy as bsp
Quaternion Short-Term Fourier Transform (Q-STFT) example
To illustrate the behaviour of the Q-STFT, we construct a simple signal made of two linear chirps, each having its own instantaneous polarization properties.
First, define some constants:
N = 1024 # length of the signal
# linear chirps constants
a = 250*np.pi
b = 50*np.pi
c = 150*np.pi
Then define the instantaneous amplitudes, orientation, ellipticity and phase of each linear chirp. The amplitudes are taken equal - just a Hanning window.
# time vector
t = np.linspace(0, 1, N)
# first chirp
theta1 = np.pi/4 # constant orientation
chi1 = np.pi/6-t # reversing ellipticity
phi1 = b*t+a*t**2 # linear chirp
# second chirp
theta2 = np.pi/4*10*t # rotating orientation
chi2 = 0 # constant null ellipticity
phi2 = c*t+a*t**2 # linear chirp
# common amplitude -- simply a window
env = bsp.utils.windows.hanning(N)
We can now construct the two components and sum it. To do so, we use the
function signals.bivariateAMFM to compute directly the quaternion
embeddings of each linear chirp.
# define chirps x1 and x2
x1 = bsp.signals.bivariateAMFM(env, theta1, chi1, phi1)
x2 = bsp.signals.bivariateAMFM(env, theta2, chi2, phi2)
# sum it
x = x1 + x2
Let us have a look at the signal x[t]
fig, ax = bsp.utils.visual.plot2D(t, x)
Now we can compute the Q-STFT. First initialize the object Q-STFT
S = bsp.timefrequency.QSTFT(x, t)
And compute:
S.compute(window='hamming', nperseg=101, noverlap=100, nfft=N)
Computing Time-Frequency Stokes parameters
Let us have a look at Time-Frequency Stokes parameters S1, S2 and S3
fig, ax = S.plotStokes()
Alternatively, we can compute the instantaneous polarization properties from the ridges of the Q-STFT.
Extract the ridges:
S.extractRidges()
Extracting ridges
Ridge added
Ridge added
2 ridges were recovered.
And plot (quivertdecim controls the time-decimation of the quiver
plot, for a cleaner view):
fig, ax = S.plotRidges(quivertdecim=30)
The two representations are equivalent and provide the same information: time, frequency and polarization properties of the bivariate signal. A direct inspection shows that instantaneous parameters of each components are recovered by both representations.
Quaternion Continuous Wavelet Transform (Q-CWT) example
The Q-STFT method has the same limitations as the usual STFT, that is not the ideal tool to analyze signals spanning a wide range of frequencies over short time scales. We revisit here the classic two chirps example in its bivariate (polarized) version.
As before, let us first define some constants:
N = 1024 # length of the signal
# hyperbolic chirps parameters
alpha = 15*np.pi
beta = 5*np.pi
tup = 0.8 # set blow-up time value
Now, let us define the instantaneous amplitudes, orientation, ellipticity and phase of each linear chirp. The chirps are also windowed.
t = np.linspace(0, 1, N) # time vector
# chirp 1 parameters
theta1 = -np.pi/3 # constant orientation
chi1 = np.pi/6 # constant ellipticity
phi1 = alpha/(.8-t) # hyperbolic chirp
# chirp 2 parameters
theta2 = 5*t # rotating orientation
chi2 = -np.pi/10 # constant ellipticity
phi2 = beta/(.8-t) # hyperbolic chirp
# envelope
env = np.zeros(N)
Nmin = int(0.1*N) # minimum value of N such that x is nonzero
Nmax = int(0.75*N) # maximum value of N such that x is nonzero
env[Nmin:Nmax] = bsp.utils.windows.hanning(Nmax-Nmin)
Construct the two components and sum it. Again we use the function
utils.bivariateAMFM to compute directly the quaternion embeddings of
each linear chirp.
x1 = bsp.signals.bivariateAMFM(env, theta1, chi1, phi1)
x2 = bsp.signals.bivariateAMFM(env, theta2, chi2, phi2)
x = x1 + x2
Let us visualize the resulting signal, x[t]
fig, ax = bsp.utils.visual.plot2D(t, x)
Now, we can compute its Q-CWT. First define the wavelet parameters and initialize the QCWT object:
waveletParams = dict(type='Morse', beta=12, gamma=3)
S = bsp.timefrequency.QCWT(x, t)
And compute:
fmin = 0.01
fmax = 400
S.compute(fmin, fmax, waveletParams, N)
Computing Time-Frequency Stokes parameters
Let us have a look at Time-Scale Stokes parameters S1, S2 and S3
fig, ax = S.plotStokes()
Similarly we can compute the instantaneous polarization attributes from the ridges of the Q-CWT.
S.extractRidges()
Extracting ridges
Ridge added
Ridge added
2 ridges were recovered.
And plot the results
fig, ax = S.plotRidges(quivertdecim=40)
Again, both representations are equivalent and provide the same information: time, scale and polarization properties of the bivariate signal. A direct inspection shows that instantaneous parameters of each components are recovered by both representations.