The sampling theorem or Nyquist-Shannon theorem
This post deals with one of the fundamental theorem of signal processing: the sampling theorem or Nyquist-Shannon theorem (have a look on wikipedia). What is the right sampling to transform an analog signal to a digital one?First of all the news:Â I decided that having a friend when I try to write about signal processing is useful. So I gave a name to my friendand the name I chose is Wavy :)…but I had a look on google for ‘wavy’ and I found many beautiful images of wavy hair..for this reason, now, Wavy becamewith some hair :). Let Wavy answer to the questions of our latest post.Questions
- What happen if we use longer nsample?
- What happen if we use smaller sampling frequency?
First of all, let’s enunciate the sampling theorem:
“If a continuous signal is band-limited, that is its Fourier spectrum is null above a given frequency , and if the sampling rate is higher than 2 times the maximum frequency  of the signal, than the continuous signal can be perfectly recovered by the discrete signal if “ is the Sampling Frequency.In other words, if we want to fair digitalize a continuous signal which has as maximum frequency content , we need to sample the data with a frequency at minimum equal to , that is peak a point each time.At this point let’s come back to Wavy and his questions, and let’s start from second question:- What happen if we use smaller sampling frequency?
Let’s simulate again a sinusoidal signal which has as main frequency nu=50Hz
In [1]:
### importing the library
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from scipy.fftpack import fft
# sample spacing
sampling=1024
nsample = 500
dt = 1.0 / sampling
x = np.linspace(0.0, nsample*dt,nsample)
nu=50.0# frequency in Hz of the sine function
y = np.sin(nu * 2.0*np.pi*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
plt.plot(x, (y[0:nsample]))
plt.grid()
plt.show()
plt.plot(xf, 2.0/nsample * np.abs(yf[0:nsample/2]))
plt.grid()
plt.show()
We have used sampling frequency sampling=1024 Hz which is certainly $> 2*nu$.
Now let’s do the same experiment using sampling=$60$Hz, which is smaller than 2 times nu
In [2]:
# sample spacing
sampling=60
nsample = 500
dt = 1.0 / sampling
x = np.linspace(0.0, nsample*dt,nsample)
nu=50.0# frequency in Hz of the sine function
y = np.sin(nu * 2.0*np.pi*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
plt.plot(x, (y[0:nsample]))
plt.grid()
plt.show()
plt.plot(xf, 2.0/nsample * np.abs(yf[0:nsample/2]))
plt.grid()
plt.show()
The signal in time domain isn’t not certainly a single sinusoidal signal at $50$Hz, but seems a beating of 2 different frequency. The main frequency is not anymore $50$Hz, but $10$ Hz…
Now let’s sample the data at $70$Hz
In [3]:
# sample spacing
sampling=70
nsample = 500
dt = 1.0 / sampling
x = np.linspace(0.0, nsample*dt,nsample)
nu=50.0# frequency in Hz of the sine function
y = np.sin(nu * 2.0*np.pi*x)
yf = fft(y)
#xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
plt.plot(x, (y[0:nsample]))
plt.grid()
plt.show()
plt.plot(xf, 2.0/nsample * np.abs(yf[0:nsample/2]))
plt.grid()
plt.show()
Wow…the main frequency is $20$Hz…
But $60-50$ is 10 and $70-50$ is 20!!
In [4]:
# sample spacing
sampling=80
nsample = 500
dt = 1.0 / sampling
x = np.linspace(0.0, nsample*dt,nsample)
nu=50.0# frequency in Hz of the sine function
y = np.sin(nu * 2.0*np.pi*x)
yf = fft(y)
#xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
plt.plot(x, (y[0:nsample]))
plt.grid()
plt.show()
plt.plot(xf, 2.0/nsample * np.abs(yf[0:nsample/2]))
plt.grid()
plt.show()
If we use $sampling=80$Hz, again the main frequency is $sampling-nu=30$Hz
This is not a strange trick, this is the phenomenon of Aliasing, Wavy will afford in a next post.
Frequency resolution
- What happen if we use longer nsample?
In [6]:
# sample spacing
sampling=1024
nsample = 1000
dt = 1.0 / sampling
x = np.linspace(0.0, nsample*dt,nsample)
nu=50.0# frequency in Hz of the sine function
y = np.sin(nu * 2.0*np.pi*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
plt.plot(x, (y[0:nsample]))
plt.grid()
plt.show()
plt.plot(xf, 2.0/nsample * np.abs(yf[0:nsample/2]))
plt.grid()
plt.show()
In [7]:
# sample spacing
sampling=1024
nsample = 10000
dt = 1.0 / sampling
x = np.linspace(0.0, nsample*dt,nsample)
nu=50.0# frequency in Hz of the sine function
y = np.sin(nu * 2.0*np.pi*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*dt), nsample/2)
plt.plot(x, (y[0:nsample]))
plt.grid()
plt.show()
plt.plot(xf, 2.0/nsample * np.abs(yf[0:nsample/2]))
plt.grid()
plt.show()