Skip to content

fft

stable

Fast Fourier Transform and spectral analysis utilities. Compute forward/inverse FFT, power spectra, windowing, STFT, convolution, and peak frequency detection on real-valued signal arrays.

use plugin fft::{fft, ifft, magnitude, …}
19 functions Math
/ filter jk navigate Esc clear
Functions (19)
  1. fft Forward FFT of real+imaginary arrays
  2. ifft Inverse FFT back to time domain
  3. magnitude Per-bin magnitude from real+imag arrays
  4. phase Per-bin phase angle from real+imag arrays
  5. power_spectrum Power spectrum of a real signal
  6. next_power_of_2 Smallest power of 2 >= n
  7. windowed_fft FFT with a window function applied first
  8. stft Short-Time Fourier Transform (frame-based)
  9. peak_frequencies Find dominant frequency peaks
  10. bandpass Zero out bins outside a frequency range
  11. convolution Linear convolution via FFT
  12. cross_correlation Cross-correlation of two signals via FFT
  13. autocorrelation Autocorrelation of a signal via FFT
  14. spectral_centroid Frequency-weighted centre of the spectrum
  15. spectral_rolloff Frequency below which most energy lies
  16. frequency_bins Frequency value for each FFT bin
  17. apply_window Apply a window function to a signal
  18. generate_sine Generate a sine wave sample array
  19. db_scale Convert magnitude values to decibels

Overview

fft is a dependency-free signal-processing toolkit built around a Cooley-Tukey radix-2 FFT. Signals are plain Zolo arrays of numbers — there is no opaque handle or stateful context — so a waveform is just a table you can build, slice, and pass around freely. Inputs whose length is not a power of 2 are zero-padded automatically, and the complex spectrum is always returned as a {real, imag} table you can feed into the magnitude, phase, and spectral helpers.

The mental model is a pipeline: produce or load a real signal (for example with generate_sine), optionally taper it with apply_window, transform it with fft, then analyse the result with magnitude, peak_frequencies, spectral_centroid, or db_scale — and ifft back to the time domain when you need to reconstruct a filtered signal. Higher-level helpers such as convolution, cross_correlation, and stft wrap that pipeline for common tasks. Use it whenever you need spectral analysis, frequency-domain filtering, or fast convolution without pulling in a numeric library.

Common patterns

Generate a tone, transform it, and read back its magnitude spectrum:

use plugin fft::{generate_sine, fft, magnitude}

let signal = generate_sine(440.0, 44100.0, 1024)
let zeros  = generate_sine(0.0, 44100.0, 1024)
let spec   = fft(signal, zeros)
let mags   = magnitude(spec["real"], spec["imag"])
print("bins: {mags}")

Find the dominant frequency of a noisy signal:

use plugin fft::{generate_sine, fft, peak_frequencies}

let sig   = generate_sine(1000.0, 8000.0, 1024)
let zeros = generate_sine(0.0, 8000.0, 1024)
let spec  = fft(sig, zeros)
let peaks = peak_frequencies(spec["real"], spec["imag"], 8000.0)
print("dominant: {peaks[1]["frequency"]} Hz")

Band-pass filter a signal in the frequency domain, then reconstruct it:

use plugin fft::{generate_sine, fft, bandpass, ifft}

let sig      = generate_sine(440.0, 44100.0, 1024)
let zeros    = generate_sine(0.0, 44100.0, 1024)
let spec     = fft(sig, zeros)
let filtered = bandpass(spec["real"], spec["imag"], 400.0, 500.0, 44100.0)
let restored = ifft(filtered["real"], filtered["imag"])
print(restored["real"])

Forward FFT of real+imaginary arrays

Performs a forward Cooley-Tukey radix-2 FFT. Both arrays must be the same length; zero-padding to the next power of 2 is applied automatically. Returns {real, imag}.

use plugin fft::{fft, magnitude, generate_sine}

let signal = generate_sine(440.0, 44100.0, 1024)
let zeros  = generate_sine(0.0, 44100.0, 1024)
let result = fft(signal, zeros)
let mags   = magnitude(result["real"], result["imag"])
print(mags)

Inverse FFT back to time domain

Inverse FFT: converts frequency-domain arrays back to the time domain. The output is normalised by 1/N. Returns {real, imag}.

