Chapter 03 The Discrete Fourier Transform

  • The discrete Fourier transform (DFT) is one of the two most common, and powerful, procedures encountered in the field of digital signal processing. (Digital filtering is the other.)

Continuous Fourier Transform

A prominent quote from Lord Kelvin better states this sentiment: “Fourier’s theorem is not only one of the most beautiful results of modern analysis, but it may be said to furnish an indispensable instrument in the treatment of nearly every recondite question in modern physics.

DFT equation (exponential form):

3.1 UNDERSTANDING THE DFT EQUATION

DFT equation (rectangular form):

  • the th DFT output component
    • the index of the DFT output in the frequency domain.
    • .
  • the sequence of input samples
    • the time-domain index of the input samples.
    • .
  • the number of samples of the input sequence and the number of frequency points in the DFT output.

    • The value is an important parameter because it determines how many input samples are needed, the resolution of the frequency-domain results, and the amount of processing time necessary to calculate an -point DFT.
  • The exact frequencies of the different sinusoids depend on both the sampling rate at which the original signal was sampled, and the number of samples .

  • For example, if we are sampling a continuous signal at a rate of 500 samples/second and, then, perform a -point DFT on the sampled data, the fundamental frequency of the sinusoids is or Hz.

The separate DFT analysis frequencies are

The magnitude

Then the magnitude of is

3.1.1 DFT Example 1

Consider performing an 8-point DFT on a continuous input signal containing components at 1 kHz and 2 kHz a input signal:

And we use samples/second.

Then

our eight samples are:

from scipy.fft import fft, fftfreq
import numpy as np

fs = 8000  # Sampling rate in Hz
n = np.arange(0, 8, 1)  # Time vector
ts = 1.0 / fs
# Signal with 1000 Hz and 2000 Hz components
x = 1.0*np.sin(2*np.pi*1000*n*ts) + 0.5*np.sin(2*np.pi*2000*n*ts + (3/4)*np.pi)

x
array([ 0.35355339,  0.35355339,  0.64644661,  1.06066017,
0.35355339, -1.06066017, -1.35355339, -0.35355339])

We can either use scipy.fft or manual:

X = fft(x)
np.around(X,4)

array([ 0.    -0.j    , -0.    -4.j    ,  1.4142+1.4142j,
0.    +0.j    ,-0.    -0.j    ,  0.    -0.j    ,  1.4142-1.4142j, -0.    +4.j    ])

N = 8
Y = np.array([0+0*1j]*N)
for m in range(N):
    Y[m] = 0 + 0*1j
    for n in range(N):
        Y[m] = Y[m] + x[n] * (np.cos(-2*np.pi*n*m/N) + 1j*np.sin(-2*np.pi*n*m/N))

np.around(Y,4)

array([ 0.    +0.j    , -0.    -4.j    ,  1.4142+1.4142j,
0.    -0.j    , -0.    -0.j    ,  0.    +0.j    ,  1.4142-1.4142j, -0.    +4.j    ])

np.allclose(X, Y)

True

We have the following observations from this figure:

  • By looking at the , we can see, , that means has no DC component.

  • Looking at Figure 3–4(b), we might notice that the phase of is degrees. It compares against a wave at frequency .

    • At the frequency , the phase is , which corresponds to . This is correct, because .
    • At the frequency , the phase is , which corresponds to . This is correct, because , so .
  • 2 open questions:

    • What are the components when .
    • Why the max magnitude is instead of .

2 very important characteristics of the DFT that we should never forget. * any individual output value is nothing more than the sum of the term-by-term products, a correlation, of an input signal sample sequence with a cosine and a sinewave whose frequencies are complete cycles in the total sample interval of samples. This is true no matter what the sample rate is and no matter how large is in an -point DFT. * The second important characteristic of the DFT of real input samples is the symmetry of the DFT output terms.

3.2 DFT SYMMETRY

Consider is a real signal. Using equation (3-2), we have

  • If that real input function is even, then is always real and even.
  • If the real input function is odd, then is always pure imaginary.

