Simple radix2 fft code in c++
  • C++ 85.9%
  • CMake 7.1%
  • Python 7%
Find a file
thetwom 24cf3aa764 - New invariant type "Accumulate".
- Allow rfft with same size for in and out (in this case the
   last frequency real part is stored in the first frequency imag part)
- Fixes for debug mode.
- Remove "const" from some class attributes to make it copyable.
2026-05-03 20:57:01 +02:00
benchmarks - Move computation of scaling factor from FFT core to actual implementations. 2026-04-22 20:24:42 +02:00
include - New invariant type "Accumulate". 2026-05-03 20:57:01 +02:00
pytests - Adapt python API to latest changes. 2026-04-22 23:23:12 +02:00
src - Adapt python API to latest changes. 2026-04-22 23:23:12 +02:00
tests - New invariant type "Accumulate". 2026-05-03 20:57:01 +02:00
.gitignore Mostly working fft. 2026-03-30 22:55:28 +02:00
CMakeLists.txt - Adapt python API to latest changes. 2026-04-22 23:23:12 +02:00
LICENSE.md Add license and readme. 2026-04-05 20:47:43 +02:00
README.md - Adapt python API to latest changes. 2026-04-22 23:23:12 +02:00

Simple FFT Radix 2 code

Simple FFT code, just for input sizes which are a power of 2. Nothing really special about it.

Performance

In my very simple measurements, performance is similar to e.g. kissfft, sometimes worse sometimes better, but in the range of +-20%.

There are also python bindings, mainly used for testing. Compared to numpy, performance is ~30% worse, but in numpy you do not have to create a class first. So there are not really good reasons to use the python bindings.

Compilation

The c++-code are header-only and contained in a single file, so the easiest way is to just copy the include/r2fft.h-header over.

Besides, you can use the cmake. Use the target r2fft::r2fftx if you want to compile against the library. Mind the x at the end, which I used to avoid clashes with the python bindings.

If you have enabled python, the bindings will install into lib/python3.14/site-packages/r2fft.cpython-xxx-x86_64-linux-gnu.so inside the install path. The python-bindings use nanobind as binding library. cmake will download this directly.

Tests use kissfft as a reference and googletest. Both are downloaded by cmake if enabled.

There are also some benchmarks using googlebench. If enabled cmake, will download the library and compile it.

Usage

In c++, this can be used as follows:

// import
#include "r2fft.h"

// create the fft object for complex transforms
// - the template-type is the underlying scalar, so don't use `complex` here.
// - n is are the number of values to be treated and must be a power of 2.
r2fft::CFFT<double> cfft(n);

// run the fft, for complex input:
cfft.fft(input, output);

// same for inverse fft:
cfft.ifft(input, output);

// similarly, create an fft object for real transforms
// - the template-type is the underlying scalar
// - n is are the number of values to be treated and must be a power of 2.
r2fft::RFFT<double> rfft(n);

// run fft, input is a span of scalar numbers, output is 
//  a span of complex numbers, size of output is n / 2 + 1.
rfft.fft(input, output);

// and inverse fft, here input are n / 2 + 1 complex numbers, 
//  and output are n scalar numbers.
rfft.ifft(input, output);

You can also query the frequencies:

auto f = cfft.freq(i, dt);  // for getting a single frequency of the complex fft
auto f = rfft.freq(i, dt);  // for getting a single frequency of the real fft

cfft.freqs(freqs, dt);  // for getting all frequencies of the complex fft
rfft.freqs(freqs, dt);  // for getting all frequencies of the real fft

Or simply get the frequency resolution:

auto df = cfft.df(dt); // complex fft
auto df = rfft.df(dt); // real fft

The python api is similar:

import r2fft

# complex
cfft = r2fft.CFFT(n)
freqdom = cfft.fft(timedom) # complex fft
timedom = cfft.ifft(freqdom) # complex inverse fft
freqs = cfft.freqs(dt) # frequencies of complex fft

# real
rfft = r2fft.RFFT(n)
freqdom = rfft.fft(timedom) # real fft
timedom = rfft.ifft(freqdom) # real inverse fft
freqs = rfft.freqs(dt) # frequencies of real fft

Why does this project exist?

Mainly since I needed such code for deeper integration into other projects.

License

It is not really worth having a license here, since there is nothing special about this project. To still name a license, the Zero-Clause BSD license is used, mainly meaning you can copy the files over, without even mentioning this project, but no warranties.