NumPy Fourier Transform Functions

When working with signal processing, audio analysis, or image processing in Python, understanding NumPy Fourier Transform functions becomes essential. The NumPy library provides a comprehensive suite of Fourier transform functions through its numpy.fft module, enabling you to analyze frequency components of signals efficiently. These NumPy Fourier transform functions allow you to convert time-domain or spatial-domain data into frequency-domain representations, which is crucial for various scientific and engineering applications. In this tutorial, we’ll explore all the Fourier transform functions available in NumPy, helping you master frequency analysis in Python.

The Fourier transform is a mathematical operation that decomposes a signal into its constituent frequencies. NumPy’s implementation of Fourier transform functions makes it incredibly easy to perform these complex mathematical operations with just a few lines of code. Whether you’re analyzing sound waves, processing images, or working with any periodic data, NumPy Fourier transform functions provide the tools you need.

Understanding the NumPy FFT Module

The numpy.fft module contains all the Fourier transform functions in NumPy. This module implements the Fast Fourier Transform (FFT) algorithm, which is an efficient method for computing Fourier transforms. The NumPy FFT functions can handle both one-dimensional and multi-dimensional arrays, making them versatile for various applications.

The basic principle behind Fourier transforms is representing any periodic function as a sum of sine and cosine waves. When you apply NumPy Fourier transform functions to your data, you’re essentially finding out which frequencies are present in your signal and their respective amplitudes.

One-Dimensional Fourier Transform Functions

numpy.fft.fft()

The numpy.fft.fft() function is the most fundamental Fourier transform function in NumPy. It computes the one-dimensional discrete Fourier transform (DFT) of an input array. This NumPy Fourier transform function takes a sequence of values and returns the frequency components.

Syntax:

numpy.fft.fft(a, n=None, axis=-1, norm=None)

Parameters:

  • a: Input array (time-domain signal)
  • n: Length of the transformed axis (optional, defaults to length of input)
  • axis: Axis along which to compute the FFT (default is -1, the last axis)
  • norm: Normalization mode (‘backward’, ‘ortho’, or ‘forward’)

The numpy.fft.fft() function returns a complex-valued array where each element represents a frequency component. The output contains both the magnitude and phase information of each frequency.

import numpy as np

# Create a simple signal with two frequencies
time = np.linspace(0, 1, 500)
signal = np.sin(2 * np.pi * 5 * time) + 0.5 * np.sin(2 * np.pi * 10 * time)

# Apply FFT
fft_result = np.fft.fft(signal)
print(f"FFT output shape: {fft_result.shape}")
print(f"First 5 FFT coefficients: {fft_result[:5]}")

numpy.fft.ifft()

The numpy.fft.ifft() function performs the inverse Fourier transform, converting frequency-domain data back to the time domain. This NumPy Fourier transform function is essential when you want to reconstruct a signal after manipulating its frequency components.

Syntax:

numpy.fft.ifft(a, n=None, axis=-1, norm=None)

The parameters are identical to fft(). The inverse Fourier transform is particularly useful when you need to filter specific frequencies from a signal and then convert it back to its original domain.

# Reconstruct the original signal using inverse FFT
reconstructed = np.fft.ifft(fft_result)
print(f"Reconstructed signal (first 5 values): {reconstructed[:5].real}")
print(f"Original signal (first 5 values): {signal[:5]}")

numpy.fft.rfft()

The numpy.fft.rfft() function computes the Fourier transform for real-valued input. Since real signals have symmetric frequency spectra, this NumPy Fourier transform function only returns the positive frequency components, making it more memory-efficient than fft().

Syntax:

numpy.fft.rfft(a, n=None, axis=-1, norm=None)

When working with real-valued signals (which is most common in practical applications), numpy.fft.rfft() is preferred because it returns approximately half the output size compared to fft(), reducing memory usage and computation time.

# Use rfft for real-valued signals
rfft_result = np.fft.rfft(signal)
print(f"RFFT output shape: {rfft_result.shape}")
print(f"FFT output shape: {fft_result.shape}")
print(f"Memory savings: {1 - rfft_result.shape[0]/fft_result.shape[0]:.2%}")

numpy.fft.irfft()

The numpy.fft.irfft() function computes the inverse of rfft(), converting the frequency-domain representation back to real-valued time-domain data. This NumPy Fourier transform function ensures that the output is always real-valued.

