remove old gnuradio <= 3.6 demodulator code

keeps some of the device specific scripts in addition to the (supposedly
generic) osmosdr-tetra_demod_fft.py

Also, update the README file to corresponding changes.

Change-Id: Icae93bb9a6a7219e14931fb6e04a4c6fffa0779d
This commit is contained in:
Harald Welte 2016-12-18 16:51:38 +01:00
parent 409d2985cb
commit 0ca867eda2
21 changed files with 21 additions and 1535 deletions

13
README
View File

@ -1,5 +1,5 @@
TETRA MAC/PHY layer experimentation code
(C) 2010-2011 by Harald Welte <laforge@gnumonks.org>
(C) 2010-2016 by Harald Welte <laforge@gnumonks.org> and contributors
======================================================================
This code aims to implement the sending and receiving part of the
@ -19,12 +19,13 @@ You will need libosmocore (http://bb.osmocom.org/trac/wiki/libosmocore) to link.
src/demod/python/cpsk.py
* contains a gnuradio based pi4/DQPSK demodulator, courtesy of KA1RBI
src/demod/python/tetra-demod.py
src/demod/python/osmosdr-tetra_demod_fft.py
* call demodulator on any source supported by gr-osmosdr
(uhd, fcd, hackrf, blaerf, etc.)
src/demod/python/simdemod2.py
* call demodulator on a 'cfile' containing complex baseband samples
src/demod/python/usrp1-tetra_demod.py
* use demodulator in realtime with a USRP1 SDR
src/demod/python/usrp2-tetra_demod.py
* use demodulator in realtime with a USRP2 SDR
src/demod/python/{uhd,fcdp}-tetra_demod.py
* use demodulator directly with UHd or FCDP hadware (no gr-osmosdr)
The output of the demodulator is a file containing one float value for each symbol,
containing the phase shift (in units of pi/4) relative to the previous symbol.

View File

@ -1,39 +0,0 @@
#
# Copyright 2001,2006,2008,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.
#
ACLOCAL_AMFLAGS = -I config
AUTOMAKE_OPTIONS = foreign
include $(top_srcdir)/Makefile.common
SUBDIRS = python apps config grc
export pythondir
install-data-hook:
@if ! python -c "import gnuradio" > /dev/null 2>&1; then\
printf "\n*** Post-Install Message ***\
\nWarning: python could not find the gnuradio module.\
\nMake sure that $${pythondir} is in your PYTHONPATH\n\n";\
fi

View File

@ -1,77 +0,0 @@
# -*- Makefile -*-
#
# Copyright 2004,2006,2009,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 GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
# The name of this "out-of-tree" module
modname = tetra_demod
# these flags are used when compiling non-SWIG-wrapper files
# when going in to non-SWIG libraries
AM_CXXFLAGS = @autoconf_default_CXXFLAGS@
# Sets ABI version in SONAME and appends -LIBVER to filename
LTVERSIONFLAGS = -version-info 0:0:0 -release $(LIBVER)
# these flags are used when compiling any CXX file
AM_CPPFLAGS = \
$(STD_DEFINES_AND_INCLUDES) \
$(PYTHON_CPPFLAGS) \
$(CPPUNIT_INCLUDES) \
$(GNURADIO_CORE_CPPFLAGS)
# these are used by both SWIG and CXX
STD_DEFINES_AND_INCLUDES = \
$(DEFINES) \
-I$(abs_top_srcdir)/lib \
-I$(GNURADIO_CORE_INCLUDEDIR) \
-I$(GNURADIO_CORE_INCLUDEDIR)/swig
# includes
modincludedir = $(includedir)/$(modname)
# swig includes
swigincludedir = $(modincludedir)/swig
# Install this stuff in the appropriate subdirectory
# This usually ends up at:
# ${prefix}/lib/python${python_version}/site-packages/$(modname)
modpythondir = $(pythondir)/$(modname)
modpyexecdir = $(pyexecdir)/$(modname)
# Data directory for grc block wrappers
grc_blocksdir = $(prefix)/share/gnuradio/grc/blocks
# Don't assume that make predefines $(RM), because BSD make does
# not. We define it now in configure.ac using AM_PATH_PROG, but now
# here have to add a -f to be like GNU make.
RM=$(RM_PROG) -f
# Other common defines; use "+=" to add to these
STAMPS =
MOSTLYCLEANFILES = $(BUILT_SOURCES) $(STAMPS) *.pyc *.pyo *~ *.tmp *.loT
# Don't distribute the files defined in the variable 'no_dist_files'
dist-hook:
@for file in $(no_dist_files); do \
echo $(RM) $(distdir)/$$file; \
$(RM) $(distdir)/$$file; \
done;

View File

@ -1,31 +0,0 @@
#
# Copyright 2001,2006,2008,2009,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 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
# Install m4 macros in this directory
m4datadir = $(datadir)/aclocal
# List your m4 macros here
m4macros = \
gr_standalone.m4
EXTRA_DIST = $(m4macros)

View File

@ -1,135 +0,0 @@
dnl
dnl Copyright 2008,2009 Free Software Foundation, Inc.
dnl
dnl This file is part of GNU Radio
dnl
dnl GNU Radio is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3, or (at your option)
dnl any later version.
dnl
dnl GNU Radio is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License along
dnl with this program; if not, write to the Free Software Foundation, Inc.,
dnl 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
dnl
dnl
dnl GR_STANDALONE([package],[version])
dnl
dnl Handles the bulk of the configure.ac work for an out-of-tree build
dnl
dnl N.B., this is an m4_define because if it were an AC_DEFUN it would
dnl get called too late to be useful.
m4_define([GR_STANDALONE],
[
AC_CONFIG_SRCDIR([config/gr_standalone.m4])
AM_CONFIG_HEADER(config.h)
dnl Remember if the user explicity set CXXFLAGS
if test -n "${CXXFLAGS}"; then
user_set_cxxflags=yes
fi
LF_CONFIGURE_CC
LF_CONFIGURE_CXX
GR_LIB64 dnl check for lib64 suffix after choosing compilers
dnl The three macros above are known to override CXXFLAGS if the user
dnl didn't specify them. Though I'm sure somebody thought this was
dnl a good idea, it makes it hard to use other than -g -O2 when compiling
dnl selected files. Thus we "undo" the damage here...
dnl
dnl If the user specified CXXFLAGS, we use them. Otherwise when compiling
dnl the output of swig use use -O1 if we're using g++.
dnl See Makefile.common for the rest of the magic.
if test "$user_set_cxxflags" != yes; then
autoconf_default_CXXFLAGS="$CXXFLAGS"
if test "$GXX" = yes; then
case "$host_cpu" in
powerpc*)
dnl "-O1" is broken on the PPC for some reason
dnl (at least as of g++ 4.1.1)
swig_CXXFLAGS="-g1 -O2 -Wno-strict-aliasing -Wno-parentheses"
;;
*)
swig_CXXFLAGS="-g -O1 -Wno-strict-aliasing -Wno-parentheses"
;;
esac
fi
fi
AC_SUBST(autoconf_default_CXXFLAGS)
AC_SUBST(swig_CXXFLAGS)
dnl add ${prefix}/lib${gr_libdir_suffix}/pkgconfig to the head of the PKG_CONFIG_PATH
if test x${PKG_CONFIG_PATH} = x; then
PKG_CONFIG_PATH=${prefix}/lib${gr_libdir_suffix}/pkgconfig
else
PKG_CONFIG_PATH=${prefix}/lib${gr_libdir_suffix}/pkgconfig:${PKG_CONFIG_PATH}
fi
export PKG_CONFIG_PATH
LF_SET_WARNINGS
GR_SET_GPROF
GR_SET_PROF
AM_PROG_AS
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PATH_PROG([RM_PROG], [rm])
AC_LIBTOOL_WIN32_DLL
AC_ENABLE_SHARED dnl do build shared libraries
AC_DISABLE_STATIC dnl don't build static libraries
m4_ifdef([LT_INIT],[LT_INIT],[AC_PROG_LIBTOOL])
dnl GR_FORTRAN
GR_NO_UNDEFINED dnl do we need the -no-undefined linker flag
GR_SCRIPTING dnl Locate python, SWIG, etc
dnl Checks for header files.
AC_HEADER_STDC
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_C_BIGENDIAN
dnl Check for Mingw support
GR_PWIN32
AC_CHECK_PROG([XMLTO],[xmlto],[yes],[])
AM_CONDITIONAL([HAS_XMLTO], [test x$XMLTO = xyes])
PKG_CHECK_MODULES(GNURADIO_CORE, gnuradio-core >= 3)
LIBS="$LIBS $GNURADIO_CORE_LIBS"
dnl Allow user to choose whether to generate SWIG/Python
dnl Default is enabled
AC_ARG_ENABLE([python],
[AS_HELP_STRING([--enable-python],
[generate SWIG/Python components (default is yes)])],
[case "${enableval}" in
yes) enable_python=yes ;;
no) enable_python=no ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-python]) ;;
esac],
[enable_python=yes]
)
AM_CONDITIONAL([PYTHON], [test x$enable_python = xyes])
dnl Define where to look for cppunit includes and libs
dnl sets CPPUNIT_CFLAGS and CPPUNIT_LIBS
dnl Try using pkg-config first, then fall back to cppunit-config.
PKG_CHECK_EXISTS(cppunit,
[PKG_CHECK_MODULES(CPPUNIT, cppunit >= 1.9.14)],
[AM_PATH_CPPUNIT([1.9.14],[],
[AC_MSG_ERROR([GNU Radio requires cppunit. Stop])])])
])

