Want to break down complex signals into their building blocks? The Fast Fourier Transform (FFT) is like a musical analyzer for any kind of data. It can take a messy signal and show you exactly which frequencies make it up.
Python’s scipy.fft module makes this powerful tool easy to use. Whether you’re working with audio files, sensor readings, or any data that changes over time, FFT helps you see the hidden patterns inside.
In this tutorial, we’ll learn how to use scipy.fft to analyze signals step by step. You’ll see how to break down simple waves, plot the results, and even work with real audio data. No complex math needed – just practical Python code you can use right away.
What is Fast Fourier Transform (FFT) and When Is It Useful in Data Analysis?
FFT stands for Fast Fourier Transform. Think of it as a tool that takes a complex wave and breaks it down into simple sine waves. Every signal can be made up of different frequencies added together.
For example, when you hear a guitar chord, your ear hears one sound. But FFT can show you the individual notes that make up that chord. The same idea works for any data that changes over time.
How to Set Up and Install scipy.fft in Python Projects
Before we start, make sure you have the right packages installed:
pip install scipy numpy matplotlib
Breaking Down Simple Signals: Your First FFT Example with Code
Let’s start with a simple example. We’ll create a signal made of two different frequencies and see how FFT breaks it down.
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq
# Create a simple signal with two frequencies
time = np.linspace(0, 1, 500) # 1 second of time
freq1, freq2 = 5, 20 # 5 Hz and 20 Hz
signal = np.sin(2 * np.pi * freq1 * time) + np.sin(2 * np.pi * freq2 * time)
# Apply FFT
fft_result = fft(signal)
frequencies = fftfreq(len(signal), time[1] - time[0])
# Plot the results
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
# Original signal
ax1.plot(time[:100], signal[:100]) # Show first 100 points
ax1.set_title('Original Signal (First 0.2 seconds)')
ax1.set_xlabel('Time (seconds)')
ax1.set_ylabel('Amplitude')
# FFT result (magnitude)
ax2.plot(frequencies[:250], np.abs(fft_result)[:250])
ax2.set_title('FFT Result - Frequency Components')
ax2.set_xlabel('Frequency (Hz)')
ax2.set_ylabel('Magnitude')
ax2.grid(True)
plt.tight_layout()
plt.show()
Here’s what this code does step by step:
- Create the signal: We make a signal that mixes two sine waves at 5 Hz and 20 Hz
- Apply FFT: The
fft()
function finds all the frequency components - Get frequencies:
fftfreq()
tells us what frequencies correspond to our FFT results - Plot both: We show the original wavy signal and the frequency breakdown
When you run this, you’ll see two clear peaks in the frequency plot – one at 5 Hz and another at 20 Hz. That’s FFT working perfectly!
How Does FFT Work with Noisy or Complex Signals?
Real-world signals are much more complex. Let’s look at how FFT handles noise and multiple components:
# More complex signal with noise
np.random.seed(42) # For reproducible results
time = np.linspace(0, 2, 1000)
# Create a signal with multiple frequencies plus noise
signal = (2 * np.sin(2 * np.pi * 3 * time) + # 3 Hz component
1.5 * np.sin(2 * np.pi * 7 * time) + # 7 Hz component
0.5 * np.sin(2 * np.pi * 15 * time) + # 15 Hz component
0.3 * np.random.randn(len(time))) # Random noise
# Apply FFT
fft_result = fft(signal)
frequencies = fftfreq(len(signal), time[1] - time[0])
# Only look at positive frequencies
n = len(signal) // 2
positive_freqs = frequencies[:n]
positive_fft = np.abs(fft_result[:n])
# Find the peaks
from scipy.signal import find_peaks
peaks, _ = find_peaks(positive_fft, height=50)
print("Signal components found at frequencies:")
for peak in peaks:
freq = positive_freqs[peak]
magnitude = positive_fft[peak]
print(f" {freq:.1f} Hz (magnitude: {magnitude:.1f})")
# Plot
plt.figure(figsize=(12, 6))
plt.plot(positive_freqs, positive_fft)
plt.scatter(positive_freqs[peaks], positive_fft[peaks], color='red', s=100, zorder=5)
plt.title('FFT of Complex Signal - Found Peak Frequencies')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)
plt.xlim(0, 25)
plt.show()
This example shows how FFT can pick out individual frequency components even when they’re mixed with noise. The red dots show the peaks that scipy detected.
Practical Audio Analysis with FFT in Python: Example Code and Output
Now let’s look at a practical example with audio analysis. This is where FFT really shines:
# Simulate audio analysis
# This example works without actual audio files
def analyze_audio_segment(duration=1.0, sample_rate=44100):
"""Simulate analyzing a segment of audio"""
time = np.linspace(0, duration, int(sample_rate * duration))
# Simulate a musical chord (C major: C-E-G)
# Approximate frequencies: C4=262Hz, E4=330Hz, G4=392Hz
audio = (np.sin(2 * np.pi * 262 * time) + # C note
np.sin(2 * np.pi * 330 * time) + # E note
np.sin(2 * np.pi * 392 * time)) # G note
# Add some harmonics to make it more realistic
audio += 0.3 * np.sin(2 * np.pi * 524 * time) # C5 (octave)
audio += 0.2 * np.sin(2 * np.pi * 660 * time) # E5 (octave)
return audio, time
# Generate and analyze our "audio"
audio_signal, time = analyze_audio_segment()
# Apply FFT
fft_result = fft(audio_signal)
freqs = fftfreq(len(audio_signal), 1/44100)
# Focus on audible range (20 Hz to 2000 Hz)
audible_range = (freqs >= 20) & (freqs <= 2000)
audible_freqs = freqs[audible_range]
audible_magnitude = np.abs(fft_result[audible_range])
# Find the strongest frequencies
from scipy.signal import find_peaks
peaks, properties = find_peaks(audible_magnitude, height=1000, distance=20)
print("Detected musical notes:")
for i, peak in enumerate(peaks[:5]): # Show top 5 peaks
freq = audible_freqs[peak]
magnitude = audible_magnitude[peak]
print(f" {freq:.0f} Hz (strength: {magnitude:.0f})")
# Plot the frequency spectrum
plt.figure(figsize=(14, 6))
plt.plot(audible_freqs, audible_magnitude)
plt.scatter(audible_freqs[peaks], audible_magnitude[peaks],
color='red', s=80, zorder=5, label='Detected peaks')
plt.title('Audio Frequency Analysis - Musical Chord')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.legend()
plt.grid(True)
plt.xlim(200, 800)
plt.show()
This code shows you how FFT can identify the individual notes in a musical chord. In real applications, you could:
- Load actual audio files using libraries like
librosa
orsoundfile
- Detect musical notes and chords
- Find dominant frequencies in recordings
- Remove specific frequency ranges (like filtering out noise)
- Analyze speech patterns
How to Interpret Your FFT Results: Key Concepts Explained
When working with FFT, keep these key points in mind:
Magnitude vs Phase: Most of the time, you’ll work with np.abs(fft_result)
which gives you the magnitude (strength) of each frequency. The phase information is usually less important for basic analysis.
Frequency Resolution: The more data points you have, the better your frequency resolution. Longer signals give you more precise frequency measurements.
Sampling Rate: Your sampling rate determines the highest frequency you can detect. The rule is: max detectable frequency = sample_rate / 2.
Window Effects: FFT assumes your signal repeats infinitely. Real signals don’t, which can create artifacts. For advanced work, look into windowing functions.
Quick Reference: Most Used scipy.fft Functions for Beginners
Here are the most common scipy.fft functions you’ll use:
from scipy.fft import fft, ifft, fftfreq, rfft, irfft
# Basic FFT
result = fft(signal) # Complex result
freqs = fftfreq(len(signal), 1/sample_rate) # Frequency array
# Real FFT (for real-valued signals)
result = rfft(signal) # More efficient for real signals
freqs = fftfreq(len(signal), 1/sample_rate)[:len(result)]
# Inverse FFT (reconstruct signal)
original = ifft(fft_result) # Get back original signal
original_real = irfft(rfft_result) # For real FFT results
What’s Next?
You now know the basics of using scipy.fft for signal analysis! Try these ideas to learn more:
- Load real audio files and analyze them
- Experiment with filtering – remove certain frequencies and see what happens
- Try 2D FFT for image processing
- Look into spectrograms for time-frequency analysis
- Explore windowing functions for cleaner results
FFT is a powerful tool that opens up a whole world of signal processing. Start with simple examples like these, and gradually work your way up to more complex applications.