summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/python
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core/src/python')
-rw-r--r--gnuradio-core/src/python/gnuradio/Makefile.am2
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2/__init__.py4
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/Makefile.am)29
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/__init__.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/__init__.py)0
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/am_demod.py76
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/channel_model.py59
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/cpm.py249
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/d8psk.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/d8psk.py)112
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/dbpsk.py)108
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/digital_voice.py.real102
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/dqpsk.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/dqpsk.py)110
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/filterbank.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/filterbank.py)38
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/fm_demod.py111
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/fm_emph.py151
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/gmsk.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/gmsk.py)53
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/nbfm_rx.py88
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/nbfm_tx.py92
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py305
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py64
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py41
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py135
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py135
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py126
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/pkt.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/pkt.py)47
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/psk.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/psk.py)14
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam.py113
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam16.py208
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam256.py209
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam64.py208
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam8.py209
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/rational_resampler.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl2/rational_resampler.py)4
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/standard_squelch.py76
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv.py69
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv_pll.py192
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/wfm_tx.py79
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/hier_block2.py26
-rwxr-xr-xgnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py53
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/top_block.py26
38 files changed, 3489 insertions, 234 deletions
diff --git a/gnuradio-core/src/python/gnuradio/Makefile.am b/gnuradio-core/src/python/gnuradio/Makefile.am
index d9815b5230..388681e550 100644
--- a/gnuradio-core/src/python/gnuradio/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/Makefile.am
@@ -21,7 +21,7 @@
include $(top_srcdir)/Makefile.common
-SUBDIRS = gr gru gruimpl blks blksimpl blks2 blksimpl2 vocoder
+SUBDIRS = gr gru gruimpl blks blksimpl blks2 blks2impl vocoder
grpython_PYTHON = \
__init__.py \
diff --git a/gnuradio-core/src/python/gnuradio/blks2/__init__.py b/gnuradio-core/src/python/gnuradio/blks2/__init__.py
index 227e2bf7f3..89ebb92299 100644
--- a/gnuradio-core/src/python/gnuradio/blks2/__init__.py
+++ b/gnuradio-core/src/python/gnuradio/blks2/__init__.py
@@ -27,11 +27,11 @@ import os.path
# to manually update this file.
for p in __path__:
- filenames = glob.glob (os.path.join (p, "..", "blksimpl2", "*.py"))
+ filenames = glob.glob (os.path.join (p, "..", "blks2impl", "*.py"))
for f in filenames:
f = os.path.basename(f).lower()
f = f[:-3]
if f == '__init__':
continue
# print f
- exec "from gnuradio.blksimpl2.%s import *" % (f,)
+ exec "from gnuradio.blks2impl.%s import *" % (f,)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/Makefile.am b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
index 3e63510339..3fb23caef3 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2005 Free Software Foundation, Inc.
+# Copyright 2005,2007 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -24,18 +24,41 @@ include $(top_srcdir)/Makefile.common
# EXTRA_DIST = run_tests.in
# TESTS = run_tests
-grblkspythondir = $(grpythondir)/blksimpl2
+grblkspythondir = $(grpythondir)/blks2impl
grblkspython_PYTHON = \
__init__.py \
+ am_demod.py \
+ channel_model.py \
dbpsk.py \
dqpsk.py \
d8psk.py \
filterbank.py \
+ fm_demod.py \
+ fm_emph.py \
gmsk.py \
+ cpm.py \
+ nbfm_rx.py \
+ nbfm_tx.py \
+ ofdm.py \
+ ofdm_receiver.py \
+ ofdm_sync_fixed.py \
+ ofdm_sync_ml.py \
+ ofdm_sync_pnac.py \
+ ofdm_sync_pn.py \
pkt.py \
psk.py \
- rational_resampler.py
+ qam.py \
+ qam8.py \
+ qam16.py \
+ qam64.py \
+ qam256.py \
+ rational_resampler.py \
+ standard_squelch.py \
+ wfm_rcv.py \
+ wfm_rcv_pll.py \
+ wfm_tx.py
+
noinst_PYTHON =
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/__init__.py b/gnuradio-core/src/python/gnuradio/blks2impl/__init__.py
index a4917cf64c..a4917cf64c 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/__init__.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/__init__.py
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/am_demod.py b/gnuradio-core/src/python/gnuradio/blks2impl/am_demod.py
new file mode 100644
index 0000000000..b454f0942d
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/am_demod.py
@@ -0,0 +1,76 @@
+#
+# Copyright 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 gnuradio import gr, optfir
+
+class am_demod_cf(gr.hier_block2):
+ """
+ Generalized AM demodulation block with audio filtering.
+
+ This block demodulates a band-limited, complex down-converted AM
+ channel into the the original baseband signal, applying low pass
+ filtering to the audio output. It produces a float stream in the
+ range [-1.0, +1.0].
+
+ @param channel_rate: incoming sample rate of the AM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ @param audio_pass: audio low pass filter passband frequency
+ @type audio_pass: float
+ @param audio_stop: audio low pass filter stop frequency
+ @type audio_stop: float
+ """
+ def __init__(self, channel_rate, audio_decim, audio_pass, audio_stop):
+ gr.hier_block2.__init__(self, "am_demod_cf",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Input signature
+
+ MAG = gr.complex_to_mag()
+ DCR = gr.add_const_ff(-1.0)
+
+ audio_taps = optfir.low_pass(0.5, # Filter gain
+ channel_rate, # Sample rate
+ audio_pass, # Audio passband
+ audio_stop, # Audio stopband
+ 0.1, # Passband ripple
+ 60) # Stopband attenuation
+ LPF = gr.fir_filter_fff(audio_decim, audio_taps)
+
+ self.connect(self, MAG, DCR, LPF, self)
+
+class demod_10k0a3e_cf(am_demod_cf):
+ """
+ AM demodulation block, 10 KHz channel.
+
+ This block demodulates an AM channel conformant to 10K0A3E emission
+ standards, such as broadcast band AM transmissions.
+
+ @param channel_rate: incoming sample rate of the AM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ """
+ def __init__(self, channel_rate, audio_decim):
+ am_demod_cf.__init__(self, channel_rate, audio_decim,
+ 5000, # Audio passband
+ 5500) # Audio stopband
+ \ No newline at end of file
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/channel_model.py b/gnuradio-core/src/python/gnuradio/blks2impl/channel_model.py
new file mode 100644
index 0000000000..21980a22e5
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/channel_model.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# Copyright 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 gnuradio import gr
+
+class channel_model(gr.hier_block):
+ def __init__(self, fg, noise_voltage=0.0, frequency_offset=0.0, epsilon=1.0, taps=[1.0,0.0]):
+ ''' Creates a channel model that includes:
+ - AWGN noise power in terms of noise voltage
+ - A frequency offest in the channel in ratio
+ - A timing offset ratio to model clock difference (epsilon)
+ - Multipath taps
+ '''
+
+ print epsilon
+ self.timing_offset = gr.fractional_interpolator_cc(0, epsilon)
+
+ self.multipath = gr.fir_filter_ccc(1, taps)
+
+ self.noise_adder = gr.add_cc()
+ self.noise = gr.noise_source_c(gr.GR_GAUSSIAN,noise_voltage)
+ self.freq_offset = gr.sig_source_c(1, gr.GR_SIN_WAVE, frequency_offset, 1.0, 0.0)
+ self.mixer_offset = gr.multiply_cc()
+
+ fg.connect(self.timing_offset, self.multipath)
+ fg.connect(self.multipath, (self.mixer_offset,0))
+ fg.connect(self.freq_offset,(self.mixer_offset,1))
+ fg.connect(self.mixer_offset, (self.noise_adder,1))
+ fg.connect(self.noise, (self.noise_adder,0))
+
+ gr.hier_block.__init__(self, fg, self.timing_offset, self.noise_adder)
+
+ def set_noise_voltage(noise_voltage):
+ self.noise.set_amplitude(noise_voltage)
+
+ def set_frequency_offset(frequency_offset):
+ self.freq_offset.set_frequency(frequency_offset)
+
+ def set_taps(taps):
+ self.multipath.set_taps(taps)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/cpm.py b/gnuradio-core/src/python/gnuradio/blks2impl/cpm.py
new file mode 100644
index 0000000000..8f593cd51e
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/cpm.py
@@ -0,0 +1,249 @@
+#
+# CPM modulation and demodulation.
+#
+#
+# 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.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+from gnuradio import gr
+from gnuradio import modulation_utils
+from math import pi
+import numpy
+from pprint import pprint
+import inspect
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 2
+_def_bits_per_symbol = 1
+_def_h_numerator = 1
+_def_h_denominator = 2
+_def_cpm_type = 0 # 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL
+_def_bt = 0.35
+_def_symbols_per_pulse = 1
+_def_generic_taps = numpy.empty(1)
+_def_verbose = False
+_def_log = False
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# CPM modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class cpm_mod(gr.hier_block2):
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ bits_per_symbol=_def_bits_per_symbol,
+ h_numerator=_def_h_numerator,
+ h_denominator=_def_h_denominator,
+ cpm_type=_def_cpm_type,
+ bt=_def_bt,
+ symbols_per_pulse=_def_symbols_per_pulse,
+ generic_taps=_def_generic_taps,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for Continuous Phase
+ modulation.
+
+ The input is a byte stream (unsigned char)
+ representing packed bits and the
+ output is the complex modulated signal at baseband.
+
+ See Proakis for definition of generic CPM signals:
+ s(t)=exp(j phi(t))
+ phi(t)= 2 pi h int_0^t f(t') dt'
+ f(t)=sum_k a_k g(t-kT)
+ (normalizing assumption: int_0^infty g(t) dt = 1/2)
+
+ @param samples_per_symbol: samples per baud >= 2
+ @type samples_per_symbol: integer
+ @param bits_per_symbol: bits per symbol
+ @type bits_per_symbol: integer
+ @param h_numerator: numerator of modulation index
+ @type h_numerator: integer
+ @param h_denominator: denominator of modulation index (numerator and denominator must be relative primes)
+ @type h_denominator: integer
+ @param cpm_type: supported types are: 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL
+ @type cpm_type: integer
+ @param bt: bandwidth symbol time product for GMSK
+ @type bt: float
+ @param symbols_per_pulse: shaping pulse duration in symbols
+ @type symbols_per_pulse: integer
+ @param generic_taps: define a generic CPM pulse shape (sum = samples_per_symbol/2)
+ @type generic_taps: array of floats
+
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param debug: Print modulation data to files?
+ @type debug: bool
+ """
+
+ gr.hier_block2.__init__("cpm_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._bits_per_symbol = bits_per_symbol
+ self._h_numerator = h_numerator
+ self._h_denominator = h_denominator
+ self._cpm_type = cpm_type
+ self._bt=bt
+ if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic
+ self._symbols_per_pulse = symbols_per_pulse
+ elif cpm_type == 1: # GMSK
+ self._symbols_per_pulse = 4
+ else:
+ raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,))
+
+ self._generic_taps=numpy.array(generic_taps)
+
+ if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
+ raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % (samples_per_symbol,))
+
+ self.nsymbols = 2**bits_per_symbol
+ self.sym_alphabet=numpy.arange(-(self.nsymbols-1),self.nsymbols,2)
+
+
+ self.ntaps = self._symbols_per_pulse * samples_per_symbol
+ sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol
+
+ # Unpack Bytes into bits_per_symbol groups
+ self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol,gr.GR_MSB_FIRST)
+
+
+ # Turn it into symmetric PAM data.
+ self.pam = gr.chunks_to_symbols_bf(self.sym_alphabet,1)
+
+ # Generate pulse (sum of taps = samples_per_symbol/2)
+ if cpm_type == 0: # CPFSK
+ self.taps= (1.0/self._symbols_per_pulse/2,) * self.ntaps
+ elif cpm_type == 1: # GMSK
+ gaussian_taps = gr.firdes.gaussian(
+ 1.0/2, # gain
+ samples_per_symbol, # symbol_rate
+ bt, # bandwidth * symbol time
+ self.ntaps # number of taps
+ )
+ sqwave = (1,) * samples_per_symbol # rectangular window
+ self.taps = numpy.convolve(numpy.array(gaussian_taps),numpy.array(sqwave))
+ elif cpm_type == 2: # Raised Cosine
+ # generalize it for arbitrary roll-off factor
+ self.taps = (1-numpy.cos(2*pi*numpy.arange(0,self.ntaps)/samples_per_symbol/self._symbols_per_pulse))/(2*self._symbols_per_pulse)
+ elif cpm_type == 3: # Generic CPM
+ self.taps = generic_taps
+ else:
+ raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,))
+
+ self.filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps)
+
+ # FM modulation
+ self.fmmod = gr.frequency_modulator_fc(sensitivity)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect
+ self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
+
+ #def samples_per_symbol(self):
+ #return self._samples_per_symbol
+
+ #def bits_per_symbol(self):
+ #return self._bits_per_symbol
+
+ #def h_numerator(self):
+ #return self._h_numerator
+
+ #def h_denominator(self):
+ #return self._h_denominator
+
+ #def cpm_type(self):
+ #return self._cpm_type
+
+ #def bt(self):
+ #return self._bt
+
+ #def symbols_per_pulse(self):
+ #return self._symbols_per_pulse
+
+
+ def _print_verbage(self):
+ print "Samples per symbol = %d" % self._samples_per_symbol
+ print "Bits per symbol = %d" % self._bits_per_symbol
+ print "h = " , self._h_numerator , " / " , self._h_denominator
+ print "Symbol alphabet = " , self.sym_alphabet
+ print "Symbols per pulse = %d" % self._symbols_per_pulse
+ print "taps = " , self.taps
+
+ print "CPM type = %d" % self._cpm_type
+ if self._cpm_type == 1:
+ print "Gaussian filter BT = %.2f" % self._bt
+
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.B2s,
+ gr.file_sink(gr.sizeof_float, "symbols.dat"))
+ self.connect(self.pam,
+ gr.file_sink(gr.sizeof_float, "pam.dat"))
+ self.connect(self.filter,
+ gr.file_sink(gr.sizeof_float, "filter.dat"))
+ self.connect(self.fmmod,
+ gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat"))
+
+
+ def add_options(parser):
+ """
+ Adds CPM modulation-specific options to the standard parser
+ """
+ parser.add_option("", "--bt", type="float", default=_def_bt,
+ help="set bandwidth-time product [default=%default] (GMSK)")
+ 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(cpm_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# CPM demodulator
+# /////////////////////////////////////////////////////////////////////////////
+#
+# Not yet implemented
+#
+
+
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils.add_type_1_mod('cpm', cpm_mod)
+#modulation_utils.add_type_1_demod('cpm', cpm_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/d8psk.py b/gnuradio-core/src/python/gnuradio/blks2impl/d8psk.py
index f5461653d4..67cf9f5696 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/d8psk.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/d8psk.py
@@ -38,14 +38,14 @@ _def_gray_code = True
_def_verbose = False
_def_log = False
-_def_costas_alpha = 0.01
-_def_gain_mu = 0.05
+_def_costas_alpha = 0.175
+_def_gain_mu = 0.175
_def_mu = 0.5
_def_omega_relative_limit = 0.005
# /////////////////////////////////////////////////////////////////////////////
-# DQPSK modulator
+# D8PSK modulator
# /////////////////////////////////////////////////////////////////////////////
class d8psk_mod(gr.hier_block2):
@@ -74,10 +74,10 @@ class d8psk_mod(gr.hier_block2):
@type debug: 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
-
+ 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
@@ -114,16 +114,15 @@ class d8psk_mod(gr.hier_block2):
self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
- # Connect components
- self.connect(self, self.bytes2chunks, self.symbol_mapper, self.chunks2symbols,
- self.rrc_filter, self)
-
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
@@ -133,17 +132,22 @@ class d8psk_mod(gr.hier_block2):
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 "RS 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_symbol_mapper.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"))
+ 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):
"""
@@ -162,7 +166,7 @@ class d8psk_mod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(d8psk_mod.__init__,
- ('self', 'fg'), options)
+ ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
@@ -172,7 +176,6 @@ class d8psk_mod(gr.hier_block2):
# Differentially coherent detection of differentially encoded 8psk
# /////////////////////////////////////////////////////////////////////////////
-WITH_SYNC = False
class d8psk_demod(gr.hier_block2):
def __init__(self,
@@ -210,10 +213,10 @@ class d8psk_demod(gr.hier_block2):
@param debug: Print modualtion data to files?
@type debug: bool
"""
-
- gr.hier_block2.__init__(self, "d8psk_demod",
- gr.io_signature(1,1,gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1,1,gr.sizeof_char)) # Output signature
+
+ gr.hier_block2.__init__(self, "d8psk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
self._samples_per_symbol = samples_per_symbol
self._excess_bw = excess_bw
@@ -231,8 +234,9 @@ class d8psk_demod(gr.hier_block2):
# 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, 1.0)
+ #self.agc = gr.agc_cc(1e-2, 1, 1, 100)
+ self.agc = gr.agc2_cc(1e-1, 1e-2, 1, 1, 100)
+ #self.agc = gr.feedforward_agc_cc(16, 1.0)
# RRC data filter
ntaps = 11 * samples_per_symbol
@@ -248,17 +252,18 @@ class d8psk_demod(gr.hier_block2):
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.05
- fmax = 0.05
+ fmin = -0.025
+ fmax = 0.025
self.receiver=gr.mpsk_receiver_cc(arity, 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)
+ 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)
- #self.diffdec = gr.diff_decoder_bb(arity)
+ # Perform Differential decoding on the constellation
+ self.diffdec = gr.diff_phasor_cc()
# find closest constellation point
rot = 1
@@ -274,17 +279,15 @@ class d8psk_demod(gr.hier_block2):
# unpack the k bit vector into a stream of bits
self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
-
- # Connect and Initialize base class
- self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver,
- self.slicer, self.symbol_mapper, self.unpack, self)
-
if verbose:
self._print_verbage()
if log:
self._setup_logging()
-
+
+ # Connect
+ self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver,
+ self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
def samples_per_symbol(self):
return self._samples_per_symbol
@@ -308,14 +311,23 @@ class d8psk_demod(gr.hier_block2):
def _setup_logging(self):
- print "Demodulation 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.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"))
+ 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.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):
"""
@@ -326,7 +338,7 @@ class d8psk_demod(gr.hier_block2):
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=None,
+ 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)")
@@ -339,7 +351,7 @@ class d8psk_demod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(
- d8psk_demod.__init__, ('self', 'fg'), options)
+ d8psk_demod.__init__, ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
@@ -347,5 +359,5 @@ class d8psk_demod(gr.hier_block2):
# Add these to the mod/demod registry
#
# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
-#modulation_utils.add_type_1_mod('d8psk', d8psk_mod)
-#modulation_utils.add_type_1_demod('d8psk', d8psk_demod)
+modulation_utils.add_type_1_mod('d8psk', d8psk_mod)
+modulation_utils.add_type_1_demod('d8psk', d8psk_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/dbpsk.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py
index 90b7632c27..27063767c9 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/dbpsk.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py
@@ -38,8 +38,8 @@ _def_gray_code = True
_def_verbose = False
_def_log = False
-_def_costas_alpha = 0.15
-_def_gain_mu = 0.1
+_def_costas_alpha = 0.1
+_def_gain_mu = None
_def_mu = 0.5
_def_omega_relative_limit = 0.005
@@ -49,6 +49,7 @@ _def_omega_relative_limit = 0.005
# /////////////////////////////////////////////////////////////////////////////
class dbpsk_mod(gr.hier_block2):
+
def __init__(self,
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
@@ -73,9 +74,9 @@ class dbpsk_mod(gr.hier_block2):
@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
+ 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
@@ -112,15 +113,16 @@ class dbpsk_mod(gr.hier_block2):
self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol,
self.rrc_taps)
- # Connect components
- self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
- self.chunks2symbols, self.rrc_filter, self)
+ # 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
@@ -145,23 +147,28 @@ class dbpsk_mod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(dbpsk_mod.__init__,
- ('self', 'fg'), options)
+ ('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
+ 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_symbol_mapper.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"))
+ 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"))
# /////////////////////////////////////////////////////////////////////////////
@@ -207,12 +214,11 @@ class dbpsk_demod(gr.hier_block2):
@param debug: Print modualtion data to files?
@type debug: bool
"""
-
- gr.hier_block2.__init__(self, "dbpsk_demod",
- gr.io_signature(1,1,gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1,1,gr.sizeof_char)) # Output signature
-
+ gr.hier_block2.__init__(self, "dbpsk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
self._samples_per_symbol = samples_per_symbol
self._excess_bw = excess_bw
self._costas_alpha = costas_alpha
@@ -230,9 +236,8 @@ class dbpsk_demod(gr.hier_block2):
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, 1.0)
+ 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(
@@ -244,20 +249,23 @@ class dbpsk_demod(gr.hier_block2):
self.rrc_filter=gr.interp_fir_filter_ccf(1, self.rrc_taps)
# symbol clock recovery
+ if not self._mm_gain_mu:
+ self._mm_gain_mu = 0.1
+
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.02
- fmax = 0.02
+ fmin = -0.025
+ fmax = 0.025
self.receiver=gr.mpsk_receiver_cc(arity, 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)
+ 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)
- # Using differential decoding
+ # Do differential decoding based on phase change of symbols
self.diffdec = gr.diff_phasor_cc()
# find closest constellation point
@@ -273,16 +281,16 @@ class dbpsk_demod(gr.hier_block2):
# unpack the k bit vector into a stream of bits
self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
- # Connect and Initialize base class
- self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver,
- self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
-
if verbose:
self._print_verbage()
if log:
self._setup_logging()
+ # Connect and Initialize base class
+ self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver,
+ self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
+
def samples_per_symbol(self):
return self._samples_per_symbol
@@ -304,15 +312,23 @@ class dbpsk_demod(gr.hier_block2):
print "M&M omega limit: %.2f" % self._mm_omega_relative_limit
def _setup_logging(self):
- print "Demodulation 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.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"))
+ 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.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):
"""
@@ -338,7 +354,7 @@ class dbpsk_demod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(
- dbpsk_demod.__init__, ('self'), options)
+ dbpsk_demod.__init__, ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
#
# Add these to the mod/demod registry
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/digital_voice.py.real b/gnuradio-core/src/python/gnuradio/blks2impl/digital_voice.py.real
new file mode 100644
index 0000000000..6ec66825c1
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/digital_voice.py.real
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+#
+# Copyright 2005 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.
+#
+
+"""
+Digital voice Tx and Rx using GSM 13kbit vocoder and GMSK.
+
+Runs channel at 32kbit/sec. Currently uses fake channel coding,
+but there's room for a rate 1/2 coder.
+"""
+
+from gnuradio import gr, gru
+from gnuradio.blksimpl.gmsk import gmsk_mod, gmsk_demod
+
+from gnuradio.vocoder import gsm_full_rate
+
+# Size of gsm full rate speech encoder output packet in bytes
+
+GSM_FRAME_SIZE = 33
+
+# Size of packet in bytes that we send to GMSK modulator:
+#
+# Target: 256kS/sec air rate.
+#
+# 256kS 1 sym 1 bit 1 byte 0.020 sec 80 bytes
+# ---- * ----- * ----- * ------ * --------- = --------
+# sec 8 S 1 sym 8 bits frame frame
+#
+# gr_simple_framer add 10 bytes of overhead.
+
+AIR_FRAME_SIZE = 70
+
+
+class digital_voice_tx(gr.hier_block):
+ """
+ Hierarchical block for digital voice tranmission.
+
+ The input is 8kS/sec floating point audio in the range [-1,+1]
+ The output is 256kS/sec GMSK modulated complex baseband signal in the range [-1,+1].
+ """
+ def __init__(self, fg):
+ samples_per_symbol = 8
+ symbol_rate = 32000
+ bt = 0.3 # Gaussian filter bandwidth * symbol time
+
+ src_scale = gr.multiply_const_ff(32767)
+ f2s = gr.float_to_short()
+ voice_coder = gsm_full_rate.encode_sp()
+
+ channel_coder = gr.fake_channel_encoder_pp(GSM_FRAME_SIZE, AIR_FRAME_SIZE)
+ p2s = gr.parallel_to_serial(gr.sizeof_char, AIR_FRAME_SIZE)
+
+ mod = gmsk_mod(fg, sps=samples_per_symbol,
+ symbol_rate=symbol_rate, bt=bt,
+ p_size=AIR_FRAME_SIZE)
+
+ fg.connect(src_scale, f2s, voice_coder, channel_coder, p2s, mod)
+ gr.hier_block.__init__(self, fg, src_scale, mod)
+
+
+class digital_voice_rx(gr.hier_block):
+ """
+ Hierarchical block for digital voice reception.
+
+ The input is 256kS/sec GMSK modulated complex baseband signal.
+ The output is 8kS/sec floating point audio in the range [-1,+1]
+ """
+ def __init__(self, fg):
+ samples_per_symbol = 8
+ symbol_rate = 32000
+
+ demod = gmsk_demod(fg, sps=samples_per_symbol,
+ symbol_rate=symbol_rate,
+ p_size=AIR_FRAME_SIZE)
+
+ s2p = gr.serial_to_parallel(gr.sizeof_char, AIR_FRAME_SIZE)
+ channel_decoder = gr.fake_channel_decoder_pp(AIR_FRAME_SIZE, GSM_FRAME_SIZE)
+
+ voice_decoder = gsm_full_rate.decode_ps()
+ s2f = gr.short_to_float ()
+ sink_scale = gr.multiply_const_ff(1.0/32767.)
+
+ fg.connect(demod, s2p, channel_decoder, voice_decoder, s2f, sink_scale)
+ gr.hier_block.__init__(self, fg, demod, sink_scale)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/dqpsk.py b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk.py
index cc82cd2fe6..8c15d21734 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/dqpsk.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk.py
@@ -39,7 +39,7 @@ _def_verbose = False
_def_log = False
_def_costas_alpha = 0.15
-_def_gain_mu = 0.1
+_def_gain_mu = None
_def_mu = 0.5
_def_omega_relative_limit = 0.005
@@ -49,6 +49,7 @@ _def_omega_relative_limit = 0.005
# /////////////////////////////////////////////////////////////////////////////
class dqpsk_mod(gr.hier_block2):
+
def __init__(self,
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
@@ -73,9 +74,9 @@ class dqpsk_mod(gr.hier_block2):
@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
+ 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
@@ -112,16 +113,16 @@ class dqpsk_mod(gr.hier_block2):
ntaps)
self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
-
- # Connect components
- 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()
+
+ # 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
@@ -132,17 +133,22 @@ class dqpsk_mod(gr.hier_block2):
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
+ 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_symbol_mapper.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"))
+ 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):
"""
@@ -161,7 +167,7 @@ class dqpsk_mod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(dqpsk_mod.__init__,
- ('self', 'fg'), options)
+ ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
@@ -173,7 +179,7 @@ class dqpsk_mod(gr.hier_block2):
class dqpsk_demod(gr.hier_block2):
- def __init__(self,
+ def __init__(self,
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
costas_alpha=_def_costas_alpha,
@@ -209,9 +215,9 @@ class dqpsk_demod(gr.hier_block2):
@type debug: bool
"""
- gr.hier_block2.__init__(self, "dqpsk_demod",
- gr.io_signature(1,1,gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1,1,gr.sizeof_char)) # Output signature
+ gr.hier_block2.__init__(self, "dqpsk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
self._samples_per_symbol = samples_per_symbol
self._excess_bw = excess_bw
@@ -229,6 +235,7 @@ class dqpsk_demod(gr.hier_block2):
# 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
@@ -241,23 +248,26 @@ class dqpsk_demod(gr.hier_block2):
ntaps)
self.rrc_filter=gr.interp_fir_filter_ccf(1, self.rrc_taps)
- # symbol clock recovery
+ 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.01
- fmax = 0.01
+ fmin = -0.025
+ fmax = 0.025
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)
-
+ 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)
+
# 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])
@@ -271,15 +281,15 @@ class dqpsk_demod(gr.hier_block2):
# unpack the k bit vector into a stream of bits
self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
- # Connect and Initialize base class
- self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver, self.diffdec,
- self.slicer, self.symbol_mapper, self.unpack, self)
-
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.slicer, self.symbol_mapper, self.unpack, self)
def samples_per_symbol(self):
return self._samples_per_symbol
@@ -302,15 +312,23 @@ class dqpsk_demod(gr.hier_block2):
print "M&M omega limit: %.2f" % self._mm_omega_relative_limit
def _setup_logging(self):
- print "Demodulation 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.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"))
+ 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.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):
"""
@@ -321,7 +339,7 @@ class dqpsk_demod(gr.hier_block2):
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=None,
+ 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)")
@@ -334,7 +352,7 @@ class dqpsk_demod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(
- dqpsk_demod.__init__, ('self', 'fg'), options)
+ dqpsk_demod.__init__, ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/filterbank.py b/gnuradio-core/src/python/gnuradio/blks2impl/filterbank.py
index 0cff78bef3..c1284565f3 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/filterbank.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/filterbank.py
@@ -1,5 +1,5 @@
#
-# Copyright 2005 Free Software Foundation, Inc.
+# Copyright 2005,2007 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -45,7 +45,6 @@ class synthesis_filterbank(gr.hier_block2):
Takes M complex streams in, produces single complex stream out
that runs at M times the input sample rate
- @param fg: flow_graph
@param mpoints: number of freq bins/interpolation factor/subbands
@param taps: filter taps for subband filter
@@ -83,9 +82,10 @@ class synthesis_filterbank(gr.hier_block2):
utility.
"""
item_size = gr.sizeof_gr_complex
- gr.hier_block2.__init__(self, "synthesis_filterbank",
- gr.io_signature(mpoints, mpoints, item_size),
- gr.io_signature(1, 1, item_size))
+ gr.hier_block2.__init__(self, "synthesis_filterbank",
+ gr.io_signature(mpoints, mpoints, item_size), # Input signature
+ gr.io_signature(1, 1, item_size)) # Output signature
+
if taps is None:
taps = _generate_synthesis_taps(mpoints)
@@ -104,9 +104,9 @@ class synthesis_filterbank(gr.hier_block2):
# mpoints filters go in here...
self.ss2s = gr.streams_to_stream(item_size, mpoints)
- for i in range(mpoints):
- self.connect((self, i), (self.ss2v, i))
-
+ for i in range(mpoints):
+ self.connect((self, i), (self.ss2v, i))
+
self.connect(self.ss2v, self.ifft, self.v2ss, self)
# build mpoints fir filters...
@@ -127,17 +127,16 @@ class analysis_filterbank(gr.hier_block2):
Takes 1 complex stream in, produces M complex streams out
that runs at 1/M times the input sample rate
- @param fg: flow_graph
@param mpoints: number of freq bins/interpolation factor/subbands
@param taps: filter taps for subband filter
Same channel to frequency mapping as described above.
"""
item_size = gr.sizeof_gr_complex
- gr.hier_block2.__init__(self, "analysis_filterbank",
- gr.io_signature(1, 1, item_size),
- gr.io_signature(mpoints, mpoints, item_size))
-
+ gr.hier_block2.__init__(self, "analysis_filterbank",
+ gr.io_signature(1, 1, item_size), # Input signature
+ gr.io_signature(mpoints, mpoints, item_size)) # Output signature
+
if taps is None:
taps = _generate_synthesis_taps(mpoints)
@@ -157,18 +156,13 @@ class analysis_filterbank(gr.hier_block2):
self.fft = gr.fft_vcc(mpoints, True, [])
self.v2ss = gr.vector_to_streams(item_size, mpoints)
- self.connect(self, self.s2ss)
-
+ self.connect(self, self.s2ss)
+
# build mpoints fir filters...
for i in range(mpoints):
f = gr.fft_filter_ccc(1, sub_taps[mpoints-i-1])
self.connect((self.s2ss, i), f)
self.connect(f, (self.ss2v, i))
-
+ self.connect((self.v2ss, i), (self, i))
+
self.connect(self.ss2v, self.fft, self.v2ss)
-
- for i in range(mpoints):
- self.connect((self.v2ss, i), (self, i))
-
-
-
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/fm_demod.py b/gnuradio-core/src/python/gnuradio/blks2impl/fm_demod.py
new file mode 100644
index 0000000000..1910b50117
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/fm_demod.py
@@ -0,0 +1,111 @@
+#
+# Copyright 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 gnuradio import gr, optfir
+from gnuradio.blks2impl.fm_emph import fm_deemph
+from math import pi
+
+class fm_demod_cf(gr.hier_block2):
+ """
+ Generalized FM demodulation block with deemphasis and audio
+ filtering.
+
+ This block demodulates a band-limited, complex down-converted FM
+ channel into the the original baseband signal, optionally applying
+ deemphasis. Low pass filtering is done on the resultant signal. It
+ produces an output float strem in the range of [-1.0, +1.0].
+
+ @param channel_rate: incoming sample rate of the FM baseband
+ @type sample_rate: integer
+ @param deviation: maximum FM deviation (default = 5000)
+ @type deviation: float
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ @param audio_pass: audio low pass filter passband frequency
+ @type audio_pass: float
+ @param audio_stop: audio low pass filter stop frequency
+ @type audio_stop: float
+ @param gain: gain applied to audio output (default = 1.0)
+ @type gain: float
+ @param tau: deemphasis time constant (default = 75e-6), specify 'None'
+ to prevent deemphasis
+ """
+ def __init__(self, channel_rate, audio_decim, deviation,
+ audio_pass, audio_stop, gain=1.0, tau=75e-6):
+ gr.hier_block2.__init__(self, "fm_demod_cf",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
+
+ k = channel_rate/(2*pi*deviation)
+ QUAD = gr.quadrature_demod_cf(k)
+
+ audio_taps = optfir.low_pass(gain, # Filter gain
+ channel_rate, # Sample rate
+ audio_pass, # Audio passband
+ audio_stop, # Audio stopband
+ 0.1, # Passband ripple
+ 60) # Stopband attenuation
+ LPF = gr.fir_filter_fff(audio_decim, audio_taps)
+
+ if tau is not None:
+ DEEMPH = fm_deemph(channel_rate, tau)
+ self.connect(self, QUAD, DEEMPH, LPF, self)
+ else:
+ self.connect(self, QUAD, LPF, self)
+
+class demod_20k0f3e_cf(fm_demod_cf):
+ """
+ NBFM demodulation block, 20 KHz channels
+
+ This block demodulates a complex, downconverted, narrowband FM
+ channel conforming to 20K0F3E emission standards, outputting
+ floats in the range [-1.0, +1.0].
+
+ @param sample_rate: incoming sample rate of the FM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ """
+ def __init__(self, channel_rate, audio_decim):
+ fm_demod_cf.__init__(self, channel_rate, audio_decim,
+ 5000, # Deviation
+ 3000, # Audio passband frequency
+ 4000) # Audio stopband frequency
+
+class demod_200kf3e_cf(fm_demod_cf):
+ """
+ WFM demodulation block, mono.
+
+ This block demodulates a complex, downconverted, wideband FM
+ channel conforming to 200KF3E emission standards, outputting
+ floats in the range [-1.0, +1.0].
+
+ @param sample_rate: incoming sample rate of the FM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ """
+ def __init__(self, channel_rate, audio_decim):
+ fm_demod_cf.__init__(self, channel_rate, audio_decim,
+ 75000, # Deviation
+ 15000, # Audio passband
+ 16000, # Audio stopband
+ 20.0) # Audio gain
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/fm_emph.py b/gnuradio-core/src/python/gnuradio/blks2impl/fm_emph.py
new file mode 100644
index 0000000000..fd19f5fd99
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/fm_emph.py
@@ -0,0 +1,151 @@
+#
+# Copyright 2005,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 gnuradio import gr
+import math
+
+
+#
+# 1
+# H(s) = -------
+# 1 + s
+#
+# tau is the RC time constant.
+# critical frequency: w_p = 1/tau
+#
+# We prewarp and use the bilinear z-transform to get our IIR coefficients.
+# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis
+#
+
+class fm_deemph(gr.hier_block2):
+ """
+ FM Deemphasis IIR filter.
+ """
+
+
+ def __init__(self, fs, tau=75e-6):
+ """
+ @param fs: sampling frequency in Hz
+ @type fs: float
+ @param tau: Time constant in seconds (75us in US, 50us in EUR)
+ @type tau: float
+ """
+ gr.hier_block2.__init__(self, "fm_deemph",
+ gr.io_signature(1, 1, gr.sizeof_float), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
+
+ w_p = 1/tau
+ w_pp = math.tan (w_p / (fs * 2)) # prewarped analog freq
+
+ a1 = (w_pp - 1)/(w_pp + 1)
+ b0 = w_pp/(1 + w_pp)
+ b1 = b0
+
+ btaps = [b0, b1]
+ ataps = [1, a1]
+
+ if 0:
+ print "btaps =", btaps
+ print "ataps =", ataps
+ global plot1
+ plot1 = gru.gnuplot_freqz (gru.freqz (btaps, ataps), fs, True)
+
+ deemph = gr.iir_filter_ffd(btaps, ataps)
+ self.connect(self, deemph, self)
+
+#
+# 1 + s*t1
+# H(s) = ----------
+# 1 + s*t2
+#
+# I think this is the right transfer function.
+#
+#
+# This fine ASCII rendition is based on Figure 5-15
+# in "Digital and Analog Communication Systems", Leon W. Couch II
+#
+#
+# R1
+# +-----||------+
+# | |
+# o------+ +-----+--------o
+# | C1 | |
+# +----/\/\/\/--+ \
+# /
+# \ R2
+# /
+# \
+# |
+# o--------------------------+--------o
+#
+# f1 = 1/(2*pi*t1) = 1/(2*pi*R1*C)
+#
+# 1 R1 + R2
+# f2 = ------- = ------------
+# 2*pi*t2 2*pi*R1*R2*C
+#
+# t1 is 75us in US, 50us in EUR
+# f2 should be higher than our audio bandwidth.
+#
+#
+# The Bode plot looks like this:
+#
+#
+# /----------------
+# /
+# / <-- slope = 20dB/decade
+# /
+# -------------/
+# f1 f2
+#
+# We prewarp and use the bilinear z-transform to get our IIR coefficients.
+# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis
+#
+
+class fm_preemph(gr.hier_block2):
+ """
+ FM Preemphasis IIR filter.
+ """
+ def __init__(self, fs, tau=75e-6):
+ """
+ @param fs: sampling frequency in Hz
+ @type fs: float
+ @param tau: Time constant in seconds (75us in US, 50us in EUR)
+ @type tau: float
+ """
+
+ gr.hier_block2.__init__(self, "fm_deemph",
+ gr.io_signature(1, 1, gr.sizeof_float), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
+
+ # FIXME make this compute the right answer
+
+ btaps = [1]
+ ataps = [1]
+
+ if 0:
+ print "btaps =", btaps
+ print "ataps =", ataps
+ global plot2
+ plot2 = gru.gnuplot_freqz (gru.freqz (btaps, ataps), fs, True)
+
+ preemph = gr.iir_filter_ffd(btaps, ataps)
+ self.connect(self, preemph, self)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/gmsk.py b/gnuradio-core/src/python/gnuradio/blks2impl/gmsk.py
index d1cf55c7ff..3b6c016a0b 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/gmsk.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/gmsk.py
@@ -37,7 +37,7 @@ _def_bt = 0.35
_def_verbose = False
_def_log = False
-_def_gain_mu = 0.05
+_def_gain_mu = None
_def_mu = 0.5
_def_freq_error = 0.0
_def_omega_relative_limit = 0.005
@@ -71,9 +71,9 @@ class gmsk_mod(gr.hier_block2):
@type debug: bool
"""
- gr.hier_block2.__init__(self, "gmsk_mod",
- gr.io_signature(1,1,gr.sizeof_char), # Input signature
- gr.io_signature(1,1,gr.sizeof_gr_complex)) # Output signature
+ gr.hier_block2.__init__(self, "gmsk_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._bt = bt
@@ -103,15 +103,15 @@ class gmsk_mod(gr.hier_block2):
# FM modulation
self.fmmod = gr.frequency_modulator_fc(sensitivity)
- # Connect components
- self.connect(self, self.nrz, self.gaussian_filter, self.fmmod, self)
-
if verbose:
self._print_verbage()
if log:
self._setup_logging()
+ # Connect & Initialize base class
+ self.connect(self, self.nrz, self.gaussian_filter, self.fmmod, self)
+
def samples_per_symbol(self):
return self._samples_per_symbol
@@ -127,9 +127,13 @@ class gmsk_mod(gr.hier_block2):
def _setup_logging(self):
print "Modulation logging turned on."
- self.connect(self.nrz, gr.file_sink(gr.sizeof_float, "tx_nrz.dat"))
- self.connect(self.gaussian_filter, gr.file_sink(gr.sizeof_float, "tx_gaussian_filter.dat"))
- self.connect(self.fmmod, gr.file_sink(gr.sizeof_gr_complex, "tx_fmmod.dat"))
+ self.connect(self.nrz,
+ gr.file_sink(gr.sizeof_float, "nrz.dat"))
+ self.connect(self.gaussian_filter,
+ gr.file_sink(gr.sizeof_float, "gaussian_filter.dat"))
+ self.connect(self.fmmod,
+ gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat"))
+
def add_options(parser):
"""
@@ -145,7 +149,7 @@ class gmsk_mod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(gmsk_mod.__init__,
- ('self', 'fg'), options)
+ ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
@@ -190,9 +194,9 @@ class gmsk_demod(gr.hier_block2):
@param float
"""
- gr.hier_block2.__init__(self, "gmsk_demod",
- gr.io_signature(1,1,gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1,1,gr.sizeof_char)) # Output signature
+ gr.hier_block2.__init__(self, "gmsk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
self._samples_per_symbol = samples_per_symbol
self._gain_mu = gain_mu
@@ -205,6 +209,9 @@ class gmsk_demod(gr.hier_block2):
self._omega = samples_per_symbol*(1+self._freq_error)
+ if not self._gain_mu:
+ self._gain_mu = 0.175
+
self._gain_omega = .25 * self._gain_mu * self._gain_mu # critically damped
# Demodulate FM
@@ -220,15 +227,15 @@ class gmsk_demod(gr.hier_block2):
# slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample
self.slicer = gr.binary_slicer_fb()
- # Connect components
- self.connect(self, self.fmdemod, self.clock_recovery, self.slicer, self)
-
if verbose:
self._print_verbage()
if log:
self._setup_logging()
+ # Connect & Initialize base class
+ self.connect(self, self.fmdemod, self.clock_recovery, self.slicer, self)
+
def samples_per_symbol(self):
return self._samples_per_symbol
@@ -236,6 +243,7 @@ class gmsk_demod(gr.hier_block2):
return 1
bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method.
+
def _print_verbage(self):
print "bits per symbol = %d" % self.bits_per_symbol()
print "M&M clock recovery omega = %f" % self._omega
@@ -247,9 +255,12 @@ class gmsk_demod(gr.hier_block2):
def _setup_logging(self):
print "Demodulation logging turned on."
- self.connect(self.fmdemod, gr.file_sink(gr.sizeof_float, "rx_fmdemod.dat"))
- self.connect(self.clock_recovery, gr.file_sink(gr.sizeof_float, "rx_clock_recovery.dat"))
- self.connect(self.slicer, gr.file_sink(gr.sizeof_char, "rx_slicer.dat"))
+ self.connect(self.fmdemod,
+ gr.file_sink(gr.sizeof_float, "fmdemod.dat"))
+ self.connect(self.clock_recovery,
+ gr.file_sink(gr.sizeof_float, "clock_recovery.dat"))
+ self.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "slicer.dat"))
def add_options(parser):
"""
@@ -270,7 +281,7 @@ class gmsk_demod(gr.hier_block2):
Given command line options, create dictionary suitable for passing to __init__
"""
return modulation_utils.extract_kwargs_from_options(gmsk_demod.__init__,
- ('self', 'fg'), options)
+ ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/nbfm_rx.py b/gnuradio-core/src/python/gnuradio/blks2impl/nbfm_rx.py
new file mode 100644
index 0000000000..8a1704000a
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/nbfm_rx.py
@@ -0,0 +1,88 @@
+#
+# Copyright 2005 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, optfir
+from gnuradio.blks2impl.fm_emph import fm_deemph
+#from gnuradio.blks2impl.standard_squelch import standard_squelch
+
+class nbfm_rx(gr.hier_block2):
+ def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3):
+ """
+ Narrow Band FM Receiver.
+
+ Takes a single complex baseband input stream and produces a single
+ float output stream of audio sample in the range [-1, +1].
+
+ @param audio_rate: sample rate of audio stream, >= 16k
+ @type audio_rate: integer
+ @param quad_rate: sample rate of output stream
+ @type quad_rate: integer
+ @param tau: preemphasis time constant (default 75e-6)
+ @type tau: float
+ @param max_dev: maximum deviation in Hz (default 5e3)
+ @type max_dev: float
+
+ quad_rate must be an integer multiple of audio_rate.
+
+ Exported sub-blocks (attributes):
+ squelch
+ quad_demod
+ deemph
+ audio_filter
+ """
+
+ gr.hier_block2.__init__(self, "nbfm_rx",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
+
+ # FIXME audio_rate and quad_rate ought to be exact rationals
+ audio_rate = int(audio_rate)
+ quad_rate = int(quad_rate)
+
+ if quad_rate % audio_rate != 0:
+ raise ValueError, "quad_rate is not an integer multiple of audio_rate"
+
+ squelch_threshold = 20 # dB
+ #self.squelch = gr.simple_squelch_cc(squelch_threshold, 0.001)
+
+ # FM Demodulator input: complex; output: float
+ k = quad_rate/(2*math.pi*max_dev)
+ self.quad_demod = gr.quadrature_demod_cf(k)
+
+ # FM Deemphasis IIR filter
+ self.deemph = fm_deemph (quad_rate, tau=tau)
+
+ # compute FIR taps for audio filter
+ audio_decim = quad_rate // audio_rate
+ audio_taps = gr.firdes.low_pass (1.0, # gain
+ quad_rate, # sampling rate
+ 4.5e3, # Audio LPF cutoff
+ 2.5e3, # Transition band
+ gr.firdes.WIN_HAMMING) # filter type
+
+ print "len(audio_taps) =", len(audio_taps)
+
+ # Decimating audio filter
+ # input: float; output: float; taps: float
+ self.audio_filter = gr.fir_filter_fff(audio_decim, audio_taps)
+
+ self.connect(self, self.quad_demod, self.deemph, self.audio_filter, self)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/nbfm_tx.py b/gnuradio-core/src/python/gnuradio/blks2impl/nbfm_tx.py
new file mode 100644
index 0000000000..15818c2043
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/nbfm_tx.py
@@ -0,0 +1,92 @@
+#
+# Copyright 2005 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, optfir
+from gnuradio.blks2impl.fm_emph import fm_preemph
+
+#from gnuradio import ctcss
+
+class nbfm_tx(gr.hier_block2):
+ def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3):
+ """
+ Narrow Band FM Transmitter.
+
+ Takes a single float input stream of audio samples in the range [-1,+1]
+ and produces a single FM modulated complex baseband output.
+
+ @param audio_rate: sample rate of audio stream, >= 16k
+ @type audio_rate: integer
+ @param quad_rate: sample rate of output stream
+ @type quad_rate: integer
+ @param tau: preemphasis time constant (default 75e-6)
+ @type tau: float
+ @param max_dev: maximum deviation in Hz (default 5e3)
+ @type max_dev: float
+
+ quad_rate must be an integer multiple of audio_rate.
+ """
+
+ gr.hier_block2.__init__(self, "nbfm_tx",
+ gr.io_signature(1, 1, gr.sizeof_float), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ # FIXME audio_rate and quad_rate ought to be exact rationals
+ audio_rate = int(audio_rate)
+ quad_rate = int(quad_rate)
+
+ if quad_rate % audio_rate != 0:
+ raise ValueError, "quad_rate is not an integer multiple of audio_rate"
+
+
+ do_interp = audio_rate != quad_rate
+
+ if do_interp:
+ interp_factor = quad_rate / audio_rate
+ interp_taps = optfir.low_pass (interp_factor, # gain
+ quad_rate, # Fs
+ 4500, # passband cutoff
+ 7000, # stopband cutoff
+ 0.1, # passband ripple dB
+ 40) # stopband atten dB
+
+ #print "len(interp_taps) =", len(interp_taps)
+ self.interpolator = gr.interp_fir_filter_fff (interp_factor, interp_taps)
+
+ self.preemph = fm_preemph (quad_rate, tau=tau)
+
+ k = 2 * math.pi * max_dev / quad_rate
+ self.modulator = gr.frequency_modulator_fc (k)
+
+ if do_interp:
+ self.connect (self, self.interpolator, self.preemph, self.modulator, self)
+ else:
+ self.connect(self, self.preemph, self.modulator, self)
+
+
+class ctcss_gen_f(gr.hier_block2):
+ def __init__(self, sample_rate, tone_freq):
+ gr.hier_block2.__init__(self, "ctcss_gen_f",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
+
+ self.plgen = gr.sig_source_f(sample_rate, gr.GR_SIN_WAVE, tone_freq, 0.1, 0.0)
+ self.connect(self.plgen, self)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
new file mode 100644
index 0000000000..b040d8c7f4
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
@@ -0,0 +1,305 @@
+
+#
+# Copyright 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.
+#
+
+import math
+from numpy import fft
+from gnuradio import gr, ofdm_packet_utils
+import gnuradio.gr.gr_threading as _threading
+import psk, qam
+
+from gnuradio.blksimpl.ofdm_receiver import ofdm_receiver
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# mod/demod with packets as i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class ofdm_mod(gr.hier_block):
+ """
+ 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, fg, 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 fg: flow graph
+ @type fg: flow graph
+ @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
+ """
+
+ 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
+
+ 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,
+ known_symbols_4512_1[0:self._occupied_tones],
+ known_symbols_4512_2[0:self._occupied_tones])
+
+ 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
+
+ mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
+ arity = mods[self._modulation]
+
+ rot = 1
+ if self._modulation == "qpsk":
+ rot = (0.707+0.707j)
+
+ if(self._modulation.find("psk") >= 0):
+ rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
+ elif(self._modulation.find("qam") >= 0):
+ rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+ #print rotated_const
+ self._pkt_input = gr.ofdm_mapper_bcv(rotated_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))
+
+ fg.connect((self._pkt_input, 0), (self.preambles, 0))
+ fg.connect((self._pkt_input, 1), (self.preambles, 1))
+ fg.connect(self.preambles, self.ifft, self.cp_adder, self.scale)
+
+ if options.verbose:
+ self._print_verbage()
+
+ if options.log:
+ fg.connect(self._pkt_input, gr.file_sink(gr.sizeof_gr_complex*options.fft_length,
+ "ofdm_mapper_c.dat"))
+
+ gr.hier_block.__init__(self, fg, None, self.scale)
+
+ 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
+ """
+ normal.add_option("-m", "--modulation", type="string", default="bpsk",
+ help="set modulation type (bpsk or qpsk) [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]")
+ # 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_block):
+ """
+ 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, fg, 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 fg: flow graph
+ @type fg: flow graph
+ @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
+ """
+ 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
+
+
+ # Use freq domain to get doubled-up known symbol for correlation in time domain
+ ksfreq = known_symbols_4512_3[0:self._occupied_tones]
+ for i in range(len(ksfreq)):
+ if(i&1):
+ ksfreq[i] = 0
+
+ zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0))
+ zeros_on_right = self._fft_length - self._occupied_tones - zeros_on_left
+ ks0 = zeros_on_left*[0.0,]
+ ks0.extend(ksfreq)
+ ks0.extend(zeros_on_right*[0.0,])
+
+ ks0time = fft.ifft(ks0)
+ # ADD SCALING FACTOR
+ ks0time = ks0time.tolist()
+
+ # hard-coded known symbols
+ preambles = (ks0time,
+ known_symbols_4512_1[0:self._occupied_tones],
+ known_symbols_4512_2[0:self._occupied_tones])
+
+ symbol_length = self._fft_length + self._cp_length
+ self.ofdm_recv = ofdm_receiver(fg, self._fft_length, self._cp_length,
+ self._occupied_tones, self._snr, preambles,
+ options.log)
+
+ mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
+ arity = mods[self._modulation]
+
+ rot = 1
+ if self._modulation == "qpsk":
+ rot = (0.707+0.707j)
+
+ if(self._modulation.find("psk") >= 0):
+ rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
+ elif(self._modulation.find("qam") >= 0):
+ rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+ #print rotated_const
+ self.ofdm_demod = gr.ofdm_frame_sink(rotated_const, range(arity),
+ self._rcvd_pktq,
+ self._occupied_tones)
+
+ fg.connect((self.ofdm_recv, 0), (self.ofdm_demod, 0))
+ fg.connect((self.ofdm_recv, 1), (self.ofdm_demod, 1))
+
+ if options.verbose:
+ self._print_verbage()
+
+ gr.hier_block.__init__(self, fg, self.ofdm_recv, None)
+ self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+
+
+ def add_options(normal, expert):
+ """
+ Adds OFDM-specific options to the Options Parser
+ """
+ normal.add_option("-m", "--modulation", type="string", default="bpsk",
+ help="set modulation type (bpsk or qpsk) [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]")
+ # 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_200_1 = [1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0]
+
+known_symbols_200_2 = [-1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0]
+
+
+known_symbols_4512_1 = [-1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1]
+
+known_symbols_4512_2 = [1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1]
+
+
+known_symbols_4512_impulse = 4512*[1,]
+
+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/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py
new file mode 100644
index 0000000000..d16d2e2940
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+#
+
+import math
+from gnuradio import gr
+from gnuradio.blksimpl.ofdm_sync_ml import ofdm_sync_ml
+from gnuradio.blksimpl.ofdm_sync_pn import ofdm_sync_pn
+from gnuradio.blksimpl.ofdm_sync_pnac import ofdm_sync_pnac
+
+class ofdm_receiver(gr.hier_block):
+ def __init__(self, fg, fft_length, cp_length, occupied_tones, snr, ks, logging=False):
+ self.fg = fg
+
+ bw = (float(occupied_tones) / float(fft_length)) / 2.0
+ tb = bw*0.08
+ chan_coeffs = gr.firdes.low_pass (1.0, # gain
+ 1.0, # sampling rate
+ bw+tb, # midpoint of trans. band
+ tb, # width of trans. band
+ gr.firdes.WIN_HAMMING) # filter type
+ self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs)
+
+ win = [1 for i in range(fft_length)]
+
+ SYNC = "pn"
+ if SYNC == "ml":
+ self.ofdm_sync = ofdm_sync_ml(fg, fft_length, cp_length, snr, logging)
+ elif SYNC == "pn":
+ self.ofdm_sync = ofdm_sync_pn(fg, fft_length, cp_length, logging)
+ elif SYNC == "pnac":
+ self.ofdm_sync = ofdm_sync_pnac(fg, fft_length, cp_length, ks[0])
+
+ self.fft_demod = gr.fft_vcc(fft_length, True, win, True)
+ self.ofdm_corr = gr.ofdm_correlator(occupied_tones, fft_length,
+ cp_length, ks[1], ks[2])
+
+ self.fg.connect(self.chan_filt, self.ofdm_sync, self.fft_demod, self.ofdm_corr)
+
+ if logging:
+ self.fg.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "chan_filt_c.dat"))
+ self.fg.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "fft_out_c.dat"))
+ self.fg.connect(self.ofdm_corr, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_corr_out_c.dat"))
+ self.fg.connect((self.ofdm_corr,1), gr.file_sink(1, "found_corr_b.dat"))
+
+ gr.hier_block.__init__(self, fg, self.chan_filt, self.ofdm_corr)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py
new file mode 100644
index 0000000000..b56f65660e
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+#
+
+import math
+from gnuradio import gr
+
+class ofdm_sync_fixed(gr.hier_block):
+ def __init__(self, fg, fft_length, cp_length, snr):
+ self.fg = fg
+
+ # Use a fixed trigger point instead of sync block
+ data = (fft_length+cp_len)*[0,]
+ data[(fft_length+cp_len)-1] = 1
+ peak_trigger = gr.vector_source_b(data, True)
+
+ self.fg.connect(peak_trigger, (self.sampler,1))
+
+ if 1:
+ self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length,
+ "ofdm_sync_fixed-sampler_c.dat"))
+
+ gr.hier_block.__init__(self, fg, (self.sampler,0), self.sampler)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py
new file mode 100644
index 0000000000..d58f56cffc
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+#
+
+import math
+from gnuradio import gr
+
+class ofdm_sync_ml(gr.hier_block):
+ def __init__(self, fg, fft_length, cp_length, snr, logging):
+ ''' Maximum Likelihood OFDM synchronizer:
+ J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation
+ of Time and Frequency Offset in OFDM Systems," IEEE Trans.
+ Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997.
+ '''
+
+ self.fg = fg
+
+ # FIXME: when converting to hier_block2's, the output signature
+ # should be the output of the divider (the normalized peaks) and
+ # the angle value out of the sample and hold block
+
+ self.input = gr.add_const_cc(0)
+
+ SNR = 10.0**(snr/10.0)
+ rho = SNR / (SNR + 1.0)
+ symbol_length = fft_length + cp_length
+
+ # ML Sync
+
+ # Energy Detection from ML Sync
+
+ # Create a delay line
+ self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)
+ self.fg.connect(self.input, self.delay)
+
+ # magnitude squared blocks
+ self.magsqrd1 = gr.complex_to_mag_squared()
+ self.magsqrd2 = gr.complex_to_mag_squared()
+ self.adder = gr.add_ff()
+
+ moving_sum_taps = [rho/2 for i in range(cp_length)]
+ self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps)
+
+ self.fg.connect(self.input,self.magsqrd1)
+ self.fg.connect(self.delay,self.magsqrd2)
+ self.fg.connect(self.magsqrd1,(self.adder,0))
+ self.fg.connect(self.magsqrd2,(self.adder,1))
+ self.fg.connect(self.adder,self.moving_sum_filter)
+
+
+ # Correlation from ML Sync
+ self.conjg = gr.conjugate_cc();
+ self.mixer = gr.multiply_cc();
+
+ movingsum2_taps = [1.0 for i in range(cp_length)]
+ self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps)
+
+ # Correlator data handler
+ self.c2mag = gr.complex_to_mag()
+ self.angle = gr.complex_to_arg()
+ self.fg.connect(self.input,(self.mixer,1))
+ self.fg.connect(self.delay,self.conjg,(self.mixer,0))
+ self.fg.connect(self.mixer,self.movingsum2,self.c2mag)
+ self.fg.connect(self.movingsum2,self.angle)
+
+ # ML Sync output arg, need to find maximum point of this
+ self.diff = gr.sub_ff()
+ self.fg.connect(self.c2mag,(self.diff,0))
+ self.fg.connect(self.moving_sum_filter,(self.diff,1))
+
+ #ML measurements input to sampler block and detect
+ nco_sensitivity = -1.0/fft_length
+ self.f2c = gr.float_to_complex()
+ self.sampler = gr.ofdm_sampler(fft_length,symbol_length)
+ self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005)
+ self.sample_and_hold = gr.sample_and_hold_ff()
+ self.nco = gr.frequency_modulator_fc(nco_sensitivity)
+ self.sigmix = gr.multiply_cc()
+
+ # Mix the signal with an NCO controlled by the sync loop
+ self.fg.connect(self.input, (self.sigmix,0))
+ self.fg.connect(self.nco, (self.sigmix,1))
+ self.fg.connect(self.sigmix, (self.sampler,0))
+
+ # use the sync loop values to set the sampler and the NCO
+ # self.diff = theta
+ # self.angle = epsilon
+
+ self.fg.connect(self.diff, self.pk_detect)
+
+ use_dpll = 1
+ if use_dpll:
+ self.dpll = gr.dpll_bb(float(symbol_length),0.01)
+ self.fg.connect(self.pk_detect, self.dpll)
+ self.fg.connect(self.dpll, (self.sampler,1))
+ self.fg.connect(self.dpll, (self.sample_and_hold,1))
+ else:
+ self.fg.connect(self.pk_detect, (self.sampler,1))
+ self.fg.connect(self.pk_detect, (self.sample_and_hold,1))
+
+ self.fg.connect(self.angle, (self.sample_and_hold,0))
+ self.fg.connect(self.sample_and_hold, self.nco)
+
+ if logging:
+ self.fg.connect(self.diff, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat"))
+ self.fg.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat"))
+ self.fg.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat"))
+ if use_dpll:
+ self.fg.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat"))
+
+ self.fg.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-sigmix_c.dat"))
+ self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_sync_ml-sampler_c.dat"))
+ self.fg.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat"))
+ self.fg.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-nco_c.dat"))
+ self.fg.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
+
+ gr.hier_block.__init__(self, fg, self.input, self.sampler)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py
new file mode 100644
index 0000000000..56425868f9
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+#
+
+import math
+from numpy import fft
+from gnuradio import gr
+
+class ofdm_sync_pn(gr.hier_block):
+ def __init__(self, fg, fft_length, cp_length, logging=False):
+ ''' OFDM synchronization using PN Correlation:
+ T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
+ Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
+ no. 12, 1997.
+ '''
+
+ self.fg = fg
+
+ # FIXME: when converting to hier_block2's, the output signature
+ # should be the output of the divider (the normalized peaks) and
+ # the angle value out of the sample and hold block
+
+ self.input = gr.add_const_cc(0)
+
+ symbol_length = fft_length + cp_length
+
+ # PN Sync
+
+ # Create a delay line
+ self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)
+
+ # Correlation from ML Sync
+ self.conjg = gr.conjugate_cc();
+ self.corr = gr.multiply_cc();
+
+ # Create a moving sum filter for the corr output
+ if 1:
+ moving_sum_taps = [1.0 for i in range(fft_length//2)]
+ self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
+ else:
+ moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
+ self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)
+
+ # Create a moving sum filter for the input
+ self.inputmag2 = gr.complex_to_mag_squared()
+ movingsum2_taps = [1.0 for i in range(fft_length//2)]
+
+ if 1:
+ self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
+ else:
+ self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)
+
+ self.square = gr.multiply_ff()
+ self.normalize = gr.divide_ff()
+
+ # Get magnitude (peaks) and angle (phase/freq error)
+ self.c2mag = gr.complex_to_mag_squared()
+ self.angle = gr.complex_to_arg()
+
+ self.sample_and_hold = gr.sample_and_hold_ff()
+
+ # Mix the signal with an NCO controlled by the sync loop
+ nco_sensitivity = -2.0/fft_length
+ self.nco = gr.frequency_modulator_fc(nco_sensitivity)
+ self.sigmix = gr.multiply_cc()
+
+ #ML measurements input to sampler block and detect
+ self.sub1 = gr.add_const_ff(-1)
+ self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005)
+ self.regen = gr.regenerate_bb(symbol_length)
+
+ self.sampler = gr.ofdm_sampler(fft_length,symbol_length)
+
+ self.fg.connect(self.input, self.delay)
+ self.fg.connect(self.input, (self.corr,0))
+ self.fg.connect(self.delay, self.conjg)
+ self.fg.connect(self.conjg, (self.corr,1))
+ self.fg.connect(self.corr, self.moving_sum_filter)
+ self.fg.connect(self.moving_sum_filter, self.c2mag)
+ self.fg.connect(self.moving_sum_filter, self.angle)
+ self.fg.connect(self.angle, (self.sample_and_hold,0))
+ self.fg.connect(self.sample_and_hold, self.nco)
+
+ self.fg.connect(self.input, (self.sigmix,0))
+ self.fg.connect(self.nco, (self.sigmix,1))
+ self.fg.connect(self.sigmix, (self.sampler,0))
+
+ self.fg.connect(self.input, self.inputmag2, self.inputmovingsum)
+ self.fg.connect(self.inputmovingsum, (self.square,0))
+ self.fg.connect(self.inputmovingsum, (self.square,1))
+ self.fg.connect(self.square, (self.normalize,1))
+ self.fg.connect(self.c2mag, (self.normalize,0))
+
+ # Create a moving sum filter for the corr output
+ matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
+ self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
+ self.fg.connect(self.normalize, self.matched_filter)
+
+ self.fg.connect(self.matched_filter, self.sub1, self.pk_detect)
+ self.fg.connect(self.pk_detect, self.regen)
+ self.fg.connect(self.regen, (self.sampler,1))
+ self.fg.connect(self.pk_detect, (self.sample_and_hold,1))
+
+
+ if logging:
+ self.fg.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
+ self.fg.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
+ self.fg.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
+ self.fg.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
+ self.fg.connect(self.regen, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-regen_b.dat"))
+ self.fg.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-sigmix_c.dat"))
+ self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_sync_pn-sampler_c.dat"))
+ self.fg.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
+ self.fg.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-nco_c.dat"))
+ self.fg.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
+
+ gr.hier_block.__init__(self, fg, self.input, self.sampler)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py
new file mode 100644
index 0000000000..e3774e3410
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+#
+
+import math
+from numpy import fft
+from gnuradio import gr
+
+class ofdm_sync_pnac(gr.hier_block):
+ def __init__(self, fg, fft_length, cp_length, ks):
+ self.fg = fg
+
+ # FIXME: when converting to hier_block2's, the output signature
+ # should be the output of the divider (the normalized peaks) and
+ # the angle value out of the sample and hold block
+
+ self.input = gr.add_const_cc(0)
+
+ symbol_length = fft_length + cp_length
+
+ # PN Sync
+
+ # autocorrelate with the known symbol
+ ks = ks[0:fft_length//2]
+ ks.reverse()
+ self.crosscorr_filter = gr.fir_filter_ccc(1, ks)
+ self.fg.connect(self.crosscorr_filter, gr.file_sink(gr.sizeof_gr_complex, "crosscorr.dat"))
+
+ # Create a delay line
+ self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)
+
+ # Correlation from ML Sync
+ self.conjg = gr.conjugate_cc();
+ self.corr = gr.multiply_cc();
+
+ # Create a moving sum filter for the corr output
+ moving_sum_taps = [1.0 for i in range(fft_length//2)]
+ self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
+
+ # Create a moving sum filter for the input
+ self.inputmag2 = gr.complex_to_mag_squared()
+ movingsum2_taps = [1.0 for i in range(fft_length/2)]
+ self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
+ self.square = gr.multiply_ff()
+ self.normalize = gr.divide_ff()
+
+ # Get magnitude (peaks) and angle (phase/freq error)
+ self.c2mag = gr.complex_to_mag_squared()
+ self.angle = gr.complex_to_arg()
+
+ self.sample_and_hold = gr.sample_and_hold_ff()
+
+ # Mix the signal with an NCO controlled by the sync loop
+ nco_sensitivity = -1.0/fft_length
+ self.nco = gr.frequency_modulator_fc(nco_sensitivity)
+ self.sigmix = gr.multiply_cc()
+
+ #ML measurements input to sampler block and detect
+ self.sub1 = gr.add_const_ff(-1)
+ self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005)
+
+ self.sampler = gr.ofdm_sampler(fft_length,symbol_length)
+
+ self.fg.connect(self.input, self.crosscorr_filter)
+ self.fg.connect(self.crosscorr_filter, self.delay)
+ self.fg.connect(self.crosscorr_filter, (self.corr,0))
+ self.fg.connect(self.delay, self.conjg)
+ self.fg.connect(self.conjg, (self.corr,1))
+ self.fg.connect(self.corr, self.moving_sum_filter)
+ self.fg.connect(self.moving_sum_filter, self.c2mag)
+ self.fg.connect(self.moving_sum_filter, self.angle)
+ self.fg.connect(self.angle, (self.sample_and_hold,0))
+ self.fg.connect(self.sample_and_hold, self.nco)
+
+ self.fg.connect(self.input, (self.sigmix,0))
+ self.fg.connect(self.nco, (self.sigmix,1))
+ self.fg.connect(self.sigmix, (self.sampler,0))
+
+ self.fg.connect(self.input, self.inputmag2, self.inputmovingsum)
+ self.fg.connect(self.inputmovingsum, (self.square,0))
+ self.fg.connect(self.inputmovingsum, (self.square,1))
+ self.fg.connect(self.square, (self.normalize,1))
+ self.fg.connect(self.c2mag, (self.normalize,0))
+ self.fg.connect(self.normalize, self.sub1, self.pk_detect)
+
+ self.fg.connect(self.pk_detect, (self.sampler,1))
+ self.fg.connect(self.pk_detect, (self.sample_and_hold,1))
+
+
+ if 1:
+ self.fg.connect(self.normalize, gr.file_sink(gr.sizeof_float,
+ "ofdm_sync_pnac-theta_f.dat"))
+ self.fg.connect(self.angle, gr.file_sink(gr.sizeof_float,
+ "ofdm_sync_pnac-epsilon_f.dat"))
+ self.fg.connect(self.pk_detect, gr.file_sink(gr.sizeof_char,
+ "ofdm_sync_pnac-peaks_b.dat"))
+ self.fg.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex,
+ "ofdm_sync_pnac-sigmix_c.dat"))
+ self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length,
+ "ofdm_sync_pnac-sampler_c.dat"))
+ self.fg.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float,
+ "ofdm_sync_pnac-sample_and_hold_f.dat"))
+ self.fg.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex,
+ "ofdm_sync_pnac-nco_c.dat"))
+ self.fg.connect(self.input, gr.file_sink(gr.sizeof_gr_complex,
+ "ofdm_sync_pnac-input_c.dat"))
+
+ gr.hier_block.__init__(self, fg, self.input, self.sampler)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/pkt.py b/gnuradio-core/src/python/gnuradio/blks2impl/pkt.py
index 70eab5bfb9..908437ef2b 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/pkt.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/pkt.py
@@ -1,5 +1,5 @@
#
-# Copyright 2005,2006,2007 Free Software Foundation, Inc.
+# Copyright 2005, 2006, 2007 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -34,29 +34,34 @@ class mod_pkts(gr.hier_block2):
Send packets by calling send_pkt
"""
- def __init__(self, modulator, access_code=None, msgq_limit=2, pad_for_usrp=True):
+ def __init__(self, modulator, access_code=None, msgq_limit=2, pad_for_usrp=True, use_whitener_offset=False):
"""
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_block)
+ @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
+
+ See gmsk_mod for remaining parameters
"""
- gr.hier_block2.__init__(self, "mod_pkts",
- gr.io_signature(0,0,0), # Input signature
- gr.io_signature(1,1,gr.sizeof_gr_complex)) # Output signature
+ gr.hier_block2.__init__(self, "mod_pkts",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # 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):
@@ -65,7 +70,7 @@ class mod_pkts(gr.hier_block2):
# accepts messages from the outside world
self._pkt_input = gr.message_source(gr.sizeof_char, msgq_limit)
- self.connect(self._pkt_input, self._modulator, self)
+ self.connect(self._pkt_input, self._modulator, self)
def send_pkt(self, payload='', eof=False):
"""
@@ -82,9 +87,13 @@ class mod_pkts(gr.hier_block2):
self._modulator.samples_per_symbol(),
self._modulator.bits_per_symbol(),
self._access_code,
- self._pad_for_usrp)
+ 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)
@@ -104,7 +113,7 @@ class demod_pkts(gr.hier_block2):
The input is the complex modulated signal at baseband.
Demodulated packets are sent to the handler.
- @param demodulator: instance of demodulator class (gr_block or hier_block)
+ @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
@@ -114,10 +123,10 @@ class demod_pkts(gr.hier_block2):
@type threshold: int
"""
- gr.hier_block2.__init__(self, "demod_pkts",
- gr.io_signature(1,1,gr.sizeof_gr_complex), # Input signature
- gr.io_signature(0,0,0)) # Output signature
-
+ gr.hier_block2.__init__(self, "demod_pkts",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # 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
@@ -129,11 +138,11 @@ class demod_pkts(gr.hier_block2):
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._correlator = gr.correlate_access_code_bb(access_code, threshold)
- self._framer_sink = gr.framer_sink_1(self._rcvd_pktq)
- self.connect(self, self._demodulator, self._correlator, self._framer_sink)
-
+ self.framer_sink = gr.framer_sink_1(self._rcvd_pktq)
+ self.connect(self, self._demodulator, self.correlator, self.framer_sink)
+
self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
@@ -150,6 +159,6 @@ class _queue_watcher_thread(_threading.Thread):
def run(self):
while self.keep_running:
msg = self.rcvd_pktq.delete_head()
- ok, payload = packet_utils.unmake_packet(msg.to_string())
+ ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1()))
if self.callback:
self.callback(ok, payload)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/psk.py b/gnuradio-core/src/python/gnuradio/blks2impl/psk.py
index 69899ebe3e..acedf3b69a 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/psk.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/psk.py
@@ -38,14 +38,14 @@ def make_gray_constellation(m):
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
@@ -53,6 +53,12 @@ constellation = {
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
# -----------------------
@@ -62,7 +68,7 @@ binary_to_gray = {
4 : [0,1,3,2],
8 : [0, 1, 3, 2, 7, 6, 4, 5]
}
-
+
# gray to binary
gray_to_binary = {
2 : range(2),
@@ -79,7 +85,7 @@ binary_to_ungray = {
4 : range(4),
8 : range(8)
}
-
+
# identity mapping
ungray_to_binary = {
2 : range(2),
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
new file mode 100644
index 0000000000..22b1e1dabb
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
@@ -0,0 +1,113 @@
+#
+# 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
+import math
+
+# These constellations are generated for Gray coding when symbos [1, ..., m] are used
+# Mapping to Gray coding is therefore unnecessary
+
+def make_constellation(m):
+ # number of bits/symbol (log2(M))
+ k = int(math.log10(m) / math.log10(2.0))
+
+ coeff = 1
+ const_map = []
+ for i in range(m):
+ a = (i&(0x01 << k-1)) >> k-1
+ b = (i&(0x01 << k-2)) >> k-2
+ bits_i = [((i&(0x01 << k-j-1)) >> k-j-1) for j in range(2, k, 2)]
+ bits_q = [((i&(0x01 << k-j-1)) >> k-j-1) for j in range(3, k, 2)]
+
+ ss = 0
+ ll = len(bits_i)
+ for ii in range(ll):
+ rr = 0
+ for jj in range(ll-ii):
+ rr = abs(bits_i[jj] - rr)
+ ss += rr*pow(2.0, ii+1)
+ re = (2*a-1)*(ss+1)
+
+ ss = 0
+ ll = len(bits_q)
+ for ii in range(ll):
+ rr = 0
+ for jj in range(ll-ii):
+ rr = abs(bits_q[jj] - rr)
+ ss += rr*pow(2.0, ii+1)
+ im = (2*b-1)*(ss+1)
+
+ a = max(re, im)
+ if a > coeff:
+ coeff = a
+ const_map.append(complex(re, im))
+
+ norm_map = [complex(i.real/coeff, i.imag/coeff) for i in const_map]
+ return norm_map
+
+# Common definition of constellations for Tx and Rx
+constellation = {
+ 4 : make_constellation(4), # QAM4 (QPSK)
+ 8 : make_constellation(8), # QAM8
+ 16: make_constellation(16), # QAM16
+ 64: make_constellation(64), # QAM64
+ 256: make_constellation(256) # QAM256
+ }
+
+# -----------------------
+# Do Gray code
+# -----------------------
+# binary to gray coding
+binary_to_gray = {
+ 4 : range(4),
+ 8 : range(8),
+ 16: range(16),
+ 64: range(64),
+ 256: range(256)
+ }
+
+# gray to binary
+gray_to_binary = {
+ 4 : range(4),
+ 8 : range(8),
+ 16: range(16),
+ 64: range(64),
+ 256: range(256)
+ }
+
+# -----------------------
+# Don't Gray code
+# -----------------------
+# identity mapping
+binary_to_ungray = {
+ 4 : range(4),
+ 8 : range(8),
+ 16: range(16),
+ 64: range(64)
+ }
+
+# identity mapping
+ungray_to_binary = {
+ 4 : range(4),
+ 8 : range(8),
+ 16: range(16),
+ 64: range(64)
+ }
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam16.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam16.py
new file mode 100644
index 0000000000..0bdb9c6fb8
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam16.py
@@ -0,0 +1,208 @@
+#
+# 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.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+QAM16 modulation and demodulation.
+"""
+
+from gnuradio import gr, gru, modulation_utils
+from math import pi, sqrt
+import qam
+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_costas_alpha = None
+_def_gain_mu = 0.03
+_def_mu = 0.05
+_def_omega_relative_limit = 0.005
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM16 modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam16_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, "qam16_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)
+
+ ntaps = 11 * 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(qam.binary_to_gray[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ rot = 1.0
+ print "constellation with %d arity" % arity
+ rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+ self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
+
+ # 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
+ 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 4
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ 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, "bytes2chunks.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
+
+ def add_options(parser):
+ """
+ Adds QAM 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(qam16_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM16 demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam16_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):
+
+ gr.hier_block2.__init__(self, "qam16_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+ # do this
+ pass
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 4
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+#
+# Add these to the mod/demod registry
+#
+# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
+#modulation_utils.add_type_1_mod('qam16', qam16_mod)
+#modulation_utils.add_type_1_demod('qam16', qam16_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam256.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam256.py
new file mode 100644
index 0000000000..fc455f17c1
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam256.py
@@ -0,0 +1,209 @@
+#
+# 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.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+QAM256 modulation and demodulation.
+"""
+
+from gnuradio import gr, gru, modulation_utils
+from math import pi, sqrt
+import qam
+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_costas_alpha = None
+_def_gain_mu = 0.03
+_def_mu = 0.05
+_def_omega_relative_limit = 0.005
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM256 modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam256_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, "qam256_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)
+
+ ntaps = 11 * 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(qam.binary_to_gray[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ rot = 1.0
+ print "constellation with %d arity" % arity
+ rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+ self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
+
+ # 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
+ 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 8
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ 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, "bytes2chunks.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
+
+ def add_options(parser):
+ """
+ Adds QAM 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(qam256_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM256 demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam256_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):
+
+ gr.hier_block2.__init__(self, "qam256_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ # do this
+ pass
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 8
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+#
+# Add these to the mod/demod registry
+#
+# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
+#modulation_utils.add_type_1_mod('qam256', qam256_mod)
+#modulation_utils.add_type_1_demod('qam256', qam256_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam64.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam64.py
new file mode 100644
index 0000000000..5509f37458
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam64.py
@@ -0,0 +1,208 @@
+#
+# 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.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+differential QPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru, modulation_utils
+from math import pi, sqrt
+import qam
+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_costas_alpha = None
+_def_gain_mu = 0.03
+_def_mu = 0.05
+_def_omega_relative_limit = 0.005
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM64 modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam64_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, "qam64_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)
+
+ ntaps = 11 * 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(qam.binary_to_gray[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ rot = 1.0
+ print "constellation with %d arity" % arity
+ rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+ self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
+
+ # 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
+ 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 6
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+ def _print_verbage(self):
+ 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, "bytes2chunks.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
+
+ def add_options(parser):
+ """
+ Adds QAM 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(qam64_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM16 demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam64_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):
+
+ gr.hier_block2.__init__(self, "qam64_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ # do this
+ pass
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 6
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
+
+#
+# Add these to the mod/demod registry
+#
+# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
+#modulation_utils.add_type_1_mod('qam64', qam64_mod)
+#modulation_utils.add_type_1_demod('qam16', qam16_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam8.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam8.py
new file mode 100644
index 0000000000..977dec930a
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam8.py
@@ -0,0 +1,209 @@
+#
+# 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.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+"""
+QAM8 modulation and demodulation.
+"""
+
+from gnuradio import gr, gru, modulation_utils
+from math import pi, sqrt
+import qam
+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_costas_alpha = None
+_def_gain_mu = 0.03
+_def_mu = 0.05
+_def_omega_relative_limit = 0.005
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM8 modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam8_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, "qam8_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)
+
+ ntaps = 11 * 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(qam.binary_to_gray[arity])
+ else:
+ self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
+
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ rot = 1.0
+ print "constellation with %d arity" % arity
+ rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+ self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
+
+ # 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
+ 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 "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, "bytes2chunks.dat"))
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
+
+ def add_options(parser):
+ """
+ Adds QAM 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(qam8_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM8 demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam8_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):
+
+ gr.hier_block2.__init__(self, "qam8_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_char)) # Output signature
+
+ # do this
+ pass
+
+ 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
+
+#
+# Add these to the mod/demod registry
+#
+# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
+modulation_utils.add_type_1_mod('qam8', qam8_mod)
+#modulation_utils.add_type_1_demod('qam8', qam8_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl2/rational_resampler.py b/gnuradio-core/src/python/gnuradio/blks2impl/rational_resampler.py
index cbd59b08a2..b7de0de7cf 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl2/rational_resampler.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/rational_resampler.py
@@ -96,9 +96,9 @@ class _rational_resampler_base(gr.hier_block2):
taps = design_filter(interpolation, decimation, fractional_bw)
resampler = resampler_base(interpolation, decimation, taps)
- gr.hier_block2.__init__(self, resampler.name(),
+ gr.hier_block2.__init__(self, "rational_resampler",
gr.io_signature(1, 1, resampler.input_signature().sizeof_stream_item(0)),
- gr.io_signature(1, 1, resampler.output_signature().sizeof_stream_item(1)))
+ gr.io_signature(1, 1, resampler.output_signature().sizeof_stream_item(0)))
self.connect(self, resampler, self)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/standard_squelch.py b/gnuradio-core/src/python/gnuradio/blks2impl/standard_squelch.py
new file mode 100644
index 0000000000..c5fdc01dbc
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/standard_squelch.py
@@ -0,0 +1,76 @@
+#
+# Copyright 2005,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.
+#
+
+import math
+from gnuradio import gr, optfir
+
+class standard_squelch(gr.hier_block2):
+ def __init__(self, audio_rate):
+ gr.hier_block2.__init__(self, "standard_squelch",
+ gr.io_signature(1, 1, gr.sizeof_float), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
+
+ self.input_node = gr.add_const_ff(0) # FIXME kludge
+
+ self.low_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.9524,-0.9615))
+ self.low_square = gr.multiply_ff()
+ self.low_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate)) # 100ms time constant
+
+ self.hi_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.3597,-0.9615))
+ self.hi_square = gr.multiply_ff()
+ self.hi_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))
+
+ self.sub = gr.sub_ff();
+ self.add = gr.add_ff();
+ self.gate = gr.threshold_ff(0.3,0.43,0)
+ self.squelch_lpf = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))
+
+ self.div = gr.divide_ff()
+ self.squelch_mult = gr.multiply_ff()
+
+ self.connect (self, self.input_node)
+ self.connect (self.input_node, (self.squelch_mult, 0))
+
+ self.connect (self.input_node,self.low_iir)
+ self.connect (self.low_iir,(self.low_square,0))
+ self.connect (self.low_iir,(self.low_square,1))
+ self.connect (self.low_square,self.low_smooth,(self.sub,0))
+ self.connect (self.low_smooth, (self.add,0))
+
+ self.connect (self.input_node,self.hi_iir)
+ self.connect (self.hi_iir,(self.hi_square,0))
+ self.connect (self.hi_iir,(self.hi_square,1))
+ self.connect (self.hi_square,self.hi_smooth,(self.sub,1))
+ self.connect (self.hi_smooth, (self.add,1))
+
+ self.connect (self.sub, (self.div, 0))
+ self.connect (self.add, (self.div, 1))
+ self.connect (self.div, self.gate, self.squelch_lpf, (self.squelch_mult,1))
+ self.connect (self.squelch_mult, self)
+
+ def set_threshold(self, threshold):
+ self.gate.set_hi(threshold)
+
+ def threshold(self):
+ return self.gate.hi()
+
+ def squelch_range(self):
+ return (0.0, 1.0, 1.0/100)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv.py b/gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv.py
new file mode 100644
index 0000000000..3bdb22cce9
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv.py
@@ -0,0 +1,69 @@
+#
+# Copyright 2005,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 gnuradio import gr
+from gnuradio.blks2impl.fm_emph import fm_deemph
+import math
+
+class wfm_rcv(gr.hier_block2):
+ def __init__ (self, quad_rate, audio_decimation):
+ """
+ Hierarchical block for demodulating a broadcast FM signal.
+
+ The input is the downconverted complex baseband signal (gr_complex).
+ The output is the demodulated audio (float).
+
+ @param quad_rate: input sample rate of complex baseband input.
+ @type quad_rate: float
+ @param audio_decimation: how much to decimate quad_rate to get to audio.
+ @type audio_decimation: integer
+ """
+ gr.hier_block2.__init__(self, "wfm_rcv",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
+
+ volume = 20.
+
+ max_dev = 75e3
+ fm_demod_gain = quad_rate/(2*math.pi*max_dev)
+ audio_rate = quad_rate / audio_decimation
+
+
+ # We assign to self so that outsiders can grab the demodulator
+ # if they need to. E.g., to plot its output.
+ #
+ # input: complex; output: float
+ self.fm_demod = gr.quadrature_demod_cf (fm_demod_gain)
+
+ # input: float; output: float
+ self.deemph = fm_deemph (audio_rate)
+
+ # compute FIR filter taps for audio filter
+ width_of_transition_band = audio_rate / 32
+ audio_coeffs = gr.firdes.low_pass (1.0, # gain
+ quad_rate, # sampling rate
+ audio_rate/2 - width_of_transition_band,
+ width_of_transition_band,
+ gr.firdes.WIN_HAMMING)
+ # input: float; output: float
+ self.audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)
+
+ self.connect (self, self.fm_demod, self.audio_filter, self.deemph, self)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv_pll.py b/gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv_pll.py
new file mode 100644
index 0000000000..d7a930754b
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/wfm_rcv_pll.py
@@ -0,0 +1,192 @@
+#
+# 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 gnuradio import gr
+from gnuradio.blks2impl.fm_emph import fm_deemph
+import math
+
+class wfm_rcv_pll(gr.hier_block2):
+ def __init__ (self, demod_rate, audio_decimation):
+ """
+ Hierarchical block for demodulating a broadcast FM signal.
+
+ The input is the downconverted complex baseband signal (gr_complex).
+ The output is two streams of the demodulated audio (float) 0=Left, 1=Right.
+
+ @param demod_rate: input sample rate of complex baseband input.
+ @type demod_rate: float
+ @param audio_decimation: how much to decimate demod_rate to get to audio.
+ @type audio_decimation: integer
+ """
+ gr.hier_block2.__init__(self, "wfm_rcv_pll",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 2, gr.sizeof_float)) # Output signature
+ bandwidth = 200e3
+ audio_rate = demod_rate / audio_decimation
+
+
+ # We assign to self so that outsiders can grab the demodulator
+ # if they need to. E.g., to plot its output.
+ #
+ # input: complex; output: float
+ alpha = 0.25*bandwidth * math.pi / demod_rate
+ beta = alpha * alpha / 4.0
+ max_freq = 2.0*math.pi*100e3/demod_rate
+
+ self.fm_demod = gr.pll_freqdet_cf (alpha,beta,max_freq,-max_freq)
+
+ # input: float; output: float
+ self.deemph_Left = fm_deemph (audio_rate)
+ self.deemph_Right = fm_deemph (audio_rate)
+
+ # compute FIR filter taps for audio filter
+ width_of_transition_band = audio_rate / 32
+ audio_coeffs = gr.firdes.low_pass (1.0 , # gain
+ demod_rate, # sampling rate
+ 15000 ,
+ width_of_transition_band,
+ gr.firdes.WIN_HAMMING)
+ # input: float; output: float
+ self.audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)
+ if 1:
+ # Pick off the stereo carrier/2 with this filter. It attenuated 10 dB so apply 10 dB gain
+ # We pick off the negative frequency half because we want to base band by it!
+ ## NOTE THIS WAS HACKED TO OFFSET INSERTION LOSS DUE TO DEEMPHASIS
+
+ stereo_carrier_filter_coeffs = gr.firdes.complex_band_pass(10.0,
+ demod_rate,
+ -19020,
+ -18980,
+ width_of_transition_band,
+ gr.firdes.WIN_HAMMING)
+
+ #print "len stereo carrier filter = ",len(stereo_carrier_filter_coeffs)
+ #print "stereo carrier filter ", stereo_carrier_filter_coeffs
+ #print "width of transition band = ",width_of_transition_band, " audio rate = ", audio_rate
+
+ # Pick off the double side band suppressed carrier Left-Right audio. It is attenuated 10 dB so apply 10 dB gain
+
+ stereo_dsbsc_filter_coeffs = gr.firdes.complex_band_pass(20.0,
+ demod_rate,
+ 38000-15000/2,
+ 38000+15000/2,
+ width_of_transition_band,
+ gr.firdes.WIN_HAMMING)
+ #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs)
+ #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs
+ # construct overlap add filter system from coefficients for stereo carrier
+
+ self.stereo_carrier_filter = gr.fir_filter_fcc(audio_decimation, stereo_carrier_filter_coeffs)
+
+ # carrier is twice the picked off carrier so arrange to do a commplex multiply
+
+ self.stereo_carrier_generator = gr.multiply_cc();
+
+ # Pick off the rds signal
+
+ stereo_rds_filter_coeffs = gr.firdes.complex_band_pass(30.0,
+ demod_rate,
+ 57000 - 1500,
+ 57000 + 1500,
+ width_of_transition_band,
+ gr.firdes.WIN_HAMMING)
+ #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs)
+ #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs
+ # construct overlap add filter system from coefficients for stereo carrier
+
+ self.stereo_carrier_filter = gr.fir_filter_fcc(audio_decimation, stereo_carrier_filter_coeffs)
+ self.rds_signal_filter = gr.fir_filter_fcc(audio_decimation, stereo_rds_filter_coeffs)
+
+
+
+
+
+
+ self.rds_carrier_generator = gr.multiply_cc();
+ self.rds_signal_generator = gr.multiply_cc();
+ self_rds_signal_processor = gr.null_sink(gr.sizeof_gr_complex);
+
+
+
+ alpha = 5 * 0.25 * math.pi / (audio_rate)
+ beta = alpha * alpha / 4.0
+ max_freq = -2.0*math.pi*18990/audio_rate;
+ min_freq = -2.0*math.pi*19010/audio_rate;
+
+ self.stereo_carrier_pll_recovery = gr.pll_refout_cc(alpha,beta,max_freq,min_freq);
+ #self.stereo_carrier_pll_recovery.squelch_enable(False) #pll_refout does not have squelch yet, so disabled for now
+
+
+ # set up mixer (multiplier) to get the L-R signal at baseband
+
+ self.stereo_basebander = gr.multiply_cc();
+
+ # pick off the real component of the basebanded L-R signal. The imaginary SHOULD be zero
+
+ self.LmR_real = gr.complex_to_real();
+ self.Make_Left = gr.add_ff();
+ self.Make_Right = gr.sub_ff();
+
+ self.stereo_dsbsc_filter = gr.fir_filter_fcc(audio_decimation, stereo_dsbsc_filter_coeffs)
+
+
+ if 1:
+
+ # send the real signal to complex filter to pick off the carrier and then to one side of a multiplier
+ self.connect (self, self.fm_demod,self.stereo_carrier_filter,self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator,0))
+ # send the already filtered carrier to the otherside of the carrier
+ self.connect (self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator,1))
+ # the resulting signal from this multiplier is the carrier with correct phase but at -38000 Hz.
+
+ # send the new carrier to one side of the mixer (multiplier)
+ self.connect (self.stereo_carrier_generator, (self.stereo_basebander,0))
+ # send the demphasized audio to the DSBSC pick off filter, the complex
+ # DSBSC signal at +38000 Hz is sent to the other side of the mixer/multiplier
+ self.connect (self.fm_demod,self.stereo_dsbsc_filter, (self.stereo_basebander,1))
+ # the result is BASEBANDED DSBSC with phase zero!
+
+ # Pick off the real part since the imaginary is theoretically zero and then to one side of a summer
+ self.connect (self.stereo_basebander, self.LmR_real, (self.Make_Left,0))
+ #take the same real part of the DSBSC baseband signal and send it to negative side of a subtracter
+ self.connect (self.LmR_real,(self.Make_Right,1))
+
+ # Make rds carrier by taking the squared pilot tone and multiplying by pilot tone
+ self.connect (self.stereo_basebander,(self.rds_carrier_generator,0))
+ self.connect (self.stereo_carrier_pll_recovery,(self.rds_carrier_generator,1))
+ # take signal, filter off rds, send into mixer 0 channel
+ self.connect (self.fm_demod,self.rds_signal_filter,(self.rds_signal_generator,0))
+ # take rds_carrier_generator output and send into mixer 1 channel
+ self.connect (self.rds_carrier_generator,(self.rds_signal_generator,1))
+ # send basebanded rds signal and send into "processor" which for now is a null sink
+ self.connect (self.rds_signal_generator,self_rds_signal_processor)
+
+
+ if 1:
+ # pick off the audio, L+R that is what we used to have and send it to the summer
+ self.connect(self.fm_demod, self.audio_filter, (self.Make_Left, 1))
+ # take the picked off L+R audio and send it to the PLUS side of the subtractor
+ self.connect(self.audio_filter,(self.Make_Right, 0))
+ # The result of Make_Left gets (L+R) + (L-R) and results in 2*L
+ # The result of Make_Right gets (L+R) - (L-R) and results in 2*R
+ self.connect(self.Make_Left , self.deemph_Left, (self, 0))
+ self.connect(self.Make_Right, self.deemph_Right, (self, 1))
+ else:
+ self.connect (self.fm_demod, self.audio_filter, self)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/wfm_tx.py b/gnuradio-core/src/python/gnuradio/blks2impl/wfm_tx.py
new file mode 100644
index 0000000000..c7c831ca16
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/wfm_tx.py
@@ -0,0 +1,79 @@
+#
+# Copyright 2005,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.
+#
+
+import math
+from gnuradio import gr, optfir
+from gnuradio.blks2impl.fm_emph import fm_preemph
+
+class wfm_tx(gr.hier_block2):
+ def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=75e3):
+ """
+ Wide Band FM Transmitter.
+
+ Takes a single float input stream of audio samples in the range [-1,+1]
+ and produces a single FM modulated complex baseband output.
+
+ @param audio_rate: sample rate of audio stream, >= 16k
+ @type audio_rate: integer
+ @param quad_rate: sample rate of output stream
+ @type quad_rate: integer
+ @param tau: preemphasis time constant (default 75e-6)
+ @type tau: float
+ @param max_dev: maximum deviation in Hz (default 75e3)
+ @type max_dev: float
+
+ quad_rate must be an integer multiple of audio_rate.
+ """
+ gr.hier_block2.__init__(self, "wfm_tx",
+ gr.io_signature(1, 1, gr.sizeof_float), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ # FIXME audio_rate and quad_rate ought to be exact rationals
+ audio_rate = int(audio_rate)
+ quad_rate = int(quad_rate)
+
+ if quad_rate % audio_rate != 0:
+ raise ValueError, "quad_rate is not an integer multiple of audio_rate"
+
+
+ do_interp = audio_rate != quad_rate
+
+ if do_interp:
+ interp_factor = quad_rate / audio_rate
+ interp_taps = optfir.low_pass (interp_factor, # gain
+ quad_rate, # Fs
+ 16000, # passband cutoff
+ 18000, # stopband cutoff
+ 0.1, # passband ripple dB
+ 40) # stopband atten dB
+
+ print "len(interp_taps) =", len(interp_taps)
+ self.interpolator = gr.interp_fir_filter_fff (interp_factor, interp_taps)
+
+ self.preemph = fm_preemph (quad_rate, tau=tau)
+
+ k = 2 * math.pi * max_dev / quad_rate
+ self.modulator = gr.frequency_modulator_fc (k)
+
+ if do_interp:
+ self.connect (self, self.interpolator, self.preemph, self.modulator, self)
+ else:
+ self.connect(self, self.preemph, self.modulator, self)
diff --git a/gnuradio-core/src/python/gnuradio/gr/hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/hier_block2.py
index bc6402b872..1c096b709e 100644
--- a/gnuradio-core/src/python/gnuradio/gr/hier_block2.py
+++ b/gnuradio-core/src/python/gnuradio/gr/hier_block2.py
@@ -37,13 +37,17 @@ class hier_block2(object):
return getattr(self._hb, name)
def connect(self, *points):
- '''connect requires two or more arguments that can be coerced to endpoints.
+ '''connect requires one or more arguments that can be coerced to endpoints.
If more than two arguments are provided, they are connected together successively.
'''
- if len (points) < 2:
- raise ValueError, ("connect requires at least two endpoints; %d provided." % (len (points),))
- for i in range (1, len (points)):
- self._connect(points[i-1], points[i])
+ if len (points) < 1:
+ raise ValueError, ("connect requires at least one endpoint; %d provided." % (len (points),))
+ else:
+ if len(points) == 1:
+ self._hb.connect(points[0].basic_block())
+ else:
+ for i in range (1, len (points)):
+ self._connect(points[i-1], points[i])
def _connect(self, src, dst):
(src_block, src_port) = self._coerce_endpoint(src)
@@ -61,13 +65,17 @@ class hier_block2(object):
raise ValueError("unable to coerce endpoint")
def disconnect(self, *points):
- '''connect requires two or more arguments that can be coerced to endpoints.
+ '''connect requires one or more arguments that can be coerced to endpoints.
If more than two arguments are provided, they are disconnected successively.
'''
- if len (points) < 2:
+ if len (points) < 1:
raise ValueError, ("disconnect requires at least two endpoints; %d provided." % (len (points),))
- for i in range (1, len (points)):
- self._disconnect(points[i-1], points[i])
+ else:
+ if len (points) == 1:
+ self._hb.disconnect(points[0].basic_block())
+ else:
+ for i in range (1, len (points)):
+ self._disconnect(points[i-1], points[i])
def _disconnect(self, src, dst):
(src_block, src_port) = self._coerce_endpoint(src)
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py
index d07d4cb389..7249a2194f 100755
--- a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py
@@ -187,5 +187,58 @@ class test_hier_block2(gr_unittest.TestCase):
hblock.run()
self.assertEquals(data, dst.data())
+ def test_021_connect_single(self):
+ hblock = gr.top_block("test_block")
+ blk = gr.hier_block2("block",
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(0, 0, 0))
+ hblock.connect(blk)
+
+ def test_022_connect_single_with_ports(self):
+ hblock = gr.top_block("test_block")
+ blk = gr.hier_block2("block",
+ gr.io_signature(1, 1, 1),
+ gr.io_signature(1, 1, 1))
+ self.assertRaises(ValueError,
+ lambda: hblock.connect(blk))
+
+ def test_023_connect_single_twice(self):
+ hblock = gr.top_block("test_block")
+ blk = gr.hier_block2("block",
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(0, 0, 0))
+ hblock.connect(blk)
+ self.assertRaises(ValueError,
+ lambda: hblock.connect(blk))
+
+ def test_024_disconnect_single(self):
+ hblock = gr.top_block("test_block")
+ blk = gr.hier_block2("block",
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(0, 0, 0))
+ hblock.connect(blk)
+ hblock.disconnect(blk)
+
+ def test_025_disconnect_single_not_connected(self):
+ hblock = gr.top_block("test_block")
+ blk = gr.hier_block2("block",
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(0, 0, 0))
+ self.assertRaises(ValueError,
+ lambda: hblock.disconnect(blk))
+
+ def test_026_run_single(self):
+ expected_data = (1.0,)
+ tb = gr.top_block("top_block")
+ hb = gr.hier_block2("block",
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(0, 0, 0))
+ src = gr.vector_source_f(expected_data)
+ dst = gr.vector_sink_f()
+ hb.connect(src, dst)
+ tb.connect(hb)
+ tb.run()
+ self.assertEquals(expected_data, dst.data())
+
if __name__ == "__main__":
gr_unittest.main()
diff --git a/gnuradio-core/src/python/gnuradio/gr/top_block.py b/gnuradio-core/src/python/gnuradio/gr/top_block.py
index 9b709c01dd..8bd4052c9f 100644
--- a/gnuradio-core/src/python/gnuradio/gr/top_block.py
+++ b/gnuradio-core/src/python/gnuradio/gr/top_block.py
@@ -51,13 +51,17 @@ class top_block(object):
# in the original C++ class (gr_hier_block2), then they would all be inherited here
def connect(self, *points):
- '''connect requires two or more arguments that can be coerced to endpoints.
+ '''connect requires one or more arguments that can be coerced to endpoints.
If more than two arguments are provided, they are connected together successively.
'''
- if len (points) < 2:
- raise ValueError, ("connect requires at least two endpoints; %d provided." % (len (points),))
- for i in range (1, len (points)):
- self._connect(points[i-1], points[i])
+ if len (points) < 1:
+ raise ValueError, ("connect requires at least one endpoint; %d provided." % (len (points),))
+ else:
+ if len(points) == 1:
+ self._tb.connect(points[0].basic_block())
+ else:
+ for i in range (1, len (points)):
+ self._connect(points[i-1], points[i])
def _connect(self, src, dst):
(src_block, src_port) = self._coerce_endpoint(src)
@@ -75,13 +79,17 @@ class top_block(object):
raise ValueError("unable to coerce endpoint")
def disconnect(self, *points):
- '''connect requires two or more arguments that can be coerced to endpoints.
+ '''connect requires one or more arguments that can be coerced to endpoints.
If more than two arguments are provided, they are disconnected successively.
'''
- if len (points) < 2:
+ if len (points) < 1:
raise ValueError, ("disconnect requires at least two endpoints; %d provided." % (len (points),))
- for i in range (1, len (points)):
- self._disconnect(points[i-1], points[i])
+ else:
+ if len(points) == 1:
+ self._tb.disconnect(points[0].basic_block())
+ else:
+ for i in range (1, len (points)):
+ self._disconnect(points[i-1], points[i])
def _disconnect(self, src, dst):
(src_block, src_port) = self._coerce_endpoint(src)