Written and maintained by CASRAI Editorial Board
Last updated
To take a Fourier transform in NumPy, call np.fft.fft(a) on a one-dimensional array. It returns a complex array of the same length. Entry 0 is the sum of the signal, and the other entries are the coefficients of the frequencies listed by np.fft.fftfreq. Most mistakes come from three details that short tutorials skip: how the norm argument scales the result, the order in which frequencies are stored, and what the complex numbers mean. This guide covers all three, with a four-point example you can check by hand. It follows the NumPy documentation (current stable release 2.5, checked 2026-10-29).
What it is used for in research
The discrete Fourier transform rewrites a sampled signal as a sum of sinusoids, so you can see which frequencies it contains. Researchers use it to find the dominant oscillation in a time series (instrument vibration, a periodic physiological signal, a seasonal cycle), to measure how power is spread across frequency, and to filter in the frequency domain and transform back. For the wider field, see what signal processing is; for modelling time-ordered data in the time domain instead, see ARIMA models for research time series.
NumPy’s numpy.fft module defines the transform as Ak = Σ am exp(−2πi·mk/n), summed over m = 0 to n−1. The inverse differs only by the sign of the exponent and, by default, a factor of 1/n.
Install or access (official source only)
NumPy is free, open-source software. The official install page (checked 2026-10-29) gives these routes:
- pip:
pip install numpy - conda:
conda create -n my-env, thenconda activate my-env, thenconda install numpy - Virtual environment:
python -m venv my-env, thensource my-env/bin/activateon macOS and Linux ormy-env\Scripts\activateon Windows, thenpip install numpy
If the analysis will be shared, record the environment so others can rebuild it; see sharing a reproducible conda environment and the definition of computational reproducibility. The functions below live in numpy.fft, so no extra package is needed.
Step-by-step: transform, invert and read a signal
1. Transform an array and invert it
- Import NumPy and create a one-dimensional real array:
import numpy as np, thena = np.array([1.0, 2.0, 3.0, 4.0]). - Transform it:
A = np.fft.fft(a). - Check the round trip:
a_back = np.fft.ifft(A)returns the original values (as complex numbers with zero imaginary part).
For this input, A is [10+0j, -2+2j, -2+0j, -2-2j]. Entry 0 is 1+2+3+4 = 10, the sum of the signal, exactly as the documentation describes the zero-frequency term.
2. Attach frequencies to the bins
- Build the frequency axis:
freqs = np.fft.fftfreq(len(a), d=dt), wheredis the sample spacing, the inverse of the sampling rate. The default is 1. Ifdtis in seconds, the frequencies are in cycles per second (Hz).
With len(a) = 4 and d = 1, freqs is [0, 0.25, -0.5, -0.25]. The documentation gives the layout: for even n, the values [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n). Non-negative frequencies come first, then negative ones, and this matches the order of the fft output.
3. Plot amplitude against frequency
- Take
amp = np.abs(A)and plot it againstfreqs. To get a plot with the zero frequency in the middle, applynp.fft.fftshiftto both the spectrum and the frequencies.np.fft.ifftshiftundoes the shift.
Worked example: finding two known frequencies
For real-valued signals, rfft returns only the non-negative frequencies. Build a signal sampled at 100 Hz for 1 second, made of a 5 Hz sine with amplitude 3 and a 20 Hz sine with amplitude 1:
import numpy as np
fs = 100
t = np.arange(0, 1, 1/fs)
x = 3*np.sin(2*np.pi*5*t) + 1*np.sin(2*np.pi*20*t)
X = np.fft.rfft(x)
f = np.fft.rfftfreq(len(x), d=1/fs)
amp = 2*np.abs(X)/len(x)
Running this, the two largest entries of amp are 3.0 at f = 5.0 and 1.0 at f = 20.0. The factor 2/N is a convention for one-sided spectra of sinusoids: because the signal covers whole cycles, each sine’s energy splits between a positive and a negative frequency, and rfft keeps only the positive one. The SciPy tutorial uses the plain abs(rfft(x)/N), which gives half these values; both are valid as long as you state which scaling you report.
Output and how to read it
Why is the output complex?
Each coefficient carries a magnitude and a phase. NumPy’s documentation states that np.abs(A) is the amplitude spectrum, np.abs(A)**2 is the power spectrum, and np.angle(A) gives the phase spectrum. For real input, A[0] is always purely real.
What does the norm argument do?
The norm keyword decides where the 1/n factor goes. The documentation notes that the "backward" and "forward" values were added in NumPy 1.20.0. Use the same setting for the forward and inverse call, or the round trip will be scaled wrongly.
| norm | Forward scaling | Inverse scaling |
|---|---|---|
"backward" (default; None is an alias) |
none | 1/n |
"ortho" |
1/√n | 1/√n |
"forward" |
1/n | none |
For the four-point example, np.fft.fft(a, norm="ortho") returns [5+0j, -1+1j, -1+0j, -1-1j], which is the default result divided by √4 = 2. With "ortho" both directions are scaled by the same factor, so the sum of squared magnitudes is preserved between the signal and its transform. In the example, the signal has 1+4+9+16 = 30, and the ortho spectrum has 25+2+1+2 = 30.
What is the difference between rfft and fft?
rfft takes real input of n points and returns n/2+1 complex points, the non-negative frequencies only. fft returns all n. Use rfftfreq for the matching frequency axis. Going back, irfft needs the original length passed as n when it was odd: from the same rfft output, the default irfft returns an even length, so pass n=5 to recover a 5-point signal.
Troubleshooting
- Spectrum looks mirrored or frequencies look wrong. The output is not sorted from negative to positive. Use
fftfreqfor labels, orfftshifton both arrays together. - Peak heights do not match the signal amplitude. The default
normleaves the forward transform unscaled, so amplitudes grow with n. Divide by n (and double non-zero bins for a one-sided spectrum), or usenorm="forward". - Slow on some lengths. The documentation says the FFT is most efficient when n is a power of 2. SciPy’s documentation adds that it is slowest when n is prime, and offers
scipy.fft.next_fast_lento find a good length. In NumPy you can passntofft: a smaller n crops the input and a larger n zero-pads it. IndexErrorfromfft. Theaxisyou passed does not exist for the array. The default is the last axis (axis=-1).- Single-precision input.
numpy.fftpromotesfloat32andcomplex64arrays tofloat64andcomplex128, so the output is double precision. - Edge artefacts. The transform assumes the signal repeats periodically. The SciPy tutorial discusses detrending but warns that it does not necessarily improve the spectrum.
Free alternatives
| Option | What its documentation says |
|---|---|
numpy.fft |
fft/ifft, 2-D and n-D versions (fft2, fftn), real-input versions (rfft, irfft), Hermitian-signal versions (hfft, ihfft), plus fftfreq, rfftfreq, fftshift, ifftshift. |
scipy.fft |
The same family of transforms, plus discrete cosine and sine transforms (dct, dst), next_fast_len, a set_workers context manager for the maximum number of threads, and set_backend for third-party backends. |
Both are free and open source. Choose by the features you need from the table; for a plain FFT of an array, numpy.fft is enough.
FAQ
How do I get frequencies in Hz from np.fft.fft?
Call np.fft.fftfreq(n, d=1/fs), where n is the number of samples and fs the sampling rate in Hz. Entry k of the result is the frequency of bin k of the transform.
Is the FFT output complex even for a real signal?
Yes. Take the magnitude with np.abs for amplitude and np.angle for phase. For real input, rfft returns only the non-redundant half.
Does the default scaling make ifft(fft(a)) equal a?
Yes. With the default norm="backward" the inverse applies the 1/n factor, so the round trip returns the input up to round-off.
When should I use scipy.fft instead?
When you need cosine or sine transforms, multithreaded execution via set_workers, helpers such as next_fast_len, or a third-party backend. Otherwise numpy.fft covers the standard transforms.
Sources (official docs)
All pages checked 2026-10-29.
- NumPy, “Discrete Fourier Transform (numpy.fft)”: https://numpy.org/doc/stable/reference/routines.fft.html
- NumPy, “numpy.fft.fft”: https://numpy.org/doc/stable/reference/generated/numpy.fft.fft.html
- NumPy, “numpy.fft.fftfreq”: https://numpy.org/doc/stable/reference/generated/numpy.fft.fftfreq.html
- NumPy, “Installing NumPy”: https://numpy.org/install/
- SciPy, “Discrete Fourier transforms (scipy.fft)” tutorial: https://docs.scipy.org/doc/scipy/tutorial/fft.html
- SciPy, “Discrete Fourier transforms (scipy.fft)” reference: https://docs.scipy.org/doc/scipy/reference/fft.html








