4-to-32 bit symbol mapper block

Hi list,

I’d like to write a custom block that takes 1, 4-bit symbol and remaps
it to 1, 32-bit symbol. Some code for a general_work() method is below
[1], but it doesn’t quite work yet.

It isn’t convolutional - i.e. the 4-bits of symbol k, do not overlap
with the 4-bits of symbol k-1 - so it doesn’t really fall into the
concept of a filter. It also must operate on multiples of 4-bits in
one operation (at least 4).

In a sense, it’s an interpolating block that operates on 4 bits at a
time.

I originally thought that I should be operating on vectors, but
haven’t really found many examples of the stream_to_vector_ii block or
the vector_to_stream_ii block.

Does anyone on the list have any thoughts or suggestions?

Thanks,

C

[1]

#define N 4
#define M 32
#define K (M/N)

forecast():

// input items requires for nout < 4 = 0
ninput_items_required[0] = ( noutput_items / N ) * N * K;

general_work():

// input is a binary stream encoded as integers
// output is a binary stream encoded as integers

int *in = (int *) input_items[ 0 ];
int *out = (int *) output_items[ 0 ];

int j, nchips = 0;

for( j=0; j < noutput_items; j += M, nchips++, in += j/K, out += j ) {
// FIXME: throw some sort of exception if j / K >= ninput_items
// Do symbol-to-chip mapping
// pack the first four input items and form a nibble
unsigned symbol = 0;
for( int i=0; i < N; i++ ) {
int bit = !! in[ i ];
symbol |= bit << i;
}
// form a word via the LUT
unsigned chip = LUT[ symbol ];
// unpack the word into output items
for( int i=0; i < M; i++ ) {
int bit = ( chip >> i ) & 0x1;
out[ i ] = bit;
}
}
// Tell runtime system how many input items we consumed on each input
stream.
consume_each ( nchips * N );
// Tell runtime system how many output items we produced.
return nchips * M;

I’ll definitely try the Pack K Bits block - that might just do it!

On Sat, Jan 3, 2015 at 1:38 PM, Marcus Müller [email protected]
wrote:

as you noted, this block has a fixed relation between in- and output;
thus, you can use the sync_interpolator [1] to get rid of the need to
write your own forecast and calling consume; you’ll need to override
work instead of general_work, which is more comfortable. With the
set_output_multiple[2] you can restrict the possible values of
n_output_items, which are directly proportional to your input items.

Perfect - thanks!

On Sat, Jan 3, 2015 at 1:38 PM, Marcus Müller [email protected]
wrote:

Then: If I understand you correctly, what you have is an input stream of
unsigned (32 bit)ints, each int containing exactly one bit of information:
0x00000000, 0x00000001, 0x00000001, 0x00000000, and so forth.
This format is especially wasteful on memory, and wherever GNU Radio
uses unpacked bits, they are usually transported as unsigned char items
(giving you a memory overhead of only 8x instead of 32x), so there’s
blocks for that particular job (packed_to_unpacked and the reverse).

For sure it’s wasteful on memory. I usually just try getting something
working before optimizing it. Unit tests pass now, thankfully :slight_smile:

So, assuming that I may do this basing my class on the
sync_interpolator class, I’d like to pack my input and output -
ideally as 32 or 64-bit ints (whatever the wordsize is - 64 bits in my
case). From what I’ve read, I can only expect to pack up to 32-bits
into each integer-type output item [1], and therefore will
unfortunately only be able to pack up to 4-bits into each integer-type
input. Is that correct, or is there also a 64-bit output type?

I guess if I’m packing 4 bits into one byte on the output and 32-bits
into an int on the output, I would probably just use a sync block with
a ratio of 1-1, and e.g. add an example to remind the user to use the
Pack 4 Bits block on the input.

It was an interesting exercise to learn a bit about some of gr’s
various blocks :slight_smile:

Since I really want to understand what is happening here, I’ll go

I wrote most of my code snippet when I was 1/2 asleep at 2 am last
night! Sorry for subjecting you to it!

[1]
http://gnuradio.org/redmine/projects/gnuradio/wiki/FAQ#What-are-items-in-a-flowgraph

Hi Christopher,

On 01/03/2015 09:56 PM, Christopher F. wrote:

On Sat, Jan 3, 2015 at 1:38 PM, Marcus Müller [email protected] wrote:

Then: If I understand you correctly, what you have is an input stream of
unsigned (32 bit)ints, each int containing exactly one bit of information:
0x00000000, 0x00000001, 0x00000001, 0x00000000, and so forth.
This format is especially wasteful on memory, and wherever GNU Radio
uses unpacked bits, they are usually transported as unsigned char items
(giving you a memory overhead of only 8x instead of 32x), so there’s
blocks for that particular job (packed_to_unpacked and the reverse).
For sure it’s wasteful on memory. I usually just try getting something
working before optimizing it. Unit tests pass now, thankfully :slight_smile:
Good approach; I often do premature optimization and end up with
nothing…
So, assuming that I may do this basing my class on the
sync_interpolator class, I’d like to pack my input and output -
ideally as 32 or 64-bit ints (whatever the wordsize is - 64 bits in my
case).
As you mentioned in IRC, your symbols/chips might contain a maximum of
32 bit, which would make uint32_t sufficient. x86_64 CPUs still deal
with 32 bit ints as efficiently as it does in 32 bit mode, so use
whatever makes sense for your application (or use 64 bit if you might
want to expand).
From what I’ve read, I can only expect to pack up to 32-bits
into each integer-type output item [1], and therefore will
unfortunately only be able to pack up to 4-bits into each integer-type
input. Is that correct, or is there also a 64-bit output type?
Well, the FAQ entry is half-true, only. Basically, GNU Radio knows
nothing of types. We don’t have a convention on how to suffix blocks
that take 64 bit integers, and I guess GRC doesn’t have a color for
them, but other than that, there’s nothing stopping you from using items
of an arbitrary length of bytes (there’s memory reservation issues if
you use things that are hard to page-align, but unless you use items of
say 1023 byte length, this shouldn’t be a problem). This has some
dangerous effects: for example, you can connect a block that produces
float items to a block that consumes 32 bit integers – because these
items have the same size, GNU Radio won’t notice the mixup. Therefore,
the suffix convention explained in that FAQ entry was born.

