Fork me on GitHub

The discrete Fourier transform in pure Go.
numpy.fft semantics, no FFTW.

go-fft computes the discrete Fourier transform of complex and real signals of any length โ€” an iterative mixed-radix Stockham engine for lengths with small prime factors, Rader and Bluestein's chirp-z for the rest โ€” in pure Go, with cgo disabled. It follows the numpy.fft / scipy.fft conventions: forward and inverse complex and real transforms, multi-dimensional and 2-D transforms, frequency-bin helpers, window functions and spectral helpers (PSD, spectrogram).

7 API families, numpy and scipy names6 64-bit targetsCGO=0 no FFTW
main.go
import "github.com/go-fft/fft"

X := fft.FFT(x)          // forward DFT of []complex128, any length
y := fft.IFFT(X)         // inverse DFT, normalized by N (IFFT(FFT(x)) โ‰ˆ x)

R := fft.RFFT(r)         // real-input DFT, non-redundant N/2+1 bins (numpy.fft.rfft)
z := fft.IRFFT(R, len(r)) // back to []float64 (numpy.fft.irfft)

// Windowing and spectral helpers:
w  := fft.Hann(n)             // also Hamming, Blackman, BlackmanHarris, Bartlett
f  := fft.FFTFreq(n, d)       // bin frequencies (numpy.fft.fftfreq)
p  := fft.PSD(sig, d)         // one-sided power spectral density (periodogram)
3 repositories โ€” one cgo-free module that cross-compiles to a static binary on every target
Ask it, do not take our word

One length per engine, checked against itself.

Five lengths, one for each way go-fft takes a transform: powers of two and smooth composites on the Stockham engine, a prime through Rader's algorithm, another through Bluestein's chirp-z. For each, how far IFFT(FFT(x)) lands from x, and how well Parseval's identity holds. The output below is a real run against the published module, with nothing edited.

go run ./fftcheck โ€” zsh
# go-fft v0.19.1 on arm64 โ€” round trip and Parseval, max error
$ go run ./fftcheck
N       LENGTH                 ROUND TRIP     PARSEVAL
4096    2^12, Stockham         9.2e-16        4.7e-15
1296    2^4ยท3^4, Stockham      1.6e-15        1.9e-15
1009    prime, Rader           2.4e-15        3.4e-16
10007   prime, Bluestein       2.7e-15        1.5e-15
1048576 2^20, Stockham         1.9e-15        7.6e-14

NextFastLen(1009) = 1024
Why go-fft

The workhorse of signal processing, without FFTW.

The fast Fourier transform is the workhorse of signal processing, and in most languages it means binding the native FFTW3 C library. go-fft brings the numpy.fft / scipy.fft vocabulary to Go with no cgo and no FFTW: a single portable module that cross-compiles to a static binary on every target, accelerated by go-asmgen-generated SIMD where the Go assembler allows it.

๐Ÿน

Pure Go

CGO_ENABLED=0 across the org. No cgo, no FFTW, no native shims.

โœ…

100% test coverage

Gated in CI, differentially checked against numpy.fft.

๐Ÿ”ข

numpy.fft semantics

The same normalization, bin layout and frequency conventions you already know.

โšก

AVX2, AVX-512 & NEON, bit-identical

On amd64 the transform's passes run as go-asmgen AVX2 kernels, and AVX-512 for large powers of two; on arm64 as NEON kernels that reproduce the compiler's own fused multiply-adds โ€” each tested bit-identical to the Go code, because a faster transform that answers differently is not the same transform. The same Go code runs on all six 64-bit targets.

๐Ÿ’Ž

The cgo-free FFT that was missing

Ruby has no cgo-free FFT (every option wraps FFTW3) and gonum/dsp/fourier's optimized assembly is amd64-only. go-fft runs on all six 64-bit Go targets, in pure Go.

โš–๏ธ

BSD-3-Clause

On every source file.

What the module offers

7 families, numpy's and scipy's names.

Complex 1-D

FFT, IFFT and Plan for any length: Stockham for lengths whose prime factors are at most 13, Rader or Bluestein for the rest.

Real 1-D and Hermitian

RFFT, IRFFT, HFFT, IHFFT and RealPlan: the N/2+1 non-redundant bins, as numpy.fft.rfft returns them.

N-D and 2-D

FFTN, FFT2, RFFTN, RFFT2 and allocation-free PlanN/RealPlan2, over a row-major shape, spread across cores when large.

numpy's arguments

n, norm and axes through the ...With(Options) variants, whose zero value is numpy’s defaults; FFTShift and NextFastLen.

DCT and DST

Types Iโ€“IV, forward, inverse and N-D, as scipy.fft.dct and dst define them, with reusable plans.

Single precision

Every function above with 32 appended: complex64 in, complex64 out, as scipy.fft and NumPy 2 keep it, on its own AVX2 and NEON kernels.

Windows and spectra

Hann, Hamming, Blackman, BlackmanHarris, Bartlett, FFTFreq, RFFTFreq, PSD and Spectrogram.

100%
test coverage, differentially checked against numpy
24/24
benchmark rows at or above numpy.fft and scipy.fft, on each of three hosts (v0.27.0)
24/24
benchmark rows faster than FFTW on Neoverse-N1 (within 5% or faster: 18/24 on Zen 3, 15/24 on Cascade Lake, where every 2-D row is faster), v0.27.0
CGO=0
no cgo, no FFTW, no native shims
Repositories

What is here.

fft

library

The library. Complex & real transforms of any length (FFT/IFFT/RFFT/IRFFT), N-D and 2-D (FFTN/FFT2), allocation-free plans (NewPlan, NewPlanN, NewRealPlan2), numpy's n/norm/axes, HFFT, FFTShift, the DCT and DST of types Iโ€“IV, single precision for all of it (FFT32, FFTN32, DCT32โ€ฆ, with its own SIMD kernels), frequency-bin helpers, windows, and spectral helpers (PSD/Spectrogram). A mixed-radix Stockham engine, Rader and Bluestein for the other lengths, AVX2 and AVX-512 pass kernels on amd64 and NEON on arm64, chosen at run time and bit-identical to the Go code.

docs

site

The documentation site (Hugo + hugo-theme-relearn): the API, the phased roadmap, and benchmarks against FFTW, numpy/scipy (pocketfft) and gonum. Source โ†’

brand

assets

Logos and icons for the organization, in SVG / PNG / JPG / ICO / ICNS across colour, white and black variants.

The cgo-free FFT the Go and Ruby ecosystems lacked.

No cgo, no FFTW. Pure Go on all six 64-bit targets, with AVX2 and AVX-512 kernels on amd64 and NEON kernels on arm64, all bit-identical to the Go code. Faster than FFTW on 24 of 24 rows on arm64; within 5% of it or faster on 18 of 24 on AMD (faster on 17) and on 15 of 24 on Intel (faster on 14, every 2-D row among them); behind it on complex 256 and 1,024 on amd64, and on Intel on composites and at 65,536 points; and at or above numpy and scipy at every size measured on all three hosts โ€” the numbers are on the performance page.

Read the source on GitHub โ†’