Sampled measurements often contain repeating components that are easier to read by frequency than by time. NumPy can calculate a fast Fourier transform from a numeric array and identify which frequency bin carries the strongest part of a real-valued signal.

For real-valued input, np.fft.rfft() returns the non-negative side of the discrete Fourier transform. Pair it with np.fft.rfftfreq() built from the same sample count and sample spacing so each magnitude lines up with a frequency bin in hertz.

One second of synthetic data sampled at 16 Hz with a 3 Hz sine wave gives a known peak for the smoke test. Measured data can use the same calculation once signal contains evenly spaced samples and sample_rate matches the acquisition rate; windowing, detrending, and filtering are separate analysis choices.

Steps to calculate a real-input FFT with NumPy:

  1. Create a Python script that samples a sine wave and checks the dominant FFT bin.
    fft-calculate.py
    import numpy as np
     
    sample_rate = 16
    frequency_hz = 3
    samples = np.arange(sample_rate) / sample_rate
    signal = np.sin(2 * np.pi * frequency_hz * samples)
     
    spectrum = np.fft.rfft(signal)
    frequencies = np.fft.rfftfreq(signal.size, d=1 / sample_rate)
    magnitudes = np.abs(spectrum)
     
    dominant_index = np.argmax(magnitudes[1:]) + 1
    dominant_frequency = frequencies[dominant_index]
     
    print("frequency bins:", frequencies)
    print("magnitudes:", np.round(magnitudes, 3))
    print("dominant frequency:", dominant_frequency)
    print("matches expected:", np.isclose(dominant_frequency, frequency_hz))

    np.argmax(magnitudes[1:]) + 1 skips the zero-frequency term so a DC offset does not become the selected peak.

  1. Run the script.
    $ python3 fft-calculate.py
    frequency bins: [0. 1. 2. 3. 4. 5. 6. 7. 8.]
    magnitudes: [0. 0. 0. 8. 0. 0. 0. 0. 0.]
    dominant frequency: 3.0
    matches expected: True

    The strongest non-DC magnitude is at 3 Hz, matching the sine wave used to generate the samples.

  1. Confirm that matches expected prints True before replacing the sample data.

    Keep signal.size and d=1 / sample_rate paired with the data being transformed. Use np.fft.fft() with np.fft.fftfreq() when the input values are complex.