1
$\begingroup$

I'm trying to generate coefficients for a FIR low pass filter to be used in an FPGA. I'm using python (scipy.signal) to attempt to do this, but am having trouble getting coefficients in a usable form.

This is the function I'm using to generate coefficients:

b = signal.firwin(21, 0.01, window='blackman');

The coefficients it returns are:

[ -1.62779573e-18   1.08170091e-03   4.74493669e-03   1.19927580e-02
   2.37996986e-02   4.03774280e-02   6.06306778e-02   8.20599398e-02
   1.01201426e-01   1.14487974e-01   1.19246920e-01   1.14487974e-01
   1.01201426e-01   8.20599398e-02   6.06306778e-02   4.03774280e-02
   2.37996986e-02   1.19927580e-02   4.74493669e-03   1.08170091e-03
  -1.62779573e-18]

These are unusable to me when it comes to FPGA implementation. How do you scale these or is there a better technique that produces either integer coefficients or coefficients that could be scaled to fixed point in hardware?

$\endgroup$

1 Answer 1

2
$\begingroup$

These even aren't great coefficients for any software implementation that supports floating point – you could easily omit the last and the first coefficient without changing the filter significantly; the rest of the coefficients seem relatively well-conditioned.

So, basically, what you do is that you pick a fixed point bit width $B$ that suits the signal you're dealing with and the precision you need, and multiply each coefficient with $k=\frac{2^{N}}{\max\limits_{x\in b}|x|}$ (or $2^{N-1}$, as we're probably talking about signed numbers); you then usually just round, and try your filter with pseudorandom white noise, as you'll be inferring some degree of quantization error. Alternatively, you analytically calculate the frequency response in $\mathcal Z$-domain (freqz does that for you) of the quantized filter. Of course, you'll see an additional gain of $k$, but DSP engineers typically just "carry through" such factors (as most operations are linear), and interpret the results accordingly at the very end.

Now, as said, your coefficients (aside from the edge ones) look relatively well-conditioned, and I daresay that if you for example decided that 24 bit are enough precision for your coefficients, then that quantization error might be negligible.

If, however, the resulting frequency response is suboptimal, you can increase bit depth of the coefficients in bit steps¹, or by selectively increasing or decreasing symmetrical pairs of taps. For example, if you find that your frequency response is distorted to have too much gain at low frequencies, it might be a good idea to alternatingly in- and decrease adjacent coefficients by one (be slow with that, and always make sure the errors you're fixing even matter at all – who cares if your passband ripple is 0.2 dB instead of the floating point 0.18 dB, if all you needed was 0.4 dB?).

Without loss of generality, yes, there's also methods to generate integer taps directly (they shouldn't be much better for the window method you're using than rounding afterwards, but might be better for iterative approaches), but I'm not versed in these, or would even know of any toolbox that does them.


¹: as FPGAs really do not care whether you're using 23, 24, or 25 bits – unlike CPUs, they are not inherently limited to specific bitwidths; now, this is a bit of a lie, as for multiplication you might be using "DSP slices", which do have finite bit width and are fixed, not implemented on demand. However, it's thoroughly possible that your synthesizer might decide that for "fixed factor" multiplications, a straightforward combinatorial multiplier is appropriate. Maybe don't worry about these details right now.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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