This example shows how to use HDL Coder™ to check, generate, and verify HDL code for a 512-point complex serial FFT block built using the MATLAB Function blocks and Simulink blocks.
This model implements a simple OFDM transmitter and receiver. The OFDM receiver part contains a 512-point Radix-2 complex FFT to convert signal back to the frequency domain. There are two FFT implementations in this model:
The Behavioral FFT block is the complex FFT block in DSP System Toolbox™ library. It calculates a 512-point vector input each sample and works at a sample rate of 512.
The FFT_512Pt_EML_Serial block implements a serialized, streaming I/O FFT block using the MATLAB Function blocks and Simulink blocks and is suitable for hardware. This implementation accepts streaming complex input data and generates streaming complex results continuously after the initial pipelining latency.
The results of the two FFT implementations are shown to be equal after matching the initial pipelining latency.
Communications System Toolbox
DSP System Toolbox
% To open this model, run the following commands: modelname = 'hdlcoder_ofdm_fft_eml'; open_system(modelname);
Cooley-Tukey Radix-2 Serialized FFT
Complex input, complex output
Streaming input, streaming output
Decimation in time
Bit width: 12 bits
Initial pipelining latency: 1298 clock cycles
enable -> enable signal indicates the first valid input data
data_in -> streaming input data
data_en -> enable signal indicates the first valid output data
data_out -> streaming output data
index_out -> index of output data
The serialize block generates the streaming input data for the FFT block. The original 512-point vector input is converted to one data point per sample by the Unbuffer block.
In the deserialize block, the streaming output of the serial FFT block is converted back to a 512-element vector at the sample rate of 512 by the Buffer block.
This FFT block implements the Decimation-in-Time FFT algorithm which requires bit reverse-ordered input data. So the natural-ordered input data will pass through the stage Start_BitReverse in the beginning.
The serial FFT block is composed of log2(512)= 9 stages of radix-2 butterfly units. These FFT stages are pipelined and connected in tandem.
The following picture shows a typical 8-point FFT with 3 (log2(8)) stages. Each stage uses 4 (8/2) butterfly units. A serial FFT implemented in this model uses only one butterfly resource for each stage of implementation.
Each radix-2 FFT stage includes one radix-2 butterfly computing unit, memory blocks to cache the streaming data, a ROM to store the FFT twiddle factors, and control logic implemented in MATLAB Function blocks. The memory size of each stage equals the Stage Number.
The radix-2 FFT butterfly algorithm is implemented in MATLAB file hdlcoder_serial_fft_butterfly.m on the MATLAB path. All the Butterfly_FFT2_Computing_Unit blocks call this function.
The Butterfly_FFT2_Computing_Unit block uses a right shift to scale down the result data after every FFT stage to avoid overflow. In this model the Scale variable is set to 1 to turn off the scaling.
function [fft2_x, fft2_y] = fcn(fft2_u, fft2_v, fft2_twiddle) % FFT2 Computing Unit
% Scale down number for this stage. Need to be power of 2. Scale = 1;
% Call function in MATLAB file hdlcoder_serial_fft_butterfly_scale.m on path [x, y] = hdlcoder_serial_fft_butterfly(fft2_u, fft2_v, fft2_twiddle);
% scaling down by 2 for each FFT2 stage. fft2_x = bitsra(x, log2(Scale)); fft2_y = bitsra(y, log2(Scale));
function [x, y] = hdlcoder_serial_fft_butterfly(u, v, twiddle) % FFT2 butterfly block % This function is used in hdlcoder_ofdm_fft_eml example model. %#codegen
nt = numerictype(u); fm = fimath(u);
% multiply twiddle and butterfly. twv = fi(v * twiddle, nt, fm);
x = fi(u + twv, nt, fm); y = fi(u - twv, nt, fm);
checkhdl( [modelname '/FFT_512Pt_EML_Serial']); makehdl( [modelname '/FFT_512Pt_EML_Serial']); makehdltb([modelname '/FFT_512Pt_EML_Serial']);
This concludes the OFDM Receiver with 512-Point Serial FFT example.