nk 1.0.0
C++ Numerical Computing Runtime
Loading...
Searching...
No Matches
fft_radix2.hpp
1#pragma once
2//
3// Scalar iterative radix-2 Cooley-Tukey FFT butterfly (in-place).
4//
5// This is an ops-layer numerical kernel: it operates on a raw contiguous
6// Complex buffer + a precomputed twiddle table, with no dependency on the
7// engine, the filesystem, or any toolbox. It was previously defined in
8// toolboxes/signal/src/dsp_helpers.hpp, which made the ops-layer portable
9// FFT (ops/src/fft_portable.cpp) reach UP into the signal toolbox (a layering
10// inversion that only surfaced on SIMD-off builds, where fft_portable.cpp is
11// compiled). Hosting the butterfly here keeps ops self-contained; signal's
12// dsp_helpers.hpp now includes this header for its convenience overloads.
13//
14#include <nk/value/value.hpp> // nk::Complex
15
16#include <algorithm> // std::swap
17#include <complex>
18#include <cstddef>
19
20namespace nk {
21
22// Iterative radix-2 Cooley-Tukey FFT (in-place). N must be a power of 2.
23// Takes a precomputed twiddle table W of length N/2 (see fillFftTwiddles in
24// signal's dsp_helpers.hpp for how to build one). Decoupled from any container
25// type so callers can back the buffer with std::vector, std::pmr::vector, a
26// stack array, or any other contiguous Complex storage.
27inline void fftRadix2(Complex *buf, std::size_t N, const Complex *W)
28{
29 if (N <= 1)
30 return;
31
32 // Bit-reversal permutation
33 for (std::size_t i = 1, j = 0; i < N; ++i) {
34 std::size_t bit = N >> 1;
35 for (; j & bit; bit >>= 1)
36 j ^= bit;
37 j ^= bit;
38 if (i < j)
39 std::swap(buf[i], buf[j]);
40 }
41
42 // Butterfly stages — look up twiddles from the precomputed table.
43 for (std::size_t len = 2; len <= N; len <<= 1) {
44 const std::size_t step = N / len;
45 for (std::size_t i = 0; i < N; i += len) {
46 for (std::size_t j = 0; j < len / 2; ++j) {
47 const Complex w = W[j * step];
48 const Complex u = buf[i + j];
49 const Complex v = buf[i + j + len / 2] * w;
50 buf[i + j] = u + v;
51 buf[i + j + len / 2] = u - v;
52 }
53 }
54 }
55}
56
57} // namespace nk