DQPSK Modulation/Demodulation issue

I’ve recently been working on transmitting data from a vector source via
DQPSK.

I’ve created a Simulation [non USRP] with the following flow graph:

TX
Vector Source [0x6c] ie 01 10 11 00 > Packed To Unpacked > Mapper
[Binary 2 Gray] > Differential Encoder >
Chunks to Symbols

RX
Differential Phasor > Constellation Decoder > Mapper [Gray 2 Binary]

Unpacked To Packed > Vector Sink

For differential encoding, i’ve also ammended the first input byte to be
0.
The Output for the simulation is as expected:

ie. Input = 0 108 108 108 108 108 108 …
Output = 0 108 108 108 108 108 108 …

When i try transmitting this data through the USRP however, i receive 4
possible outputs. These include:

108 [which is correct]
177 [wrong]
108 [wrong]
27 [wrong]

These are funnily the 4 possible outputs which have all possible
symbols
in 1 byte. ie 00 01 10 11
The output varies, one time i might get all 108s as expected , and
other
times ill get one of the other 3 outputs.
The signal constellation at the output of the differential phasor
looks
correct.

Does anyone have any idea what is going wrong here?
I’ve included my python source code below:

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

Gnuradio Python Flow Graph

Title: Qpsktest

Generated: Thu Apr 22 02:01:45 2010

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

from gnuradio import gr
from gnuradio.blks2impl import psk
from gnuradio.eng_option import eng_option
from gnuradio.gr import firdes
from grc_gnuradio import usrp as grc_usrp
from grc_gnuradio import wxgui as grc_wxgui
from optparse import OptionParser
import wx

class QPSKtest(gr.top_block):

    def __init__(self):
            gr.top_block.__init__(self)

            ##################################################
            # Variables
            ##################################################
            self.arity = arity = pow(2,2)
            self.samp_rate = samp_rate = 256000
            self.rotated_const = rotated_const = map(lambda pt: pt * 

1,
psk.constellation[arity])
self.rot = rot = .707 + .707j
self.data = 100000 * [0x6C,]

            ## Initial Block to Capture data from Vector Source and 

