summaryrefslogtreecommitdiff
path: root/gr-digital
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital')
-rw-r--r--gr-digital/.gitignore3
-rw-r--r--gr-digital/Makefile.am31
-rw-r--r--gr-digital/README4
-rw-r--r--gr-digital/apps/.gitignore2
-rw-r--r--gr-digital/apps/Makefile.am33
-rw-r--r--gr-digital/gnuradio-digital.pc.in11
-rw-r--r--gr-digital/grc/.gitignore2
-rw-r--r--gr-digital/grc/Makefile.am37
-rw-r--r--gr-digital/grc/digital_block_tree.xml47
-rw-r--r--gr-digital/grc/digital_cma_equalizer_cc.xml42
-rw-r--r--gr-digital/grc/digital_costas_loop_cc.xml44
-rw-r--r--gr-digital/grc/digital_dxpsk_demod.xml167
-rw-r--r--gr-digital/grc/digital_dxpsk_mod.xml121
-rw-r--r--gr-digital/grc/digital_kurtotic_equalizer_cc.xml31
-rw-r--r--gr-digital/grc/digital_lms_dd_equalizer_cc.xml41
-rw-r--r--gr-digital/grc/digital_psk_demod.xml158
-rw-r--r--gr-digital/grc/digital_psk_mod.xml130
-rw-r--r--gr-digital/grc/digital_qam_demod.xml158
-rw-r--r--gr-digital/grc/digital_qam_mod.xml130
-rw-r--r--gr-digital/lib/.gitignore4
-rw-r--r--gr-digital/lib/Makefile.am51
-rw-r--r--gr-digital/lib/digital_cma_equalizer_cc.cc46
-rw-r--r--gr-digital/lib/digital_cma_equalizer_cc.h101
-rw-r--r--gr-digital/lib/digital_constellation.cc468
-rw-r--r--gr-digital/lib/digital_constellation.h352
-rw-r--r--gr-digital/lib/digital_constellation_decoder_cb.cc77
-rw-r--r--gr-digital/lib/digital_constellation_decoder_cb.h64
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.cc131
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.h149
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.cc201
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.h150
-rw-r--r--gr-digital/lib/digital_kurtotic_equalizer_cc.cc51
-rw-r--r--gr-digital/lib/digital_kurtotic_equalizer_cc.h111
-rw-r--r--gr-digital/lib/digital_lms_dd_equalizer_cc.cc85
-rw-r--r--gr-digital/lib/digital_lms_dd_equalizer_cc.h116
-rw-r--r--gr-digital/lib/digital_metric_type.h31
-rw-r--r--gr-digital/python/.gitignore3
-rw-r--r--gr-digital/python/Makefile.am54
-rw-r--r--gr-digital/python/__init__.py32
-rw-r--r--gr-digital/python/bpsk.py98
-rw-r--r--gr-digital/python/d8psk.py369
-rw-r--r--gr-digital/python/dbpsk.py370
-rw-r--r--gr-digital/python/dqpsk.py374
-rw-r--r--gr-digital/python/generic_mod_demod.py397
-rw-r--r--gr-digital/python/modulation_utils2.py101
-rw-r--r--gr-digital/python/ofdm.py295
-rw-r--r--gr-digital/python/pkt.py184
-rw-r--r--gr-digital/python/psk.py94
-rw-r--r--gr-digital/python/psk2.py123
-rwxr-xr-xgr-digital/python/qa_constellation.py205
-rwxr-xr-xgr-digital/python/qa_constellation_receiver.py136
-rwxr-xr-xgr-digital/python/qa_costas_loop_cc.py156
-rwxr-xr-xgr-digital/python/qa_digital.py35
-rw-r--r--gr-digital/python/qam.py227
-rw-r--r--gr-digital/python/qpsk.py79
-rw-r--r--gr-digital/python/run_tests.in10
-rw-r--r--gr-digital/python/utils/.gitignore3
-rw-r--r--gr-digital/python/utils/Makefile.am34
-rw-r--r--gr-digital/python/utils/__init__.py21
-rw-r--r--gr-digital/python/utils/alignment.py139
-rw-r--r--gr-digital/python/utils/gray_code.py66
-rw-r--r--gr-digital/python/utils/mod_codes.py33
-rw-r--r--gr-digital/swig/.gitignore9
-rw-r--r--gr-digital/swig/Makefile.am75
-rw-r--r--gr-digital/swig/Makefile.swig.gen145
-rw-r--r--gr-digital/swig/digital_cma_equalizer_cc.i44
-rw-r--r--gr-digital/swig/digital_constellation.i171
-rw-r--r--gr-digital/swig/digital_constellation_decoder_cb.i38
-rw-r--r--gr-digital/swig/digital_constellation_receiver_cb.i47
-rw-r--r--gr-digital/swig/digital_costas_loop_cc.i44
-rw-r--r--gr-digital/swig/digital_kurtotic_equalizer_cc.i40
-rw-r--r--gr-digital/swig/digital_lms_dd_equalizer_cc.i46
-rw-r--r--gr-digital/swig/digital_swig.i50
-rw-r--r--gr-digital/swig/gnuradio/.gitignore2
-rw-r--r--gr-digital/swig/gnuradio/digital.scm28
-rw-r--r--gr-digital/swig/run_guile_tests.in14
76 files changed, 7771 insertions, 0 deletions
diff --git a/gr-digital/.gitignore b/gr-digital/.gitignore
new file mode 100644
index 000000000..37c287f40
--- /dev/null
+++ b/gr-digital/.gitignore
@@ -0,0 +1,3 @@
+/Makefile
+/Makefile.in
+gnuradio-digital.pc
diff --git a/gr-digital/Makefile.am b/gr-digital/Makefile.am
new file mode 100644
index 000000000..62c40f2df
--- /dev/null
+++ b/gr-digital/Makefile.am
@@ -0,0 +1,31 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+SUBDIRS = lib
+
+if PYTHON
+SUBDIRS += swig python apps grc
+endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+dist_pkgconfig_DATA = gnuradio-digital.pc
diff --git a/gr-digital/README b/gr-digital/README
new file mode 100644
index 000000000..af2005c97
--- /dev/null
+++ b/gr-digital/README
@@ -0,0 +1,4 @@
+This GNU Radio component for implementing digitial modulators and demodulators.
+
+
+FIXME: just fixme. \ No newline at end of file
diff --git a/gr-digital/apps/.gitignore b/gr-digital/apps/.gitignore
new file mode 100644
index 000000000..282522db0
--- /dev/null
+++ b/gr-digital/apps/.gitignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/gr-digital/apps/Makefile.am b/gr-digital/apps/Makefile.am
new file mode 100644
index 000000000..7373a0719
--- /dev/null
+++ b/gr-digital/apps/Makefile.am
@@ -0,0 +1,33 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+if PYTHON
+
+dist_bin_SCRIPTS =
+
+noinst_PYTHON =
+
+endif
+
+EXTRA_DIST +=
+
diff --git a/gr-digital/gnuradio-digital.pc.in b/gr-digital/gnuradio-digital.pc.in
new file mode 100644
index 000000000..6c0a7ccf8
--- /dev/null
+++ b/gr-digital/gnuradio-digital.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: gnuradio-digital
+Description: GNU Radio blocks for digital communications
+Requires: gnuradio-core
+Version: @LIBVER@
+Libs: -L${libdir} -lgnuradio-digital
+Cflags: -I${includedir}
diff --git a/gr-digital/grc/.gitignore b/gr-digital/grc/.gitignore
new file mode 100644
index 000000000..3dda72986
--- /dev/null
+++ b/gr-digital/grc/.gitignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/gr-digital/grc/Makefile.am b/gr-digital/grc/Makefile.am
new file mode 100644
index 000000000..d271ca06a
--- /dev/null
+++ b/gr-digital/grc/Makefile.am
@@ -0,0 +1,37 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+grcblocksdir = $(grc_blocksdir)
+
+dist_grcblocks_DATA = \
+ digital_block_tree.xml \
+ digital_costas_loop_cc.xml \
+ digital_cma_equalizer_cc.xml \
+ digital_lms_dd_equalizer_cc.xml \
+ digital_kurtotic_equalizer_cc.xml \
+ digital_dxpsk_mod.xml \
+ digital_dxpsk_demod.xml \
+ digital_psk_mod.xml \
+ digital_psk_demod.xml \
+ digital_qam_mod.xml \
+ digital_qam_demod.xml
diff --git a/gr-digital/grc/digital_block_tree.xml b/gr-digital/grc/digital_block_tree.xml
new file mode 100644
index 000000000..1be4110e1
--- /dev/null
+++ b/gr-digital/grc/digital_block_tree.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2011 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 3, 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., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<!--
+###################################################
+##Block Tree for GR Digital blocks.
+###################################################
+ -->
+<cat>
+ <name></name> <!-- Blank for Root Name -->
+ <cat>
+ <name>Digital</name>
+ <block>digital_costas_loop_cc</block>
+ <block>digital_cma_equalizer_cc</block>
+ <block>digital_lms_dd_equalizer_cc</block>
+ <block>digital_kurtotic_equalizer_cc</block>
+ </cat>
+ <cat>
+ <name>Digital Modulators</name>
+ <block>digital_dxpsk_mod</block>
+ <block>digital_dxpsk_demod</block>
+ <block>digital_psk_mod</block>
+ <block>digital_psk_demod</block>
+ <block>digital_qam_mod</block>
+ <block>digital_qam_demod</block>
+ </cat>
+</cat>
diff --git a/gr-digital/grc/digital_cma_equalizer_cc.xml b/gr-digital/grc/digital_cma_equalizer_cc.xml
new file mode 100644
index 000000000..118c18e29
--- /dev/null
+++ b/gr-digital/grc/digital_cma_equalizer_cc.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## CMA Equalizer
+###################################################
+ -->
+<block>
+ <name>CMA Equalizer</name>
+ <key>digital_cma_equalizer_cc</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.cma_equalizer_cc($num_taps, $modulus, $mu, $sps)</make>
+ <callback>set_gain($mu)</callback>
+ <callback>set_modulus($modulus)</callback>
+ <param>
+ <name>Num. Taps</name>
+ <key>num_taps</key>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Modulus</name>
+ <key>modulus</key>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Gain</name>
+ <key>mu</key>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Samples per Symbol</name>
+ <key>sps</key>
+ <type>int</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_costas_loop_cc.xml b/gr-digital/grc/digital_costas_loop_cc.xml
new file mode 100644
index 000000000..087535b87
--- /dev/null
+++ b/gr-digital/grc/digital_costas_loop_cc.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Costas Loop
+###################################################
+ -->
+<block>
+ <name>Costas Loop</name>
+ <key>digital_costas_loop_cc</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.costas_loop_cc($eta, $w, $order)</make>
+ <callback>set_damping_factor($eta)</callback>
+ <callback>set_natural_freq($w)</callback>
+ <param>
+ <name>Damping Factor</name>
+ <key>eta</key>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Natural Frequency</name>
+ <key>w</key>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Order</name>
+ <key>order</key>
+ <type>int</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+
+ <!-- Optional Outputs -->
+ <source>
+ <name>frequency</name>
+ <type>float</type>
+ <optional>1</optional>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_dxpsk_demod.xml b/gr-digital/grc/digital_dxpsk_demod.xml
new file mode 100644
index 000000000..5e6dced22
--- /dev/null
+++ b/gr-digital/grc/digital_dxpsk_demod.xml
@@ -0,0 +1,167 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<!--
+###################################################
+##DPSK2 Mod - 2, 4, 8
+###################################################
+ -->
+<block>
+ <name>DPSK Demod</name>
+ <key>digital_dxpsk_demod</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.$(type)_demod(
+ samples_per_symbol=$samples_per_symbol,
+ excess_bw=$excess_bw,
+ costas_alpha=$costas_alpha,
+ timing_alpha=$timing_alpha,
+ timing_max_dev=$timing_max_dev,
+ gray_code=$gray_code,
+ verbose=$verbose,
+ log=$log,
+ sync_out=$sync_out,
+)</make>
+ <callback>clock_recov.set_alpha($costas_alpha)</callback>
+ <callback>clock_recov.set_beta(0.25*$costas_alpha**2)</callback>
+ <callback>time_recov.set_alpha($timing_alpha)</callback>
+ <param>
+ <name>Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>DBPSK</name>
+ <key>dbpsk</key>
+ </option>
+ <option>
+ <name>DQPSK</name>
+ <key>dqpsk</key>
+ </option>
+ </param>
+ <param>
+ <name>Samples/Symbol</name>
+ <key>samples_per_symbol</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Excess BW</name>
+ <key>excess_bw</key>
+ <value>0.35</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Costas Alpha</name>
+ <key>costas_alpha</key>
+ <value>0.175</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Timing Alpha</name>
+ <key>timing_alpha</key>
+ <value>0.100</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Timing Max Dev</name>
+ <key>timing_max_dev</key>
+ <value>1.5</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Omega Relative Limit</name>
+ <key>omega_relative_limit</key>
+ <value>0.005</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Gray Code</name>
+ <key>gray_code</key>
+ <value>True</value>
+ <type>bool</type>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Verbose</name>
+ <key>verbose</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($verbose) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Logging</name>
+ <key>log</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($log) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Sync Out</name>
+ <key>sync_out</key>
+ <value>False</value>
+ <type>bool</type>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+ <source>
+ <name>sync</name>
+ <type>complex</type>
+ <optional>1</optional>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_dxpsk_mod.xml b/gr-digital/grc/digital_dxpsk_mod.xml
new file mode 100644
index 000000000..5d59f36e0
--- /dev/null
+++ b/gr-digital/grc/digital_dxpsk_mod.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<!--
+###################################################
+##DPSK2 Mod - 2, 4, 8
+###################################################
+ -->
+<block>
+ <name>DPSK Mod</name>
+ <key>digital_dxpsk_mod</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.$(type)_mod(
+ samples_per_symbol=$samples_per_symbol,
+ excess_bw=$excess_bw,
+ gray_code=$gray_code,
+ verbose=$verbose,
+ log=$log)
+ </make>
+ <param>
+ <name>Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>DBPSK</name>
+ <key>dbpsk</key>
+ </option>
+ <option>
+ <name>DQPSK</name>
+ <key>dqpsk</key>
+ </option>
+ <option>
+ <name>D8PSK</name>
+ <key>d8psk</key>
+ </option>
+ </param>
+ <param>
+ <name>Samples/Symbol</name>
+ <key>samples_per_symbol</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Excess BW</name>
+ <key>excess_bw</key>
+ <value>0.35</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Gray Code</name>
+ <key>gray_code</key>
+ <value>True</value>
+ <type>bool</type>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Verbose</name>
+ <key>verbose</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($verbose) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Logging</name>
+ <key>log</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($log) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>byte</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_kurtotic_equalizer_cc.xml b/gr-digital/grc/digital_kurtotic_equalizer_cc.xml
new file mode 100644
index 000000000..8c4a2012d
--- /dev/null
+++ b/gr-digital/grc/digital_kurtotic_equalizer_cc.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## Kurtotic Equalizer
+###################################################
+ -->
+<block>
+ <name>Kurtotic Equalizer</name>
+ <key>digital_kurtotic_equalizer_cc</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.kurtotic_equalizer_cc($num_taps, $mu)</make>
+ <callback>set_gain($mu)</callback>
+ <param>
+ <name>Num. Taps</name>
+ <key>num_taps</key>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Mu</name>
+ <key>mu</key>
+ <type>real</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_lms_dd_equalizer_cc.xml b/gr-digital/grc/digital_lms_dd_equalizer_cc.xml
new file mode 100644
index 000000000..0fd7d523b
--- /dev/null
+++ b/gr-digital/grc/digital_lms_dd_equalizer_cc.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## LMS DD Equalizer
+###################################################
+ -->
+<block>
+ <name>LMS DD Equalizer</name>
+ <key>digital_lms_dd_equalizer_cc</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.lms_dd_equalizer_cc($num_taps, $mu, $sps, $cnst)</make>
+ <callback>set_gain($mu)</callback>
+ <param>
+ <name>Gain</name>
+ <key>mu</key>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Num. Taps</name>
+ <key>num_taps</key>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Samples per Symbol</name>
+ <key>sps</key>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Constellation Object</name>
+ <key>cnst</key>
+ <type>raw</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_psk_demod.xml b/gr-digital/grc/digital_psk_demod.xml
new file mode 100644
index 000000000..b2628ac88
--- /dev/null
+++ b/gr-digital/grc/digital_psk_demod.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<!--
+###################################################
+##PSK Demod
+###################################################
+ -->
+<block>
+ <name>PSK Demod</name>
+ <key>digital_psk_demod</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.psk.psk_demod(
+ constellation_points=$constellation_points,
+ mod_code=$mod_code,
+ differential=$differential,
+ samples_per_symbol=$samples_per_symbol,
+ excess_bw=$excess_bw,
+ freq_alpha=$freq_alpha,
+ timing_alpha=$timing_alpha,
+ timing_max_dev=$timing_max_dev,
+ phase_alpha=$phase_alpha,
+ verbose=$verbose,
+ log=$log,
+ )</make>
+ <param>
+ <name>Number of Constellation Points</name>
+ <key>constellation_points</key>
+ <value>8</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Gray Code</name>
+ <key>mod_code</key>
+ <type>enum</type>
+ <option>
+ <name>Yes</name>
+ <key>gray</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>none</key>
+ </option>
+ </param>
+ <param>
+ <name>Differential Encoding</name>
+ <key>differential</key>
+ <value>True</value>
+ <type>bool</type>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Samples/Symbol</name>
+ <key>samples_per_symbol</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Excess BW</name>
+ <key>excess_bw</key>
+ <value>0.35</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Frequency Alpha</name>
+ <key>freq_alpha</key>
+ <value>0.01</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Timing Alpha</name>
+ <key>timing_alpha</key>
+ <value>0.100</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Timing Max Dev</name>
+ <key>timing_max_dev</key>
+ <value>1.5</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Phase Alpha</name>
+ <key>phase_alpha</key>
+ <value>0.1</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Verbose</name>
+ <key>verbose</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($verbose) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Logging</name>
+ <key>log</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($log) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+ <source>
+ <name>sync</name>
+ <type>complex</type>
+ <optional>1</optional>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_psk_mod.xml b/gr-digital/grc/digital_psk_mod.xml
new file mode 100644
index 000000000..f4566c2b4
--- /dev/null
+++ b/gr-digital/grc/digital_psk_mod.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<!--
+###################################################
+##PSK Mod
+###################################################
+ -->
+<block>
+ <name>PSK Mod</name>
+ <key>digital_psk_mod</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.psk2.psk_mod(
+ constellation_points=$constellation_points,
+ mod_code=$mod_code,
+ differential=$differential,
+ samples_per_symbol=$samples_per_symbol,
+ excess_bw=$excess_bw,
+ verbose=$verbose,
+ log=$log,
+ )</make>
+ <param>
+ <name>Number of Constellation Points</name>
+ <key>constellation_points</key>
+ <value>8</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Gray Code</name>
+ <key>mod_code</key>
+ <type>enum</type>
+ <option>
+ <name>Yes</name>
+ <key>gray</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>none</key>
+ </option>
+ </param>
+ <param>
+ <name>Differential Encoding</name>
+ <key>differential</key>
+ <value>True</value>
+ <type>bool</type>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Samples/Symbol</name>
+ <key>samples_per_symbol</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Excess BW</name>
+ <key>excess_bw</key>
+ <value>0.35</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Verbose</name>
+ <key>verbose</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($verbose) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Logging</name>
+ <key>log</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($log) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+ <source>
+ <name>sync</name>
+ <type>complex</type>
+ <optional>1</optional>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_qam_demod.xml b/gr-digital/grc/digital_qam_demod.xml
new file mode 100644
index 000000000..88b20293e
--- /dev/null
+++ b/gr-digital/grc/digital_qam_demod.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<!--
+###################################################
+##QAM Demod
+###################################################
+ -->
+<block>
+ <name>QAM Demod</name>
+ <key>digital_qam_demod</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.qam.qam_demod(
+ constellation_points=$constellation_points,
+ mod_code=$mod_code,
+ differential=$differential,
+ samples_per_symbol=$samples_per_symbol,
+ excess_bw=$excess_bw,
+ freq_alpha=$freq_alpha,
+ timing_alpha=$timing_alpha,
+ timing_max_dev=$timing_max_dev,
+ phase_alpha=$phase_alpha,
+ verbose=$verbose,
+ log=$log,
+ )</make>
+ <param>
+ <name>Number of Constellation Points</name>
+ <key>constellation_points</key>
+ <value>16</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Gray Code</name>
+ <key>mod_code</key>
+ <type>enum</type>
+ <option>
+ <name>Yes</name>
+ <key>gray</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>none</key>
+ </option>
+ </param>
+ <param>
+ <name>Differential Encoding</name>
+ <key>differential</key>
+ <value>True</value>
+ <type>bool</type>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Samples/Symbol</name>
+ <key>samples_per_symbol</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Excess BW</name>
+ <key>excess_bw</key>
+ <value>0.35</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Frequency Alpha</name>
+ <key>freq_alpha</key>
+ <value>0.01</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Timing Alpha</name>
+ <key>timing_alpha</key>
+ <value>0.100</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Timing Max Dev</name>
+ <key>timing_max_dev</key>
+ <value>1.5</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Phase Alpha</name>
+ <key>phase_alpha</key>
+ <value>0.1</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Verbose</name>
+ <key>verbose</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($verbose) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Logging</name>
+ <key>log</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($log) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+ <source>
+ <name>sync</name>
+ <type>complex</type>
+ <optional>1</optional>
+ </source>
+</block>
diff --git a/gr-digital/grc/digital_qam_mod.xml b/gr-digital/grc/digital_qam_mod.xml
new file mode 100644
index 000000000..87782fe86
--- /dev/null
+++ b/gr-digital/grc/digital_qam_mod.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<!--
+###################################################
+##QAM Mod
+###################################################
+ -->
+<block>
+ <name>QAM Mod</name>
+ <key>digital_qam_mod</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.qam.qam_mod(
+ constellation_points=$constellation_points,
+ mod_code=$mod_code,
+ differential=$differential,
+ samples_per_symbol=$samples_per_symbol,
+ excess_bw=$excess_bw,
+ verbose=$verbose,
+ log=$log,
+ )</make>
+ <param>
+ <name>Number of Constellation Points</name>
+ <key>constellation_points</key>
+ <value>16</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Gray Code</name>
+ <key>mod_code</key>
+ <type>enum</type>
+ <option>
+ <name>Yes</name>
+ <key>gray</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>none</key>
+ </option>
+ </param>
+ <param>
+ <name>Differential Encoding</name>
+ <key>differential</key>
+ <value>True</value>
+ <type>bool</type>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Samples/Symbol</name>
+ <key>samples_per_symbol</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Excess BW</name>
+ <key>excess_bw</key>
+ <value>0.35</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Verbose</name>
+ <key>verbose</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($verbose) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <param>
+ <name>Logging</name>
+ <key>log</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>#if str($log) == 'False' then 'part' else 'none'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+ <source>
+ <name>sync</name>
+ <type>complex</type>
+ <optional>1</optional>
+ </source>
+</block>
diff --git a/gr-digital/lib/.gitignore b/gr-digital/lib/.gitignore
new file mode 100644
index 000000000..1b6114c39
--- /dev/null
+++ b/gr-digital/lib/.gitignore
@@ -0,0 +1,4 @@
+/.libs
+/.deps
+/Makefile
+/Makefile.in
diff --git a/gr-digital/lib/Makefile.am b/gr-digital/lib/Makefile.am
new file mode 100644
index 000000000..4f67614d8
--- /dev/null
+++ b/gr-digital/lib/Makefile.am
@@ -0,0 +1,51 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES)
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ digital_constellation.h \
+ digital_constellation_receiver_cb.h \
+ digital_constellation_decoder_cb.h \
+ digital_costas_loop_cc.h \
+ digital_cma_equalizer_cc.h \
+ digital_lms_dd_equalizer_cc.h \
+ digital_kurtotic_equalizer_cc.h \
+ digital_metric_type.h
+
+lib_LTLIBRARIES = libgnuradio-digital.la
+
+libgnuradio_digital_la_SOURCES = \
+ digital_constellation.cc \
+ digital_constellation_receiver_cb.cc \
+ digital_constellation_decoder_cb.cc \
+ digital_costas_loop_cc.cc \
+ digital_cma_equalizer_cc.cc \
+ digital_lms_dd_equalizer_cc.cc \
+ digital_kurtotic_equalizer_cc.cc
+
+libgnuradio_digital_la_LIBADD = \
+ $(GNURADIO_CORE_LA)
+
+libgnuradio_digital_la_LDFLAGS = $(NO_UNDEFINED) $(LTVERSIONFLAGS)
diff --git a/gr-digital/lib/digital_cma_equalizer_cc.cc b/gr-digital/lib/digital_cma_equalizer_cc.cc
new file mode 100644
index 000000000..c6c46c2d8
--- /dev/null
+++ b/gr-digital/lib/digital_cma_equalizer_cc.cc
@@ -0,0 +1,46 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <digital_cma_equalizer_cc.h>
+#include <cstdio>
+
+digital_cma_equalizer_cc_sptr
+digital_make_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps)
+{
+ return gnuradio::get_initial_sptr(new digital_cma_equalizer_cc(num_taps, modulus,
+ mu, sps));
+}
+
+digital_cma_equalizer_cc::digital_cma_equalizer_cc(int num_taps, float modulus,
+ float mu, int sps)
+ : gr_adaptive_fir_ccc("cma_equalizer_cc", sps,
+ std::vector<gr_complex>(num_taps, gr_complex(0,0)))
+{
+ set_modulus(modulus);
+ set_gain(mu);
+ if (num_taps > 0)
+ d_taps[0] = 1.0;
+}
diff --git a/gr-digital/lib/digital_cma_equalizer_cc.h b/gr-digital/lib/digital_cma_equalizer_cc.h
new file mode 100644
index 000000000..0dd99debd
--- /dev/null
+++ b/gr-digital/lib/digital_cma_equalizer_cc.h
@@ -0,0 +1,101 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_CMA_EQUALIZER_CC_H
+#define INCLUDED_DIGITAL_CMA_EQUALIZER_CC_H
+
+#include <gr_adaptive_fir_ccc.h>
+#include <gr_math.h>
+#include <iostream>
+
+class digital_cma_equalizer_cc;
+typedef boost::shared_ptr<digital_cma_equalizer_cc> digital_cma_equalizer_cc_sptr;
+
+digital_cma_equalizer_cc_sptr
+digital_make_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps);
+
+/*!
+ * \brief Implements constant modulus adaptive filter on complex stream
+ * \ingroup eq_blk
+ *
+ * The error value and tap update equations (for p=2) can be found in:
+ *
+ * D. Godard, "Self-Recovering Equalization and Carrier Tracking in
+ * Two-Dimensional Data Communication Systems," IEEE Transactions on
+ * Communications, Vol. 28, No. 11, pp. 1867 - 1875, 1980,
+ */
+class digital_cma_equalizer_cc : public gr_adaptive_fir_ccc
+{
+private:
+ float d_modulus;
+ float d_mu;
+
+ friend digital_cma_equalizer_cc_sptr digital_make_cma_equalizer_cc(int num_taps,
+ float modulus,
+ float mu,
+ int sps);
+ digital_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps);
+
+protected:
+
+ virtual gr_complex error(const gr_complex &out)
+ {
+ gr_complex error = out*(norm(out) - d_modulus);
+ float re = gr_clip(error.real(), 1.0);
+ float im = gr_clip(error.imag(), 1.0);
+ return gr_complex(re, im);
+ }
+
+ virtual void update_tap(gr_complex &tap, const gr_complex &in)
+ {
+ // Hn+1 = Hn - mu*conj(Xn)*zn*(|zn|^2 - 1)
+ tap -= d_mu*conj(in)*d_error;
+ }
+
+public:
+ float get_gain()
+ {
+ return d_mu;
+ }
+
+ void set_gain(float mu)
+ {
+ if(mu < 0.0f || mu > 1.0f) {
+ throw std::out_of_range("digital_cma_equalizer::set_gain: Gain value must be in [0,1]");
+ }
+ d_mu = mu;
+ }
+
+ float get_modulus()
+ {
+ return d_modulus;
+ }
+
+ void set_modulus(float mod)
+ {
+ if(mod < 0)
+ throw std::out_of_range("digital_cma_equalizer::set_modulus: Modulus value must be >= 0");
+ d_modulus = mod;
+ }
+};
+
+#endif
diff --git a/gr-digital/lib/digital_constellation.cc b/gr-digital/lib/digital_constellation.cc
new file mode 100644
index 000000000..d1f218439
--- /dev/null
+++ b/gr-digital/lib/digital_constellation.cc
@@ -0,0 +1,468 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010, 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_io_signature.h>
+#include <digital_constellation.h>
+#include <digital_metric_type.h>
+#include <gr_math.h>
+#include <gr_complex.h>
+#include <math.h>
+#include <iostream>
+#include <stdlib.h>
+#include <float.h>
+#include <stdexcept>
+
+#define M_TWOPI (2*M_PI)
+#define SQRT_TWO 0.707107
+
+// Base Constellation Class
+
+digital_constellation::digital_constellation (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality) :
+ d_constellation(constellation),
+ d_pre_diff_code(pre_diff_code),
+ d_rotational_symmetry(rotational_symmetry),
+ d_dimensionality(dimensionality)
+{
+ if (pre_diff_code.size() == 0)
+ d_apply_pre_diff_code = false;
+ else if (pre_diff_code.size() != constellation.size())
+ throw std::runtime_error ("The constellation and pre-diff code must be of the same length.");
+ else
+ d_apply_pre_diff_code = true;
+ calc_arity();
+}
+
+digital_constellation::digital_constellation () :
+ d_apply_pre_diff_code(false),
+ d_rotational_symmetry(0),
+ d_dimensionality(1)
+{
+ calc_arity();
+}
+
+//! Returns the constellation points for a symbol value
+void
+digital_constellation::map_to_points(unsigned int value, gr_complex *points)
+{
+ for (unsigned int i=0; i<d_dimensionality; i++)
+ points[i] = d_constellation[value*d_dimensionality + i];
+}
+
+std::vector<gr_complex>
+digital_constellation::map_to_points_v(unsigned int value)
+{
+ std::vector<gr_complex> points_v;
+ points_v.resize(d_dimensionality);
+ map_to_points(value, &(points_v[0]));
+ return points_v;
+}
+
+float
+digital_constellation::get_distance(unsigned int index, const gr_complex *sample)
+{
+ float dist = 0;
+ for (unsigned int i=0; i<d_dimensionality; i++) {
+ dist += norm(sample[i] - d_constellation[index*d_dimensionality + i]);
+ }
+ return dist;
+}
+
+unsigned int
+digital_constellation::get_closest_point(const gr_complex *sample)
+{
+ unsigned int min_index = 0;
+ float min_euclid_dist;
+ float euclid_dist;
+
+ min_euclid_dist = get_distance(0, sample);
+ min_index = 0;
+ for (unsigned int j = 1; j < d_arity; j++){
+ euclid_dist = get_distance(j, sample);
+ if (euclid_dist < min_euclid_dist){
+ min_euclid_dist = euclid_dist;
+ min_index = j;
+ }
+ }
+ return min_index;
+}
+
+unsigned int
+digital_constellation::decision_maker_pe(const gr_complex *sample, float *phase_error)
+{
+ unsigned int index = decision_maker(sample);
+ *phase_error = 0;
+ for (unsigned int d=0; d<d_dimensionality; d++)
+ *phase_error += -arg(sample[d]*conj(d_constellation[index+d]));
+ return index;
+}
+
+/*
+unsigned int digital_constellation::decision_maker_e(const gr_complex *sample, float *error)
+{
+ unsigned int index = decision_maker(sample);
+ *error = 0;
+ for (unsigned int d=0; d<d_dimensionality; d++)
+ *error += sample[d]*conj(d_constellation[index+d]);
+ return index;
+}
+*/
+
+std::vector<gr_complex> digital_constellation::s_points () {
+ if (d_dimensionality != 1)
+ throw std::runtime_error ("s_points only works for dimensionality 1 constellations.");
+ else
+ return d_constellation;
+}
+
+std::vector<std::vector<gr_complex> >
+digital_constellation::v_points ()
+{
+ std::vector<std::vector<gr_complex> > vv_const;
+ vv_const.resize(d_arity);
+ for (unsigned int p=0; p<d_arity; p++) {
+ std::vector<gr_complex> v_const;
+ v_const.resize(d_dimensionality);
+ for (unsigned int d=0; d<d_dimensionality; d++) {
+ v_const[d] = d_constellation[p*d_dimensionality+d];
+ }
+ vv_const[p] = v_const;
+ }
+ return vv_const;
+}
+
+void
+digital_constellation::calc_metric(const gr_complex *sample, float *metric,
+ trellis_metric_type_t type)
+{
+ switch (type){
+ case TRELLIS_EUCLIDEAN:
+ calc_euclidean_metric(sample, metric);
+ break;
+ case TRELLIS_HARD_SYMBOL:
+ calc_hard_symbol_metric(sample, metric);
+ break;
+ case TRELLIS_HARD_BIT:
+ throw std::runtime_error ("Invalid metric type (not yet implemented).");
+ break;
+ default:
+ throw std::runtime_error ("Invalid metric type.");
+ }
+}
+
+void
+digital_constellation::calc_euclidean_metric(const gr_complex *sample, float *metric)
+{
+ for (unsigned int o=0; o<d_arity; o++) {
+ metric[o] = get_distance(o, sample);
+ }
+}
+
+void
+digital_constellation::calc_hard_symbol_metric(const gr_complex *sample, float *metric)
+{
+ float minm = FLT_MAX;
+ unsigned int minmi = 0;
+ for (unsigned int o=0; o<d_arity; o++) {
+ float dist = get_distance(o, sample);
+ if (dist < minm) {
+ minm = dist;
+ minmi = o;
+ }
+ }
+ for(unsigned int o=0; o<d_arity; o++) {
+ metric[o] = (o==minmi?0.0:1.0);
+ }
+}
+
+void
+digital_constellation::calc_arity ()
+{
+ if (d_constellation.size() % d_dimensionality != 0)
+ throw std::runtime_error ("Constellation vector size must be a multiple of the dimensionality.");
+ d_arity = d_constellation.size()/d_dimensionality;
+}
+
+unsigned int
+digital_constellation::decision_maker_v (std::vector<gr_complex> sample)
+{
+ assert(sample.size() == d_dimensionality);
+ return decision_maker (&(sample[0]));
+}
+
+digital_constellation_calcdist_sptr
+digital_make_constellation_calcdist(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality)
+{
+ return digital_constellation_calcdist_sptr(new digital_constellation_calcdist
+ (constellation, pre_diff_code,
+ rotational_symmetry, dimensionality));
+}
+
+digital_constellation_calcdist::digital_constellation_calcdist(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality) :
+ digital_constellation(constellation, pre_diff_code, rotational_symmetry, dimensionality)
+{}
+
+// Chooses points base on shortest distance.
+// Inefficient.
+unsigned int
+digital_constellation_calcdist::decision_maker(const gr_complex *sample)
+{
+ return get_closest_point(sample);
+}
+
+digital_constellation_sector::digital_constellation_sector (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality,
+ unsigned int n_sectors) :
+ digital_constellation(constellation, pre_diff_code, rotational_symmetry, dimensionality),
+ n_sectors(n_sectors)
+{
+}
+
+unsigned int
+digital_constellation_sector::decision_maker (const gr_complex *sample)
+{
+ unsigned int sector;
+ sector = get_sector(sample);
+ return sector_values[sector];
+}
+
+void
+digital_constellation_sector::find_sector_values ()
+{
+ unsigned int i;
+ sector_values.clear();
+ for (i=0; i<n_sectors; i++) {
+ sector_values.push_back(calc_sector_value(i));
+ }
+}
+
+digital_constellation_rect_sptr
+digital_make_constellation_rect(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors)
+{
+ return digital_constellation_rect_sptr(new digital_constellation_rect
+ (constellation, pre_diff_code,
+ rotational_symmetry,
+ real_sectors, imag_sectors,
+ width_real_sectors,
+ width_imag_sectors));
+ }
+
+digital_constellation_rect::digital_constellation_rect (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors) :
+ digital_constellation_sector(constellation, pre_diff_code, rotational_symmetry, 1, real_sectors * imag_sectors),
+ n_real_sectors(real_sectors), n_imag_sectors(imag_sectors),
+ d_width_real_sectors(width_real_sectors), d_width_imag_sectors(width_imag_sectors)
+{
+ find_sector_values();
+}
+
+unsigned int
+digital_constellation_rect::get_sector (const gr_complex *sample)
+{
+ int real_sector, imag_sector;
+ unsigned int sector;
+
+ real_sector = int(real(*sample)/d_width_real_sectors + n_real_sectors/2.0);
+ if(real_sector < 0)
+ real_sector = 0;
+ if(real_sector >= (int)n_real_sectors)
+ real_sector = n_real_sectors-1;
+
+ imag_sector = int(imag(*sample)/d_width_imag_sectors + n_imag_sectors/2.0);
+ if(imag_sector < 0)
+ imag_sector = 0;
+ if(imag_sector >= (int)n_imag_sectors)
+ imag_sector = n_imag_sectors-1;
+
+ sector = real_sector * n_imag_sectors + imag_sector;
+ return sector;
+}
+
+unsigned int
+digital_constellation_rect::calc_sector_value (unsigned int sector)
+{
+ unsigned int real_sector, imag_sector;
+ gr_complex sector_center;
+ unsigned int closest_point;
+ real_sector = float(sector)/n_imag_sectors;
+ imag_sector = sector - real_sector * n_imag_sectors;
+ sector_center = gr_complex((real_sector + 0.5 - n_real_sectors/2.0) * d_width_real_sectors,
+ (imag_sector + 0.5 - n_imag_sectors/2.0) * d_width_imag_sectors);
+ closest_point = get_closest_point(&sector_center);
+ return closest_point;
+}
+
+
+digital_constellation_psk_sptr
+digital_make_constellation_psk(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors)
+{
+ return digital_constellation_psk_sptr(new digital_constellation_psk
+ (constellation, pre_diff_code,
+ n_sectors));
+}
+
+digital_constellation_psk::digital_constellation_psk (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors) :
+ digital_constellation_sector(constellation, pre_diff_code, constellation.size(), 1, n_sectors)
+{
+ find_sector_values();
+}
+
+unsigned int
+digital_constellation_psk::get_sector (const gr_complex *sample)
+{
+ float phase = arg(*sample);
+ float width = M_TWOPI / n_sectors;
+ int sector = floor(phase/width + 0.5);
+ unsigned int u_sector;
+ if (sector < 0)
+ sector += n_sectors;
+ u_sector = sector;
+ return sector;
+}
+
+unsigned int
+digital_constellation_psk::calc_sector_value (unsigned int sector)
+{
+ float phase = sector * M_TWOPI / n_sectors;
+ gr_complex sector_center = gr_complex(cos(phase), sin(phase));
+ unsigned int closest_point = get_closest_point(&sector_center);
+ return closest_point;
+}
+
+
+digital_constellation_bpsk_sptr
+digital_make_constellation_bpsk()
+{
+ return digital_constellation_bpsk_sptr(new digital_constellation_bpsk ());
+}
+
+digital_constellation_bpsk::digital_constellation_bpsk ()
+{
+ d_constellation.resize(2);
+ d_constellation[0] = gr_complex(-1, 0);
+ d_constellation[1] = gr_complex(1, 0);
+ d_rotational_symmetry = 2;
+ d_dimensionality = 1;
+ calc_arity();
+}
+
+unsigned int
+digital_constellation_bpsk::decision_maker(const gr_complex *sample)
+{
+ return (real(*sample) > 0);
+}
+
+
+digital_constellation_qpsk_sptr
+digital_make_constellation_qpsk()
+{
+ return digital_constellation_qpsk_sptr(new digital_constellation_qpsk ());
+}
+
+digital_constellation_qpsk::digital_constellation_qpsk ()
+{
+ d_constellation.resize(4);
+ // Gray-coded
+ d_constellation[0] = gr_complex(-SQRT_TWO, -SQRT_TWO);
+ d_constellation[1] = gr_complex(SQRT_TWO, -SQRT_TWO);
+ d_constellation[2] = gr_complex(-SQRT_TWO, SQRT_TWO);
+ d_constellation[3] = gr_complex(SQRT_TWO, SQRT_TWO);
+ d_rotational_symmetry = 4;
+ d_dimensionality = 1;
+ calc_arity();
+}
+
+unsigned int
+digital_constellation_qpsk::decision_maker(const gr_complex *sample)
+{
+ // Real component determines small bit.
+ // Imag component determines big bit.
+ return 2*(imag(*sample)>0) + (real(*sample)>0);
+}
+
+
+digital_constellation_8psk_sptr
+digital_make_constellation_8psk()
+{
+ return digital_constellation_8psk_sptr(new digital_constellation_8psk ());
+}
+
+digital_constellation_8psk::digital_constellation_8psk ()
+{
+ float angle = M_PI/8.0;
+ d_constellation.resize(8);
+ // Gray-coded
+ d_constellation[0] = gr_complex(cos( 1*angle), sin( 1*angle));
+ d_constellation[1] = gr_complex(cos( 7*angle), sin( 7*angle));
+ d_constellation[2] = gr_complex(cos(15*angle), sin(15*angle));
+ d_constellation[3] = gr_complex(cos( 9*angle), sin( 9*angle));
+ d_constellation[4] = gr_complex(cos( 3*angle), sin( 3*angle));
+ d_constellation[5] = gr_complex(cos( 5*angle), sin( 5*angle));
+ d_constellation[6] = gr_complex(cos(13*angle), sin(13*angle));
+ d_constellation[7] = gr_complex(cos(11*angle), sin(11*angle));
+ d_rotational_symmetry = 8;
+ d_dimensionality = 1;
+ calc_arity();
+}
+
+unsigned int
+digital_constellation_8psk::decision_maker(const gr_complex *sample)
+{
+ unsigned int ret = 0;
+
+ float re = sample->real();
+ float im = sample->imag();
+
+ if(fabsf(re) <= fabsf(im))
+ ret = 4;
+ if(re <= 0)
+ ret |= 1;
+ if(im <= 0)
+ ret |= 2;
+
+ return ret;
+}
diff --git a/gr-digital/lib/digital_constellation.h b/gr-digital/lib/digital_constellation.h
new file mode 100644
index 000000000..d345ebc10
--- /dev/null
+++ b/gr-digital/lib/digital_constellation.h
@@ -0,0 +1,352 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010, 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_CONSTELLATION_H
+#define INCLUDED_DIGITAL_CONSTELLATION_H
+
+#include <vector>
+#include <math.h>
+#include <gr_complex.h>
+#include <boost/enable_shared_from_this.hpp>
+#include <digital_metric_type.h>
+
+/************************************************************/
+/* digital_constellation */
+/* */
+/* Base class defining interface. */
+/************************************************************/
+
+class digital_constellation;
+typedef boost::shared_ptr<digital_constellation> digital_constellation_sptr;
+
+class digital_constellation : public boost::enable_shared_from_this<digital_constellation>
+{
+public:
+ digital_constellation (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry, unsigned int dimensionality);
+ digital_constellation ();
+
+ //! Returns the constellation points for a symbol value
+ void map_to_points(unsigned int value, gr_complex *points);
+ std::vector<gr_complex> map_to_points_v(unsigned int value);
+
+ //! Returns the constellation point that matches best.
+ virtual unsigned int decision_maker (const gr_complex *sample) = 0;
+ //! Takes a vector rather than a pointer. Better for SWIG wrapping.
+ unsigned int decision_maker_v (std::vector<gr_complex> sample);
+ //! Also calculates the phase error.
+ unsigned int decision_maker_pe (const gr_complex *sample, float *phase_error);
+ //! Calculates distance.
+ unsigned int decision_maker_e (const gr_complex *sample, float *error);
+
+ //! Calculates metrics for all points in the constellation.
+ //! For use with the viterbi algorithm.
+ virtual void calc_metric(const gr_complex *sample, float *metric, trellis_metric_type_t type);
+ virtual void calc_euclidean_metric(const gr_complex *sample, float *metric);
+ virtual void calc_hard_symbol_metric(const gr_complex *sample, float *metric);
+
+ //! Returns the set of points in this constellation.
+ std::vector<gr_complex> points() { return d_constellation;}
+ //! Returns the vector of points in this constellation.
+ //! Raise error if dimensionality is not one.
+ std::vector<gr_complex> s_points();
+ //! Returns a vector of vectors of points.
+ std::vector<std::vector<gr_complex> > v_points();
+ //! Whether to apply an encoding before doing differential encoding. (e.g. gray coding)
+ bool apply_pre_diff_code() { return d_apply_pre_diff_code;}
+ //! Returns the encoding to apply before differential encoding.
+ std::vector<unsigned int> pre_diff_code() { return d_pre_diff_code;}
+ //! Returns the order of rotational symmetry.
+ unsigned int rotational_symmetry() { return d_rotational_symmetry;}
+ //! Returns the number of complex numbers in a single symbol.
+ unsigned int dimensionality() {return d_dimensionality;}
+
+ unsigned int bits_per_symbol () {
+ return floor(log(double(d_constellation.size()))/d_dimensionality/log(2.0));
+ }
+
+ unsigned int arity () {
+ return d_arity;
+ }
+
+ digital_constellation_sptr base() {
+ return shared_from_this();
+ }
+
+ protected:
+
+ std::vector<gr_complex> d_constellation;
+ std::vector<unsigned int> d_pre_diff_code;
+ bool d_apply_pre_diff_code;
+ unsigned int d_rotational_symmetry;
+ unsigned int d_dimensionality;
+ unsigned int d_arity;
+
+ float get_distance(unsigned int index, const gr_complex *sample);
+ unsigned int get_closest_point(const gr_complex *sample);
+ void calc_arity ();
+};
+
+/************************************************************/
+/* digital_constellation_calcdist */
+/* */
+/* Constellation which calculates the distance to each */
+/* point in the constellation for decision making. */
+/* Inefficient for large constellations. */
+/************************************************************/
+
+class digital_constellation_calcdist;
+typedef boost::shared_ptr<digital_constellation_calcdist> digital_constellation_calcdist_sptr;
+
+// public constructor
+digital_constellation_calcdist_sptr
+digital_make_constellation_calcdist (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry, unsigned int dimensionality);
+
+
+class digital_constellation_calcdist : public digital_constellation
+{
+ public:
+ digital_constellation_calcdist (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+ unsigned int decision_maker (const gr_complex *sample);
+ // void calc_metric(gr_complex *sample, float *metric, trellis_metric_type_t type);
+ // void calc_euclidean_metric(gr_complex *sample, float *metric);
+ // void calc_hard_symbol_metric(gr_complex *sample, float *metric);
+
+ private:
+ friend digital_constellation_calcdist_sptr
+ digital_make_constellation_calcdist (std::vector<gr_complex> constellation);
+};
+
+/************************************************************/
+/* digital_constellation_sector */
+/* */
+/* An abstract class. */
+/* Constellation space is divided into sectors. */
+/* Each sector is associated with the nearest constellation */
+/* point. */
+/************************************************************/
+
+class digital_constellation_sector : public digital_constellation
+{
+ public:
+
+ digital_constellation_sector (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality,
+ unsigned int n_sectors);
+
+ unsigned int decision_maker (const gr_complex *sample);
+
+ protected:
+
+ virtual unsigned int get_sector (const gr_complex *sample) = 0;
+ virtual unsigned int calc_sector_value (unsigned int sector) = 0;
+ void find_sector_values ();
+
+ unsigned int n_sectors;
+
+ private:
+
+ std::vector<unsigned int> sector_values;
+
+};
+
+/************************************************************/
+/* digital_constellation_rect */
+/* */
+/* Only implemented for 1-(complex)dimensional */
+/* constellation. */
+/* Constellation space is divided into rectangular sectors. */
+/* Each sector is associated with the nearest constellation */
+/* point. */
+/* Works well for square QAM. */
+/* Works for any generic constellation provided sectors are */
+/* not too large. */
+/************************************************************/
+
+class digital_constellation_rect;
+typedef boost::shared_ptr<digital_constellation_rect> digital_constellation_rect_sptr;
+
+// public constructor
+digital_constellation_rect_sptr
+digital_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+
+class digital_constellation_rect : public digital_constellation_sector
+{
+ public:
+
+ digital_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+
+ protected:
+
+ unsigned int get_sector (const gr_complex *sample);
+
+ unsigned int calc_sector_value (unsigned int sector);
+
+ private:
+
+ unsigned int n_real_sectors;
+ unsigned int n_imag_sectors;
+ float d_width_real_sectors;
+ float d_width_imag_sectors;
+
+ friend digital_constellation_rect_sptr
+ digital_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+
+};
+
+/************************************************************/
+/* digital_constellation_psk */
+/* */
+/* Constellation space is divided into pie slices sectors. */
+/* Each slice is associated with the nearest constellation */
+/* point. */
+/* Works well for PSK but nothing else. */
+/* Assumes that there is a constellation point at 1. */
+/************************************************************/
+
+class digital_constellation_psk;
+typedef boost::shared_ptr<digital_constellation_psk> digital_constellation_psk_sptr;
+
+// public constructor
+digital_constellation_psk_sptr
+digital_make_constellation_psk (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+
+class digital_constellation_psk : public digital_constellation_sector
+{
+ public:
+
+ digital_constellation_psk (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+
+ protected:
+
+ unsigned int get_sector (const gr_complex *sample);
+
+ unsigned int calc_sector_value (unsigned int sector);
+
+ private:
+
+ friend digital_constellation_psk_sptr
+ digital_make_constellation_psk (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+
+};
+
+/************************************************************/
+/* digital_constellation_bpsk */
+/* */
+/* Only works for BPSK. */
+/* */
+/************************************************************/
+
+class digital_constellation_bpsk;
+typedef boost::shared_ptr<digital_constellation_bpsk> digital_constellation_bpsk_sptr;
+
+// public constructor
+digital_constellation_bpsk_sptr
+digital_make_constellation_bpsk ();
+
+class digital_constellation_bpsk : public digital_constellation
+{
+ public:
+
+ digital_constellation_bpsk ();
+ unsigned int decision_maker (const gr_complex *sample);
+
+ friend digital_constellation_bpsk_sptr
+ digital_make_constellation_bpsk ();
+
+};
+
+/************************************************************/
+/* digital_constellation_qpsk */
+/* */
+/* Only works for QPSK. */
+/* */
+/************************************************************/
+
+class digital_constellation_qpsk;
+typedef boost::shared_ptr<digital_constellation_qpsk> digital_constellation_qpsk_sptr;
+
+// public constructor
+digital_constellation_qpsk_sptr
+digital_make_constellation_qpsk ();
+
+class digital_constellation_qpsk : public digital_constellation
+{
+ public:
+
+ digital_constellation_qpsk ();
+ unsigned int decision_maker (const gr_complex *sample);
+
+ friend digital_constellation_qpsk_sptr
+ digital_make_constellation_qpsk ();
+
+};
+
+
+/************************************************************/
+/* digital_constellation_8psk */
+/* */
+/* Only works for 8PSK. */
+/* */
+/************************************************************/
+
+class digital_constellation_8psk;
+typedef boost::shared_ptr<digital_constellation_8psk> digital_constellation_8psk_sptr;
+
+// public constructor
+digital_constellation_8psk_sptr
+digital_make_constellation_8psk ();
+
+class digital_constellation_8psk : public digital_constellation
+{
+ public:
+
+ digital_constellation_8psk ();
+ unsigned int decision_maker (const gr_complex *sample);
+
+ friend digital_constellation_8psk_sptr
+ digital_make_constellation_8psk ();
+
+};
+
+#endif
diff --git a/gr-digital/lib/digital_constellation_decoder_cb.cc b/gr-digital/lib/digital_constellation_decoder_cb.cc
new file mode 100644
index 000000000..4638790f6
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_decoder_cb.cc
@@ -0,0 +1,77 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <digital_constellation_decoder_cb.h>
+#include <digital_constellation.h>
+#include <gr_io_signature.h>
+#include <iostream>
+
+digital_constellation_decoder_cb_sptr
+digital_make_constellation_decoder_cb (digital_constellation_sptr constellation)
+{
+ return gnuradio::get_initial_sptr
+ (new digital_constellation_decoder_cb(constellation));
+}
+
+digital_constellation_decoder_cb::
+digital_constellation_decoder_cb (digital_constellation_sptr constellation)
+ : gr_block ("constellation_decoder_cb",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signature (1, 1, sizeof (unsigned char))),
+ d_constellation(constellation),
+ d_dim(constellation->dimensionality())
+{
+ set_relative_rate (1.0 / ((double) d_dim));
+}
+
+void
+digital_constellation_decoder_cb::forecast (int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ unsigned int input_required = noutput_items * d_dim;
+
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned int i = 0; i < ninputs; i++)
+ ninput_items_required[i] = input_required;
+}
+
+
+int
+digital_constellation_decoder_cb::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex const *in = (const gr_complex *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ for(int i = 0; i < noutput_items; i++){
+ out[i] = d_constellation->decision_maker(&(in[i*d_dim]));
+ }
+
+ consume_each (noutput_items * d_dim);
+ return noutput_items;
+}
diff --git a/gr-digital/lib/digital_constellation_decoder_cb.h b/gr-digital/lib/digital_constellation_decoder_cb.h
new file mode 100644
index 000000000..022456733
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_decoder_cb.h
@@ -0,0 +1,64 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_H
+#define INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_H
+
+#include <gr_block.h>
+#include <digital_constellation.h>
+#include <vector>
+
+class digital_constellation_decoder_cb;
+typedef boost::shared_ptr<digital_constellation_decoder_cb>digital_constellation_decoder_cb_sptr;
+
+digital_constellation_decoder_cb_sptr
+digital_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+/*!
+ * \brief Constellation Decoder
+ * \ingroup coding_blk
+ *
+ */
+class digital_constellation_decoder_cb : public gr_block
+{
+
+ private:
+ digital_constellation_sptr d_constellation;
+ unsigned int d_dim;
+
+ friend digital_constellation_decoder_cb_sptr
+ digital_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ digital_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ public:
+
+ void forecast (int noutput_items,
+ gr_vector_int &ninput_items_required);
+
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gr-digital/lib/digital_constellation_receiver_cb.cc b/gr-digital/lib/digital_constellation_receiver_cb.cc
new file mode 100644
index 000000000..573c4e855
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_receiver_cb.cc
@@ -0,0 +1,131 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_io_signature.h>
+#include <gr_prefs.h>
+#include <digital_constellation_receiver_cb.h>
+#include <stdexcept>
+#include <gr_math.h>
+#include <gr_expj.h>
+
+
+#define M_TWOPI (2*M_PI)
+#define VERBOSE_MM 0 // Used for debugging symbol timing loop
+#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking
+
+// Public constructor
+
+digital_constellation_receiver_cb_sptr
+digital_make_constellation_receiver_cb(digital_constellation_sptr constell,
+ float alpha, float beta,
+ float fmin, float fmax)
+{
+ return gnuradio::get_initial_sptr(new digital_constellation_receiver_cb (constell,
+ alpha, beta,
+ fmin, fmax));
+}
+
+static int ios[] = {sizeof(char), sizeof(float), sizeof(float), sizeof(float)};
+static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
+digital_constellation_receiver_cb::digital_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax)
+ : gr_block ("constellation_receiver_cb",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signaturev (1, 4, iosig)),
+ d_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0),
+ d_constellation(constellation),
+ d_current_const_point(0)
+{
+ if (d_constellation->dimensionality() != 1)
+ throw std::runtime_error ("This receiver only works with constellations of dimension 1.");
+}
+
+void
+digital_constellation_receiver_cb::phase_error_tracking(float phase_error)
+{
+ d_freq += d_beta*phase_error; // adjust frequency based on error
+ d_phase += d_freq + d_alpha*phase_error; // adjust phase based on error
+
+ // Make sure we stay within +-2pi
+ while(d_phase > M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase < -M_TWOPI)
+ d_phase += M_TWOPI;
+
+ // Limit the frequency range
+ d_freq = gr_branchless_clip(d_freq, d_max_freq);
+
+#if VERBOSE_COSTAS
+ printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n",
+ phase_error, d_phase, d_freq, sample.real(), sample.imag(),
+ d_constellation->points()[d_current_const_point].real(),
+ d_constellation->points()[d_current_const_point].imag());
+#endif
+}
+
+int
+digital_constellation_receiver_cb::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const gr_complex *in = (const gr_complex *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ int i=0;
+
+ float phase_error;
+ unsigned int sym_value;
+ gr_complex sample, nco;
+
+ float *out_err = 0, *out_phase = 0, *out_freq = 0;
+ if(output_items.size() == 4) {
+ out_err = (float *) output_items[1];
+ out_phase = (float *) output_items[2];
+ out_freq = (float *) output_items[3];
+ }
+
+ while((i < noutput_items) && (i < ninput_items[0])) {
+ sample = in[i];
+ nco = gr_expj(d_phase); // get the NCO value for derotating the current sample
+ sample = nco*sample; // get the downconverted symbol
+ sym_value = d_constellation->decision_maker_pe(&sample, &phase_error);
+ // phase_error = -arg(sample*conj(d_constellation->points()[sym_value]));
+ phase_error_tracking(phase_error); // corrects phase and frequency offsets
+ out[i] = sym_value;
+ if(output_items.size() == 4) {
+ out_err[i] = phase_error;
+ out_phase[i] = d_phase;
+ out_freq[i] = d_freq;
+ }
+ i++;
+ }
+
+ consume_each(i);
+ return i;
+}
+
diff --git a/gr-digital/lib/digital_constellation_receiver_cb.h b/gr-digital/lib/digital_constellation_receiver_cb.h
new file mode 100644
index 000000000..bf6fc51fa
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_receiver_cb.h
@@ -0,0 +1,149 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_H
+#define INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_H
+
+#include <gr_block.h>
+#include <digital_constellation.h>
+#include <gr_complex.h>
+#include <math.h>
+#include <fstream>
+
+class digital_constellation_receiver_cb;
+typedef boost::shared_ptr<digital_constellation_receiver_cb> digital_constellation_receiver_cb_sptr;
+
+// public constructor
+digital_constellation_receiver_cb_sptr
+digital_make_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+/*!
+ * \brief This block takes care of receiving generic modulated signals through phase, frequency, and symbol
+ * synchronization.
+ * \ingroup sync_blk
+ * \ingroup demod_blk
+ *
+ * This block takes care of receiving generic modulated signals through phase, frequency, and symbol
+ * synchronization. It performs carrier frequency and phase locking as well as symbol timing recovery.
+ *
+ * The phase and frequency synchronization are based on a Costas loop that finds the error of the incoming
+ * signal point compared to its nearest constellation point. The frequency and phase of the NCO are
+ * updated according to this error.
+ *
+ * The symbol synchronization is done using a modified Mueller and Muller circuit from the paper:
+ *
+ * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller
+ * algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033.
+ *
+ * This circuit interpolates the downconverted sample (using the NCO developed by the Costas loop)
+ * every mu samples, then it finds the sampling error based on this and the past symbols and the decision
+ * made on the samples. Like the phase error detector, there are optimized decision algorithms for BPSK
+ * and QPKS, but 8PSK uses another brute force computation against all possible symbols. The modifications
+ * to the M&M used here reduce self-noise.
+ *
+ */
+
+class digital_constellation_receiver_cb : public gr_block
+{
+ public:
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+
+ // Member function related to the phase/frequency tracking portion of the receiver
+ //! (CL) Returns the value for alpha (the phase gain term)
+ float alpha() const { return d_alpha; }
+
+ //! (CL) Returns the value of beta (the frequency gain term)
+ float beta() const { return d_beta; }
+
+ //! (CL) Returns the current value of the frequency of the NCO in the Costas loop
+ float freq() const { return d_freq; }
+
+ //! (CL) Returns the current value of the phase of the NCO in the Costal loop
+ float phase() const { return d_phase; }
+
+ //! (CL) Sets the value for alpha (the phase gain term)
+ void set_alpha(float alpha) { d_alpha = alpha; }
+
+ //! (CL) Setss the value of beta (the frequency gain term)
+ void set_beta(float beta) { d_beta = beta; }
+
+ //! (CL) Sets the current value of the frequency of the NCO in the Costas loop
+ void set_freq(float freq) { d_freq = freq; }
+
+ //! (CL) Setss the current value of the phase of the NCO in the Costal loop
+ void set_phase(float phase) { d_phase = phase; }
+
+
+protected:
+
+ /*!
+ * \brief Constructor to synchronize incoming M-PSK symbols
+ *
+ * \param constellation constellation of points for generic modulation
+ * \param alpha gain parameter to adjust the phase in the Costas loop (~0.01)
+ * \param beta gain parameter to adjust the frequency in the Costas loop (~alpha^2/4)
+ * \param fmin minimum normalized frequency value the loop can achieve
+ * \param fmax maximum normalized frequency value the loop can achieve
+ *
+ * The constructor also chooses which phase detector and decision maker to use in the
+ * work loop based on the value of M.
+ */
+ digital_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+ void phase_error_tracking(float phase_error);
+
+ private:
+ unsigned int d_M;
+
+ // Members related to carrier and phase tracking
+ float d_alpha;
+ float d_beta;
+ float d_freq, d_max_freq, d_min_freq;
+ float d_phase;
+
+ digital_constellation_sptr d_constellation;
+ unsigned int d_current_const_point;
+
+ //! delay line length.
+ static const unsigned int DLLEN = 8;
+
+ //! delay line plus some length for overflow protection
+ gr_complex d_dl[2*DLLEN] __attribute__ ((aligned(8)));
+
+ //! index to delay line
+ unsigned int d_dl_idx;
+
+ friend digital_constellation_receiver_cb_sptr
+ digital_make_constellation_receiver_cb (digital_constellation_sptr constell,
+ float alpha, float beta,
+ float fmin, float fmax);
+};
+
+#endif
diff --git a/gr-digital/lib/digital_costas_loop_cc.cc b/gr-digital/lib/digital_costas_loop_cc.cc
new file mode 100644
index 000000000..5d98bde4c
--- /dev/null
+++ b/gr-digital/lib/digital_costas_loop_cc.cc
@@ -0,0 +1,201 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2010,2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <digital_costas_loop_cc.h>
+#include <gr_io_signature.h>
+#include <gr_expj.h>
+#include <gr_sincos.h>
+#include <gr_math.h>
+
+#define M_TWOPI (2*M_PI)
+
+digital_costas_loop_cc_sptr
+digital_make_costas_loop_cc (float damping, float nat_freq,
+ int order
+ ) throw (std::invalid_argument)
+{
+ return gnuradio::get_initial_sptr(new digital_costas_loop_cc (damping,
+ nat_freq,
+ order));
+}
+
+digital_costas_loop_cc::digital_costas_loop_cc (float damping, float nat_freq,
+ int order
+ ) throw (std::invalid_argument)
+ : gr_sync_block ("costas_loop_cc",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signature2 (1, 2, sizeof (gr_complex), sizeof(float))),
+ d_max_freq(1.0), d_min_freq(-1.0), d_phase(0), d_freq(0.0),
+ d_nat_freq(nat_freq), d_damping(damping),
+ d_order(order), d_phase_detector(NULL)
+{
+ // initialize gains from the natural freq and damping factors
+ update_gains();
+
+ switch(d_order) {
+ case 2:
+ d_phase_detector = &digital_costas_loop_cc::phase_detector_2;
+ break;
+
+ case 4:
+ d_phase_detector = &digital_costas_loop_cc::phase_detector_4;
+ break;
+
+ case 8:
+ d_phase_detector = &digital_costas_loop_cc::phase_detector_8;
+ break;
+
+ default:
+ throw std::invalid_argument("order must be 2, 4, or 8");
+ break;
+ }
+}
+
+float
+digital_costas_loop_cc::phase_detector_8(gr_complex sample) const
+{
+ /* This technique splits the 8PSK constellation into 2 squashed
+ QPSK constellations, one when I is larger than Q and one where
+ Q is larger than I. The error is then calculated proportionally
+ to these squashed constellations by the const K = sqrt(2)-1.
+
+ The signal magnitude must be > 1 or K will incorrectly bias
+ the error value.
+
+ Ref: Z. Huang, Z. Yi, M. Zhang, K. Wang, "8PSK demodulation for
+ new generation DVB-S2", IEEE Proc. Int. Conf. Communications,
+ Circuits and Systems, Vol. 2, pp. 1447 - 1450, 2004.
+ */
+
+ float K = (sqrt(2.0) - 1);
+ if(fabsf(sample.real()) >= fabsf(sample.imag())) {
+ return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -
+ (sample.imag()>0 ? 1.0 : -1.0) * sample.real() * K);
+ }
+ else {
+ return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() * K -
+ (sample.imag()>0 ? 1.0 : -1.0) * sample.real());
+ }
+}
+
+float
+digital_costas_loop_cc::phase_detector_4(gr_complex sample) const
+{
+
+ return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -
+ (sample.imag()>0 ? 1.0 : -1.0) * sample.real());
+}
+
+float
+digital_costas_loop_cc::phase_detector_2(gr_complex sample) const
+{
+ return (sample.real()*sample.imag());
+}
+
+void
+digital_costas_loop_cc::set_natural_freq(float w)
+{
+ d_nat_freq = w;
+ update_gains();
+}
+
+void
+digital_costas_loop_cc::set_damping_factor(float eta)
+{
+ d_damping = eta;
+ update_gains();
+}
+
+void
+digital_costas_loop_cc::update_gains()
+{
+ d_beta = d_nat_freq*d_nat_freq;
+ d_alpha = 2*d_damping*d_nat_freq;
+}
+
+int
+digital_costas_loop_cc::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const gr_complex *iptr = (gr_complex *) input_items[0];
+ gr_complex *optr = (gr_complex *) output_items[0];
+ float *foptr = (float *) output_items[1];
+
+ bool write_foptr = output_items.size() >= 2;
+
+ float error;
+ gr_complex nco_out;
+
+ if (write_foptr) {
+
+ for (int i = 0; i < noutput_items; i++){
+ nco_out = gr_expj(-d_phase);
+ optr[i] = iptr[i] * nco_out;
+
+ error = (*this.*d_phase_detector)(optr[i]);
+ error = gr_branchless_clip(error, 1.0);
+
+ d_freq = d_freq + d_beta * error;
+ d_phase = d_phase + d_freq + d_alpha * error;
+
+ while(d_phase>M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase<-M_TWOPI)
+ d_phase += M_TWOPI;
+
+ if (d_freq > d_max_freq)
+ d_freq = d_min_freq;
+ else if (d_freq < d_min_freq)
+ d_freq = d_max_freq;
+
+ foptr[i] = d_freq;
+ }
+ } else {
+ for (int i = 0; i < noutput_items; i++){
+ nco_out = gr_expj(-d_phase);
+ optr[i] = iptr[i] * nco_out;
+
+ error = (*this.*d_phase_detector)(optr[i]);
+ error = gr_branchless_clip(error, 1.0);
+
+ d_freq = d_freq + d_beta * error;
+ d_phase = d_phase + d_freq + d_alpha * error;
+
+ while(d_phase>M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase<-M_TWOPI)
+ d_phase += M_TWOPI;
+
+ if (d_freq > d_max_freq)
+ d_freq = d_min_freq;
+ else if (d_freq < d_min_freq)
+ d_freq = d_max_freq;
+
+ }
+ }
+ return noutput_items;
+}
diff --git a/gr-digital/lib/digital_costas_loop_cc.h b/gr-digital/lib/digital_costas_loop_cc.h
new file mode 100644
index 000000000..9c112d328
--- /dev/null
+++ b/gr-digital/lib/digital_costas_loop_cc.h
@@ -0,0 +1,150 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef INCLUDED_DIGITAL_COSTAS_LOOP_CC_H
+#define INCLUDED_DIGITAL_COSTAS_LOOP_CC_H
+
+#include <gr_sync_block.h>
+#include <stdexcept>
+#include <fstream>
+
+
+/*! \brief A Costas loop carrier recovery module.
+ * \ingroup sync_blk
+ *
+ * The Costas loop locks to the center frequency of a signal and
+ * downconverts it to baseband. The second (order=2) order loop is
+ * used for BPSK where the real part of the output signal is the
+ * baseband BPSK signal and the imaginary part is the error
+ * signal. When order=4, it can be used for quadrature modulations
+ * where both I and Q (real and imaginary) are outputted.
+ *
+ * More details can be found online:
+ *
+ * J. Feigin, "Practical Costas loop design: Designing a simple and inexpensive
+ * BPSK Costas loop carrier recovery circuit," RF signal processing, pp. 20-36,
+ * 2002.
+ *
+ * http://rfdesign.com/images/archive/0102Feigin20.pdf
+ *
+ * \param alpha the loop gain used for phase adjustment
+ * \param beta the loop gain for frequency adjustments
+ * \param max_freq the maximum frequency deviation (radians/sample) the loop can handle
+ * \param min_freq the minimum frequency deviation (radians/sample) the loop can handle
+ * \param order the loop order, either 2 or 4
+ */
+class digital_costas_loop_cc;
+typedef boost::shared_ptr<digital_costas_loop_cc> digital_costas_loop_cc_sptr;
+
+
+digital_costas_loop_cc_sptr
+digital_make_costas_loop_cc (float damping, float nat_freq,
+ int order
+ ) throw (std::invalid_argument);
+
+
+/*!
+ * \brief Carrier tracking PLL for QPSK
+ * \ingroup sync_blk
+ * input: complex; output: complex
+ * <br>The Costas loop can have two output streams:
+ * stream 1 is the baseband I and Q;
+ * stream 2 is the normalized frequency of the loop
+ *
+ * \p order must be 2 or 4.
+ */
+class digital_costas_loop_cc : public gr_sync_block
+{
+ friend digital_costas_loop_cc_sptr
+ digital_make_costas_loop_cc (float damping, float nat_freq,
+ int order
+ ) throw (std::invalid_argument);
+
+ float d_alpha, d_beta, d_max_freq, d_min_freq, d_phase, d_freq;
+ float d_nat_freq, d_damping;
+ int d_order;
+
+ digital_costas_loop_cc (float damping, float nat_freq,
+ int order
+ ) throw (std::invalid_argument);
+
+
+ /*! \brief update the system gains from omega and eta
+ *
+ * This function updates the system gains based on the natural
+ * frequency (omega) and damping factor (eta) of the system.
+ * These two factors can be set separately through their own
+ * set functions.
+ *
+ * These equations are summarized nicely in this paper from Berkeley:
+ * http://www.complextoreal.com/chapters/pll.pdf
+ */
+ void update_gains();
+
+ /*! \brief the phase detector circuit for 8th-order PSK loops
+ * \param sample complex sample
+ * \return the phase error
+ */
+ float phase_detector_8(gr_complex sample) const; // for 8PSK
+
+ /*! \brief the phase detector circuit for fourth-order loops
+ * \param sample complex sample
+ * \return the phase error
+ */
+ float phase_detector_4(gr_complex sample) const; // for QPSK
+
+ /*! \brief the phase detector circuit for second-order loops
+ * \param sample a complex sample
+ * \return the phase error
+ */
+ float phase_detector_2(gr_complex sample) const; // for BPSK
+
+
+ float (digital_costas_loop_cc::*d_phase_detector)(gr_complex sample) const;
+
+public:
+
+ void set_natural_freq(float w);
+ void set_damping_factor(float eta);
+
+ /*! \brief get the first order gain
+ *
+ */
+ float alpha() const { return d_alpha; }
+
+ /*! \brief get the second order gain
+ *
+ */
+ float beta() const { return d_beta; }
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ /*! \brief returns the current NCO frequency in radians/sample
+ *
+ */
+ float freq() const { return d_freq; }
+};
+
+#endif
diff --git a/gr-digital/lib/digital_kurtotic_equalizer_cc.cc b/gr-digital/lib/digital_kurtotic_equalizer_cc.cc
new file mode 100644
index 000000000..c95b56021
--- /dev/null
+++ b/gr-digital/lib/digital_kurtotic_equalizer_cc.cc
@@ -0,0 +1,51 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <digital_kurtotic_equalizer_cc.h>
+
+digital_kurtotic_equalizer_cc_sptr
+digital_make_kurtotic_equalizer_cc(int num_taps, float mu)
+{
+ return gnuradio::get_initial_sptr(new digital_kurtotic_equalizer_cc(num_taps, mu));
+}
+
+digital_kurtotic_equalizer_cc::digital_kurtotic_equalizer_cc(int num_taps, float mu)
+ : gr_adaptive_fir_ccc("kurtotic_equalizer_cc", 1, std::vector<gr_complex>(num_taps))
+{
+ set_gain(mu);
+ if (num_taps > 0)
+ d_taps[0] = 1.0;
+
+ d_alpha_p = 0.01;
+ d_alpha_q = 0.01;
+ d_alpha_m = 0.01;
+
+ d_p = 0.0f;
+ d_m = 0.0f;
+ d_q = gr_complex(0,0);
+ d_u = gr_complex(0,0);
+}
+
diff --git a/gr-digital/lib/digital_kurtotic_equalizer_cc.h b/gr-digital/lib/digital_kurtotic_equalizer_cc.h
new file mode 100644
index 000000000..e01cbd6e6
--- /dev/null
+++ b/gr-digital/lib/digital_kurtotic_equalizer_cc.h
@@ -0,0 +1,111 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_H
+#define INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_H
+
+#include <gr_adaptive_fir_ccc.h>
+#include <gr_math.h>
+#include <iostream>
+
+class digital_kurtotic_equalizer_cc;
+typedef boost::shared_ptr<digital_kurtotic_equalizer_cc> digital_kurtotic_equalizer_cc_sptr;
+
+digital_kurtotic_equalizer_cc_sptr
+digital_make_kurtotic_equalizer_cc(int num_taps, float mu);
+
+/*!
+ * \brief Implements a kurtosis-based adaptive equalizer on complex stream
+ * \ingroup eq_blk
+ *
+ * Y. Guo, J. Zhao, Y. Sun, "Sign kurtosis maximization based blind
+ * equalization algorithm," IEEE Conf. on Control, Automation,
+ * Robotics and Vision, Vol. 3, Dec. 2004, pp. 2052 - 2057.
+ */
+class digital_kurtotic_equalizer_cc : public gr_adaptive_fir_ccc
+{
+private:
+ float d_mu;
+ float d_p, d_m;
+ gr_complex d_q, d_u;
+ float d_alpha_p, d_alpha_q, d_alpha_m;
+
+ friend digital_kurtotic_equalizer_cc_sptr digital_make_kurtotic_equalizer_cc(int num_taps,
+ float mu);
+ digital_kurtotic_equalizer_cc(int num_taps, float mu);
+
+ gr_complex sign(gr_complex x)
+ {
+ float re = (float)(x.real() >= 0.0f);
+ float im = (float)(x.imag() >= 0.0f);
+ return gr_complex(re, im);
+ }
+
+protected:
+
+ virtual gr_complex error(const gr_complex &out)
+ {
+
+ // p = E[|z|^2]
+ // q = E[z^2]
+ // m = E[|z|^4]
+ // u = E[kurtosis(z)]
+
+ float nrm = norm(out);
+ gr_complex cnj = conj(out);
+ float epsilon_f = 1e-12;
+ gr_complex epsilon_c = gr_complex(1e-12, 1e-12);
+
+
+ d_p = (1-d_alpha_p)*d_p + (d_alpha_p)*nrm + epsilon_f;
+ d_q = (1-d_alpha_q)*d_q + (d_alpha_q)*out*out + epsilon_c;
+ d_m = (1-d_alpha_m)*d_m + (d_alpha_m)*nrm*nrm + epsilon_f;
+ d_u = d_m - 2.0f*(d_p*d_p) - d_q*d_q;
+
+ gr_complex F = (1.0f / (d_p*d_p*d_p)) *
+ (sign(d_u) * (nrm*cnj - 2.0f*d_p*cnj - conj(d_q)*out) -
+ abs(d_u)*cnj);
+
+ //std::cout << "out: " << out << " p: " << d_p << " q: " << d_q;
+ //std::cout << " m: " << d_m << " u: " << d_u << std::endl;
+ //std::cout << "error: " << F << std::endl;
+
+ float re = gr_clip(F.real(), 1.0);
+ float im = gr_clip(F.imag(), 1.0);
+ return gr_complex(re, im);
+ }
+
+ virtual void update_tap(gr_complex &tap, const gr_complex &in)
+ {
+ tap += d_mu*in*d_error;
+ }
+
+public:
+ void set_gain(float mu)
+ {
+ if(mu < 0)
+ throw std::out_of_range("digital_kurtotic_equalizer::set_gain: Gain value must be >= 0");
+ d_mu = mu;
+ }
+};
+
+#endif
diff --git a/gr-digital/lib/digital_lms_dd_equalizer_cc.cc b/gr-digital/lib/digital_lms_dd_equalizer_cc.cc
new file mode 100644
index 000000000..e2c2f16f2
--- /dev/null
+++ b/gr-digital/lib/digital_lms_dd_equalizer_cc.cc
@@ -0,0 +1,85 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <digital_lms_dd_equalizer_cc.h>
+#include <gr_io_signature.h>
+#include <gr_misc.h>
+#include <iostream>
+
+digital_lms_dd_equalizer_cc_sptr
+digital_make_lms_dd_equalizer_cc(int num_taps, float mu, int sps,
+ digital_constellation_sptr cnst)
+{
+ return gnuradio::get_initial_sptr(new digital_lms_dd_equalizer_cc(num_taps, mu,
+ sps, cnst));
+}
+
+digital_lms_dd_equalizer_cc::digital_lms_dd_equalizer_cc(int num_taps, float mu,
+ int sps,
+ digital_constellation_sptr cnst)
+ : gr_adaptive_fir_ccc("lms_dd_equalizer_cc", sps,
+ std::vector<gr_complex>(num_taps, gr_complex(0,0))),
+ d_taps(num_taps), d_cnst(cnst)
+{
+ set_gain(mu);
+ if (num_taps > 0)
+ d_taps[num_taps/2] = 1.0;
+}
+
+
+
+
+/*
+int
+digital_lms_dd_equalizer_cc::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const gr_complex *in = (const gr_complex *) input_items[0];
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ gr_complex acc, decision, error;
+
+ for(int i = 0; i < noutput_items; i++) {
+ acc = 0;
+
+ // Compute output
+ for (size_t j=0; j < d_taps.size(); j++)
+ acc += in[i+j] * conj(d_taps[j]);
+
+ d_cnst->map_to_points(d_cnst->decision_maker(&acc), &decision);
+ error = decision - acc;
+
+ // Update taps
+ for (size_t j=0; j < d_taps.size(); j++)
+ d_taps[j] += d_mu * conj(error) * in[i+j];
+
+ out[i] = acc;
+ }
+
+ return noutput_items;
+}
+*/
diff --git a/gr-digital/lib/digital_lms_dd_equalizer_cc.h b/gr-digital/lib/digital_lms_dd_equalizer_cc.h
new file mode 100644
index 000000000..e3ad4bf4a
--- /dev/null
+++ b/gr-digital/lib/digital_lms_dd_equalizer_cc.h
@@ -0,0 +1,116 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_H
+#define INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_H
+
+#include <gr_adaptive_fir_ccc.h>
+#include <digital_constellation.h>
+
+class digital_lms_dd_equalizer_cc;
+typedef boost::shared_ptr<digital_lms_dd_equalizer_cc> digital_lms_dd_equalizer_cc_sptr;
+
+digital_lms_dd_equalizer_cc_sptr digital_make_lms_dd_equalizer_cc (int num_taps,
+ float mu, int sps,
+ digital_constellation_sptr cnst);
+
+/*!
+ * \brief Least-Mean-Square Decision Directed Equalizer (complex in/out)
+ * \ingroup eq_blk
+ *
+ * This block implements an LMS-based decision-directed equalizer.
+ * It uses a set of weights, w, to correlate against the inputs, u,
+ * and a decisions is then made from this output. The error
+ * in the decision is used to update teh weight vector.
+ *
+ * y[n] = conj(w[n]) u[n]
+ * d[n] = decision(y[n])
+ * e[n] = d[n] - y[n]
+ * w[n+1] = w[n] + mu u[n] conj(e[n])
+ *
+ * Where mu is a gain value (between 0 and 1 and usualy small,
+ * around 0.001 - 0.01.
+ *
+ * This block uses the digital_constellation object for making
+ * the decision from y[n]. Create the constellation object for
+ * whatever constellation is to be used and pass in the object.
+ * In Python, you can use something like:
+ * self.constellation = digital.constellation_qpsk()
+ * To create a QPSK constellation (see the digital_constellation
+ * block for more details as to what constellations are available
+ * or how to create your own). You then pass the object to this
+ * block as an sptr, or using "self.constellation.base()".
+ *
+ * The theory for this algorithm can be found in Chapter 9 of:
+ * S. Haykin, Adaptive Filter Theory, Upper Saddle River, NJ:
+ * Prentice Hall, 1996.
+ *
+ */
+class digital_lms_dd_equalizer_cc : public gr_adaptive_fir_ccc
+{
+private:
+ friend digital_lms_dd_equalizer_cc_sptr digital_make_lms_dd_equalizer_cc (int num_taps,
+ float mu, int sps,
+ digital_constellation_sptr cnst);
+
+ float d_mu;
+ std::vector<gr_complex> d_taps;
+ digital_constellation_sptr d_cnst;
+
+ digital_lms_dd_equalizer_cc (int num_taps,
+ float mu, int sps,
+ digital_constellation_sptr cnst);
+
+protected:
+
+ virtual gr_complex error(const gr_complex &out)
+ {
+ gr_complex decision, error;
+ d_cnst->map_to_points(d_cnst->decision_maker(&out), &decision);
+ error = decision - out;
+ return error;
+ }
+
+ virtual void update_tap(gr_complex &tap, const gr_complex &in)
+ {
+ tap += d_mu*conj(in)*d_error;
+ }
+
+public:
+ float get_gain()
+ {
+ return d_mu;
+ }
+
+ void set_gain(float mu)
+ {
+ if(mu < 0.0f || mu > 1.0f) {
+ throw std::out_of_range("digital_lms_dd_equalizer::set_mu: Gain value must in [0, 1]");
+ }
+ else {
+ d_mu = mu;
+ }
+ }
+
+};
+
+#endif
diff --git a/gr-digital/lib/digital_metric_type.h b/gr-digital/lib/digital_metric_type.h
new file mode 100644
index 000000000..83de166f0
--- /dev/null
+++ b/gr-digital/lib/digital_metric_type.h
@@ -0,0 +1,31 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_METRIC_TYPE_H
+#define INCLUDED_DIGITAL_METRIC_TYPE_H
+
+typedef enum {
+ TRELLIS_EUCLIDEAN = 200, TRELLIS_HARD_SYMBOL, TRELLIS_HARD_BIT
+} trellis_metric_type_t;
+
+#endif
+
diff --git a/gr-digital/python/.gitignore b/gr-digital/python/.gitignore
new file mode 100644
index 000000000..604b402c5
--- /dev/null
+++ b/gr-digital/python/.gitignore
@@ -0,0 +1,3 @@
+/Makefile
+/Makefile.in
+/run_tests
diff --git a/gr-digital/python/Makefile.am b/gr-digital/python/Makefile.am
new file mode 100644
index 000000000..392ce45c1
--- /dev/null
+++ b/gr-digital/python/Makefile.am
@@ -0,0 +1,54 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+TESTS =
+EXTRA_DIST += run_tests.in
+
+if PYTHON
+SUBDIRS = utils
+TESTS += run_tests
+
+digitaldir = $(grpythondir)/digital
+
+noinst_PYTHON = \
+ qa_digital.py \
+ qa_constellation.py \
+ qa_constellation_receiver.py \
+ qa_costas_loop_cc.py
+
+digital_PYTHON = \
+ __init__.py \
+ psk.py \
+ dbpsk.py \
+ dqpsk.py \
+ d8psk.py \
+ psk2.py \
+ generic_mod_demod.py \
+ qam.py \
+ bpsk.py \
+ qpsk.py \
+ ofdm.py \
+ pkt.py \
+ modulation_utils2.py
+
+endif
diff --git a/gr-digital/python/__init__.py b/gr-digital/python/__init__.py
new file mode 100644
index 000000000..3d0be3865
--- /dev/null
+++ b/gr-digital/python/__init__.py
@@ -0,0 +1,32 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# The presence of this file turns this directory into a Python package
+
+from digital_swig import *
+from dbpsk import *
+from dqpsk import *
+from d8psk import *
+from psk2 import *
+from qam import *
+from ofdm import *
+from pkt import *
+from modulation_utils2 import *
diff --git a/gr-digital/python/bpsk.py b/gr-digital/python/bpsk.py
new file mode 100644
index 000000000..6d2eb5d6d
--- /dev/null
+++ b/gr-digital/python/bpsk.py
@@ -0,0 +1,98 @@
+#
+# Copyright 2005,2006,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+"""
+BPSK modulation and demodulation.
+"""
+
+from math import pi, log
+from cmath import exp
+
+from gnuradio import gr, modulation_utils2
+from gnuradio.digital.generic_mod_demod import generic_mod, generic_demod
+
+# Default number of points in constellation.
+_def_constellation_points = 2
+# Whether differential coding is used.
+_def_differential = True
+
+# /////////////////////////////////////////////////////////////////////////////
+# BPSK constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def bpsk_constellation(m=_def_constellation_points):
+ if m != _def_constellation_points:
+ raise ValueError("BPSK can only have 2 constellation points.")
+ return gr.constellation_bpsk()
+
+# /////////////////////////////////////////////////////////////////////////////
+# BPSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class bpsk_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ *args, **kwargs):
+
+ """
+ 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.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = gr.constellation_bpsk()
+ if constellation_points != 2:
+ raise ValueError('Number of constellation points must be 2 for BPSK.')
+ super(bpsk_mod, self).__init__(constellation, *args, **kwargs)
+
+# /////////////////////////////////////////////////////////////////////////////
+# BPSK demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class bpsk_demod(generic_demod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ *args, **kwargs):
+
+ """
+ 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.
+
+ See generic_demod block for list of parameters.
+ """
+
+ constellation = gr.constellation_bpsk()
+ if constellation_points != 2:
+ raise ValueError('Number of constellation points must be 2 for BPSK.')
+ super(bpsk_demod, self).__init__(constellation, *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('bpsk', bpsk_mod)
+modulation_utils2.add_type_1_demod('bpsk', bpsk_demod)
+modulation_utils2.add_type_1_constellation('bpsk', bpsk_constellation)
diff --git a/gr-digital/python/d8psk.py b/gr-digital/python/d8psk.py
new file mode 100644
index 000000000..8bed395a7
--- /dev/null
+++ b/gr-digital/python/d8psk.py
@@ -0,0 +1,369 @@
+#
+# Copyright 2005,2006,2007,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+differential 8PSK modulation and demodulation.
+"""
+
+from gnuradio import gr, modulation_utils2
+from math import pi, sqrt
+import digital_swig, psk
+import cmath
+from pprint import pprint
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 3
+_def_excess_bw = 0.35
+_def_gray_code = True
+_def_verbose = False
+_def_log = False
+
+_def_freq_alpha = 0.010
+_def_phase_damping = 0.4
+_def_phase_natfreq = 0.25
+_def_timing_alpha = 0.100
+_def_timing_beta = 0.010
+_def_timing_max_dev = 1.5
+
+# /////////////////////////////////////////////////////////////////////////////
+# D8PSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class d8psk_mod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ gray_code=_def_gray_code,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for RRC-filtered differential 8PSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param samples_per_symbol: samples per symbol >= 2
+ @type samples_per_symbol: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param gray_code: Tell modulator to Gray code the bits
+ @type gray_code: bool
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param log: Log modulation data to files?
+ @type log: bool
+ """
+
+ gr.hier_block2.__init__(self, "d8psk_mod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._gray_code = gray_code
+
+ if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
+ raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol)
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
+
+ if self._gray_code:
+ self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity])
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, psk.constellation[arity])
+ self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
+
+ # pulse shaping filter
+ nfilts = 32
+ ntaps = 11 * int(nfilts * self._samples_per_symbol) # make nfilts filters of ntaps each
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ nfilts, # gain
+ nfilts, # sampling rate based on 32 filters in resampler
+ 1.0, # symbol rate
+ self._excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+ self.rrc_filter = gr.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect & Initialize base class
+ self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
+ self.chunks2symbols, self.rrc_filter, self)
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 3
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ print "\nModulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "Gray code: %s" % self._gray_code
+ print "RRC roll-off factor: %f" % self._excess_bw
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.bytes2chunks,
+ gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "tx_graycoder.dat"))
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "tx_diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat"))
+
+ def add_options(parser):
+ """
+ Adds 8PSK modulation-specific options to the standard parser
+ """
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default] (PSK)")
+ parser.add_option("", "--no-gray-code", dest="gray_code",
+ action="store_false", default=_def_gray_code,
+ help="disable gray coding on modulated bits (PSK)")
+ add_options=staticmethod(add_options)
+
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils2.extract_kwargs_from_options(d8psk_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# D8PSK demodulator
+#
+# Differentially coherent detection of differentially encoded 8psk
+# /////////////////////////////////////////////////////////////////////////////
+
+class d8psk_demod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ freq_alpha=_def_freq_alpha,
+ phase_damping=_def_phase_damping,
+ phase_natfreq=_def_phase_natfreq,
+ timing_alpha=_def_timing_alpha,
+ timing_max_dev=_def_timing_max_dev,
+ gray_code=_def_gray_code,
+ verbose=_def_verbose,
+ log=_def_log,
+ sync_out=False):
+ """
+ Hierarchical block for RRC-filtered DQPSK demodulation
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param samples_per_symbol: samples per symbol >= 2
+ @type samples_per_symbol: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param freq_alpha: loop filter gain for frequency recovery
+ @type freq_alpha: float
+ @param phase_damping: loop filter damping factor for phase/fine frequency recovery
+ @type phase_damping: float
+ @param phase_natfreq: loop filter natural frequency for phase/fine frequency recovery
+ @type phase_natfreq: float
+ @param timing_alpha: timing loop alpha gain
+ @type timing_alpha: float
+ @param timing_max: timing loop maximum rate deviations
+ @type timing_max: float
+ @param gray_code: Tell modulator to Gray code the bits
+ @type gray_code: bool
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param debug: Print modualtion data to files?
+ @type debug: bool
+ """
+ if sync_out: io_sig_out = gr.io_signaturev(2, 2, (gr.sizeof_char, gr.sizeof_gr_complex))
+ else: io_sig_out = gr.io_signature(1, 1, gr.sizeof_char)
+
+ gr.hier_block2.__init__(self, "d8psk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ io_sig_out) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._freq_alpha = freq_alpha
+ self._freq_beta = 0.25*self._freq_alpha**2
+ self._phase_damping = phase_damping
+ self._phase_natfreq = phase_natfreq
+ self._timing_alpha = timing_alpha
+ self._timing_beta = _def_timing_beta
+ self._timing_max_dev=timing_max_dev
+ self._gray_code = gray_code
+
+ if samples_per_symbol < 2:
+ raise TypeError, "sbp must be >= 2, is %d" % samples_per_symbol
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # Automatic gain control
+ self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
+ #self.agc = gr.feedforward_agc_cc(16, 2.0)
+
+ # Frequency correction
+ self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ 11*int(self._samples_per_symbol),
+ self._freq_alpha, self._freq_beta)
+
+ # symbol timing recovery with RRC data filter
+ nfilts = 32
+ ntaps = 11 * int(samples_per_symbol*nfilts)
+ taps = gr.firdes.root_raised_cosine(1.41*nfilts, nfilts,
+ 1.0/float(self._samples_per_symbol),
+ self._excess_bw, ntaps)
+ self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
+ self._timing_alpha,
+ taps, nfilts, nfilts/2, self._timing_max_dev)
+ self.time_recov.set_beta(self._timing_beta)
+
+ # Perform phase / fine frequency correction
+ self.phase_recov = digital_swig.costas_loop_cc(self._phase_damping,
+ self._phase_natfreq,
+ arity)
+
+ # Perform Differential decoding on the constellation
+ self.diffdec = gr.diff_phasor_cc()
+
+ # find closest constellation point
+ rot = cmath.exp(1j*cmath.pi/8.0)
+ rotated_const = map(lambda pt: pt * rot, psk.constellation[arity])
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+
+ if self._gray_code:
+ self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect
+ self.connect(self, self.agc,
+ self.freq_recov, self.time_recov, self.phase_recov,
+ self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
+ if sync_out: self.connect(self.phase_recov, (self, 1))
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 3
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ print "\nDemodulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "Gray code: %s" % self._gray_code
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+ print "FLL gain: %.2f" % self._freq_alpha
+ print "Timing alpha gain: %.2f" % self._timing_alpha
+ print "Timing beta gain: %.2f" % self._timing_beta
+ print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
+ self.connect(self.freq_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
+ self.connect(self.time_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect(self.phase_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat"))
+ self.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
+ self.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "rx_slicer.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "rx_gray_decoder.dat"))
+ self.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "rx_unpack.dat"))
+
+ def add_options(parser):
+ """
+ Adds D8PSK demodulation-specific options to the standard parser
+ """
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default] (PSK)")
+ parser.add_option("", "--no-gray-code", dest="gray_code",
+ action="store_false", default=_def_gray_code,
+ help="disable gray coding on modulated bits (PSK)")
+ parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
+ help="set frequency lock loop alpha gain value [default=%default] (PSK)")
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default] (PSK)")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
+ help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)")
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
+ help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)")
+ parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
+ help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)")
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils2.extract_kwargs_from_options(
+ d8psk_demod.__init__, ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('d8psk', d8psk_mod)
+modulation_utils2.add_type_1_demod('d8psk', d8psk_demod)
diff --git a/gr-digital/python/dbpsk.py b/gr-digital/python/dbpsk.py
new file mode 100644
index 000000000..2e9b756e6
--- /dev/null
+++ b/gr-digital/python/dbpsk.py
@@ -0,0 +1,370 @@
+#
+# Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+differential BPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, modulation_utils2
+from math import pi, sqrt, ceil
+import digital_swig, psk
+import cmath
+from pprint import pprint
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 2
+_def_excess_bw = 0.35
+_def_gray_code = True
+_def_verbose = False
+_def_log = False
+
+_def_freq_alpha = 0.010
+_def_phase_damping = 0.4
+_def_phase_natfreq = 0.25
+_def_timing_alpha = 0.100
+_def_timing_beta = 0.010
+_def_timing_max_dev = 1.5
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# DBPSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class dbpsk_mod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ gray_code=_def_gray_code,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for RRC-filtered differential BPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param samples_per_symbol: samples per symbol >= 2
+ @type samples_per_symbol: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param gray_code: Tell modulator to Gray code the bits
+ @type gray_code: bool
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param log: Log modulation data to files?
+ @type log: bool
+ """
+
+ gr.hier_block2.__init__(self, "dbpsk_mod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._gray_code = gray_code
+
+ if self._samples_per_symbol < 2:
+ raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol)
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
+
+ if self._gray_code:
+ self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity])
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity])
+
+ # pulse shaping filter
+ nfilts = 32
+ ntaps = nfilts * 11 * int(self._samples_per_symbol) # make nfilts filters of ntaps each
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ nfilts, # gain
+ nfilts, # sampling rate based on 32 filters in resampler
+ 1.0, # symbol rate
+ self._excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+ self.rrc_filter = gr.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps)
+
+ # Connect
+ self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
+ self.chunks2symbols, self.rrc_filter, self)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # static method that's also callable on an instance
+ return 1
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def add_options(parser):
+ """
+ Adds DBPSK modulation-specific options to the standard parser
+ """
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default]")
+ parser.add_option("", "--no-gray-code", dest="gray_code",
+ action="store_false", default=True,
+ help="disable gray coding on modulated bits (PSK)")
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils2.extract_kwargs_from_options(dbpsk_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+ def _print_verbage(self):
+ print "\nModulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "Gray code: %s" % self._gray_code
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.bytes2chunks,
+ gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "tx_graycoder.dat"))
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "tx_diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat"))
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# DBPSK demodulator
+#
+# Differentially coherent detection of differentially encoded BPSK
+# /////////////////////////////////////////////////////////////////////////////
+
+class dbpsk_demod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ freq_alpha=_def_freq_alpha,
+ phase_damping=_def_phase_damping,
+ phase_natfreq=_def_phase_natfreq,
+ timing_alpha=_def_timing_alpha,
+ timing_max_dev=_def_timing_max_dev,
+ gray_code=_def_gray_code,
+ verbose=_def_verbose,
+ log=_def_log,
+ sync_out=False):
+ """
+ Hierarchical block for RRC-filtered differential 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 samples_per_symbol: samples per symbol >= 2
+ @type samples_per_symbol: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param freq_alpha: loop filter gain for frequency recovery
+ @type freq_alpha: float
+ @param phase_damping: loop filter damping factor for phase/fine frequency recovery
+ @type phase_damping: float
+ @param phase_natfreq: loop filter natural frequency for phase/fine frequency recovery
+ @type phase_natfreq: float
+ @param timing_alpha: loop alpha gain for timing recovery
+ @type timing_alpha: float
+ @param timing_max: timing loop maximum rate deviations
+ @type timing_max: float
+ @param gray_code: Tell modulator to Gray code the bits
+ @type gray_code: bool
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param log: Print modualtion data to files?
+ @type log: bool
+ @param sync_out: Output a sync signal on :1?
+ @type sync_out: bool
+ """
+ if sync_out: io_sig_out = gr.io_signaturev(2, 2, (gr.sizeof_char, gr.sizeof_gr_complex))
+ else: io_sig_out = gr.io_signature(1, 1, gr.sizeof_char)
+
+ gr.hier_block2.__init__(self, "dbpsk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ io_sig_out) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._freq_alpha = freq_alpha
+ self._freq_beta = 0.10*self._freq_alpha
+ self._phase_damping = phase_damping
+ self._phase_natfreq = phase_natfreq
+ self._timing_alpha = timing_alpha
+ self._timing_beta = _def_timing_beta
+ self._timing_max_dev=timing_max_dev
+ self._gray_code = gray_code
+
+ if samples_per_symbol < 2:
+ raise TypeError, "samples_per_symbol must be >= 2, is %r" % (samples_per_symbol,)
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # Automatic gain control
+ self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
+ #self.agc = gr.feedforward_agc_cc(16, 1.0)
+
+ # Frequency correction
+ self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ 11*int(self._samples_per_symbol),
+ self._freq_alpha, self._freq_beta)
+
+ # symbol timing recovery with RRC data filter
+ nfilts = 32
+ ntaps = 11 * int(self._samples_per_symbol*nfilts)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts,
+ 1.0/float(self._samples_per_symbol),
+ self._excess_bw, ntaps)
+ self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
+ self._timing_alpha,
+ taps, nfilts, nfilts/2, self._timing_max_dev)
+ self.time_recov.set_beta(self._timing_beta)
+
+ # Perform phase / fine frequency correction
+ self.phase_recov = digital_swig.costas_loop_cc(self._phase_damping,
+ self._phase_natfreq,
+ arity)
+
+ # Do differential decoding based on phase change of symbols
+ self.diffdec = gr.diff_phasor_cc()
+
+ # find closest constellation point
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, psk.constellation[arity])
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+
+ if self._gray_code:
+ self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect
+ self.connect(self, self.agc,
+ self.freq_recov, self.time_recov, self.phase_recov,
+ self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
+ if sync_out: self.connect(self.phase_recov, (self, 1))
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 1
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ print "\nDemodulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "Gray code: %s" % self._gray_code
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+ print "FLL gain: %.2e" % self._freq_alpha
+ print "Timing alpha gain: %.2e" % self._timing_alpha
+ print "Timing beta gain: %.2e" % self._timing_beta
+ print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
+ self.connect(self.freq_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
+ self.connect(self.time_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect(self.phase_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat"))
+ self.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
+ self.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "rx_slicer.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "rx_symbol_mapper.dat"))
+ self.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "rx_unpack.dat"))
+
+ def add_options(parser):
+ """
+ Adds DBPSK demodulation-specific options to the standard parser
+ """
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default] (PSK)")
+ parser.add_option("", "--no-gray-code", dest="gray_code",
+ action="store_false", default=_def_gray_code,
+ help="disable gray coding on modulated bits (PSK)")
+ parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
+ help="set frequency lock loop alpha gain value [default=%default] (PSK)")
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default] (PSK)")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
+ help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)")
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
+ help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)")
+ parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
+ help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)")
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils2.extract_kwargs_from_options(
+ dbpsk_demod.__init__, ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('dbpsk3', dbpsk_mod)
+modulation_utils2.add_type_1_demod('dbpsk3', dbpsk_demod)
diff --git a/gr-digital/python/dqpsk.py b/gr-digital/python/dqpsk.py
new file mode 100644
index 000000000..29afd5530
--- /dev/null
+++ b/gr-digital/python/dqpsk.py
@@ -0,0 +1,374 @@
+#
+# Copyright 2009,2010,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+differential QPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, modulation_utils2
+from math import pi, sqrt
+import digital_swig, psk
+import cmath
+from pprint import pprint
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 2
+_def_excess_bw = 0.35
+_def_gray_code = True
+_def_verbose = False
+_def_log = False
+
+_def_freq_alpha = 0.010
+_def_phase_damping = 0.4
+_def_phase_natfreq = 0.25
+_def_timing_alpha = 0.100
+_def_timing_beta = 0.010
+_def_timing_max_dev = 1.5
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# DQPSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class dqpsk_mod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ gray_code=_def_gray_code,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ 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 samples_per_symbol: samples per symbol >= 2
+ @type samples_per_symbol: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param gray_code: Tell modulator to Gray code the bits
+ @type gray_code: bool
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param debug: Print modualtion data to files?
+ @type debug: bool
+ """
+
+ gr.hier_block2.__init__(self, "dqpsk_mod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._gray_code = gray_code
+
+ if samples_per_symbol < 2:
+ raise TypeError, ("sbp must be >= 2, is %f" % samples_per_symbol)
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
+
+ if self._gray_code:
+ self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity])
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ rot = .707 + .707j
+ rotated_const = map(lambda pt: pt * rot, psk.constellation[arity])
+ self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
+
+ # pulse shaping filter
+ nfilts = 32
+ ntaps = 11 * int(nfilts * self._samples_per_symbol) # make nfilts filters of ntaps each
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ nfilts, # gain
+ nfilts, # sampling rate based on 32 filters in resampler
+ 1.0, # symbol rate
+ self._excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+ self.rrc_filter = gr.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect & Initialize base class
+ self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
+ self.chunks2symbols, self.rrc_filter, self)
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 2
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ print "\nModulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "Gray code: %s" % self._gray_code
+ print "RRC roll-off factor: %f" % self._excess_bw
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.bytes2chunks,
+ gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "tx_graycoder.dat"))
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "tx_diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat"))
+
+ def add_options(parser):
+ """
+ Adds QPSK modulation-specific options to the standard parser
+ """
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default] (PSK)")
+ parser.add_option("", "--no-gray-code", dest="gray_code",
+ action="store_false", default=_def_gray_code,
+ help="disable gray coding on modulated bits (PSK)")
+ add_options=staticmethod(add_options)
+
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils2.extract_kwargs_from_options(dqpsk_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# DQPSK demodulator
+#
+# Differentially coherent detection of differentially encoded qpsk
+# /////////////////////////////////////////////////////////////////////////////
+
+class dqpsk_demod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ freq_alpha=_def_freq_alpha,
+ phase_damping=_def_phase_damping,
+ phase_natfreq=_def_phase_natfreq,
+ timing_alpha=_def_timing_alpha,
+ timing_max_dev=_def_timing_max_dev,
+ gray_code=_def_gray_code,
+ verbose=_def_verbose,
+ log=_def_log,
+ sync_out=False):
+ """
+ Hierarchical block for RRC-filtered DQPSK demodulation
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param samples_per_symbol: samples per symbol >= 2
+ @type samples_per_symbol: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param freq_alpha: loop filter gain for frequency recovery
+ @type freq_alpha: float
+ @param phase_damping: loop filter damping factor for phase/fine frequency recovery
+ @type phase_damping: float
+ @param phase_natfreq: loop filter natural frequency for phase/fine frequency recovery
+ @type phase_natfreq: float
+ @param timing_alpha: timing loop alpha gain
+ @type timing_alpha: float
+ @param timing_max: timing loop maximum rate deviations
+ @type timing_max: float
+ @param gray_code: Tell modulator to Gray code the bits
+ @type gray_code: bool
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param log: Print modualtion data to files?
+ @type log: bool
+ @param sync_out: Output a sync signal on :1?
+ @type sync_out: bool
+ """
+ if sync_out: io_sig_out = gr.io_signaturev(2, 2, (gr.sizeof_char, gr.sizeof_gr_complex))
+ else: io_sig_out = gr.io_signature(1, 1, gr.sizeof_char)
+
+ gr.hier_block2.__init__(self, "dqpsk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ io_sig_out) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._freq_alpha = freq_alpha
+ self._freq_beta = 0.25*self._freq_alpha**2
+ self._phase_damping = phase_damping
+ self._phase_natfreq = phase_natfreq
+ self._timing_alpha = timing_alpha
+ self._timing_beta = _def_timing_beta
+ self._timing_max_dev=timing_max_dev
+ self._gray_code = gray_code
+
+ if samples_per_symbol < 2:
+ raise TypeError, "sbp must be >= 2, is %d" % samples_per_symbol
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # Automatic gain control
+ self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
+ #self.agc = gr.feedforward_agc_cc(16, 2.0)
+
+ # Frequency correction
+ self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ 11*int(self._samples_per_symbol),
+ self._freq_alpha, self._freq_beta)
+
+
+ # symbol timing recovery with RRC data filter
+ nfilts = 32
+ ntaps = 11 * int(samples_per_symbol*nfilts)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts,
+ 1.0/float(self._samples_per_symbol),
+ self._excess_bw, ntaps)
+ self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
+ self._timing_alpha,
+ taps, nfilts, nfilts/2, self._timing_max_dev)
+ self.time_recov.set_beta(self._timing_beta)
+
+
+ # Perform phase / fine frequency correction
+ self.phase_recov = digital_swig.costas_loop_cc(self._phase_damping,
+ self._phase_natfreq,
+ arity)
+
+ # Perform Differential decoding on the constellation
+ self.diffdec = gr.diff_phasor_cc()
+
+ # find closest constellation point
+ rot = 1
+ rotated_const = map(lambda pt: pt * rot, psk.constellation[arity])
+ self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+
+ if self._gray_code:
+ self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity])
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect
+ self.connect(self, self.agc,
+ self.freq_recov, self.time_recov, self.phase_recov,
+ self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
+ if sync_out: self.connect(self.phase_recov, (self, 1))
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 2
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ print "\nDemodulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "Gray code: %s" % self._gray_code
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+ print "FLL gain: %.2f" % self._freq_alpha
+ print "Timing alpha gain: %.2f" % self._timing_alpha
+ print "Timing beta gain: %.2f" % self._timing_beta
+ print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
+ self.connect(self.freq_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
+ self.connect(self.time_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect(self.phase_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat"))
+ self.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
+ self.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "rx_slicer.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "rx_gray_decoder.dat"))
+ self.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "rx_unpack.dat"))
+
+ def add_options(parser):
+ """
+ Adds DQPSK demodulation-specific options to the standard parser
+ """
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default] (PSK)")
+ parser.add_option("", "--no-gray-code", dest="gray_code",
+ action="store_false", default=_def_gray_code,
+ help="disable gray coding on modulated bits (PSK)")
+ parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
+ help="set frequency lock loop alpha gain value [default=%default] (PSK)")
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default] (PSK)")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
+ help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)")
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
+ help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)")
+ parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
+ help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)")
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils2.extract_kwargs_from_options(
+ dqpsk_demod.__init__, ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('dqpsk', dqpsk_mod)
+modulation_utils2.add_type_1_demod('dqpsk', dqpsk_demod)
diff --git a/gr-digital/python/generic_mod_demod.py b/gr-digital/python/generic_mod_demod.py
new file mode 100644
index 000000000..f8051db0a
--- /dev/null
+++ b/gr-digital/python/generic_mod_demod.py
@@ -0,0 +1,397 @@
+#
+# Copyright 2005,2006,2007,2009,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+Generic modulation and demodulation.
+"""
+
+from gnuradio import gr
+from modulation_utils2 import extract_kwargs_from_options_for_class
+#from gnuradio.digital.utils import mod_codes
+from utils import mod_codes
+import digital_swig
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 2
+_def_excess_bw = 0.35
+_def_verbose = False
+_def_log = False
+
+# Frequency correction
+_def_freq_alpha = 0.010
+# Symbol timing recovery
+_def_timing_alpha = 0.100
+_def_timing_beta = 0.010
+_def_timing_max_dev = 1.5
+# Fine frequency / Phase correction
+_def_phase_alpha = 0.1
+# Number of points in constellation
+_def_constellation_points = 16
+# Whether differential coding is used.
+_def_differential = True
+
+def add_common_options(parser):
+ """
+ Sets options common to both modulator and demodulator.
+ """
+ parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points,
+ help="set the number of constellation points (must be a power of 2 (power of 4 for QAM) [default=%default]")
+ parser.add_option("", "--differential", action="store_true", dest="differential", default=True,
+ help="use differential encoding [default=%default]")
+ parser.add_option("", "--not-differential", action="store_false", dest="differential",
+ help="do not use differential encoding [default=%default]")
+ parser.add_option("", "--mod-code", type="choice", choices=mod_codes.codes,
+ default=mod_codes.NO_CODE,
+ help="Select modulation code from: %s [default=%%default]"
+ % (', '.join(mod_codes.codes),))
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default]")
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# Generic modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class generic_mod(gr.hier_block2):
+
+ def __init__(self, constellation,
+ differential=_def_differential,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for RRC-filtered differential generic modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param constellation: determines the modulation type
+ @type constellation: gnuradio.digital.gr_constellation
+ @param samples_per_symbol: samples per baud >= 2
+ @type samples_per_symbol: integer
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param log: Log modulation data to files?
+ @type log: bool
+ """
+
+ gr.hier_block2.__init__(self, "generic_mod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._constellation = constellation.base()
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._differential = differential
+
+ if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2:
+ raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol)
+
+ ntaps = 11 * self._samples_per_symbol
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
+
+ if self._constellation.apply_pre_diff_code():
+ self.symbol_mapper = gr.map_bb(self._constellation.pre_diff_code())
+
+ if differential:
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ self.chunks2symbols = gr.chunks_to_symbols_bc(self._constellation.points())
+
+ # pulse shaping filter
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ self._samples_per_symbol, # gain (samples_per_symbol since we're
+ # interpolating by samples_per_symbol)
+ self._samples_per_symbol, # sampling rate
+ 1.0, # symbol rate
+ self._excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+ self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol,
+ self.rrc_taps)
+
+ # Connect
+ blocks = [self, self.bytes2chunks]
+ if self._constellation.apply_pre_diff_code():
+ blocks.append(self.symbol_mapper)
+ if differential:
+ blocks.append(self.diffenc)
+ blocks += [self.chunks2symbols, self.rrc_filter, self]
+ self.connect(*blocks)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self): # static method that's also callable on an instance
+ return self._constellation.bits_per_symbol()
+
+ def add_options(parser):
+ """
+ Adds generic modulation options to the standard parser
+ """
+ add_common_options(parser)
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(cls, options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return extract_kwargs_from_options_for_class(cls, options)
+ extract_kwargs_from_options=classmethod(extract_kwargs_from_options)
+
+
+ def _print_verbage(self):
+ print "\nModulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.bytes2chunks,
+ gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat"))
+ if self._constellation.apply_pre_diff_code():
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "tx_symbol_mapper.dat"))
+ if self._differential:
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "tx_diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat"))
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# Generic demodulator
+#
+# Differentially coherent detection of differentially encoded generically
+# modulated signal.
+# /////////////////////////////////////////////////////////////////////////////
+
+class generic_demod(gr.hier_block2):
+
+ def __init__(self, constellation,
+ samples_per_symbol=_def_samples_per_symbol,
+ differential=_def_differential,
+ excess_bw=_def_excess_bw,
+ freq_alpha=_def_freq_alpha,
+ timing_alpha=_def_timing_alpha,
+ timing_max_dev=_def_timing_max_dev,
+ phase_alpha=_def_phase_alpha,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for RRC-filtered differential generic demodulation.
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param constellation: determines the modulation type
+ @type constellation: gnuradio.digital.gr_constellation
+ @param samples_per_symbol: samples per symbol >= 2
+ @type samples_per_symbol: float
+ @param excess_bw: Root-raised cosine filter excess bandwidth
+ @type excess_bw: float
+ @param freq_alpha: loop filter gain for frequency recovery
+ @type freq_alpha: float
+ @param timing_alpha: loop alpha gain for timing recovery
+ @type timing_alpha: float
+ @param timing_max_dev: timing loop maximum rate deviations
+ @type timing_max_dev: float
+ @param phase_alpha: loop filter gain in phase loop
+ @type phase_alphas: float
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param debug: Print modualtion data to files?
+ @type debug: bool
+ """
+
+ gr.hier_block2.__init__(self, "generic_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ self._constellation = constellation.base()
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._phase_alpha = phase_alpha
+ self._freq_alpha = freq_alpha
+ self._freq_beta = 0.10*self._freq_alpha
+ self._timing_alpha = timing_alpha
+ self._timing_beta = _def_timing_beta
+ self._timing_max_dev=timing_max_dev
+ self._differential = differential
+
+ if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2:
+ raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol)
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # Automatic gain control
+ self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
+
+ # Frequency correction
+ self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ 11*int(self._samples_per_symbol),
+ self._freq_alpha, self._freq_beta)
+
+ # symbol timing recovery with RRC data filter
+ nfilts = 32
+ ntaps = 11 * int(self._samples_per_symbol*nfilts)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts,
+ 1.0/float(self._samples_per_symbol),
+ self._excess_bw, ntaps)
+ self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
+ self._timing_alpha,
+ taps, nfilts, nfilts/2, self._timing_max_dev)
+ self.time_recov.set_beta(self._timing_beta)
+
+ #self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
+ self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
+ fmin = -0.25
+ fmax = 0.25
+
+ self.receiver = digital_swig.constellation_receiver_cb(
+ self._constellation,
+ self._phase_alpha, self._phase_beta,
+ fmin, fmax)
+
+ # Do differential decoding based on phase change of symbols
+ if differential:
+ self.diffdec = gr.diff_decoder_bb(arity)
+
+ if self._constellation.apply_pre_diff_code():
+ self.symbol_mapper = gr.map_bb(
+ mod_codes.invert_code(self._constellation.pre_diff_code()))
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect and Initialize base class
+ blocks = [self, self.agc, self.freq_recov, self.time_recov, self.receiver]
+ if differential:
+ blocks.append(self.diffdec)
+ if self._constellation.apply_pre_diff_code():
+ blocks.append(self.symbol_mapper)
+ blocks += [self.unpack, self]
+ self.connect(*blocks)
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self): # staticmethod that's also callable on an instance
+ return self._constellation.bits_per_symbol()
+
+ def _print_verbage(self):
+ print "\nDemodulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+ print "FLL gain: %.2e" % self._freq_alpha
+ print "Timing alpha gain: %.2e" % self._timing_alpha
+ print "Timing beta gain: %.2e" % self._timing_beta
+ print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
+ self.connect((self.freq_recov, 0),
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
+ self.connect((self.freq_recov, 1),
+ gr.file_sink(gr.sizeof_float, "rx_freq_recov_freq.dat"))
+ self.connect((self.freq_recov, 2),
+ gr.file_sink(gr.sizeof_float, "rx_freq_recov_phase.dat"))
+ self.connect((self.freq_recov, 3),
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov_error.dat"))
+ self.connect((self.time_recov, 0),
+ gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect((self.time_recov, 1),
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_error.dat"))
+ self.connect((self.time_recov, 2),
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_rate.dat"))
+ self.connect((self.time_recov, 3),
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_phase.dat"))
+ self.connect((self.receiver, 0),
+ gr.file_sink(gr.sizeof_char, "rx_receiver.dat"))
+ self.connect((self.receiver, 1),
+ gr.file_sink(gr.sizeof_float, "rx_receiver_error.dat"))
+ self.connect((self.receiver, 2),
+ gr.file_sink(gr.sizeof_float, "rx_receiver_phase.dat"))
+ self.connect((self.receiver, 3),
+ gr.file_sink(gr.sizeof_float, "rx_receiver_freq.dat"))
+ if self._differential:
+ self.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_char, "rx_diffdec.dat"))
+ if self._constellation.apply_pre_diff_code():
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "rx_symbol_mapper.dat"))
+ self.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "rx_unpack.dat"))
+
+ def add_options(parser):
+ """
+ Adds generic demodulation options to the standard parser
+ """
+ # Add options shared with modulator.
+ add_common_options(parser)
+ # Add options specific to demodulator.
+ parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
+ help="set frequency lock loop alpha gain value [default=%default]")
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default]")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
+ help="set timing symbol sync loop gain alpha value [default=%default]")
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
+ help="set timing symbol sync loop gain beta value [default=%default]")
+ parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
+ help="set timing symbol sync loop maximum deviation [default=%default]")
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(cls, options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return extract_kwargs_from_options_for_class(cls, options)
+ extract_kwargs_from_options=classmethod(extract_kwargs_from_options)
+
diff --git a/gr-digital/python/modulation_utils2.py b/gr-digital/python/modulation_utils2.py
new file mode 100644
index 000000000..f30055f4a
--- /dev/null
+++ b/gr-digital/python/modulation_utils2.py
@@ -0,0 +1,101 @@
+#
+# Copyright 2010 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 3, 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 this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+"""
+Miscellaneous utilities for managing mods and demods, as well as other items
+useful in dealing with generalized handling of different modulations and demods.
+"""
+
+import inspect
+
+
+# Type 1 modulators accept a stream of bytes on their input and produce complex baseband output
+_type_1_modulators = {}
+
+def type_1_mods():
+ return _type_1_modulators
+
+def add_type_1_mod(name, mod_class):
+ _type_1_modulators[name] = mod_class
+
+
+# Type 1 demodulators accept complex baseband input and produce a stream of bits, packed
+# 1 bit / byte as their output. Their output is completely unambiguous. There is no need
+# to resolve phase or polarity ambiguities.
+_type_1_demodulators = {}
+
+def type_1_demods():
+ return _type_1_demodulators
+
+def add_type_1_demod(name, demod_class):
+ _type_1_demodulators[name] = demod_class
+
+# Also record the constellation making functions of the modulations
+_type_1_constellations = {}
+
+def type_1_constellations():
+ return _type_1_constellations
+
+def add_type_1_constellation(name, constellation):
+ _type_1_constellations[name] = constellation
+
+
+def extract_kwargs_from_options(function, excluded_args, options):
+ """
+ Given a function, a list of excluded arguments and the result of
+ parsing command line options, create a dictionary of key word
+ arguments suitable for passing to the function. The dictionary
+ will be populated with key/value pairs where the keys are those
+ that are common to the function's argument list (minus the
+ excluded_args) and the attributes in options. The values are the
+ corresponding values from options unless that value is None.
+ In that case, the corresponding dictionary entry is not populated.
+
+ (This allows different modulations that have the same parameter
+ names, but different default values to coexist. The downside is
+ that --help in the option parser will list the default as None,
+ but in that case the default provided in the __init__ argument
+ list will be used since there is no kwargs entry.)
+
+ @param function: the function whose parameter list will be examined
+ @param excluded_args: function arguments that are NOT to be added to the dictionary
+ @type excluded_args: sequence of strings
+ @param options: result of command argument parsing
+ @type options: optparse.Values
+ """
+ # Try this in C++ ;)
+ args, varargs, varkw, defaults = inspect.getargspec(function)
+ d = {}
+ for kw in [a for a in args if a not in excluded_args]:
+ if hasattr(options, kw):
+ if getattr(options, kw) is not None:
+ d[kw] = getattr(options, kw)
+ return d
+
+def extract_kwargs_from_options_for_class(cls, options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ d = extract_kwargs_from_options(
+ cls.__init__, ('self',), options)
+ for base in cls.__bases__:
+ if hasattr(base, 'extract_kwargs_from_options'):
+ d.update(base.extract_kwargs_from_options(options))
+ return d
diff --git a/gr-digital/python/ofdm.py b/gr-digital/python/ofdm.py
new file mode 100644
index 000000000..e05f074f4
--- /dev/null
+++ b/gr-digital/python/ofdm.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+#
+# Copyright 2006,2007,2008 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import math
+from gnuradio import gr, ofdm_packet_utils, modulation_utils2
+import gnuradio.gr.gr_threading as _threading
+import psk, qam
+
+from gnuradio.blks2impl.ofdm_receiver import ofdm_receiver
+
+def _add_common_options(normal, expert):
+ """
+ Adds OFDM-specific options to the Options Parser that are common
+ both to the modulator and demodulator.
+ """
+ mods_list = ", ".join(modulation_utils2.type_1_constellations().keys())
+ print dir(modulation_utils2)
+ print "MODS LIST: ", mods_list
+ print modulation_utils2.type_1_mods()
+ normal.add_option("-m", "--modulation", type="string", default="psk",
+ help="set modulation type (" + mods_list + ") [default=%default]")
+ normal.add_option("-c", "--constellation-points", type="int", default=2,
+ help="set number of constellation points [default=%default]")
+ expert.add_option("", "--fft-length", type="intx", default=512,
+ help="set the number of FFT bins [default=%default]")
+ expert.add_option("", "--occupied-tones", type="intx", default=200,
+ help="set the number of occupied FFT bins [default=%default]")
+ expert.add_option("", "--cp-length", type="intx", default=128,
+ help="set the number of bits in the cyclic prefix [default=%default]")
+
+# /////////////////////////////////////////////////////////////////////////////
+# mod/demod with packets as i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class ofdm_mod(gr.hier_block2):
+ """
+ Modulates an OFDM stream. Based on the options fft_length, occupied_tones, and
+ cp_length, this block creates OFDM symbols using a specified modulation option.
+
+ Send packets by calling send_pkt
+ """
+ def __init__(self, options, 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 options: pass modulation options from higher layers (fft length, occupied tones, etc.)
+ @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
+ """
+
+ gr.hier_block2.__init__(self, "ofdm_mod",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._pad_for_usrp = pad_for_usrp
+ self._modulation = options.modulation
+ self._fft_length = options.fft_length
+ self._occupied_tones = options.occupied_tones
+ self._cp_length = options.cp_length
+
+ print (options)
+ arity = options.constellation_points
+
+ win = [] #[1 for i in range(self._fft_length)]
+
+ # Use freq domain to get doubled-up known symbol for correlation in time domain
+ zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0))
+ ksfreq = known_symbols_4512_3[0:self._occupied_tones]
+ for i in range(len(ksfreq)):
+ if((zeros_on_left + i) & 1):
+ ksfreq[i] = 0
+
+ # hard-coded known symbols
+ preambles = (ksfreq,)
+
+ padded_preambles = list()
+ for pre in preambles:
+ padded = self._fft_length*[0,]
+ padded[zeros_on_left : zeros_on_left + self._occupied_tones] = pre
+ padded_preambles.append(padded)
+
+ symbol_length = options.fft_length + options.cp_length
+
+ print modulation_utils2.type_1_constellations
+ const = modulation_utils2.type_1_constellations()[self._modulation](arity).points()
+
+ self._pkt_input = gr.ofdm_mapper_bcv(const, msgq_limit,
+ options.occupied_tones, options.fft_length)
+
+ self.preambles = gr.ofdm_insert_preamble(self._fft_length, padded_preambles)
+ self.ifft = gr.fft_vcc(self._fft_length, False, win, True)
+ self.cp_adder = gr.ofdm_cyclic_prefixer(self._fft_length, symbol_length)
+ self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length))
+
+ self.connect((self._pkt_input, 0), (self.preambles, 0))
+ self.connect((self._pkt_input, 1), (self.preambles, 1))
+ self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self)
+
+ if options.verbose:
+ self._print_verbage()
+
+ if options.log:
+ self.connect(self._pkt_input, gr.file_sink(gr.sizeof_gr_complex*options.fft_length,
+ "ofdm_mapper_c.dat"))
+ self.connect(self.preambles, gr.file_sink(gr.sizeof_gr_complex*options.fft_length,
+ "ofdm_preambles.dat"))
+ self.connect(self.ifft, gr.file_sink(gr.sizeof_gr_complex*options.fft_length,
+ "ofdm_ifft_c.dat"))
+ self.connect(self.cp_adder, gr.file_sink(gr.sizeof_gr_complex,
+ "ofdm_cp_adder_c.dat"))
+
+ 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 = ofdm_packet_utils.make_packet(payload, 1, 1, self._pad_for_usrp, whitening=True)
+
+ #print "pkt =", string_to_hex_list(pkt)
+ msg = gr.message_from_string(pkt)
+ self._pkt_input.msgq().insert_tail(msg)
+
+ def add_options(normal, expert):
+ """
+ Adds OFDM-specific options to the Options Parser
+ """
+ _add_common_options(normal, expert)
+ for mod in modulation_utils2.type_1_mods().values():
+ mod.add_options(expert)
+
+ # Make a static method to call before instantiation
+ add_options = staticmethod(add_options)
+
+ def _print_verbage(self):
+ """
+ Prints information about the OFDM modulator
+ """
+ print "\nOFDM Modulator:"
+ print "Modulation Type: %s" % (self._modulation)
+ print "FFT length: %3d" % (self._fft_length)
+ print "Occupied Tones: %3d" % (self._occupied_tones)
+ print "CP length: %3d" % (self._cp_length)
+
+
+class ofdm_demod(gr.hier_block2):
+ """
+ Demodulates a received OFDM stream. Based on the options fft_length, occupied_tones, and
+ cp_length, this block performs synchronization, FFT, and demodulation of incoming OFDM
+ symbols and passes packets up the a higher layer.
+
+ The input is complex baseband. When packets are demodulated, they are passed to the
+ app via the callback.
+ """
+
+ def __init__(self, options, callback=None):
+ """
+ Hierarchical block for demodulating and deframing packets.
+
+ The input is the complex modulated signal at baseband.
+ Demodulated packets are sent to the handler.
+
+ @param options: pass modulation options from higher layers (fft length, occupied tones, etc.)
+ @param callback: function of two args: ok, payload
+ @type callback: ok: bool; payload: string
+ """
+ gr.hier_block2.__init__(self, "ofdm_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+
+ self._rcvd_pktq = gr.msg_queue() # holds packets from the PHY
+
+ self._modulation = options.modulation
+ self._fft_length = options.fft_length
+ self._occupied_tones = options.occupied_tones
+ self._cp_length = options.cp_length
+ self._snr = options.snr
+
+ arity = options.constellation_points
+ print("con points is %s" % options.constellation_points)
+
+ # Use freq domain to get doubled-up known symbol for correlation in time domain
+ zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0))
+ ksfreq = known_symbols_4512_3[0:self._occupied_tones]
+ for i in range(len(ksfreq)):
+ if((zeros_on_left + i) & 1):
+ ksfreq[i] = 0
+
+ # hard-coded known symbols
+ preambles = (ksfreq,)
+
+ symbol_length = self._fft_length + self._cp_length
+ self.ofdm_recv = ofdm_receiver(self._fft_length, self._cp_length,
+ self._occupied_tones, self._snr, preambles,
+ options.log)
+
+ constell = modulation_utils2.type_1_constellations()[self._modulation](arity)
+
+ phgain = 0.25
+ frgain = phgain*phgain / 4.0
+ self.ofdm_demod = gr.ofdm_frame_sink2(constell.base(),
+ self._rcvd_pktq,
+ self._occupied_tones,
+ phgain, frgain)
+
+ self.connect(self, self.ofdm_recv)
+ self.connect((self.ofdm_recv, 0), (self.ofdm_demod, 0))
+ self.connect((self.ofdm_recv, 1), (self.ofdm_demod, 1))
+
+ # added output signature to work around bug, though it might not be a bad
+ # thing to export, anyway
+ self.connect(self.ofdm_recv.chan_filt, self)
+
+ if options.log:
+ self.connect(self.ofdm_demod, gr.file_sink(gr.sizeof_gr_complex*self._occupied_tones, "ofdm_frame_sink_c.dat"))
+ else:
+ self.connect(self.ofdm_demod, gr.null_sink(gr.sizeof_gr_complex*self._occupied_tones))
+
+ if options.verbose:
+ self._print_verbage()
+
+ self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+
+ def add_options(normal, expert):
+ """
+ Adds OFDM-specific options to the Options Parser
+ """
+ _add_common_options(normal, expert)
+ for mod in modulation_utils2.type_1_mods().values():
+ mod.add_options(expert)
+ # Make a static method to call before instantiation
+ add_options = staticmethod(add_options)
+
+ def _print_verbage(self):
+ """
+ Prints information about the OFDM demodulator
+ """
+ print "\nOFDM Demodulator:"
+ print "Modulation Type: %s" % (self._modulation)
+ print "FFT length: %3d" % (self._fft_length)
+ print "Occupied Tones: %3d" % (self._occupied_tones)
+ print "CP length: %3d" % (self._cp_length)
+
+
+
+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 = ofdm_packet_utils.unmake_packet(msg.to_string())
+ if self.callback:
+ self.callback(ok, payload)
+
+# Generating known symbols with:
+# i = [2*random.randint(0,1)-1 for i in range(4512)]
+
+known_symbols_4512_3 = [-1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1]
diff --git a/gr-digital/python/pkt.py b/gr-digital/python/pkt.py
new file mode 100644
index 000000000..aa720d1a5
--- /dev/null
+++ b/gr-digital/python/pkt.py
@@ -0,0 +1,184 @@
+#
+# Copyright 2005, 2006, 2007 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from math import pi
+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_block2):
+ """
+ Wrap an arbitrary digital modulator in our packet handling framework.
+
+ Send packets by calling send_pkt
+ """
+ def __init__(self, modulator, access_code=None, msgq_limit=2, pad_for_usrp=True, use_whitener_offset=False,
+ modulate=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 modulator: instance of modulator class (gr_block or hier_block2)
+ @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
+ @param use_whitener_offset: If true, start of whitener XOR string is incremented each packet
+ @param modulate: If false, no modulation will be performed.
+
+ See gmsk_mod for remaining parameters
+ """
+ if modulate:
+ output_size = gr.sizeof_gr_complex
+ else:
+ output_size = gr.sizeof_char
+
+ gr.hier_block2.__init__(self, "mod_pkts",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, output_size)) # Output signature
+
+ self._modulator = modulator
+ self._pad_for_usrp = pad_for_usrp
+ self._use_whitener_offset = use_whitener_offset
+ self._whitener_offset = 0
+
+ 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)
+ if modulate:
+ self.connect(self._pkt_input, self._modulator, self)
+ else:
+ self.connect(self._pkt_input, self)
+
+ 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_symbol(),
+ self._modulator.bits_per_symbol(),
+ self._access_code,
+ self._pad_for_usrp,
+ self._whitener_offset)
+ #print "pkt =", string_to_hex_list(pkt)
+ msg = gr.message_from_string(pkt)
+ if self._use_whitener_offset is True:
+ self._whitener_offset = (self._whitener_offset + 1) % 16
+
+ self._pkt_input.msgq().insert_tail(msg)
+
+
+
+class demod_pkts(gr.hier_block2):
+ """
+ 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, demodulator, access_code=None, callback=None, threshold=-1, demodulate=True):
+ """
+ Hierarchical block for demodulating and deframing packets.
+
+ The input is the complex modulated signal at baseband.
+ Demodulated packets are sent to the handler.
+
+ If demodulator is None it is assumed the input is already demodulated.
+
+ @param demodulator: instance of demodulator class (gr_block or hier_block2)
+ @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
+ """
+
+ if demodulator is not None:
+ input_size = gr.sizeof_gr_complex
+ else:
+ input_size = gr.sizeof_char
+
+ gr.hier_block2.__init__(self, "demod_pkts",
+ gr.io_signature(1, 1, input_size), # Input signature
+ gr.io_signature(0, 0, 0)) # Output signature
+
+ 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)
+ if self._demodulator is not None:
+ self.connect(self, self._demodulator, self.correlator, self.framer_sink)
+ else:
+ self.connect(self, self.correlator, self.framer_sink)
+
+ if callback is not 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(), int(msg.arg1()))
+ if self.callback:
+ self.callback(ok, payload)
diff --git a/gr-digital/python/psk.py b/gr-digital/python/psk.py
new file mode 100644
index 000000000..acedf3b69
--- /dev/null
+++ b/gr-digital/python/psk.py
@@ -0,0 +1,94 @@
+#
+# 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from math import pi, sqrt, log10
+import math, cmath
+
+# The following algorithm generates Gray coded constellations for M-PSK for M=[2,4,8]
+def make_gray_constellation(m):
+ # number of bits/symbol (log2(M))
+ k = int(log10(m) / log10(2.0))
+
+ coeff = 1
+ const_map = []
+ bits = [0]*3
+ for i in range(m):
+ # get a vector of the k bits to use in this mapping
+ bits[3-k:3] = [((i&(0x01 << k-j-1)) >> k-j-1) for j in range(k)]
+
+ theta = -(2*bits[0]-1)*(2*pi/m)*(bits[0]+abs(bits[1]-bits[2])+2*bits[1])
+ re = math.cos(theta)
+ im = math.sin(theta)
+ const_map.append(complex(re, im)) # plug it into the constellation
+
+ # return the constellation; by default, it is normalized
+ return const_map
+
+# This makes a constellation that increments around the unit circle
+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
+ }
+
+gray_constellation = {
+ 2 : make_gray_constellation(2), # BPSK
+ 4 : make_gray_constellation(4), # QPSK
+ 8 : make_gray_constellation(8) # 8PSK
+ }
+
+# -----------------------
+# Do Gray code
+# -----------------------
+# binary to gray coding -- constellation does Gray coding
+binary_to_gray = {
+ 2 : range(2),
+ 4 : [0,1,3,2],
+ 8 : [0, 1, 3, 2, 7, 6, 4, 5]
+ }
+
+# gray to binary
+gray_to_binary = {
+ 2 : range(2),
+ 4 : [0,1,3,2],
+ 8 : [0, 1, 3, 2, 6, 7, 5, 4]
+ }
+
+# -----------------------
+# Don't Gray code
+# -----------------------
+# identity mapping
+binary_to_ungray = {
+ 2 : range(2),
+ 4 : range(4),
+ 8 : range(8)
+ }
+
+# identity mapping
+ungray_to_binary = {
+ 2 : range(2),
+ 4 : range(4),
+ 8 : range(8)
+ }
diff --git a/gr-digital/python/psk2.py b/gr-digital/python/psk2.py
new file mode 100644
index 000000000..778c1e5e5
--- /dev/null
+++ b/gr-digital/python/psk2.py
@@ -0,0 +1,123 @@
+#
+# Copyright 2005,2006,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+"""
+PSK modulation and demodulation.
+"""
+
+from math import pi, log
+from cmath import exp
+
+from gnuradio import gr
+import digital_swig
+import modulation_utils2
+from utils import mod_codes, gray_code
+from generic_mod_demod import generic_mod, generic_demod
+
+# Default number of points in constellation.
+_def_constellation_points = 4
+# The default encoding (e.g. gray-code, set-partition)
+_def_mod_code = mod_codes.GRAY_CODE
+
+def create_encodings(mod_code, arity):
+ post_diff_code = None
+ if mod_code not in mod_codes.codes:
+ raise ValueError('That modulation code does not exist.')
+ if mod_code == mod_codes.GRAY_CODE:
+ pre_diff_code = gray_code.gray_code(arity)
+ elif mod_code == mod_codes.SET_PARTITION_CODE:
+ pre_diff_code = set_partition_code.set_partition_code(arity)
+ elif mod_code == mod_codes.NO_CODE:
+ pre_diff_code = []
+ else:
+ raise ValueError('That modulation code is not implemented for this constellation.')
+ return (pre_diff_code, post_diff_code)
+
+# /////////////////////////////////////////////////////////////////////////////
+# PSK constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def psk_constellation(m=_def_constellation_points, mod_code=_def_mod_code):
+ """
+ Creates a PSK constellation object.
+ """
+ k = log(m) / log(2.0)
+ if (k != int(k)):
+ raise StandardError('Number of constellation points must be a power of two.')
+ points = [exp(2*pi*(0+1j)*i/m) for i in range(0,m)]
+ pre_diff_code, post_diff_code = create_encodings(mod_code, m)
+ if post_diff_code is not None:
+ inverse_post_diff_code = mod_codes.invert_code(post_diff_code)
+ points = [points[x] for x in inverse_post_diff_code]
+ constellation = digital_swig.constellation_psk(points, pre_diff_code, m)
+ return constellation
+
+# /////////////////////////////////////////////////////////////////////////////
+# PSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class psk_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ 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.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = psk_constellation(constellation_points, mod_code)
+ super(psk_mod, self).__init__(constellation, *args, **kwargs)
+
+# /////////////////////////////////////////////////////////////////////////////
+# PSK demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class psk_demod(generic_demod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ 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.
+
+ See generic_demod block for list of parameters.
+ """
+
+ constellation = psk_constellation(constellation_points, mod_code)
+ super(psk_demod, self).__init__(constellation, *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('psk', psk_mod)
+modulation_utils2.add_type_1_demod('psk', psk_demod)
+modulation_utils2.add_type_1_constellation('psk', psk_constellation)
diff --git a/gr-digital/python/qa_constellation.py b/gr-digital/python/qa_constellation.py
new file mode 100755
index 000000000..02afb8d2d
--- /dev/null
+++ b/gr-digital/python/qa_constellation.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import random
+from cmath import exp, pi, log
+
+from gnuradio import gr, gr_unittest, blks2
+from utils import mod_codes
+import digital_swig
+
+# import from local folder
+import psk2
+import qam
+
+tested_mod_codes = (mod_codes.NO_CODE, mod_codes.GRAY_CODE)
+
+# A list of the constellations to test.
+# Each constellation is given by a 3-tuple.
+# First item is a function to generate the constellation
+# Second item is a dictionary of arguments for function with lists of
+# possible values.
+# Third item is whether differential encoding should be tested.
+# Fourth item is the name of the argument to constructor that specifices
+# whether differential encoding is used.
+
+def twod_constell():
+ """
+
+ """
+ points = ((1+0j), (0+1j),
+ (-1+0j), (0-1j))
+ rot_sym = 2
+ dim = 2
+ return digital_swig.constellation_calcdist(points, [], rot_sym, dim)
+
+def threed_constell():
+ oned_points = ((1+0j), (0+1j), (-1+0j), (0-1j))
+ points = []
+ r4 = range(0, 4)
+ for ia in r4:
+ for ib in r4:
+ for ic in r4:
+ points += [oned_points[ia], oned_points[ib], oned_points[ic]]
+ rot_sym = 4
+ dim = 3
+ return digital_swig.constellation_calcdist(points, [], rot_sym, dim)
+
+tested_constellation_info = (
+ (psk2.psk_constellation,
+ {'m': (2, 4, 8, 16, 32, 64),
+ 'mod_code': tested_mod_codes, },
+ True, None),
+ (digital_swig.constellation_bpsk, {}, True, None),
+ # No differential testing for qpsk because it is gray-coded.
+ # This is because soft decision making is simpler if we can assume
+ # gray coding.
+ (digital_swig.constellation_qpsk, {}, False, None),
+ (digital_swig.constellation_8psk, {}, False, None),
+ (twod_constell, {}, True, None),
+ (threed_constell, {}, True, None),
+ )
+
+def tested_constellations():
+ """
+ Generator to produce (constellation, differential) tuples for testing purposes.
+ """
+ for constructor, poss_args, differential, diff_argname in tested_constellation_info:
+ if differential:
+ diff_poss = (True, False)
+ else:
+ diff_poss = (False,)
+ poss_args = [[argname, argvalues, 0] for argname, argvalues in poss_args.items()]
+ for current_diff in diff_poss:
+ # Add an index into args to keep track of current position in argvalues
+ while True:
+ current_args = dict([(argname, argvalues[argindex])
+ for argname, argvalues, argindex in poss_args])
+ if diff_argname is not None:
+ current_args[diff_argname] = current_diff
+ constellation = constructor(**current_args)
+ yield (constellation, current_diff)
+ for this_poss_arg in poss_args:
+ argname, argvalues, argindex = this_poss_arg
+ if argindex < len(argvalues) - 1:
+ this_poss_arg[2] += 1
+ break
+ else:
+ this_poss_arg[2] = 0
+ if sum([argindex for argname, argvalues, argindex in poss_args]) == 0:
+ break
+
+
+class test_constellation (gr_unittest.TestCase):
+
+ src_length = 256
+
+ def setUp(self):
+ # Generate a list of random bits.
+ self.src_data = tuple([random.randint(0,1) for i in range(0, self.src_length)])
+
+ def tearDown(self):
+ pass
+
+ def test_hard_decision(self):
+ for constellation, differential in tested_constellations():
+ if differential:
+ rs = constellation.rotational_symmetry()
+ rotations = [exp(i*2*pi*(0+1j)/rs) for i in range(0, rs)]
+ else:
+ rotations = [None]
+ for rotation in rotations:
+ src = gr.vector_source_b(self.src_data)
+ content = mod_demod(constellation, differential, rotation)
+ dst = gr.vector_sink_b()
+ self.tb = gr.top_block()
+ self.tb.connect(src, content, dst)
+ self.tb.run()
+ data = dst.data()
+ # Don't worry about cut off data for now.
+ first = constellation.bits_per_symbol()
+ self.assertEqual (self.src_data[first:len(data)], data[first:])
+
+
+class mod_demod(gr.hier_block2):
+ def __init__(self, constellation, differential, rotation):
+ if constellation.arity() > 256:
+ # If this becomes limiting some of the blocks should be generalised so that they can work
+ # with shorts and ints as well as chars.
+ raise ValueError("Constellation cannot contain more than 256 points.")
+
+ gr.hier_block2.__init__(self, "mod_demod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ arity = constellation.arity()
+
+ # TX
+ self.constellation = constellation
+ self.differential = differential
+ self.blocks = [self]
+ # We expect a stream of unpacked bits.
+ # First step is to pack them.
+ self.blocks.append(
+ gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST))
+ # Second step we unpack them such that we have k bits in each byte where
+ # each constellation symbol hold k bits.
+ self.blocks.append(
+ gr.packed_to_unpacked_bb(self.constellation.bits_per_symbol(),
+ gr.GR_MSB_FIRST))
+ # Apply any pre-differential coding
+ # Gray-coding is done here if we're also using differential coding.
+ if self.constellation.apply_pre_diff_code():
+ self.blocks.append(gr.map_bb(self.constellation.pre_diff_code()))
+ # Differential encoding.
+ if self.differential:
+ self.blocks.append(gr.diff_encoder_bb(arity))
+ # Convert to constellation symbols.
+ self.blocks.append(gr.chunks_to_symbols_bc(self.constellation.points(), self.constellation.dimensionality()))
+ # CHANNEL
+ # Channel just consists of a rotation to check differential coding.
+ if rotation is not None:
+ self.blocks.append(gr.multiply_const_cc(rotation))
+
+ # RX
+ # Convert the constellation symbols back to binary values.
+ self.blocks.append(digital_swig.constellation_decoder_cb(self.constellation.base()))
+ # Differential decoding.
+ if self.differential:
+ self.blocks.append(gr.diff_decoder_bb(arity))
+ # Decode any pre-differential coding.
+ if self.constellation.apply_pre_diff_code():
+ self.blocks.append(gr.map_bb(
+ mod_codes.invert_code(self.constellation.pre_diff_code())))
+ # unpack the k bit vector into a stream of bits
+ self.blocks.append(gr.unpack_k_bits_bb(
+ self.constellation.bits_per_symbol()))
+ # connect to block output
+ check_index = len(self.blocks)
+ self.blocks = self.blocks[:check_index]
+ self.blocks.append(self)
+
+ self.connect(*self.blocks)
+
+
+if __name__ == '__main__':
+ gr_unittest.run(test_constellation, "test_constellation.xml")
diff --git a/gr-digital/python/qa_constellation_receiver.py b/gr-digital/python/qa_constellation_receiver.py
new file mode 100755
index 000000000..70b62c7aa
--- /dev/null
+++ b/gr-digital/python/qa_constellation_receiver.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import random
+
+from gnuradio import gr, blks2, packet_utils, gr_unittest
+from utils import mod_codes, alignment
+import digital_swig
+from generic_mod_demod import generic_mod, generic_demod
+
+from qa_constellation import tested_constellations, twod_constell
+
+
+# Set a seed so that if errors turn up they are reproducible.
+# 1234 fails
+random.seed(1239)
+
+# TESTING PARAMETERS
+# The number of symbols to test with.
+# We need this many to let the frequency recovery block converge.
+DATA_LENGTH = 200000
+# Test fails if fraction of output that is correct is less than this.
+REQ_CORRECT = 0.8
+
+# CHANNEL PARAMETERS
+NOISE_VOLTAGE = 0.01
+FREQUENCY_OFFSET = 0.01
+TIMING_OFFSET = 1.0
+
+# RECEIVER PARAMETERS
+# Increased from normal default of 0.01 to speed things up.
+FREQ_ALPHA = 0.02
+# Decreased from normal default of 0.1 is required for the constellations
+# with smaller point separations.
+PHASE_ALPHA = 0.02
+
+
+class test_constellation_receiver (gr_unittest.TestCase):
+
+ # We ignore the first half of the output data since often it takes
+ # a while for the receiver to lock on.
+ ignore_fraction = 0.8
+ seed = 1234
+ max_data_length = DATA_LENGTH * 6
+ max_num_samples = 1000
+
+ def test_basic(self):
+ """
+ Tests a bunch of different constellations by using generic
+ modulation, a channel, and generic demodulation. The generic
+ demodulation uses constellation_receiver which is what
+ we're really trying to test.
+ """
+
+ # Assumes not more than 64 points in a constellation
+ # Generates some random input data to use.
+ self.src_data = tuple(
+ [random.randint(0,1) for i in range(0, self.max_data_length)])
+ # Generates some random indices to use for comparing input and
+ # output data (a full comparison is too slow in python).
+ self.indices = alignment.random_sample(
+ self.max_data_length, self.max_num_samples, self.seed)
+
+ for constellation, differential in tested_constellations():
+ # The constellation_receiver doesn't work for constellations
+ # of multple dimensions (i.e. multiple complex numbers to a
+ # single symbol).
+ # That is not implemented since the receiver has no way of
+ # knowing where the beginning of a symbol is.
+ # It also doesn't work for non-differential modulation.
+ if constellation.dimensionality() != 1 or not differential:
+ continue
+ data_length = DATA_LENGTH * constellation.bits_per_symbol()
+ tb = rec_test_tb(constellation, differential,
+ src_data=self.src_data[:data_length])
+ tb.run()
+ data = tb.dst.data()
+ d1 = tb.src_data[:int(len(tb.src_data)*self.ignore_fraction)]
+ d2 = data[:int(len(data)*self.ignore_fraction)]
+ correct, overlap, offset, indices = alignment.align_sequences(
+ d1, d2, indices=self.indices)
+ self.assertTrue(correct > REQ_CORRECT)
+
+
+class rec_test_tb (gr.top_block):
+ """
+ Takes a constellation an runs a generic modulation, channel,
+ and generic demodulation.
+ """
+ def __init__(self, constellation, differential,
+ data_length=None, src_data=None):
+ """
+ constellation -- a constellation object
+ differential -- whether differential encoding is used
+ data_length -- the number of bits of data to use
+ src_data -- a list of the bits to use
+ """
+ super(rec_test_tb, self).__init__()
+ # Transmission Blocks
+ if src_data is None:
+ self.src_data = tuple([random.randint(0,1) for i in range(0, data_length)])
+ else:
+ self.src_data = src_data
+ packer = gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST)
+ src = gr.vector_source_b(self.src_data)
+ mod = generic_mod(constellation, differential=differential)
+ # Channel
+ channel = gr.channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET)
+ # Receiver Blocks
+ demod = generic_demod(constellation, differential=differential,
+ freq_alpha=FREQ_ALPHA,
+ phase_alpha=PHASE_ALPHA)
+ self.dst = gr.vector_sink_b()
+ self.connect(src, packer, mod, channel, demod, self.dst)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_constellation_receiver, "test_constellation_receiver.xml")
diff --git a/gr-digital/python/qa_costas_loop_cc.py b/gr-digital/python/qa_costas_loop_cc.py
new file mode 100755
index 000000000..368704093
--- /dev/null
+++ b/gr-digital/python/qa_costas_loop_cc.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, blks2, gr_unittest
+import digital_swig
+import random, cmath
+
+class test_digital(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test01 (self):
+ # test basic functionality by setting all gains to 0
+ damp = 0.4
+ natfreq = 0.25
+ order = 2
+ self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+
+ data = 100*[complex(1,0),]
+ self.src = gr.vector_source_c(data, False)
+ self.snk = gr.vector_sink_c()
+
+ self.tb.connect(self.src, self.test, self.snk)
+ self.tb.run()
+
+ expected_result = data
+ dst_data = self.snk.data()
+ self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 5)
+
+ def test02 (self):
+ # Make sure it doesn't diverge given perfect data
+ damp = 0.4
+ natfreq = 0.25
+ order = 2
+ self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+
+ data = [complex(2*random.randint(0,1)-1, 0) for i in xrange(100)]
+ self.src = gr.vector_source_c(data, False)
+ self.snk = gr.vector_sink_c()
+
+ self.tb.connect(self.src, self.test, self.snk)
+ self.tb.run()
+
+ expected_result = data
+ dst_data = self.snk.data()
+
+ self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 5)
+
+ def test03 (self):
+ # BPSK Convergence test with static rotation
+ damp = 0.4
+ natfreq = 0.25
+ order = 2
+ self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+
+ rot = cmath.exp(0.2j) # some small rotation
+ data = [complex(2*random.randint(0,1)-1, 0) for i in xrange(100)]
+
+ N = 40 # settling time
+ expected_result = data[N:]
+ data = [rot*d for d in data]
+
+ self.src = gr.vector_source_c(data, False)
+ self.snk = gr.vector_sink_c()
+
+ self.tb.connect(self.src, self.test, self.snk)
+ self.tb.run()
+
+ dst_data = self.snk.data()[N:]
+
+ # generously compare results; the loop will converge near to, but
+ # not exactly on, the target data
+ self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 2)
+
+ def test04 (self):
+ # QPSK Convergence test with static rotation
+ damp = 0.4
+ natfreq = 0.25
+ order = 4
+ self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+
+ rot = cmath.exp(0.2j) # some small rotation
+ data = [complex(2*random.randint(0,1)-1, 2*random.randint(0,1)-1)
+ for i in xrange(100)]
+
+ N = 40 # settling time
+ expected_result = data[N:]
+ data = [rot*d for d in data]
+
+ self.src = gr.vector_source_c(data, False)
+ self.snk = gr.vector_sink_c()
+
+ self.tb.connect(self.src, self.test, self.snk)
+ self.tb.run()
+
+ dst_data = self.snk.data()[N:]
+
+ # generously compare results; the loop will converge near to, but
+ # not exactly on, the target data
+ self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 2)
+
+ def test05 (self):
+ # 8PSK Convergence test with static rotation
+ damp = 0.5
+ natfreq = 0.5
+ order = 8
+ self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+
+ rot = cmath.exp(-cmath.pi/8.0j) # rotate to match Costas rotation
+ const = blks2.psk.make_constellation(order)
+ data = [random.randint(0,7) for i in xrange(100)]
+ data = [2*rot*const[d] for d in data]
+
+ N = 40 # settling time
+ expected_result = data[N:]
+
+ rot = cmath.exp(0.1j) # some small rotation
+ data = [rot*d for d in data]
+
+ self.src = gr.vector_source_c(data, False)
+ self.snk = gr.vector_sink_c()
+
+ self.tb.connect(self.src, self.test, self.snk)
+ self.tb.run()
+
+ dst_data = self.snk.data()[N:]
+
+ # generously compare results; the loop will converge near to, but
+ # not exactly on, the target data
+ self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 2)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_digital, "test_digital.xml")
diff --git a/gr-digital/python/qa_digital.py b/gr-digital/python/qa_digital.py
new file mode 100755
index 000000000..97e35da56
--- /dev/null
+++ b/gr-digital/python/qa_digital.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig
+
+class test_digital(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+if __name__ == '__main__':
+ gr_unittest.run(test_digital, "test_digital.xml")
diff --git a/gr-digital/python/qam.py b/gr-digital/python/qam.py
new file mode 100644
index 000000000..ee2b1e416
--- /dev/null
+++ b/gr-digital/python/qam.py
@@ -0,0 +1,227 @@
+#
+# Copyright 2005,2006,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+"""
+QAM modulation and demodulation.
+"""
+
+from math import pi, sqrt, log
+
+from gnuradio import gr
+import modulation_utils2
+from generic_mod_demod import generic_mod, generic_demod
+from utils.gray_code import gray_code
+from utils import mod_codes
+
+# Default number of points in constellation.
+_def_constellation_points = 16
+# Whether the quadrant bits are coded differentially.
+_def_differential = True
+# Whether gray coding is used. If differential is True then gray
+# coding is used within but not between each quadrant.
+_def_mod_code = mod_codes.NO_CODE
+
+def is_power_of_four(x):
+ v = log(x)/log(4)
+ return int(v) == v
+
+def get_bit(x, n):
+ """ Get the n'th bit of integer x (from little end)."""
+ return (x&(0x01 << n)) >> n
+
+def get_bits(x, n, k):
+ """ Get the k bits of integer x starting at bit n(from little end)."""
+ # Remove the n smallest bits
+ v = x >> n
+ # Remove all bits bigger than n+k-1
+ return v % pow(2, k)
+
+def make_differential_constellation(m, gray_coded):
+ """
+ Create a constellation with m possible symbols where m must be
+ a power of 4.
+
+ Points are laid out in a square grid.
+
+ Bits referring to the quadrant are differentilly encoded,
+ remaining bits are gray coded.
+
+ """
+ sqrtm = pow(m, 0.5)
+ if (not isinstance(m, int) or m < 4 or not is_power_of_four(m)):
+ raise ValueError("m must be a power of 4 integer.")
+ # Each symbol holds k bits.
+ k = int(log(m) / log(2.0))
+ # First create a constellation for one quadrant containing m/4 points.
+ # The quadrant has 'side' points along each side of a quadrant.
+ side = int(sqrtm/2)
+ if gray_coded:
+ # Number rows and columns using gray codes.
+ gcs = gray_code(side)
+ # Get inverse gray codes.
+ i_gcs = dict([(v, key) for key, v in enumerate(gcs)])
+ else:
+ i_gcs = dict([(i, i) for i in range(0, side)])
+ # The distance between points is found.
+ step = 1/(side-0.5)
+
+ gc_to_x = [(i_gcs[gc]+0.5)*step for gc in range(0, side)]
+
+ # Takes the (x, y) location of the point with the quadrant along
+ # with the quadrant number. (x, y) are integers referring to which
+ # point within the quadrant it is.
+ # A complex number representing this location of this point is returned.
+ def get_c(gc_x, gc_y, quad):
+ if quad == 0:
+ return complex(gc_to_x[gc_x], gc_to_x[gc_y])
+ if quad == 1:
+ return complex(-gc_to_x[gc_y], gc_to_x[gc_x])
+ if quad == 2:
+ return complex(-gc_to_x[gc_x], -gc_to_x[gc_y])
+ if quad == 3:
+ return complex(gc_to_x[gc_y], -gc_to_x[gc_x])
+ raise StandardError("Impossible!")
+
+ # First two bits determine quadrant.
+ # Next (k-2)/2 bits determine x position.
+ # Following (k-2)/2 bits determine y position.
+ # How x and y relate to real and imag depends on quadrant (see get_c function).
+ const_map = []
+ for i in range(m):
+ y = get_bits(i, 0, (k-2)/2)
+ x = get_bits(i, (k-2)/2, (k-2)/2)
+ quad = get_bits(i, k-2, 2)
+ const_map.append(get_c(x, y, quad))
+
+ return const_map
+
+def make_not_differential_constellation(m, gray_coded):
+ side = int(pow(m, 0.5))
+ if (not isinstance(m, int) or m < 4 or not is_power_of_four(m)):
+ raise ValueError("m must be a power of 4 integer.")
+ # Each symbol holds k bits.
+ k = int(log(m) / log(2.0))
+ if gray_coded:
+ # Number rows and columns using gray codes.
+ gcs = gray_code(side)
+ # Get inverse gray codes.
+ i_gcs = mod_codes.invert_code(gcs)
+ else:
+ i_gcs = range(0, side)
+ # The distance between points is found.
+ step = 2.0/(side-1)
+
+ gc_to_x = [-1 + i_gcs[gc]*step for gc in range(0, side)]
+ # First k/2 bits determine x position.
+ # Following k/2 bits determine y position.
+ const_map = []
+ for i in range(m):
+ y = gc_to_x[get_bits(i, 0, k/2)]
+ x = gc_to_x[get_bits(i, k/2, k/2)]
+ const_map.append(complex(x,y))
+ return const_map
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def qam_constellation(constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ mod_code=_def_mod_code):
+ """
+ Creates a QAM constellation object.
+ """
+ if mod_code == mod_codes.GRAY_CODE:
+ gray_coded = True
+ elif mod_code == mod_codes.NO_CODE:
+ gray_coded = False
+ else:
+ raise ValueError("Mod code is not implemented for QAM")
+ if differential:
+ points = make_differential_constellation(constellation_points, gray_coded)
+ else:
+ points = make_not_differential_constellation(constellation_points, gray_coded)
+ side = int(sqrt(constellation_points))
+ width = 2.0/(side-1)
+ # No pre-diff code
+ # Should add one so that we can gray-code the quadrant bits too.
+ pre_diff_code = []
+ constellation = gr.constellation_rect(points, pre_diff_code, 4, side, side, width, width)
+ return constellation
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered QAM modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = qam_constellation(constellation_points, differential, mod_code)
+ # We take care of the gray coding in the constellation generation so it doesn't
+ # need to be done in the block.
+ super(qam_mod, self).__init__(constellation, differential=differential,
+ *args, **kwargs)
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam_demod(generic_demod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered QAM modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_demod block for list of parameters.
+ """
+ constellation = qam_constellation(constellation_points, differential, mod_code)
+ # We take care of the gray coding in the constellation generation so it doesn't
+ # need to be done in the block.
+ super(qam_demod, self).__init__(constellation, differential=differential,
+ *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('qam', qam_mod)
+modulation_utils2.add_type_1_demod('qam', qam_demod)
+modulation_utils2.add_type_1_constellation('qam', qam_constellation)
diff --git a/gr-digital/python/qpsk.py b/gr-digital/python/qpsk.py
new file mode 100644
index 000000000..ea1724424
--- /dev/null
+++ b/gr-digital/python/qpsk.py
@@ -0,0 +1,79 @@
+#
+# Copyright 2005,2006,2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+"""
+QPSK modulation.
+
+Demodulation is not included since the generic_mod_demod
+doesn't work for non-differential encodings.
+"""
+
+from gnuradio import gr, modulation_utils2
+from gnuradio.digital.generic_mod_demod import generic_mod
+
+
+# Default number of points in constellation.
+_def_constellation_points = 4
+# Whether differential coding is used.
+_def_differential = False
+_def_gray_coded = True
+
+# /////////////////////////////////////////////////////////////////////////////
+# QPSK constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def qpsk_constellation(m=_def_constellation_points):
+ if m != _def_constellation_points:
+ raise ValueError("QPSK can only have 4 constellation points.")
+ return gr.constellation_qpsk()
+
+# /////////////////////////////////////////////////////////////////////////////
+# QPSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qpsk_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ gray_coded=_def_gray_coded,
+ *args, **kwargs):
+
+ """
+ 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.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = gr.constellation_qpsk()
+ if constellation_points != 4:
+ raise ValueError("QPSK can only have 4 constellation points.")
+ if differential or not gray_coded:
+ raise ValueError("This QPSK mod/demod works only for gray-coded, non-differential.")
+ super(qpsk_mod, self).__init__(constellation, differential, gray_coded, *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('qpsk', qpsk_mod)
+modulation_utils2.add_type_1_constellation('qpsk', qpsk_constellation)
diff --git a/gr-digital/python/run_tests.in b/gr-digital/python/run_tests.in
new file mode 100644
index 000000000..b39e7e847
--- /dev/null
+++ b/gr-digital/python/run_tests.in
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# 1st parameter is absolute path to component source directory
+# 2nd parameter is absolute path to component build directory
+# 3rd parameter is path to Python QA directory
+
+@top_builddir@/run_tests.sh \
+ @abs_top_srcdir@/gr-digital \
+ @abs_top_builddir@/gr-digital \
+ @srcdir@
diff --git a/gr-digital/python/utils/.gitignore b/gr-digital/python/utils/.gitignore
new file mode 100644
index 000000000..60c81fdce
--- /dev/null
+++ b/gr-digital/python/utils/.gitignore
@@ -0,0 +1,3 @@
+run_tests
+Makefile
+Makefile.in
diff --git a/gr-digital/python/utils/Makefile.am b/gr-digital/python/utils/Makefile.am
new file mode 100644
index 000000000..6da4d61dd
--- /dev/null
+++ b/gr-digital/python/utils/Makefile.am
@@ -0,0 +1,34 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+if PYTHON
+utilspythondir = $(grpythondir)/digital/utils
+
+TESTS =
+
+utilspython_PYTHON = \
+ __init__.py \
+ gray_code.py \
+ mod_codes.py \
+ alignment.py
+endif \ No newline at end of file
diff --git a/gr-digital/python/utils/__init__.py b/gr-digital/python/utils/__init__.py
new file mode 100644
index 000000000..b3e997f9f
--- /dev/null
+++ b/gr-digital/python/utils/__init__.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
diff --git a/gr-digital/python/utils/alignment.py b/gr-digital/python/utils/alignment.py
new file mode 100644
index 000000000..d32365866
--- /dev/null
+++ b/gr-digital/python/utils/alignment.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+"""
+This module contains functions for aligning sequences.
+
+>>> import random
+>>> random.seed(1234)
+>>> ran_seq = [random.randint(0,1) for i in range(0, 100)]
+>>> offset_seq = [0] * 20 + ran_seq
+>>> correct, overlap, offset = align_sequences(ran_seq, offset_seq)
+>>> print(correct, overlap, offset)
+(1.0, 100, -20)
+>>> offset_err_seq = []
+>>> for bit in offset_seq:
+... if random.randint(0,4) == 4:
+... offset_err_seq.append(random.randint(0,1))
+... else:
+... offset_err_seq.append(bit)
+>>> correct, overlap, offset = align_sequences(ran_seq, offset_err_seq)
+>>> print(overlap, offset)
+(100, -20)
+
+"""
+
+import random
+
+# DEFAULT PARAMETERS
+# If the fraction of matching bits between two sequences is greater than
+# this the sequences are assumed to be aligned.
+def_correct_cutoff = 0.9
+# The maximum offset to test during sequence alignment.
+def_max_offset = 500
+# The maximum number of samples to take from two sequences to check alignment.
+def_num_samples = 1000
+
+def compare_sequences(d1, d2, offset, sample_indices=None):
+ """
+ Takes two binary sequences and an offset and returns the number of
+ matching entries and the number of compared entries.
+ d1 & d2 -- sequences
+ offset -- offset of d2 relative to d1
+ sample_indices -- a list of indices to use for the comparison
+ """
+ max_index = min(len(d1), len(d2)+offset)
+ if sample_indices is None:
+ sample_indices = range(0, max_index)
+ correct = 0
+ total = 0
+ for i in sample_indices:
+ if i >= max_index:
+ break
+ if d1[i] == d2[i-offset]:
+ correct += 1
+ total += 1
+ return (correct, total)
+
+def random_sample(size, num_samples=def_num_samples, seed=None):
+ """
+ Returns a set of random integers between 0 and (size-1).
+ The set contains no more than num_samples integers.
+ """
+ random.seed(seed)
+ if num_samples > size:
+ indices = set(range(0, size))
+ else:
+ if num_samples > size/2:
+ num_samples = num_samples/2
+ indices = set([])
+ while len(indices) < num_samples:
+ index = random.randint(0, size-1)
+ indices.add(index)
+ indices = list(indices)
+ indices.sort()
+ return indices
+
+def align_sequences(d1, d2,
+ num_samples=def_num_samples,
+ max_offset=def_max_offset,
+ correct_cutoff=def_correct_cutoff,
+ seed=None,
+ indices=None):
+ """
+ Takes two sequences and finds the offset and which the two sequences best
+ match. It returns the fraction correct, the number of entries compared,
+ the offset.
+ d1 & d2 -- sequences to compare
+ num_samples -- the maximum number of entries to compare
+ max_offset -- the maximum offset between the sequences that is checked
+ correct_cutoff -- If the fraction of bits correct is greater than this then
+ the offset is assumed to optimum.
+ seed -- a random number seed
+ indices -- an explicit list of the indices used to compare the two sequences
+ """
+ max_overlap = max(len(d1), len(d2))
+ if indices is None:
+ indices = random_sample(max_overlap, num_samples, seed)
+ max_frac_correct = 0
+ best_offset = None
+ best_compared = None
+ best_correct = None
+ pos_range = range(0, min(len(d1), max_offset))
+ neg_range = range(-1, -min(len(d2), max_offset), -1)
+ # Interleave the positive and negative offsets.
+ int_range = [item for items in zip(pos_range, neg_range) for item in items]
+ for offset in int_range:
+ correct, compared = compare_sequences(d1, d2, offset, indices)
+ frac_correct = 1.0*correct/compared
+ if frac_correct > max_frac_correct:
+ max_frac_correct = frac_correct
+ best_offset = offset
+ best_compared = compared
+ best_correct = correct
+ if frac_correct > correct_cutoff:
+ break
+ return max_frac_correct, best_compared, best_offset, indices
+
+if __name__ == "__main__":
+ import doctest
+ doctest.testmod()
+
diff --git a/gr-digital/python/utils/gray_code.py b/gr-digital/python/utils/gray_code.py
new file mode 100644
index 000000000..926a1ded1
--- /dev/null
+++ b/gr-digital/python/utils/gray_code.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+class GrayCodeGenerator(object):
+ """
+ Generates and caches gray codes.
+ """
+
+ def __init__(self):
+ self.gcs = [0, 1]
+ # The last power of two passed through.
+ self.lp2 = 2
+ # The next power of two that will be passed through.
+ self.np2 = 4
+ # Curent index
+ self.i = 2
+
+ def get_gray_code(self, length):
+ """
+ Returns a list of gray code of given length.
+ """
+ if len(self.gcs) < length:
+ self.generate_new_gray_code(length)
+ return self.gcs[:length]
+
+ def generate_new_gray_code(self, length):
+ """
+ Generates new gray code and places into cache.
+ """
+ while len(self.gcs) < length:
+ if self.i == self.lp2:
+ # if i is a power of two then gray number is of form 1100000...
+ result = self.i + self.i/2
+ else:
+ # if not we take advantage of the symmetry of all but the last bit
+ # around a power of two.
+ result = self.gcs[2*self.lp2-1-self.i] + self.lp2
+ self.gcs.append(result)
+ self.i += 1
+ if self.i == self.np2:
+ self.lp2 = self.i
+ self.np2 = self.i*2
+
+_gray_code_generator = GrayCodeGenerator()
+
+gray_code = _gray_code_generator.get_gray_code
+
diff --git a/gr-digital/python/utils/mod_codes.py b/gr-digital/python/utils/mod_codes.py
new file mode 100644
index 000000000..caacda5cc
--- /dev/null
+++ b/gr-digital/python/utils/mod_codes.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+GRAY_CODE = 'gray'
+SET_PARTITION_CODE = 'set-partition'
+NO_CODE = 'none'
+
+codes = (GRAY_CODE, SET_PARTITION_CODE, NO_CODE)
+
+def invert_code(code):
+ c = enumerate(code)
+ ic = [(b, a) for (a, b) in c]
+ ic.sort()
+ return [a for (b, a) in ic]
diff --git a/gr-digital/swig/.gitignore b/gr-digital/swig/.gitignore
new file mode 100644
index 000000000..7e864f43f
--- /dev/null
+++ b/gr-digital/swig/.gitignore
@@ -0,0 +1,9 @@
+/Makefile
+/Makefile.in
+/pager_swig.py
+/pager_swig.cc
+/*.pyc
+/run_tests
+/run_guile_tests
+/guile
+/python
diff --git a/gr-digital/swig/Makefile.am b/gr-digital/swig/Makefile.am
new file mode 100644
index 000000000..b9ebf4cc5
--- /dev/null
+++ b/gr-digital/swig/Makefile.am
@@ -0,0 +1,75 @@
+#
+# Copyright 2011 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+include $(top_srcdir)/Makefile.swig
+
+TESTS =
+EXTRA_DIST += $(nobase_guile_DATA)
+
+AM_CPPFLAGS = \
+ -I$(abs_top_srcdir)/gr-digital/lib \
+ -I$(abs_top_builddir)/gr-digital/lib \
+ $(STD_DEFINES_AND_INCLUDES) \
+ $(PYTHON_CPPFLAGS) \
+ $(WITH_INCLUDES)
+
+if GUILE
+nobase_guile_DATA = \
+ gnuradio/digital.scm
+endif
+
+noinst_GUILE = digital.test
+
+
+##############################
+# SWIG interface and library
+TOP_SWIG_IFILES = \
+ digital_swig.i
+
+# Install so that they end up available as:
+# import gnuradio.digital
+# This ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio/digital
+digital_swig_pythondir_category = \
+ gnuradio/digital
+
+# additional libraries for linking with the SWIG-generated library
+digital_swig_la_swig_libadd = \
+ $(abs_top_builddir)/gr-digital/lib/libgnuradio-digital.la
+
+# additional SWIG files to be installed
+digital_swig_swiginclude_headers = \
+ digital_constellation.i \
+ digital_constellation_receiver_cb.i \
+ digital_constellation_decoder_cb.i \
+ digital_costas_loop_cc.i \
+ digital_cma_equalizer_cc.i \
+ digital_lms_dd_equalizer_cc.i \
+ digital_kurtotic_equalizer_cc.i
+
+digital_swig_swig_args = \
+ -I$(abs_top_srcdir)/gr-digital/lib \
+ -I$(abs_top_builddir)/gr-digital/lib
+
+if GUILE
+TESTS += run_guile_tests
+endif \ No newline at end of file
diff --git a/gr-digital/swig/Makefile.swig.gen b/gr-digital/swig/Makefile.swig.gen
new file mode 100644
index 000000000..bd9aabcea
--- /dev/null
+++ b/gr-digital/swig/Makefile.swig.gen
@@ -0,0 +1,145 @@
+# -*- Makefile -*-
+#
+# Copyright 2009 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# Makefile.swig.gen for digital_swig.i
+
+## Default install locations for these files:
+##
+## Default location for the Python directory is:
+## ${prefix}/lib/python${python_version}/site-packages/[category]/digital_swig
+## Default location for the Python exec directory is:
+## ${exec_prefix}/lib/python${python_version}/site-packages/[category]/digital_swig
+##
+## The following can be overloaded to change the install location, but
+## this has to be done in the including Makefile.am -before-
+## Makefile.swig is included.
+
+digital_swig_pythondir_category ?= gnuradio/digital_swig
+digital_swig_pylibdir_category ?= $(digital_swig_pythondir_category)
+digital_swig_pythondir = $(pythondir)/$(digital_swig_pythondir_category)
+digital_swig_pylibdir = $(pyexecdir)/$(digital_swig_pylibdir_category)
+
+# The .so libraries for the guile modules get installed whereever guile
+# is installed, usually /usr/lib/guile/gnuradio/
+# FIXME: determince whether these should be installed with gnuradio.
+digital_swig_scmlibdir = $(libdir)
+
+# The scm files for the guile modules get installed where ever guile
+# is installed, usually /usr/share/guile/site/digital_swig
+# FIXME: determince whether these should be installed with gnuradio.
+digital_swig_scmdir = $(guiledir)
+
+## SWIG headers are always installed into the same directory.
+
+digital_swig_swigincludedir = $(swigincludedir)
+
+## This is a template file for a "generated" Makefile addition (in
+## this case, "Makefile.swig.gen"). By including the top-level
+## Makefile.swig, this file will be used to generate the SWIG
+## dependencies. Assign the variable TOP_SWIG_FILES to be the list of
+## SWIG .i files to generated wrappings for; there can be more than 1
+## so long as the names are unique (no sorting is done on the
+## TOP_SWIG_FILES list). This file explicitly assumes that a SWIG .i
+## file will generate .cc, .py, and possibly .h files -- meaning that
+## all of these files will have the same base name (that provided for
+## the SWIG .i file).
+##
+## This code is setup to ensure parallel MAKE ("-j" or "-jN") does the
+## right thing. For more info, see <
+## http://sources.redhat.com/automake/automake.html#Multiple-Outputs >
+
+## Other cleaned files: dependency files generated by SWIG or this Makefile
+
+MOSTLYCLEANFILES += $(DEPDIR)/*.S*
+
+## Various SWIG variables. These can be overloaded in the including
+## Makefile.am by setting the variable value there, then including
+## Makefile.swig .
+
+digital_swig_swiginclude_HEADERS = \
+ digital_swig.i \
+ $(digital_swig_swiginclude_headers)
+
+if PYTHON
+digital_swig_pylib_LTLIBRARIES = \
+ _digital_swig.la
+
+_digital_swig_la_SOURCES = \
+ python/digital_swig.cc \
+ $(digital_swig_la_swig_sources)
+
+digital_swig_python_PYTHON = \
+ digital_swig.py \
+ $(digital_swig_python)
+
+_digital_swig_la_LIBADD = \
+ $(STD_SWIG_LA_LIB_ADD) \
+ $(digital_swig_la_swig_libadd)
+
+_digital_swig_la_LDFLAGS = \
+ $(STD_SWIG_LA_LD_FLAGS) \
+ $(digital_swig_la_swig_ldflags)
+
+_digital_swig_la_CXXFLAGS = \
+ $(STD_SWIG_CXX_FLAGS) \
+ -I$(top_builddir) \
+ $(digital_swig_la_swig_cxxflags)
+
+python/digital_swig.cc: digital_swig.py
+digital_swig.py: digital_swig.i
+
+# Include the python dependencies for this file
+-include python/digital_swig.d
+
+endif # end of if python
+
+if GUILE
+
+digital_swig_scmlib_LTLIBRARIES = \
+ libguile-gnuradio-digital_swig.la
+libguile_gnuradio_digital_swig_la_SOURCES = \
+ guile/digital_swig.cc \
+ $(digital_swig_la_swig_sources)
+nobase_digital_swig_scm_DATA = \
+ gnuradio/digital_swig.scm \
+ gnuradio/digital_swig-primitive.scm
+libguile_gnuradio_digital_swig_la_LIBADD = \
+ $(STD_SWIG_LA_LIB_ADD) \
+ $(digital_swig_la_swig_libadd)
+libguile_gnuradio_digital_swig_la_LDFLAGS = \
+ $(STD_SWIG_LA_LD_FLAGS) \
+ $(digital_swig_la_swig_ldflags)
+libguile_gnuradio_digital_swig_la_CXXFLAGS = \
+ $(STD_SWIG_CXX_FLAGS) \
+ -I$(top_builddir) \
+ $(digital_swig_la_swig_cxxflags)
+
+guile/digital_swig.cc: gnuradio/digital_swig.scm
+gnuradio/digital_swig.scm: digital_swig.i
+gnuradio/digital_swig-primitive.scm: gnuradio/digital_swig.scm
+
+# Include the guile dependencies for this file
+-include guile/digital_swig.d
+
+endif # end of GUILE
+
+
diff --git a/gr-digital/swig/digital_cma_equalizer_cc.i b/gr-digital/swig/digital_cma_equalizer_cc.i
new file mode 100644
index 000000000..183e43ef9
--- /dev/null
+++ b/gr-digital/swig/digital_cma_equalizer_cc.i
@@ -0,0 +1,44 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,cma_equalizer_cc)
+
+// retrieve info on the base class, without generating wrappers since
+// the base class has a pure virual method.
+%import "gr_adaptive_fir_ccc.i"
+
+digital_cma_equalizer_cc_sptr
+digital_make_cma_equalizer_cc(int num_taps, float modulus,
+ float mu, int sps);
+
+class digital_cma_equalizer_cc : public gr_adaptive_fir_ccc
+{
+private:
+ digital_cma_equalizer_cc(int num_taps, float modulus,
+ float mu, int sps);
+
+public:
+ float get_gain();
+ void set_gain(float mu);
+ float get_modulus();
+ void set_modulus(float mod);
+};
diff --git a/gr-digital/swig/digital_constellation.i b/gr-digital/swig/digital_constellation.i
new file mode 100644
index 000000000..ae31d443e
--- /dev/null
+++ b/gr-digital/swig/digital_constellation.i
@@ -0,0 +1,171 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010, 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+%template(gr_complex_vector) std::vector<gr_complex>;
+%template(unsigned_int_vector) std::vector<unsigned int>;
+
+// Make sure metric types get SWIGed.
+%include "digital_metric_type.h"
+
+class digital_constellation;
+typedef boost::shared_ptr<digital_constellation> digital_constellation_sptr;
+%template(digital_constellation_sptr) boost::shared_ptr<digital_constellation>;
+
+class digital_constellation
+{
+public:
+ digital_constellation (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+ std::vector<gr_complex> points();
+ std::vector<gr_complex> s_points();
+ std::vector<std::vector<gr_complex> > v_points();
+ virtual unsigned int decision_maker (gr_complex *sample) = 0;
+ unsigned int decision_maker_v (std::vector<gr_complex> sample);
+ // void calc_metric(gr_complex *sample, float *metric, trellis_metric_type_t type);
+ // void calc_euclidean_metric(gr_complex *sample, float *metric);
+ // void calc_hard_symbol_metric(gr_complex *sample, float *metric);
+ std::vector<gr_complex> map_to_points_v(unsigned int value);
+ unsigned int bits_per_symbol ();
+ unsigned int arity ();
+ digital_constellation_sptr base ();
+ bool apply_pre_diff_code();
+ std::vector<unsigned int> pre_diff_code();
+ unsigned int rotational_symmetry();
+ unsigned int dimensionality();
+};
+
+class digital_constellation_calcdist;
+typedef boost::shared_ptr<digital_constellation_calcdist> digital_constellation_calcdist_sptr;
+%template(digital_constellation_calcdist_sptr) boost::shared_ptr<digital_constellation_calcdist>;
+%rename(constellation_calcdist) digital_make_constellation_calcdist;
+digital_constellation_calcdist_sptr
+digital_make_constellation_calcdist(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+%ignore digital_constellation_calcdist;
+
+class digital_constellation_calcdist: public digital_constellation
+{
+ public:
+ digital_constellation_calcdist (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+ unsigned int decision_maker (const gr_complex *sample);
+};
+
+class digital_constellation_sector: public digital_constellation
+{
+};
+
+class digital_constellation_rect;
+typedef boost::shared_ptr<digital_constellation_rect> digital_constellation_rect_sptr;
+%template(digital_constellation_rect_sptr) boost::shared_ptr<digital_constellation_rect>;
+%rename(constellation_rect) digital_make_constellation_rect;
+digital_constellation_rect_sptr digital_make_constellation_rect(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+%ignore digital_constellation_rect;
+
+class digital_constellation_rect : public digital_constellation_sector
+{
+public:
+ digital_constellation_rect (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+};
+
+class digital_constellation_psk;
+typedef boost::shared_ptr<digital_constellation_psk> digital_constellation_psk_sptr;
+%template(digital_constellation_psk_sptr) boost::shared_ptr<digital_constellation_psk>;
+%rename(constellation_psk) digital_make_constellation_psk;
+digital_constellation_psk_sptr digital_make_constellation_psk(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+%ignore digital_constellation_psk;
+
+class digital_constellation_psk : public digital_constellation_sector
+{
+public:
+ digital_constellation_psk (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+};
+
+/*
+ BPSK Constellation
+*/
+
+class digital_constellation_bpsk;
+typedef boost::shared_ptr<digital_constellation_bpsk> digital_constellation_bpsk_sptr;
+%template(digital_constellation_bpsk_sptr) boost::shared_ptr<digital_constellation_bpsk>;
+%rename(constellation_bpsk) digital_make_constellation_bpsk;
+digital_constellation_bpsk_sptr digital_make_constellation_bpsk();
+%ignore digital_constellation_bpsk;
+
+class digital_constellation_bpsk : public digital_constellation
+{
+public:
+ digital_constellation_bpsk ();
+};
+
+/*
+ QPSK Constellation
+*/
+
+class digital_constellation_qpsk;
+typedef boost::shared_ptr<digital_constellation_qpsk> digital_constellation_qpsk_sptr;
+%template(digital_constellation_qpsk_sptr) boost::shared_ptr<digital_constellation_qpsk>;
+%rename(constellation_qpsk) digital_make_constellation_qpsk;
+digital_constellation_qpsk_sptr digital_make_constellation_qpsk();
+%ignore digital_constellation_qpsk;
+
+class digital_constellation_qpsk : public digital_constellation
+{
+public:
+ digital_constellation_qpsk ();
+};
+
+
+/*
+ 8PSK Constellation
+*/
+
+class digital_constellation_8psk;
+typedef boost::shared_ptr<digital_constellation_8psk> digital_constellation_8psk_sptr;
+%template(digital_constellation_8psk_sptr) boost::shared_ptr<digital_constellation_8psk>;
+%rename(constellation_8psk) digital_make_constellation_8psk;
+digital_constellation_8psk_sptr digital_make_constellation_8psk();
+%ignore digital_constellation_8psk;
+
+class digital_constellation_8psk : public digital_constellation
+{
+public:
+ digital_constellation_8psk ();
+};
diff --git a/gr-digital/swig/digital_constellation_decoder_cb.i b/gr-digital/swig/digital_constellation_decoder_cb.i
new file mode 100644
index 000000000..53d3fe8e0
--- /dev/null
+++ b/gr-digital/swig/digital_constellation_decoder_cb.i
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,constellation_decoder_cb)
+
+digital_constellation_decoder_cb_sptr
+digital_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+class digital_constellation_decoder_cb : public gr_sync_block
+{
+ private:
+ digital_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ friend digital_constellation_decoder_cb_sptr
+ gr_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ public:
+ ~digital_constellation_decoder_cb();
+};
diff --git a/gr-digital/swig/digital_constellation_receiver_cb.i b/gr-digital/swig/digital_constellation_receiver_cb.i
new file mode 100644
index 000000000..ad17ef371
--- /dev/null
+++ b/gr-digital/swig/digital_constellation_receiver_cb.i
@@ -0,0 +1,47 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,constellation_receiver_cb);
+
+%include "digital_constellation.i"
+
+digital_constellation_receiver_cb_sptr
+digital_make_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+class digital_constellation_receiver_cb : public gr_block
+{
+ private:
+ digital_constellation_receiver_cb (digital_contellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+public:
+ float alpha() const { return d_alpha; }
+ float beta() const { return d_beta; }
+ float freq() const { return d_freq; }
+ float phase() const { return d_phase; }
+ void set_alpha(float alpha) { d_alpha = alpha; }
+ void set_beta(float beta) { d_beta = beta; }
+ void set_freq(float freq) { d_freq = freq; }
+ void set_phase(float phase) { d_phase = phase; }
+};
diff --git a/gr-digital/swig/digital_costas_loop_cc.i b/gr-digital/swig/digital_costas_loop_cc.i
new file mode 100644
index 000000000..6d3d009f8
--- /dev/null
+++ b/gr-digital/swig/digital_costas_loop_cc.i
@@ -0,0 +1,44 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2006,2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,costas_loop_cc);
+
+digital_costas_loop_cc_sptr
+digital_make_costas_loop_cc (float damping, float nat_freq,
+ int order
+ ) throw (std::invalid_argument);
+
+
+class digital_costas_loop_cc : public gr_sync_block
+{
+ private:
+ digital_costas_loop_cc (float damping, float nat_freq,
+ int order);
+
+ public:
+ float alpha();
+ float beta();
+ float freq();
+
+ void set_natural_freq(float w);
+ void set_damping_factor(float eta);
+};
diff --git a/gr-digital/swig/digital_kurtotic_equalizer_cc.i b/gr-digital/swig/digital_kurtotic_equalizer_cc.i
new file mode 100644
index 000000000..67a9dc6fd
--- /dev/null
+++ b/gr-digital/swig/digital_kurtotic_equalizer_cc.i
@@ -0,0 +1,40 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,kurtotic_equalizer_cc)
+
+// retrieve info on the base class, without generating wrappers since
+// the base class has a pure virual method.
+%import "gr_adaptive_fir_ccc.i"
+
+digital_kurtotic_equalizer_cc_sptr
+digital_make_kurtotic_equalizer_cc(int num_taps,
+ float mu);
+
+class digital_kurtotic_equalizer_cc : public gr_adaptive_fir_ccc
+{
+private:
+ digital_kurtotic_equalizer_cc(int num_taps, float mu);
+
+public:
+ void set_gain(float mu);
+};
diff --git a/gr-digital/swig/digital_lms_dd_equalizer_cc.i b/gr-digital/swig/digital_lms_dd_equalizer_cc.i
new file mode 100644
index 000000000..bd5c6ae29
--- /dev/null
+++ b/gr-digital/swig/digital_lms_dd_equalizer_cc.i
@@ -0,0 +1,46 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+GR_SWIG_BLOCK_MAGIC(digital,lms_dd_equalizer_cc)
+
+// retrieve info on the base class, without generating wrappers since
+// the base class has a pure virual method.
+%import "gr_adaptive_fir_ccc.i"
+
+
+digital_lms_dd_equalizer_cc_sptr
+digital_make_lms_dd_equalizer_cc (int num_taps,
+ float mu, int sps,
+ digital_constellation_sptr cnst);
+
+class digital_lms_dd_equalizer_cc : public gr_sync_block
+{
+private:
+ digital_lms_dd_equalizer_cc (int num_taps,
+ float mu, int sps,
+ digital_constellation_sptr cnst);
+
+public:
+ float get_gain();
+ void set_gain(float mu);
+};
diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i
new file mode 100644
index 000000000..26a9dd130
--- /dev/null
+++ b/gr-digital/swig/digital_swig.i
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+%include "gnuradio.i"
+
+%{
+#include "digital_constellation.h"
+#include "digital_costas_loop_cc.h"
+#include "digital_cma_equalizer_cc.h"
+#include "digital_lms_dd_equalizer_cc.h"
+#include "digital_kurtotic_equalizer_cc.h"
+#include "digital_constellation_receiver_cb.h"
+#include "digital_constellation_decoder_cb.h"
+%}
+
+%include "digital_constellation.i"
+%include "digital_costas_loop_cc.i"
+%include "digital_cma_equalizer_cc.i"
+%include "digital_lms_dd_equalizer_cc.i"
+%include "digital_kurtotic_equalizer_cc.i"
+%include "digital_constellation_receiver_cb.i"
+%include "digital_constellation_decoder_cb.i"
+
+#if SWIGGUILE
+%scheme %{
+(load-extension-global "libguile-gnuradio-digital_swig" "scm_init_gnuradio_digital_swig_module")
+%}
+
+%goops %{
+(use-modules (gnuradio gnuradio_core_runtime))
+%}
+#endif
diff --git a/gr-digital/swig/gnuradio/.gitignore b/gr-digital/swig/gnuradio/.gitignore
new file mode 100644
index 000000000..c264c571a
--- /dev/null
+++ b/gr-digital/swig/gnuradio/.gitignore
@@ -0,0 +1,2 @@
+digital_swig-primitive.scm
+digital_swig.scm
diff --git a/gr-digital/swig/gnuradio/digital.scm b/gr-digital/swig/gnuradio/digital.scm
new file mode 100644
index 000000000..834bc8d6d
--- /dev/null
+++ b/gr-digital/swig/gnuradio/digital.scm
@@ -0,0 +1,28 @@
+;;;
+;;; Copyright 2011 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 3, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+;;;
+
+;;; Module that just re-exports the digital_swig module
+
+(define-module (gnuradio digital)
+ #:use-module (gnuradio export-safely)
+ #:use-module (gnuradio digital_swig)
+ #:duplicates (merge-generics replace check))
+
+(re-export-all '(gnuradio digital_swig))
+
diff --git a/gr-digital/swig/run_guile_tests.in b/gr-digital/swig/run_guile_tests.in
new file mode 100644
index 000000000..5d08b0dd5
--- /dev/null
+++ b/gr-digital/swig/run_guile_tests.in
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. @top_builddir@/setup_guile_test_env
+
+# 1st argument is absolute path to hand coded guile source directory
+# 2nd argument is absolute path to component C++ shared library build directory
+# 3nd argument is absolute path to component SWIG build directory
+
+add_local_paths \
+ @srcdir@ \
+ @abs_builddir@ \
+ @abs_builddir@
+
+@GUILE@ -e main -c '(use-modules (gnuradio test-suite guile-test))' -t @srcdir@