3.3 DFT LINEARITY

3.4 DFT MAGNITUDES

  • When a real input signal contains a sinewave component, whose frequency is less than half the sample rate, of peak amplitude with an integral number of cycles over input samples, the output magnitude of the DFT for that particular sinewave is where

  • If the DFT input is a complex sinusoid of magnitude Ao (i.e., ) with an integer number of cycles over samples, the output magnitude of the DFT for that particular sinewave is

The other 2 forms of DFT

Or

3.5 DFT FREQUENCY AXIS

  • Just remember that the DFT’s frequency spacing (resolution) is .
  • Each DFT output term is the sum of the term-by-term products of an input time-domain sequence with sequences representing a sine and a cosine wave.
  • For real inputs, an -point DFT’s output provides only independent terms.
  • The DFT is a linear operation.
  • The magnitude of the DFT results is directly proportional to .
  • The DFT’s frequency resolution is .

3.6 DFT SHIFTING THEOREM

Consider and

3.6.1 DFT Example 2

We still use the same example in 3.1.1

And let , here is the python code

from scipy.fft import fft, fftfreq
import numpy as np

fs = 8000  # Sampling rate in Hz
n = np.arange(0, 8, 1)  # Time vector
ts = 1.0 / fs
# Signal with 1000 Hz and 2000 Hz components
x = 1.0*np.sin(2*np.pi*1000*n*ts) + 0.5*np.sin(2*np.pi*2000*n*ts + (3/4)*np.pi)

x_1 = np.roll(x, -3)
x_1

array([ 1.06066017,  0.35355339, -1.06066017, -1.35355339, -0.35355339, 0.35355339,  0.35355339,  0.64644661])

X_1 = fft(x_1)
np.around(X_1,4)

array([ 0.    -0.j    ,  2.8284+2.8284j,  1.4142-1.4142j, -0.    +0.j    ,
        0.    -0.j    , -0.    -0.j    ,  1.4142+1.4142j,  2.8284-2.8284j])

X_2 = np.array([0+0*1j]*N)
for m in range(N):
    X_2[m] = np.exp(1j * 2 * np.pi * 3 * m / N) * X[m]
np.around(X_2,4)

array([ 0.    +0.j    ,  2.8284+2.8284j,  1.4142-1.4142j, -0.    +0.j    ,
        0.    -0.j    , -0.    -0.j    ,  1.4142+1.4142j,  2.8284-2.8284j])

np.allclose(X_1, X_2)
True

3.7 INVERSE DFT

Here is the python code to implement it

from scipy.fft import fft, fftfreq, ifft
import numpy as np

fs = 8000  # Sampling rate in Hz
n = np.arange(0, 8, 1)  # Time vector
ts = 1.0 / fs
# Signal with 1000 Hz and 2000 Hz components
x = 1.0*np.sin(2*np.pi*1000*n*ts) + 0.5*np.sin(2*np.pi*2000*n*ts + (3/4)*np.pi)

X = fft(x)
x_ifft = ifft(X)
np.around(x_ifft,4)

array([ 0.3536+0.j,  0.3536+0.j,  0.6464+0.j,  1.0607+0.j,  0.3536+0.j,
       -1.0607+0.j, -1.3536-0.j, -0.3536+0.j])

Y_inv = np.array([0+0*1j]*N)
for m in range(N):
    Y_inv[m] = 0 + 0*1j
    for n in range(N):
        Y_inv[m] = Y_inv[m] + (1 / N) * X[n] * (np.cos(2*np.pi*n*m/N) + 1j*np.sin(2*np.pi*n*m/N))
np.around(Y_inv, 4)

array([ 0.3536+0.j,  0.3536+0.j,  0.6464+0.j,  1.0607+0.j,  0.3536+0.j,
       -1.0607+0.j, -1.3536-0.j, -0.3536+0.j])

np.allclose(x_ifft, Y_inv)
True