• 0
Sign in to follow this  
Followers 0
Yannick

How to easily implement a basic low-pass filter using FIR Compiler (on Nexys 4 DDR)

Question

Hello,

I'm currently trying to implement a simple low-pass filter using the FIR Compiler available in the IP catalog. My design is very basic, I've generated a sine wave using the DDS IP :

* Configuration Options : Phase generator and SIN COS LUT

* System clock : 100 MHz

* Mode of operation : Standard

* Output frequency : 1.2 MHz

* Output width : 8 Bits

 

I want now to apply a low-pass filter and to see how is it going in simulation, using Analog waveform style. To generate the coefficients, I am using Matlab and the filterDesigner. Here are the specifications : 

 

* Lowpass, FIR (Equiripple)

* Fs : 2.7 MHz

* Fpass : 1.3 MHz

* Fstop : 1.35 MHz

* Apass : 1 dB

* Astop :40 dB

 

Then, I generate a .COE file which I use in the FIR compiler. I specify these options : 

 

* Filter type : Single rate 

* Input sampling frequency : 2.7 MHz

* Clock frequency : 100 MHz

* Coefficient type : signed, on 16 bits

* Coefficient structure : Inferred

* Input data type : Signed, on 8 bits

* Output rounding mode : Full precision

 

The screenshot shows what I obtain and it seems that it is not working very well. Does anybody can explain me what is going on ? Do I make some mistakes when I am setting up the filter ?

Thank you very much for your help ! 

 

 




 

image.png

Share this post


Link to post
Share on other sites

14 answers to this question

  • 0

@Yannick,

Looks like a fun problem!

Let's start at the top, are you running the output at a lower speed than the input?  Check your CE lines along the way, and make certain you are using them properly.  It looks like you are dropping samples (and logic) along the way and then trying to up the sample rate towards the end.

Dan

Share this post


Link to post
Share on other sites
  • 0

So, when doing signal processing, you very often need to operate on data streams that are somewhat slower than your system clock.  To deal with this, you pass along with the data a signal that will be true for one system clock once for every sample.  All of the signal processing logic then is required to be gated by this CE signal.

At least, I've always called that function a "CE" or circuit enable signal.

Looking over the spec for the FIR compiler, Xilinx doesn't use any signals labeled as CE.  Instead, the "CE" signal is generated by the logical AND between the READY output signal and your VALID input.  Your picture above would suggest you don't have those lines set up right.  Xilinx's choice of wires are a touch more difficult to deal with than a simple CE signal, but they are more capable.  Basically, you need to raise a "VALID" (I think they call this s_axis_data_tvalid) signal whenever you have valid data going into their component.  That VALID line then needs to stay high until there has been one clock with both VALID and READY (s_axis_data_tready) high at the same time.  You'll also need to set an m_axis_data_tready signal.  Looks like you should be able to set m_axis_data_tready to a constant one, but then you'll need to pay attention to m_axis_data_tvalid to know when data is present to send forward one step further in your processing flow.

Dan

Share this post


Link to post
Share on other sites
  • 0

Okay, I think I have understood what you mean. In my design, I have wired the valid signal output of the DDS in the valid signal input of the FIR. It should assert correctly the valid signal in entry of the FIR, no ?

 

 

image.png

Share this post


Link to post
Share on other sites
  • 0

@Yannick,

Yeah, ok, that's a good start.

Any particular reason why you are tying m_axis_data_tready to zero on the DDS compiler?  I would've thought you'd need to tie that one to one.