then
Add 0 at the beginning

            fg = gr.top_block()

            self.vectorSource = gr.vector_source_b(self.data, False, 
  1.          self.VSINK = gr.vector_sink_b(1)
    
             fg.connect(self.vectorSource, self.VSINK)
    
             fg.run()
    
             actual_data = self.VSINK.data()
    
             ##make first data element 0 for the sake of the Diff 
    

Encoder
etc
actual_data_copy = (0,) + actual_data[1:]
print actual_data_copy

            ##################################################
            # Main Blocks
            ##################################################
            self.gr_chunks_to_symbols_xx_0 =

gr.chunks_to_symbols_bc((map(lambda pt: pt * rot,
psk.constellation[arity])), 1)
self.gr_clock_recovery_mm_xx_0 =
gr.clock_recovery_mm_cc(2,
0.25 * 0.03 * 0.03, 0.05, 0.03, 0.005)
self.gr_constellation_decoder_cb_0 =
gr.constellation_decoder_cb((rotated_const), (range(arity)))
self.gr_costas_loop_cc_0 = gr.costas_loop_cc(0.10, 0.25
*
0.1 * 0.1, 0.002, -0.002, 4)
self.gr_diff_encoder_bb_0 = gr.diff_encoder_bb(arity)
self.gr_diff_phasor_cc_0 = gr.diff_phasor_cc()
self.gr_feedforward_agc_cc_0 = gr.feedforward_agc_cc(16,
1.0)
self.gr_fir_filter_xxx_1 = gr.fir_filter_ccf(1,
(gr.firdes.root_raised_cosine(2,2,1.0,0.35,22)))
self.gr_interp_fir_filter_xxx_0 =
gr.interp_fir_filter_ccf(2, (gr.firdes.root_raised_cosine(2, 2, 1.0,
0.35,
22)))
self.gr_map_bb_0 =
gr.map_bb((psk.binary_to_gray[arity]))
self.gr_map_bb_0_0 =
gr.map_bb((psk.gray_to_binary[arity]))
self.gr_multiply_const_vxx_0 =
gr.multiply_const_vcc(((1.0/16384.0), ))
self.gr_multiply_const_vxx_0_1 =
gr.multiply_const_vcc((16384.0, ))
self.gr_packed_to_unpacked_xx_0 =
gr.packed_to_unpacked_bb(2, gr.GR_MSB_FIRST)
self.gr_unpacked_to_packed_xx_0 =
gr.unpacked_to_packed_bb(2, gr.GR_MSB_FIRST)

            self.dataSource = gr.vector_source_b(actual_data_copy,

False, 1)

            self.usrp_simple_sink_x = 

grc_usrp.simple_sink_c(which=0,
side=“B”)
self.usrp_simple_sink_x.set_interp_rate(500)
self.usrp_simple_sink_x.set_frequency(2430000000,
verbose=True)
self.usrp_simple_sink_x.set_gain(0)
self.usrp_simple_sink_x.set_enable(True)
self.usrp_simple_source_x_0_0 =
grc_usrp.simple_source_c(which=0, side=“B”, rx_ant=“RX2”)
self.usrp_simple_source_x_0_0.set_decim_rate(250)
self.usrp_simple_source_x_0_0.set_frequency(2430000000,
verbose=True)
self.usrp_simple_source_x_0_0.set_gain(0)
self.vOut = gr.vector_sink_b(1)

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

(self.gr_costas_loop_cc_0, 0))
self.connect((self.gr_multiply_const_vxx_0, 0),
(self.gr_feedforward_agc_cc_0, 0))
self.connect((self.gr_diff_encoder_bb_0, 0),
(self.gr_chunks_to_symbols_xx_0, 0))
self.connect((self.gr_map_bb_0, 0),
(self.gr_diff_encoder_bb_0, 0))
self.connect((self.gr_packed_to_unpacked_xx_0, 0),
(self.gr_map_bb_0, 0))
self.connect(self.dataSource,
self.gr_packed_to_unpacked_xx_0)
self.connect((self.gr_costas_loop_cc_0, 0),
(self.gr_fir_filter_xxx_1, 0))
self.connect((self.gr_interp_fir_filter_xxx_0, 0),
(self.gr_multiply_const_vxx_0_1, 0))
self.connect((self.usrp_simple_source_x_0_0, 0),
(self.gr_multiply_const_vxx_0, 0))
self.connect((self.gr_constellation_decoder_cb_0, 0),
(self.gr_map_bb_0_0, 0))
self.connect((self.gr_diff_phasor_cc_0, 0),
(self.gr_constellation_decoder_cb_0, 0))
self.connect((self.gr_clock_recovery_mm_xx_0, 0),
(self.gr_diff_phasor_cc_0, 0))
self.connect((self.gr_multiply_const_vxx_0_1, 0),
(self.usrp_simple_sink_x, 0))
self.connect((self.gr_chunks_to_symbols_xx_0, 0),
(self.gr_interp_fir_filter_xxx_0, 0))
self.connect((self.gr_fir_filter_xxx_1, 0),
(self.gr_clock_recovery_mm_xx_0, 0))
self.connect((self.gr_map_bb_0_0, 0),
(self.gr_unpacked_to_packed_xx_0, 0))
self.connect((self.gr_unpacked_to_packed_xx_0, 0),
(self.vOut, 0))

            self.run()

            output = self.vOut.data()
            print output[0:5000]

    def set_arity(self, arity):
            self.arity = arity
            self.set_rotated_const(map(lambda pt: pt * 1,

psk.constellation[self.arity]))

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

    def set_rotated_const(self, rotated_const):
            self.rotated_const = rotated_const

    def set_rot(self, rot):
            self.rot = rot

if name == ‘main’:
QPSKtest()

Regards,

Marcin


View this message in context:
http://old.nabble.com/DQPSK-Modulation-Demodulation-issue-tp28288015p28288015.html
Sent from the GnuRadio mailing list archive at Nabble.com.

On Tue, Apr 27, 2010 at 11:49 AM, marcin_w [email protected]
wrote:

Hi All,

I have been battling with this for the last week and still have not found a
solution.

I’ve include some more info for anyone who can help.