Syntax:

numpy.fft.irfft(a, n=None, axis=-1, norm=None)
# Reconstruct signal from rfft result
reconstructed_real = np.fft.irfft(rfft_result)
print(f"Reconstructed from RFFT (first 5 values): {reconstructed_real[:5]}")

numpy.fft.hfft()

The numpy.fft.hfft() function computes the Fourier transform of a signal with Hermitian symmetry. A Hermitian-symmetric signal in the frequency domain corresponds to a real signal in the time domain. This NumPy Fourier transform function is useful when you know your frequency-domain data has Hermitian symmetry.

Syntax:

numpy.fft.hfft(a, n=None, axis=-1, norm=None)
# Create Hermitian symmetric array
hermitian_signal = np.array([1, 2+3j, 4+5j, 4-5j, 2-3j])
hfft_result = np.fft.hfft(hermitian_signal)
print(f"HFFT result: {hfft_result}")
print(f"Result is real: {np.all(np.isreal(hfft_result))}")

numpy.fft.ihfft()

The numpy.fft.ihfft() function performs the inverse of hfft(). It takes a real-valued array and returns a Hermitian-symmetric complex array. This NumPy Fourier transform function is the counterpart to hfft().

Syntax:

numpy.fft.ihfft(a, n=None, axis=-1, norm=None)
# Inverse HFFT
ihfft_result = np.fft.ihfft(hfft_result)
print(f"Inverse HFFT result: {ihfft_result}")

Multi-Dimensional Fourier Transform Functions

numpy.fft.fft2()

The numpy.fft.fft2() function computes the two-dimensional Fourier transform, which is extremely useful for image processing. This NumPy Fourier transform function applies the FFT along two axes, making it perfect for analyzing 2D spatial data.

Syntax:

numpy.fft.fft2(a, s=None, axes=(-2, -1), norm=None)

Parameters:

  • a: Input array (2D signal or image)
  • s: Shape of the output (optional)
  • axes: Axes along which to compute the FFT
  • norm: Normalization mode
# Create a 2D signal (simple image)
image = np.zeros((100, 100))
image[40:60, 40:60] = 1  # Square in the center

# Apply 2D FFT
fft2_result = np.fft.fft2(image)
print(f"2D FFT output shape: {fft2_result.shape}")
print(f"2D FFT magnitude at center: {np.abs(fft2_result[0, 0])}")

numpy.fft.ifft2()

The numpy.fft.ifft2() function performs the inverse two-dimensional Fourier transform. This NumPy Fourier transform function reconstructs the spatial-domain image from its frequency-domain representation.

Syntax:

numpy.fft.ifft2(a, s=None, axes=(-2, -1), norm=None)
# Reconstruct the image
reconstructed_image = np.fft.ifft2(fft2_result)
print(f"Reconstructed image shape: {reconstructed_image.shape}")
print(f"Reconstruction matches original: {np.allclose(image, reconstructed_image.real)}")

numpy.fft.rfft2()

The numpy.fft.rfft2() function computes the two-dimensional Fourier transform for real-valued input. Similar to rfft(), this NumPy Fourier transform function is more efficient for real-valued 2D data like images.

Syntax:

numpy.fft.rfft2(a, s=None, axes=(-2, -1), norm=None)
# Use rfft2 for real-valued 2D data
rfft2_result = np.fft.rfft2(image)
print(f"RFFT2 output shape: {rfft2_result.shape}")

numpy.fft.irfft2()

The numpy.fft.irfft2() function is the inverse of rfft2(), converting 2D frequency-domain data back to real-valued spatial-domain data. This NumPy Fourier transform function ensures efficient reconstruction of real-valued 2D signals.

Syntax:

numpy.fft.irfft2(a, s=None, axes=(-2, -1), norm=None)
# Reconstruct from rfft2
reconstructed_from_rfft2 = np.fft.irfft2(rfft2_result)
print(f"Reconstruction successful: {np.allclose(image, reconstructed_from_rfft2)}")

numpy.fft.fftn()

The numpy.fft.fftn() function computes the N-dimensional Fourier transform. This NumPy Fourier transform function can handle arrays of any dimensionality, making it extremely versatile for multi-dimensional signal processing.

Syntax:

numpy.fft.fftn(a, s=None, axes=None, norm=None)

