cordic_fft / cordic_ifft
Radix-2 DIT FFT and IFFT for N=8. Twiddle factors computed in hardware via cordic_core rotation mode.
Implementation
FFT
Algorithm: In-place Radix-2 DIT. One butterfly per clock, sequential stages.
Twiddle generation: N/2 cordic_core instances launched in parallel on start. Each computes W_N^k = cos(2πk/N) − j·sin(2πk/N) by rotating x_init=K_SCALE, y_init=0, z=−2πk/N. All twiddles are ready before the first butterfly stage.
CORDIC rotation converges only for |z| < π/2. Angles outside this range are folded at elaboration time via localparam: if angle < −π/2, use angle + π and negate both outputs since cos(a+π) = −cos(a), sin(a+π) = −sin(a).
Fixed-point chain:
- Data: Q1.30 (
WIDTH=32,ANGLE_FRAC_BITS=30) - Twiddle:
x_out >> 16= Q1.14 (x_out = cos × 2^30→ shift givescos × 2^14) - Butterfly multiply:
Q1.30 × Q1.14 >> 14 = Q1.30 - Guard:
>> 1per stage against overflow - Output scale:
X[k] = DFT(x) / N
FSM:
S_WTTW— wait for allN/2twiddle coresS_BITREV— bit-reversal, one conditional swap per clockS_BF— butterfly, iteratesstage0..N_LOG2−1,bfcnt0..N/2−1S_DONE— pulsevalid, dropbusy
Latency (N=8, ITER=16): 19 cycles (twiddle) + 8 (bit-reversal) + 12 (3 stages × 4 butterflies) = ~39 cycles.
IFFT
Wrapper around cordic_fft using the identity:
IFFT(X) = conj( FFT( conj(X) ) ) / N
cordic_fft already divides by N. Conjugation is two wire negations — din_im negated on input, dout_im negated on output. No extra logic. Output scale: x[n] = IDFT(X) / N.
Interface
Both modules share the same interface:
cordic_fft #(.N_LOG2(3), .WIDTH(`CORDIC_WIDTH), .ITER(`CORDIC_ITER)) u (
.clk, .rst_n,
.load_en, .din_re, .din_im, .din_idx, // load before start
.start,
.busy, .valid,
.rd_idx, .dout_re, .dout_im // combinatorial readback
);
Load N samples via load_en/din_re/din_im/din_idx, pulse start, wait for valid, read via rd_idx.
Directed Tests
FFT — sim/fft_tb.v
Real-valued inputs. Reference = exact DFT / N.
| Test | Input | Expected |
|---|---|---|
| 1 | Impulse at n=0 | All bins = 1/N |
| 2 | DC (all ones) | X[0]=1, rest≈0 |
| 3 | cos(2π·1·n/N) | X[1]=X[7]=0.5, rest≈0 |
| 4 | cos(2π·2·n/N) | X[2]=X[6]=0.5, rest≈0 |
| Test | Max error |
|---|---|
| 1 | 0 |
| 2 | 9.2e-05 |
| 3 | 3.4e-05 |
| 4 | 3.1e-05 |
IFFT — sim/ifft_tb.v
Reference = exact IDFT / N.
| Test | Input X[k] | Expected x[n] |
|---|---|---|
| 1 | delta[k=0] | 1/N uniform |
| 2 | All ones | delta[n=0] |
| 3 | delta[k=1] + delta[k=7] | cos(2π·n/N) / 4 |
| 4 | Round-trip: cos → FFT → IFFT | x[n] / N |
| 5 | Round-trip: complex exp → FFT → IFFT | x[n] / N |
| Test | Max error |
|---|---|
| 1 | 0 |
| 2 | 9.2e-05 |
| 3 | 3.1e-05 |
| 4 | 1.1e-05 |
| 5 | 7.6e-06 |
Round-trip error (tests 4–5) is lower than single-pass — quantization errors partially cancel through conjugation symmetry.
Verification — FFT
Stress Tests
| Case | Max error | Mean error | SNR |
|---|---|---|---|
| impulse | 0.00e+00 | 0.00e+00 | ∞ dB |
| all_ones | 1.29e-04 | 3.92e-05 | 76.5 dB |
| all_zeros | 0.00e+00 | 0.00e+00 | ∞ dB |
| pure_tone | 3.62e-05 | 2.08e-05 | 80.8 dB |
| max_pos | 1.29e-04 | 3.92e-05 | 76.5 dB |
| max_neg | 1.29e-04 | 3.92e-05 | 76.5 dB |
| alternating | 1.29e-04 | 3.92e-05 | 76.5 dB |
| ramp | 4.32e-05 | 2.43e-05 | 78.6 dB |
Impulse and all-zeros are exact (zero error) as expected — no butterfly arithmetic is exercised for trivial spectra.
Monte-Carlo Results (200 tests, 1600 samples)
Max error : 0.000083
Mean error : 0.000021
RMS error : 0.000024
SNR mean/min/max : 78.79 / 74.27 / 84.46 dB
SFDR (random) : 1.11 dBc mean
SFDR (pure-tone) : 87.08 dBc avg across bins
Phase err mean/max: 0.0082 / 0.7267 deg
SNR ~79 dB is consistent with the theoretical limit for a 30-bit fractional CORDIC implementation. The SFDR of 87 dBc under pure-tone excitation is measured using the correct conjugate-pair metric for a real-input FFT — the symmetric bins (k, N-k) are treated as the fundamental, not as spurs. Phase error mean of 0.008° is negligible.
Per-Bin Mean Error
| Bin | Mean Error |
|---|---|
| 0 | 2.4e-05 |
| 1 | 1.8e-05 |
| 2 | 2.3e-05 |
| 3 | 1.7e-05 |
| 4 | 2.4e-05 |
| 5 | 1.9e-05 |
| 6 | 2.3e-05 |
| 7 | 1.6e-05 |
Even-indexed bins carry slightly higher error than odd-indexed bins — a known butterfly symmetry pattern in Cooley-Tukey at small N. The variation is minor (~30%) and within expected fixed-point rounding behaviour.
Error Distribution