Does anyone have any idea what is going wrong here?
I’ve included my python source code below:

  1. To be honest, your code is really hard to read, which is the reason
    I didn’t originally reply to your question. I started to look through
    to make sure your blocks and connections were set up correctly, but
    it’s just a big mess.

  2. There is a DQPSK implementation in the gnuradio blks2 source,
    search the repository for it, there is a transmitter and a receiver.

  3. I would guess your problem has to do with incorrectly applying the
    differential coding, since you get a unique stream of symbols in each
    of your four cases:
    108d - 1h 2h 3h 0h
    177d - 2h 3h 0h 1h
    27d - 0h 1h 2h 3h
    198d - 3h 0h 1h 2h

Notice that the difference is the same in each of these cases:
(previous+1) % 4. This comes from the phase ambiguities in the costas
loop, it locks on to wherever. That’s why the differential coding is
used. You can confirm this by sending something that’s not an even
distribution of symbols. For example, send: 92d - (1h 1h 3h 0h) = (+1
+0 +2 +1) and I bet you’ll get back four different values just like
you do now:
(1h 1h 3h 0h) = (+x +0 +2 +1)
(2h 2h 0h 1h) = (+x +0 +2 +1)
(3h 3h 1h 2h) = (+x +0 +2 +1)
(0h 0h 2h 3h) = (+x +0 +2 +1)

Jason

Hi All,

I have been battling with this for the last week and still have not
found a
solution.

I’ve include some more info for anyone who can help.

USRP1
Daughterboard: RFX2400 [using TX/RX port for Transmission & RX2 port for
Reception]
Carrier Freq: 2.43 GHz

I’ve also included the constellation diagrams (for the output of the
differential Phasor) for each of the 4 cases.

So once again recapping, i’m inputting the byte [108] through a vector
source, but only get the correct output sequence [108] SOME of the time,
while at other times i will get either 177, 27, or 28.

Case 1) The correct decoded sequence [108] = [0x6x] = [01101100]
http://users.tpg.com.au/marcinw//correct.PNG

Case 2) Incorrectly decoded sequence [177]
http://users.tpg.com.au/marcinw//incorrect1.PNG

Case 3) Incorrectly decoded sequence [27]
http://users.tpg.com.au/marcinw//incorrect2.PNG

Case 4) Incorrectly decoded sequence [198]
http://users.tpg.com.au/marcinw//incorrect3.PNG

Note: When inputting less complicated input sequences however, eg:
11111111
,00000000, 01010101, were only 1 possible QPSK symbol is contained
within
the byte, the output sequence seems to decode correctly.
Once i complicate the input byte though, to something like [01101100] =
[108] , where ALL possible QPSK symbols are contained within that byte,
i
will receive the incorrect sequence at the output (most of the time).

Some final questions:

  1. Can anybody work out why the sequence isn’t decoding correctly?
  2. Has anybody actually successfully created DQPSK
    transmission/reception
    using a Byte Vector Source as the input and Byte vector sink as the
    output?
  3. Will i have to resort to some sort of Channel Coding/Decoding to
    correct
    the received sequence?

Regards,

Marcin

marcin_w wrote:

The output varies, one time i might get all 108s as expected , and other

