Gr-dsp Library Block Parameters

Hi Al,

We’re trying to use your gr-dsp library and are having difficulty
verifying the output of your DSP.fir_ccf blocks. To allow for easy
comparison to the standard filter type, gr.fir_filter_ccf, we generated
a very simple block diagram in GRC. This consisted of a vector source,
an fir_filter_ccf block, and a file sink. All of the original data and
filter taps are the same, but the outputs are not lining up with their
expected values.

I have included the full script file at the bottom of this email. The
relevant calls to the filter constructors are shown in the text.

For instance:

We have:

src = (0.01+0.11j,
0.02+0.22j,
0.03+0.33j,
0.04+0.44j,
0.05+0.55j,
0.06+0.66j,
0.07+0.77j,
0.08+0.88j,
0.09+0.99j)

src_coeff = (0.101, 0.102, 0.103, 0.104, 0.105)

Without scaling (scaling_factor = 0, so scaling by 2^0 = 1):

 gr.fir_filter_ccf(1, src_coeff)

 This produces output:
    0.0010 + 0.0111i
    0.0030 + 0.0334i
    0.0061 + 0.0671i
    0.0102 + 0.1122i
    0.0154 + 0.1689i
    0.0205 + 0.2255i
    0.0257 + 0.2822i
    0.0308 + 0.3388i
    0.0360 + 0.3954i

 What we thought would be the equivalent call using the fir_ccf

block is:

 self.gr_fir_filter_xxx_0 = dsp.fir_ccf (src_coeff, 0, 1, 0, 0, 0, 
 This produces output:

  0
  0
  0
  0
  0
  0
  0
  0
  0

With scaling (scaling_factor = 15, so scaling by 2^15):

 gr.fir_filter_ccf(1, src_coeff)
 The data was manually scaled by 2^15 in MATLAB, producing output:

    1.0e+04 *

    0.0033 + 0.0364i
    0.0100 + 0.1096i
    0.0200 + 0.2199i
    0.0334 + 0.3677i
    0.0503 + 0.5533i
    0.0672 + 0.7389i
    0.0840 + 0.9245i
    0.1009 + 1.1102i
    0.1178 + 1.2958i


 dsp.fir_ccf (src_coeff, 15, 1, 0, 1, 0, 0)

 * output-signature = 1, so we want the output to be have the same

scale factor that it is on the DSP.

 This produces output:

    1.0e+03 *

    0.3350 + 0.3350i
    0.3400 + 0.3390i
    0.3430 + 0.3440i
    0.3470 + 0.3470i
    0.3500 - 0.0340i
   -0.3650 - 0.1000i
   -1.0960 - 0.2000i
   -2.1990 - 0.3350i
   -3.6770 - 0.5030i

In neither of these cases do the dsp implementation and the gpp
implementation give the same output.

I’m pretty sure that the issue is in my interpretation of your
parameters. I’ve already been using the online documentation to figure
out what the parameters do, so I know the basic jist of it, but
obviously I haven’t got it figured out yet. Could you please explain
the use of the scaling_factor, input_signature, and output_signature
parameters in more detail?

Also, for the input_signature parameter to be 0, like it is in the
examples qa_fir_ccf2.py and qa_fir_ccf3.py, doesn’t the input need to be
normalized? By my understanding, normalized vectors are unit vectors,
so they should have length 1. But src (above) has length 9, so it’s not
normalized and the input_signature parameter should be 1. Is that
correct?

Thanks,

Chris


#!/usr/bin/env python
##################################################

Gnuradio Python Flow Graph

Title: Top Block

Generated: Wed Jul 13 11:09:34 2011

##################################################

from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.gr import firdes
from optparse import OptionParser
from gnuradio import dsp

class top_block(gr.top_block):

     def __init__(self):
             gr.top_block.__init__(self, "Top Block")

             ##################################################
             # Variables
             ##################################################
             self.samp_rate = samp_rate = 32000

             ##################################################
             # Blocks
             ##################################################
             self.gr_vector_source_x_0 =

gr.vector_source_c((0.01+0.11j,0.02+0.22j,0.03+0.33j,0.04+0.44j,0.05+0.55j,
0.06+0.66j, .07+0.77j, 0.08+0.88j, 0.09+0.99j), False, 1)
#self.gr_fir_filter_xxx_0 = gr.fir_filter_ccf(1,
(0.101, 0.102, 0.103, 0.104, 0.105))
# Uncomment the previous line, comment in the next
three lines to switch from dsp-based to gpp-based filter.
src_coeff = (0.101, 0.102, 0.103, 0.104, 0.105)
dsp.init()
self.gr_fir_filter_xxx_0 = dsp.fir_ccf (src_coeff, 15,
1, 0, 1, 0, 0)

             self.gr_file_sink_0 =

gr.file_sink(gr.sizeof_gr_complex*1, “filtertest-dsp2.dat”)
self.gr_file_sink_0.set_unbuffered(False)

             ##################################################
             # Connections
             ##################################################
             self.connect((self.gr_vector_source_x_0, 0),

(self.gr_fir_filter_xxx_0, 0))
self.connect((self.gr_fir_filter_xxx_0, 0),
(self.gr_file_sink_0, 0))

     def get_samp_rate(self):
             return self.samp_rate

     def set_samp_rate(self, samp_rate):
             self.samp_rate = samp_rate

