[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] gnuradio-examples/python/gmsk2 benchmark_gmsk_t...
From: |
Thomas W. Rondeau |
Subject: |
[Commit-gnuradio] gnuradio-examples/python/gmsk2 benchmark_gmsk_t... |
Date: |
Wed, 28 Jun 2006 18:15:24 +0000 |
CVSROOT: /sources/gnuradio
Module name: gnuradio-examples
Changes by: Thomas W. Rondeau <trondeau1122> 06/06/28 18:15:24
Modified files:
python/gmsk2 : benchmark_gmsk_tx.py benchmark_mpsk_rx.py
benchmark_mpsk_tx.py receive_path.py
transmit_path.py
Added files:
python/gmsk2 : bpsk.py dbpsk.py dqpsk.py pkt.py qpsk.py
Log message:
working m-psk; seperate files for bpsk, dbpsk, qpsk (not working at MAC
level), and dqpsk
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/benchmark_gmsk_tx.py?cvsroot=gnuradio&r1=1.17&r2=1.18
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/benchmark_mpsk_rx.py?cvsroot=gnuradio&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/benchmark_mpsk_tx.py?cvsroot=gnuradio&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/receive_path.py?cvsroot=gnuradio&r1=1.12&r2=1.13
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/transmit_path.py?cvsroot=gnuradio&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/bpsk.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/dbpsk.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/dqpsk.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/pkt.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/qpsk.py?cvsroot=gnuradio&rev=1.1
Patches:
Index: benchmark_gmsk_tx.py
===================================================================
RCS file:
/sources/gnuradio/gnuradio-examples/python/gmsk2/benchmark_gmsk_tx.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- benchmark_gmsk_tx.py 21 Jun 2006 00:55:01 -0000 1.17
+++ benchmark_gmsk_tx.py 28 Jun 2006 18:15:23 -0000 1.18
@@ -46,7 +46,8 @@
bitrate, interp_rate, spb, bt, options):
gr.flow_graph.__init__(self)
self.txpath = transmit_path(self, mod_class, tx_subdev_spec,
- bitrate, interp_rate, spb, bt, options)
+ bitrate, interp_rate, spb, gain, m_arity,
+ options, mod_kwargs)
# /////////////////////////////////////////////////////////////////////////////
@@ -65,15 +66,20 @@
parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
help="select USRP Tx side A or B")
parser.add_option("-f", "--freq", type="eng_float", default=423.1e6,
- help="set Tx and Rx frequency to FREQ
[default=%default]", metavar="FREQ")
+ help="set Tx and Rx frequency to FREQ
[default=%default]",
+ metavar="FREQ")
parser.add_option("-r", "--bitrate", type="eng_float", default=None,
help="specify bitrate. spb and interp will be derived.")
- parser.add_option("-S", "--spb", type="int", default=None, help="set
samples/baud [default=%default]")
+ parser.add_option("-S", "--spb", type="int", default=None,
+ help="set samples/baud [default=%default]")
parser.add_option("-i", "--interp", type="intx", default=None,
help="set fpga interpolation rate to INTERP
[default=%default]")
parser.add_option("-s", "--size", type="eng_float", default=1500,
help="set packet size [default=%default]")
- parser.add_option("", "--bt", type="float", default=0.3, help="set
bandwidth-time product [default=%default]")
+ parser.add_option("", "--bt", type="float", default=0.3,
+ help="set bandwidth-time product [default=%default]")
+ parser.add_option("-g", "--gain", type="eng_float", default=100.0,
+ help="transmitter gain [default=%default]")
parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
help="set megabytes to transmit [default=%default]")
parser.add_option("","--discontinuous", action="store_true", default=False,
Index: benchmark_mpsk_rx.py
===================================================================
RCS file:
/sources/gnuradio/gnuradio-examples/python/gmsk2/benchmark_mpsk_rx.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- benchmark_mpsk_rx.py 31 May 2006 03:11:32 -0000 1.1
+++ benchmark_mpsk_rx.py 28 Jun 2006 18:15:23 -0000 1.2
@@ -30,7 +30,11 @@
import struct
# from current dir
-from mpsk_receive_path import mpsk_receive_path
+from bpsk import bpsk_demod
+from dbpsk import dbpsk_demod
+from dqpsk import dqpsk_demod
+from receive_path import receive_path
+import fusb_options
#import os
#print os.getpid()
@@ -39,11 +43,13 @@
class my_graph(gr.flow_graph):
- def __init__(self, rx_subdev_spec, bitrate, decim_rate, spb,
- arity, excess_bw, rx_callback, log):
+ def __init__(self, demod_class, rx_subdev_spec,
+ bitrate, decim_rate, spb, arity,
+ rx_callback, options, demod_kwargs):
gr.flow_graph.__init__(self)
- self.rxpath = mpsk_receive_path(self, rx_subdev_spec, bitrate,
decim_rate,
- spb, arity, excess_bw, rx_callback,
log)
+ self.rxpath = receive_path(self, demod_class, rx_subdev_spec,
+ bitrate, decim_rate, spb, arity,
+ rx_callback, options, demod_kwargs)
# /////////////////////////////////////////////////////////////////////////////
# main
@@ -71,20 +77,23 @@
parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
help="select USRP Rx side A or B")
parser.add_option("-f", "--freq", type="eng_float", default=423.1e6,
- help="set Rx frequency to FREQ [default=%default]",
metavar="FREQ")
+ help="set Rx frequency to FREQ [default=%default]",
+ metavar="FREQ")
parser.add_option("-r", "--bitrate", type="eng_float", default=None,
help="specify bitrate. spb and interp will be derived.")
- parser.add_option("-S", "--spb", type="int", default=None, help="set
samples/baud [default=%default]")
+ parser.add_option("-S", "--spb", type="int", default=None,
+ help="set samples/baud [default=%default]")
parser.add_option("-d", "--decim", type="intx", default=None,
help="set fpga decim rate to DECIM [default=%default]")
- parser.add_option("", "--m-arity", type=int, default=4,
- help="PSK arity [default=%default]")
+ parser.add_option("-m", "--modulation", type="string", default='dbpsk',
+ help="modulation type (bpsk, dbpsk, dqpsk)
[default=%default]")
parser.add_option("", "--excess-bw", type="float", default=0.3,
help="set RRC excess bandwith factor [default=%default]")
parser.add_option("-g", "--gain", type="eng_float", default=27,
help="set rx gain")
parser.add_option("","--log", action="store_true", default=False,
help="enable diagnostic logging")
+ fusb_options.add_options(parser)
(options, args) = parser.parse_args ()
if len(args) != 0:
@@ -94,19 +103,44 @@
if options.freq < 1e6:
options.freq *= 1e6
+ demod_kwargs = {
+ 'excess_bw' : options.excess_bw,
+ }
+
+ #FIXME: Needs to be worked in to overall structure; this will be fixed
+ # once static class definitions for modulations are defined
+ if(options.modulation=='bpsk'):
+ modulation=bpsk_demod
+ m_arity=2
+ elif(options.modulation=='dbpsk'):
+ modulation=dbpsk_demod
+ m_arity=2
+ else:
+ modulation=dqpsk_demod
+ m_arity=4
+
# build the graph
- fg = my_graph(options.rx_subdev_spec, options.bitrate,
- options.decim, options.spb, options.m_arity,
- options.excess_bw, rx_callback, options.log)
+ fg = my_graph(modulation,
+ options.rx_subdev_spec, options.bitrate,
+ options.decim, options.spb, m_arity,
+ rx_callback, options, demod_kwargs)
print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.rxpath.bitrate()),)
print "spb: %3d" % (fg.rxpath.spb(),)
print "decim: %3d" % (fg.rxpath.decim(),)
- fg.rxpath.set_freq(options.freq)
+ ok = fg.rxpath.set_freq(options.freq)
+ if not ok:
+ print "Failed to set Rx frequency to %s" %
(eng_notation.num_to_str(options.freq),)
+ raise SystemExit
+
fg.rxpath.set_gain(options.gain)
print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using",
fg.rxpath.gain
+ r = gr.enable_realtime_scheduling()
+ if r != gr.RT_OK:
+ print "Warning: Failed to enable realtime scheduling."
+
fg.start() # start flow graph
fg.wait() # wait for it to finish
Index: benchmark_mpsk_tx.py
===================================================================
RCS file:
/sources/gnuradio/gnuradio-examples/python/gmsk2/benchmark_mpsk_tx.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- benchmark_mpsk_tx.py 6 Jun 2006 05:01:22 -0000 1.3
+++ benchmark_mpsk_tx.py 28 Jun 2006 18:15:23 -0000 1.4
@@ -26,13 +26,14 @@
from gnuradio.eng_option import eng_option
from optparse import OptionParser
-import random
-import time
-import struct
-import sys
+import random, time, struct, sys
# from current dir
-from mpsk_transmit_path import mpsk_transmit_path
+from bpsk import bpsk_mod
+from dbpsk import dbpsk_mod
+from dqpsk import dqpsk_mod
+from transmit_path import transmit_path
+import fusb_options
#import os
#print os.getpid()
@@ -41,11 +42,13 @@
class my_graph(gr.flow_graph):
- def __init__(self, tx_subdev_spec, bitrate, interp_rate, spb,
- arity, excess_bw):
+ def __init__(self, mod_class, tx_subdev_spec,
+ bitrate, interp_rate, spb, gain,
+ options, mod_kwargs):
gr.flow_graph.__init__(self)
- self.txpath = mpsk_transmit_path(self, tx_subdev_spec, bitrate,
- interp_rate, spb, arity, excess_bw)
+ self.txpath = transmit_path(self, mod_class, tx_subdev_spec,
+ bitrate, interp_rate, spb, gain,
+ options, mod_kwargs)
# /////////////////////////////////////////////////////////////////////////////
@@ -64,22 +67,27 @@
parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
help="select USRP Tx side A or B")
parser.add_option("-f", "--freq", type="eng_float", default=423.1e6,
- help="set Tx and Rx frequency to FREQ
[default=%default]", metavar="FREQ")
+ help="set Tx and Rx frequency to FREQ
[default=%default]",
+ metavar="FREQ")
parser.add_option("-r", "--bitrate", type="eng_float", default=None,
help="specify bitrate. spb and interp will be derived.")
- parser.add_option("-S", "--spb", type="int", default=None, help="set
samples/baud [default=%default]")
+ parser.add_option("-S", "--spb", type="int", default=None,
+ help="set samples/baud [default=%default]")
parser.add_option("-i", "--interp", type="intx", default=None,
help="set fpga interpolation rate to INTERP
[default=%default]")
parser.add_option("-s", "--size", type="eng_float", default=1500,
help="set packet size [default=%default]")
- parser.add_option("", "--m-arity", type=int, default=4,
- help="PSK arity [default=%default]")
+ parser.add_option("-m", "--modulation", type="string", default='dbpsk',
+ help="modulation type (bpsk, dbpsk, dqpsk)
[default=%default]")
parser.add_option("", "--excess-bw", type="float", default=0.3,
help="set RRC excess bandwith factor [default=%default]")
+ parser.add_option("-g", "--gain", type="eng_float", default=100.0,
+ help="transmitter gain [default=%default]")
parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
help="set megabytes to transmit [default=%default]")
parser.add_option("","--discontinuous", action="store_true", default=False,
help="enable discontinous transmission (bursts of 5
packets)")
+ fusb_options.add_options(parser)
(options, args) = parser.parse_args ()
if len(args) != 0:
@@ -91,15 +99,36 @@
pkt_size = int(options.size)
+ mod_kwargs = {
+ 'excess_bw' : options.excess_bw,
+ }
+
+ #FIXME: rework when static class defintions are ready for the modulation
types
+ if(options.modulation=='bpsk'):
+ modulation=bpsk_mod
+ elif( options.modulation=='dbpsk'):
+ modulation=dbpsk_mod
+ else:
+ modulation=dqpsk_mod
+
# build the graph
- fg = my_graph(options.tx_subdev_spec, options.bitrate, options.interp,
- options.spb, options.m_arity, options.excess_bw)
+ fg = my_graph(modulation,
+ options.tx_subdev_spec, options.bitrate, options.interp,
+ options.spb, options.gain,
+ options, mod_kwargs)
print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),)
print "spb: %3d" % (fg.txpath.spb(),)
print "interp: %3d" % (fg.txpath.interp(),)
- fg.txpath.set_freq(options.freq)
+ ok = fg.txpath.set_freq(options.freq)
+ if not ok:
+ print "Failed to set Tx frequency to %s" %
(eng_notation.num_to_str(options.freq),)
+ raise SystemExit
+
+ r = gr.enable_realtime_scheduling()
+ if r != gr.RT_OK:
+ print "Warning: failed to enable realtime scheduling"
fg.start() # start flow graph
Index: receive_path.py
===================================================================
RCS file: /sources/gnuradio/gnuradio-examples/python/gmsk2/receive_path.py,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- receive_path.py 21 Jun 2006 00:55:01 -0000 1.12
+++ receive_path.py 28 Jun 2006 18:15:23 -0000 1.13
@@ -24,6 +24,7 @@
from gnuradio import usrp
# from current dir
+from pkt import demod_pkts
from pick_bitrate import pick_rx_bitrate
# /////////////////////////////////////////////////////////////////////////////
@@ -32,12 +33,8 @@
class receive_path(gr.hier_block):
def __init__(self, fg, demod_class, rx_subdev_spec,
- bitrate, decim, spb, rx_callback, options):
-
- # FIXME add this as a parameter
- demod_kwargs = {
- 'gain_mu' : 0.03, # default
- }
+ bitrate, decim, spb, m_arity,
+ rx_callback, options, demod_kwargs):
self.u = usrp.source_c (fusb_block_size=options.fusb_block_size,
fusb_nblocks=options.fusb_nblocks)
Index: transmit_path.py
===================================================================
RCS file: /sources/gnuradio/gnuradio-examples/python/gmsk2/transmit_path.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- transmit_path.py 21 Jun 2006 00:55:01 -0000 1.9
+++ transmit_path.py 28 Jun 2006 18:15:23 -0000 1.10
@@ -31,19 +31,17 @@
class transmit_path(gr.hier_block):
def __init__(self, fg, mod_class, tx_subdev_spec,
- bitrate, interp, spb, bt, options):
+ bitrate, interp, spb, gain,
+ options, mod_kwargs):
- # FIXME add this as a parameter, and move bt arg into dict
- mod_kwargs = {
- 'bt' : bt
- }
-
- self.normal_gain = 8000
+ self.normal_gain = gain
self.u = usrp.sink_c (fusb_block_size=options.fusb_block_size,
fusb_nblocks=options.fusb_nblocks)
dac_rate = self.u.dac_rate();
+ print mod_class
+ print mod_class.bits_per_baud()
(self._bitrate, self._spb, self._interp) = \
pick_tx_bitrate(bitrate, mod_class.bits_per_baud(), spb, interp,
dac_rate)
Index: bpsk.py
===================================================================
RCS file: bpsk.py
diff -N bpsk.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ bpsk.py 28 Jun 2006 18:15:23 -0000 1.1
@@ -0,0 +1,256 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+BPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+ return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+
+# Common definition of constellations for Tx and Rx
+constellation = {
+ 2 : make_constellation(2), # BPSK
+ 4 : make_constellation(4), # QPSK
+ 8 : make_constellation(8) # 8PSK
+ }
+
+if 0:
+ print "const(2) ="
+ pprint(constellation[2])
+ print "const(4) ="
+ pprint(constellation[4])
+ print "const(8) ="
+ pprint(constellation[8])
+
+
+if _use_gray_code:
+ # -----------------------
+ # Do Gray code
+ # -----------------------
+ # binary to gray coding
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 7, 6, 4, 5)
+ }
+
+ # gray to binary
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 6, 7, 5, 4)
+ }
+else:
+ # -----------------------
+ # Don't Gray code
+ # -----------------------
+ # identity mapping
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+ # identity mapping
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# mPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class bpsk_mod(gr.hier_block):
+
+ def __init__(self, fg, spb, excess_bw):
+ """
+ Hierarchical block for RRC-filtered BPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ """
+ if not isinstance(spb, int) or spb < 2:
+ raise TypeError, "sbp must be an integer >= 2"
+ self.spb = spb
+
+ ntaps = 11 * spb
+
+ bits_per_symbol = self.bits_per_baud()
+ arity = pow(2,bits_per_symbol)
+ print "bits_per_symbol =", bits_per_symbol
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+ self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+ # pulse shaping filter
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ spb, # gain (spb since we're interpolating by spb)
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+ # Connect
+ fg.connect(self.bytes2chunks, self.chunks2symbols, self.rrc_filter)
+
+ if 1:
+ fg.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an
instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static
method. RTFM
+
+
+class bpsk_demod__coherent_detection_of_psk(gr.hier_block):
+ def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05):
+ """
+ Hierarchical block for RRC-filtered BPSK demodulation
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param costas_alpha: loop filter gain
+ @type costas_alphas: float
+ @param gain_mu:
+ @type gain_mu: float
+ """
+ if spb < 2:
+ raise TypeError, "sbp must be >= 2"
+ self.spb = spb
+
+ bits_per_symbol = self.bits_per_baud()
+ arity = pow(2,bits_per_symbol)
+ print "bits_per_symbol =", bits_per_symbol
+
+ # Automatic gain control
+ self.preamp = gr.multiply_const_cc(10e-5)
+ self.agc = gr.agc_cc(1e-3, 1, 1)
+
+ # Costas loop (carrier tracking)
+ # FIXME: need to decide how to handle this more generally; do we pull
it from higher layer?
+ costas_order = 2
+ costas_alpha *= 15 # 2nd order loop needs more gain
+ beta = .25 * costas_alpha * costas_alpha
+ self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05,
costas_order)
+
+ # RRC data filter
+ ntaps = 11 * spb
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ 1.0, # gain
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+ # symbol clock recovery
+ omega = spb
+ gain_omega = .25 * gain_mu * gain_mu
+ omega_rel_limit = 0.5
+ mu = 0.05
+ gain_mu = 0.1
+ self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+ mu, gain_mu,
omega_rel_limit)
+
+ # find closest constellation point
+ #rot = .707 + .707j
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, constellation[arity])
+ print "rotated_const =", rotated_const
+
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+ self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+ fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ self.slicer, self.gray_decoder, self.unpack)
+
+ # Debug sinks
+ if 1:
+ fg.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+ fg.connect(self.costas_loop,
+ gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+ fg.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+ fg.connect(self.clock_recovery,
+ gr.file_sink(gr.sizeof_gr_complex,
"clock_recovery.dat"))
+ fg.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "slicer.dat"))
+ fg.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.preamp, self.unpack)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an
instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static
method. RTFM
+
+
+bpsk_demod = bpsk_demod__coherent_detection_of_psk
+
Index: dbpsk.py
===================================================================
RCS file: dbpsk.py
diff -N dbpsk.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ dbpsk.py 28 Jun 2006 18:15:23 -0000 1.1
@@ -0,0 +1,282 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+differential BPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+ return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+
+# Common definition of constellations for Tx and Rx
+constellation = {
+ 2 : make_constellation(2), # BPSK
+ 4 : make_constellation(4), # QPSK
+ 8 : make_constellation(8) # 8PSK
+ }
+
+if 0:
+ print "const(2) ="
+ pprint(constellation[2])
+ print "const(4) ="
+ pprint(constellation[4])
+ print "const(8) ="
+ pprint(constellation[8])
+
+
+if _use_gray_code:
+ # -----------------------
+ # Do Gray code
+ # -----------------------
+ # binary to gray coding
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 7, 6, 4, 5)
+ }
+
+ # gray to binary
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 6, 7, 5, 4)
+ }
+else:
+ # -----------------------
+ # Don't Gray code
+ # -----------------------
+ # identity mapping
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+ # identity mapping
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# BPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class dbpsk_mod(gr.hier_block):
+
+ def __init__(self, fg, spb, excess_bw):
+ """
+ Hierarchical block for RRC-filtered QPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ """
+ if not isinstance(spb, int) or spb < 2:
+ raise TypeError, "sbp must be an integer >= 2"
+ self.spb = spb
+
+ ntaps = 11 * spb
+
+ bits_per_symbol = self.bits_per_baud()
+ arity = pow(2,bits_per_symbol)
+ self.bits_per_symbol = bits_per_symbol
+ print "bits_per_symbol =", bits_per_symbol
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+ if True:
+ self.gray_coder = gr.map_bb(binary_to_gray[arity])
+ else:
+ self.gray_coder = None
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+ # pulse shaping filter
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ spb, # gain (spb since we're interpolating by spb)
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+ # Connect
+ if self.gray_coder:
+ fg.connect(self.bytes2chunks, self.gray_coder)
+ t = self.gray_coder
+ else:
+ t = self.bytes2chunks
+
+ fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter)
+
+ if 1:
+ fg.connect(self.gray_coder,
+ gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+ fg.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an
instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static
method. RTFM
+
+
+
+class
dbpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block):
+ def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05):
+ """
+ Hierarchical block for RRC-filtered BPSK demodulation
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param costas_alpha: loop filter gain
+ @type costas_alphas: float
+ @param gain_mu:
+ @type gain_mu: float
+ """
+ if spb < 2:
+ raise TypeError, "sbp must be >= 2"
+ self.spb = spb
+
+ bits_per_symbol = self.bits_per_baud()
+ arity = pow(2,bits_per_symbol)
+ print "bits_per_symbol =", bits_per_symbol
+
+ # Automatic gain control
+ self.preamp = gr.multiply_const_cc(10e-5)
+ self.agc = gr.agc_cc(1e-3, 1, 1)
+
+ # Costas loop (carrier tracking)
+ # FIXME: need to decide how to handle this more generally; do we pull
it from higher layer?
+ costas_order = 2
+ costas_alpha *= 15 # 2nd order loop needs more gain
+ beta = .25 * costas_alpha * costas_alpha
+ self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05,
costas_order)
+
+ # RRC data filter
+ ntaps = 11 * spb
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ 1.0, # gain
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+ # symbol clock recovery
+ omega = spb
+ gain_omega = .25 * gain_mu * gain_mu
+ omega_rel_limit = 0.5
+ mu = 0.05
+ gain_mu = 0.1
+ self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+ mu, gain_mu,
omega_rel_limit)
+
+ # find closest constellation point
+ #rot = .707 + .707j
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, constellation[arity])
+ print "rotated_const =", rotated_const
+
+ self.diffdec = gr.diff_phasor_cc()
+ #self.diffdec = gr.diff_decoder_bb(arity)
+
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+ self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+ fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ self.diffdec, self.slicer, self.gray_decoder, self.unpack)
+ #fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ # self.slicer, self.diffdec, self.gray_decoder, self.unpack)
+
+ # Debug sinks
+ if 1:
+ fg.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+ fg.connect(self.costas_loop,
+ gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+ fg.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+ fg.connect(self.clock_recovery,
+ gr.file_sink(gr.sizeof_gr_complex,
"clock_recovery.dat"))
+ fg.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "slicer.dat"))
+ fg.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat"))
+ #fg.connect(self.diffdec,
+ # gr.file_sink(gr.sizeof_char, "diffdec.dat"))
+ fg.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.preamp, self.unpack)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an
instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static
method. RTFM
+
+
+dbpsk_demod = dbpsk_demod__coherent_detection_of_differentially_encoded_psk
+
Index: dqpsk.py
===================================================================
RCS file: dqpsk.py
diff -N dqpsk.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ dqpsk.py 28 Jun 2006 18:15:23 -0000 1.1
@@ -0,0 +1,280 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+differential QPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+ return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+
+# Common definition of constellations for Tx and Rx
+constellation = {
+ 2 : make_constellation(2), # BPSK
+ 4 : make_constellation(4), # QPSK
+ 8 : make_constellation(8) # 8PSK
+ }
+
+if 0:
+ print "const(2) ="
+ pprint(constellation[2])
+ print "const(4) ="
+ pprint(constellation[4])
+ print "const(8) ="
+ pprint(constellation[8])
+
+
+if _use_gray_code:
+ # -----------------------
+ # Do Gray code
+ # -----------------------
+ # binary to gray coding
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 7, 6, 4, 5)
+ }
+
+ # gray to binary
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 6, 7, 5, 4)
+ }
+else:
+ # -----------------------
+ # Don't Gray code
+ # -----------------------
+ # identity mapping
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+ # identity mapping
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class dqpsk_mod(gr.hier_block):
+
+ def __init__(self, fg, spb, excess_bw):
+ """
+ Hierarchical block for RRC-filtered QPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ """
+ if not isinstance(spb, int) or spb < 2:
+ raise TypeError, "sbp must be an integer >= 2"
+ self.spb = spb
+
+ ntaps = 11 * spb
+
+ bits_per_symbol = self.bits_per_baud()
+ arity = pow(2,bits_per_symbol)
+ print "bits_per_symbol =", bits_per_symbol
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+ if True:
+ self.gray_coder = gr.map_bb(binary_to_gray[arity])
+ else:
+ self.gray_coder = None
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+ # pulse shaping filter
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ spb, # gain (spb since we're interpolating by spb)
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+ # Connect
+ if self.gray_coder:
+ fg.connect(self.bytes2chunks, self.gray_coder)
+ t = self.gray_coder
+ else:
+ t = self.bytes2chunks
+
+ fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter)
+
+ if 1:
+ fg.connect(self.gray_coder,
+ gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+ fg.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an
instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static
method. RTFM
+
+
+
+class
dqpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block):
+ def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05):
+ """
+ Hierarchical block for RRC-filtered QPSK demodulation
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param costas_alpha: loop filter gain
+ @type costas_alphas: float
+ @param gain_mu:
+ @type gain_mu: float
+ """
+ if spb < 2:
+ raise TypeError, "sbp must be >= 2"
+ self.spb = spb
+
+ bits_per_symbol = self.bits_per_baud()
+ arity = pow(2,bits_per_symbol)
+ print "bits_per_symbol =", bits_per_symbol
+
+ # Automatic gain control
+ self.preamp = gr.multiply_const_cc(10e-5)
+ self.agc = gr.agc_cc(1e-3, 1, 1)
+
+ # Costas loop (carrier tracking)
+ # FIXME: need to decide how to handle this more generally; do we pull
it from higher layer?
+ costas_order = 4
+ beta = .25 * costas_alpha * costas_alpha
+ self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05,
costas_order)
+
+ # RRC data filter
+ ntaps = 11 * spb
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ 1.0, # gain
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+ # symbol clock recovery
+ omega = spb
+ gain_omega = .25 * gain_mu * gain_mu
+ omega_rel_limit = 0.5
+ mu = 0.05
+ gain_mu = 0.1
+ self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+ mu, gain_mu,
omega_rel_limit)
+
+ # find closest constellation point
+ #rot = .707 + .707j
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, constellation[arity])
+ print "rotated_const =", rotated_const
+
+ self.diffdec = gr.diff_phasor_cc()
+ #self.diffdec = gr.diff_decoder_bb(arity)
+
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+ self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+ fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ self.diffdec, self.slicer, self.gray_decoder, self.unpack)
+ #fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ # self.slicer, self.diffdec, self.gray_decoder, self.unpack)
+
+ # Debug sinks
+ if 1:
+ fg.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+ fg.connect(self.costas_loop,
+ gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+ fg.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+ fg.connect(self.clock_recovery,
+ gr.file_sink(gr.sizeof_gr_complex,
"clock_recovery.dat"))
+ fg.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "slicer.dat"))
+ fg.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat"))
+ #fg.connect(self.diffdec,
+ # gr.file_sink(gr.sizeof_char, "diffdec.dat"))
+ fg.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.preamp, self.unpack)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an
instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static
method. RTFM
+
+
+dqpsk_demod = dqpsk_demod__coherent_detection_of_differentially_encoded_psk
+
Index: pkt.py
===================================================================
RCS file: pkt.py
diff -N pkt.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ pkt.py 28 Jun 2006 18:15:23 -0000 1.1
@@ -0,0 +1,156 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from math import pi
+import Numeric
+
+from gnuradio import gr, packet_utils
+import gnuradio.gr.gr_threading as _threading
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# mod/demod with packets as i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class mod_pkts(gr.hier_block):
+ """
+ Wrap an arbitrary digital modulator in our packet handling framework.
+
+ Send packets by calling send_pkt
+ """
+ def __init__(self, fg, modulator, access_code=None, msgq_limit=2,
pad_for_usrp=True):
+ """
+ Hierarchical block for sending packets
+
+ Packets to be sent are enqueued by calling send_pkt.
+ The output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param modulator: instance of modulator class (gr_block or hier_block)
+ @type modulator: complex baseband out
+ @param access_code: AKA sync vector
+ @type access_code: string of 1's and 0's between 1 and 64 long
+ @param msgq_limit: maximum number of messages in message queue
+ @type msgq_limit: int
+ @param pad_for_usrp: If true, packets are padded such that they end up
a multiple of 128 samples
+
+ See gmsk_mod for remaining parameters
+ """
+ self._modulator = modulator
+ self._pad_for_usrp = pad_for_usrp
+
+ if access_code is None:
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's
and 0's" % (access_code,)
+ self._access_code = access_code
+
+ # accepts messages from the outside world
+ self._pkt_input = gr.message_source(gr.sizeof_char, msgq_limit)
+ fg.connect(self._pkt_input, self._modulator)
+ gr.hier_block.__init__(self, fg, None, self._modulator)
+
+ def send_pkt(self, payload='', eof=False):
+ """
+ Send the payload.
+
+ @param payload: data to send
+ @type payload: string
+ """
+ if eof:
+ msg = gr.message(1) # tell self._pkt_input we're not sending any
more packets
+ else:
+ # print "original_payload =", string_to_hex_list(payload)
+ pkt = packet_utils.make_packet(payload,
+ self._modulator.samples_per_baud(),
+ self._modulator.bits_per_baud(),
+ self._access_code,
+ self._pad_for_usrp)
+ #print "pkt =", string_to_hex_list(pkt)
+ msg = gr.message_from_string(pkt)
+ self._pkt_input.msgq().insert_tail(msg)
+
+
+
+class demod_pkts(gr.hier_block):
+ """
+ Wrap an arbitrary digital demodulator in our packet handling framework.
+
+ The input is complex baseband. When packets are demodulated, they are
passed to the
+ app via the callback.
+ """
+
+ def __init__(self, fg, demodulator, access_code=None, callback=None,
threshold=-1):
+ """
+ Hierarchical block for demodulating and deframing packets.
+
+ The input is the complex modulated signal at baseband.
+ Demodulated packets are sent to the handler.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param demodulator: instance of demodulator class (gr_block or
hier_block)
+ @type demodulator: complex baseband in
+ @param access_code: AKA sync vector
+ @type access_code: string of 1's and 0's
+ @param callback: function of two args: ok, payload
+ @type callback: ok: bool; payload: string
+ @param threshold: detect access_code with up to threshold bits wrong
(-1 -> use default)
+ @type threshold: int
+ """
+
+ self._demodulator = demodulator
+ if access_code is None:
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's
and 0's" % (access_code,)
+ self._access_code = access_code
+
+ if threshold == -1:
+ threshold = 12 # FIXME raise exception
+
+ self._rcvd_pktq = gr.msg_queue() # holds packets from the PHY
+ self.correlator = gr.correlate_access_code_bb(access_code, threshold)
+
+ self.framer_sink = gr.framer_sink_1(self._rcvd_pktq)
+ fg.connect(self._demodulator, self.correlator, self.framer_sink)
+
+ gr.hier_block.__init__(self, fg, self._demodulator, None)
+ self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+
+
+class _queue_watcher_thread(_threading.Thread):
+ def __init__(self, rcvd_pktq, callback):
+ _threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.rcvd_pktq = rcvd_pktq
+ self.callback = callback
+ self.keep_running = True
+ self.start()
+
+
+ def run(self):
+ while self.keep_running:
+ msg = self.rcvd_pktq.delete_head()
+ ok, payload = packet_utils.unmake_packet(msg.to_string())
+ if self.callback:
+ self.callback(ok, payload)
Index: qpsk.py
===================================================================
RCS file: qpsk.py
diff -N qpsk.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ qpsk.py 28 Jun 2006 18:15:23 -0000 1.1
@@ -0,0 +1,418 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+PSK and differential PSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+ return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+
+# Common definition of constellations for Tx and Rx
+constellation = {
+ 2 : make_constellation(2), # BPSK
+ 4 : make_constellation(4), # QPSK
+ 8 : make_constellation(8) # 8PSK
+ }
+
+if 0:
+ print "const(2) ="
+ pprint(constellation[2])
+ print "const(4) ="
+ pprint(constellation[4])
+ print "const(8) ="
+ pprint(constellation[8])
+
+
+if _use_gray_code:
+ # -----------------------
+ # Do Gray code
+ # -----------------------
+ # binary to gray coding
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 7, 6, 4, 5)
+ }
+
+ # gray to binary
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 3, 2),
+ 8 : (0, 1, 3, 2, 6, 7, 5, 4)
+ }
+else:
+ # -----------------------
+ # Don't Gray code
+ # -----------------------
+ # identity mapping
+ binary_to_gray = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+ # identity mapping
+ gray_to_binary = {
+ 2 : (0, 1),
+ 4 : (0, 1, 2, 3),
+ 8 : (0, 1, 2, 3, 4, 5, 6, 7)
+ }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# mPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class mpsk_mod(gr.hier_block):
+
+ def __init__(self, fg, spb, arity, excess_bw, diff=False):
+ """
+ Hierarchical block for RRC-filtered PSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param arity: whick PSK: 2, 4, 8
+ @type arity: int in {2, 4, 8}
+ @param diff: differential PSK if true
+ @type diff: bool
+ """
+ if not isinstance(spb, int) or spb < 2:
+ raise TypeError, "sbp must be an integer >= 2"
+ self.spb = spb
+
+ if not arity in (2, 4):
+ raise ValueError, "n must be 2, 4, or 8"
+
+ ntaps = 11 * spb
+
+ bits_per_symbol = int(gru.log2(arity))
+ self.bits_per_symbol = bits_per_symbol
+ print "bits_per_symbol =", bits_per_symbol
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+ if True or arity > 2:
+ self.gray_coder = gr.map_bb(binary_to_gray[arity])
+ else:
+ self.gray_coder = None
+
+ if diff:
+ self.diffenc = gr.diff_encoder_bb(arity)
+ else:
+ self.diffenc = None
+
+ self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+ # pulse shaping filter
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ spb, # gain (spb since we're interpolating by spb)
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+ # Connect
+ if self.gray_coder:
+ fg.connect(self.bytes2chunks, self.gray_coder)
+ t = self.gray_coder
+ else:
+ t = self.bytes2chunks
+
+ if diff:
+ fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter)
+ else:
+ fg.connect(t, self.chunks2symbols, self.rrc_filter)
+
+ if 1:
+ fg.connect(self.gray_coder,
+ gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+ if diff:
+ fg.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self):
+ return self.bits_per_symbol
+
+
+class
mpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block):
+ def __init__(self, fg, spb, arity, excess_bw, diff=False,
costas_alpha=0.005, gain_mu=0.05):
+ """
+ Hierarchical block for RRC-filtered PSK demodulation
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param arity: whick PSK: 2, 4, 8
+ @type arity: int in {2, 4, 8}
+ @param diff: differential PSK if true
+ @type diff: bool
+ @param costas_alpha: loop filter gain
+ @type costas_alphas: float
+ @param gain_mu:
+ @type gain_mu: float
+ """
+ if spb < 2:
+ raise TypeError, "sbp must be >= 2"
+ self.spb = spb
+
+ if not arity in (2, 4):
+ raise ValueError, "n must be 2 or 4"
+
+ if not diff and arity==4:
+ raise NotImplementedError, "non-differential QPSK not supported
yet"
+
+ bits_per_symbol = int(gru.log2(arity))
+ print "bits_per_symbol =", bits_per_symbol
+
+ # Automatic gain control
+ self.agc = gr.agc_cc(1e-3, 1, 1)
+
+ # Costas loop (carrier tracking)
+ # FIXME: need to decide how to handle this more generally; do we pull
it from higher layer?
+ if arity == 2:
+ costas_order = 2
+ costas_alpha *= 15 # 2nd order loop needs more gain
+ else:
+ costas_order = 4
+ beta = .25 * costas_alpha * costas_alpha
+ self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05,
costas_order)
+
+ # RRC data filter
+ ntaps = 11 * spb
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ 1.0, # gain
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+ # symbol clock recovery
+ omega = spb
+ gain_omega = .25 * gain_mu * gain_mu
+ omega_rel_limit = 0.5
+ mu = 0.05
+ gain_mu = 0.1
+ self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+ mu, gain_mu,
omega_rel_limit)
+
+ # find closest constellation point
+ #rot = .707 + .707j
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, constellation[arity])
+ print "rotated_const =", rotated_const
+
+ if(diff):
+ self.diffdec = gr.diff_phasor_cc()
+ #self.diffdec = gr.diff_decoder_bb(arity)
+
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+ self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+ if(diff):
+ fg.connect(self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ self.diffdec, self.slicer, self.gray_decoder,
self.unpack)
+ else:
+ fg.connect(self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ self.slicer, self.gray_decoder, self.unpack)
+
+ #fg.connect(self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ # self.slicer, self.diffdec, self.gray_decoder, self.unpack)
+
+ # Debug sinks
+ if 1:
+ fg.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+ fg.connect(self.costas_loop,
+ gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+ fg.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+ fg.connect(self.clock_recovery,
+ gr.file_sink(gr.sizeof_gr_complex,
"clock_recovery.dat"))
+ fg.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "slicer.dat"))
+ if(diff):
+ fg.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat"))
+ #fg.connect(self.diffdec,
+ # gr.file_sink(gr.sizeof_char, "diffdec.dat"))
+ fg.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.agc, self.unpack)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self):
+ return self.bits_per_symbol
+
+
+#########################################################################
+
+class
mpsk_demod__coherent_detection_of_nondifferentially_encoded_psk(gr.hier_block):
+ def __init__(self, fg, spb, arity, excess_bw, diff=False,
costas_alpha=0.005, gain_mu=0.05):
+ """
+ Hierarchical block for RRC-filtered PSK demodulation
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param arity: whick PSK: 2, 4, 8
+ @type arity: int in {2, 4, 8}
+ @param diff: differential PSK if true
+ @type diff: bool
+ @param costas_alpha: loop filter gain
+ @type costas_alphas: float
+ @param gain_mu:
+ @type gain_mu: float
+ """
+ if spb < 2:
+ raise TypeError, "sbp must be >= 2"
+ self.spb = spb
+
+ if not arity in (2, 4):
+ raise ValueError, "n must be 2 or 4"
+
+ bits_per_symbol = int(gru.log2(arity))
+ print "bits_per_symbol =", bits_per_symbol
+
+ # Automatic gain control
+ self.agc = gr.agc_cc(1e-3, 1, 1)
+
+ # Costas loop (carrier tracking)
+ # FIXME: need to decide how to handle this more generally; do we pull
it from higher layer?
+ if arity == 2:
+ costas_order = 2
+ costas_alpha *= 15 # 2nd order loop needs more gain
+ else:
+ costas_order = 4
+ beta = .25 * costas_alpha * costas_alpha
+ self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05,
costas_order)
+
+ # RRC data filter
+ ntaps = 11 * spb
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ 1.0, # gain
+ spb, # sampling rate
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+
+ self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+ # symbol clock recovery
+ omega = spb
+ gain_omega = .25 * gain_mu * gain_mu
+ omega_rel_limit = 0.5
+ mu = 0.05
+ gain_mu = 0.1
+ self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+ mu, gain_mu,
omega_rel_limit)
+
+ # find closest constellation point
+ #rot = .707 + .707j
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, constellation[arity])
+ print "rotated_const =", rotated_const
+
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+ self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+ fg.connect(self.agc, self.costas_loop, self.rrc_filter,
self.clock_recovery,
+ self.slicer, self.gray_decoder, self.unpack)
+
+ # Debug sinks
+ if 1:
+ fg.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+ fg.connect(self.costas_loop,
+ gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+ fg.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+ fg.connect(self.clock_recovery,
+ gr.file_sink(gr.sizeof_gr_complex,
"clock_recovery.dat"))
+ fg.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "slicer.dat"))
+ fg.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.agc, self.unpack)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self):
+ return self.bits_per_symbol
+
+
+mpsk_demod = mpsk_demod__coherent_detection_of_differentially_encoded_psk
+#mpsk_demod = mpsk_demod__coherent_detection_of_nondifferentially_encoded_psk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] gnuradio-examples/python/gmsk2 benchmark_gmsk_t...,
Thomas W. Rondeau <=