Errors are tightly concentrated near zero with a long tail — typical of fixed-point CORDIC quantisation noise. The distribution is consistent across all 200 trials.
SNR Distribution

SNR ranges from 74 to 85 dB across random inputs, with mean ~79 dB. Variation is driven by input-dependent signal power, not by implementation instability.
SFDR

Left panel shows SFDR distribution for random multi-tone inputs — low values here are expected as random inputs excite all bins simultaneously and there is no dominant fundamental. Right panel shows the meaningful measurement: SFDR for a single cosine tone at each bin, ~87 dBc uniformly, demonstrating clean twiddle computation with minimal spurious content.
Per-Bin Error

Phase Error Distribution

Phase error mean of 0.008° across all active bins. Occasional outliers up to ~1° occur when the reference bin has small magnitude (denominator near zero in angle computation) — not representative of typical operation.
Error vs Input Amplitude

Error is largely independent of input amplitude, confirming that the fixed-point noise floor is dominated by twiddle quantisation rather than input-level scaling.
Stress Test Max Errors

CORDIC Iteration Sweep

SNR converges monotonically with iteration count. At 4 iterations the design is already usable at ~23 dB; 12 iterations gives ~67 dB; 16 iterations reaches the fixed-point noise floor at ~79 dB. Further iterations yield no improvement as angle quantisation (30-bit) becomes the limiting factor.
| Iterations | Mean SNR |
|---|---|
| 4 | 23.5 dB |
| 8 | 40.3 dB |
| 12 | 67.4 dB |
| 16 | 79.2 dB |
Verification — IFFT
Stress Tests
| Case | Max error | Mean error | SNR |
|---|---|---|---|
| dc_only | 0.00e+00 | 0.00e+00 | ∞ dB |
| single_tone | 4.32e-05 | 2.77e-05 | 75.6 dB |
| all_ones_spec | 1.29e-04 | 3.92e-05 | 76.5 dB |
| all_zeros_spec | 0.00e+00 | 0.00e+00 | ∞ dB |
| max_pos | 1.29e-04 | 3.92e-05 | 76.5 dB |
| max_neg | 1.29e-04 | 3.92e-05 | 76.5 dB |
| alternating | 1.29e-04 | 3.92e-05 | 76.5 dB |
| random_phase | 7.34e-05 | 2.58e-05 | 80.8 dB |
DC-only and all-zeros inputs are exact. The IFFT is implemented as a thin conjugation wrapper over the FFT core, so its error floor matches the FFT directly.
Monte-Carlo Results (200 tests, 1600 samples)
Max error : 0.000104
Mean error : 0.000031
RMS error : 0.000035
SNR mean/min/max : 78.40 / 75.43 / 82.61 dB
Phase err mean/max: 0.0059 / 0.1514 deg
IFFT SNR (~78 dB) matches the FFT closely — expected since the IFFT adds no arithmetic beyond two wire negations. The slightly higher mean error vs FFT (~31e-06 vs ~21e-06) is due to the IFFT accepting complex spectrum inputs, which exercise more of the butterfly datapath.
Roundtrip Test (FFT → IFFT, 50 trials)
Roundtrip max error : 0.000025
Roundtrip mean error : 0.000007
Roundtrip SNR mean : 78.26 dB
Roundtrip SNR min : 75.54 dB
Real inputs are passed through hardware FFT, then the spectrum is fed directly into hardware IFFT. The recovered signal achieves 78 dB SNR end-to-end. Roundtrip error (7e-06 mean) is lower than single-pass IFFT error (31e-06 mean) — CORDIC angle quantisation errors partially cancel through the conjugation symmetry of the roundtrip.
Per-Bin Mean Error
| Sample | Mean Error |
|---|---|
| 0 | 3.9e-05 |
| 1 | 2.5e-05 |
| 2 | 3.4e-05 |
| 3 | 2.3e-05 |
| 4 | 4.0e-05 |
| 5 | 2.6e-05 |
| 6 | 3.3e-05 |
| 7 | 2.4e-05 |
Same even/odd alternating pattern as the FFT, consistent with shared butterfly structure.
Error Distribution

