Scientific ComputingIntermediate

Fourier Transform (FFT) in Python

Learn the Fast Fourier Transform in Python. Decompose signals into frequencies with numpy.fft, plot the spectrum, and filter noise — all runnable in your browser.

Try it yourself

Run this code directly in your browser. Click "Open in full editor" to experiment further.

Loading...

Click Run to see output

Or press Ctrl + Enter

How it works

The Fast Fourier Transform is one of those rare algorithms that quietly runs the modern world. Every time you stream music, make a phone call, look at a JPEG, or use Wi-Fi, an FFT is somewhere in the loop. Once you see what it does, a lot of seemingly-magical tech suddenly makes sense.

The Big Idea (No Math Required)

Any signal that varies over time — audio, vibrations, stock prices, an EKG — can be thought of as a mix of pure sine waves at different frequencies. The FFT takes that signal in and tells you exactly which sine waves it's made of and how loud each one is.

It's a translator between two ways of looking at the same data:

  • Time domain: "the signal looked like this at each moment"
  • Frequency domain: "the signal contains this much of every possible frequency"
  • The two views carry the same information. The FFT (and its sibling, the inverse FFT) lets you flip between them in milliseconds.

    Why The "Fast" In Fast Fourier Transform Matters

    The naive way to compute a discrete Fourier transform takes O(N²) operations. For an audio clip with a million samples, that's a trillion operations. The FFT pulls the same answer out in O(N log N) — about 20 million operations for the same clip. That difference is why real-time audio processing exists at all.

    You never need to implement it yourself. NumPy's np.fft.fft and SciPy's scipy.fft.fft are wrappers around extremely well-tuned C/Fortran libraries.

    The Two Functions You Need

    fft_values = np.fft.fft(signal)               # the complex amplitudes
    freqs      = np.fft.fftfreq(N, d=1/sample_rate)  # the Hz value of each bin

    A few things to know about what comes back:

  • The output is complex numbers. Take np.abs(...) to get amplitudes (how loud each frequency is) and np.angle(...) for phase.
  • For a real-valued input signal, the output is symmetric — the second half is the mirror image of the first. You only ever plot the first N // 2 bins.
  • To convert raw amplitudes to something physically meaningful, multiply by 2 / N.
  • The Sample Rate Rule You Cannot Ignore

    The Nyquist theorem says: to capture a frequency of f Hz cleanly, you need to sample at least 2f times per second. In other words, with a sample rate of 1000 Hz, the highest frequency you can possibly see in your FFT is 500 Hz. Anything above that gets aliased — it folds back down and shows up as a fake lower frequency.

    This is why CD audio uses 44.1 kHz — slightly more than 2× the upper limit of human hearing (~20 kHz).

    What You Can Actually Do With It

  • Find dominant frequencies — what note is being played, what the engine RPM is, what the heart rate is
  • Filter noise — kill the small frequency components and inverse-transform back. The denoising example in the snippet does exactly this.
  • Compress data — JPEG and MP3 throw away frequency components humans can't perceive
  • Detect patterns — spot the periodic component hiding in chaotic-looking data
  • Compare signals — two clips that sound similar will have similar spectra even if the time-domain waveforms look different
  • Common Gotchas

  • Forgot to scale by `2/N` — your amplitudes will be in the thousands and meaningless.
  • Plotting the full spectrum — the right half is the mirror of the left half. Slice with [:N//2].
  • DC offset dominates — if your signal has a non-zero average, the bin at 0 Hz will be huge. Subtract the mean before transforming if that's hiding the interesting stuff.
  • Window leakage — if your signal isn't a perfect integer number of periods, peaks smear into neighboring bins. Apply a window (np.hanning(N) * signal) before the FFT to clean this up.
  • When To Reach For SciPy Instead

    scipy.fft has the same API as numpy.fft but is generally faster and supports more variants (real FFT, multi-dimensional FFT, DCT). For 2D image work, scipy.fft.fft2 is what you want.

    Run the snippet above and you'll see the FFT cleanly recover three tones from a mixed signal, then watch a noisy waveform get rebuilt into something almost identical to the clean original — using nothing but FFT, threshold, inverse FFT.

    Related examples