Pack k bits?

I want to take an input stream of bytes in which only one LSB is
relevant (e.g., the output of the GR GLFSR block) and pack these bits
into bytes with k relevant bits. For example, I’d like to take a stream
of raw bits generated by the GLFSR and feed them to an M-PSK modulator,
which requires chunks with k=log2(M) bits. Unfortunately I haven’t found
this to be straightforward. There is no “pack_k_bits” module that I
could find, so I tried using unpacked_to_packed_bb and
packed_to_unpacked_bb. They are not working like I would expect. For
instance, here’s an example in Python:


data = [1,0,1,0, 0,0,1,0, 1,1,1,0, 0,1,1,0]

45 67

self.source = gr.vector_source_b(data, False, 1)
self.pack = gr.unpacked_to_packed_bb(1, gr.GR_LSB_FIRST)
self.unpack = gr.packed_to_unpacked_bb(2, gr.GR_LSB_FIRST) # stuff
2 bits into LSB of each output byte
self.head = gr.head(gr.sizeof_char, 8) #
should have 16/2 = 8 output bytes
self.sink = gr.file_sink(gr.sizeof_char, “out.bin”)
self.connect(self.source, self.pack, self.unpack, self.head, self.sink)

This gives the following:
$ hexdump -C out.bin
0000000 02 02 00 02 03 02 01 02 |…|
0000008

But I would expect the following:
0000000 01 01 00 01 03 01 02 01 |…|
0000008

Notice that the two least significant bits are in reverse order. Any
clue what’s going on here?

Thanks,
Sean

I think it would work if I modified
gnuradio/gnuradio-core/src/lib/gengen/gr_packed_to_unpacked_XX.cc.t
(line 119) to the following:

x = (x>>1) | (get_bit_le(in, index_tmp) << (d_bits_per_chunk - 1) );

-OR-

x |= get_bit_le(in, index_tmp) << j;

I haven’t tested, but I think these are functionally equivalent. Does
this change sound reasonable?

– Sean

From: discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalid
[mailto:discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalid] On
Behalf Of Nowlan, Sean
Sent: Wednesday, March 28, 2012 8:49 AM
To: [email protected]
Subject: [Discuss-gnuradio] Pack k bits?

I want to take an input stream of bytes in which only one LSB is
relevant (e.g., the output of the GR GLFSR block) and pack these bits
into bytes with k relevant bits. For example, I’d like to take a stream
of raw bits generated by the GLFSR and feed them to an M-PSK modulator,
which requires chunks with k=log2(M) bits. Unfortunately I haven’t found
this to be straightforward. There is no “pack_k_bits” module that I
could find, so I tried using unpacked_to_packed_bb and
packed_to_unpacked_bb. They are not working like I would expect. For
instance, here’s an example in Python:


data = [1,0,1,0, 0,0,1,0, 1,1,1,0, 0,1,1,0]

45 67

self.source = gr.vector_source_b(data, False, 1)
self.pack = gr.unpacked_to_packed_bb(1, gr.GR_LSB_FIRST)
self.unpack = gr.packed_to_unpacked_bb(2, gr.GR_LSB_FIRST) # stuff
2 bits into LSB of each output byte
self.head = gr.head(gr.sizeof_char, 8) #
should have 16/2 = 8 output bytes
self.sink = gr.file_sink(gr.sizeof_char, “out.bin”)
self.connect(self.source, self.pack, self.unpack, self.head, self.sink)

This gives the following:
$ hexdump -C out.bin
0000000 02 02 00 02 03 02 01 02 |…|
0000008

But I would expect the following:
0000000 01 01 00 01 03 01 02 01 |…|
0000008

Notice that the two least significant bits are in reverse order. Any
clue what’s going on here?

Thanks,
Sean

Any comment on this? I think the current implementation of
gr_packed_to_unpacked_bb(int k, gr_endianness_t endianness) puts bits in
an incorrect order when k > 1 and endianness = gr.GR_LSB_FIRST.

From: discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalid
[mailto:discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalid] On
Behalf Of Nowlan, Sean
Sent: Wednesday, March 28, 2012 9:26 AM
To: [email protected]
Subject: Re: [Discuss-gnuradio] Pack k bits?