SNR Distribution

Roundtrip Error and SNR

Left panel shows roundtrip absolute error distribution — tightly concentrated below 2e-05. Right panel shows roundtrip SNR, mean 78 dB, confirming that FFT + IFFT in series introduces no significant error accumulation beyond the single-pass floor.
Per-Bin Error

Phase Error Distribution

IFFT phase error (mean 0.006°, max 0.15°) is tighter than FFT (max 0.73°). The conjugate-symmetry path through the IFFT wrapper suppresses phase error buildup.
Error vs Input Amplitude

Stress Test Max Errors

CORDIC Iteration Sweep

IFFT convergence curve is nearly identical to the FFT — as expected for a wrapper implementation sharing the same CORDIC core.
| Iterations | Mean SNR |
|---|---|
| 4 | 23.2 dB |
| 8 | 40.4 dB |
| 12 | 67.4 dB |
| 16 | 78.5 dB |
Summary
| Metric | FFT | IFFT |
|---|---|---|
| SNR mean | 78.8 dB | 78.4 dB |
| SNR min | 74.3 dB | 75.4 dB |
| Max error | 8.3e-05 | 1.0e-04 |
| Mean error | 2.1e-05 | 3.1e-05 |
| RMS error | 2.4e-05 | 3.5e-05 |
| SFDR (pure-tone) | 87.1 dBc | — (complex output) |
| Phase err mean | 0.008° | 0.006° |
| Roundtrip SNR | — | 78.3 dB |
| Iterations to floor | 16 | 16 |