Parameters:

  • a: Input array (N-dimensional)
  • s: Shape of the result (optional)
  • axes: Axes along which to compute the FFT (None means all axes)
  • norm: Normalization mode
# Create a 3D signal
signal_3d = np.random.random((10, 10, 10))

# Apply N-dimensional FFT
fftn_result = np.fft.fftn(signal_3d)
print(f"N-dimensional FFT shape: {fftn_result.shape}")

numpy.fft.ifftn()

The numpy.fft.ifftn() function performs the inverse N-dimensional Fourier transform. This NumPy Fourier transform function reconstructs the original N-dimensional signal from its frequency representation.

Syntax:

numpy.fft.ifftn(a, s=None, axes=None, norm=None)
# Inverse N-dimensional FFT
ifftn_result = np.fft.ifftn(fftn_result)
print(f"Reconstruction matches original: {np.allclose(signal_3d, ifftn_result.real)}")

numpy.fft.rfftn()

The numpy.fft.rfftn() function computes the N-dimensional Fourier transform for real-valued input. This NumPy Fourier transform function extends the efficiency benefits of rfft() to N-dimensional arrays.

Syntax:

numpy.fft.rfftn(a, s=None, axes=None, norm=None)
# N-dimensional RFFT
rfftn_result = np.fft.rfftn(signal_3d)
print(f"RFFTN output shape: {rfftn_result.shape}")

numpy.fft.irfftn()

The numpy.fft.irfftn() function is the inverse of rfftn(), reconstructing N-dimensional real-valued signals from their frequency representations. This NumPy Fourier transform function completes the real-valued N-dimensional transform pair.

Syntax:

numpy.fft.irfftn(a, s=None, axes=None, norm=None)
# Inverse N-dimensional RFFT
irfftn_result = np.fft.irfftn(rfftn_result)
print(f"Reconstruction successful: {np.allclose(signal_3d, irfftn_result)}")

Helper Functions for Fourier Transforms

numpy.fft.fftfreq()

The numpy.fft.fftfreq() function returns the discrete Fourier transform sample frequencies. This helper function is crucial for interpreting the results of NumPy Fourier transform functions by providing the frequency values corresponding to each FFT coefficient.

Syntax:

numpy.fft.fftfreq(n, d=1.0)

Parameters:

  • n: Window length (number of samples)
  • d: Sample spacing (inverse of sampling rate)
# Get frequency values
sample_rate = 500  # Hz
n_samples = 500
frequencies = np.fft.fftfreq(n_samples, 1/sample_rate)
print(f"Frequency array shape: {frequencies.shape}")
print(f"First 10 frequencies (Hz): {frequencies[:10]}")

numpy.fft.rfftfreq()

The numpy.fft.rfftfreq() function returns sample frequencies for rfft() and irfft(). Since these functions only return positive frequencies, this helper function provides the corresponding frequency values.

Syntax:

numpy.fft.rfftfreq(n, d=1.0)
# Get frequencies for rfft
rfreqs = np.fft.rfftfreq(n_samples, 1/sample_rate)
print(f"RFFT frequency array shape: {rfreqs.shape}")
print(f"All frequencies are non-negative: {np.all(rfreqs >= 0)}")

numpy.fft.fftshift()

The numpy.fft.fftshift() function shifts the zero-frequency component to the center of the spectrum. This is useful for visualization and analysis of Fourier transform results, as it places negative frequencies on the left and positive frequencies on the right.

Syntax:

numpy.fft.fftshift(x, axes=None)
# Shift FFT result
fft_vals = np.fft.fft(signal)
fft_shifted = np.fft.fftshift(fft_vals)
freq_shifted = np.fft.fftshift(frequencies)
print(f"Center frequency after shift: {freq_shifted[len(freq_shifted)//2]}")

numpy.fft.ifftshift()

The numpy.fft.ifftshift() function is the inverse of fftshift(). It undoes the frequency shift, returning the spectrum to its original layout where zero frequency is at the beginning.

Syntax:

numpy.fft.ifftshift(x, axes=None)
# Undo the shift
fft_unshifted = np.fft.ifftshift(fft_shifted)
print(f"Unshift successful: {np.allclose(fft_vals, fft_unshifted)}")

Comprehensive Example: Audio Signal Analysis

