Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

3_spectral_resolution_correction

February 19, 2021

1 Lab 3 : Spectral resolution


Signal Processing in Geosciences / J. Vergne / Feb 2021

This short this lab deals with the notion of the frequency step of a Fourier transform and
it’s link with the spectral resolution. An extra activity introduces the zero padding technique to
increase the precision (but not the resolution)

In [1]: import numpy as np


import matplotlib.pyplot as plt
from numpy import fft
%matplotlib inline

1.0.1 1. Temporal and spectral representation of the gravity timeseries


We will focus on the temporal variation of gravity measured in Strasbourg. This timeseries is
particulary rich and will allow use to discuss the frequency resolution of the amplitude spectrum

To do : * Read the gravi.dat file (1 point / hour) and plot the timeseries * Compute
the fourier transform and plot the amplitude spectrum in a log-log scale * Show that
this timeseries exibits the following periodicities : 12h, 24h, 28 days, half a year, 1 year
* What are the associated physical phenomena ?

In [2]: gravi = np.loadtxt('Data/gravi.dat')


dt = 1 # sampling step in hour
N = len(gravi) # number of points
time = np.arange(0,N)*dt # time vector

# Removing the mean


gravi = gravi - np.mean(gravi)

plt.figure(figsize=(15,8))
plt.plot(time,gravi)
plt.xlabel('time (h)')
plt.ylabel('nm/s-2')

1
Out[2]: Text(0,0.5,'nm/s-2')

In [3]: # Moving to the frequency domain

GRAVI = fft.fft(gravi) # fourier transform


f = fft.fftfreq(N,dt) # vector of associated frequencies

# Keep only the positive frequencies


GRAVI = GRAVI[0:int(N/2)]
f = f [0:int(N/2)]

plt.figure(figsize=(15,8))
plt.loglog(f,abs(GRAVI))
plt.xlabel('frequencies (h^(-1))')
plt.ylim((1,1e8))
#plt.xlim((0.,0.1))

# Plot frequencies assiociated to the tide effect of


# The sun (daily)
plt.loglog([1/24, 1/24],[0,4e7],'r--') # fundamental
plt.loglog([2/24, 2/24],[0,4e7],'r--') # harmonic
# The sun (365.25 days)
plt.loglog([1/(365.25*24), 1/(365.25*24)],[0,4e7],'g--') # fundamental
plt.loglog([2/(365.25*24), 2/(365.25*24)],[0,4e7],'g--') # harmonic
# The moon (daily)
plt.loglog([1/(24+50/60), 1/(24+50/60)],[0,4e7],'b--') # fundamental
plt.loglog([2/(24+50/60), 2/(24+50/60)],[0,4e7],'b--') # harmonic
# The moon (28 days)

2
plt.loglog([1/(28*24), 1/(28*24)],[0,4e7],'c--') # fundamental
plt.loglog([2/(28*24), 2/(28*24)],[0,4e7],'c--') # harmonic

Out[3]: [<matplotlib.lines.Line2D at 0x11cce79e8>]

1.0.2 2. effect of observation duration on frequency resolution


This timeseries is about 17.5 years long (one of the longest in the world)
We will now simulate the effect of a shorter timeseries :

To do : * Plot again the amplitude spectrum for the whole dataset but in a linear-linear
scale and zooming (with plt.xlim) in the frequency range [0.07 - 0.09 $ hˆ{-1}$]. *
See the two peaks associated with the periodicities 12h et 12h25min * Create a new
array with only the data for the first 30 days (we simulate a 30 days long recording) *
Compute and plot the corresponding amplitude spectrum * Do you still see the 2 peaks
associates to T=12h and T=12h25min ? * Repeat the above procedure but keeping only
10 days of signal

In [4]: plt.figure(figsize=(15,8))

plt.plot([2/24, 2/24],[0,4e7],'r--') # Sun 1srt harmonic


plt.plot([2/(24+50/60), 2/(24+50/60)],[0,4e7],'b--') # Moon 1rst harmonic

plt.plot(f,abs(GRAVI))
plt.xlabel('frequency (h-1)')
plt.xlim((0.07,0.09))

Out[4]: (0.07, 0.09)

3
In [5]: # For a recording duration of 30 days

gravi30d = gravi[0:30*24] # extract the first 30 days from the data


time30d = time[0:30*24]
N30d = len(gravi30d)

#plt.plot(time30d,gravi30d)
#plt.xlabel('time (h)')

GRAVI30D = fft.fft(gravi30d)[0:int(N30d/2)]
f30d = fft.fftfreq(N30d,dt)[0:int(N30d/2)]

plt.figure(figsize=(15,8))
plt.plot(f30d,abs(GRAVI30D))
plt.xlabel('frequencies (h-1)')
plt.title('spectrum of gravity for T = 30 days')