There’s a lot of blocks that really don’t care about what’s inside an
item – file_sink for example just takes the items as memory, and puts
them into a file. You just have to tell it “hey, expect items of length
N bytes”; the same goes for many network sinks etc.

On the other hand, you might want to use existing arithmetic blocks on
these items – in that case, you might be better off using a type that
they actually know.

I guess if I’m packing 4 bits into one byte on the output and 32-bits
into an int on the output, I would probably just use a sync block with
a ratio of 1-1, and e.g. add an example to remind the user to use the
Pack 4 Bits block on the input.
Well, I agree that memory is most probably not the problem – so it
might be easiest to modify your block to take completely unpacked bits
in bytes, and using
a) a matching output multiple or
b) vectors of 4.
By the way, b) would be a 4 byte input signature, exactly like you have
with your int block, but with different packing scheme (eg. 0x01010101
instead of 0x0000000F for the 1111-symbol)

It was an interesting exercise to learn a bit about some of gr’s
various blocks :slight_smile:
:slight_smile: !

Since I really want to understand what is happening here, I’ll go
I wrote most of my code snippet when I was 1/2 asleep at 2 am last
night! Sorry for subjecting you to it!
Oh no problem at all, keep it coming! So nice to read something like
that; I’ve written code that used a bit more variables than it needed to
a hundred times, and the fact that I put my own rewrite in the mail was
that I had it at hand, anyway (it’s how I often try to understand
someone else’s code, by slightly rewriting it), it just had to be
formatted a bit nicer. In fact, I think it’s commonly agreed that
although GR has gotten some nice features for digital data (as in hard
symbols) processing over the last two years (PDUs, tagged stream blocks,
the whole messaging/PMT thing), there’s still a lot of room and need for
best practices when it comes to processing bitstreams – so your program
excerpt is, as I assume, useful for the community and development
process.

Greetings,
Marcus

Hi Christopher,

as you noted, this block has a fixed relation between in- and output;
thus, you can use the sync_interpolator [1] to get rid of the need to
write your own forecast and calling consume; you’ll need to override
work instead of general_work, which is more comfortable. With the
set_output_multiple[2] you can restrict the possible values of
n_output_items, which are directly proportional to your input items.

Then: If I understand you correctly, what you have is an input stream of
unsigned (32 bit)ints, each int containing exactly one bit of
information:
0x00000000, 0x00000001, 0x00000001, 0x00000000, and so forth.
This format is especially wasteful on memory, and wherever GNU Radio
uses unpacked bits, they are usually transported as unsigned char items
(giving you a memory overhead of only 8x instead of 32x), so there’s
blocks for that particular job (packed_to_unpacked and the reverse).
However, I’m not completely sure you’re actually doing that, because
your nested loop with N,k,j,M and i confused me a lot, and I personally
would avoid doing #defines whenever possible, because compilers are
smart. (also, I had to look up if it’s well defined to do “j += M, …,
out += j” in the for loop advancement statement)

Since I really want to understand what is happening here, I’ll go
ahead and rewrite your outer for loop to increment only one variable,
and substitute the others in place when used. Please don’t take my usage
of uint32_t too serious, I just wanted to make sure I got the data types
right myself.

work (int noutput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)

{
uint32_t in = …;
uint32_t out = …;
for(unsigned int nchips = 0; nchips * M < noutput_items; nchips++)
/
aha, so we’re actually doing one chip per iteration! /
{
/
from for loop advancement statement: /
in += N;
/
was j/K == j / (M/N) == nchips * M / M * N == nchips * N,
simplified this.
/
uint32_t symbol = 0x0;
for(unsigned int bitcounter=0; bitcounter < N; i++ )
{
int bit = !(!in[bitcounter]); /this indicates that an input
item is 0 iff none of the bits are set, else 1
/
symbol |= bit << bitcounter;
}
uint32_t chip = LUT [symbol];

    for(unsigned int i=0; i < M; i++ )

{
uint32_t bit = ( chip >> i ) & 0x1;
*(out++) = bit;
}
}
return noutput_items;
}

If I’ve (sense-)correctly reproduced your loop, then what you’re doing
is a sync_interpolator with an interpolation rate of M/N, and an
output_multiple of M, which automatically implies that GNU Radio will
only call you with N-multiples of input items, if, in your constructor,
you set the correct io signature (sizeof(uint32_t)), and call
set_output_multiple(M/N).

I hope this was a little helpful,

Greetings,
Marcus

[1]http://gnuradio.org/doc/doxygen/classgr_1_1sync__interpolator.html#details
[2]http://gnuradio.org/doc/doxygen/classgr_1_1block.html#a63d67fd758b70c6f2d7b7d4edcec53b3