Here’s a complete example demonstrating how to use NumPy Fourier transform functions to analyze an audio signal, identify dominant frequencies, and filter out unwanted frequencies.

import numpy as np
import matplotlib.pyplot as plt

# Create a composite audio signal with multiple frequencies
# Sample rate: 1000 Hz, Duration: 2 seconds
sample_rate = 1000
duration = 2
num_samples = sample_rate * duration
time_array = np.linspace(0, duration, num_samples, endpoint=False)

# Create signal with three frequency components: 50Hz, 120Hz, and 300Hz
frequency1 = 50  # Hz - bass tone
frequency2 = 120  # Hz - mid tone
frequency3 = 300  # Hz - high tone
noise_frequency = 450  # Hz - unwanted noise

# Composite signal with noise
audio_signal = (np.sin(2 * np.pi * frequency1 * time_array) + 
                0.7 * np.sin(2 * np.pi * frequency2 * time_array) +
                0.5 * np.sin(2 * np.pi * frequency3 * time_array) +
                0.3 * np.sin(2 * np.pi * noise_frequency * time_array))

print("Original Signal Analysis")
print(f"Signal shape: {audio_signal.shape}")
print(f"Signal duration: {duration} seconds")
print(f"Sample rate: {sample_rate} Hz")
print(f"First 5 samples: {audio_signal[:5]}")

# Compute FFT using NumPy Fourier transform function
fft_result = np.fft.fft(audio_signal)
fft_magnitude = np.abs(fft_result)
fft_phase = np.angle(fft_result)

# Get frequency values
frequencies = np.fft.fftfreq(num_samples, 1/sample_rate)

print(f"\nFFT Analysis")
print(f"FFT result shape: {fft_result.shape}")
print(f"FFT result is complex: {np.iscomplexobj(fft_result)}")

# Find dominant frequencies (using only positive frequencies)
positive_freq_indices = np.where(frequencies > 0)
positive_frequencies = frequencies[positive_freq_indices]
positive_magnitudes = fft_magnitude[positive_freq_indices]

# Get top 4 frequencies
top_indices = np.argsort(positive_magnitudes)[-4:][::-1]
dominant_frequencies = positive_frequencies[top_indices]
dominant_magnitudes = positive_magnitudes[top_indices]

print(f"\nDominant Frequencies Found:")
for i, (freq, mag) in enumerate(zip(dominant_frequencies, dominant_magnitudes), 1):
    print(f"{i}. Frequency: {freq:.2f} Hz, Magnitude: {mag:.2f}")

# Filter out the noise frequency (450 Hz)
# Create a filter mask
filter_mask = np.ones_like(fft_result)
noise_threshold = 400  # Hz
for i, freq in enumerate(frequencies):
    if abs(freq) > noise_threshold:
        filter_mask[i] = 0  # Zero out high frequencies

# Apply filter in frequency domain
filtered_fft = fft_result * filter_mask

print(f"\nFiltering Operation")
print(f"Filter applied at: {noise_threshold} Hz")
print(f"Frequencies removed: {np.sum(filter_mask == 0)}")
print(f"Frequencies retained: {np.sum(filter_mask == 1)}")

# Convert back to time domain using inverse FFT
filtered_signal = np.fft.ifft(filtered_fft).real

print(f"\nFiltered Signal")
print(f"Filtered signal shape: {filtered_signal.shape}")
print(f"First 5 samples: {filtered_signal[:5]}")
print(f"Signal is real: {np.all(np.isreal(filtered_signal))}")

# Compare signal power before and after filtering
original_power = np.sum(audio_signal**2) / len(audio_signal)
filtered_power = np.sum(filtered_signal**2) / len(filtered_signal)
noise_power = original_power - filtered_power

print(f"\nPower Analysis")
print(f"Original signal power: {original_power:.4f}")
print(f"Filtered signal power: {filtered_power:.4f}")
print(f"Removed noise power: {noise_power:.4f}")
print(f"Noise reduction: {(noise_power/original_power)*100:.2f}%")

# Demonstrate rfft for efficiency
rfft_result = np.fft.rfft(audio_signal)
rfft_frequencies = np.fft.rfftfreq(num_samples, 1/sample_rate)

print(f"\nRFFT Efficiency Comparison")
print(f"FFT output size: {fft_result.shape[0]}")
print(f"RFFT output size: {rfft_result.shape[0]}")
print(f"Memory reduction: {(1 - rfft_result.shape[0]/fft_result.shape[0])*100:.2f}%")