Not sure what you are doing with s_axis_data_tready, though.  That signal is designed to go back to the source, which in this case would mean that it is supposed to connected to the m_axis_data_tready line of the DDS compiler.  (Yeah, I know I just said you needed to tie it to one --- it's designed to be tied to the m_axis_data_tready line, though.)

You also haven't shown me what you are doing with your filter's m_axis_data_tready signal.  Are you setting that one to a constant one?  Or did you configure the FIR compiler so it doesn't have a m_axis_data_tready signal?  (This would be valid as well.)

I'm also not finding how you are dealing with a 2.7MHz sample rate.  If ACLK is at 100MHz, then how are you dropping to 2.7MHz?  I would've expected a strobe (logical 1 for one sys clock cycle) at 2.7MHz feeding the ACLKEN signal of the DDS to handle this, but ... I'm not seeing that in your example above.

Dan

Share this post


Link to post
Share on other sites
  • 0

Posted (edited)

@D@n

 

So, I tried your suggestions and here is my updated design. I've feed the ACLKEN  of the DDS with a clock divider cadenced at 2.7 MHZ and that is what I can visualise in simulation : 

 

 

design.png

simulation.png

Edited by Yannick

Share this post


Link to post
Share on other sites
  • 0

@Yannick,

Hmm ... okay, that's closer, but ... let's try connecting that ACLKEN to both the DDS and the FIR compiler and see if that doesn't get you any closer,

Dan

Share this post


Link to post
Share on other sites
  • 0

Posted (edited)

@D@n

That is what I tried. On the top picture, the output frequency of the DDS (FIR's input) is 1.2 MHz, on the second, 1.35 MHz. I kept the filter's settings mentionned previously. So, normally, in the second picture, the signal should not be the same as on the first picture, right ?

 

 

sim_2.png

sim_1.png

Edited by Yannick

Share this post


Link to post
Share on other sites
  • 0

@Yannick,

Ok ... I read your question, but ... I'm not sure I understand both the question and what you are doing.  Can you please back up for me a touch?

Dan

Share this post


Link to post
Share on other sites
  • 0

Yannic,

Your post says that you want to "easily" implement a FIR filter. Based on the proceeding posts I interpret that as meaning that you want to quickly implement a FIR filter. Without the HDL skills there is no "easy" even using free Xilinx IP. You no doubt know this at this point.

If this were an exercise for someone with good HDL skills and the time to experiment I'd advise ditching the Vivado board design flow ( this only seems to be easy ) and complicated Xilinx IP all together. Read the documentation for DDS devices from Analog Devices or some other vendor to grasp the concepts of how it works. Code your own Sine wave generator using Xilinx BRAM or DPRAM IP. Most of the Xilinx IP will provide an implementation in "Native" mode so that you can use it without the board design flow or understanding complicated data bus standards that have features you don't need. Use MatLAB or OCTAVE or SCILAB to create your sine lookup table. You only need to worry 90 degrees if you can work out the logic to use that to create a full cycle. And yes, there are details that aren't obvious that you''l have to understand. Once you have a working Sine wave generator designing a phase accumulator similar to that described in the DDS literature requires a surprisingly simple implementation... though the complexity behind that simplicity is anything but obvious. Add a bit of logic and viola you have a simple but perfectly usable DDS... that you understand because you did it yourself. The FIR filter involves a bit of insight but the actual structure is also quite simple. Such an exercise will make you quite proficient at understanding fractional and multiple precision binary numbers which of itself is a goal worthy of such an undertaking.  This would be a great exercise for even people with considerable FPGA development skills.

 

Share this post


Link to post
Share on other sites
  • 0

@Yannick,

Ok, now that I understand what you wish to do, try this:

  1. Tie ACLKEN on the DDS to 1.  This will generate a signal at your system clock rate.  It'll also look nice and pretty in the simulator as it comes out of the DDS.
  2. Tie ACLKEN on the FIR compiler so that it is 1 for one system clock 2.7M times per second.  The result won't look so pretty going into the filter any more, but it will be at your desired sample rate.
  3. Tie m_axis_tdata_ready going into the DDS to 1.  This will allow the DDS to free run, even though you are only looking at samples 2.7M times a second.
  4. Tie m_axis_tdata_ready going into your FIR to 1 as well.  We won't use that.
  5. Now, on the output of the FIR compiler, you'll want to sample the data once every time ACLKEN is valid.  This will then capture the sampling effects, and allow you to visualize how the sample rate is affecting things.

You should see some fascinating things happen as you set the DDS to just less than 1/2 your sample rate through just greater than 1/2 your sample rate.  Likewise, you may find setting the DDS to somewhere between just less than 2.7MHz and just greater than 2.7MHz should also be quite fascinating for you.

Dan

Yannick likes this

Share this post


Link to post
Share on other sites
  • 0

D@n's reference "CE" as circuit enable has been bubbling up from my sub-conscience often enough for me to want to comment.

CE is generally reserved to mean clock enable. I've run across people new to FPGA development with a strong background in ASIC development who get confused by the term. A clock enable prevents the clock source from making transitions. In the ASIC world there are clock sources with enables. In the FPGA world we imitate a clock enable with a signal used in our logic to prevent that logic from clocking under certain conditions. I re-checked the Xilinx HDL guidelines and didn't find any clock buffers with a clock enable. There is a clock control primitive but I've never had use for it. As far as I know none of the external clock modules used on Digilent boards have an enable.  Well if that helps no one as least I can forget D@n's comment....

Share this post


Link to post
Share on other sites
  • 0

@zygot,

Is that what that means?  I've always gotten confused between the two terms.  Clock Enable certainly makes more sense of a port labelled ACLKEN then circuit enable does.

Dan

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0