Generated: Thu Apr 22 02:01:45 2010

            self.rotated_const = rotated_const = map(lambda pt: pt *
  1.          actual_data_copy = (0,) + actual_data[1:]
             self.gr_constellation_decoder_cb_0 =
    

gr.interp_fir_filter_ccf(2, (gr.firdes.root_raised_cosine(2, 2, 1.0, 0.35,
self.gr_unpacked_to_packed_xx_0 =
self.usrp_simple_sink_x.set_gain(0)
# Connections
(self.gr_map_bb_0, 0))
self.connect((self.gr_diff_phasor_cc_0, 0),
(self.gr_unpacked_to_packed_xx_0, 0))
self.set_rotated_const(map(lambda pt: pt * 1,

if name == ‘main’:
QPSKtest()

Regards,

Marcin


View this message in context:
http://old.nabble.com/DQPSK-Modulation-Demodulation-issue-tp28288015p28379148.html
Sent from the GnuRadio mailing list archive at Nabble.com.

On Wed, Apr 28, 2010 at 12:30 AM, marcin_w [email protected]
wrote:

Ah, generated code would explain a lot.

The code has no glaring errors that I can see, but if you suspect that
it’s the channel, what happens if you simply remove it? or replace it
with a simulated one?

I like the ‘outside in’ approach when developing gnuradio graphs,
especially for learning the system. For DQPSK I would start with just
my vector source/sink pair and make sure the extraneous fluff worked,
then add in the chunks-to-symbols and test, and so on. It takes about
20 minutes for simple graphs and you can debug single problems as they
arise rather than all of them at once (O(n) vs O(n^2)).

You can remove the USRP/channel from the equation as long as your
samples per symbol line up for the transmitter and receiver you’ll be
fine, then you’ll know.

p.s Your suggested input of [92d] actually produced the correct output

Interesting, what happens if you send longer than single byte vectors
(I assume you are going to want to do that eventually anyway)

Jason

Hi Jason thanks for the feedback.

Sorry about the code, it was generated mostly via Grc. I’ve cleaned it
up,
should make much more sense now:
http://users.tpg.com.au/marcinw//qpskTest.py

I’ve tried using the available DQPSK blocks as you suggested, but i get
the
same result. i.e with 108 as the input i get either 108, 177, 27 or 198
as
the output.

The source code for the graph using the available DQPSK block is given
here:
http://users.tpg.com.au/marcinw//QPSKtest16.py

Onto the differential Encoder, i believe it is encoding my data
correctly. I
have proven this by connecting a vector sink at the output of the
encoder
and so with:

Input [108] = [1 2 3 0] >> Packed2Unpacked [2, MSB] >> Binary2Gray >>
Differential Encoder >> Vector Sink

the output at the encoder is:

y[0] = (x[0] + y[-1]) % M (where M = 4 for QPSK)

y[0] = 1
y[1] = 0
y[2] = 2
y[3] = 2

y[4] = 3
y[5] = 2
y[6] = 0
y[7] = 0

y[8] = 1
y[9] = 0
y[10] = 2
y[11] = 2

y[8] = 3
y[9] = 2
y[10] = 0
y[11] = 0

and so on…

If the system is Encoding my data correctly, i am still led to believe
the
problem lies with the noisy channel?
Do you have any more suggestions?

Regards,

Marcin

p.s Your suggested input of [92d] actually produced the correct output

Jason U. wrote:

differential coding, since you get a unique stream of symbols in each
distribution of symbols. For example, send: 92d - (1h 1h 3h 0h) = (+1


Discuss-gnuradio mailing list
[email protected]
Discuss-gnuradio Info Page


View this message in context:
http://old.nabble.com/DQPSK-Modulation-Demodulation-issue-tp28288015p28384967.html
Sent from the GnuRadio mailing list archive at Nabble.com.

anyone?
Surely someone has created a dqpsk trasmitter/receiver that works with a
simple vector source as input & vector sink as output.


View this message in context:
http://old.nabble.com/DQPSK-Modulation-Demodulation-issue-tp28288015p28431613.html
Sent from the GnuRadio mailing list archive at Nabble.com.

Jason U. wrote:

The code has no glaring errors that I can see, but if you suspect that
it’s the channel, what happens if you simply remove it? or replace it
with a simulated one?

Yes, the graph works perfectly when i remove the channel/usrp.

i.e.

TX
Vector Source [180] > Packed To Unpacked > Mapper [Binary 2 Gray] >
Differential Encoder >
Chunks to Symbols

RX
Differential Phasor > Constellation Decoder > Mapper [Gray 2 Binary]

Unpacked To Packed > Vector Sink

No problems here, my output is always 108.

Getting back to the USRP model, i can’t seen to work out whether my
bitrates/sample rates are correct.
For instance, the interpolation of my USRP sink is set to 500, meaning
it
should be accepting samples at a rate of of 256ks/s.

I’ve had a look at pick_bitrate.py in the examples, but here are a few
more
questions:

  1. Do my sample rates / interpolation / decimation look correct,
    according
    to:
    http://users.tpg.com.au/marcinw//qpskTest.py

  2. Do i need to use the throttle block in my graph to control the bit
    rates?
    , or does simply setting the interpolation on the usrp automatically
    control
    this?

  3. Would setting the interpolation of the usrp to 500, automatically set
    the
    bit rate to 128kb/s if my graph looks like this:

Vector Source [180] > Packed To Unpacked > Mapper [Binary 2 Gray] >
Differential Encoder >
Chunks to Symbols > Interpolating FIR Filter (RRC) [samples/symbol = 2 ,
interpolation = 2 ] > USRP sink [ interp: 500]

  1. Why do we even bother using an interpolating filter in the modulator
    block. Why not just a RRC filter?

  2. For the demodulator block, why is the decimation level on the
    decimating
    FIR filter set to 1 and not to 2.

Regards,

Marcin

Jason U. wrote:

You can remove the USRP/channel from the equation as long as your
Jason


Discuss-gnuradio mailing list
[email protected]
Discuss-gnuradio Info Page


View this message in context:
http://old.nabble.com/DQPSK-Modulation-Demodulation-issue-tp28288015p28400750.html
Sent from the GnuRadio mailing list archive at Nabble.com.

Hi Marcin,

some answers - unfortunately only to those of your questions that I
feel confident to answer.

On Thu, Apr 29, 2010 at 06:45:23AM -0700, marcin_w wrote:

Getting back to the USRP model, i can’t seen to work out whether my
bitrates/sample rates are correct.
For instance, the interpolation of my USRP sink is set to 500, meaning it
should be accepting samples at a rate of of 256ks/s.

This is correct.

  1. Do i need to use the throttle block in my graph to control the bit rates?
    , or does simply setting the interpolation on the usrp automatically control
    this?

You only need a throttle block in case you dont have a real hardware
source
or sink. Once you use the USRP sink, it will “pull” the respective
number
of samples into the sink, which is what drives all the preceding blocks
to
generate some output.

  1. Would setting the interpolation of the usrp to 500, automatically set the
    bit rate to 128kb/s if my graph looks like this:

Vector Source [180] > Packed To Unpacked > Mapper [Binary 2 Gray] >
Differential Encoder >
Chunks to Symbols > Interpolating FIR Filter (RRC) [samples/symbol = 2 ,
interpolation = 2 ] > USRP sink [ interp: 500]

At least as far as I understand: yes.

Regards,
Harald

  • Harald W. [email protected]
    http://laforge.gnumonks.org/
    ============================================================================
    “Privacy in residential applications is a desirable marketing option.”
    (ETSI EN 300 175-7 Ch.
    A6)

Hi Marcin,

On Sun, May 02, 2010 at 10:24:57PM -0700, marcin_w wrote:

anyone?
Surely someone has created a dqpsk trasmitter/receiver that works with a
simple vector source as input & vector sink as output.

I’ve tried that independent of you last week, but also was unable to
make it
work.

Right now I unfortunately simply don’t have the time to
research/investigate
this further :confused:

However, if you do get a working example script or grc graph at some
point,
please make the effort of publishing/posting it so it can be referenced
by
others.

  • Harald W. [email protected]
    http://laforge.gnumonks.org/
    ============================================================================
    “Privacy in residential applications is a desirable marketing option.”
    (ETSI EN 300 175-7 Ch.
    A6)

Harald W. wrote:

However, if you do get a working example script or grc graph at some
point,
please make the effort of publishing/posting it so it can be referenced by
others.

Hi Harald & everyone else with DxPSK issues.

After weeks of battling with my simple DQPSK transmitter/receiver, i
have
finally found the solution.
The key was always just to add a packet encoder & decoder.

I now receive my input sequence of [01101100] ie 108 Decimal, every
time.
I have further tried transmitting with DQPSK from a file source [i.e a .dat file containing 20 seconds of music, sampled at 48KHz]. My received file
is
almost identical with minimal audible noise, and low BER.

I will provide source code and GRC flow graphs for both the simulation
and
actual USRP transmission/reception using both DBPSK & DQPSK in the next
day
or so.

Thank you to everyone for your suggestions,

Marcin


View this message in context:
http://old.nabble.com/DQPSK-Modulation-Demodulation-issue-tp28288015p28462231.html
Sent from the GnuRadio mailing list archive at Nabble.com.