View File

@ -1,55 +0,0 @@
dnl
dnl Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc.
dnl
dnl This file is part of GNU Radio
dnl
dnl GNU Radio is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3, or (at your option)
dnl any later version.
dnl
dnl GNU Radio is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with GNU Radio; see the file COPYING. If not, write to
dnl the Free Software Foundation, Inc., 51 Franklin Street,
dnl Boston, MA 02110-1301, USA.
dnl
AC_INIT([tetra-demod], [0.0.1])
AC_PREREQ(2.57)
AC_CONFIG_AUX_DIR([.])
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
AC_CANONICAL_TARGET
GR_VERSION
dnl ustar required to have pathnames > 99 chars
_AM_SET_OPTION([tar-ustar])
AM_INIT_AUTOMAKE([])
dnl This is kind of non-standard, but it sure shortens up this file :-)
m4_include([config/gr_standalone.m4])
GR_STANDALONE
AM_PATH_PYTHON
AC_CONFIG_FILES([\
Makefile \
apps/Makefile \
config/Makefile \
grc/Makefile \
python/Makefile \
python/py_run_tests \
])
dnl run_tests is created from run_tests.in. Make it executable.
AC_CONFIG_COMMANDS([run_tests], [chmod +x python/py_run_tests])
AC_OUTPUT

View File

@ -2,7 +2,7 @@
import sys
import math
from gnuradio import gr, gru, audio, eng_notation, blks2, optfir
from gnuradio import gr, gru, audio, eng_notation, blocks, filter
from gnuradio import audio
from gnuradio.eng_option import eng_option
from optparse import OptionParser
@ -22,7 +22,7 @@ class my_top_block(gr.top_block):
self.asrc = audio.source(sample_rate, options.audio_device, True)
self.f2c = gr.float_to_complex(1)
self.f2c = blocks.float_to_complex(1)
self.connect((self.asrc, 1), (self.f2c, 1))
self.connect((self.asrc, 0), (self.f2c, 0))
@ -33,9 +33,9 @@ class my_top_block(gr.top_block):
ntaps = 11 * sps
new_sample_rate = symbol_rate * sps
channel_taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, gr.firdes.WIN_HANN)
channel_taps = filter.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, filter.firdes.WIN_HANN)
FILTER = gr.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
FILTER = filter.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
sys.stderr.write("sample rate: %d\n" %(sample_rate))
@ -48,11 +48,11 @@ class my_top_block(gr.top_block):
log=options.log,
verbose=options.verbose)
OUT = gr.file_sink(gr.sizeof_float, options.output_file)
OUT = blocks.file_sink(gr.sizeof_float, options.output_file)
r = float(sample_rate) / float(new_sample_rate)
INTERPOLATOR = gr.fractional_interpolator_cc(0, r)
INTERPOLATOR = filter.fractional_interpolator_cc(0, r)
self.connect(self.f2c, FILTER, INTERPOLATOR, DEMOD, OUT)