plt.plot([2/24, 2/24],[0,1e5],'r--') # Sun 1srt harmonic


plt.plot([2/(24+50/60), 2/(24+50/60)],[0,1e5],'b--') # Moon 1rst harmonic

plt.xlim((0.07,0.09))

Out[5]: (0.07, 0.09)

4
In [6]: df = 1 / (30*24)
print(df, 'h-1')

0.001388888888888889 h-1

In [7]: # For a recording duration of 10 days

gravi10d = gravi[0:10*24] # extract the first 10 days from the data


time10d = time[0:10*24]
N10d = len(gravi10d)

#plt.plot(time10d,gravi10d)
#plt.xlabel('time (h)')

GRAVI10D = fft.fft(gravi10d)[0:int(N10d/2)]
f10d = fft.fftfreq(N10d,dt)[0:int(N10d/2)]

plt.figure(figsize=(15,8))
plt.plot(f10d,abs(GRAVI10D))
plt.xlabel('frequencies (h-1)')
plt.title('spectrum of gravity for T = 10 days')

plt.plot([2/24, 2/24],[0,1e5],'r--') # Sun 1srt harmonic


plt.plot([2/(24+50/60), 2/(24+50/60)],[0,1e5],'b--') # Moon 1rst harmonic

plt.xlim((0.07,0.09))

5
Out[7]: (0.07, 0.09)

In [8]: df = 1 / (10 * 24)


print(df, 'h-1')

0.004166666666666667 h-1

This example shows that the only parameter that affects the frequency resolution is the dura-
tion of the signal (not the time step for example).
The longer you observe, the more you are able to seperate two close frequencies in a signal
The spectral resolution is ∆ f = T1 where T is the duration of your observations

In [9]: df = 1/(12)-1/(12+25/60)
print(df)
print(1/df)

0.0027964205816554677
357.60000000000167

In [10]: 357/24

Out[10]: 14.875

6
1.0.3 3. Zero padding
Since the spectral resolution is inversely proportional to the duration of the signal, one can think
that by adding arbitrary values to the end of datasets we can artificially extend the length of the
dataset and therefore improve the spectral resolution.
Adding zeros (0) at the end of some data is called zero padding
An easy way to implement a zero padding is to use the optionnal parameter n= of fft.fft to
specify the number of points of the fourier transform.
The help message from fft.fft states : "If n is smaller than the length of the input, the input is
cropped. If it is larger, the input is padded with zeros"
We will test this option to see that it will allow use to improve the accuracy but NOT the
resolution

To do : * Repeat the previous procedure (keeping only 30 days and only 10 days) but
use the n= option of fft.fft with the number of points of the initial datasets * Can you
observe the two peaks for periodicities 12h and 12h25min for the 10-days long datasets
? * Explain the difference between accuracy and resolution

In [11]: N = len(gravi)
GRAVI = fft.fft(gravi)[0:int(N/2)]
f = fft.fftfreq(N,dt)[0:int(N/2)]

plt.figure(figsize=(15,15))
plt.subplot(311)
plt.plot(f,np.abs(GRAVI)/N)
plt.title('17.5 years')
plt.xlim((0.07,0.09))
plt.plot([2/24,2/24],[0,300],'m:')
plt.plot([2/(24+50/60),2/(24+50/60)],[0,300],'g:')

gravi_30days = gravi[0:30*24]
GRAVI_30DAYS = fft.fft(gravi_30days,N)[0:int(N/2)]
f = fft.fftfreq(N,dt)[0:int(N/2)]

plt.subplot(312)
plt.plot(f,np.abs(GRAVI_30DAYS)/N)
plt.title('30 days')
plt.xlim((0.07,0.09))
plt.plot([2/24,2/24],[0,1],'m:')
plt.plot([2/(24+50/60),2/(24+50/60)],[0,1],'g:')

gravi_10days = gravi[0:10*24]
GRAVI_10DAYS = fft.fft(gravi_10days,N)[0:int(N/2)]
f = fft.fftfreq(N,dt)[0:int(N/2)]

plt.subplot(313)
plt.plot(f,np.abs(GRAVI_10DAYS)/N)
plt.xlabel('frequency (h-1)')
plt.title('10 days')

7
plt.xlim((0.07,0.09))
plt.plot([2/24,2/24],[0,.5],'m:')
plt.plot([2/(24+50/60),2/(24+50/60)],[0,.5],'g:')

Out[11]: [<matplotlib.lines.Line2D at 0x11fa10a20>]

You should see that the zero padding : * Do not increase the resolution (eg. ability to separate
two frequencies in the spectrum) * Introduces artefacts ("bumps" in the amplitude spectrum) due
to the sinc effect of windowing the data.
Therefore it is dangerous to use it if you don’t know the effects.

You might also like