if name == ‘main’:
parser = OptionParser(option_class=eng_option, usage="%prog:
[options]")
(options, args) = parser.parse_args()
if gr.enable_realtime_scheduling() != gr.RT_OK:
print “Error: failed to enable realtime scheduling.”
tb = top_block()
tb.start()
raw_input('Press Enter to quit: ')
tb.stop()

Hey Chris, if you reached this far I’m assuming that the new packages
have solved your issues … Since you’re passing normalized values to
the DSP you will need to scale them or they will be converted to zeros
when moved to the DSP

float fixed
0.3333 = 0
3.3333 = 3
33.333 = 33

so your scaling factor should be 15. Regarding input/output signature
it allows you to define if the input is normalized (signature = 0)
meaning that the easycom-gpp library would need to scale it before
transferring it to the dsp and the same for the output you’ll tell it if
it should scale it back to normalized numbers or should it keep it as
fixed point numbers. The motivation for this is the USRP1 with non-uhd
drivers would provide fixed point data during receive mode and
normalized data for transmit mode.

al

src_coeff, 0, 1, 0, 0, 0, 0)

Hi Al,

That really clears things up conceptually. Thanks for the insight.

Given that, I went back and modified the dsp test case to use a scaling
factor of 15, normalized input, and normalized output, so the block
invocation was “dsp.fir_ccf (src_coeff, 15, 1, 0, 0, 0, 0)”. Running
the test provides:

-0.0102 - 0.0102i
-0.0104 - 0.0103i
-0.0105 - 0.0105i
-0.0106 - 0.0106i
-0.0107 + 0.0010i
0.0111 + 0.0031i
0.0334 + 0.0061i
0.0671 + 0.0102i
0.1122 + 0.0154i

However, this differs from the output of the gr.fir_filter_ccf block and
the result of direct computation in MATLAB:

0.0010 + 0.0111i
0.0030 + 0.0334i
0.0061 + 0.0671i
0.0102 + 0.1122i
0.0154 + 0.1689i
0.0205 + 0.2255i
0.0257 + 0.2822i
0.0308 + 0.3388i
0.0360 + 0.3954i

I’ve checked the magnitude and phase of each of these results, and it
doesn’t look like they’re a simple rotation or multiple of each other.

I thought that it might just not work for decimal sources/coefficients,
so I adjusted the tests so that src = (1,1,1,1,1,1,1,1,1) and src_coeff
= (1,1,1,1,1).

Since we no longer needed to scale it before or after, our block
invocation is “dsp.fir_ccf (src_coeff, 15, 1, 1, 1, 0, 0)”. This gives
the output:

1.0e+04 *

3.2748 + 3.2751i
3.2762 + 3.2752i
3.2762 + 3.2767i
3.2763 - 3.2768i

-3.2768 - 0.0001i
0 - 0.0002i
0 - 0.0003i
0 - 0.0004i
0 - 0.0005i
0
0
0
0
0
2.8678 - 3.2752i
-3.2757 - 3.2751i
-3.2757 + 0.0001i
0.0005 - 3.2768i
-3.2768

The output from the gr.fir_filter_ccf test is the first nine elements of
the MATLAB output:

  1
  2
  3
  4
  5
  5
  5
  5
  5

Finally, I thought that the issue might be that I’m not normalizing my
source coefficients. So, I normalized them in MATLAB, yielding
src_coeff = (0.4472, 0.4472, 0.4472, 0.4472, 0.4472), which provided the
output:

1.0e+03 *

6.5440 + 6.5450i
6.5500 + 6.5460i
6.5500 + 6.5520i
6.5510 + 6.5530i
6.5530 - 0.0010i
     0 - 0.0010i
     0 - 0.0020i
     0 - 0.0020i
     0 - 0.0030i

What am I doing wrong?

Thanks,

Chris

Did you recompile the DSP code or did you download the the precompiled
binary? I think there was an issue that I fixed in the DSP code but
didn’t update the binary.

al

I compiled the DSP code, as of Monday. How long ago did you find/fix
the issue?

Chris, I FINALLY got around looking at and fixing the problem … I
pushed updates to the easyCom-gpp and easyCom-dsp repos and updated the
gpp prebaked packages there was a memory alignment issue that i didn’t
backup properly so I didn’t push to the repos … moral of the story
regular backups are a good thing :slight_smile:

Try to keep your filter input and taps as multiples of 4, I added extra
data points to the python file you sent me to do that. The DSP will
always load 4 data points at a time which might not be an issue if the
buffer has zeros in the latter locations but if you have left over data
points from a previous filter operation it can throw your result off …
I need to add code that automatically pads unaligned input by zeros to
address this but I won’t get around to it for a while.

As a piece of advise if you start developing code for the DSP, memory
alignment can be an absolute nightmare so I really need to add API
functions to handle it so developers won’t have to face them with each
newly developed function.

Tell me if this update works for you.

al

that was a while back that I fixed it, I’m currently in the process of
verifying that all of the code I have on github is the same code that is
on my computers. I’m almost at the point where I’ll be validating the
DSP code … I’ll use your test case test file and step through the code
with a JTAG to figure what’s going on.

al