I think it would work if I modified
gnuradio/gnuradio-core/src/lib/gengen/gr_packed_to_unpacked_XX.cc.t
(line 119) to the following:

x = (x>>1) | (get_bit_le(in, index_tmp) << (d_bits_per_chunk - 1) );

-OR-

x |= get_bit_le(in, index_tmp) << j;

I haven’t tested, but I think these are functionally equivalent. Does
this change sound reasonable?

– Sean

From:
discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalidmailto:discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalid
[mailto:discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalid]mailto:[mailto:discuss-gnuradio-bounces+sean.nowlan=removed_email_address@domain.invalid]
On Behalf Of Nowlan, Sean
Sent: Wednesday, March 28, 2012 8:49 AM
To: [email protected]mailto:[email protected]
Subject: [Discuss-gnuradio] Pack k bits?

I want to take an input stream of bytes in which only one LSB is
relevant (e.g., the output of the GR GLFSR block) and pack these bits
into bytes with k relevant bits. For example, I’d like to take a stream
of raw bits generated by the GLFSR and feed them to an M-PSK modulator,
which requires chunks with k=log2(M) bits. Unfortunately I haven’t found
this to be straightforward. There is no “pack_k_bits” module that I
could find, so I tried using unpacked_to_packed_bb and
packed_to_unpacked_bb. They are not working like I would expect. For
instance, here’s an example in Python:


data = [1,0,1,0, 0,0,1,0, 1,1,1,0, 0,1,1,0]

45 67

self.source = gr.vector_source_b(data, False, 1)
self.pack = gr.unpacked_to_packed_bb(1, gr.GR_LSB_FIRST)
self.unpack = gr.packed_to_unpacked_bb(2, gr.GR_LSB_FIRST) # stuff
2 bits into LSB of each output byte
self.head = gr.head(gr.sizeof_char, 8) #
should have 16/2 = 8 output bytes
self.sink = gr.file_sink(gr.sizeof_char, “out.bin”)
self.connect(self.source, self.pack, self.unpack, self.head, self.sink)

This gives the following:
$ hexdump -C out.bin
0000000 02 02 00 02 03 02 01 02 |…|
0000008

But I would expect the following:
0000000 01 01 00 01 03 01 02 01 |…|
0000008

Notice that the two least significant bits are in reverse order. Any
clue what’s going on here?

Thanks,
Sean

So I’ll add a bit more detail, and bump the thread because I don’t
understand this either.

If we apply the following unpackings to a byte of value 69 we get:

gr.packed_to_unpacked_bb(1, gr.GR_LSB_FIRST) -> (1, 0, 1, 0, 0, 0, 1,
0)
gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) -> (0, 1, 0, 0, 0, 1, 0, 1)
gr.packed_to_unpacked_bb(2, gr.GR_LSB_FIRST) -> (2, 2, 0, 2)
gr.packed_to_unpacked_bb(2, gr.GR_MSB_FIRST) -> (1, 0, 1, 1)

packed_to_unpacked and unpacked_to_packed are consistent with one
another.

On Fri, Mar 30, 2012 at 1:33 PM, Nowlan, Sean

On Wed, Mar 28, 2012 at 8:48 AM, Nowlan, Sean
[email protected] wrote:

data = [1,0,1,0, 0,0,1,0, 1,1,1,0, 0,1,1,0]

Ok, finally got some time to work through this.

What’s happening here is that first you are packing these into bytes,
but in reverse order since you’re taking the LSB first. So the output
of self.pack is:
[01000101, 01100111] → 0x45, 0x67

Then you are telling the upacked_to_packed to read the LSB first and
unpack from there where the output stream has 2-bits per byte:

[01, 00, 01, 01 | 01, 10, 01, 11] → unpack 2, LSB, read left to right

That means that you are reading each byte out from left to right and
putting them into bytes two at a time. In other words:

Byte 1: [01, 00, 01, 01]
01 → 10 (2)
01 → 10 (2)
00 → 00 (0)
01 → 10 (2)

