1
$\begingroup$

I am trying to implement a chain of CIC/FIR filters on an ZYNQ FPGA. Using the Xilinx FIR compiler works fine so far but I am unable to properly get all the math.

At the moment I have 2 chains of filters:

  • $5\times$ downsampling, passband $12.5\text{MHz}$:
    → FIR filter 2, 5x downsampling, input 17.7.0, output 17.7

  • $625\times$ downsampling, passband $100\text{kHz}$:

    → CIC filter, $25\times$ downsampling, input 14 bit, output 16 bit

    → Compensation FIR filter, no downsampling, input 17.7, output 17.7

    → FIR filter 1, $5\times$ downsampling, input 17.7.0, output 17.7

    → FIR filter 2, $5\times$ downsampling, input 17.7.0, output 17.7

I have a 14 bit, $20\text{kHz}$ signal that I feed into both chains:

  • If I feed it into the first chain I sign extend the 14bit value to 17bits and add 7 zero-bits at the end (.7). I get a nice output that wins me one bit.

  • If I feed the signal into the second chain I directly feed the 14bit signal into the CIC filter and left-shift the output signal to only keep the 16 MSBs. I then sign extend that 16bit value to 17bit (yes I could have also just kept the first 17bits of the CIC return value, if that would be better, please tell me) and add 7 zero-bits at the end (.7) as well. The filters win me 1-2 bit until the output of the "FIR filter 1" but at the output of the "FIR filter 2" I have an output where I lost 8bit (upper 8 non-sign bits are 0). This is the exact same FIR filter that gives me +1 bit in the first ($5\times$ downsampling) chain ... This broken chain also seems to have a lot of jitter after one period ... (I can exclude overflows as the source of error as the Xilinx FIR compiler guarantees no overflows).

How can this be, what am I missing?

In the same question I would like to ask:

Let's assume all the chains finally work properly. I then will have different bit growth. Initially I knew that 14bit correspond to $2.2\text{Vpp}$ which means that 12.86bits correspond to $1\text{V}$. But now I suddenly have a 17.7bit output. How do I know where my $1\text{V}$ reference level is now? Because it has shifted some. I am quite sure that accounting just for the DC gain yields wrong results.

My waveforms:

Output $5\times$ chain:

output 5x chain

Chain $625\times$:

chain 625x

I am very grateful for any hints and will gladly add more information if some more is required.

$\endgroup$
  • $\begingroup$ Did you design the CIC filter or is it a Xilinx core? Do you use rounding before truncating the data? $\endgroup$ – Ben Jul 28 '17 at 13:26
  • $\begingroup$ Yes it is a CIC filter created with the Xilinx core. I do not use rounding before truncating the data. Also what would that have an impact on? I would assume that woul maximally influence one bit or am I wrong? $\endgroup$ – Yatekii Jul 28 '17 at 15:55
  • $\begingroup$ You should always round before truncating. Otherwise you can introduce a DC offset. Second of all, keep track of all the gains of your filter, ok? Keep track of which bits are guard bits (bits to prevent overflow so you can saturate instead), which bits are fractionnal, assuming your original is all integer. Can you send me a link to your filter cores? $\endgroup$ – Ben Jul 28 '17 at 15:59
  • $\begingroup$ Hmm ok so I need to round properly everywhere (have to figure out how I do that best, but that's doable). Yes, keeping track of the gain and how I apply it properly is my problem I am trying to solve :-) Sure I can hook you up with my Vivado project (I have one for sim purposes without any processing system), I will just have to make it ready as I use a custom core to multiplex, which I have to put at a proper place, so it works for you too with the IP repos :) $\endgroup$ – Yatekii Jul 28 '17 at 17:28
  • $\begingroup$ Pretty sure that there is a rounding option in the Xilinx cores. At least with Altera, you can do it. $\endgroup$ – Ben Jul 28 '17 at 17:33
0
$\begingroup$

I've worked a lot with FIR and IIR filters in FPGAs, here are a few pointers

1 - Keep track of your bits and their respective weights.

2 - Keep track of your filter gain and the number of bits for the coefficients. For example, assume you have a 14-bit signed input. Your input can go from +16383 to -16384. Now you filter it in a 17-taps FIR low-pass filter (for example), its DC gain should be '1'. Assuming 16-bit coefficients, and no coefficient greater than or equal to '1', the sum of the coefficients should be 32768 (2^15). It could be slightly smaller, it doesn't really matter, especially if you round the output. However, it is possible, that because of the scaling, the sum of the coefficients could be 32769, 32770, etc. In this case your DC gain would be slightly bigger than unity and you will likely need guard bits.

3 - Assuming there can be no overflow at the output of the filters, now you need to determine how many "fractional bits" you need to keep. There are no simple answers. Assuming no decimation, it could be a good idea to keep the output format the same as the input. For example, 14-bit input with 1 sign-bit ---> 14-bit ouput with 1 sign bit. However, please round the data before truncating, otherwise you could insert some DC offset or other unpleasantness.

4 - If you decimate, one of the reasons why could be to increase the resolution of your data, in this case your output should have more fractional bits than your input.

5 - If your filters have a gain higher than 1 (on purpose, not because of quantization), such a resonant IIR filter, you will need to implement the appropriate number of guard bits. For example, you add a 20 dB-gain at a certain frequency, you will need 4 additional guard bits at the output.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.