# Reconstruct from RFFT
reconstructed_from_rfft = np.fft.irfft(rfft_result)
reconstruction_error = np.max(np.abs(audio_signal - reconstructed_from_rfft))

print(f"Reconstruction error: {reconstruction_error:.10f}")
print(f"Perfect reconstruction: {reconstruction_error < 1e-10}")

# Demonstrate fftshift for visualization
fft_shifted = np.fft.fftshift(fft_result)
freq_shifted = np.fft.fftshift(frequencies)

print(f"\nFFTShift Operation")
print(f"Original zero-frequency index: {np.argmin(np.abs(frequencies))}")
print(f"Shifted zero-frequency index: {np.argmin(np.abs(freq_shifted))}")
print(f"Zero frequency now at center: {np.argmin(np.abs(freq_shifted)) == len(freq_shifted)//2}")

# Statistical analysis of frequency components
print(f"\nFrequency Domain Statistics")
print(f"Maximum magnitude: {np.max(fft_magnitude):.2f}")
print(f"Mean magnitude: {np.mean(fft_magnitude):.2f}")
print(f"Magnitude standard deviation: {np.std(fft_magnitude):.2f}")

# Phase information
print(f"\nPhase Information")
print(f"Phase range: [{np.min(fft_phase):.4f}, {np.max(fft_phase):.4f}] radians")
print(f"Phase at DC component: {fft_phase[0]:.4f} radians")

# Energy conservation (Parseval's theorem)
time_domain_energy = np.sum(np.abs(audio_signal)**2)
freq_domain_energy = np.sum(np.abs(fft_result)**2) / num_samples

print(f"\nEnergy Conservation (Parseval's Theorem)")
print(f"Time domain energy: {time_domain_energy:.4f}")
print(f"Frequency domain energy: {freq_domain_energy:.4f}")
print(f"Energy conservation verified: {np.isclose(time_domain_energy, freq_domain_energy)}")

Output:

Original Signal Analysis
Signal shape: (2000,)
Signal duration: 2 seconds
Sample rate: 1000 Hz
First 5 samples: [ 1.3         1.99683308  2.29022477  2.15423935  1.60180907]

FFT Analysis
FFT result shape: (2000,)
FFT result is complex: True

Dominant Frequencies Found:
1. Frequency: 50.00 Hz, Magnitude: 1000.18
2. Frequency: 120.00 Hz, Magnitude: 700.13
3. Frequency: 300.00 Hz, Magnitude: 500.09
4. Frequency: 450.00 Hz, Magnitude: 300.05

Filtering Operation
Filter applied at: 400 Hz
Frequencies removed: 1200
Frequencies retained: 800

Filtered Signal
Filtered signal shape: (2000,)
First 5 samples: [ 1.3         1.99670882  2.28970015  2.15332804  1.60117695]
Signal is real: True

Power Analysis
Original signal power: 1.2725
Filtered signal power: 1.2275
Removed noise power: 0.0450
Noise reduction: 3.54%

RFFT Efficiency Comparison
FFT output size: 2000
RFFT output size: 1001
Memory reduction: 49.95%

Reconstruction error: 0.0000000000
Perfect reconstruction: True

FFTShift Operation
Original zero-frequency index: 0
Shifted zero-frequency index: 1000
Zero frequency now at center: True

Frequency Domain Statistics
Maximum magnitude: 1000.18
Mean magnitude: 48.63
Magnitude standard deviation: 112.47

Phase Information
Phase range: [-3.1416, 3.1416] radians
Phase at DC component: 0.0000 radians

Energy Conservation (Parseval's Theorem)
Time domain energy: 2544.9100
Frequency domain energy: 2544.9100
Energy conservation verified: True

This comprehensive example demonstrates the practical application of NumPy Fourier transform functions in signal processing. The code shows how to analyze frequency content, identify dominant frequencies, apply filters in the frequency domain, and reconstruct the filtered signal. The NumPy FFT functions make complex signal processing tasks straightforward and efficient.

For more information about NumPy Fourier transform functions, visit the official NumPy documentation at https://numpy.org/doc/stable/reference/routines.fft.html where you can find additional details about advanced usage and mathematical foundations of these functions.