View File

@ -2,7 +2,7 @@
import sys
import math
from gnuradio import gr, gru, audio, eng_notation, blks2, optfir
from gnuradio import gr, gru, audio, eng_notation, blocks, filter
from gnuradio import audio
from gnuradio.eng_option import eng_option
from gnuradio.wxgui import stdgui2, fftsink2
@ -28,7 +28,7 @@ class my_top_block(stdgui2.std_top_block):
self.asrc = audio.source(sample_rate, options.audio_device, True)
self.f2c = gr.float_to_complex(1)
self.f2c = blocks.float_to_complex(1)
self.connect((self.asrc, 1), (self.f2c, 1))
self.connect((self.asrc, 0), (self.f2c, 0))
@ -39,9 +39,9 @@ class my_top_block(stdgui2.std_top_block):
ntaps = 11 * sps
new_sample_rate = symbol_rate * sps
channel_taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, gr.firdes.WIN_HANN)
channel_taps = filter.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, filter.firdes.WIN_HANN)
FILTER = gr.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
FILTER = filter.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
sys.stderr.write("sample rate: %d\n" %(sample_rate))
@ -54,11 +54,11 @@ class my_top_block(stdgui2.std_top_block):
log=options.log,
verbose=options.verbose)
OUT = gr.file_sink(gr.sizeof_float, options.output_file)
OUT = blocks.file_sink(gr.sizeof_float, options.output_file)
r = float(sample_rate) / float(new_sample_rate)
INTERPOLATOR = gr.fractional_interpolator_cc(0, r)
INTERPOLATOR = filter.fractional_interpolator_cc(0, r)
self.connect(self.f2c, FILTER, INTERPOLATOR, DEMOD, OUT)

View File

@ -1,22 +0,0 @@
# (C) 2011 by Holger Hans Peter Freyther
# All Rights Reserved
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
include $(top_srcdir)/Makefile.common
grcblocksdir = $(grc_blocksdir)
dist_grcblocks_DATA = \
tetra_demod_qpsk.xml

View File

@ -1,18 +0,0 @@
<?xml version="1.0"?>
<block>
<name>Tetra QPSK pi/4 demodulation</name>
<key>tetra_demod</key>
<category>Tetra</category>
<import>import tetra_demod</import>
<make>tetra_demod.demod()</make>
<sink>
<name>in</name>
<type>complex</type>
</sink>
<source>
<name>out</name>
<type>float</type>
</source>
</block>

View File

@ -1,37 +0,0 @@
#
# Copyright 2001,2006,2008,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.
#
#
include $(top_srcdir)/Makefile.common
bin_SCRIPTS = \
tetra-demod.py \
usrp1-tetra_demod.py \
usrp2-tetra_demod.py
EXTRA_DIST = py_run_tests.in tetra-demod.py usrp1-tetra_demod.py usrp2-tetra_demod.py
TESTS = py_run_tests
modpython_PYTHON = \
__init__.py \
cqpsk.py
noinst_PYTHON = \
qa_tetra.py

View File