Byte 2: [01, 10, 01, 11]
11 → 11 (3)
01 → 10 (2)
10 → 01 (1)
01 → 10 (2)

If you want it your way, use gr.GR_MSB_FIRST for the
gr.unpacked_to_packed_bb.

Working through it this way, I’m pretty sure what’s happening is
correct. There might be a confusion about byte order and how the
unpacked_to_packed with LSB first swaps things around on you. For
instance, you said that "data = [1,0,1,0, 0,0,1,0, 1,1,1,0, 0,1,1,0]

45 67", but they are just bits in a string of bytes at that point,

so you’re trying to read it backwards. That vector is actually [0xA2,
0xE6].

Of course, now I’m confused… but I’m pretty sure the way that it’s
working is correct.

Tom

Thanks for the input. Endianness has been frying brains for decades!

I agree that what’s happening with unpacked_to_packed_bb is correct.
Each input byte (for which only the first LSB is relevant) is stuffed
into a byte, beginning at the LSB. Hence, [1,0,1,0, 0,0,1,0] →
0b01000101 = 0h45.

Where I’m having trouble is in packed_to_unpacked_bb when bits are read
from the LSB of a packed byte and stuffed, 2 at a time, into the MSB
of the 2-bit destination. Using your example:

Byte 1: [01, 00, 01, 01]
01 → 10 (2) # output byte: [msb] 0 0 0 0 0 0 1 0
[lsb] <==> 0h02
01 → 10 (2)
00 → 00 (0)
01 → 10 (2)

Byte 2: [01, 10, 01, 11]
11 → 11 (3)
01 → 10 (2)
10 → 01 (1)
01 → 10 (2)

I was expecting bits to be read from the LSB of the input byte and
packed into the LSB of the output byte. In other words, I was looking
to slice the input byte into 4 sections (since 8/2 = 4) and output them
starting with the 2 LSB of the input byte. Your example:

Byte 1: 0b01000101 ==> 01 | 00 | 01 | 01 ==> vector: [1, 1, 0, 1]
Byte 2: 0b01100111 ==> 01 | 10 | 01 | 11 ==> vector: [3, 1, 2, 1]

I tried with the MSB suggestion, but it reverses output byte order on
me, i.e., the values are correct but the vector comes out in reverse
order.

Thanks!
Sean


From: [email protected] [[email protected]] on behalf of Tom
Rondeau [[email protected]]
Sent: Monday, April 02, 2012 2:47 PM
To: Nowlan, Sean
Cc: [email protected]
Subject: Re: [Discuss-gnuradio] Pack k bits?

On Wed, Mar 28, 2012 at 8:48 AM, Nowlan, Sean
[email protected] wrote:

data = [1,0,1,0, 0,0,1,0, 1,1,1,0, 0,1,1,0]

Ok, finally got some time to work through this.

What’s happening here is that first you are packing these into bytes,
but in reverse order since you’re taking the LSB first. So the output
of self.pack is:
[01000101, 01100111] → 0x45, 0x67

Then you are telling the upacked_to_packed to read the LSB first and
unpack from there where the output stream has 2-bits per byte:

[01, 00, 01, 01 | 01, 10, 01, 11] → unpack 2, LSB, read left to right

That means that you are reading each byte out from left to right and
putting them into bytes two at a time. In other words:

Byte 1: [01, 00, 01, 01]
01 → 10 (2)
01 → 10 (2)
00 → 00 (0)
01 → 10 (2)

Byte 2: [01, 10, 01, 11]
11 → 11 (3)
01 → 10 (2)
10 → 01 (1)
01 → 10 (2)

If you want it your way, use gr.GR_MSB_FIRST for the
gr.unpacked_to_packed_bb.

Working through it this way, I’m pretty sure what’s happening is
correct. There might be a confusion about byte order and how the
unpacked_to_packed with LSB first swaps things around on you. For
instance, you said that "data = [1,0,1,0, 0,0,1,0, 1,1,1,0, 0,1,1,0]

45 67", but they are just bits in a string of bytes at that point,

so you’re trying to read it backwards. That vector is actually [0xA2,
0xE6].

Of course, now I’m confused… but I’m pretty sure the way that it’s
working is correct.

Tom