# How do I call an FFT multiple times with HDL Coder: System Object Methods in Loops?

9 views (last 30 days)

Show older comments

Hello!

I want to create a 128 point FFT and call it multiple times in an HDL project.

But first I wanted to create a 128 point FFT, and found that the dsp.HDLFFT system object it needs to be called iteratively.

I tried following this example: https://www.mathworks.com/help/dsp/ref/dsp.hdlfft-system-object.html

Create Vector-Input FFT for HDL Generation:

In the example, I can create the HDL code for the FFT that uses the dsp.HDLFFT system object if...

ONLY the object blocks instantiation and call are done once.

However, this design needs to be run multiple times as the dsp.HDLFFT input is maxed to 64 points.

This is because the dsp.HDLFFT is an iterative FFT.

I tried to move the loop that loops through all the 128 input points from the test script into code generation.

However, I found that system objects [both instantiations and method calls] (those that come from dsp.HDLFFT) can not be put within a loop.

Below is the code that generates this error: "System object methods, in file 'fft_function_fixpt' line 0, col 0, cannot be called inside 'for' loops, 'while' loops and switch statements in HDL code generation."

Question #1: This then leads to the question, how do I call an FFT multiple times in an HDL coder design if the system object method can not be put in a loop.

Wouldn't it make sense that you could instantiate an FFT on an FPGA and then call it multiple times? I don't want to instantiate all the FFTs that I need to do upfront.

Question #2: I also thought, could synthesize the dsp system call in a different HDL coder project. Then call this sub-module multiple times in for loop?

Is there an easy way to do this?

***fft_function_test.m:

%% Create Vector-Input FFT for HDL Generation

%%

% Create specifications and input signal. This example uses a

% 128-point FFT and computes the transform over 16 samples at a time.

N = 128;

V = 16;

Fs = 40;

t = (0:N-1)'/Fs;

x = sin(2*pi*15*t) + 0.75*cos(2*pi*10*t);

y = x + .25*randn(size(x));

y_fixed = sfi(y,32,24);

y_vect = zeros(128,1);

y_vect = reshape(y_fixed,N,1);

%%

% Write a function that creates and calls the System object(TM). The

% function does not need to know the vector size. The

% object saves the size of the input signal the first time you call it.

%

% *Note:* This object syntax runs only in R2016b or later. If you are using an

% earlier release, replace each call of an object with the equivalent |step|

% syntax. For example, replace |myObject(x)| with |step(myObject,x)|.

%

% <include>HDLFFT128V16.m</include>

%

[Yf_flat,loop_count] = fft_function(y_vect);

Yf_flat = reshape(Yf_flat,N,[]);

%%

% Plot the frequency channel data from the FFT. The FFT output is in

% bit-reversed order. Reorder it before plotting.

Yr = bitrevorder(Yf_flat);

plot(Fs/2*linspace(0,1,N/2),2*abs(Yr(1:N/2)/N))

title('Single-Sided Amplitude Spectrum of Noisy Signal y(t)')

xlabel('Frequency (Hz)')

ylabel('Output of FFT (f)')

***fft_function.m:

function [output,loopCount] = fft_function(y_fixed)

V = 16;

N = 128;

y_vect = reshape(y_fixed,V,N/V);

%%

% Compute the FFT by passing 16-element vectors to the object. Use the

% |getLatency| function to find out when the first output data sample will be

% ready. Then, add the frame length to determine how many times to call the

% object. Because the object variable is inside the function, use a second

% object to call |getLatency|. Use the loop counter to flip |validIn|

% to |false| after _N_ input samples.

tempfft = dsp.HDLFFT;

%loopCount = getLatency(tempfft,N,V)+N/V;

loopCount = 68;

Yf = complex(zeros(V,loopCount));

inin = complex(zeros(V,1));

validOut = false(V,loopCount);

persistent fft128v16;

if isempty(fft128v16)

fft128v16 = dsp.HDLFFT('FFTLength',128);

end

for loop = 1:1:loopCount

if ( mod(loop,N/V) == 0 )

i = N/V;

else

i = mod(loop,N/V);

end

inin = complex(y_vect(:,i));

logical_test = (loop<=N/V);

[Yf(:,loop),validOut(loop)] = fft128v16(inin(1:16),logical_test);

%[Yf(:,loop),validOut(loop)] = HDLFFT128V16(inin(1:16),logical_test);

end

%%

% Discard invalid output samples.

C = complex(zeros(16,8));

%C = Yf(:,validOut==1);

C = Yf(:,1+end-8:end);

Yf=Yf(:);

output = complex(zeros(128,1));

output(1:128) = C(:);

end

##### 0 Comments

### Answers (2)

Bharath Venkataraman
on 9 Mar 2020

##### 11 Comments

satish kumar
on 12 Feb 2021

Bharath Venkataraman
on 12 Feb 2021

Here is an equivalent Simulink model.

Data comes in through the Signal To Workspace blocks whose input can come in from any workspace variable. The FFT and IFFT blocks are connected back to back. The input and output can be seen in the logic analyzer, and are exported to the workspace in the variable out (see out.logsout for the data logged).

Hope this model helps.

Bharath

##### 5 Comments

Bharath Venkataraman
on 23 Feb 2021

A couple of thoughts on your model:

- While the FFT and IFFT are 8-point, you should be feeding in one value in at a time. So your MATLAB Function should be written to allow processing of one input at a time.
- What is the purpose of the MATLAB Function block after the FFT? If possible, I suggest a simpler logic of say, dividing by a fixed power of 2 using the Shift Arithmetic or Bit Shift blocks.
- All the design that needs to generate HDL should be in the Subsystem. Please generate HDL code for the Subsystem, not for the entire model. You can right click on the Subsystem and generate HDL, or specify the subsystem during HDL code generation.
- All code that is being used to analyze the output is best done in MATLAB - for example, your comparison between input and IFFT output.
- Please run the following on your model to get the right settings for HDL code generation: hdlsetup('<modelname>')

### See Also

### Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!