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

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

Answers (2)

As shown in the example, the HDL FFT needs into the separated out into a separte design file. The example puts the HDL-optimized FFT into the design, while putting the for-loop into the "testbench". The way to think about this is that the HDL FFT design will do the 128-point FFT operation, while the rest of teh design needs to pass in 16 values in every clock.

11 Comments

Thank you for your answer.
Should I think of HDL coder as limited to only single clock cycle designs?
Do you know if there is a way to programmatically call the HDL-optimized FFT for different clock cycles?
I have found some examples that talk about using Simulink and inserting generated HDL code into a black box. But I was hoping there would be a programmatic way to call an existing HDL design in HDL coder.
Is there a programmatic version of Simulink?
I am not sure what single clock cycle designs means.
Just like other HDL code, you can call the HDL Optimized FFT whenever you want - there is a valid input that can go high and low every clock cycle.
Thank you for responding.
I guess what I am stuck on is how to call the HDL Optimized FFT in a larger HDL coder project.
I have generated the FFT with HDL Coder and now have HDL source files.
Is it possible to take this generated FFT and insert it into a larger design using only an HDL coder project?
Or do I have to create a Simulink project and add a submodule?
The goal is to be able to convert existing projects that have FFTs in them using an HDL coder project. But I am unsure if I can call existing HDL code and generate a larger project with it. I have tried looking around for answers but they are not clear to me.
Thanks for clarifying the question.
Yes, this FFT is callable as needed from a larger HDL Coder project. To do that, you can just use a subsystem that has the FFT logic in it. You can also use model reference for this behavior.
In HDL, you can instantiate the highest level entity from the HDL files as many times you need.
If you need FFTs that need a change in parameters or input sizes, you will have to use a different HDL Optimized FFT blocks for each case that you need. One exception to this is a variable-size FFT which can be implementated using the largest FFT as shown in this example.
Thank you Bharath!
Just to clarify. If I use model reference, I can programmatically create a subsystem, put the FFT that I generated with HDL coder in that subsystem.
Then call that subsystem from a matlab script and code generate the entire 'system'/script which includes calls to that subsystem(the FFT)?
You can just put the FFT into a subsystem with other logic. This logic for example, could feed data from different sources and figure out which one to feed into the FFT subsystem.
I still feel that I am missing something you are asking - not sure why you asked about a MATLAB script.
Hi.. I too have similar issue. Can we generate HDL code when the function(.m) contains more than one system objects, like, dsp. HDLFFT and dsp. HDLIFFT in the same function. Please reply, I am really unable to proceed further.
Yes, you can generate HDL code from such a function. If you send me a sample of your current code, I can try to see what the issue is.
Please remember to have a testbench MATLAB file that runs the design (in a separate MATLAB file) which contains the FFT & IFFT.
Bharath
Please check attachments: for the sample code of 'function' and 'test bench'
Purpose of this code is as follows. I am giving input : yIn , on which FFT applied and on this result(yOut) i applied IFFT to get back the given input yIn which is in YOut. But couldnt generate HDL. Please help.
I had to change your testbench and main function a bit to feed the fft output to the ifft. Please take a look and let me know if what I did makes sense. With these changes, I am able to generate HDL code.
If you happen to have Simulink, you can model this as an input -> fft block -> ifft block -> output.
Thank you Bharath.I checked your code,HDL code generated and it worked. I have simulink. I know its easy there to place blocks but i am struggling to generate hdl from simulink. So used matlab. If you have any example related to fft or anything in simulink to generate HDL, please send. It will be very helpful.

Sign in to comment.

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

i have matlab 2020a , how to open this .slx which is in 2020b
Hi bharath!
  1. I tried to generate HDL code for the shared " fft_ifft_model_20a.slx " model. But got the following error which I couldnt resolve. Error message is attached.
  2. Coming to algorithm (model attached), for which I am trying to generate HDL code involves the following steps: Input is a vector (8x1, in this example).
  3. On which my algorithm acts this way: To the input I multply another vector 'e' . Which is implemented in matlab user defined function block.
  4. This vector ouput is now fed to FFT block. The FFT output of size 8 (this example), is fed to subsystem matlab function. Where I perform division operation with unity matrix vector. This output is now fed to IFFT block
  5. IFFT block output vector is given to subsystem matlab function1. Which gives 'ans1'.
So I need a VHDL code which generates 'ans1' vector from the input vector. This is what I am trying. Is it feasible in HDL coder to generate HDL code for the same and to dump in the relevant fpga board. Kindly give your valuable feedaback and support.
Thankyou
Hi Bharath!
Can you give any updates about my question.
A couple of thoughts on your model:
  1. 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.
  2. 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.
  3. 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.
  4. All code that is being used to analyze the output is best done in MATLAB - for example, your comparison between input and IFFT output.
  5. Please run the following on your model to get the right settings for HDL code generation: hdlsetup('<modelname>')

Sign in to comment.

Products

Release

R2019b

Asked:

on 5 Mar 2020

Community Treasure Hunt

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

Start Hunting!