use plugin fft::{fft, ifft, generate_sine}

let sig    = generate_sine(220.0, 44100.0, 512)
let zeros  = generate_sine(0.0, 44100.0, 512)
let freq   = fft(sig, zeros)
let back   = ifft(freq["real"], freq["imag"])
print(back["real"])

A forward then inverse transform reconstructs the original signal (up to padding):

use plugin fft::{fft, ifft}

let sig   = [1.0, 2.0, 3.0, 4.0]
let zeros = [0.0, 0.0, 0.0, 0.0]
let freq  = fft(sig, zeros)
let round = ifft(freq["real"], freq["imag"])
print(round["real"])  // ~[1, 2, 3, 4]

Per-bin magnitude from real+imag arrays

Computes sqrt(r^2 + i^2) for each bin. Use this after fft to get the amplitude spectrum.

use plugin fft::{fft, magnitude, generate_sine}

let sig  = generate_sine(1000.0, 8000.0, 256)
let im   = generate_sine(0.0, 8000.0, 256)
let spec = fft(sig, im)
let mags = magnitude(spec["real"], spec["imag"])
print(mags)

Per-bin phase angle from real+imag arrays

Computes atan2(imag, real) for each bin, returning phase angles in radians.

use plugin fft::{fft, phase, generate_sine}

let sig = generate_sine(100.0, 8000.0, 256)
let im  = generate_sine(0.0, 8000.0, 256)
let sp  = fft(sig, im)
let ph  = phase(sp["real"], sp["imag"])
print(ph)

Power spectrum of a real signal

Computes the power spectrum (r^2 + i^2) of a real-valued signal in one step. Takes only the real array; the imaginary part is assumed zero.

use plugin fft::{power_spectrum, generate_sine}

let sig   = generate_sine(440.0, 44100.0, 1024)
let power = power_spectrum(sig)
print(power)

Smallest power of 2 >= n

Returns the smallest power of 2 that is greater than or equal to n. Useful for sizing FFT buffers.

use plugin fft::{next_power_of_2}

print(next_power_of_2(100))   // 128
print(next_power_of_2(1024))  // 1024
print(next_power_of_2(1025))  // 2048

FFT with a window function applied first

Applies a window function to the signal before computing the FFT. Supported window types: "hann", "hamming", "blackman". Returns {real, imag}.

use plugin fft::{windowed_fft, magnitude, generate_sine}

let sig  = generate_sine(440.0, 44100.0, 1024)
let spec = windowed_fft(sig, "hann")
let mags = magnitude(spec["real"], spec["imag"])
print(mags)

Short-Time Fourier Transform (frame-based)

Computes the Short-Time Fourier Transform by sliding a Hann-windowed frame over the signal with the given hop size. Returns a table of frames, each containing {real, imag} for the positive-frequency bins.

use plugin fft::{stft, generate_sine}

let sig    = generate_sine(440.0, 44100.0, 4096)
let frames = stft(sig, 512, 256)
print("frame count: {frames}")

Each frame is a {real, imag} table, so you can transform a single frame further:

use plugin fft::{stft, magnitude, generate_sine}

let sig    = generate_sine(440.0, 44100.0, 4096)
let frames = stft(sig, 512, 256)
let first  = frames[1]
let mags   = magnitude(first["real"], first["imag"])
print(mags)

Find dominant frequency peaks

Finds local maxima in the magnitude spectrum and returns them sorted by magnitude descending. Each entry contains {frequency, magnitude}.

use plugin fft::{fft, peak_frequencies, generate_sine}

let sig    = generate_sine(440.0, 44100.0, 1024)
let zeros  = generate_sine(0.0, 44100.0, 1024)
let spec   = fft(sig, zeros)
let peaks  = peak_frequencies(spec["real"], spec["imag"], 44100.0)
print(peaks[1]["frequency"])  // ~440 Hz

Zero out bins outside a frequency range

Zeroes out all FFT bins outside the [low_freq, high_freq] range, effectively filtering the spectrum. Returns {real, imag}.

use plugin fft::{fft, bandpass, ifft, generate_sine}

let sig      = generate_sine(440.0, 44100.0, 1024)
let zeros    = generate_sine(0.0, 44100.0, 1024)
let spec     = fft(sig, zeros)
let filtered = bandpass(spec["real"], spec["imag"], 400.0, 500.0, 44100.0)
let out      = ifft(filtered["real"], filtered["imag"])
print(out["real"])