@ -1,28 +0,0 @@
"""
(C) 2011 by Holger Hans Peter Freyther
All Rights Reserved
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import cqpsk
def demod():
return cqpsk.cqpsk_demod(samples_per_symbol = 2,
excess_bw=0.35,
costas_alpha=0.03,
gain_mu=0.05,
mu=0.05,
omega_relative_limit=0.05)

View File

@ -1,370 +0,0 @@
#
# Copyright 2005,2006,2007 Free Software Foundation, Inc.
#
# cqpsk.py (C) Copyright 2009, KA1RBI
#
# 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 PI/4 CQPSK modulation and demodulation.
"""
from gnuradio import gr, gru
from math import pi, sqrt
#import psk
import cmath
from pprint import pprint
_def_has_gr_digital = False
# address gnuradio 3.5.x changes
try:
from gnuradio import modulation_utils
except ImportError:
from gnuradio import digital
_def_has_gr_digital = True
# default values (used in __init__ and add_options)
_def_samples_per_symbol = 10
_def_excess_bw = 0.35
_def_gray_code = True
_def_verbose = False
_def_log = False
_def_costas_alpha = 0.15
_def_gain_mu = None
_def_mu = 0.5
_def_omega_relative_limit = 0.005
# /////////////////////////////////////////////////////////////////////////////
# CQPSK modulator
# /////////////////////////////////////////////////////////////////////////////
class cqpsk_mod(gr.hier_block2):
def __init__(self,
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
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 verbose: Print information about modulator?
@type verbose: bool
@param debug: Print modualtion data to files?
@type debug: bool
"""
gr.hier_block2.__init__(self, "cqpsk_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
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)
ntaps = 11 * samples_per_symbol
arity = 8
# turn bytes into k-bit vectors
self.bytes2chunks = \
gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
# 0 +45 1 [+1]
# 1 +135 3 [+3]
# 2 -45 7 [-1]
# 3 -135 5 [-3]
self.pi4map = [1, 3, 7, 5]
self.symbol_mapper = gr.map_bb(self.pi4map)
self.diffenc = gr.diff_encoder_bb(arity)
self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity])
# pulse shaping filter
self.rrc_taps = gr.firdes.root_raised_cosine(
self._samples_per_symbol, # gain (sps since we're interpolating by sps)
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)
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 "RRS 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_utils.extract_kwargs_from_options(dqpsk_mod.__init__,
('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
# /////////////////////////////////////////////////////////////////////////////
# CQPSK demodulator
#
# /////////////////////////////////////////////////////////////////////////////
class cqpsk_demod(gr.hier_block2):
def __init__(self,
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
costas_alpha=_def_costas_alpha,
gain_mu=_def_gain_mu,
mu=_def_mu,
omega_relative_limit=_def_omega_relative_limit,
gray_code=_def_gray_code,
verbose=_def_verbose,
log=_def_log):
"""
Hierarchical block for RRC-filtered CQPSK demodulation
The input is the complex modulated signal at baseband.
The output is a stream of floats in [ -3 / -1 / +1 / +3 ]
@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 costas_alpha: loop filter gain
@type costas_alphas: float
@param gain_mu: for M&M block
@type gain_mu: float
@param mu: for M&M block
@type mu: float
@param omega_relative_limit: for M&M block
@type omega_relative_limit: 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, "cqpsk_demod",
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
self._samples_per_symbol = samples_per_symbol
self._excess_bw = excess_bw
self._costas_alpha = costas_alpha
self._mm_gain_mu = gain_mu
self._mm_mu = mu
self._mm_omega_relative_limit = omega_relative_limit
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
scale = (1.0/16384.0)
self.pre_scaler = gr.multiply_const_cc(scale) # scale the signal from full-range to +-1
#self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
self.agc = gr.feedforward_agc_cc(16, 2.0)
# RRC data filter
ntaps = 11 * samples_per_symbol
self.rrc_taps = gr.firdes.root_raised_cosine(
1.0, # gain
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(1, self.rrc_taps)
if not self._mm_gain_mu:
sbs_to_mm = {2: 0.050, 3: 0.075, 4: 0.11, 5: 0.125, 6: 0.15, 7: 0.15}
self._mm_gain_mu = sbs_to_mm[samples_per_symbol]
self._mm_omega = self._samples_per_symbol
self._mm_gain_omega = .25 * self._mm_gain_mu * self._mm_gain_mu
self._costas_beta = 0.25 * self._costas_alpha * self._costas_alpha
fmin = -0.025
fmax = 0.025
if not _def_has_gr_digital:
self.receiver=gr.mpsk_receiver_cc(arity, pi/4.0,
self._costas_alpha, self._costas_beta,
fmin, fmax,
self._mm_mu, self._mm_gain_mu,
self._mm_omega, self._mm_gain_omega,
self._mm_omega_relative_limit)
else:
self.receiver=digital.mpsk_receiver_cc(arity, pi/4.0,
2*pi/150,
fmin, fmax,
self._mm_mu, self._mm_gain_mu,
self._mm_omega, self._mm_gain_omega,
self._mm_omega_relative_limit)
self.receiver.set_alpha(self._costas_alpha)
self.receiver.set_beta(self._costas_beta)
# Perform Differential decoding on the constellation
self.diffdec = gr.diff_phasor_cc()
# take angle of the difference (in radians)
self.to_float = gr.complex_to_arg()
# convert from radians such that signal is in -3/-1/+1/+3
self.rescale = gr.multiply_const_ff( 1 / (pi / 4) )
if verbose:
self._print_verbage()
if log:
self._setup_logging()
# Connect & Initialize base class
self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver,
self.diffdec, self.to_float, self.rescale, 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 "\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 "Costas Loop alpha: %.2e" % self._costas_alpha
print "Costas Loop beta: %.2e" % self._costas_beta
print "M&M mu: %.2f" % self._mm_mu
print "M&M mu gain: %.2e" % self._mm_gain_mu
print "M&M omega: %.2f" % self._mm_omega
print "M&M omega gain: %.2e" % self._mm_gain_omega
print "M&M omega limit: %.2f" % self._mm_omega_relative_limit
def _setup_logging(self):
print "Modulation logging turned on."
self.connect(self.pre_scaler,
gr.file_sink(gr.sizeof_gr_complex, "rx_prescaler.dat"))
self.connect(self.agc,
gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
self.connect(self.rrc_filter,
gr.file_sink(gr.sizeof_gr_complex, "rx_rrc_filter.dat"))
self.connect(self.receiver,
gr.file_sink(gr.sizeof_gr_complex, "rx_receiver.dat"))
self.connect(self.diffdec,
gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
self.connect(self.to_float,
gr.file_sink(gr.sizeof_float, "rx_to_float.dat"))
self.connect(self.rescale,
gr.file_sink(gr.sizeof_float, "rx_rescale.dat"))
def add_options(parser):
"""
Adds 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)")
parser.add_option("", "--costas-alpha", type="float", default=_def_costas_alpha,
help="set Costas loop alpha value [default=%default] (PSK)")
parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu,
help="set M&M symbol sync loop gain mu value [default=%default] (PSK)")
parser.add_option("", "--mu", type="float", default=_def_mu,
help="set M&M symbol sync loop mu value [default=%default] (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_utils.extract_kwargs_from_options(
cqpsk_demod.__init__, ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
#
# Add these to the mod/demod registry
#
#modulation_utils.add_type_1_mod('cqpsk', cqpsk_mod)
#modulation_utils.add_type_1_demod('cqpsk', cqpsk_demod)

View File

@ -1,259 +0,0 @@
#!/usr/bin/env python
# Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net>
# Usage:
# src$ ./demod/python/osmosdr-tetra_demod_fft.py -o /dev/stdout | ./float_to_bits /dev/stdin /dev/stdout | ./tetra-rx /dev/stdin
#
# Adjust the center frequency (-f) and gain (-g) according to your needs.
# Use left click in Wideband Spectrum window to roughly select a TETRA carrier.
# In Wideband Spectrum you can also tune by 1/4 of the bandwidth by clicking on the rightmost/leftmost spectrum side.
# Use left click in Channel Spectrum windows to fine tune the carrier by clicking on the left or right side of the spectrum.
import sys
import math
from gnuradio import gr, gru, eng_notation, blks2, optfir
from gnuradio.eng_option import eng_option
from gnuradio.wxgui import fftsink2
from gnuradio.wxgui import scopesink2
from gnuradio.wxgui import forms
from grc_gnuradio import wxgui as grc_wxgui
from optparse import OptionParser
import osmosdr
import wx
try:
import cqpsk
except:
from tetra_demod import cqpsk
# applies frequency translation, resampling and demodulation
class top_block(grc_wxgui.top_block_gui):
def __init__(self):
grc_wxgui.top_block_gui.__init__(self, title="Top Block")
options = get_options()
self.ifreq = options.frequency
self.rfgain = options.gain
self.offset = options.frequency_offset
self.src = osmosdr.source_c(options.args)
self.src.set_center_freq(self.ifreq)
self.src.set_sample_rate(int(options.sample_rate))
if self.rfgain is None:
self.src.set_gain_mode(1)
self.iagc = 1
self.rfgain = 0
else:
self.iagc = 0
self.src.set_gain_mode(0)
self.src.set_gain(self.rfgain)
# may differ from the requested rate
sample_rate = self.src.get_sample_rate()
sys.stderr.write("sample rate: %d\n" % (sample_rate))
symbol_rate = 18000
sps = 2 # output rate will be 36,000
out_sample_rate = symbol_rate * sps
options.low_pass = options.low_pass / 2.0
if sample_rate == 96000: # FunCube Dongle
first_decim = 2
else:
first_decim = 10
self.offset = 0
taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.2, gr.firdes.WIN_HANN)
self.tuner = gr.freq_xlating_fir_filter_ccf(first_decim, taps, self.offset, sample_rate)
self.demod = cqpsk.cqpsk_demod(
samples_per_symbol = sps,
excess_bw=0.35,
costas_alpha=0.03,
gain_mu=0.05,
mu=0.05,
omega_relative_limit=0.05,
log=options.log,
verbose=options.verbose)
self.output = gr.file_sink(gr.sizeof_float, options.output_file)
rerate = float(sample_rate / float(first_decim)) / float(out_sample_rate)
sys.stderr.write("resampling factor: %f\n" % rerate)
if rerate.is_integer():
sys.stderr.write("using pfb decimator\n")
self.resamp = blks2.pfb_decimator_ccf(int(rerate))
else:
sys.stderr.write("using pfb resampler\n")
self.resamp = blks2.pfb_arb_resampler_ccf(1 / rerate)
self.connect(self.src, self.tuner, self.resamp, self.demod, self.output)
self.Main = wx.Notebook(self.GetWin(), style=wx.NB_TOP)
self.Main.AddPage(grc_wxgui.Panel(self.Main), "Wideband Spectrum")
self.Main.AddPage(grc_wxgui.Panel(self.Main), "Channel Spectrum")
self.Main.AddPage(grc_wxgui.Panel(self.Main), "Soft Bits")
def set_ifreq(ifreq):
self.ifreq = ifreq
self._ifreq_text_box.set_value(self.ifreq)
self.src.set_center_freq(self.ifreq)
self._ifreq_text_box = forms.text_box(
parent=self.GetWin(),
value=self.ifreq,
callback=set_ifreq,
label="Center Frequency",
converter=forms.float_converter(),
)
self.Add(self._ifreq_text_box)
def set_iagc(iagc):
self.iagc = iagc
self._agc_check_box.set_value(self.iagc)
self.src.set_gain_mode(self.iagc, 0)
self.src.set_gain(0 if self.iagc == 1 else self.rfgain, 0)
self._agc_check_box = forms.check_box(
parent=self.GetWin(),
value=self.iagc,
callback=set_iagc,
label="Automatic Gain",
true=1,
false=0,
)
self.Add(self._agc_check_box)
def set_rfgain(rfgain):
self.rfgain = rfgain
self._rfgain_slider.set_value(self.rfgain)
self._rfgain_text_box.set_value(self.rfgain)
self.src.set_gain(0 if self.iagc == 1 else self.rfgain, 0)
_rfgain_sizer = wx.BoxSizer(wx.VERTICAL)
self._rfgain_text_box = forms.text_box(
parent=self.GetWin(),
sizer=_rfgain_sizer,
value=self.rfgain,
callback=set_rfgain,
label="RF Gain",
converter=forms.float_converter(),
proportion=0,
)
self._rfgain_slider = forms.slider(
parent=self.GetWin(),
sizer=_rfgain_sizer,
value=self.rfgain,
callback=set_rfgain,
minimum=0,
maximum=50,
num_steps=200,
style=wx.SL_HORIZONTAL,
cast=float,
proportion=1,
)
self.Add(_rfgain_sizer)
self.Add(self.Main)
def fftsink2_callback(x, y):
if abs(x / (sample_rate / 2)) > 0.9:
set_ifreq(self.ifreq + x / 2)
else:
self.offset = -x
sys.stderr.write("coarse tuned to: %d Hz => %d Hz\n" % (self.offset, (self.ifreq + self.offset)))
self.tuner.set_center_freq(self.offset)
self.scope = fftsink2.fft_sink_c(self.Main.GetPage(0).GetWin(),
title="Wideband Spectrum (click to coarse tune)",
fft_size=1024,
sample_rate=sample_rate,
ref_scale=2.0,
ref_level=0,
y_divs=10,
fft_rate=10,
average=False,
avg_alpha=0.6)
self.Main.GetPage(0).Add(self.scope.win)
self.scope.set_callback(fftsink2_callback)
self.connect(self.src, self.scope)
def fftsink2_callback2(x, y):
self.offset = self.offset - (x / 10)
sys.stderr.write("fine tuned to: %d Hz => %d Hz\n" % (self.offset, (self.ifreq + self.offset)))
self.tuner.set_center_freq(self.offset)
self.scope2 = fftsink2.fft_sink_c(self.Main.GetPage(1).GetWin(),
title="Channel Spectrum (click to fine tune)",
fft_size=1024,
sample_rate=out_sample_rate,
ref_scale=2.0,
ref_level=-20,
y_divs=10,
fft_rate=10,
average=False,
avg_alpha=0.6)
self.Main.GetPage(1).Add(self.scope2.win)
self.scope2.set_callback(fftsink2_callback2)
self.connect(self.resamp, self.scope2)
self.scope3 = scopesink2.scope_sink_f(
self.Main.GetPage(2).GetWin(),
title="Soft Bits",
sample_rate=out_sample_rate,
v_scale=0,
v_offset=0,
t_scale=0.001,
ac_couple=False,
xy_mode=False,
num_inputs=1,
trig_mode=gr.gr_TRIG_MODE_AUTO,
y_axis_label="Counts",
)
self.Main.GetPage(2).Add(self.scope3.win)
self.connect(self.demod, self.scope3)
def get_options():
parser = OptionParser(option_class=eng_option)
parser.add_option("-a", "--args", type="string", default="",
help="gr-osmosdr device arguments")
parser.add_option("-s", "--sample-rate", type="eng_float", default=1800000,
help="set receiver sample rate (default 1800000)")
parser.add_option("-f", "--frequency", type="eng_float", default=394.4e6,
help="set receiver center frequency")
parser.add_option("-F", "--frequency-offset", type="eng_float", default=0,
help="set receiver offset frequency")
parser.add_option("-g", "--gain", type="eng_float", default=None,
help="set receiver gain")
# demodulator related settings
parser.add_option("-l", "--log", action="store_true", default=False, help="dump debug .dat files")
parser.add_option("-L", "--low-pass", type="eng_float", default=25e3, help="low pass cut-off", metavar="Hz")
parser.add_option("-o", "--output-file", type="string", default="out.float", help="specify the bit output file")
parser.add_option("-v", "--verbose", action="store_true", default=False, help="dump demodulation data")
(options, args) = parser.parse_args()
if len(args) != 0:
parser.print_help()
raise SystemExit, 1
return (options)
if __name__ == '__main__':
tb = top_block()
tb.Run(True)

View File

@ -1,69 +0,0 @@
#!/usr/bin/env python
import sys
import math
from gnuradio import gr, gru, audio, eng_notation, blks2, optfir
from gnuradio.eng_option import eng_option
from optparse import OptionParser
# Load it locally or from the module
try:
import cqpsk
except:
from tetra_demod import cqpsk
# accepts an input file in complex format
# applies frequency translation, resampling (interpolation/decimation)
class my_top_block(gr.top_block):
def __init__(self):
gr.top_block.__init__(self)
parser = OptionParser(option_class=eng_option)
parser.add_option("-c", "--calibration", type="eng_float", default=0, help="freq offset")
parser.add_option("-i", "--input-file", type="string", default="in.dat", help="specify the input file")
parser.add_option("-l", "--log", action="store_true", default=False, help="dump debug .dat files")
parser.add_option("-L", "--low-pass", type="eng_float", default=25e3, help="low pass cut-off", metavar="Hz")
parser.add_option("-o", "--output-file", type="string", default="out.dat", help="specify the output file")
parser.add_option("-s", "--sample-rate", type="int", default=100000000/512, help="input sample rate")
parser.add_option("-v", "--verbose", action="store_true", default=False, help="dump demodulation data")
(options, args) = parser.parse_args()
sample_rate = options.sample_rate
symbol_rate = 18000
sps = 2
# output rate will be 36,000
ntaps = 11 * sps
new_sample_rate = symbol_rate * sps
channel_taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, gr.firdes.WIN_HANN)
FILTER = gr.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
sys.stderr.write("sample rate: %d\n" %(sample_rate))
IN = gr.file_source(gr.sizeof_gr_complex, options.input_file)
DEMOD = cqpsk.cqpsk_demod( samples_per_symbol = sps,
excess_bw=0.35,
costas_alpha=0.03,
gain_mu=0.05,
mu=0.05,
omega_relative_limit=0.05,
log=options.log,
verbose=options.verbose)
OUT = gr.file_sink(gr.sizeof_float, options.output_file)
r = float(sample_rate) / float(new_sample_rate)
INTERPOLATOR = gr.fractional_interpolator_cc(0, r)
self.connect(IN, FILTER, INTERPOLATOR, DEMOD, OUT)
if __name__ == "__main__":
try:
my_top_block().run()
except KeyboardInterrupt:
tb.stop()

View File

@ -1,130 +0,0 @@
#!/usr/bin/env python
import sys
import math
from gnuradio import gr, gru, audio, eng_notation, blks2, optfir
from gnuradio import uhd
from gnuradio.eng_option import eng_option
from optparse import OptionParser
# Load it locally or from the module
try:
import cqpsk
except:
from tetra_demod import cqpsk
# accepts an input file in complex format
# applies frequency translation, resampling (interpolation/decimation)
class my_top_block(gr.top_block):
def __init__(self, options):
gr.top_block.__init__(self)
# Create a UHD source
self._u = uhd.usrp_source(
device_addr=options.args,
io_type=uhd.io_type.COMPLEX_FLOAT32,
num_channels=1)
# Set the subdevice spec
if(options.spec):
self._u.set_subdev_spec(options.spec, 0)
# Set the antenna
if(options.antenna):
self._u.set_antenna(options.antenna, 0)
# Pick the lowest possible value for the input rate
supported_rates = self._u.get_samp_rates()
self._u.set_samp_rate(supported_rates.start())
sample_rate = self._u.get_samp_rate()
symbol_rate = 18000
sps = 2
# output rate will be 36,000
ntaps = 11 * sps
new_sample_rate = symbol_rate * sps
# Set receive daughterboard gain
if options.gain is None:
g = self._u.get_gain_range()
options.gain = float(g.stop()+g.start())/2
print "Using mid-point gain of", options.gain, "(", g.start(), "-", g.stop(), ")"
self._u.set_gain(options.gain)
# Set frequency (tune request takes lo_offset)
if(options.lo_offset is not None):
treq = uhd.tune_request(options.freq, options.lo_offset)
else:
treq = uhd.tune_request(options.freq)
tr = self._u.set_center_freq(treq)
if tr == None:
sys.stderr.write('Failed to set center frequency\n')
raise SystemExit, 1
channel_taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, gr.firdes.WIN_HANN)
FILTER = gr.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
sys.stderr.write("sample rate: %d\n" %(sample_rate))
DEMOD = cqpsk.cqpsk_demod( samples_per_symbol = sps,
excess_bw=0.35,
costas_alpha=0.03,
gain_mu=0.05,
mu=0.05,
omega_relative_limit=0.05,
log=options.log,
verbose=options.verbose)
OUT = gr.file_sink(gr.sizeof_float, options.output_file)
r = float(sample_rate) / float(new_sample_rate)
INTERPOLATOR = gr.fractional_interpolator_cc(0, r)
self.connect(self._u, FILTER, INTERPOLATOR, DEMOD, OUT)
def get_options():
parser = OptionParser(option_class=eng_option)
# usrp related settings
parser.add_option("-a", "--args", type="string", default="",
help="UHD device address args, [default=%default]")
parser.add_option("", "--spec", type="string", default=None,
help="Subdevice of UHD device where appropriate")
parser.add_option("-A", "--antenna", type="string", default=None,
help="select Rx Antenna where appropriate")
parser.add_option("-f", "--freq", type="eng_float", default=None,
help="set frequency to FREQ", metavar="FREQ")
parser.add_option("-g", "--gain", type="eng_float", default=None,
help="set gain in dB (default is midpoint)")
parser.add_option("", "--lo-offset", type="eng_float", default=None,
help="set daughterboard LO offset to OFFSET [default=hw default]")
# demodulator related settings
parser.add_option("-c", "--calibration", type="int", default=0, help="freq offset")
parser.add_option("-l", "--log", action="store_true", default=False, help="dump debug .dat files")
parser.add_option("-L", "--low-pass", type="eng_float", default=25e3, help="low pass cut-off", metavar="Hz")
parser.add_option("-o", "--output-file", type="string", default="out.float", help="specify the bit output file")
parser.add_option("-v", "--verbose", action="store_true", default=False, help="dump demodulation data")
(options, args) = parser.parse_args()
if len(args) != 0:
parser.print_help()
raise SystemExit, 1
if options.freq is None:
parser.print_help()
sys.stderr.write('You must specify the frequency with -f FREQ\n');
raise SystemExit, 1
return (options)
if __name__ == "__main__":
(options) = get_options()
tb = my_top_block(options)
try:
tb.run()
except KeyboardInterrupt:
tb.stop()

View File

@ -1,133 +0,0 @@
#!/usr/bin/env python
import sys
import math
from gnuradio import gr, gru, audio, eng_notation, blks2, optfir
from gnuradio import usrp
from gnuradio.eng_option import eng_option
from optparse import OptionParser
try:
import cqpsk
except:
from tetra_demod import cqpsk
# applies frequency translation, resampling (interpolation/decimation) and cqpsk demodulation
class my_top_block(gr.top_block):
def __init__(self, options):
gr.top_block.__init__(self)
fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096)
fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16)
self._u = usrp.source_c(decim_rate=options.decim, fusb_block_size=fusb_block_size, fusb_nblocks=fusb_nblocks)
# master clock
if options.fpga_freq is not None:
self._u.set_fpga_master_clock_freq(long(options.fpga_freq))
# default subdev if use didn't pick one
if options.rx_subdev_spec is None:
if u.db(0, 0).dbid() >= 0:
options.rx_subdev_spec = (0, 0)
elif u.db(1, 0).dbid() >= 0:
options.rx_subdev_spec = (1, 0)
else:
options.rx_subdev_spec = (0, 0)
# configure usrp mux
self._u.set_mux(usrp.determine_rx_mux_value(self._u, options.rx_subdev_spec))
# determine the daughterboard subdevice
self.subdev = usrp.selected_subdev(self._u, options.rx_subdev_spec)
# select antenna
if options.antenna is not None:
print "Selecting antenna %s" % (options.antenna,)
self.subdev.select_rx_antenna(options.antenna)
# set initial values
if options.gain is None:
# if no gain was specified, use the mid-point in dB
g = self.subdev.gain_range()
options.gain = float(g[0]+g[1])/2
r = self._u.tune(0, self.subdev, options.freq)
self.subdev.set_gain(options.gain)
#sample_rate = options.fpga_clock/options.decim
sample_rate = self._u.adc_freq() / self._u.decim_rate()
symbol_rate = 18000
sps = 2
# output rate will be 36,000
ntaps = 11 * sps
new_sample_rate = symbol_rate * sps
channel_taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, gr.firdes.WIN_HANN)
FILTER = gr.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
sys.stderr.write("sample rate: %d\n" %(sample_rate))
DEMOD = cqpsk.cqpsk_demod( samples_per_symbol = sps,
excess_bw=0.35,
costas_alpha=0.03,
gain_mu=0.05,
mu=0.05,
omega_relative_limit=0.05,
log=options.log,
verbose=options.verbose)
OUT = gr.file_sink(gr.sizeof_float, options.output_file)
r = float(sample_rate) / float(new_sample_rate)
INTERPOLATOR = gr.fractional_interpolator_cc(0, r)
self.connect(self._u, FILTER, INTERPOLATOR, DEMOD, OUT)
def get_options():
parser = OptionParser(option_class=eng_option)
# usrp related settings
parser.add_option("-d", "--decim", type="int", default=250,
help="Set USRP decimation rate to DECIM [default=%default]")
parser.add_option("-f", "--freq", type="eng_float", default=None,
help="set frequency to FREQ", metavar="FREQ")
parser.add_option("-g", "--gain", type="eng_float", default=None,
help="set gain in dB (default is midpoint)")
parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
help="Select USRP Rx side A or B (default=first one with a daughterboard)")
parser.add_option("-A", "--antenna", default=None,
help="select Rx Antenna")
parser.add_option("-F", "--fpga-freq", type="eng_float", default=None,
help="set USRP reference clock frequency to FPGA_FREQ", metavar="FPGA_FREQ")
# demodulator related settings
parser.add_option("-c", "--calibration", type="int", default=0, help="freq offset")
parser.add_option("-l", "--log", action="store_true", default=False, help="dump debug .dat files")
parser.add_option("-L", "--low-pass", type="eng_float", default=25e3, help="low pass cut-off", metavar="Hz")
parser.add_option("-o", "--output-file", type="string", default="out.float", help="specify the bit output file")
parser.add_option("-v", "--verbose", action="store_true", default=False, help="dump demodulation data")
(options, args) = parser.parse_args()
if len(args) != 0:
parser.print_help()
raise SystemExit, 1
if options.freq is None:
parser.print_help()
sys.stderr.write('You must specify the frequency with -f FREQ\n');
raise SystemExit, 1
return (options)
if __name__ == "__main__":
(options) = get_options()
tb = my_top_block(options)
try:
tb.run()
except KeyboardInterrupt:
tb.stop()

View File

@ -1,112 +0,0 @@
#!/usr/bin/env python
import sys
import math
from gnuradio import gr, gru, audio, eng_notation, blks2, optfir
from gnuradio import usrp2
from gnuradio.eng_option import eng_option
from optparse import OptionParser
# Load it locally or from the module
try:
import cqpsk
except:
from tetra_demod import cqpsk
# accepts an input file in complex format
# applies frequency translation, resampling (interpolation/decimation)
class my_top_block(gr.top_block):
def __init__(self, options):
gr.top_block.__init__(self)
# Create a USRP2 source and set decimation rate
self._u = usrp2.source_32fc(options.interface, options.mac_addr)
self._u.set_decim(512)
# Set receive daughterboard gain
if options.gain is None:
g = self._u.gain_range()
options.gain = float(g[0]+g[1])/2
print "Using mid-point gain of", options.gain, "(", g[0], "-", g[1], ")"
self._u.set_gain(options.gain)
# Set receive frequency
if options.lo_offset is not None:
self._u.set_lo_offset(options.lo_offset)
tr = self._u.set_center_freq(options.freq)
if tr == None:
sys.stderr.write('Failed to set center frequency\n')
raise SystemExit, 1
sample_rate = 100e6/512
symbol_rate = 18000
sps = 2
# output rate will be 36,000
ntaps = 11 * sps
new_sample_rate = symbol_rate * sps
channel_taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, gr.firdes.WIN_HANN)
FILTER = gr.freq_xlating_fir_filter_ccf(1, channel_taps, options.calibration, sample_rate)
sys.stderr.write("sample rate: %d\n" %(sample_rate))
DEMOD = cqpsk.cqpsk_demod( samples_per_symbol = sps,
excess_bw=0.35,
costas_alpha=0.03,
gain_mu=0.05,
mu=0.05,
omega_relative_limit=0.05,
log=options.log,
verbose=options.verbose)
OUT = gr.file_sink(gr.sizeof_float, options.output_file)
r = float(sample_rate) / float(new_sample_rate)
INTERPOLATOR = gr.fractional_interpolator_cc(0, r)
self.connect(self._u, FILTER, INTERPOLATOR, DEMOD, OUT)
def get_options():
parser = OptionParser(option_class=eng_option)
# usrp related settings
parser.add_option("-e", "--interface", type="string", default="eth0",
help="use specified Ethernet interface [default=%default]")
parser.add_option("-m", "--mac-addr", type="string", default="",
help="use USRP2 at specified MAC address [default=None]")
parser.add_option("-f", "--freq", type="eng_float", default=None,
help="set frequency to FREQ", metavar="FREQ")
parser.add_option("-g", "--gain", type="eng_float", default=None,
help="set gain in dB (default is midpoint)")
parser.add_option("", "--lo-offset", type="eng_float", default=None,
help="set daughterboard LO offset to OFFSET [default=hw default]")
# demodulator related settings
parser.add_option("-c", "--calibration", type="int", default=0, help="freq offset")
parser.add_option("-l", "--log", action="store_true", default=False, help="dump debug .dat files")
parser.add_option("-L", "--low-pass", type="eng_float", default=25e3, help="low pass cut-off", metavar="Hz")
parser.add_option("-o", "--output-file", type="string", default="out.float", help="specify the bit output file")
parser.add_option("-v", "--verbose", action="store_true", default=False, help="dump demodulation data")
(options, args) = parser.parse_args()
if len(args) != 0:
parser.print_help()
raise SystemExit, 1
if options.freq is None:
parser.print_help()
sys.stderr.write('You must specify the frequency with -f FREQ\n');
raise SystemExit, 1
return (options)
if __name__ == "__main__":
(options) = get_options()
tb = my_top_block(options)
try:
tb.run()
except KeyboardInterrupt:
tb.stop()

View File

@ -12,7 +12,7 @@
import sys
import math
from gnuradio import gr, gru, eng_notation, blks2, optfir
from gnuradio import gr, gru, eng_notation, blocks
from gnuradio.eng_option import eng_option
from optparse import OptionParser
import osmosdr
@ -30,7 +30,7 @@ class top_block(gr.top_block):
options = get_options()
self.input_file=options.input_file
self.gr_file_source_0 = gr.file_source(gr.sizeof_gr_complex*1, self.input_file, True)
self.gr_file_source_0 = blocks.file_source(gr.sizeof_gr_complex*1, self.input_file, True)
symbol_rate = 18000
sps = 2 # output rate will be 36,000