from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

Discrete Fourier TransformΒΆ

The Discrete Fourier Transform (DFT) decomposes a signal into its constituent frequencies. NumPy’s np.fft module provides functions for computing forward and inverse DFTs, working with real-valued inputs, and extracting frequency information. DFTs are fundamental in signal processing, audio analysis, image filtering, and feature extraction for time-series ML models. Understanding complex numbers is a prerequisite, since frequency-domain representations use complex amplitudes to encode both magnitude and phase.

from datetime import date
date.today()
author = "kyubyong. https://github.com/Kyubyong/numpy_exercises"
### Complex Numbers

Complex numbers have a real part and an imaginary part, written as `a + bj` in Python. NumPy provides functions to extract components (`np.real()`, `np.imag()`), compute angles (`np.angle()`), and find conjugates (`np.conj()`). Complex arithmetic is essential for Fourier analysis because the DFT maps real-valued signals into the complex plane, where magnitude represents amplitude and angle represents phase.

Complex NumbersΒΆ

Q1. Return the angle of a in radian.

a = 1+1j
output = ...
print(output)

Q2. Return the real part and imaginary part of a.

a = np.array([1+2j, 3+4j, 5+6j])
real = ...
imag = ...
print("real part=", real)
print("imaginary part=", imag)

Q3. Replace the real part of a with 9, the imaginary part with [5, 7, 9].

a = np.array([1+2j, 3+4j, 5+6j])
...
...
print(a)

Q4. Return the complex conjugate of a.

### Discrete Fourier Transform Functions

`np.fft.fft()` computes the 1D DFT, transforming a time-domain signal into its frequency components. `np.fft.ifft()` performs the inverse, reconstructing the signal from its frequencies. `np.fft.rfft()` is optimized for real-valued inputs (it only returns the positive frequencies since the negative frequencies are conjugate symmetric). `np.fft.fftfreq()` returns the sample frequencies corresponding to each DFT output bin. These tools are the foundation for spectral analysis, noise filtering, and feature extraction from periodic data.

Discrete Fourier TransformΒΆ

Q5. Compuete the one-dimensional DFT of a.

a = np.exp(2j * np.pi * np.arange(8))
output = ...
print(output)

Q6. Compute the one-dimensional inverse DFT of the output in the above question.

print("a=", a)
inversed = ...
print("inversed=", a)

Q7. Compute the one-dimensional discrete Fourier Transform for real input a.

a = [0, 1, 0, 0]
output = ...
print(output)
assert output.size==len(a)//2+1 if len(a)%2==0 else (len(a)+1)//2

# cf.
output2 = np.fft.fft(a)
print(output2)

Q8. Compute the one-dimensional inverse DFT of the output in the above question.

inversed = ...
print("inversed=", a)

Q9. Return the DFT sample frequencies of a.

### Window Functions

Window functions taper a signal toward zero at its edges before applying the DFT, reducing spectral leakage (artificial frequency artifacts caused by abrupt signal boundaries). NumPy provides several standard windows: **Bartlett** (triangular), **Blackman** (three-term cosine), **Hamming** and **Hanning** (raised cosine variants), and **Kaiser** (parameterized by beta for adjustable trade-off between main-lobe width and side-lobe level). Choosing the right window function is critical in audio processing, vibration analysis, and any application where accurate frequency estimation matters.

Window FunctionsΒΆ

fig = plt.figure(figsize=(19, 10))

# Hamming window
window = np.hamming(51)
plt.plot(np.bartlett(51), label="Bartlett window")
plt.plot(np.blackman(51), label="Blackman window")
plt.plot(np.hamming(51), label="Hamming window")
plt.plot(np.hanning(51), label="Hanning window")
plt.plot(np.kaiser(51, 14), label="Kaiser window")
plt.xlabel("sample")
plt.ylabel("amplitude")
plt.legend()
plt.grid()

plt.show()