Linear convolution via FFT

Computes the linear convolution of two signals using FFT multiplication. Returns the result as a real-valued array of length len(s1) + len(s2) - 1.

use plugin fft::{convolution}

let a   = [1.0, 2.0, 3.0]
let b   = [1.0, 1.0]
let out = convolution(a, b)
print(out)  // [1.0, 3.0, 5.0, 3.0]

Convolving a signal with a smoothing kernel applies a moving average filter:

use plugin fft::{convolution}

let signal = [0.0, 4.0, 0.0, 4.0, 0.0]
let kernel = [0.5, 0.5]
let smooth = convolution(signal, kernel)
print(smooth)

Cross-correlation of two signals via FFT

Computes the cross-correlation between two signals via FFT. Useful for detecting time delays between related signals.

use plugin fft::{cross_correlation, generate_sine}

let a    = generate_sine(440.0, 44100.0, 512)
let b    = generate_sine(440.0, 44100.0, 512)
let corr = cross_correlation(a, b)
print(corr)

Autocorrelation of a signal via FFT

Computes the autocorrelation of a signal with itself, returning a real-valued array of length 2*N - 1. Useful for pitch detection.

use plugin fft::{autocorrelation, generate_sine}

let sig  = generate_sine(440.0, 44100.0, 512)
let auto = autocorrelation(sig)
print(auto)

Frequency-weighted centre of the spectrum

Returns the frequency-weighted mean of the magnitude spectrum — the "centre of mass" of the spectrum. Higher values indicate more high-frequency content.

use plugin fft::{fft, magnitude, spectral_centroid, generate_sine}

let sig  = generate_sine(1000.0, 44100.0, 1024)
let im   = generate_sine(0.0, 44100.0, 1024)
let spec = fft(sig, im)
let mags = magnitude(spec["real"], spec["imag"])
let sc   = spectral_centroid(mags, 44100.0)
print("centroid: {sc} Hz")

Frequency below which most energy lies

Returns the frequency below which threshold fraction (default 0.85) of total spectral energy is contained. Useful for characterising timbral brightness.

use plugin fft::{fft, magnitude, spectral_rolloff, generate_sine}

let sig  = generate_sine(2000.0, 44100.0, 1024)
let im   = generate_sine(0.0, 44100.0, 1024)
let spec = fft(sig, im)
let mags = magnitude(spec["real"], spec["imag"])
let ro   = spectral_rolloff(mags, 44100.0, 0.85)
print("rolloff: {ro} Hz")

Frequency value for each FFT bin

Returns a table of n frequency values (in Hz), one per FFT bin. Use this to label the output of magnitude or power_spectrum.

use plugin fft::{frequency_bins}

let bins = frequency_bins(8, 8000.0)
print(bins)  // [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000]

Apply a window function to a signal

Applies a named window function ("hann", "hamming", or "blackman") to a sample array and returns the windowed signal. Use before FFT to reduce spectral leakage.

use plugin fft::{apply_window, generate_sine}

let sig      = generate_sine(440.0, 44100.0, 512)
let windowed = apply_window(sig, "hamming")
print(windowed)

Generate a sine wave sample array

Generates a table of num_samples sine wave samples at the given frequency and sample rate. Useful for testing FFT functions.

use plugin fft::{generate_sine}

let wave = generate_sine(440.0, 44100.0, 1024)
print(wave[1])  // first sample

Convert magnitude values to decibels

Converts magnitude values to decibels using 20 * log10(magnitude / reference). reference defaults to 1.0 when omitted. Values of 0 or below become -Infinity.

use plugin fft::{fft, magnitude, db_scale, generate_sine}

let sig  = generate_sine(440.0, 44100.0, 1024)
let im   = generate_sine(0.0, 44100.0, 1024)
let spec = fft(sig, im)
let mags = magnitude(spec["real"], spec["imag"])
let db   = db_scale(mags, 1.0)
print(db)

When reference is omitted it defaults to 1.0, so raw magnitudes convert directly to dB:

use plugin fft::{db_scale}

let mags = [1.0, 0.1, 0.01]
print(db_scale(mags))  // [0, -20, -40]
enespt-br