A high-performance, in-place FFT library written in Odin, optimized for SDR (Software Defined Radio) applications and real-time signal processing.
- In-place radix-2 DIT FFT - Memory efficient Cooley-Tukey decimation-in-time algorithm
- Optimized performance - Pre-computed per-stage twiddle factors and unrolled early stages
- SDR-friendly utilities - Built-in support for CU8 IQ data conversion and spectrum analysis
- Windowing support - Integrated Hann window with efficient application
- Spectrum analysis tools - Magnitude, power (dBFS), peak detection, and FFT shift functions
- Zero dependencies - Uses only Odin's core math library
Add to your project:
git submodule add https://github.com/grpllyer/offt.git vendor/fftoimport fft "vendor/ffto"
// Create an FFT plan for 1024 samples at 2.4 MHz sample rate
plan := fft.fft_make_plan(1024, 2_400_000.0)
defer fft.fft_destroy_plan(&plan)
// Prepare your data (example with SDR IQ bytes)
iq_bytes := []u8{...} // Your CU8 IQ data
samples := fft.cu8_interleaved_to_cf32(iq_bytes)
// Apply windowing to reduce spectral leakage
fft.fft_apply_hann(plan.window, samples)
// Compute FFT in-place
fft.fft_inplace(&plan, samples)
// Analyze the spectrum
power_db := fft.fft_power_dbfs(samples)
peak_bin, peak_freq := fft.fft_peak_bin(power_db, plan.sample_rate)
// Center the spectrum for display (-Fs/2 to +Fs/2)
fft.fft_shift_inplace(samples)Creates an FFT plan for size n (must be power of 2). Pre-computes twiddle factors and Hann window.
Cleans up allocated memory for the FFT plan.
Performs in-place FFT using optimized radix-2 algorithm with unrolled early stages.
Applies Hann window to reduce spectral leakage. Use before FFT computation.
Computes magnitude spectrum |X[k]| from frequency domain data.
Converts to power spectrum in dBFS (decibels relative to full scale).
Finds the bin index and frequency of the peak in the positive frequency range [0..N/2).
Shifts zero-frequency component to center for spectrum display (-Fs/2 to +Fs/2).
Converts interleaved CU8 IQ samples (common SDR format) to Complex32 in range [-1,1).
Maps FFT bin index to frequency in Hz after FFT shift.
The library includes several optimizations for real-time performance:
- Per-stage twiddle pre-computation - Eliminates trigonometric calculations during FFT
- Early stage unrolling - Stages 0 and 1 are unrolled for better performance
- Inlined complex arithmetic - Reduces function call overhead in inner loops
- Optional bounds checking disable - Use
#no_bounds_checkfor maximum speed
Current implementation uses iterative in-place radix-2 Cooley-Tukey DIT. The code includes extensive comments about potential future optimizations:
- Split-radix FFT for ~20% fewer operations
- Mixed radix (radix-4/8) for better vectorization
- SIMD optimizations for modern CPUs
- Real-input FFT specialization
- Cache-friendly memory access patterns
- FFT Plan: O(N) for twiddle factors + O(N) for window = ~2N complex numbers
- Computation: In-place, no additional allocation during FFT
- Utilities: Output arrays allocated as needed (caller responsibility to free)
- Odin compiler
- Power-of-2 FFT sizes only
- Input data as
[]Complex32or convertible formats
// Analyze a 1 kHz sine wave
plan := fft.fft_make_plan(512, 48000.0)
defer fft.fft_destroy_plan(&plan)
// Generate test signal (1 kHz sine wave)
samples := make([]fft.Complex32, 512)
for i in 0..<512 {
t := f32(i) / 48000.0
samples[i] = fft.Complex32{math.sin(2*math.PI*1000*t), 0}
}
fft.fft_apply_hann(plan.window, samples)
fft.fft_inplace(&plan, samples)
power := fft.fft_power_dbfs(samples)
peak_bin, peak_freq := fft.fft_peak_bin(power, plan.sample_rate)// Process RTL-SDR data for waterfall display
plan := fft.fft_make_plan(2048, 2_400_000.0)
defer fft.fft_destroy_plan(&plan)
// Convert raw SDR samples
samples := fft.cu8_interleaved_to_cf32(sdr_iq_data)
fft.fft_apply_hann(plan.window, samples)
fft.fft_inplace(&plan, samples)
fft.fft_shift_inplace(samples) // Center for display
// samples now contains centered spectrum ready for waterfall[Specify your license here]
[Add contribution guidelines if desired]