summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--docs/doxygen/other/metadata.dox25
-rw-r--r--docs/doxygen/other/operating_fg.dox8
-rw-r--r--docs/doxygen/other/pmt.dox6
-rw-r--r--docs/exploring-gnuradio/exploring_gnuradio.dox14
-rw-r--r--gnuradio-runtime/include/gnuradio/types.h26
-rw-r--r--gnuradio-runtime/lib/buffer.cc2
-rw-r--r--gr-blocks/grc/blocks_file_source.xml12
-rw-r--r--gr-blocks/grc/blocks_tag_gate.xml2
-rw-r--r--gr-blocks/include/gnuradio/blocks/file_source.h5
-rw-r--r--gr-blocks/lib/file_source_impl.cc35
-rw-r--r--gr-blocks/lib/file_source_impl.h7
-rw-r--r--gr-blocks/python/blocks/qa_file_source_sink.py62
-rw-r--r--gr-digital/examples/CMakeLists.txt2
-rw-r--r--gr-digital/examples/demod/symbol_sync_test_complex.grc2876
-rw-r--r--gr-digital/examples/demod/symbol_sync_test_float.grc2703
-rw-r--r--gr-digital/grc/digital_block_tree.xml3
-rw-r--r--gr-digital/grc/digital_symbol_sync_xx.xml207
-rw-r--r--gr-digital/include/gnuradio/digital/CMakeLists.txt6
-rw-r--r--gr-digital/include/gnuradio/digital/interpolating_resampler_type.h40
-rw-r--r--gr-digital/include/gnuradio/digital/symbol_sync_cc.h316
-rw-r--r--gr-digital/include/gnuradio/digital/symbol_sync_ff.h316
-rw-r--r--gr-digital/include/gnuradio/digital/timing_error_detector_type.h46
-rw-r--r--gr-digital/lib/CMakeLists.txt7
-rw-r--r--gr-digital/lib/clock_tracking_loop.cc333
-rw-r--r--gr-digital/lib/clock_tracking_loop.h781
-rw-r--r--gr-digital/lib/interpolating_resampler.cc782
-rw-r--r--gr-digital/lib/interpolating_resampler.h599
-rw-r--r--gr-digital/lib/symbol_sync_cc_impl.cc654
-rw-r--r--gr-digital/lib/symbol_sync_cc_impl.h156
-rw-r--r--gr-digital/lib/symbol_sync_ff_impl.cc654
-rw-r--r--gr-digital/lib/symbol_sync_ff_impl.h156
-rw-r--r--gr-digital/lib/timing_error_detector.cc443
-rw-r--r--gr-digital/lib/timing_error_detector.h513
-rw-r--r--gr-digital/python/grc_gnuradio/blks2/packet.py14
-rw-r--r--gr-digital/swig/digital_swig2.i17
-rw-r--r--gr-dtv/examples/germany-g1.grc2
-rw-r--r--gr-dtv/examples/germany-g10.grc2
-rw-r--r--gr-dtv/examples/germany-g2.grc2
-rw-r--r--gr-dtv/examples/germany-g3.grc2
-rw-r--r--gr-dtv/examples/germany-g4.grc2
-rw-r--r--gr-dtv/examples/germany-g5.grc2
-rw-r--r--gr-dtv/examples/germany-g6.grc2
-rw-r--r--gr-dtv/examples/germany-g7.grc2
-rw-r--r--gr-dtv/examples/germany-g8.grc2
-rw-r--r--gr-dtv/examples/germany-g9.grc2
-rw-r--r--gr-dtv/examples/vv001-cr35.grc2
-rw-r--r--gr-dtv/examples/vv003-cr23.grc2
-rw-r--r--gr-dtv/examples/vv004-8kfft.grc2
-rw-r--r--gr-dtv/examples/vv005-8kfft.grc2
-rw-r--r--gr-dtv/examples/vv007-16kfft.grc2
-rw-r--r--gr-dtv/examples/vv008-16kfft.grc2
-rw-r--r--gr-dtv/examples/vv009-4kfft.grc2
-rw-r--r--gr-dtv/examples/vv010-2kfft.grc2
-rw-r--r--gr-dtv/examples/vv011-1kfft.grc2
-rw-r--r--gr-dtv/examples/vv012-64qam45.grc2
-rw-r--r--gr-dtv/examples/vv013-64qam56.grc2
-rw-r--r--gr-dtv/examples/vv014-64qam34.grc2
-rw-r--r--gr-dtv/examples/vv015-8kfft.grc2
-rw-r--r--gr-dtv/examples/vv016-256qam34.grc2
-rw-r--r--gr-dtv/examples/vv017-paprtr.grc2
-rw-r--r--gr-dtv/examples/vv018-miso.grc4
-rw-r--r--gr-dtv/examples/vv019-norot.grc2
-rw-r--r--gr-dtv/examples/vv034-dtg016.grc2
-rw-r--r--gr-dtv/examples/vv035-dtg052.grc2
-rw-r--r--gr-dtv/examples/vv036-dtg091.grc2
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvb_bbheader_bb.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvb_bbscrambler_bb.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvb_bch_bb.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvb_ldpc_bb.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbs2_interleaver_bb.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbs2_physical_cc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_cellinterleaver_cc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_interleaver_bb.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h6
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_modulator_bc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h4
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h4
-rw-r--r--gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc13
-rw-r--r--gr-fcd/lib/CMakeLists.txt2
-rw-r--r--gr-fec/grc/variable_polar_code_configurator.xml14
-rw-r--r--gr-fft/lib/fft.cc4
-rw-r--r--gr-filter/include/gnuradio/filter/CMakeLists.txt4
-rw-r--r--gr-filter/include/gnuradio/filter/interp_differentiator_taps.h162
-rw-r--r--gr-filter/include/gnuradio/filter/mmse_interp_differentiator_cc.h80
-rw-r--r--gr-filter/include/gnuradio/filter/mmse_interp_differentiator_ff.h79
-rw-r--r--gr-filter/lib/CMakeLists.txt6
-rw-r--r--gr-filter/lib/gen_interpolator_taps/diff_objective_fct.c214
-rw-r--r--gr-filter/lib/gen_interpolator_taps/gen_interp_differentiator_taps.c182
-rwxr-xr-xgr-filter/lib/gen_interpolator_taps/generate.sh43
-rw-r--r--gr-filter/lib/mmse_interp_differentiator_cc.cc78
-rw-r--r--gr-filter/lib/mmse_interp_differentiator_ff.cc78
-rw-r--r--gr-filter/lib/qa_filter.cc6
-rw-r--r--gr-filter/lib/qa_mmse_interp_differentiator_cc.cc130
-rw-r--r--gr-filter/lib/qa_mmse_interp_differentiator_cc.h45
-rw-r--r--gr-filter/lib/qa_mmse_interp_differentiator_ff.cc99
-rw-r--r--gr-filter/lib/qa_mmse_interp_differentiator_ff.h45
-rw-r--r--gr-qtgui/doc/qtgui.dox23
-rw-r--r--gr-uhd/lib/usrp_sink_impl.cc3
-rw-r--r--grc/core/Param.py8
-rw-r--r--grc/gui/ActionHandler.py4
-rw-r--r--grc/gui/NotebookPage.py25
106 files changed, 13152 insertions, 155 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a793096f9e..de86d8a002 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -210,6 +210,10 @@ endif(MSVC)
if(WIN32)
add_definitions(-D_USE_MATH_DEFINES)
+
+ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ add_definitions(-DMS_WIN64)
+ endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
endif(WIN32)
# Record Compiler Info for record
diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
index d64f404e96..b58d2a6aee 100644
--- a/docs/doxygen/other/metadata.dox
+++ b/docs/doxygen/other/metadata.dox
@@ -14,9 +14,8 @@
Metadata files have extra information in the form of headers that
carry metadata about the samples in the file. Raw, binary files carry
no extra information and must be handled delicately. Any changes in
-the system state such as sample rate or if a receiver's frequency are
-not conveyed with the data in the file itself. Header of metadata
-solve this problem.
+the system state such as a receiver's sample rate or frequency are
+not conveyed with the data in the file itself. Headers solve this problem.
We write metadata files using gr::blocks::file_meta_sink and read metadata
files using gr::blocks::file_meta_source.
@@ -35,14 +34,14 @@ information.
- version: (char) version number (usually set to METADATA_VERSION)
- rx_rate: (double) Stream's sample rate
- rx_time: (pmt::pmt_t pair - (uint64_t, double)) Time stamp (format from UHD)
-- size: (int) item size in bytes - reflects vector length if any.
+- size: (int) item size in bytes - reflects vector length if any
- type: (int) data type (enum below)
- cplx: (bool) true if data is complex
- strt: (uint64_t) start of data relative to current header
- bytes: (uint64_t) size of following data segment in bytes
An optional extra section of the header stores information in any
-received tags. The two main tags associated with tags are:
+received tags. The two main tags associated with headers are:
- rx_rate: the sample rate of the stream.
- rx_time: the time stamp of the first item in the segment.
@@ -51,15 +50,15 @@ These tags were inspired by the UHD tag format.
The header gives enough information to process and handle the
data. One cautionary note, though, is that the data type should never
-change within a file. There should be very little need for this, but
-more importantly. GNU Radio blocks can only set the data type of their
+change within a file. There should be very little need for this, because
+GNU Radio blocks can only set the data type of their
IO signatures in the constructor, so changes in the data type
afterward will not be recognized.
-We also have an extra header segment that is option. This can be
+We also have an extra header segment that is optional. This can be
loaded up at the beginning by the user specifying some extra metadata
that should be transmitted along with the data. It also grows whenever
-it sees a stream tag, so the dictionary will contain and key:value
+it sees a stream tag, so the dictionary will contain any key:value
pairs out of tags from the flowgraph.
@@ -114,7 +113,7 @@ Metadata files are created using gr::blocks::file_meta_sink. The
default behavior is to create a single file with inline headers as
metadata. An option can be set to switch to detached header mode.
-Metadata file are read into a flowgraph using
+Metadata files are read into a flowgraph using
gr::blocks::file_meta_source. This source reads a metadata file,
inline by default with a settable option to use detached headers. The
data from the segments is converted into a standard streaming
@@ -132,7 +131,7 @@ dictionary. Headers are created by building a PMT dictionary
serialized into a string to be written to file. The header is always
the same length that is predetermined by the version of the header
(this must be known already). The header will then indicate if there
-is an extra data to be extracted as a separate serialized dictionary.
+is extra data to be extracted as a separate serialized dictionary.
To work with the PMTs for creating and extracting header information,
we use PMT operators. For example, we create a simplified version of
@@ -261,7 +260,7 @@ data type of the PMT value. The key is always a PMT symbol, but the
value can be any other PMT type. There are PMT functions that allow us
to query the PMT to test if it is a particular type. We also have the
ability to do pmt::print on any PMT object to print it to
-screen. Before converting from a PMT to it's natural data type, it is
+screen. Before converting from a PMT to its natural data type, it is
necessary to know the data type.
@@ -327,7 +326,7 @@ vectors of data.
The following shows a simple way of creating extra metadata for a
metadata file. This example is just showing how we can insert a date
-into the metadata to keep track of later. The date in this case is
+into the metadata to keep track of it later. The date in this case is
encoded as a vector of uint16 with [day, month, year].
\code
diff --git a/docs/doxygen/other/operating_fg.dox b/docs/doxygen/other/operating_fg.dox
index c2c66cccd9..62cc56fd4e 100644
--- a/docs/doxygen/other/operating_fg.dox
+++ b/docs/doxygen/other/operating_fg.dox
@@ -22,7 +22,7 @@ between.
A program must at least create a GNU Radio 'top_block', which
represents the top-most structure of the flowgraph. The top blocks
provide the overall control and hold methods such as 'start,' 'stop,'
-and 'wait.'
+and 'wait'.
The general construction of a GNU Radio application is to create a
gr_top_block, instantiate the blocks, connect the blocks together, and
@@ -67,7 +67,7 @@ By default, GNU Radio runs a scheduler that attempts to optimize
throughput. Using a dynamic scheduler, blocks in a flowgraph pass
chunks of items from sources to sinks. The sizes of these chunks will
vary depending on the speed of processing. For each block, the number
-of items is can process is dependent on how much space it has in its
+of items it can process is dependent on how much space it has in its
output buffer(s) and how many items are available on the input
buffer(s).
@@ -153,8 +153,8 @@ latency. Limiting the size of the buffer may decrease performance.
4. The real buffer size is actually based on a minimum granularity of
the system. Typically, this is a page size, which is typically 4096
bytes. This means that any buffer size that is specified with this
-command will get rounded up to the nearest granularity (e.g., page)
-size. When calling max_output_buffer(port) after the flowgraph is
+command will get rounded up to the nearest granularity (e.g., page size).
+When calling max_output_buffer(port) after the flowgraph is
started, you will get how many items were actually allocated in the
buffer, which may be different than what was initially specified.
diff --git a/docs/doxygen/other/pmt.dox b/docs/doxygen/other/pmt.dox
index 932f6c0a83..1bc6cbecd4 100644
--- a/docs/doxygen/other/pmt.dox
+++ b/docs/doxygen/other/pmt.dox
@@ -55,7 +55,7 @@ std::cout << P2 << std::endl;
std::cout << pmt::is_complex(P2) << std::endl;
\endcode
-Two things stand out in both Python and C++: First we can simply print
+Two things stand out in both Python and C++. First, we can simply print
the contents of a PMT. How is this possible? Well, the PMTs have
in-built capability to cast their value to a string (this is not
possible with all types, though). Second, PMTs must obviously know
@@ -85,7 +85,7 @@ The pmt::intern is another way of saying pmt::string_to_symbol.
In Python, we can make use of the dynamic typing, and there's actually a
helper function to do these conversions (C++ also has a helper
-function for converting to PMTs called pmt::mp(), but its less
+function for converting to PMTs called pmt::mp(), but it's less
powerful, and not quite as useful, because types are always strictly
known in C++):
@@ -283,7 +283,7 @@ if(pmt::is_double(pmt_a))
\section pmt_dict Dictionaries
-PMT dictionaries and lists of key:value pairs. They have a
+PMT dictionaries are lists of key:value pairs. They have a
well-defined interface for creating, adding, removing, and accessing
items in the dictionary. Note that every operation that changes the
dictionary both takes a PMT dictionary as an argument and returns a
diff --git a/docs/exploring-gnuradio/exploring_gnuradio.dox b/docs/exploring-gnuradio/exploring_gnuradio.dox
index 78dcfdf3cc..d762db443b 100644
--- a/docs/exploring-gnuradio/exploring_gnuradio.dox
+++ b/docs/exploring-gnuradio/exploring_gnuradio.dox
@@ -43,7 +43,7 @@ We next take the three blocks we've built and connect together the
flowgraph. The flowgraph connects sources to sinks through other
signal processing blocks. Here, we are directly connecting two sources
to a single sink. The next example uses more complex flowgraphs to
-farther explore these concepts. The two lines containing the
+further explore these concepts. The two lines containing the
"tb.connect" statements are where the connections are made. The
flowgraph will look like:
@@ -69,7 +69,7 @@ is implied. Otherwise, we could write this as "tb.connect((src0, 0),
When we are done connecting the blocks, we have a flowgraph in the
object "tb". While it's connected, the sources are not generating any
-samples. We have to start the flowgraph running. In the main section,
+samples. We have to start running the flowgraph. In the main section,
we return the top_block object and then call the "start" function on
it. This is a non-blocking call that launches the flowgraph's main
thread, which initiates the sources to start sending samples through
@@ -97,15 +97,15 @@ outputting the original signal to the audio system as well as viewing
it in time and frequency at different stages.
The intent of this example is to generate a frequency-modulated dial
-tone signal and save itto a file. While saving it to a file, we only
-want to generate a signal large enough to make use of but it doesn't
+tone signal and save it to a file. While saving it to a file, we only
+want to generate a signal large enough to make use of it, but it doesn't
have to be too large. So we put a gr::blocks::head block that limits
the number of samples into the file sink. Once this block has seen N
number of samples, it will stop the flowgraph. Meanwhile, we use a
gr::blocks::skiphead block to ignore the first M samples, which helps
us avoid the transients and group delay of the filters in the system.
-We run this either using the menu "Build->Execute" or using the gears
+We run this either using the menu "Build->Execute" or using the play
button on the toolbar. It will run for a short amount of time and stop
once the head has seen the items set in the "nitems" parameter. The
result is a file "dummy.dat" that contains the complex FM samples.
@@ -129,7 +129,7 @@ any rate as well as filter the signal to the audio rate we want. The
output of this block is filtered to a 15 kHz bandwidth at a sample
rate of 44.1 ksps, which is ready for the gr::audio::sink block.
-Both the GRC and Python files can be explored farther to better
+Both the GRC and Python files can be explored further to better
understand the operations of the blocks.
-*/ \ No newline at end of file
+*/
diff --git a/gnuradio-runtime/include/gnuradio/types.h b/gnuradio-runtime/include/gnuradio/types.h
index 6cb0f72834..7e13d3bf32 100644
--- a/gnuradio-runtime/include/gnuradio/types.h
+++ b/gnuradio-runtime/include/gnuradio/types.h
@@ -30,6 +30,8 @@
#include <gnuradio/gr_complex.h>
+#include <stdint.h>
+
typedef std::vector<int> gr_vector_int;
typedef std::vector<unsigned int> gr_vector_uint;
typedef std::vector<float> gr_vector_float;
@@ -37,29 +39,5 @@ typedef std::vector<double> gr_vector_double;
typedef std::vector<void *> gr_vector_void_star;
typedef std::vector<const void *> gr_vector_const_void_star;
-/*
- * #include <config.h> must be placed beforehand
- * in the source file including gnuradio/types.h for
- * the following to work correctly
- */
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-typedef int16_t gr_int16;
-typedef int32_t gr_int32;
-typedef int64_t gr_int64;
-typedef uint16_t gr_uint16;
-typedef uint32_t gr_uint32;
-typedef uint64_t gr_uint64;
-#else
-/*
- * Note: these defaults may be wrong on 64-bit systems
- */
-typedef short gr_int16;
-typedef int gr_int32;
-typedef long long gr_int64;
-typedef unsigned short gr_uint16;
-typedef unsigned int gr_uint32;
-typedef unsigned long long gr_uint64;
-#endif /* HAVE_STDINT_H */
#endif /* INCLUDED_GR_TYPES_H */
diff --git a/gnuradio-runtime/lib/buffer.cc b/gnuradio-runtime/lib/buffer.cc
index b706408412..db554d21e7 100644
--- a/gnuradio-runtime/lib/buffer.cc
+++ b/gnuradio-runtime/lib/buffer.cc
@@ -346,7 +346,7 @@ namespace gr {
{
gr::thread::scoped_lock guard(*mutex());
- v.resize(0);
+ v.clear();
std::multimap<uint64_t,tag_t>::iterator itr = d_buffer->get_tags_lower_bound(std::min(abs_start, abs_start - d_attr_delay));
std::multimap<uint64_t,tag_t>::iterator itr_end = d_buffer->get_tags_upper_bound(std::min(abs_end, abs_end - d_attr_delay));
diff --git a/gr-blocks/grc/blocks_file_source.xml b/gr-blocks/grc/blocks_file_source.xml
index 7ac573f2da..1f09e95168 100644
--- a/gr-blocks/grc/blocks_file_source.xml
+++ b/gr-blocks/grc/blocks_file_source.xml
@@ -8,8 +8,11 @@
<name>File Source</name>
<key>blocks_file_source</key>
<import>from gnuradio import blocks</import>
- <make>blocks.file_source($type.size*$vlen, $file, $repeat)</make>
+ <import>import pmt</import>
+ <make>blocks.file_source($type.size*$vlen, $file, $repeat)
+self.$(id).set_begin_tag($begin_tag)</make>
<callback>open($file, $repeat)</callback>
+ <callback>self.$(id).set_begin_tag($begin_tag)</callback>
<param>
<name>File</name>
<key>file</key>
@@ -66,6 +69,13 @@
<value>1</value>
<type>int</type>
</param>
+
+ <param>
+ <name>Add begin tag</name>
+ <key>begin_tag</key>
+ <value>pmt.PMT_NIL</value>
+ <type>raw</type>
+ </param>
<check>$vlen &gt; 0</check>
<source>
<name>out</name>
diff --git a/gr-blocks/grc/blocks_tag_gate.xml b/gr-blocks/grc/blocks_tag_gate.xml
index 34475ff96f..0cf6dc42ed 100644
--- a/gr-blocks/grc/blocks_tag_gate.xml
+++ b/gr-blocks/grc/blocks_tag_gate.xml
@@ -4,7 +4,7 @@
<key>blocks_tag_gate</key>
<import>from gnuradio import blocks</import>
<make>blocks.tag_gate($type.size * $vlen, $propagate_tags)
-self.$(id).set_single_key($single_key))</make>
+self.$(id).set_single_key($single_key)</make>
<callback>self.$(id).set_single_key($single_key)</callback>
<param>
diff --git a/gr-blocks/include/gnuradio/blocks/file_source.h b/gr-blocks/include/gnuradio/blocks/file_source.h
index 5682853a35..c8138339fd 100644
--- a/gr-blocks/include/gnuradio/blocks/file_source.h
+++ b/gr-blocks/include/gnuradio/blocks/file_source.h
@@ -77,6 +77,11 @@ namespace gr {
* \brief Close the file handle.
*/
virtual void close() = 0;
+
+ /*!
+ * \brief Add a stream tag to the first sample of the file if true
+ */
+ virtual void set_begin_tag(pmt::pmt_t val) = 0;
};
} /* namespace blocks */
diff --git a/gr-blocks/lib/file_source_impl.cc b/gr-blocks/lib/file_source_impl.cc
index 1602b02416..c077c74fd9 100644
--- a/gr-blocks/lib/file_source_impl.cc
+++ b/gr-blocks/lib/file_source_impl.cc
@@ -64,10 +64,15 @@ namespace gr {
io_signature::make(0, 0, 0),
io_signature::make(1, 1, itemsize)),
d_itemsize(itemsize), d_fp(0), d_new_fp(0), d_repeat(repeat),
- d_updated(false)
+ d_updated(false), d_file_begin(true), d_repeat_cnt(0),
+ d_add_begin_tag(pmt::PMT_NIL)
{
open(filename, repeat);
do_update();
+
+ std::stringstream str;
+ str << name() << unique_id();
+ _id = pmt::string_to_symbol(str.str());
}
file_source_impl::~file_source_impl()
@@ -110,6 +115,16 @@ namespace gr {
throw std::runtime_error("can't open file");
}
+ //Check to ensure the file will be consumed according to item size
+ fseek(d_new_fp, 0, SEEK_END);
+ int file_size = ftell(d_new_fp);
+ rewind (d_new_fp);
+
+ //Warn the user if part of the file will not be consumed.
+ if(file_size % d_itemsize){
+ GR_LOG_WARN(d_logger, "WARNING: File will not be fully consumed with the current output type");
+ }
+
d_updated = true;
d_repeat = repeat;
}
@@ -139,9 +154,16 @@ namespace gr {
d_fp = d_new_fp; // install new file pointer
d_new_fp = 0;
d_updated = false;
+ d_file_begin = true;
}
}
+ void
+ file_source_impl::set_begin_tag(pmt::pmt_t val)
+ {
+ d_add_begin_tag = val;
+ }
+
int
file_source_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
@@ -156,7 +178,14 @@ namespace gr {
throw std::runtime_error("work with file not open");
gr::thread::scoped_lock lock(fp_mutex); // hold for the rest of this function
+
while(size) {
+ // Add stream tag whenever the file starts again
+ if (d_file_begin && d_add_begin_tag != pmt::PMT_NIL) {
+ add_item_tag(0, nitems_written(0) + noutput_items - size, d_add_begin_tag, pmt::from_long(d_repeat_cnt), _id);
+ d_file_begin = false;
+ }
+
i = fread(o, d_itemsize, size, (FILE*)d_fp);
size -= i;
@@ -178,6 +207,10 @@ namespace gr {
fprintf(stderr, "[%s] fseek failed\n", __FILE__);
exit(-1);
}
+ if (d_add_begin_tag != pmt::PMT_NIL) {
+ d_file_begin = true;
+ d_repeat_cnt++;
+ }
}
if(size > 0) { // EOF or error
diff --git a/gr-blocks/lib/file_source_impl.h b/gr-blocks/lib/file_source_impl.h
index 80232a1dbe..19f393fc1d 100644
--- a/gr-blocks/lib/file_source_impl.h
+++ b/gr-blocks/lib/file_source_impl.h
@@ -37,7 +37,12 @@ namespace gr {
FILE *d_new_fp;
bool d_repeat;
bool d_updated;
+ bool d_file_begin;
+ long d_repeat_cnt;
+ pmt::pmt_t d_add_begin_tag;
+
boost::mutex fp_mutex;
+ pmt::pmt_t _id;
void do_update();
@@ -52,6 +57,8 @@ namespace gr {
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
+
+ void set_begin_tag(pmt::pmt_t val);
};
} /* namespace blocks */
diff --git a/gr-blocks/python/blocks/qa_file_source_sink.py b/gr-blocks/python/blocks/qa_file_source_sink.py
index da1a07b347..32910cb4bc 100644
--- a/gr-blocks/python/blocks/qa_file_source_sink.py
+++ b/gr-blocks/python/blocks/qa_file_source_sink.py
@@ -23,6 +23,7 @@
from gnuradio import gr, gr_unittest, blocks
import os
import tempfile
+import pmt
class test_file_source_sink(gr_unittest.TestCase):
@@ -55,6 +56,7 @@ class test_file_source_sink(gr_unittest.TestCase):
result_data = snk2.data()
self.assertFloatTuplesAlmostEqual(expected_result, result_data)
+ self.assertEqual(len(snk2.tags()), 0)
def test_descriptor_001(self):
src_data = range(1000)
@@ -86,6 +88,7 @@ class test_file_source_sink(gr_unittest.TestCase):
result_data = snk2.data()
self.assertFloatTuplesAlmostEqual(expected_result, result_data)
+ self.assertEqual(len(snk2.tags()), 0)
def test_file_source_can_seek_after_open(self):
src_data = range(1000)
@@ -101,6 +104,65 @@ class test_file_source_sink(gr_unittest.TestCase):
source = blocks.file_source(gr.sizeof_float, temp.name)
self.assertTrue(source.seek(0, os.SEEK_SET))
+ def test_begin_tag(self):
+ src_data = range(1000)
+ expected_result = range(1000)
+
+ snk2 = blocks.vector_sink_f()
+
+ with tempfile.NamedTemporaryFile() as temp:
+ src = blocks.vector_source_f(src_data)
+ snk = blocks.file_sink(gr.sizeof_float, temp.name)
+ snk.set_unbuffered(True)
+
+ src2 = blocks.file_source(gr.sizeof_float, temp.name)
+ src2.set_begin_tag(pmt.string_to_symbol("file_begin"))
+
+ self.tb.connect(src, snk)
+ self.tb.run()
+
+ self.tb.disconnect(src, snk)
+ self.tb.connect(src2, snk2)
+ self.tb.run()
+
+ result_data = snk2.data()
+ self.assertFloatTuplesAlmostEqual(expected_result, result_data)
+ self.assertEqual(len(snk2.tags()), 1)
+
+ def test_begin_tag_repeat(self):
+ src_data = range(1000)
+ expected_result = range(1000)
+ expected_result.extend(range(1000))
+
+ snk2 = blocks.vector_sink_f()
+
+ with tempfile.NamedTemporaryFile() as temp:
+ src = blocks.vector_source_f(src_data)
+ snk = blocks.file_sink(gr.sizeof_float, temp.name)
+ snk.set_unbuffered(True)
+
+ src2 = blocks.file_source(gr.sizeof_float, temp.name, True)
+ src2.set_begin_tag(pmt.string_to_symbol("file_begin"))
+ hd = blocks.head(gr.sizeof_float, 2000)
+
+ self.tb.connect(src, snk)
+ self.tb.run()
+
+ self.tb.disconnect(src, snk)
+ self.tb.connect(src2, hd, snk2)
+ self.tb.run()
+
+ result_data = snk2.data()
+ self.assertFloatTuplesAlmostEqual(expected_result, result_data)
+ tags = snk2.tags()
+ self.assertEqual(len(tags), 2)
+ self.assertEqual(str(tags[0].key), "file_begin")
+ self.assertEqual(str(tags[0].value), "0")
+ self.assertEqual(tags[0].offset, 0)
+ self.assertEqual(str(tags[1].key), "file_begin")
+ self.assertEqual(str(tags[1].value), "1")
+ self.assertEqual(tags[1].offset, 1000)
+
if __name__ == '__main__':
gr_unittest.run(test_file_source_sink, "test_file_source_sink.xml")
diff --git a/gr-digital/examples/CMakeLists.txt b/gr-digital/examples/CMakeLists.txt
index 5f1adf08ab..d5a419dfc8 100644
--- a/gr-digital/examples/CMakeLists.txt
+++ b/gr-digital/examples/CMakeLists.txt
@@ -88,6 +88,8 @@ install(
demod/ber_simulation.grc
demod/dpsk_loopback.grc
demod/gfsk_loopback.grc
+ demod/symbol_sync_test_complex.grc
+ demod/symbol_sync_test_float.grc
demod/test_corr_and_sync.grc
demod/test_corr_est.grc
demod/uhd_corr_and_sync_tx.grc
diff --git a/gr-digital/examples/demod/symbol_sync_test_complex.grc b/gr-digital/examples/demod/symbol_sync_test_complex.grc
new file mode 100644
index 0000000000..cd0ca99e23
--- /dev/null
+++ b/gr-digital/examples/demod/symbol_sync_test_complex.grc
@@ -0,0 +1,2876 @@
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.12'?>
+<!--
+ Copyright (C) 2017 Free Software Foundation
+
+ 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.
+-->
+<flow_graph>
+ <timestamp>Mon Jan 12 16:38:01 2015</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>author</key>
+ <value>Andy Walls</value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>3200, 700</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(10, 10)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>hier_block_src_path</key>
+ <value>.:</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>symbol_sync_test_complex</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>qt_qss_theme</key>
+ <value></value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>run_command</key>
+ <value>{python} -u {filename}</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>thread_safe_setters</key>
+ <value></value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>Symbol Sync Test (Complex)</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(552, 244)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>baud_rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1200.0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_chooser</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(392, 48)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,0,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>data_src</value>
+ </param>
+ <param>
+ <key>label0</key>
+ <value>Random</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>Low freq</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>Dot Pattern</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value>Pulse</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value>Packets</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value></value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>num_opts</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>option0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>option1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>option2</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>option3</key>
+ <value>3</value>
+ </param>
+ <param>
+ <key>option4</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>options</key>
+ <value>[0, 1, 2]</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.QVBoxLayout</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>combo_box</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2288, 588)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>integral_gain</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>(2.0-proportional_gain-2.0*math.exp(-zeta*omega_n_norm)*(math.cosh(omega_d_norm) if zeta &gt; 1.0 else math.cos(omega_d_norm)))/ted_gain</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_label</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>"%8.6f" % integral_gain</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2760, 484)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,2,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>integral_gain_label</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Integral Gain</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>string</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2288, 460)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>omega_d_norm</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>omega_n_norm*math.sqrt((zeta*zeta-1.0) if zeta &gt; 1.0 else (1.0-zeta*zeta))</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0.25</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2440, 568)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,1,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>omega_n_norm</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Normalized Bandwidth</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>2.0*math.pi*0.25</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2608, 212)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>osps</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_tag_object</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 600)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>packet_time_est_tag</value>
+ </param>
+ <param>
+ <key>key</key>
+ <value>pmt.intern("test")</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>9</value>
+ </param>
+ <param>
+ <key>src</key>
+ <value>pmt.intern("packet_vector_source")</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>pmt.from_double(0.0)</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2288, 524)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>proportional_gain</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>2.0/ted_gain*math.exp(-zeta*omega_n_norm)*math.sinh(zeta*omega_n_norm)</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_label</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>"%8.6f" % proportional_gain</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2760, 564)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,2,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>proportional_gain_label</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Proportional Gain</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>string</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1336, 236)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>sps</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>7</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2608, 568)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,0,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>ted_gain</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Expected TED Gain</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>5.0</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2440, 448)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,1,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>zeta</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Damping Factor</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>5.0</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_random_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 192)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>analog_random_source_x_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>num_samps</key>
+ <value>16384</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_add_xx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(448, 264)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_add_xx_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_char_to_float</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1160, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_char_to_float_2</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_float_to_char</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(872, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_float_to_char_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_float_to_complex</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2752, 328)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_float_to_complex_0_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_float_to_complex</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2752, 392)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_float_to_complex_1_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_float_to_complex</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1936, 328)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_float_to_complex_3</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 4 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(224, 540)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 3 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(216, 460)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 2 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(216, 380)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 1 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(216, 308)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 0 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(208, 212)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0_0_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>0.707+0.707j</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2128, 340)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_1</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_repeat</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1312, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_repeat_0</value>
+ </param>
+ <param>
+ <key>interp</key>
+ <value>sps*2</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_short_to_float</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(712, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_short_to_float_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(544, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>ignoretag</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>baud_rate*10</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 364)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>(0, 1, 0, 1, 0, 1, 0, 1)</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 284)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>(0,0,0,0,1,1,1,1)</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 444)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0_1</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>[1]+[0]*7</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 524)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0_1_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[packet_time_est_tag]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>[1,0]*(4*12*0)+[1,1,0,1,0,1,0,1]*12+[1,0,1,1,1,1,1,0,0,1]+[1,1,1,1,0,1,1,0,0,1]+[1,0,1,1,1,1,1,0,0,1]+[0,1,1,1,0,1,1,0,1,0]+[0,0,0,0,0,1,0,1,0,1,1,0,0,1,1,1,0,0,0,0]+[2]*128</value>
+ </param>
+ </block>
+ <block>
+ <key>digital_map_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1024, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>digital_map_bb_0</value>
+ </param>
+ <param>
+ <key>map</key>
+ <value>[-1, 1,0]</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>digital_symbol_sync_xx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>damping</key>
+ <value>zeta</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>ted_gain</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>nfilters</key>
+ <value>128</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2376, 292)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>cc</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>digital_symbol_sync_xx_0</value>
+ </param>
+ <param>
+ <key>resamp_type</key>
+ <value>digital.IR_MMSE_8TAP</value>
+ </param>
+ <param>
+ <key>loop_bw</key>
+ <value>omega_n_norm</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max_dev</key>
+ <value>1.5</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>osps</key>
+ <value>osps</value>
+ </param>
+ <param>
+ <key>pfb_mf_taps</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>sps</key>
+ <value>sps</value>
+ </param>
+ <param>
+ <key>constellation</key>
+ <value>digital.constellation_qpsk().base()</value>
+ </param>
+ <param>
+ <key>ted_type</key>
+ <value>digital.TED_MUELLER_AND_MULLER</value>
+ </param>
+ </block>
+ <block>
+ <key>fir_filter_xxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>decim</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1688, 316)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>fir_filter_xxx_0_1_0_0_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>samp_delay</key>
+ <value>int((sps-1.0)/2.0)+4</value>
+ </param>
+ <param>
+ <key>taps</key>
+ <value>[1.0/float(sps)]*sps</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fff</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(184, 12)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>import_0</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>autoscale</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>axislabels</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ctrlpanel</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>entags</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2992, 296)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,1,1,2</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0_0_0_0_0</value>
+ </param>
+ <param>
+ <key>legend</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alpha1</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color1</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>Soft Bits Re</value>
+ </param>
+ <param>
+ <key>marker1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>style1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha10</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color10</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker10</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha2</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color2</key>
+ <value>"magenta"</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>Soft Bits Im</value>
+ </param>
+ <param>
+ <key>marker2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>style2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha3</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color3</key>
+ <value>"red"</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value>Error</value>
+ </param>
+ <param>
+ <key>marker3</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha4</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color4</key>
+ <value>"green"</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value>Instantaneous Period</value>
+ </param>
+ <param>
+ <key>marker4</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha5</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color5</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>label5</key>
+ <value>Average Period</value>
+ </param>
+ <param>
+ <key>marker5</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha6</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color6</key>
+ <value>"yellow"</value>
+ </param>
+ <param>
+ <key>label6</key>
+ <value>(unused)</value>
+ </param>
+ <param>
+ <key>marker6</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>width6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha7</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color7</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>label7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker7</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha8</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color8</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>label8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker8</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>width8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha9</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color9</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>label9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker9</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>Symbol Synched Output and Debug</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>3</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>256*osps</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>baud_rate*osps</value>
+ </param>
+ <param>
+ <key>tr_chan</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>tr_delay</key>
+ <value>0.01</value>
+ </param>
+ <param>
+ <key>tr_level</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_NORM</value>
+ </param>
+ <param>
+ <key>tr_slope</key>
+ <value>qtgui.TRIG_SLOPE_POS</value>
+ </param>
+ <param>
+ <key>tr_tag</key>
+ <value>"time_est"</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>ylabel</key>
+ <value>Amplitude</value>
+ </param>
+ <param>
+ <key>yunit</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>sps+2</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1.5</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>autoscale</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>axislabels</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ctrlpanel</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>entags</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2376, 204)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0_1_0</value>
+ </param>
+ <param>
+ <key>legend</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alpha1</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color1</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>Re</value>
+ </param>
+ <param>
+ <key>marker1</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha10</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color10</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker10</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha2</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color2</key>
+ <value>"red"</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>Im</value>
+ </param>
+ <param>
+ <key>marker2</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha3</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color3</key>
+ <value>"green"</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker3</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha4</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color4</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker4</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha5</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color5</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>label5</key>
+ <value>Baseband</value>
+ </param>
+ <param>
+ <key>marker5</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha6</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color6</key>
+ <value>"magenta"</value>
+ </param>
+ <param>
+ <key>label6</key>
+ <value>Abs(Corr)</value>
+ </param>
+ <param>
+ <key>marker6</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha7</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color7</key>
+ <value>"yellow"</value>
+ </param>
+ <param>
+ <key>label7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker7</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha8</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color8</key>
+ <value>"dark red"</value>
+ </param>
+ <param>
+ <key>label8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker8</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha9</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color9</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>label9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker9</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024*3</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>baud_rate*sps</value>
+ </param>
+ <param>
+ <key>tr_chan</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>tr_delay</key>
+ <value>0.01</value>
+ </param>
+ <param>
+ <key>tr_level</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_NORM</value>
+ </param>
+ <param>
+ <key>tr_slope</key>
+ <value>qtgui.TRIG_SLOPE_POS</value>
+ </param>
+ <param>
+ <key>tr_tag</key>
+ <value></value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>ylabel</key>
+ <value>Amplitude</value>
+ </param>
+ <param>
+ <key>yunit</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>1.5</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1.5</value>
+ </param>
+ </block>
+ <block>
+ <key>rational_resampler_xxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>decim</key>
+ <value>21</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>fbw</key>
+ <value>0.45</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1480, 304)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>rational_resampler_xxx_0_0</value>
+ </param>
+ <param>
+ <key>interp</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>taps</key>
+ <value></value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fff</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>analog_random_source_x_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_add_xx_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_char_to_float_2</source_block_id>
+ <sink_block_id>blocks_repeat_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_float_to_char_0</source_block_id>
+ <sink_block_id>digital_map_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_float_to_complex_0_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_float_to_complex_1_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>2</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_float_to_complex_3</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_1</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>4</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>3</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>2</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0_0_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_1</source_block_id>
+ <sink_block_id>digital_symbol_sync_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_1</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_1_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_repeat_0</source_block_id>
+ <sink_block_id>rational_resampler_xxx_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_short_to_float_0</source_block_id>
+ <sink_block_id>blocks_float_to_char_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>blocks_short_to_float_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0_1</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0_1_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_map_bb_0</source_block_id>
+ <sink_block_id>blocks_char_to_float_2</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_1_0</sink_block_id>
+ <source_key>3</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_0_0</sink_block_id>
+ <source_key>2</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_0_0</sink_block_id>
+ <source_key>1</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fir_filter_xxx_0_1_0_0_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_3</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>rational_resampler_xxx_0_0</source_block_id>
+ <sink_block_id>fir_filter_xxx_0_1_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-digital/examples/demod/symbol_sync_test_float.grc b/gr-digital/examples/demod/symbol_sync_test_float.grc
new file mode 100644
index 0000000000..5507cbf848
--- /dev/null
+++ b/gr-digital/examples/demod/symbol_sync_test_float.grc
@@ -0,0 +1,2703 @@
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.12'?>
+<!--
+ Copyright (C) 2017 Free Software Foundation
+
+ 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.
+-->
+<flow_graph>
+ <timestamp>Mon Jan 12 16:38:01 2015</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>author</key>
+ <value>Andy Walls</value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>2600, 700</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(10, 10)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>hier_block_src_path</key>
+ <value>.:</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>symbol_sync_test_float</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>qt_qss_theme</key>
+ <value></value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>run_command</key>
+ <value>{python} -u {filename}</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>thread_safe_setters</key>
+ <value></value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>Symbol Sync Test (Float)</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(552, 244)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>baud_rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1200.0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_chooser</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(392, 48)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,0,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>data_src</value>
+ </param>
+ <param>
+ <key>label0</key>
+ <value>Random</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>Low freq</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>Dot Pattern</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value>Pulse</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value>Packets</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value></value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>num_opts</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>option0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>option1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>option2</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>option3</key>
+ <value>3</value>
+ </param>
+ <param>
+ <key>option4</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>options</key>
+ <value>[0, 1, 2]</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.QVBoxLayout</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>combo_box</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1800, 548)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>integral_gain</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>(2.0-proportional_gain-2.0*math.exp(-zeta*omega_n_norm)*(math.cosh(omega_d_norm) if zeta &gt; 1.0 else math.cos(omega_d_norm)))/ted_gain</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_label</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>"%8.6f" % integral_gain</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2296, 420)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,2,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>integral_gain_label</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Integral Gain</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>string</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1800, 420)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>omega_d_norm</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>omega_n_norm*math.sqrt((zeta*zeta-1.0) if zeta &gt; 1.0 else (1.0-zeta*zeta))</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0.07</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1944, 416)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,1,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>omega_n_norm</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Normalized Bandwidth</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>2.0*math.pi*0.25</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2192, 196)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>osps</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_tag_object</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 600)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>packet_time_est_tag</value>
+ </param>
+ <param>
+ <key>key</key>
+ <value>pmt.intern("test")</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>9</value>
+ </param>
+ <param>
+ <key>src</key>
+ <value>pmt.intern("packet_vector_source")</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>pmt.from_double(0.0)</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1800, 484)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>proportional_gain</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>2.0/ted_gain*math.exp(-zeta*omega_n_norm)*math.sinh(zeta*omega_n_norm)</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_label</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>"%8.6f" % proportional_gain</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2296, 500)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,2,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>proportional_gain_label</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Proportional Gain</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>string</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1328, 228)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>sps</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>7</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2120, 536)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,0,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>ted_gain</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Expected TED Gain</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>5.0</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1944, 536)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,1,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>zeta</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Damping Factor</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>5.0</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_random_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 192)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>analog_random_source_x_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>num_samps</key>
+ <value>16384</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_add_xx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(448, 264)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_add_xx_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_char_to_float</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1160, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_char_to_float_2</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_float_to_char</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(872, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_float_to_char_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 4 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(224, 540)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 3 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(216, 460)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 2 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(216, 380)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 1 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(216, 308)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1 if data_src == 0 else 0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(208, 212)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0_0_0_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_repeat</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1312, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_repeat_0</value>
+ </param>
+ <param>
+ <key>interp</key>
+ <value>sps*2</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_short_to_float</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(712, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_short_to_float_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(544, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>ignoretag</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>baud_rate*10</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 364)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>(0, 1, 0, 1, 0, 1, 0, 1)</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 284)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>(0,0,0,0,1,1,1,1)</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 444)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0_1</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>[1]+[0]*7</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_source_x</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 524)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_source_x_0_0_1_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>short</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tags</key>
+ <value>[packet_time_est_tag]</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>vector</key>
+ <value>[1,0]*(4*12*0)+[1,1,0,1,0,1,0,1]*12+[1,0,1,1,1,1,1,0,0,1]+[1,1,1,1,0,1,1,0,0,1]+[1,0,1,1,1,1,1,0,0,1]+[0,1,1,1,0,1,1,0,1,0]+[0,0,0,0,0,1,0,1,0,1,1,0,0,1,1,1,0,0,0,0]+[2]*128</value>
+ </param>
+ </block>
+ <block>
+ <key>digital_map_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1024, 324)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>digital_map_bb_0</value>
+ </param>
+ <param>
+ <key>map</key>
+ <value>[-1, 1,0]</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>digital_symbol_sync_xx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>damping</key>
+ <value>zeta</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>ted_gain</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>nfilters</key>
+ <value>128</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1944, 276)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>ff</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>digital_symbol_sync_xx_0</value>
+ </param>
+ <param>
+ <key>resamp_type</key>
+ <value>digital.IR_MMSE_8TAP</value>
+ </param>
+ <param>
+ <key>loop_bw</key>
+ <value>omega_n_norm</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max_dev</key>
+ <value>1.5</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>osps</key>
+ <value>osps</value>
+ </param>
+ <param>
+ <key>pfb_mf_taps</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>sps</key>
+ <value>sps</value>
+ </param>
+ <param>
+ <key>constellation</key>
+ <value>digital.constellation_bpsk().base()</value>
+ </param>
+ <param>
+ <key>ted_type</key>
+ <value>digital.TED_MUELLER_AND_MULLER</value>
+ </param>
+ </block>
+ <block>
+ <key>fir_filter_xxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>decim</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1672, 316)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>fir_filter_xxx_0_1_0_0_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>samp_delay</key>
+ <value>int((sps-1.0)/2.0)+4</value>
+ </param>
+ <param>
+ <key>taps</key>
+ <value>[1.0/float(sps)]*sps</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fff</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(184, 12)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>import_0</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(184, 60)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>import_0_0</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>from gnuradio import digital</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>autoscale</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>axislabels</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ctrlpanel</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>entags</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(2296, 280)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,1,1,2</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0_0_0_0_0</value>
+ </param>
+ <param>
+ <key>legend</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alpha1</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color1</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>Soft Bits</value>
+ </param>
+ <param>
+ <key>marker1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>style1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha10</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color10</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker10</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha2</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color2</key>
+ <value>"red"</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>Error</value>
+ </param>
+ <param>
+ <key>marker2</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha3</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color3</key>
+ <value>"green"</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value>Instantaneous Period</value>
+ </param>
+ <param>
+ <key>marker3</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha4</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color4</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value>Average Period</value>
+ </param>
+ <param>
+ <key>marker4</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha5</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color5</key>
+ <value>"cyan"</value>
+ </param>
+ <param>
+ <key>label5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker5</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha6</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color6</key>
+ <value>"magenta"</value>
+ </param>
+ <param>
+ <key>label6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker6</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha7</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color7</key>
+ <value>"yellow"</value>
+ </param>
+ <param>
+ <key>label7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker7</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha8</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color8</key>
+ <value>"dark red"</value>
+ </param>
+ <param>
+ <key>label8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker8</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha9</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color9</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>label9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker9</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>Symbol Synched Output and Debug</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>256*osps</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>baud_rate*osps</value>
+ </param>
+ <param>
+ <key>tr_chan</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>tr_delay</key>
+ <value>0.01</value>
+ </param>
+ <param>
+ <key>tr_level</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_NORM</value>
+ </param>
+ <param>
+ <key>tr_slope</key>
+ <value>qtgui.TRIG_SLOPE_POS</value>
+ </param>
+ <param>
+ <key>tr_tag</key>
+ <value>"time_est"</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>ylabel</key>
+ <value>Amplitude</value>
+ </param>
+ <param>
+ <key>yunit</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>sps+2</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1.5</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>autoscale</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>axislabels</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ctrlpanel</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>entags</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1976, 172)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0_1_0</value>
+ </param>
+ <param>
+ <key>legend</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alpha1</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color1</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker1</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha10</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color10</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker10</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha2</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color2</key>
+ <value>"red"</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker2</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha3</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color3</key>
+ <value>"green"</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker3</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha4</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color4</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker4</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha5</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color5</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>label5</key>
+ <value>Baseband</value>
+ </param>
+ <param>
+ <key>marker5</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha6</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color6</key>
+ <value>"magenta"</value>
+ </param>
+ <param>
+ <key>label6</key>
+ <value>Abs(Corr)</value>
+ </param>
+ <param>
+ <key>marker6</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha7</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color7</key>
+ <value>"yellow"</value>
+ </param>
+ <param>
+ <key>label7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker7</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha8</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color8</key>
+ <value>"dark red"</value>
+ </param>
+ <param>
+ <key>label8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker8</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha9</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color9</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>label9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>marker9</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>style9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>width9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024*3</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>baud_rate*sps</value>
+ </param>
+ <param>
+ <key>tr_chan</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>tr_delay</key>
+ <value>0.01</value>
+ </param>
+ <param>
+ <key>tr_level</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_NORM</value>
+ </param>
+ <param>
+ <key>tr_slope</key>
+ <value>qtgui.TRIG_SLOPE_POS</value>
+ </param>
+ <param>
+ <key>tr_tag</key>
+ <value></value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>ylabel</key>
+ <value>Amplitude</value>
+ </param>
+ <param>
+ <key>yunit</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>1.5</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1.5</value>
+ </param>
+ </block>
+ <block>
+ <key>rational_resampler_xxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>decim</key>
+ <value>21</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>fbw</key>
+ <value>0.45</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1472, 304)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>rational_resampler_xxx_0</value>
+ </param>
+ <param>
+ <key>interp</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>taps</key>
+ <value></value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fff</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>analog_random_source_x_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_add_xx_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_char_to_float_2</source_block_id>
+ <sink_block_id>blocks_repeat_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_float_to_char_0</source_block_id>
+ <sink_block_id>digital_map_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>4</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>3</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>2</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0_0_0_0_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_repeat_0</source_block_id>
+ <sink_block_id>rational_resampler_xxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_short_to_float_0</source_block_id>
+ <sink_block_id>blocks_float_to_char_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>blocks_short_to_float_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0_1</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_source_x_0_0_1_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_map_bb_0</source_block_id>
+ <sink_block_id>blocks_char_to_float_2</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0_0_0_0</sink_block_id>
+ <source_key>3</source_key>
+ <sink_key>3</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0_0_0_0</sink_block_id>
+ <source_key>2</source_key>
+ <sink_key>2</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0_0_0_0</sink_block_id>
+ <source_key>1</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_symbol_sync_xx_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fir_filter_xxx_0_1_0_0_0</source_block_id>
+ <sink_block_id>digital_symbol_sync_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fir_filter_xxx_0_1_0_0_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_1_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>rational_resampler_xxx_0</source_block_id>
+ <sink_block_id>fir_filter_xxx_0_1_0_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-digital/grc/digital_block_tree.xml b/gr-digital/grc/digital_block_tree.xml
index f11f27e5c3..0bea4a29e6 100644
--- a/gr-digital/grc/digital_block_tree.xml
+++ b/gr-digital/grc/digital_block_tree.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
- Copyright 2011-2016 Free Software Foundation, Inc.
+ Copyright (C) 2011-2017 Free Software Foundation, Inc.
This file is part of GNU Radio
@@ -119,6 +119,7 @@
<block>digital_mpsk_receiver_cc</block>
<block>digital_pfb_clock_sync_xxx</block>
<block>digital_pn_correlator_cc</block>
+ <block>digital_symbol_sync_xx</block>
<block>digital_corr_est_cc</block>
</cat>
<cat>
diff --git a/gr-digital/grc/digital_symbol_sync_xx.xml b/gr-digital/grc/digital_symbol_sync_xx.xml
new file mode 100644
index 0000000000..ffd2f5daff
--- /dev/null
+++ b/gr-digital/grc/digital_symbol_sync_xx.xml
@@ -0,0 +1,207 @@
+<?xml version="1.0"?>
+<!--
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+
+ This file is part of GNU Radio.
+
+ GNU Radio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Radio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Radio; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+ -->
+
+<block>
+ <name>Symbol Sync</name>
+ <key>digital_symbol_sync_xx</key>
+ <category>[Core]/Synchronizers</category>
+ <import>from gnuradio import digital</import>
+ <import>from gnuradio import filter</import>
+ <make>digital.symbol_sync_$(type)($ted_type, $sps, $loop_bw, $damping, $ted_gain, $max_dev, $osps, $constellation, $resamp_type, $nfilters, $pfb_mf_taps)</make>
+
+ <callback>set_loop_bandwidth($loop_bw)</callback>
+ <callback>set_damping_factor($damping)</callback>
+ <callback>set_ted_gain($ted_gain)</callback>
+
+ <param>
+ <name>I/O Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>Complex</name>
+ <key>cc</key>
+ <opt>input:complex</opt>
+ <opt>output:complex</opt>
+ </option>
+ <option>
+ <name>Float</name>
+ <key>ff</key>
+ <opt>input:float</opt>
+ <opt>output:float</opt>
+ </option>
+ </param>
+ <param>
+ <name>Timing Error Detector</name>
+ <key>ted_type</key>
+ <type>enum</type>
+ <option>
+ <name>Mueller and Müller</name>
+ <key>digital.TED_MUELLER_AND_MULLER</key>
+ <opt>hide_constellation:part</opt>
+ </option>
+ <option>
+ <name>Modified Mueller and Müller</name>
+ <key>digital.TED_MOD_MUELLER_AND_MULLER</key>
+ <opt>hide_constellation:part</opt>
+ </option>
+ <option>
+ <name>Zero Crossing</name>
+ <key>digital.TED_ZERO_CROSSING</key>
+ <opt>hide_constellation:part</opt>
+ </option>
+ <option>
+ <name>Gardner</name>
+ <key>digital.TED_GARDNER</key>
+ <opt>hide_constellation:all</opt>
+ </option>
+ <option>
+ <name>Early-Late</name>
+ <key>digital.TED_EARLY_LATE</key>
+ <opt>hide_constellation:all</opt>
+ </option>
+ <option>
+ <name>D'Andrea and Mengali Gen MSK</name>
+ <key>digital.TED_DANDREA_AND_MENGALI_GEN_MSK</key>
+ <opt>hide_constellation:all</opt>
+ </option>
+ <option>
+ <name>Mengali and D'Andrea GMSK</name>
+ <key>digital.TED_MENGALI_AND_DANDREA_GMSK</key>
+ <opt>hide_constellation:all</opt>
+ </option>
+ <option>
+ <name>y[n]y'[n] Maximum Likelyhood</name>
+ <key>digital.TED_SIGNAL_TIMES_SLOPE_ML</key>
+ <opt>hide_constellation:all</opt>
+ </option>
+ <option>
+ <name>sgn(y[n])y'[n] Maximum Likelyhood</name>
+ <key>digital.TED_SIGNUM_TIMES_SLOPE_ML</key>
+ <opt>hide_constellation:all</opt>
+ </option>
+ </param>
+ <param>
+ <name>TED Slicer Constellation</name>
+ <key>constellation</key>
+ <value>digital.constellation_bpsk().base()</value>
+ <type>raw</type>
+ <hide>$ted_type.hide_constellation</hide>
+ </param>
+ <param>
+ <name>Samples per Symbol</name>
+ <key>sps</key>
+ <value>sps</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Expected TED Gain</name>
+ <key>ted_gain</key>
+ <value>1.0</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Loop Bandwidth</name>
+ <key>loop_bw</key>
+ <value>0.045</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Damping Factor</name>
+ <key>damping</key>
+ <value>1.0</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Maximum Deviation</name>
+ <key>max_dev</key>
+ <value>1.5</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Output Samples/Symbol</name>
+ <key>osps</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Interpolating Resampler</name>
+ <key>resamp_type</key>
+ <type>enum</type>
+ <option>
+ <name>MMSE, 8 tap FIR</name>
+ <key>digital.IR_MMSE_8TAP</key>
+ <opt>hide_nfilters:all</opt>
+ <opt>hide_pfb_mf_taps:all</opt>
+ </option>
+ <option>
+ <name>Polyphase Filterbank, MMSE</name>
+ <key>digital.IR_PFB_NO_MF</key>
+ <opt>hide_nfilters:</opt>
+ <opt>hide_pfb_mf_taps:all</opt>
+ </option>
+ <option>
+ <name>Polyphase Filterbank, MF</name>
+ <key>digital.IR_PFB_MF</key>
+ <opt>hide_nfilters:</opt>
+ <opt>hide_pfb_mf_taps:</opt>
+ </option>
+ </param>
+ <param>
+ <name>Filterbank Arms</name>
+ <key>nfilters</key>
+ <value>128</value>
+ <type>int</type>
+ <hide>$resamp_type.hide_nfilters</hide>
+ </param>
+ <param>
+ <name>PFB MF Taps</name>
+ <key>pfb_mf_taps</key>
+ <value>[]</value>
+ <type>real_vector</type>
+ <hide>$resamp_type.hide_pfb_mf_taps</hide>
+ </param>
+
+ <sink>
+ <name>in</name>
+ <type>$type.input</type>
+ </sink>
+
+ <source>
+ <name>out</name>
+ <type>$type.output</type>
+ </source>
+ <source>
+ <name>error</name>
+ <type>float</type>
+ <optional>1</optional>
+ </source>
+ <source>
+ <name>T_inst</name>
+ <type>float</type>
+ <optional>1</optional>
+ </source>
+ <source>
+ <name>T_avg</name>
+ <type>float</type>
+ <optional>1</optional>
+ </source>
+</block>
diff --git a/gr-digital/include/gnuradio/digital/CMakeLists.txt b/gr-digital/include/gnuradio/digital/CMakeLists.txt
index 911187cee5..143f8f7e26 100644
--- a/gr-digital/include/gnuradio/digital/CMakeLists.txt
+++ b/gr-digital/include/gnuradio/digital/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2011-2016 Free Software Foundation, Inc.
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -114,6 +114,10 @@ install(FILES
simple_correlator.h
simple_framer.h
simple_framer_sync.h
+ interpolating_resampler_type.h
+ symbol_sync_cc.h
+ symbol_sync_ff.h
+ timing_error_detector_type.h
header_payload_demux.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/digital
COMPONENT "digital_devel"
diff --git a/gr-digital/include/gnuradio/digital/interpolating_resampler_type.h b/gr-digital/include/gnuradio/digital/interpolating_resampler_type.h
new file mode 100644
index 0000000000..78687a545a
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/interpolating_resampler_type.h
@@ -0,0 +1,40 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_TYPE_H
+#define INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_TYPE_H
+
+namespace gr {
+ namespace digital {
+
+ // Interpolating Resampler type
+ enum ir_type {
+ IR_NONE = -1,
+ IR_MMSE_8TAP = 0, // Valid for [-Fs/4, Fs/4] bandlimited input
+ IR_PFB_NO_MF = 1, // No matched filtering, just interpolation
+ IR_PFB_MF = 2,
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_TYPE_H */
diff --git a/gr-digital/include/gnuradio/digital/symbol_sync_cc.h b/gr-digital/include/gnuradio/digital/symbol_sync_cc.h
new file mode 100644
index 0000000000..dc856ecaf6
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/symbol_sync_cc.h
@@ -0,0 +1,316 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_SYMBOL_SYNC_CC_H
+#define INCLUDED_DIGITAL_SYMBOL_SYNC_CC_H
+
+#include <gnuradio/digital/api.h>
+#include <gnuradio/block.h>
+#include <gnuradio/digital/timing_error_detector_type.h>
+#include <gnuradio/digital/constellation.h>
+#include <gnuradio/digital/interpolating_resampler_type.h>
+
+namespace gr {
+ namespace digital {
+
+ /*!
+ * \brief Symbol Synchronizer block with complex input, complex output.
+ * \ingroup synchronizers_blk
+ *
+ * \details
+ * This implements a discrete-time error-tracking synchronizer.
+ *
+ * For this block to work properly, the input stream must meet the
+ * following requirements:
+ *
+ * 1. if not using the PFB Matched Filter interpolator, and using
+ * a non-CPM timing error detector, the input pulses must have peaks
+ * (not flat), which usually can be implemented by using a matched
+ * filter before this block.
+ *
+ * 2. for decision directed timing error detectors, the input pulses
+ * should nominally match the normalized slicer constellation, which
+ * is normalized to an average symbol magnitude of 1.0 over the entire
+ * constellation.
+ */
+ class DIGITAL_API symbol_sync_cc : virtual public block
+ {
+ public:
+ // gr::digital::symbol_sync_cc::sptr
+ typedef boost::shared_ptr<symbol_sync_cc> sptr;
+
+ /*!
+ * Make a Symbol Synchronizer block.
+ *
+ * \details
+ * This implements a discrete-time error-tracking synchronizer.
+ *
+ * For this block to work properly, the input stream must meet the
+ * following requirements:
+ *
+ * 1. if not using the PFB Matched Filter interpolator, and using
+ * a non-CPM timing error detector, the input pulses must have peaks
+ * (not flat), which usually can be implemented by using a matched
+ * filter before this block.
+ *
+ * 2. for decision directed timing error detectors, the input pulses
+ * should nominally match the normalized slicer constellation, which
+ * is normalized to an average symbol magnitude of 1.0 over the entire
+ * constellation.
+ *
+ * \param detector_type
+ * The enumerated type of timing error detector to use.
+ * See enum ted_type for a list of possible types.
+ *
+ * \param sps
+ * User specified nominal clock period in samples per symbol.
+ *
+ * \param loop_bw
+ * Approximate normailzed loop bandwidth of the symbol clock tracking
+ * loop. It should nominally be close to 0, but greater than 0. If
+ * unsure, start with a number around 2*pi*0.040, and experiment to find
+ * the value that works best for your situation.
+ *
+ * \param damping_factor
+ * Damping factor of the symbol clock tracking loop.
+ * Damping < 1.0f is an under-damped loop.
+ * Damping = 1.0f/sqrt(2.0f) is a maximally flat loop response.
+ * Damping = 1.0f is a critically-damped loop.
+ * Damping > 1.0f is an over-damped loop.
+ *
+ * \param ted_gain
+ * Expected gain of the timing error detector, given the TED in use
+ * and the anticipated input amplitude, pulse shape, and Es/No.
+ * This value is the slope of the TED's S-curve at timing offset tau = 0.
+ * This value is normally computed by the user analytically or by
+ * simulation in a tool outside of GNURadio.
+ * This value must be correct for the loop filter gains to be computed
+ * properly from the desired input loop bandwidth and damping factor.
+ *
+ * \param max_deviation
+ * Maximum absolute deviation of the average clock period estimate
+ * from the user specified nominal clock period in samples per symbol.
+ *
+ * \param osps
+ * The number of output samples per symbol (default=1).
+ *
+ * \param slicer
+ * A constellation obj shared pointer that will be used by
+ * decision directed timing error detectors to make decisions.
+ * I.e. the timing error detector will use this constellation
+ * as a slicer, if the particular algorithm needs sliced
+ * symbols.
+ *
+ * \param interp_type
+ * The enumerated type of interpolating resampler to use.
+ * See the interpolating resampler type enum for a list of possible types.
+ *
+ * \param n_filters
+ * The number of arms in the polyphase filterbank of the interpolating
+ * resampler, if using an interpolating resampler that uses a PFB.
+ *
+ * \param taps
+ * The prototype filter for the polyphase filterbank of the interpolating
+ * resampler, if using an interpolating resampler that uses a PFB.
+ */
+ static sptr make(enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor = 1.0f,
+ float ted_gain = 1.0f,
+ float max_deviation = 1.5f,
+ int osps = 1,
+ constellation_sptr slicer = constellation_sptr(),
+ ir_type interp_type = IR_MMSE_8TAP,
+ int n_filters = 128,
+ const std::vector<float> &taps = std::vector<float>());
+
+ /*!
+ * \brief Returns the normalized approximate loop bandwidth.
+ *
+ * \details
+ * See the documenation for set_loop_bandwidth() for more details.
+ *
+ * Note that if set_alpha() or set_beta() were called to directly
+ * set gains, the value returned by this method will be inaccurate/stale.
+ */
+ virtual float loop_bandwidth() const = 0;
+
+ /*!
+ * \brief Returns the loop damping factor.
+ *
+ * \details
+ * See the documenation for set_damping_factor() for more details.
+ *
+ * Note that if set_alpha() or set_beta() were called to directly
+ * set gains, the value returned by this method will be inaccurate/stale.
+ */
+ virtual float damping_factor() const = 0;
+
+ /*!
+ * \brief Returns the user provided expected gain of the Timing Error
+ * Detector.
+ *
+ * \details
+ * See the documenation for set_ted_gain() for more details.
+ */
+ virtual float ted_gain() const = 0;
+
+ /*!
+ * \brief Returns the PI filter proportional gain, alpha.
+ *
+ * \details
+ * See the documenation for set_alpha() for more details.
+ */
+ virtual float alpha() const = 0;
+
+ /*!
+ * \brief Returns the PI filter integral gain, beta.
+ *
+ * \details
+ * See the documenation for set_beta() for more details.
+ */
+ virtual float beta() const = 0;
+
+ /*!
+ * \brief Set the normalized approximate loop bandwidth.
+ *
+ * \details
+ * Set the normalized approximate loop bandwidth.
+ * Useful values are usually close to 0.0, e.g. 2*pi*0.045.
+ *
+ * It should be a small positive number, corresponding to the normalized
+ * natural radian frequency of the loop as digital low-pass filter that is
+ * filtering the clock phase/timing error.
+ *
+ * Technically this parameter corresponds to the natural radian frequency
+ * of the 2nd order loop transfer function (scaled by Fs),
+ * which is the radius of the pole locations in the s-plane of an
+ * underdamped analog 2nd order system.
+ *
+ * The input parameter corresponds to omega_n_norm in the following
+ * relation:
+ *
+ * omega_n_norm = omega_n*T = 2*pi*f_n*T = 2*pi*f_n_norm
+ *
+ * where T is the period of the clock being estimated by this
+ * clock tracking loop, and omega_n is the natural radian frequency
+ * of the 2nd order loop transfer function.
+ *
+ * When a new loop bandwidth is set, the gains, alpha and beta,
+ * of the loop are automatically recalculated.
+ *
+ * \param omega_n_norm normalized approximate loop bandwidth
+ */
+ virtual void set_loop_bandwidth (float omega_n_norm) = 0;
+
+ /*!
+ * \brief Set the loop damping factor.
+ *
+ * \details
+ * Set the damping factor of the loop.
+ * Damping in the range (0.0, 1.0) yields an under-damped loop.
+ * Damping in the range (1.0, Inf) yields an over-damped loop.
+ * Damping equal to 1.0 yields a crtically-damped loop.
+ * Damping equal to 1.0/sqrt(2.0) yields a maximally flat
+ * loop filter response.
+ *
+ * Damping factor of the 2nd order loop transfer function.
+ * When a new damping factor is set, the gains, alpha and beta,
+ * of the loop are automatcally recalculated.
+ *
+ * \param zeta loop damping factor
+ */
+ virtual void set_damping_factor (float zeta) = 0;
+
+ /*!
+ * \brief Set the expected gain of the Timing Error Detector.
+ *
+ * \details
+ * Sets the expected gain of the timing error detector, given the TED in
+ * use and the anticipated input amplitude, pulse shape, and Es/No.
+ * This value is the slope of the TED's S-curve at timing offset tau = 0.
+ * This value is normally computed by the user analytically or by
+ * simulation in a tool outside of GNURadio.
+ * This value must be correct for the loop filter gains to be computed
+ * properly from the desired input loop bandwidth and damping factor.
+ *
+ * When a new ted_gain is set, the gains, alpha and beta,
+ * of the loop are automatcally recalculated.
+ *
+ * \param ted_gain expected gain of the timing error detector
+ */
+ virtual void set_ted_gain (float ted_gain) = 0;
+
+ /*!
+ * \brief Set the PI filter proportional gain, alpha.
+ *
+ * \details
+ * Sets the PI filter proportional gain, alpha.
+ * This gain directly mutliplies the clock phase/timing error
+ * term in the PI filter when advancing the loop.
+ * It most directly affects the instantaneous clock period estimate,
+ * T_inst, and instantaneous clock phase estimate, tau.
+ *
+ * This value would normally be adjusted by setting the loop
+ * bandwidth and damping factor. However,
+ * it can be set here directly if desired.
+ *
+ * Setting this parameter directly is probably only feasible if
+ * the user is directly observing the estimates of average clock
+ * period and instantaneous clock period over time in response to
+ * an impulsive change in the input stream (i.e. watching the loop
+ * transient behavior at the start of a data burst).
+ *
+ * \param alpha PI filter proportional gain
+ */
+ virtual void set_alpha (float alpha) = 0;
+
+ /*!
+ * \brief Set the PI filter integral gain, beta.
+ *
+ * \details
+ * Sets the PI filter integral gain, beta.
+ * This gain is used when integrating the clock phase/timing error
+ * term in the PI filter when advancing the loop.
+ * It most directly affects the average clock period estimate,
+ * T_avg.
+ *
+ * This value would normally be adjusted by setting the loop
+ * bandwidth and damping factor. However,
+ * it can be set here directly if desired.
+ *
+ * Setting this parameter directly is probably only feasible if
+ * the user is directly observing the estimates of average clock
+ * period and instantaneous clock period over time in response to
+ * an impulsive change in the input stream (i.e. watching the loop
+ * transient behavior at the start of a data burst).
+ *
+ * \param beta PI filter integral gain
+ */
+ virtual void set_beta (float beta) = 0;
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_SYMBOL_SYNC_CC_H */
diff --git a/gr-digital/include/gnuradio/digital/symbol_sync_ff.h b/gr-digital/include/gnuradio/digital/symbol_sync_ff.h
new file mode 100644
index 0000000000..f551c0a96c
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/symbol_sync_ff.h
@@ -0,0 +1,316 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_SYMBOL_SYNC_FF_H
+#define INCLUDED_DIGITAL_SYMBOL_SYNC_FF_H
+
+#include <gnuradio/digital/api.h>
+#include <gnuradio/block.h>
+#include <gnuradio/digital/timing_error_detector_type.h>
+#include <gnuradio/digital/constellation.h>
+#include <gnuradio/digital/interpolating_resampler_type.h>
+
+namespace gr {
+ namespace digital {
+
+ /*!
+ * \brief Symbol Synchronizer block with float input, float output.
+ * \ingroup synchronizers_blk
+ *
+ * \details
+ * This implements a discrete-time error-tracking synchronizer.
+ *
+ * For this block to work properly, the input stream must meet the
+ * following requirements:
+ *
+ * 1. if not using the PFB Matched Filter interpolator, and using
+ * a non-CPM timing error detector, the input pulses must have peaks
+ * (not flat), which usually can be implemented by using a matched
+ * filter before this block.
+ *
+ * 2. for decision directed timing error detectors, the input pulses
+ * should nominally match the normalized slicer constellation, which
+ * is normalized to an average symbol magnitude of 1.0 over the entire
+ * constellation.
+ */
+ class DIGITAL_API symbol_sync_ff : virtual public block
+ {
+ public:
+ // gr::digital::symbol_sync_ff::sptr
+ typedef boost::shared_ptr<symbol_sync_ff> sptr;
+
+ /*!
+ * Make a Symbol Synchronizer block.
+ *
+ * \details
+ * This implements a discrete-time error-tracking synchronizer.
+ *
+ * For this block to work properly, the input stream must meet the
+ * following requirements:
+ *
+ * 1. if not using the PFB Matched Filter interpolator, and using
+ * a non-CPM timing error detector, the input pulses must have peaks
+ * (not flat), which usually can be implemented by using a matched
+ * filter before this block.
+ *
+ * 2. for decision directed timing error detectors, the input pulses
+ * should nominally match the normalized slicer constellation, which
+ * is normalized to an average symbol magnitude of 1.0 over the entire
+ * constellation.
+ *
+ * \param detector_type
+ * The enumerated type of timing error detector to use.
+ * See enum ted_type for a list of possible types.
+ *
+ * \param sps
+ * User specified nominal clock period in samples per symbol.
+ *
+ * \param loop_bw
+ * Approximate normailzed loop bandwidth of the symbol clock tracking
+ * loop. It should nominally be close to 0, but greater than 0. If
+ * unsure, start with a number around 2*pi*0.040, and experiment to find
+ * the value that works best for your situation.
+ *
+ * \param damping_factor
+ * Damping factor of the symbol clock tracking loop.
+ * Damping < 1.0f is an under-damped loop.
+ * Damping = 1.0f/sqrt(2.0f) is a maximally flat loop response.
+ * Damping = 1.0f is a critically-damped loop.
+ * Damping > 1.0f is an over-damped loop.
+ *
+ * \param ted_gain
+ * Expected gain of the timing error detector, given the TED in use
+ * and the anticipated input amplitude, pulse shape, and Es/No.
+ * This value is the slope of the TED's S-curve at timing offset tau = 0.
+ * This value is normally computed by the user analytically or by
+ * simulation in a tool outside of GNURadio.
+ * This value must be correct for the loop filter gains to be computed
+ * properly from the desired input loop bandwidth and damping factor.
+ *
+ * \param max_deviation
+ * Maximum absolute deviation of the average clock period estimate
+ * from the user specified nominal clock period in samples per symbol.
+ *
+ * \param osps
+ * The number of output samples per symbol (default=1).
+ *
+ * \param slicer
+ * A constellation obj shared pointer that will be used by
+ * decision directed timing error detectors to make decisions.
+ * I.e. the timing error detector will use this constellation
+ * as a slicer, if the particular algorithm needs sliced
+ * symbols.
+ *
+ * \param interp_type
+ * The enumerated type of interpolating resampler to use.
+ * See the interpolating resampler type enum for a list of possible types.
+ *
+ * \param n_filters
+ * The number of arms in the polyphase filterbank of the interpolating
+ * resampler, if using an interpolating resampler that uses a PFB.
+ *
+ * \param taps
+ * The prototype filter for the polyphase filterbank of the interpolating
+ * resampler, if using an interpolating resampler that uses a PFB.
+ */
+ static sptr make(enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor = 1.0f,
+ float ted_gain = 1.0f,
+ float max_deviation = 1.5f,
+ int osps = 1,
+ constellation_sptr slicer = constellation_sptr(),
+ ir_type interp_type = IR_MMSE_8TAP,
+ int n_filters = 128,
+ const std::vector<float> &taps = std::vector<float>());
+
+ /*!
+ * \brief Returns the normalized approximate loop bandwidth.
+ *
+ * \details
+ * See the documenation for set_loop_bandwidth() for more details.
+ *
+ * Note that if set_alpha() or set_beta() were called to directly
+ * set gains, the value returned by this method will be inaccurate/stale.
+ */
+ virtual float loop_bandwidth() const = 0;
+
+ /*!
+ * \brief Returns the loop damping factor.
+ *
+ * \details
+ * See the documenation for set_damping_factor() for more details.
+ *
+ * Note that if set_alpha() or set_beta() were called to directly
+ * set gains, the value returned by this method will be inaccurate/stale.
+ */
+ virtual float damping_factor() const = 0;
+
+ /*!
+ * \brief Returns the user provided expected gain of the Timing Error
+ * Detector.
+ *
+ * \details
+ * See the documenation for set_ted_gain() for more details.
+ */
+ virtual float ted_gain() const = 0;
+
+ /*!
+ * \brief Returns the PI filter proportional gain, alpha.
+ *
+ * \details
+ * See the documenation for set_alpha() for more details.
+ */
+ virtual float alpha() const = 0;
+
+ /*!
+ * \brief Returns the PI filter integral gain, beta.
+ *
+ * \details
+ * See the documenation for set_beta() for more details.
+ */
+ virtual float beta() const = 0;
+
+ /*!
+ * \brief Set the normalized approximate loop bandwidth.
+ *
+ * \details
+ * Set the normalized approximate loop bandwidth.
+ * Useful values are usually close to 0.0, e.g. 2*pi*0.045.
+ *
+ * It should be a small positive number, corresponding to the normalized
+ * natural radian frequency of the loop as digital low-pass filter that is
+ * filtering the clock phase/timing error.
+ *
+ * Technically this parameter corresponds to the natural radian frequency
+ * of the 2nd order loop transfer function (scaled by Fs),
+ * which is the radius of the pole locations in the s-plane of an
+ * underdamped analog 2nd order system.
+ *
+ * The input parameter corresponds to omega_n_norm in the following
+ * relation:
+ *
+ * omega_n_norm = omega_n*T = 2*pi*f_n*T = 2*pi*f_n_norm
+ *
+ * where T is the period of the clock being estimated by this
+ * clock tracking loop, and omega_n is the natural radian frequency
+ * of the 2nd order loop transfer function.
+ *
+ * When a new loop bandwidth is set, the gains, alpha and beta,
+ * of the loop are automatically recalculated.
+ *
+ * \param omega_n_norm normalized approximate loop bandwidth
+ */
+ virtual void set_loop_bandwidth (float omega_n_norm) = 0;
+
+ /*!
+ * \brief Set the loop damping factor.
+ *
+ * \details
+ * Set the damping factor of the loop.
+ * Damping in the range (0.0, 1.0) yields an under-damped loop.
+ * Damping in the range (1.0, Inf) yields an over-damped loop.
+ * Damping equal to 1.0 yields a crtically-damped loop.
+ * Damping equal to 1.0/sqrt(2.0) yields a maximally flat
+ * loop filter response.
+ *
+ * Damping factor of the 2nd order loop transfer function.
+ * When a new damping factor is set, the gains, alpha and beta,
+ * of the loop are automatcally recalculated.
+ *
+ * \param zeta loop damping factor
+ */
+ virtual void set_damping_factor (float zeta) = 0;
+
+ /*!
+ * \brief Set the expected gain of the Timing Error Detector.
+ *
+ * \details
+ * Sets the expected gain of the timing error detector, given the TED in
+ * use and the anticipated input amplitude, pulse shape, and Es/No.
+ * This value is the slope of the TED's S-curve at timing offset tau = 0.
+ * This value is normally computed by the user analytically or by
+ * simulation in a tool outside of GNURadio.
+ * This value must be correct for the loop filter gains to be computed
+ * properly from the desired input loop bandwidth and damping factor.
+ *
+ * When a new ted_gain is set, the gains, alpha and beta,
+ * of the loop are automatcally recalculated.
+ *
+ * \param ted_gain expected gain of the timing error detector
+ */
+ virtual void set_ted_gain (float ted_gain) = 0;
+
+ /*!
+ * \brief Set the PI filter proportional gain, alpha.
+ *
+ * \details
+ * Sets the PI filter proportional gain, alpha.
+ * This gain directly mutliplies the clock phase/timing error
+ * term in the PI filter when advancing the loop.
+ * It most directly affects the instantaneous clock period estimate,
+ * T_inst, and instantaneous clock phase estimate, tau.
+ *
+ * This value would normally be adjusted by setting the loop
+ * bandwidth and damping factor. However,
+ * it can be set here directly if desired.
+ *
+ * Setting this parameter directly is probably only feasible if
+ * the user is directly observing the estimates of average clock
+ * period and instantaneous clock period over time in response to
+ * an impulsive change in the input stream (i.e. watching the loop
+ * transient behavior at the start of a data burst).
+ *
+ * \param alpha PI filter proportional gain
+ */
+ virtual void set_alpha (float alpha) = 0;
+
+ /*!
+ * \brief Set the PI filter integral gain, beta.
+ *
+ * \details
+ * Sets the PI filter integral gain, beta.
+ * This gain is used when integrating the clock phase/timing error
+ * term in the PI filter when advancing the loop.
+ * It most directly affects the average clock period estimate,
+ * T_avg.
+ *
+ * This value would normally be adjusted by setting the loop
+ * bandwidth and damping factor. However,
+ * it can be set here directly if desired.
+ *
+ * Setting this parameter directly is probably only feasible if
+ * the user is directly observing the estimates of average clock
+ * period and instantaneous clock period over time in response to
+ * an impulsive change in the input stream (i.e. watching the loop
+ * transient behavior at the start of a data burst).
+ *
+ * \param beta PI filter integral gain
+ */
+ virtual void set_beta (float beta) = 0;
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_SYMBOL_SYNC_FF_H */
diff --git a/gr-digital/include/gnuradio/digital/timing_error_detector_type.h b/gr-digital/include/gnuradio/digital/timing_error_detector_type.h
new file mode 100644
index 0000000000..e2bc51e80e
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/timing_error_detector_type.h
@@ -0,0 +1,46 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_TIMING_ERROR_DETECTOR_TYPE_H
+#define INCLUDED_DIGITAL_TIMING_ERROR_DETECTOR_TYPE_H
+
+namespace gr {
+ namespace digital {
+
+ // Timing Error Detector types.
+ enum ted_type {
+ TED_NONE = -1,
+ TED_MUELLER_AND_MULLER = 0, // Decision directed
+ TED_MOD_MUELLER_AND_MULLER = 1, // Decision directed
+ TED_ZERO_CROSSING = 2, // Decision directed
+ TED_GARDNER = 4,
+ TED_EARLY_LATE = 5,
+ TED_DANDREA_AND_MENGALI_GEN_MSK = 6, // Operates on the CPM signal
+ TED_SIGNAL_TIMES_SLOPE_ML = 7, // ML approx. for small signal
+ TED_SIGNUM_TIMES_SLOPE_ML = 8, // ML approx. for large signal
+ TED_MENGALI_AND_DANDREA_GMSK = 9, // Operates on the CPM signal
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_TIMING_ERROR_DETECTOR_TYPE_H */
diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt
index 9df6808d1c..1fcae4713a 100644
--- a/gr-digital/lib/CMakeLists.txt
+++ b/gr-digital/lib/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2011-2016 Free Software Foundation, Inc.
+# Copyright (C) 2011-2016,2017 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -54,6 +54,7 @@ list(APPEND digital_sources
binary_slicer_fb_impl.cc
clock_recovery_mm_cc_impl.cc
clock_recovery_mm_ff_impl.cc
+ clock_tracking_loop.cc
cma_equalizer_cc_impl.cc
constellation.cc
constellation_decoder_cb_impl.cc
@@ -127,6 +128,10 @@ list(APPEND digital_sources
scrambler_bb_impl.cc
simple_correlator_impl.cc
simple_framer_impl.cc
+ interpolating_resampler.cc
+ symbol_sync_cc_impl.cc
+ symbol_sync_ff_impl.cc
+ timing_error_detector.cc
)
#Add Windows DLL resource file if using MSVC
diff --git a/gr-digital/lib/clock_tracking_loop.cc b/gr-digital/lib/clock_tracking_loop.cc
new file mode 100644
index 0000000000..51a1db9e71
--- /dev/null
+++ b/gr-digital/lib/clock_tracking_loop.cc
@@ -0,0 +1,333 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2011,2013,2016-2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clock_tracking_loop.h"
+#include <gnuradio/math.h>
+#include <stdexcept>
+
+namespace gr {
+ namespace digital {
+
+ clock_tracking_loop::clock_tracking_loop(float loop_bw,
+ float max_period, float min_period,
+ float nominal_period,
+ float damping,
+ float ted_gain)
+ : d_avg_period(nominal_period),
+ d_max_avg_period(max_period),
+ d_min_avg_period(min_period),
+ d_nom_avg_period(nominal_period),
+ d_inst_period(nominal_period),
+ d_phase(0.0f),
+ d_zeta(damping),
+ d_omega_n_norm(loop_bw),
+ d_ted_gain(ted_gain),
+ d_alpha(0.0f),
+ d_beta(0.0f),
+ d_prev_avg_period(nominal_period),
+ d_prev_inst_period(nominal_period),
+ d_prev_phase(0.0f)
+ {
+ set_max_avg_period(max_period);
+ set_min_avg_period(min_period);
+ set_nom_avg_period(nominal_period);
+
+ set_avg_period(d_nom_avg_period);
+ set_inst_period(d_nom_avg_period);
+
+ if (d_zeta < 0.0f)
+ throw std::out_of_range (
+ "clock_tracking_loop: damping factor must be > 0.0");
+
+ if (d_omega_n_norm < 0.0f)
+ throw std::out_of_range (
+ "clock_tracking_loop: loop bandwidth must be greater than 0.0");
+
+ if (d_ted_gain <= 0.0f)
+ throw std::out_of_range (
+ "clock_tracking_loop: expected ted gain must be greater than 0.0");
+
+ update_gains();
+ }
+
+ clock_tracking_loop::~clock_tracking_loop()
+ {
+ }
+
+ void
+ clock_tracking_loop::update_gains()
+ {
+ float omega_n_T, omega_d_T, zeta_omega_n_T, cosx_omega_d_T;
+ float k0, k1, sinh_zeta_omega_n_T;
+ float alpha, beta;
+
+ omega_n_T = d_omega_n_norm;
+ zeta_omega_n_T = d_zeta * omega_n_T;
+ k0 = 2.0f/d_ted_gain;
+ k1 = expf(-zeta_omega_n_T);
+ sinh_zeta_omega_n_T = sinhf(zeta_omega_n_T);
+
+ if (d_zeta > 1.0f) { // Over-damped (or critically-damped too)
+
+ omega_d_T = omega_n_T * sqrtf(d_zeta * d_zeta - 1.0f);
+ cosx_omega_d_T = coshf(omega_d_T);
+ // cosh ---------^^^^
+
+ } else if (d_zeta == 1.0f) { // Critically-damped
+
+ omega_d_T = 0.0f;
+ cosx_omega_d_T = 1.0f;
+ // cosh(omega_d_T) & cos(omega_d_T) are both 1 for omega_d_T == 0
+
+ } else { // Under-damped (or critically-damped too)
+
+ omega_d_T = omega_n_T * sqrtf(1.0 - d_zeta * d_zeta);
+ cosx_omega_d_T = cosf(omega_d_T);
+ // cos ----------^^^
+ }
+
+ alpha = k0 * k1 * sinh_zeta_omega_n_T;
+ beta = k0 * (1 - k1*(sinh_zeta_omega_n_T + cosx_omega_d_T));
+
+ set_alpha(alpha);
+ set_beta(beta);
+ }
+
+ void
+ clock_tracking_loop::advance_loop(float error)
+ {
+ // So the loop can be reverted one step, if needed.
+ d_prev_avg_period = d_avg_period;
+ d_prev_inst_period = d_inst_period;
+ d_prev_phase = d_phase;
+
+ // Integral arm of PI filter
+ d_avg_period = d_avg_period + d_beta * error;
+ // Proportional arm of PI filter and final sum of PI filter arms
+ d_inst_period = d_avg_period + d_alpha * error;
+ // Compute the new, unwrapped clock phase
+ d_phase = d_phase + d_inst_period;
+ }
+
+ void
+ clock_tracking_loop::revert_loop()
+ {
+ d_avg_period = d_prev_avg_period;
+ d_inst_period = d_prev_inst_period;
+ d_phase = d_prev_phase;
+ }
+
+ void
+ clock_tracking_loop::phase_wrap()
+ {
+ float period = d_avg_period; // One could argue d_inst_period instead
+ float limit = period/2.0f;
+
+ while (d_phase > limit)
+ d_phase -= period;
+
+ while (d_phase <= -limit)
+ d_phase += period;
+ }
+
+ void
+ clock_tracking_loop::period_limit()
+ {
+ if (d_avg_period > d_max_avg_period)
+ d_avg_period = d_max_avg_period;
+ else if (d_avg_period < d_min_avg_period)
+ d_avg_period = d_min_avg_period;
+ }
+
+ /*******************************************************************
+ * SET FUNCTIONS
+ *******************************************************************/
+
+ void
+ clock_tracking_loop::set_loop_bandwidth(float bw)
+ {
+ if (bw < 0.0f)
+ throw std::out_of_range (
+ "clock_tracking_loop: loop bandwidth must be greater than 0.0");
+
+ d_omega_n_norm = bw;
+ update_gains();
+ }
+
+ void
+ clock_tracking_loop::set_damping_factor(float df)
+ {
+ if (df < 0.0f)
+ throw std::out_of_range (
+ "clock_tracking_loop: damping factor must be > 0.0");
+
+ d_zeta = df;
+ update_gains();
+ }
+
+ void
+ clock_tracking_loop::set_ted_gain(float ted_gain)
+ {
+ if (ted_gain <= 0.0f)
+ throw std::out_of_range (
+ "clock_tracking_loop: expected ted gain must be > 0.0");
+
+ d_ted_gain = ted_gain;
+ update_gains();
+ }
+
+ void
+ clock_tracking_loop::set_alpha(float alpha)
+ {
+ d_alpha = alpha;
+ }
+
+ void
+ clock_tracking_loop::set_beta(float beta)
+ {
+ d_beta = beta;
+ }
+
+ void
+ clock_tracking_loop::set_avg_period(float period)
+ {
+ d_avg_period = period;
+ d_prev_avg_period = period;
+ }
+
+ void
+ clock_tracking_loop::set_inst_period(float period)
+ {
+ d_inst_period = period;
+ d_prev_inst_period = period;
+ }
+
+ void
+ clock_tracking_loop::set_phase(float phase)
+ {
+ // This previous phase is likely inconsistent with the tracking,
+ // but if the caller is setting the phase, the odds of
+ // revert_loop() being called are slim.
+ d_prev_phase = phase;
+
+ d_phase = phase;
+ }
+
+ void
+ clock_tracking_loop::set_max_avg_period(float period)
+ {
+ d_max_avg_period = period;
+ }
+
+ void
+ clock_tracking_loop::set_min_avg_period(float period)
+ {
+ d_min_avg_period = period;
+ }
+
+ void
+ clock_tracking_loop::set_nom_avg_period(float period)
+ {
+ if (period < d_min_avg_period or
+ period > d_max_avg_period ) {
+ d_nom_avg_period = (d_max_avg_period + d_min_avg_period)/2.0f;
+ } else {
+ d_nom_avg_period = period;
+ }
+ }
+
+ /*******************************************************************
+ * GET FUNCTIONS
+ *******************************************************************/
+
+ float
+ clock_tracking_loop::get_loop_bandwidth() const
+ {
+ return d_omega_n_norm;
+ }
+
+ float
+ clock_tracking_loop::get_damping_factor() const
+ {
+ return d_zeta;
+ }
+
+ float
+ clock_tracking_loop::get_ted_gain() const
+ {
+ return d_ted_gain;
+ }
+
+ float
+ clock_tracking_loop::get_alpha() const
+ {
+ return d_alpha;
+ }
+
+ float
+ clock_tracking_loop::get_beta() const
+ {
+ return d_beta;
+ }
+
+ float
+ clock_tracking_loop::get_avg_period() const
+ {
+ return d_avg_period;
+ }
+
+ float
+ clock_tracking_loop::get_inst_period() const
+ {
+ return d_inst_period;
+ }
+
+ float
+ clock_tracking_loop::get_phase() const
+ {
+ return d_phase;
+ }
+
+ float
+ clock_tracking_loop::get_max_avg_period() const
+ {
+ return d_max_avg_period;
+ }
+
+ float
+ clock_tracking_loop::get_min_avg_period() const
+ {
+ return d_min_avg_period;
+ }
+
+ float
+ clock_tracking_loop::get_nom_avg_period() const
+ {
+ return d_nom_avg_period;
+ }
+
+ } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/clock_tracking_loop.h b/gr-digital/lib/clock_tracking_loop.h
new file mode 100644
index 0000000000..1a20713c48
--- /dev/null
+++ b/gr-digital/lib/clock_tracking_loop.h
@@ -0,0 +1,781 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2011,2013,2016-2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_CLOCK_TRACKING_LOOP_H
+#define INCLUDED_DIGITAL_CLOCK_TRACKING_LOOP_H
+
+namespace gr {
+ namespace digital {
+
+ /*!
+ * \brief A second-order control loop implementation class.
+ *
+ * \details
+ * This class implements most of a second order symbol clock
+ * tracking loop and is inteded to act as a parent class to blocks
+ * which need a symbol clock tracking loop to determine the optimal
+ * instant to sample a received symbol from an input sample
+ * stream (i.e. *_clock_recovery* and *_clock_sync* blocks).
+ * It takes in an expected timing error detector gain, a normalized loop
+ * bandwidth and damping factor, as well as clock period bounds, and
+ * provides the functions that control the update of the loop.
+ *
+ * This control loop runs at the rate of the output clock, so
+ * each step of the loop produces estimates about the output clock,
+ * and the clock phase/timing error input must come at a rate of
+ * once per output clock.
+ *
+ * This class does not include a timing error detector, and the
+ * caller is expected to provide the clock phase/timing error input
+ * for each step of the loop.
+ *
+ * The loop's low pass filter is a Proportional-Integral (PI) filter.
+ * The proportional and integral gains of the filter are termed alpha
+ * and beta respectively. These gains are calculated using the input
+ * expected timing error detector gain, loop bandwidth and damping factor.
+ * If needed, the alpha and beta gain values can be set using their
+ * respective #set_alpha or #set_beta functions.
+ *
+ * The class estimates the average clock period, T_avg; the instantaneous
+ * clock period, T_inst; and the instantaneous clock phase, tau; of a
+ * symbol clock based on an error signal from an external clock phase/
+ * timing error detector which provides one error signal sample per
+ * clock (one error sample at the end of every T_inst clock cycle).
+ * The error calculation is unique for each TED algorithm and is
+ * calculated externally and passed to the advance_loop function,
+ * which uses this to update its estimates.
+ *
+ * This class also provides the functions #phase_wrap and
+ * #period_limit to easily keep the clock phase estimate, tau, and the
+ * average clock period estimate, T_avg, within set bounds (phase_wrap
+ * keeps the phase within +/-T_avg/2).
+ *
+ * The clock tracking loop, with its PI filter, when properly implemented, has
+ * a digital loop phase-transfer function, in terms of the timing error
+ * detector gain, \f$K_{ted}\f$; proportional gain, \f$\alpha\f$; and the
+ * integral gain, \f$\beta\f$, as follows:
+ *
+ * \f{align*}
+ * H(z) &= \dfrac {\Theta_o(z)}{\Theta_i(z)}
+ * = K_{ted}(\alpha + \beta)z^{-1} \cdot
+ * \dfrac{
+ * 1
+ * - \dfrac{\alpha}{\alpha + \beta} z^{-1}
+ * }
+ * {
+ * 1
+ * - 2 \left(1 - K_{ted}\dfrac{\alpha + \beta}{2}\right) z^{-1}
+ * + (1 - K_{ted}\alpha) z^{-2}
+ * } \\
+ * \f}
+ *
+ * Mapping the above phase-transfer function to the standard form of a transfer
+ * function for an analog second order control loop mapped to the digital domain
+ * with the mapping \f$z = e^{sT}\f$ applied to the s-plane poles,
+ * \f$s_{1,2} = -\zeta\omega_{n} \pm \omega_{n}\sqrt{\zeta^{2}-1}\f$, one obtains an
+ * alternate form of the transfer function, directly related to the damping factor
+ * \f$\zeta\f$, the natural radian frequency \f$\omega_{n}\f$, the damped radian frequency
+ * of oscillation \f$\omega_{d}\f$, and the symbol clock period \f$T\f$:
+ *
+ * \f{align*}
+ * H(z) &=
+ * \begin{cases}
+ * \dfrac{
+ * [2 -2\cos(\omega_{d}T)e^{-\zeta\omega_{n}T}] z
+ * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T}
+ * }
+ * {
+ * z^{2}
+ * - 2 \cos(\omega_{d}T) e^{-\zeta\omega_{n}T} z
+ * + e^{-2\zeta\omega_{n}T}
+ * }
+ * & \quad \text{for} \quad \zeta < 1 \quad \text{with}
+ * \quad \omega_{d}T = \omega_{n}T \sqrt{1 - \zeta^{2}}
+ * \\
+ * \\
+ * \dfrac{
+ * [2 -2(1)e^{-\zeta\omega_{n}T}] z
+ * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T}
+ * }
+ * {
+ * z^{2}
+ * - 2(1)e^{-\zeta\omega_{n}T} z
+ * + e^{-2\zeta\omega_{n}T}
+ * }
+ * & \quad \text{for} \quad \zeta = 1 \quad \text{with}
+ * \quad \omega_{d}T = 0
+ * \\
+ * \\
+ * \dfrac{
+ * [2 -2\cosh(\omega_{d}T)e^{-\zeta\omega_{n}T}] z
+ * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T}
+ * }
+ * {
+ * z^{2}
+ * - 2 \cosh(\omega_{d}T) e^{-\zeta\omega_{n}T} z
+ * + e^{-2\zeta\omega_{n}T}
+ * }
+ * & \quad \text{for} \quad \zeta > 1 \quad \text{with}
+ * \quad \omega_{d}T = \omega_{n}T \sqrt{\zeta^{2} - 1}
+ * \\
+ * \end{cases}
+ * \\
+ * \f}
+ *
+ * The PI filter gains, expressed in terms of the damping factor, \f$\zeta\f$;
+ * the natural radian frequency, \f$\omega_{n}\f$; the damped radian frequency of
+ * oscillation, \f$\omega_{d}\f$; the timing error detector gain \f$K_{ted}\f$;
+ * and the clock period \f$T\f$ are:
+ *
+ * \f{align*}
+ * \alpha &= \dfrac{2}{K_{ted}}e^{-\zeta\omega_{n}T} \sinh(\zeta\omega_{n}T) \\
+ * \\
+ * \beta &=
+ * \begin{cases}
+ * \dfrac{2}{K_{ted}} \left(1 -
+ * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + \cos(\omega_{d}T)]
+ * \right) &
+ * \text{for} \quad \zeta < 1 \quad (under \: damped)\\ \\
+ * \dfrac{2}{K_{ted}} \left(1 -
+ * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + 1]
+ * \right) &
+ * \text{for} \quad \zeta = 1 \quad (critically \: damped)\\ \\
+ * \dfrac{2}{K_{ted}} \left(1 -
+ * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) +\cosh(\omega_{d}T)]
+ * \right) &
+ * \text{for} \quad \zeta > 1 \quad (over \: damped)\\
+ * \end{cases} \\
+ * \\
+ * \f}
+ *
+ * It should be noted that the clock period \f$T\f$ is being estimated by the clock
+ * tracking loop and can vary over time, so that setting the loop bandwidth
+ * directly can be a problem. However, we specify loop bandwidth in terms
+ * of the normalized digital natural radian frequency \f$\omega_{n\_norm}\f$ of the loop.
+ * \f$\omega_{n\_norm}\f$ can only usefully be a small positive number, close to
+ * zero. The damping factor, \f$\zeta\f$, dictates the maximum value
+ * \f$\omega_{n\_norm}\f$ can practically take on. In the extreme a case of
+ * \f$\zeta = 0.0\f$, \f$\omega_{n\_norm}\f$ is practically limited to the range
+ * \f$(0, \pi)\f$, as \f$\pi\f$ then corresponds to the Nyquist frequency
+ * of the clock. However, whatever the damping factor, large values of
+ * \f$\omega_{n\_norm}\f$ are usually not useful and yield poor results.
+ *
+ * \f{align*}
+ * \omega_{n}T = \omega_{n\_norm} = 2 \pi f_{n\_norm} = 2 \pi f_{n} T =
+ * \pi \dfrac{f_{n}}{\left(\dfrac{F_{c}}{2}\right)}
+ * \f}
+ *
+ * In practice, the timing error detector (TED) of the symbol clock
+ * tracking loop is implemented with an estimator of symbol clock phase
+ * error, which has some gain \f$K_{ted}\f$. The gain, \f$K_{ted}\f$, is
+ * defined as the slope of a TED's S-curve plot at a symbol clock phase
+ * offset of \f$\tau = 0\f$. The S-curve shape and central slope, and
+ * hence the gain \f$K_{ted}\f$, depend on the TED's estimator espression,
+ * the input signal level, the pulse shaping filter, and the \f$E_s/N_0\f$
+ * of the incomping signal. The user must determine the TED's
+ * S-curve by analysis or simulation of the particular situation, in order
+ * to determine an appropriate value for \f$K_{ted}\f$.
+ *
+ * * A note on symbol clock phase vs. interpolating resampler sample phase,
+ * since most GNURadio symbol synchronization blocks seem to have the same
+ * implementation error:
+ *
+ * In general, the symbol clock phase, that the symbol clock tracking loop
+ * estimates and tracks, cannot be used alone to derive the interpolating resampler
+ * sample phase used in symbol synchronization, except in the very special case of
+ * the symbol clock period being exactly divisible by the input sample stream
+ * sample period. Since this is never guaranteed in tracking real symbol clocks,
+ * one should not use the symbol clock phase alone to compute the interpolating
+ * resampler sample phase.
+ *
+ * Consider, in the analog time domain, the optimum symbol sampling instants
+ * \f$t_{k}\f$, of an analog input signal \f$x(t)\f$, at an optimal symbol clock
+ * phase \f$\tau_{0}\f$ and the symbol clock period \f$T_{c}\f$:
+ *
+ * \f{align*}
+ * t_{k} &= \tau_{0} + k T_{c} \\
+ * y_{k} &= x(t_{k}) = x(\tau_{0} + k T_{c}) \\
+ * \f}
+ *
+ * If one divides the \f$t_{k}\f$ times by the input sample stream sample period
+ * \f$T_{i}\f$, the correct interpolating resampler sample phase \f$\tau_{0\_i}\f$ will
+ * get a contribution from the term \f$T_{c\_remainder}\f$ (which is an error) as shown
+ * below:
+ *
+ * \f{align*}
+ * \dfrac{t_{k}}{T_{i}} &= \dfrac{\tau_{0}}{T_{i}} + \dfrac{k T_{c}}{T_{i}} \\
+ * &= (m + \tau_{0\_remainder}) + (n + T_{c\_remainder}) \\
+ * &= \tau_{0\_remainder} + T_{c\_remainder} + (m + n) \\
+ * &= \tau_{0\_i} + k^{\prime}
+ * \f}
+ *
+ * So instead of using the symbol clock sample phase alone to obtain the
+ * interpolating resampler sample phase, one should use the previous interpolating
+ * resampler sample phase and the instantaneous clock period estimate provided by
+ * the symbol clock tracking loop.
+ *
+ */
+ class clock_tracking_loop
+ {
+ protected:
+ // Estimate of the average clock period, T_avg, in units of
+ // input sample clocks (so this is the average number of
+ // input samples per output symbol, aka samples/symbol).
+ // To convert to seconds, divide by the input sample rate: F_s_input.
+ float d_avg_period;
+
+ // Limits on how far the average clock period estimate can wander,
+ // and the nominal average clock period, in units of input sample clocks.
+ // To convert to seconds, divide by the input sample rate: F_s_input.
+ float d_max_avg_period, d_min_avg_period;
+ float d_nom_avg_period;
+
+ // Instantaneous clock period estimate, T_inst, in units of
+ // input sample clocks (so this is the intantaneous number of
+ // input samples per output symbol, aka instantaneous samples/symbol).
+ // To convert to seconds, divide by the input sample rate: F_s_input.
+ float d_inst_period;
+
+ // Instantaneous clock phase estimate, tau, in units of
+ // input sample clocks.
+ // To convert to seconds, divide by the input sample rate: F_s_input.
+ // To wrap, add or subtract a multiple of the estimate of the
+ // average clock period, T_avg.
+ // To convert to a normalized (but not wrapped) clock phase estimate,
+ // divide by the estimate of the average clock period, T_avg.
+ // To further convert the normalized clock phase estimate to radians,
+ // multiply the normalized clock phase estimate by 2*pi.
+ float d_phase;
+
+ // Damping factor of the 2nd order loop transfer function.
+ // Zeta in the range (0.0, 1.0) yields an under-damped loop.
+ // Zeta in the range (1.0, Inf) yields an over-damped loop.
+ // Zeta equal to 1.0 yields a crtically-damped loop.
+ float d_zeta;
+
+ // Normalized natural radian frequency of the 2nd order loop transfer
+ // function. It should be a small positive number, corresponding to
+ // the normalized natural radian frequency of the loop as digital
+ // low-pass filter that is filtering the clock phase/timing error signal.
+ // omega_n_norm = omega_n*T = 2*pi*f_n*T = 2*pi*f_n_norm
+ float d_omega_n_norm;
+
+ // Expected gain of the timing error detector in use, given the
+ // TED estimator expression, the expected input amplitude, the
+ // input pulse shape, and the expected input Es/No. (This value is the
+ // slope of the TED's S-curve plot at a timing offset of tau = 0, and
+ // must be determined by analysis and/or simulation by the user.)
+ float d_ted_gain;
+
+ // Proportional gain of the PI loop filter (aka gain_mu)
+ // (aka gain_mu in some clock recovery blocks)
+ float d_alpha;
+
+ // Integral gain of the PI loop filter
+ // (aka gain_omega in some clock recovery blocks)
+ float d_beta;
+
+ // For reverting the loop state one iteration (only)
+ float d_prev_avg_period;
+ float d_prev_inst_period;
+ float d_prev_phase;
+
+ public:
+ clock_tracking_loop(void) {}
+
+ /*! \brief Construct a clock_tracking_loop object.
+ *
+ * \details
+ * This function instantiates a clock_tracking_loop object.
+ *
+ * \param loop_bw
+ * Normalized approximate loop bandwidth.
+ * It should be a small positive number, corresponding to the normalized
+ * natural radian frequency of the loop as digital low-pass filter that is
+ * filtering the clock phase/timing error.
+ *
+ * Technically this parameter corresponds to the natural radian frequency
+ * of the 2nd order loop transfer function (scaled by Fs),
+ * which is the radius of the pole locations in the s-plane of an
+ * underdamped analog 2nd order system.
+ *
+ * \param max_period
+ * Maximum limit for the estimated clock period, in units of
+ * input stream sample periods. (i.e. maximum samples/symbol)
+ *
+ * \param min_period
+ * Minimum limit for the estimated clock period, in units of
+ * input stream sample periods. (i.e. minimum samples/symbol)
+ *
+ * \param nominal_period
+ * Nominal value for the estimated clock period, in units of
+ * input stream sample periods. (i.e. nominal samples/symbol)
+ * If not specified, this value will be set to the average of
+ * min_period and max_period,
+ *
+ * \param damping
+ * Damping factor of the 2nd order loop transfer function.
+ * Damping in the range (0.0, 1.0) yields an under-damped loop.
+ * Damping in the range (1.0, Inf) yields an over-damped loop.
+ * Damping equal to 1.0 yields a crtically-damped loop.
+ * Under-damped loops are not generally useful for clock tracking.
+ * This parameter defaults to 1.0, if not specified.
+ *
+ * \param ted_gain
+ * Expected gain of the timing error detector, given the TED in use
+ * and the anticipated input amplitude, pulse shape, and Es/No.
+ * This value is the slope of the TED's S-curve at timing offset tau = 0.
+ * This value is normally computed by the user analytically or by
+ * simulation in a tool outside of GNURadio.
+ * This value must be correct for the loop filter gains to be computed
+ * properly from the desired input loop bandwidth and damping factor.
+ * This parameter defaults to 1.0, if not specified.
+ */
+ clock_tracking_loop(float loop_bw,
+ float max_period, float min_period,
+ float nominal_period = 0.0f,
+ float damping = 1.0f,
+ float ted_gain = 1.0f);
+
+ virtual ~clock_tracking_loop();
+
+ /*! \brief Update the gains from the ted_gain, loop bw and damping factor.
+ *
+ * \details
+ * This function updates the gains based on the loop
+ * bandwidth and damping factor of the system. These two
+ * factors can be set separately through their own set
+ * functions.
+ */
+ void update_gains();
+
+ /*! \brief Advance the loop based on the current gain
+ * settings and the input error signal.
+ */
+ void advance_loop(float error);
+
+ /*! \brief Undo a single, prior advance_loop() call.
+ *
+ * \details
+ * Reverts a single, prior call to advance_loop().
+ * It cannot usefully called again, until after the next call
+ * to advance_loop().
+ *
+ * This method is needed so clock recovery/sync blocks can
+ * perform correctly given the constraints of GNURadio's streaming
+ * engine, interpolation filtering, and tag propagation.
+ */
+ void revert_loop();
+
+ /*! \brief
+ * Keep the clock phase estimate, tau, between -T_avg/2 and T_avg/2.
+ *
+ * \details
+ * This function keeps the clock phase estimate, tau, between
+ * -T_avg/2 and T_avg/2, by wrapping it modulo the estimated
+ * average clock period, T_avg. (N.B. Wrapping an estimated phase
+ * by an *estimated*, *average* period.)
+ *
+ * This function can be called after advance_loop to keep the
+ * phase value small. It is set as a separate method in case
+ * another way is desired as this is fairly heavy-handed.
+ * Clock recovery/sync blocks usually do not need the phase of the
+ * clock, and this class doesn't actually use the phase at all,
+ * so calling this is optional.
+ */
+ void phase_wrap();
+
+ /*! \brief
+ * Keep the estimated average clock period, T_avg, between T_avg_min
+ * and T_avg_max.
+ *
+ * \details
+ * This function keeps the estimated average clock period, T_avg,
+ * between T_avg_min and T_avg_max. It accomplishes this by hard limiting.
+ * This is needed because T_avg is essentially computed by the
+ * integrator portion of an IIR filter, so T_avg could potentially
+ * wander very far during periods of noise/nonsense input.
+ *
+ * This function should be called after advance_loop to keep the
+ * estimated average clock period, T_avg, in the specified range.
+ * It is set as a separate method in case another way is desired as
+ * this is fairly heavy-handed.
+ */
+ void period_limit();
+
+ /*******************************************************************
+ * SET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Set the normalized approximate loop bandwidth.
+ *
+ * \details
+ * Set the normalized approximate loop bandwidth.
+ * Useful values are usually close to 0.0, e.g. 2*pi*0.045.
+ *
+ * It should be a small positive number, corresponding to the normalized
+ * natural radian frequency of the loop as digital low-pass filter that is
+ * filtering the clock phase/timing error.
+ *
+ * Technically this parameter corresponds to the natural radian frequency
+ * of the 2nd order loop transfer function (scaled by Fs),
+ * which is the radius of the pole locations in the s-plane of an
+ * underdamped analog 2nd order system.
+ *
+ * The input parameter corresponds to omega_n_norm in the following
+ * relation:
+ *
+ * omega_n_norm = omega_n*T = 2*pi*f_n*T = 2*pi*f_n_norm
+ *
+ * where T is the period of the clock being estimated by this
+ * clock tracking loop, and omega_n is the natural radian frequency
+ * of the 2nd order loop transfer function.
+ *
+ * When a new loop bandwidth is set, the gains, alpha and beta,
+ * of the loop are recalculated by a call to update_gains().
+ *
+ * \param bw normalized approximate loop bandwidth
+ */
+ virtual void set_loop_bandwidth(float bw);
+
+ /*!
+ * \brief Set the loop damping factor.
+ *
+ * \details
+ * Set the damping factor of the loop.
+ * Damping in the range (0.0, 1.0) yields an under-damped loop.
+ * Damping in the range (1.0, Inf) yields an over-damped loop.
+ * Damping equal to 1.0 yields a crtically-damped loop.
+ * Under-damped loops are not generally useful for clock tracking.
+ * For clock tracking, as a first guess, set the damping factor to 2.0,
+ * or 1.5 or 1.0.
+ *
+ * Damping factor of the 2nd order loop transfer function.
+ * When a new damping factor is set, the gains, alpha and beta,
+ * of the loop are recalculated by a call to update_gains().
+ *
+ * \param df loop damping factor
+ */
+ void set_damping_factor(float df);
+
+ /*!
+ * \brief Set the expected gain of the Timing Error Detector.
+ *
+ * \details
+ * Sets the expected gain of the timing error detector, given the TED in
+ * use and the anticipated input amplitude, pulse shape, and Es/No.
+ * This value is the slope of the TED's S-curve at timing offset tau = 0.
+ * This value is normally computed by the user analytically or by
+ * simulation in a tool outside of GNURadio.
+ * This value must be correct for the loop filter gains to be computed
+ * properly from the desired input loop bandwidth and damping factor.
+ *
+ * When a new ted_gain is set, the gains, alpha and beta,
+ * of the loop are automatcally recalculated.
+ *
+ * \param ted_gain expected gain of the timing error detector
+ */
+ void set_ted_gain (float ted_gain);
+
+ /*!
+ * \brief Set the PI filter proportional gain, alpha.
+ *
+ * \details
+ * Sets the PI filter proportional gain, alpha.
+ * This gain directly mutliplies the clock phase/timing error
+ * term in the PI filter when advancing the loop.
+ * It most directly affects the instantaneous clock period estimate,
+ * T_inst, and instantaneous clock phase estimate, tau.
+ *
+ * This value would normally be adjusted by setting the loop
+ * bandwidth and damping factor and calling update_gains(). However,
+ * it can be set here directly if desired.
+ *
+ * Setting this parameter directly is probably only feasible if
+ * the user is directly observing the estimates of average clock
+ * period and instantaneous clock period over time in response to
+ * an impulsive change in the input stream (i.e. watching the loop
+ * transient behavior at the start of a data burst).
+ *
+ * \param alpha PI filter proportional gain
+ */
+ void set_alpha(float alpha);
+
+ /*!
+ * \brief Set the PI filter integral gain, beta.
+ *
+ * \details
+ * Sets the PI filter integral gain, beta.
+ * This gain is used when integrating the clock phase/timing error
+ * term in the PI filter when advancing the loop.
+ * It most directly affects the average clock period estimate,
+ * T_avg.
+ *
+ * This value would normally be adjusted by setting the loop
+ * bandwidth and damping factor and calling update_gains(). However,
+ * it can be set here directly if desired.
+ *
+ * Setting this parameter directly is probably only feasible if
+ * the user is directly observing the estimates of average clock
+ * period and instantaneous clock period over time in response to
+ * an impulsive change in the input stream (i.e. watching the loop
+ * transient behavior at the start of a data burst).
+ *
+ * \param beta PI filter integral gain
+ */
+ void set_beta(float beta);
+
+ /*!
+ * \brief Set the average clock period estimate, T_avg.
+ *
+ * \details
+ * Directly sets the average clock period estimate, T_avg,
+ * in units of input stream sample clocks (so the average number of
+ * input samples per output symbol, aka samples/symbol).
+ *
+ * The average clock period estimate, T_avg, is normally updated by
+ * the advance_loop() and period_limit() calls. This method is used
+ * manually reset the estimate when needed.
+ *
+ * \param period
+ * Average clock period, T_avg, in units of input stream sample clocks.
+ */
+ void set_avg_period(float period);
+
+ /*!
+ * \brief Set the instantaneous clock period estimate, T_inst.
+ *
+ * \details
+ * Directly sets the instantaneous clock period estimate, T_inst,
+ * in units of input stream sample clocks (so the instantaneous number of
+ * input samples per output symbol, aka instantaneous samples/symbol).
+ *
+ * The instantaneous clock period estimate, T_inst, is normally updated by
+ * the advance_loop() call. This method is used manually reset the
+ * estimate when needed.
+ *
+ * \param period
+ * Instantaneous clock period, T_inst, in units of input stream sample
+ * clocks.
+ */
+ void set_inst_period(float period);
+
+ /*!
+ * \brief Set the instantaneous clock phase estimate, tau.
+ *
+ * \details
+ * Directly sets the instantaneous clock phase estimate, tau,
+ * in units of input stream sample clocks.
+ *
+ * The instantaneous clock phase estimate, tau, is normally updated by
+ * the advance_loop() call. This method is used manually reset the
+ * estimate when needed.
+ *
+ * \param phase
+ * Instantaneous clock phase, tau, in units of input stream sample clocks.
+ *
+ */
+ void set_phase(float phase);
+
+ /*!
+ * \brief Set the maximum average clock period estimate limit, T_avg_max.
+ *
+ * \details
+ * Sets the maximum average clock period estimate limit, T_avg_max
+ * in units of input stream sample clocks (so the maximum average number
+ * of input samples per output symbol, aka maximum samples/symbol).
+ *
+ * This limit is needed because T_avg is essentially computed by the
+ * integrator portion of an IIR filter, so T_avg could potentially
+ * wander very far during periods of noise/nonsense input.
+ *
+ * \param period
+ * Maximum average clock period, T_avg_max, in units of input stream
+ * sample clocks.
+ */
+ void set_max_avg_period(float period);
+
+ /*!
+ * \brief Set the minimum average clock period estimate limit, T_avg_min.
+ *
+ * \details
+ * Sets the minimum average clock period estimate limit, T_avg_min
+ * in units of input stream sample clocks (so the minimum average number
+ * of input samples per output symbol, aka minimum samples/symbol).
+ *
+ * This limit is needed because T_avg is essentially computed by the
+ * integrator portion of an IIR filter, so T_avg could potentially
+ * wander very far during periods of noise/nonsense input.
+ *
+ * \param period
+ * Minimum average clock period, T_avg_min, in units of input stream
+ * sample clocks.
+ */
+ void set_min_avg_period(float period);
+
+ /*!
+ * \brief Set the nominal average clock period estimate limit, T_avg_nom.
+ *
+ * \details
+ * Sets the nominal average clock period estimate limit, T_avg_nom
+ * in units of input stream sample clocks (so the nominal average number
+ * of input samples per output symbol, aka minimum samples/symbol).
+ *
+ * \param period
+ * Nominal average clock period, T_avg_nom, in units of input stream
+ * sample clocks.
+ */
+ void set_nom_avg_period(float period);
+
+ /*******************************************************************
+ * GET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Returns the normalized approximate loop bandwidth.
+ *
+ * \details
+ * See the documenation for set_loop_bandwidth() for more details.
+ *
+ * Note that if set_alpha() or set_beta() were called to directly
+ * set gains, the value returned by this method will be inaccurate/stale.
+ */
+ float get_loop_bandwidth() const;
+
+ /*!
+ * \brief Returns the loop damping factor.
+ *
+ * \details
+ * See the documenation for set_damping_factor() for more details.
+ *
+ * Note that if set_alpha() or set_beta() were called to directly
+ * set gains, the value returned by this method will be inaccurate/stale.
+ */
+ float get_damping_factor() const;
+
+ /*!
+ * \brief Returns the user providded expected gain of the Timing Error
+ * Detector.
+ *
+ * \details
+ * See the documenation for set_ted_gain() for more details.
+ */
+ float get_ted_gain() const;
+
+ /*!
+ * \brief Returns the PI filter proportional gain, alpha.
+ *
+ * \details
+ * See the documenation for set_alpha() for more details.
+ */
+ float get_alpha() const;
+
+ /*!
+ * \brief Returns the PI filter integral gain, beta.
+ *
+ * \details
+ * See the documenation for set_beta() for more details.
+ */
+ float get_beta() const;
+
+ /*!
+ * \brief Get the average clock period estimate, T_avg.
+ *
+ * \details
+ * Gets the average clock period estimate, T_avg,
+ * in units of input stream sample clocks (so the average number of
+ * input samples per output symbol, aka samples/symbol).
+ *
+ * To convert to seconds, divide by the input stream sample rate:
+ * F_s_input.
+ */
+ float get_avg_period() const;
+
+ /*!
+ * \brief Get the instantaneous clock period estimate, T_inst.
+ *
+ * \details
+ * Gets the instantaneous clock period estimate, T_inst,
+ * in units of input stream sample clocks (so the instantaneous number of
+ * input samples per output symbol, aka instantaneous samples/symbol).
+ *
+ * To convert to seconds, divide by the input stream sample rate:
+ * F_s_input.
+ */
+ float get_inst_period() const;
+
+ /*!
+ * \brief Get the instantaneous clock phase estimate, tau.
+ *
+ * \details
+ * Gets the instantaneous clock phase estimate, tau, in units of
+ * input stream sample clocks.
+ *
+ * To convert to seconds, divide by the input stream sample rate:
+ * F_s_input.
+ *
+ * To manually wrap, add or subtract a multiple of the estimate of the
+ * average clock period, T_avg.
+ *
+ * To convert to a normalized (but not wrapped) clock phase estimate,
+ * divide by the estimate of the average clock period, T_avg.
+ * To further convert the normalized clock phase estimate to radians,
+ * multiply the normalized clock phase estimate by 2*pi.
+ */
+ float get_phase() const;
+
+ /*!
+ * \brief Get the maximum average clock period estimate limit, T_avg_max.
+ *
+ * \details
+ * See the documenation for set_max_avg_period() for more details.
+ */
+ float get_max_avg_period() const;
+
+ /*!
+ * \brief Get the minimum average clock period estimate limit, T_avg_min.
+ *
+ * \details
+ * See the documenation for set_min_avg_period() for more details.
+ */
+ float get_min_avg_period() const;
+
+ /*!
+ * \brief Get the nominal average clock period, T_avg_nom.
+ *
+ * \details
+ * Gets the nominal average clock period, T_avg_nom,
+ * in units of input stream sample clocks (so the nominal average
+ * number of input samples per output symbol, aka nominal samples/symbol).
+ *
+ * To convert to seconds, divide by the input stream sample rate:
+ * F_s_input.
+ */
+ float get_nom_avg_period() const;
+
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_CLOCK_TRACKING_LOOP_H */
diff --git a/gr-digital/lib/interpolating_resampler.cc b/gr-digital/lib/interpolating_resampler.cc
new file mode 100644
index 0000000000..7cda29d073
--- /dev/null
+++ b/gr-digital/lib/interpolating_resampler.cc
@@ -0,0 +1,782 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "interpolating_resampler.h"
+#include <gnuradio/math.h>
+#include <stdexcept>
+#include <deque>
+
+namespace gr {
+ namespace digital {
+
+ interpolating_resampler::interpolating_resampler(enum ir_type type,
+ bool derivative)
+ : d_type(type),
+ d_derivative(derivative),
+ d_phase(0.0f),
+ d_phase_wrapped(0.0f),
+ d_phase_n(0),
+ d_prev_phase(0.0f),
+ d_prev_phase_wrapped(0.0f),
+ d_prev_phase_n(0)
+ {
+ switch (d_type) {
+ case IR_MMSE_8TAP:
+ break;
+ case IR_PFB_NO_MF:
+ break;
+ case IR_PFB_MF:
+ break;
+ case IR_NONE:
+ default:
+ throw std::invalid_argument(
+ "interpolating_resampler: invalid interpolating resampler type.");
+ break;
+ }
+
+ sync_reset(0.0f);
+ }
+
+ void
+ interpolating_resampler::next_phase(float increment,
+ float &phase,
+ int &phase_n,
+ float &phase_wrapped)
+ {
+ float n;
+
+ phase = d_phase_wrapped + increment;
+ n = floorf(phase);
+ phase_wrapped = phase - n;
+ phase_n = static_cast<int>(n);
+ }
+
+ void
+ interpolating_resampler::advance_phase(float increment)
+ {
+ d_prev_phase = d_phase;
+ d_prev_phase_wrapped = d_phase_wrapped;
+ d_prev_phase_n = d_phase_n;
+
+ next_phase(increment, d_phase, d_phase_n, d_phase_wrapped);
+ }
+
+ void
+ interpolating_resampler::revert_phase()
+ {
+ d_phase = d_prev_phase;
+ d_phase_wrapped = d_prev_phase_wrapped;
+ d_phase_n = d_prev_phase_n;
+ }
+
+ void
+ interpolating_resampler::sync_reset(float phase)
+ {
+ float n;
+
+ d_phase = phase;
+ n = floorf(d_phase);
+ d_phase_wrapped = d_phase - n;
+ d_phase_n = static_cast<int>(n);
+
+ d_prev_phase = d_phase;
+ d_prev_phase_wrapped = d_phase_wrapped;
+ d_prev_phase_n = d_phase_n;
+ }
+
+ /*************************************************************************/
+
+ interpolating_resampler_ccf *
+ interpolating_resampler_ccf::make(enum ir_type type,
+ bool derivative,
+ int nfilts,
+ const std::vector<float> &taps)
+ {
+ interpolating_resampler_ccf *ret = NULL;
+ switch (type) {
+ case IR_MMSE_8TAP:
+ ret = new interp_resampler_mmse_8tap_cc(derivative);
+ break;
+ case IR_PFB_NO_MF:
+ ret = new interp_resampler_pfb_no_mf_cc(derivative, nfilts);
+ break;
+ case IR_PFB_MF:
+ ret = new interp_resampler_pfb_mf_ccf(taps, nfilts, derivative);
+ break;
+ case IR_NONE:
+ default:
+ throw std::invalid_argument("interpolating_resampler_ccf: invalid "
+ "interpolating resampler type.");
+ break;
+ }
+ return ret;
+ }
+
+ /*************************************************************************/
+
+ interpolating_resampler_fff *
+ interpolating_resampler_fff::make(enum ir_type type,
+ bool derivative,
+ int nfilts,
+ const std::vector<float> &taps)
+ {
+ interpolating_resampler_fff *ret = NULL;
+ switch (type) {
+ case IR_MMSE_8TAP:
+ ret = new interp_resampler_mmse_8tap_ff(derivative);
+ break;
+ case IR_PFB_NO_MF:
+ ret = new interp_resampler_pfb_no_mf_ff(derivative, nfilts);
+ break;
+ case IR_PFB_MF:
+ ret = new interp_resampler_pfb_mf_fff(taps, nfilts, derivative);
+ break;
+ case IR_NONE:
+ default:
+ throw std::invalid_argument("interpolating_resampler_fff: invalid "
+ "interpolating resampler type.");
+ break;
+ }
+ return ret;
+ }
+
+ /*************************************************************************/
+
+ interp_resampler_mmse_8tap_cc::interp_resampler_mmse_8tap_cc(
+ bool derivative)
+ : interpolating_resampler_ccf(IR_MMSE_8TAP, derivative),
+ d_interp(NULL),
+ d_interp_diff(NULL)
+ {
+ d_interp = new filter::mmse_fir_interpolator_cc();
+ if (d_interp == NULL)
+ throw std::runtime_error("unable to create mmse_fir_interpolator_cc");
+
+ if (d_derivative) {
+ d_interp_diff = new filter::mmse_interp_differentiator_cc();
+ if (d_interp_diff == NULL)
+ throw std::runtime_error("unable to create "
+ "mmse_interp_differentiator_cc");
+ }
+ }
+
+ interp_resampler_mmse_8tap_cc::~interp_resampler_mmse_8tap_cc()
+ {
+ delete d_interp;
+ if (d_derivative)
+ delete d_interp_diff;
+ }
+
+ gr_complex
+ interp_resampler_mmse_8tap_cc::interpolate(const gr_complex input[],
+ float mu) const
+ {
+ return d_interp->interpolate(input, mu);
+ }
+
+ gr_complex
+ interp_resampler_mmse_8tap_cc::differentiate(const gr_complex input[],
+ float mu) const
+ {
+ return d_interp_diff->differentiate(input, mu);
+ }
+
+ unsigned int
+ interp_resampler_mmse_8tap_cc::ntaps() const
+ {
+ return d_interp->ntaps();
+ }
+
+ /*************************************************************************/
+
+ interp_resampler_mmse_8tap_ff::interp_resampler_mmse_8tap_ff(
+ bool derivative)
+ : interpolating_resampler_fff(IR_MMSE_8TAP, derivative),
+ d_interp(NULL),
+ d_interp_diff(NULL)
+ {
+ d_interp = new filter::mmse_fir_interpolator_ff();
+ if (d_interp == NULL)
+ throw std::runtime_error("unable to create mmse_fir_interpolator_ff");
+
+ if (d_derivative) {
+ d_interp_diff = new filter::mmse_interp_differentiator_ff();
+ if (d_interp_diff == NULL)
+ throw std::runtime_error("unable to create "
+ "mmse_interp_differentiator_ff");
+ }
+ }
+
+ interp_resampler_mmse_8tap_ff::~interp_resampler_mmse_8tap_ff()
+ {
+ delete d_interp;
+ if (d_derivative)
+ delete d_interp_diff;
+ }
+
+ float
+ interp_resampler_mmse_8tap_ff::interpolate(const float input[],
+ float mu) const
+ {
+ return d_interp->interpolate(input, mu);
+ }
+
+ float
+ interp_resampler_mmse_8tap_ff::differentiate(const float input[],
+ float mu) const
+ {
+ return d_interp_diff->differentiate(input, mu);
+ }
+
+ unsigned int
+ interp_resampler_mmse_8tap_ff::ntaps() const
+ {
+ return d_interp->ntaps();
+ }
+
+ /*************************************************************************/
+
+#include "gnuradio/filter/interpolator_taps.h"
+#include "gnuradio/filter/interp_differentiator_taps.h"
+
+ interp_resampler_pfb_no_mf_cc::interp_resampler_pfb_no_mf_cc(
+ bool derivative,
+ int nfilts)
+ : interpolating_resampler_ccf(IR_PFB_NO_MF, derivative),
+ d_nfilters(0),
+ d_filters(),
+ d_diff_filters()
+ {
+ if (nfilts <= 1)
+ throw std::invalid_argument("interpolating_resampler_pfb_no_mf_cc: "
+ "number of polyphase filter arms "
+ "must be greater than 1");
+
+ // Round up the number of filter arms to the current or next power of 2
+ d_nfilters =
+ 1 << (static_cast<int>(log2f(static_cast<float>(nfilts-1))) + 1);
+
+ // N.B. We assume in this class: NSTEPS == DNSTEPS and NTAPS == DNTAPS
+
+ // Limit to the maximum number of precomputed MMSE tap sets
+ if (d_nfilters <= 0 or d_nfilters > NSTEPS)
+ d_nfilters = NSTEPS;
+
+ // Create our polyphase filter arms for the steps from 0.0 to 1.0 from
+ // the MMSE interpolating filter and MMSE interpolating differentiator
+ // taps rows.
+ // N.B. We create an extra final row for an offset of 1.0, because it's
+ // easier than dealing with wrap around from 0.99... to 0.0 shifted
+ // by 1 tap.
+ d_filters = std::vector<filter::kernel::fir_filter_ccf*>(d_nfilters + 1);
+ d_diff_filters = std::vector<filter::kernel::fir_filter_ccf*>(d_nfilters + 1);
+
+ std::vector<float> t(NTAPS, 0);
+ int incr = NSTEPS/d_nfilters;
+ int src, dst;
+ for (src = 0, dst = 0; src <= NSTEPS; src += incr, dst++) {
+
+ t.assign(&taps[src][0], &taps[src][NTAPS]);
+ d_filters[dst] = new filter::kernel::fir_filter_ccf(1, t);
+ if (d_filters[dst] == NULL)
+ throw std::runtime_error("unable to create fir_filter_ccf");
+
+ if (d_derivative) {
+ t.assign(&Dtaps[src][0], &Dtaps[src][DNTAPS]);
+ d_diff_filters[dst] = new filter::kernel::fir_filter_ccf(1, t);
+ if (d_diff_filters[dst] == NULL)
+ throw std::runtime_error("unable to create fir_filter_ccf");
+ }
+ }
+ }
+
+ interp_resampler_pfb_no_mf_cc::~interp_resampler_pfb_no_mf_cc()
+ {
+ for (int i = 0; i <= d_nfilters; i++) {
+ delete d_filters[i];
+ if (d_derivative)
+ delete d_diff_filters[i];
+ }
+ }
+
+ gr_complex
+ interp_resampler_pfb_no_mf_cc::interpolate(const gr_complex input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_no_mf_cc: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_filters[arm]->filter(input);
+ }
+
+ gr_complex
+ interp_resampler_pfb_no_mf_cc::differentiate(const gr_complex input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_no_mf_cc: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_diff_filters[arm]->filter(input);
+ }
+
+ unsigned int
+ interp_resampler_pfb_no_mf_cc::ntaps() const
+ {
+ return NTAPS;
+ }
+
+ /*************************************************************************/
+
+ interp_resampler_pfb_no_mf_ff::interp_resampler_pfb_no_mf_ff(
+ bool derivative,
+ int nfilts)
+ : interpolating_resampler_fff(IR_PFB_NO_MF, derivative),
+ d_nfilters(0),
+ d_filters(),
+ d_diff_filters()
+ {
+ if (nfilts <= 1)
+ throw std::invalid_argument("interpolating_resampler_pfb_no_mf_ff: "
+ "number of polyphase filter arms "
+ "must be greater than 1");
+
+ // Round up the number of filter arms to the current or next power of 2
+ d_nfilters =
+ 1 << (static_cast<int>(log2f(static_cast<float>(nfilts-1))) + 1);
+
+ // N.B. We assume in this class: NSTEPS == DNSTEPS and NTAPS == DNTAPS
+
+ // Limit to the maximum number of precomputed MMSE tap sets
+ if (d_nfilters <= 0 or d_nfilters > NSTEPS)
+ d_nfilters = NSTEPS;
+
+ // Create our polyphase filter arms for the steps from 0.0 to 1.0 from
+ // the MMSE interpolating filter and MMSE interpolating differentiator
+ // taps rows.
+ // N.B. We create an extra final row for an offset of 1.0, because it's
+ // easier than dealing with wrap around from 0.99... to 0.0 shifted
+ // by 1 tap.
+ d_filters = std::vector<filter::kernel::fir_filter_fff*>(d_nfilters + 1);
+ d_diff_filters = std::vector<filter::kernel::fir_filter_fff*>(d_nfilters + 1);
+
+ std::vector<float> t(NTAPS, 0);
+ int incr = NSTEPS/d_nfilters;
+ int src, dst;
+ for (src = 0, dst = 0; src <= NSTEPS; src += incr, dst++) {
+
+ t.assign(&taps[src][0], &taps[src][NTAPS]);
+ d_filters[dst] = new filter::kernel::fir_filter_fff(1, t);
+ if (d_filters[dst] == NULL)
+ throw std::runtime_error("unable to create fir_filter_fff");
+
+ if (d_derivative) {
+ t.assign(&Dtaps[src][0], &Dtaps[src][DNTAPS]);
+ d_diff_filters[dst] = new filter::kernel::fir_filter_fff(1, t);
+ if (d_diff_filters[dst] == NULL)
+ throw std::runtime_error("unable to create fir_filter_fff");
+ }
+ }
+ }
+
+ interp_resampler_pfb_no_mf_ff::~interp_resampler_pfb_no_mf_ff()
+ {
+ for (int i = 0; i <= d_nfilters; i++) {
+ delete d_filters[i];
+ if (d_derivative)
+ delete d_diff_filters[i];
+ }
+ }
+
+ float
+ interp_resampler_pfb_no_mf_ff::interpolate(const float input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_no_mf_ff: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_filters[arm]->filter(input);
+ }
+
+ float
+ interp_resampler_pfb_no_mf_ff::differentiate(const float input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_no_mf_ff: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_diff_filters[arm]->filter(input);
+ }
+
+ unsigned int
+ interp_resampler_pfb_no_mf_ff::ntaps() const
+ {
+ return NTAPS;
+ }
+
+ /*************************************************************************/
+
+ interp_resampler_pfb_mf_ccf::interp_resampler_pfb_mf_ccf(
+ const std::vector<float> &taps,
+ int nfilts,
+ bool derivative)
+ : interpolating_resampler_ccf(IR_PFB_MF, derivative),
+ d_nfilters(nfilts),
+ d_taps_per_filter(static_cast<unsigned int>(
+ ceil( static_cast<double>(taps.size())
+ / static_cast<double>(nfilts )))),
+ d_filters(),
+ d_diff_filters(),
+ d_taps(),
+ d_diff_taps()
+ {
+ if (d_nfilters <= 1)
+ throw std::invalid_argument("interpolating_resampler_pfb_mf_ccf: "
+ "number of polyphase filter arms "
+ "must be greater than 1");
+ if (taps.size() < static_cast<unsigned int>(d_nfilters))
+ throw std::invalid_argument("interpolating_resampler_pfb_mf_ccf: "
+ "length of the prototype filter taps"
+ " must be greater than or equal to "
+ "the number of polyphase filter arms.");
+
+ // Create a derivative filter from the provided taps
+
+ // First create a truncated ideal differentiator filter
+ int ideal_diff_filt_len = 3; // Must be odd; rest of init assumes odd.
+ std::vector<float> ideal_diff_taps(ideal_diff_filt_len, 0.0f);
+ int i, n;
+ n = ideal_diff_taps.size()/2;
+ for (i = -n; i < 0; i++) {
+ ideal_diff_taps[i+n] = (-i & 1) == 1 ? -1.0f/i : 1.0f/i;
+ ideal_diff_taps[n-i] = -ideal_diff_taps[i+n];
+ }
+ ideal_diff_taps[n] = 0.0f;
+
+ // Perform linear convolution of prototype filter taps and the truncated
+ // ideal differentiator taps to generate a derivative matched filter.
+ // N.B. the truncated ideal differentiator taps must have an odd length
+ int j, k, l, m;
+ m = ideal_diff_taps.size();
+ n = taps.size();
+ l = m + n - 1; // length of convolution
+ std::deque<float> diff_taps(l, 0.0f);
+ for (i = 0; i < l; i++) {
+ for (j = 0; j < m; j++) {
+ k = i + j - (m - 1);
+ if (k < 0 or k >= n)
+ continue;
+ diff_taps[i] += ideal_diff_taps[(m - 1) - j] * taps[k];
+ }
+ }
+
+ // Trim the convolution so the prototype derivative filter is the same
+ // length as the passed in prototype filter taps.
+ n = ideal_diff_taps.size()/2;
+ for (i = 0; i < n; i++) {
+ diff_taps.pop_back();
+ diff_taps.pop_front();
+ }
+
+ // Squash the differentiation noise spikes at the filter ends.
+ diff_taps[0] = 0.0f;
+ diff_taps[diff_taps.size()-1] = 0.0f;
+
+ // Normalize the prototype derviative filter gain to the number of
+ // filter arms
+ n = diff_taps.size();
+ float mag = 0.0f;
+ for (i = 0; i < n; i++)
+ mag += fabsf(diff_taps[i]);
+ for (i = 0; i < n; i++) {
+ diff_taps[i] *= d_nfilters/mag;
+ if (d_derivative and std::isnan(diff_taps[i]))
+ throw std::runtime_error("interpolating_resampler_pfb_mf_ccf: "
+ "NaN error creating derivative filter."
+ );
+ }
+
+ // Create our polyphase filter arms for the steps from 0.0 to 1.0 from
+ // the prototype matched filter.
+ // N.B. We create an extra final row for an offset of 1.0, because it's
+ // easier than dealing with wrap around from 0.99... to 0.0 shifted
+ // by 1 tap.
+ d_filters = std::vector<filter::kernel::fir_filter_ccf*>(d_nfilters + 1);
+ d_diff_filters = std::vector<filter::kernel::fir_filter_ccf*>(d_nfilters + 1);
+
+ m = taps.size();
+ n = diff_taps.size();
+ d_taps.resize(d_nfilters+1);
+ d_diff_taps.resize(d_nfilters+1);
+ signed int taps_per_filter = static_cast<signed int>(d_taps_per_filter);
+
+ for (i = 0; i <= d_nfilters; i++) {
+ d_taps[i] = std::vector<float>(d_taps_per_filter, 0.0f);
+ for (j = 0; j < taps_per_filter; j++) {
+ k = i+j*d_nfilters;
+ if (k < m)
+ d_taps[i][j] = taps[k];
+ }
+ d_filters[i] = new filter::kernel::fir_filter_ccf(1, d_taps[i]);
+ if (d_filters[i] == NULL)
+ throw std::runtime_error("unable to create fir_filter_ccf");
+
+ if (not d_derivative)
+ continue;
+
+ d_diff_taps[i] = std::vector<float>(d_taps_per_filter, 0.0f);
+ for (j = 0; j < taps_per_filter; j++) {
+ k = i+j*d_nfilters;
+ if (k < n)
+ d_diff_taps[i][j] = diff_taps[k];
+ }
+ d_diff_filters[i] = new filter::kernel::fir_filter_ccf(
+ 1,
+ d_diff_taps[i]);
+ if (d_diff_filters[i] == NULL)
+ throw std::runtime_error("unable to create fir_filter_ccf");
+ }
+ }
+
+ interp_resampler_pfb_mf_ccf::~interp_resampler_pfb_mf_ccf()
+ {
+ for (int i = 0; i <= d_nfilters; i++) {
+ delete d_filters[i];
+ if (d_derivative)
+ delete d_diff_filters[i];
+ }
+ }
+
+ gr_complex
+ interp_resampler_pfb_mf_ccf::interpolate(const gr_complex input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_mf_ccf: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_filters[arm]->filter(input);
+ }
+
+ gr_complex
+ interp_resampler_pfb_mf_ccf::differentiate(const gr_complex input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_mf_ccf: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_diff_filters[arm]->filter(input);
+ }
+
+ unsigned int
+ interp_resampler_pfb_mf_ccf::ntaps() const
+ {
+ return d_taps_per_filter;
+ }
+
+ /*************************************************************************/
+
+ interp_resampler_pfb_mf_fff::interp_resampler_pfb_mf_fff(
+ const std::vector<float> &taps,
+ int nfilts,
+ bool derivative)
+ : interpolating_resampler_fff(IR_PFB_MF, derivative),
+ d_nfilters(nfilts),
+ d_taps_per_filter(static_cast<unsigned int>(
+ ceil( static_cast<double>(taps.size())
+ / static_cast<double>(nfilts )))),
+ d_filters(),
+ d_diff_filters(),
+ d_taps(),
+ d_diff_taps()
+ {
+ if (d_nfilters <= 1)
+ throw std::invalid_argument("interpolating_resampler_pfb_mf_fff: "
+ "number of polyphase filter arms "
+ "must be greater than 1");
+ if (taps.size() < static_cast<unsigned int>(d_nfilters))
+ throw std::invalid_argument("interpolating_resampler_pfb_mf_fff: "
+ "length of the prototype filter taps"
+ " must be greater than or equal to "
+ "the number of polyphase filter arms.");
+
+ // Create a derivative filter from the provided taps
+
+ // First create a truncated ideal differentiator filter
+ int ideal_diff_filt_len = 3; // Must be odd; rest of init assumes odd.
+ std::vector<float> ideal_diff_taps(ideal_diff_filt_len, 0.0f);
+ int i, n;
+ n = ideal_diff_taps.size()/2;
+ for (i = -n; i < 0; i++) {
+ ideal_diff_taps[i+n] = (-i & 1) == 1 ? -1.0f/i : 1.0f/i;
+ ideal_diff_taps[n-i] = -ideal_diff_taps[i+n];
+ }
+ ideal_diff_taps[n] = 0.0f;
+
+ // Perform linear convolution of prototype filter taps and the truncated
+ // ideal differentiator taps to generate a derivative matched filter.
+ // N.B. the truncated ideal differentiator taps must have an odd length
+ int j, k, l, m;
+ m = ideal_diff_taps.size();
+ n = taps.size();
+ l = m + n - 1; // length of convolution
+ std::deque<float> diff_taps(l, 0.0f);
+ for (i = 0; i < l; i++) {
+ for (j = 0; j < m; j++) {
+ k = i + j - (m - 1);
+ if (k < 0 or k >= n)
+ continue;
+ diff_taps[i] += ideal_diff_taps[(m - 1) - j] * taps[k];
+ }
+ }
+
+ // Trim the convolution so the prototype derivative filter is the same
+ // length as the passed in prototype filter taps.
+ n = ideal_diff_taps.size()/2;
+ for (i = 0; i < n; i++) {
+ diff_taps.pop_back();
+ diff_taps.pop_front();
+ }
+
+ // Squash the differentiation noise spikes at the filter ends.
+ diff_taps[0] = 0.0f;
+ diff_taps[diff_taps.size()-1] = 0.0f;
+
+ // Normalize the prototype derviative filter gain to the number of
+ // filter arms
+ n = diff_taps.size();
+ float mag = 0.0f;
+ for (i = 0; i < n; i++)
+ mag += fabsf(diff_taps[i]);
+ for (i = 0; i < n; i++) {
+ diff_taps[i] *= d_nfilters/mag;
+ if (d_derivative and std::isnan(diff_taps[i]))
+ throw std::runtime_error("interpolating_resampler_pfb_mf_fff: "
+ "NaN error creating derivative filter."
+ );
+ }
+
+ // Create our polyphase filter arms for the steps from 0.0 to 1.0 from
+ // the prototype matched filter.
+ // N.B. We create an extra final row for an offset of 1.0, because it's
+ // easier than dealing with wrap around from 0.99... to 0.0 shifted
+ // by 1 tap.
+ d_filters = std::vector<filter::kernel::fir_filter_fff*>(d_nfilters + 1);
+ d_diff_filters = std::vector<filter::kernel::fir_filter_fff*>(d_nfilters + 1);
+
+ m = taps.size();
+ n = diff_taps.size();
+ d_taps.resize(d_nfilters+1);
+ d_diff_taps.resize(d_nfilters+1);
+ signed int taps_per_filter = static_cast<signed int>(d_taps_per_filter);
+
+ for (i = 0; i <= d_nfilters; i++) {
+ d_taps[i] = std::vector<float>(d_taps_per_filter, 0.0f);
+ for (j = 0; j < taps_per_filter; j++) {
+ k = i+j*d_nfilters;
+ if (k < m)
+ d_taps[i][j] = taps[k];
+ }
+ d_filters[i] = new filter::kernel::fir_filter_fff(1, d_taps[i]);
+ if (d_filters[i] == NULL)
+ throw std::runtime_error("unable to create fir_filter_fff");
+
+ if (not d_derivative)
+ continue;
+
+ d_diff_taps[i] = std::vector<float>(d_taps_per_filter, 0.0f);
+ for (j = 0; j < taps_per_filter; j++) {
+ k = i+j*d_nfilters;
+ if (k < n)
+ d_diff_taps[i][j] = diff_taps[k];
+ }
+ d_diff_filters[i] = new filter::kernel::fir_filter_fff(
+ 1,
+ d_diff_taps[i]);
+ if (d_diff_filters[i] == NULL)
+ throw std::runtime_error("unable to create fir_filter_fff");
+ }
+ }
+
+ interp_resampler_pfb_mf_fff::~interp_resampler_pfb_mf_fff()
+ {
+ for (int i = 0; i <= d_nfilters; i++) {
+ delete d_filters[i];
+ if (d_derivative)
+ delete d_diff_filters[i];
+ }
+ }
+
+ float
+ interp_resampler_pfb_mf_fff::interpolate(const float input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_mf_fff: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_filters[arm]->filter(input);
+ }
+
+ float
+ interp_resampler_pfb_mf_fff::differentiate(const float input[],
+ float mu) const
+ {
+ int arm = static_cast<int>(rint(mu * d_nfilters));
+
+ if (arm < 0 or arm > d_nfilters)
+ throw std::runtime_error("interp_resampler_pfb_mf_fff: mu is not "
+ "in the range [0.0, 1.0]");
+
+ return d_diff_filters[arm]->filter(input);
+ }
+
+ unsigned int
+ interp_resampler_pfb_mf_fff::ntaps() const
+ {
+ return d_taps_per_filter;
+ }
+
+ } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/interpolating_resampler.h b/gr-digital/lib/interpolating_resampler.h
new file mode 100644
index 0000000000..cdd0d976ea
--- /dev/null
+++ b/gr-digital/lib/interpolating_resampler.h
@@ -0,0 +1,599 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_H
+#define INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_H
+
+#include <gnuradio/gr_complex.h>
+#include <gnuradio/digital/interpolating_resampler_type.h>
+#include <vector>
+#include <gnuradio/filter/mmse_fir_interpolator_cc.h>
+#include <gnuradio/filter/mmse_fir_interpolator_ff.h>
+#include <gnuradio/filter/mmse_interp_differentiator_cc.h>
+#include <gnuradio/filter/mmse_interp_differentiator_ff.h>
+
+namespace gr {
+ namespace digital {
+
+ /*!
+ * \brief Base class for the composite interpolating resampler objects
+ * used by the symbol_synchronizer_xx blocks.
+ * \ingroup internal
+ *
+ * \details
+ * This is the base class for the composite interpolating resampler
+ * objects used by the symbol_synchronizer_xx blocks to provide a
+ * user selectable interpolating resampler type.
+ *
+ * This base class provides the enumeration type for the available
+ * types of interpolating resamplers.
+ *
+ * This base class also provides methods to to update, manage, and
+ * store the sample phase state of the interpolating resampler.
+ * The sample phase increments and phase state are assumed to be in
+ * units of samples, and a complete sample phase cycle is one sample.
+ */
+ class interpolating_resampler
+ {
+ public:
+
+ virtual ~interpolating_resampler() {}
+
+ /*!
+ * \brief Return the number of taps used in any single FIR filtering
+ * operation
+ */
+ virtual unsigned int ntaps() const = 0;
+
+ /*!
+ * \brief Return the current unwrapped interpolator samples phase in
+ * units of samples
+ */
+ virtual float phase() { return d_phase; }
+
+ /*!
+ * \brief Return the integral part of the current unwrapped
+ * interpolator sample phase in units of (whole) samples
+ */
+ virtual int phase_n() { return d_phase_n; }
+
+ /*!
+ * \brief Returns the fractional part of the current wrapped
+ * interpolator sample phase in units of samples from [0.0, 1.0).
+ */
+ virtual float phase_wrapped() { return d_phase_wrapped; }
+
+ /*!
+ * \brief Return the fractional part of the previous wrapped
+ * interpolator sample phase in units of samples from [0.0, 1.0).
+ */
+ virtual float prev_phase_wrapped() { return d_prev_phase_wrapped; }
+
+ /*!
+ * \brief Compute the next interpolator sample phase.
+ * \param increment The sample phase increment to the next interpolation
+ * point, in units of samples.
+ * \param phase The new interpolator sample phase, in units of
+ * samples.
+ * \param phase_n The integral part of the new interpolator sample
+ * phase, in units of samples.
+ * \param phase_wrapped The new wrapped interpolator sample phase,
+ * in units of samples.
+ */
+ virtual void next_phase(float increment,
+ float &phase,
+ int &phase_n,
+ float &phase_wrapped);
+
+ /*!
+ * \brief Advance the phase state to the next interpolator sample phase.
+ * \param increment The sample phase increment to the next interpolation
+ * point, in units of samples.
+ */
+ virtual void advance_phase(float increment);
+
+ /*!
+ * \brief Revert the phase state to the previous interpolator sample
+ * phase.
+ */
+ virtual void revert_phase();
+
+ /*!
+ * \brief Reset the phase state to the specified interpolator sample
+ * phase.
+ * \param phase The interpolator sample phase to which to reset,
+ * in units of samples.
+ */
+ virtual void sync_reset(float phase);
+
+ private:
+ enum ir_type d_type;
+
+ protected:
+ interpolating_resampler(enum ir_type type, bool derivative = false);
+
+ bool d_derivative;
+
+ float d_phase;
+ float d_phase_wrapped;
+ int d_phase_n;
+ float d_prev_phase;
+ float d_prev_phase_wrapped;
+ int d_prev_phase_n;
+ };
+
+ /*************************************************************************/
+
+ /*!
+ * \brief A complex input, complex output, composite interpolating resampler
+ * object used by the symbol_synchronizer_cc block.
+ * \ingroup internal
+ *
+ * \details
+ * This is the complex input, complex output composite interpolating
+ * resampler object used by the symbol_synchronizer_cc block to provide a
+ * user selectable interpolating resampler type.
+ *
+ * This class abstracts away the underlying interpolating resampler
+ * type implementation, so the the symbol_synchronizer_cc block need not
+ * be bothered with the underlying implementation after the object is
+ * instantiated.
+ */
+ class interpolating_resampler_ccf : public interpolating_resampler
+ {
+ public:
+ /*!
+ * \brief Create a complex input, complex output interpolating
+ * resampler object.
+ * \param type The underlying type implementation of the interpolating
+ * resampler.
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ * \param nfilts The number of polyphase filter bank arms. Only needed
+ * for some types.
+ * \param taps Prototype filter for the polyphase filter bank. Only
+ * needed for some types.
+ */
+ static interpolating_resampler_ccf *make(enum ir_type type,
+ bool derivative = false,
+ int nfilts = 32,
+ const std::vector<float> &taps
+ = std::vector<float>());
+
+ virtual ~interpolating_resampler_ccf() {};
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ virtual gr_complex interpolate(const gr_complex input[],
+ float mu) const = 0;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ virtual gr_complex differentiate(const gr_complex input[],
+ float mu) const = 0;
+
+ protected:
+ interpolating_resampler_ccf(enum ir_type type,
+ bool derivative = false)
+ : interpolating_resampler(type, derivative) {}
+ };
+
+ /*************************************************************************/
+
+ /*!
+ * \brief A float input, float output, composite interpolating resampler
+ * object used by the symbol_synchronizer_ff block.
+ * \ingroup internal
+ *
+ * \details
+ * This is the float input, float output composite interpolating
+ * resampler object used by the symbol_synchronizer_ff block to provide a
+ * user selectable interpolating resampler type.
+ *
+ * This class abstracts away the underlying interpolating resampler
+ * type implementation, so the the symbol_synchronizer_ff block need not
+ * be bothered with the underlying implementation after the object is
+ * instantiated.
+ */
+ class interpolating_resampler_fff : public interpolating_resampler
+ {
+ public:
+ /*!
+ * \brief Create a float input, float output interpolating
+ * resampler object.
+ * \param type The underlying type implementation of the interpolating
+ * resampler.
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ * \param nfilts The number of polyphase filter bank arms. Only needed
+ * for some types.
+ * \param taps Prototype filter for the polyphase filter bank. Only
+ * needed for some types.
+ */
+ static interpolating_resampler_fff *make(enum ir_type type,
+ bool derivative = false,
+ int nfilts = 32,
+ const std::vector<float> &taps
+ = std::vector<float>());
+
+ virtual ~interpolating_resampler_fff() {};
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ virtual float interpolate(const float input[], float mu) const = 0;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ virtual float differentiate(const float input[], float mu) const = 0;
+
+ protected:
+ interpolating_resampler_fff(enum ir_type type,
+ bool derivative = false)
+ : interpolating_resampler(type, derivative) {}
+ };
+
+ /*************************************************************************/
+
+ /*!
+ * \brief A complex input, complex output, interpolating resampler
+ * object using the MMSE interpolator filter bank.
+ * \ingroup internal
+ *
+ * \details
+ * This is the complex input, complex output, interpolating resampler
+ * object using the MMSE interpolator filter bank as its underlying
+ * polyphase filterbank interpolator.
+ */
+ class interp_resampler_mmse_8tap_cc : public interpolating_resampler_ccf
+ {
+ public:
+ /*!
+ * \brief Create a complex input, complex output, polyphase filter bank
+ * using the MMSE filter bank, interpolating resampler object.
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ */
+ interp_resampler_mmse_8tap_cc(bool derivative = false);
+ ~interp_resampler_mmse_8tap_cc();
+
+ /*!
+ * \brief Return the number of taps used in any single FIR filtering
+ * operation
+ */
+ unsigned int ntaps() const;
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ gr_complex interpolate(const gr_complex input[], float mu) const;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ gr_complex differentiate(const gr_complex input[], float mu) const;
+
+ private:
+ filter::mmse_fir_interpolator_cc *d_interp;
+ filter::mmse_interp_differentiator_cc *d_interp_diff;
+ };
+
+ /*!
+ * \brief A float input, float output, interpolating resampler
+ * object using the MMSE interpolator filter bank.
+ * \ingroup internal
+ *
+ * \details
+ * This is the float input, float output, interpolating resampler
+ * object using the MMSE interpolator filter bank as its underlying
+ * polyphase filterbank interpolator.
+ */
+ class interp_resampler_mmse_8tap_ff : public interpolating_resampler_fff
+ {
+ public:
+ /*!
+ * \brief Create a float input, float output, polyphase filter bank
+ * using the MMSE filter bank, interpolating resampler object.
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ */
+ interp_resampler_mmse_8tap_ff(bool derivative = false);
+ ~interp_resampler_mmse_8tap_ff();
+
+ /*!
+ * \brief Return the number of taps used in any single FIR filtering
+ * operation
+ */
+ unsigned int ntaps() const;
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ float interpolate(const float input[], float mu) const;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ float differentiate(const float input[], float mu) const;
+
+ private:
+ filter::mmse_fir_interpolator_ff *d_interp;
+ filter::mmse_interp_differentiator_ff *d_interp_diff;
+ };
+
+ /*************************************************************************/
+
+ /*!
+ * \brief A complex input, complex output, interpolating resampler
+ * object with a polyphase filter bank which uses the MMSE interpolator
+ * filter arms.
+ * \ingroup internal
+ *
+ * \details
+ * This is the complex input, complex output, interpolating resampler
+ * object with a polyphase filter bank which uses the MMSE interpolator
+ * filter arms. This class has the "advantage" that the number of arms
+ * used can be reduced from 128 (default) to 64, 32, 16, 8, 4, or 2.
+ */
+ class interp_resampler_pfb_no_mf_cc : public interpolating_resampler_ccf
+ {
+ public:
+ /*!
+ * \brief Create a complex input, complex output, polyphase filter bank
+ * using the MMSE filter bank, interpolating resampler object.
+ * \param nfilts The number of polyphase filter bank arms. Must be in
+ * {2, 4, 8, 16, 32, 64, 128 (default)}
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ */
+ interp_resampler_pfb_no_mf_cc(bool derivative = false,
+ int nfilts = 128);
+ ~interp_resampler_pfb_no_mf_cc();
+
+ /*!
+ * \brief Return the number of taps used in any single FIR filtering
+ * operation
+ */
+ unsigned int ntaps() const;
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ gr_complex interpolate(const gr_complex input[], float mu) const;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ gr_complex differentiate(const gr_complex input[], float mu) const;
+
+ private:
+ int d_nfilters;
+ std::vector<filter::kernel::fir_filter_ccf*> d_filters;
+ std::vector<filter::kernel::fir_filter_ccf*> d_diff_filters;
+ };
+
+ /*!
+ * \brief A float input, float output, interpolating resampler
+ * object with a polyphase filter bank which uses the MMSE interpolator
+ * filter arms.
+ * \ingroup internal
+ *
+ * \details
+ * This is the float input, float output, interpolating resampler
+ * object with a polyphase filter bank which uses the MMSE interpolator
+ * filter arms. This class has the "advantage" that the number of arms
+ * used can be reduced from 128 (default) to 64, 32, 16, 8, 4, or 2.
+ */
+ class interp_resampler_pfb_no_mf_ff : public interpolating_resampler_fff
+ {
+ public:
+ /*!
+ * \brief Create a float input, float output, polyphase filter bank
+ * using the MMSE filter bank, interpolating resampler object.
+ * \param nfilts The number of polyphase filter bank arms. Must be in
+ * {2, 4, 8, 16, 32, 64, 128 (default)}
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ */
+ interp_resampler_pfb_no_mf_ff(bool derivative = false,
+ int nfilts = 128);
+ ~interp_resampler_pfb_no_mf_ff();
+
+ /*!
+ * \brief Return the number of taps used in any single FIR filtering
+ * operation
+ */
+ unsigned int ntaps() const;
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ float interpolate(const float input[], float mu) const;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ float differentiate(const float input[], float mu) const;
+
+ private:
+ int d_nfilters;
+ std::vector<filter::kernel::fir_filter_fff*> d_filters;
+ std::vector<filter::kernel::fir_filter_fff*> d_diff_filters;
+ };
+
+ /*************************************************************************/
+
+ /*!
+ * \brief A complex input, complex output, interpolating resampler
+ * object with a polyphase filter bank with a user provided prototype
+ * matched filter.
+ * \ingroup internal
+ *
+ * \details
+ * This is the complex input, complex output, interpolating resampler
+ * object with a polyphase filter bank with a user provided protoype
+ * matched filter. The prototype matched filter must be designed at a
+ * rate of nfilts times the output rate.
+ */
+ class interp_resampler_pfb_mf_ccf : public interpolating_resampler_ccf
+ {
+ public:
+ /*!
+ * \brief Create a complex input, complex output, polyphase filter bank,
+ * with matched filter, interpolating resampler object.
+ * \param taps Prototype filter for the polyphase filter bank.
+ * \param nfilts The number of polyphase filter bank arms.
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ */
+ interp_resampler_pfb_mf_ccf(const std::vector<float> &taps,
+ int nfilts = 32,
+ bool derivative = false);
+ ~interp_resampler_pfb_mf_ccf();
+
+ /*!
+ * \brief Return the number of taps used in any single FIR filtering
+ * operation
+ */
+ unsigned int ntaps() const;
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ gr_complex interpolate(const gr_complex input[], float mu) const;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ gr_complex differentiate(const gr_complex input[], float mu) const;
+
+ private:
+ int d_nfilters;
+ const unsigned int d_taps_per_filter;
+ std::vector<filter::kernel::fir_filter_ccf*> d_filters;
+ std::vector<filter::kernel::fir_filter_ccf*> d_diff_filters;
+
+ std::vector< std::vector<float> > d_taps;
+ std::vector< std::vector<float> > d_diff_taps;
+ };
+
+ /*!
+ * \brief A float input, float output, interpolating resampler
+ * object with a polyphase filter bank with a user provided prototype
+ * matched filter.
+ * \ingroup internal
+ *
+ * \details
+ * This is the float input, float output, interpolating resampler
+ * object with a polyphase filter bank with a user provided protoype
+ * matched filter. The prototype matched filter must be designed at a
+ * rate of nfilts times the output rate.
+ */
+ class interp_resampler_pfb_mf_fff : public interpolating_resampler_fff
+ {
+ public:
+ /*!
+ * \brief Create a float input, float output, polyphase filter bank,
+ * with matched filter, interpolating resampler object.
+ * \param taps Prototype filter for the polyphase filter bank.
+ * \param nfilts The number of polyphase filter bank arms.
+ * \param derivative True if an interpolating differentitator is
+ * requested to be initialized to obtain interpolated
+ * derivative samples as well.
+ */
+ interp_resampler_pfb_mf_fff(const std::vector<float> &taps,
+ int nfilts = 32,
+ bool derivative = false);
+ ~interp_resampler_pfb_mf_fff();
+
+ /*!
+ * \brief Return the number of taps used in any single FIR filtering
+ * operation
+ */
+ unsigned int ntaps() const;
+
+ /*!
+ * \brief Return an interpolated sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ float interpolate(const float input[], float mu) const;
+
+ /*!
+ * \brief Return an interpolated derivative sample.
+ * \param input Array of input samples of length ntaps().
+ * \param mu Intersample phase in the range [0.0, 1.0] samples.
+ */
+ float differentiate(const float input[], float mu) const;
+
+ private:
+ int d_nfilters;
+ const unsigned int d_taps_per_filter;
+ std::vector<filter::kernel::fir_filter_fff*> d_filters;
+ std::vector<filter::kernel::fir_filter_fff*> d_diff_filters;
+
+ std::vector< std::vector<float> > d_taps;
+ std::vector< std::vector<float> > d_diff_taps;
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_H */
diff --git a/gr-digital/lib/symbol_sync_cc_impl.cc b/gr-digital/lib/symbol_sync_cc_impl.cc
new file mode 100644
index 0000000000..986a7e97de
--- /dev/null
+++ b/gr-digital/lib/symbol_sync_cc_impl.cc
@@ -0,0 +1,654 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "symbol_sync_cc_impl.h"
+#include <boost/math/common_factor.hpp>
+#include <gnuradio/io_signature.h>
+#include <gnuradio/math.h>
+#include <stdexcept>
+
+namespace gr {
+ namespace digital {
+
+ symbol_sync_cc::sptr
+ symbol_sync_cc::make(enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor,
+ float ted_gain,
+ float max_deviation,
+ int osps,
+ constellation_sptr slicer,
+ ir_type interp_type,
+ int n_filters,
+ const std::vector<float> &taps)
+ {
+ return gnuradio::get_initial_sptr
+ (new symbol_sync_cc_impl(detector_type,
+ sps,
+ loop_bw,
+ damping_factor,
+ ted_gain,
+ max_deviation,
+ osps,
+ slicer,
+ interp_type,
+ n_filters,
+ taps));
+ }
+
+ symbol_sync_cc_impl::symbol_sync_cc_impl(
+ enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor,
+ float ted_gain,
+ float max_deviation,
+ int osps,
+ constellation_sptr slicer,
+ ir_type interp_type,
+ int n_filters,
+ const std::vector<float> &taps)
+ : block("symbol_sync_cc",
+ io_signature::make(1, 1, sizeof(gr_complex)),
+ io_signature::makev(1, 4, std::vector<int>(4, sizeof(float)))),
+ d_ted(NULL),
+ d_interp(NULL),
+ d_inst_output_period(sps / static_cast<float>(osps)),
+ d_inst_clock_period(sps),
+ d_avg_clock_period(sps),
+ d_osps(static_cast<float>(osps)),
+ d_osps_n(osps),
+ d_tags(),
+ d_new_tags(),
+ d_time_est_key(pmt::intern("time_est")),
+ d_clock_est_key(pmt::intern("clock_est")),
+ d_noutputs(1),
+ d_out_error(NULL),
+ d_out_instantaneous_clock_period(NULL),
+ d_out_average_clock_period(NULL)
+ {
+ // Brute force fix of the output io_signature, because I can't get
+ // an anonymous std::vector<int>() rvalue, with a const expression
+ // initializing the vector, to work. Lvalues seem to make everything
+ // better.
+ int output_io_sizes[4] = {
+ sizeof(gr_complex),
+ sizeof(float), sizeof(float), sizeof(float)
+ };
+ std::vector<int> output_io_sizes_vector(&output_io_sizes[0],
+ &output_io_sizes[4]);
+ set_output_signature(io_signature::makev(1, 4, output_io_sizes_vector));
+
+ if (sps <= 1.0f)
+ throw std::out_of_range("nominal samples per symbol must be > 1");
+
+ if (osps < 1)
+ throw std::out_of_range("output samples per symbol must be > 0");
+
+ // Timing Error Detector
+ d_ted = timing_error_detector::make(detector_type, slicer);
+ if (d_ted == NULL)
+ throw std::runtime_error("unable to create timing_error_detector");
+
+ // Interpolating Resampler
+ d_interp = interpolating_resampler_ccf::make(interp_type,
+ d_ted->needs_derivative(),
+ n_filters, taps);
+ if (d_interp == NULL)
+ throw std::runtime_error("unable to create interpolating_resampler_ccf");
+
+ // Block Internal Clocks
+ d_interps_per_symbol_n = boost::math::lcm(d_ted->inputs_per_symbol(),
+ d_osps_n);
+ d_interps_per_ted_input_n =
+ d_interps_per_symbol_n / d_ted->inputs_per_symbol();
+ d_interps_per_output_sample_n =
+ d_interps_per_symbol_n / d_osps_n;
+
+ d_interps_per_symbol = static_cast<float>(d_interps_per_symbol_n);
+ d_interps_per_ted_input = static_cast<float>(d_interps_per_ted_input_n);
+
+ d_interp_clock = d_interps_per_symbol_n - 1;
+ sync_reset_internal_clocks();
+ d_inst_interp_period = d_inst_clock_period / d_interps_per_symbol;
+
+ if (d_interps_per_symbol > sps)
+ GR_LOG_WARN(d_logger,
+ boost::format("block performing more interopolations per "
+ "symbol (%3f) than input samples per symbol"
+ "(%3f). Consider reducing osps or "
+ "increasing sps") % d_interps_per_symbol
+ % sps);
+
+ // Symbol Clock Tracking and Estimation
+ d_clock = new clock_tracking_loop(loop_bw,
+ sps + max_deviation,
+ sps - max_deviation,
+ sps,
+ damping_factor,
+ ted_gain);
+
+ // Timing Error Detector
+ d_ted->sync_reset();
+
+ // Interpolating Resampler
+ d_interp->sync_reset(sps);
+
+ // Tag Propagation and Clock Tracking Reset/Resync
+ set_relative_rate (d_osps / sps);
+ set_tag_propagation_policy(TPP_DONT);
+ d_filter_delay = (d_interp->ntaps() + 1) / 2;
+
+ set_output_multiple(d_osps_n);
+ }
+
+ symbol_sync_cc_impl::~symbol_sync_cc_impl()
+ {
+ delete d_ted;
+ delete d_interp;
+ delete d_clock;
+ }
+
+ //
+ // Block Internal Clocks
+ //
+ void
+ symbol_sync_cc_impl::update_internal_clock_outputs()
+ {
+ // a d_interp_clock boolean output would always be true.
+ d_ted_input_clock = (d_interp_clock % d_interps_per_ted_input_n == 0);
+ d_output_sample_clock =
+ (d_interp_clock % d_interps_per_output_sample_n == 0);
+ d_symbol_clock = (d_interp_clock % d_interps_per_symbol_n == 0);
+ }
+
+ void
+ symbol_sync_cc_impl::advance_internal_clocks()
+ {
+ d_interp_clock = (d_interp_clock + 1) % d_interps_per_symbol_n;
+ update_internal_clock_outputs();
+ }
+
+ void
+ symbol_sync_cc_impl::revert_internal_clocks()
+ {
+ if (d_interp_clock == 0)
+ d_interp_clock = d_interps_per_symbol_n - 1;
+ else
+ d_interp_clock--;
+ update_internal_clock_outputs();
+ }
+
+ void
+ symbol_sync_cc_impl::sync_reset_internal_clocks()
+ {
+ d_interp_clock = d_interps_per_symbol_n - 1;
+ update_internal_clock_outputs();
+ }
+
+ //
+ // Tag Propagation and Clock Tracking Reset/Resync
+ //
+ void
+ symbol_sync_cc_impl::collect_tags(uint64_t nitems_rd, int count)
+ {
+ // Get all the tags in offset order
+ // d_new_tags is used to look for time_est and clock_est tags.
+ // d_tags is used for manual tag propagation.
+ d_new_tags.clear();
+ get_tags_in_range(d_new_tags, 0, nitems_rd, nitems_rd + count);
+ std::sort(d_new_tags.begin(), d_new_tags.end(), tag_t::offset_compare);
+ d_tags.insert(d_tags.end(), d_new_tags.begin(), d_new_tags.end());
+ std::sort(d_tags.begin(), d_tags.end(), tag_t::offset_compare);
+ }
+
+ bool
+ symbol_sync_cc_impl::find_sync_tag(uint64_t nitems_rd, int iidx,
+ int distance,
+ uint64_t &tag_offset,
+ float &timing_offset,
+ float &clock_period)
+ {
+ bool found;
+ uint64_t soffset, eoffset;
+ std::vector<tag_t>::iterator t;
+ std::vector<tag_t>::iterator t2;
+
+ // PLL Reset/Resynchronization to time_est & clock_est tags
+ //
+ // Look for a time_est tag between the current interpolated input sample
+ // and the next predicted interpolated input sample. (both rounded up)
+ soffset = nitems_rd + d_filter_delay + static_cast<uint64_t>(iidx + 1);
+ eoffset = soffset + distance;
+ found = false;
+ for (t = d_new_tags.begin();
+ t != d_new_tags.end();
+ t = d_new_tags.erase(t)) {
+
+ if (t->offset > eoffset) // search finished
+ break;
+
+ if (t->offset < soffset) // tag is in the past of what we care about
+ continue;
+
+ if (not pmt::eq(t->key, d_time_est_key) and // not a time_est tag
+ not pmt::eq(t->key, d_clock_est_key) ) // not a clock_est tag
+ continue;
+
+ found = true;
+ tag_offset = t->offset;
+ if (pmt::eq(t->key, d_time_est_key)) {
+ // got a time_est tag
+ timing_offset = static_cast<float>(pmt::to_double(t->value));
+ // next instantaneous clock period estimate will be nominal
+ clock_period = d_clock->get_nom_avg_period();
+
+ // Look for a clock_est tag at the same offset,
+ // as we prefer clock_est tags
+ for (t2 = ++t; t2 != d_new_tags.end(); ++t2) {
+ if (t2->offset > t->offset) // search finished
+ break;
+ if (not pmt::eq(t->key, d_clock_est_key)) // not a clock_est
+ continue;
+ // Found a clock_est tag at the same offset
+ tag_offset = t2->offset;
+ timing_offset = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t2->value, 0)));
+ clock_period = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t2->value, 1)));
+ break;
+ }
+ } else {
+ // got a clock_est tag
+ timing_offset = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t->value, 0)));
+ clock_period = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t->value, 1)));
+ }
+
+ if (not(timing_offset >= -1.0f and timing_offset <= 1.0f)) {
+ // the time_est/clock_est tag's payload is invalid
+ GR_LOG_WARN(d_logger,
+ boost::format("ignoring time_est/clock_est tag with"
+ " value %.2f, outside of allowed "
+ "range [-1.0, 1.0]") % timing_offset);
+ found = false;
+ continue;
+ }
+
+ if (t->offset == soffset and timing_offset < 0.0f) {
+ // already handled times earlier than this previously
+ found = false;
+ continue;
+ }
+
+ if (t->offset == eoffset and timing_offset >= 0.0f) {
+ // handle times greater than this later
+ found = false;
+ break;
+ }
+
+ if (found == true)
+ break;
+ }
+ return found;
+ }
+
+ void
+ symbol_sync_cc_impl::propagate_tags(uint64_t nitems_rd, int iidx,
+ float iidx_fraction,
+ float inst_output_period,
+ uint64_t nitems_wr, int oidx)
+ {
+ // Tag Propagation
+ //
+ // Onto this output sample, place all the remaining tags that
+ // came before the interpolated input sample, and all the tags
+ // on and after the interpolated input sample, up to half way to
+ // the next output sample.
+
+ uint64_t mid_period_offset = nitems_rd + d_filter_delay
+ + static_cast<uint64_t>(iidx)
+ + static_cast<uint64_t>(llroundf(iidx_fraction
+ + inst_output_period/2.0f));
+
+ uint64_t output_offset = nitems_wr + static_cast<uint64_t>(oidx);
+
+ int i;
+ std::vector<tag_t>::iterator t;
+ for (t = d_tags.begin();
+ t != d_tags.end() and t->offset <= mid_period_offset;
+ t = d_tags.erase(t)) {
+ t->offset = output_offset;
+ for (i = 0; i < d_noutputs; i++)
+ add_item_tag(i, *t);
+ }
+ }
+
+ void
+ symbol_sync_cc_impl::save_expiring_tags(uint64_t nitems_rd,
+ int consumed)
+ {
+ // Deferred Tag Propagation
+ //
+ // Only save away input tags that will not be available
+ // in the next call to general_work(). Otherwise we would
+ // create duplicate tags next time around.
+ // Tags that have already been propagated, have already been erased
+ // from d_tags.
+
+ uint64_t consumed_offset = nitems_rd + static_cast<uint64_t>(consumed);
+ std::vector<tag_t>::iterator t;
+
+ for (t = d_tags.begin(); t != d_tags.end(); ) {
+ if (t->offset < consumed_offset)
+ ++t;
+ else
+ t = d_tags.erase(t);
+ }
+ }
+
+ //
+ // Optional Diagnostic Outputs
+ //
+ void
+ symbol_sync_cc_impl::setup_optional_outputs(
+ gr_vector_void_star &output_items)
+ {
+ d_noutputs = output_items.size();
+ d_out_error = NULL;
+ d_out_instantaneous_clock_period = NULL;
+ d_out_average_clock_period = NULL;
+
+ if (d_noutputs < 2)
+ return;
+ d_out_error = (float *) output_items[1];
+
+ if (d_noutputs < 3)
+ return;
+ d_out_instantaneous_clock_period = (float *) output_items[2];
+
+ if (d_noutputs < 4)
+ return;
+ d_out_average_clock_period = (float *) output_items[3];
+ }
+
+ void
+ symbol_sync_cc_impl::emit_optional_output(int oidx,
+ float error,
+ float inst_clock_period,
+ float avg_clock_period)
+ {
+ if (d_noutputs < 2)
+ return;
+ d_out_error[oidx] = error;
+
+ if (d_noutputs < 3)
+ return;
+ d_out_instantaneous_clock_period[oidx] = inst_clock_period;
+
+ if (d_noutputs < 4)
+ return;
+ d_out_average_clock_period[oidx] = avg_clock_period;
+ }
+
+ void
+ symbol_sync_cc_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ unsigned ninputs = ninput_items_required.size();
+
+ // The '+ 2' in the expression below is an effort to always have at
+ // least one output sample, even if the main loop decides it has to
+ // revert one computed sample and wait for the next call to
+ // general_work().
+ // The d_clock->get_max_avg_period() is also an effort to do the same,
+ // in case we have the worst case allowable clock timing deviation on
+ // input.
+ int answer = static_cast<int>(
+ ceilf(static_cast<float>(noutput_items + 2)
+ * d_clock->get_max_avg_period() / d_osps))
+ + static_cast<int>(d_interp->ntaps());
+
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = answer;
+ }
+
+ int
+ symbol_sync_cc_impl::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ // max input to consume
+ int ni = ninput_items[0] - static_cast<int>(d_interp->ntaps());
+ if (ni <= 0)
+ return 0;
+
+ const gr_complex *in = (const gr_complex *)input_items[0];
+ gr_complex *out = (gr_complex *)output_items[0];
+
+ setup_optional_outputs(output_items);
+
+ int ii = 0; // input index
+ int oo = 0; // output index
+ gr_complex interp_output;
+ gr_complex interp_derivative = gr_complex(0.0f, 0.0f);
+ float error;
+ float look_ahead_phase = 0.0f;
+ int look_ahead_phase_n = 0;
+ float look_ahead_phase_wrapped = 0.0f;
+
+ uint64_t nitems_rd = nitems_read(0);
+ uint64_t nitems_wr = nitems_written(0);
+ uint64_t sync_tag_offset;
+ float sync_timing_offset;
+ float sync_clock_period;
+
+ // Tag Propagation and Symbol Clock Tracking Reset/Resync
+ collect_tags(nitems_rd, ni);
+
+ while (oo < noutput_items) {
+ // Block Internal Clocks
+ advance_internal_clocks();
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ interp_output = d_interp->interpolate(&in[ii],
+ d_interp->phase_wrapped());
+ if (output_sample_clock())
+ out[oo] = interp_output;
+
+ // Timing Error Detector
+ if (ted_input_clock()) {
+ if (d_ted->needs_derivative())
+ interp_derivative =
+ d_interp->differentiate(&in[ii], d_interp->phase_wrapped());
+ d_ted->input(interp_output, interp_derivative);
+ }
+ if (symbol_clock() and d_ted->needs_lookahead()) {
+ // N.B. symbol_clock() == true implies ted_input_clock() == true
+ // N.B. symbol_clock() == true implies output_sample_clock() == true
+
+ // We must interpolate ahead to the *next* ted_input_clock, so the
+ // ted will compute the error for *this* symbol.
+ d_interp->next_phase(d_interps_per_ted_input
+ * (d_clock->get_inst_period()
+ / d_interps_per_symbol),
+ look_ahead_phase,
+ look_ahead_phase_n,
+ look_ahead_phase_wrapped);
+
+ if (ii + look_ahead_phase_n >= ni) {
+ // We can't compute the look ahead interpolated output
+ // because there's not enough input.
+ // Revert the actions we took in the loop so far, and bail out.
+
+ // Symbol Clock Tracking and Estimation
+ // We haven't advanced the clock loop yet; no revert needed.
+
+ // Timing Error Detector
+ d_ted->revert(true); // keep the error value; it's still good
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ // Nothing to do
+
+ // Block Internal Clocks
+ revert_internal_clocks();
+ break;
+ }
+ // Give the ted the look ahead input that it needs to compute
+ // the error for *this* symbol.
+ interp_output = d_interp->interpolate(&in[ii + look_ahead_phase_n],
+ look_ahead_phase_wrapped);
+ if (d_ted->needs_derivative())
+ interp_derivative =
+ d_interp->differentiate(&in[ii + look_ahead_phase_n],
+ look_ahead_phase_wrapped);
+ d_ted->input_lookahead(interp_output, interp_derivative);
+ }
+ error = d_ted->error();
+
+ if (symbol_clock()) {
+ // Symbol Clock Tracking and Estimation
+ d_clock->advance_loop(error);
+ d_inst_clock_period = d_clock->get_inst_period();
+ d_avg_clock_period = d_clock->get_avg_period();
+ d_clock->phase_wrap();
+ d_clock->period_limit();
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ d_inst_interp_period = d_inst_clock_period / d_interps_per_symbol;
+
+ // Tag Propagation
+ d_inst_output_period = d_inst_clock_period / d_osps;
+ }
+
+ // Symbol Clock, Interpolator Positioning & Alignment, and
+ // Tag Propagation
+ if (symbol_clock()) {
+ // N.B. symbol_clock() == true implies ted_input_clock() == true
+ // N.B. symbol_clock() == true implies output_sample_clock() == true
+
+ // This check and revert is needed either when
+ // a) the samples per symbol to get to the next symbol is greater
+ // than d_interp->ntaps() (normally 8); thus we would consume()
+ // more input than we were given to get there.
+ // b) we can't get to the next output so we can't do tag
+ // propagation properly.
+ d_interp->next_phase(d_inst_clock_period,
+ look_ahead_phase,
+ look_ahead_phase_n,
+ look_ahead_phase_wrapped);
+
+ if (ii + look_ahead_phase_n >= ni) {
+ // We can't move forward because there's not enough input.
+ // Revert the actions we took in the loop so far, and bail out.
+
+ // Symbol Clock Tracking and Estimation
+ d_clock->revert_loop();
+
+ // Timing Error Detector
+ d_ted->revert();
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ // Nothing to do;
+
+ // Block Internal Clocks
+ revert_internal_clocks();
+ break;
+ }
+ }
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ d_interp->advance_phase(d_inst_interp_period);
+
+ // Symbol Clock Tracking Reset/Resync to time_est and clock_est tags
+ if (find_sync_tag(nitems_rd, ii, d_interp->phase_n(), sync_tag_offset,
+ sync_timing_offset, sync_clock_period) == true ) {
+
+ // Block Internal Clocks
+ sync_reset_internal_clocks();
+
+ // Timing Error Detector
+ d_ted->sync_reset();
+ error = d_ted->error();
+
+ // Symbol Clock Tracking and Estimation
+
+ // NOTE: the + 1 below was determined empirically, but doesn't
+ // seem right on paper (maybe rounding in the computation of
+ // d_filter_delay is the culprit). Anyway, experiment trumps
+ // theory *every* time; so + 1 it is.
+ d_inst_clock_period = static_cast<float>(
+ static_cast<int>(sync_tag_offset - nitems_rd - d_filter_delay)
+ - ii + 1) + sync_timing_offset - d_interp->phase_wrapped();
+
+ d_clock->set_inst_period(d_inst_clock_period);
+ d_clock->set_avg_period(sync_clock_period);
+ d_avg_clock_period = d_clock->get_avg_period();
+ d_clock->set_phase(0.0f);
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ d_inst_interp_period = d_inst_clock_period;
+ d_interp->revert_phase();
+ d_interp->advance_phase(d_inst_interp_period);
+
+ // Tag Propagation
+ // Only needed if we reverted back to an output_sample_clock()
+ // as this is only used for tag propagation. Note that the
+ // next output will also be both an output_sample_clock() and a
+ // symbol_clock().
+ d_inst_output_period = d_inst_clock_period;
+ }
+
+ if (output_sample_clock()) {
+ // Diagnostic Output of Symbol Clock Tracking cycle results
+ emit_optional_output(oo, error, d_inst_clock_period,
+ d_avg_clock_period);
+ // Tag Propagation
+ propagate_tags(nitems_rd, ii,
+ d_interp->prev_phase_wrapped(), d_inst_output_period,
+ nitems_wr, oo);
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ oo++;
+ }
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ ii += d_interp->phase_n();
+ }
+
+ // Deferred Tag Propagation
+ save_expiring_tags(nitems_rd, ii);
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ consume_each(ii);
+ return oo;
+ }
+
+ } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/symbol_sync_cc_impl.h b/gr-digital/lib/symbol_sync_cc_impl.h
new file mode 100644
index 0000000000..a146f7ed2e
--- /dev/null
+++ b/gr-digital/lib/symbol_sync_cc_impl.h
@@ -0,0 +1,156 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_SYMBOL_SYNC_CC_IMPL_H
+#define INCLUDED_DIGITAL_SYMBOL_SYNC_CC_IMPL_H
+
+#include <gnuradio/digital/symbol_sync_cc.h>
+#include "clock_tracking_loop.h"
+#include "timing_error_detector.h"
+#include "interpolating_resampler.h"
+
+namespace gr {
+ namespace digital {
+
+ class symbol_sync_cc_impl : public symbol_sync_cc
+ {
+ public:
+ symbol_sync_cc_impl(enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor,
+ float ted_gain,
+ float max_deviation,
+ int osps,
+ constellation_sptr slicer,
+ ir_type interp_type,
+ int n_filters,
+ const std::vector<float> &taps);
+ ~symbol_sync_cc_impl();
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+ int general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ // Symbol Clock Tracking and Estimation
+ float loop_bandwidth() const { return d_clock->get_loop_bandwidth(); }
+ float damping_factor() const { return d_clock->get_damping_factor(); }
+ float ted_gain() const { return d_clock->get_ted_gain(); }
+ float alpha() const { return d_clock->get_alpha(); }
+ float beta() const { return d_clock->get_beta(); }
+
+ void set_loop_bandwidth (float omega_n_norm) {
+ d_clock->set_loop_bandwidth(omega_n_norm);
+ }
+ void set_damping_factor (float zeta) {
+ d_clock->set_damping_factor(zeta);
+ }
+ void set_ted_gain (float ted_gain) { d_clock->set_ted_gain(ted_gain); }
+ void set_alpha (float alpha) { d_clock->set_alpha(alpha); }
+ void set_beta (float beta) { d_clock->set_beta(beta); }
+
+ private:
+ // Timing Error Detector
+ timing_error_detector *d_ted;
+
+ // Symbol Clock Tracking and Estimation
+ clock_tracking_loop *d_clock;
+
+ // Interpolator and Interpolator Positioning and Alignment
+ interpolating_resampler_ccf *d_interp;
+
+ // Block Internal Clocks
+ // 4 clocks that run synchronously, aligned to the Symbol Clock:
+ // Interpolator Clock (always highest rate)
+ // Timing Error Detector Input Clock
+ // Output Sample Clock
+ // Symbol Clock (always lowest rate)
+ int d_interp_clock;
+ float d_inst_interp_period;
+
+ float d_interps_per_ted_input;
+ int d_interps_per_ted_input_n;
+ bool d_ted_input_clock;
+
+ int d_interps_per_output_sample_n;
+ bool d_output_sample_clock;
+ float d_inst_output_period;
+
+ float d_interps_per_symbol;
+ int d_interps_per_symbol_n;
+ bool d_symbol_clock;
+ float d_inst_clock_period;
+ float d_avg_clock_period;
+
+ // Block output
+ float d_osps;
+ int d_osps_n;
+
+ // Tag Propagation and Symbol Clock Tracking Reset/Resync
+ uint64_t d_filter_delay; // interpolator filter delay
+ std::vector<tag_t> d_tags;
+ std::vector<tag_t> d_new_tags;
+ pmt::pmt_t d_time_est_key;
+ pmt::pmt_t d_clock_est_key;
+
+ // Optional Diagnostic Outputs
+ int d_noutputs;
+ float *d_out_error;
+ float *d_out_instantaneous_clock_period;
+ float *d_out_average_clock_period;
+
+ // Block Internal Clocks
+ void update_internal_clock_outputs();
+ void advance_internal_clocks();
+ void revert_internal_clocks();
+ void sync_reset_internal_clocks();
+ bool ted_input_clock() { return d_ted_input_clock; }
+ bool output_sample_clock() { return d_output_sample_clock; }
+ bool symbol_clock() { return d_symbol_clock; }
+
+ // Tag Propagation and Clock Tracking Reset/Resync
+ void collect_tags(uint64_t nitems_rd, int count);
+ bool find_sync_tag(uint64_t nitems_rd, int iidx,
+ int distance,
+ uint64_t &tag_offset,
+ float &timing_offset,
+ float &clock_period);
+ void propagate_tags(uint64_t nitems_rd, int iidx,
+ float iidx_fraction,
+ float inst_output_period,
+ uint64_t nitems_wr, int oidx);
+ void save_expiring_tags(uint64_t nitems_rd, int consumed);
+
+ // Optional Diagnostic Outputs
+ void setup_optional_outputs(gr_vector_void_star &output_items);
+ void emit_optional_output(int oidx,
+ float error,
+ float inst_clock_period,
+ float avg_clock_period);
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_SYMBOL_SYNC_CC_IMPL_H */
diff --git a/gr-digital/lib/symbol_sync_ff_impl.cc b/gr-digital/lib/symbol_sync_ff_impl.cc
new file mode 100644
index 0000000000..2497e52359
--- /dev/null
+++ b/gr-digital/lib/symbol_sync_ff_impl.cc
@@ -0,0 +1,654 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "symbol_sync_ff_impl.h"
+#include <boost/math/common_factor.hpp>
+#include <gnuradio/io_signature.h>
+#include <gnuradio/math.h>
+#include <stdexcept>
+
+namespace gr {
+ namespace digital {
+
+ symbol_sync_ff::sptr
+ symbol_sync_ff::make(enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor,
+ float ted_gain,
+ float max_deviation,
+ int osps,
+ constellation_sptr slicer,
+ ir_type interp_type,
+ int n_filters,
+ const std::vector<float> &taps)
+ {
+ return gnuradio::get_initial_sptr
+ (new symbol_sync_ff_impl(detector_type,
+ sps,
+ loop_bw,
+ damping_factor,
+ ted_gain,
+ max_deviation,
+ osps,
+ slicer,
+ interp_type,
+ n_filters,
+ taps));
+ }
+
+ symbol_sync_ff_impl::symbol_sync_ff_impl(
+ enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor,
+ float ted_gain,
+ float max_deviation,
+ int osps,
+ constellation_sptr slicer,
+ ir_type interp_type,
+ int n_filters,
+ const std::vector<float> &taps)
+ : block("symbol_sync_ff",
+ io_signature::make(1, 1, sizeof(float)),
+ io_signature::makev(1, 4, std::vector<int>(4, sizeof(float)))),
+ d_ted(NULL),
+ d_interp(NULL),
+ d_inst_output_period(sps / static_cast<float>(osps)),
+ d_inst_clock_period(sps),
+ d_avg_clock_period(sps),
+ d_osps(static_cast<float>(osps)),
+ d_osps_n(osps),
+ d_tags(),
+ d_new_tags(),
+ d_time_est_key(pmt::intern("time_est")),
+ d_clock_est_key(pmt::intern("clock_est")),
+ d_noutputs(1),
+ d_out_error(NULL),
+ d_out_instantaneous_clock_period(NULL),
+ d_out_average_clock_period(NULL)
+ {
+ // Brute force fix of the output io_signature, because I can't get
+ // an anonymous std::vector<int>() rvalue, with a const expression
+ // initializing the vector, to work. Lvalues seem to make everything
+ // better.
+ int output_io_sizes[4] = {
+ sizeof(float),
+ sizeof(float), sizeof(float), sizeof(float)
+ };
+ std::vector<int> output_io_sizes_vector(&output_io_sizes[0],
+ &output_io_sizes[4]);
+ set_output_signature(io_signature::makev(1, 4, output_io_sizes_vector));
+
+ if (sps <= 1.0f)
+ throw std::out_of_range("nominal samples per symbol must be > 1");
+
+ if (osps < 1)
+ throw std::out_of_range("output samples per symbol must be > 0");
+
+ // Timing Error Detector
+ d_ted = timing_error_detector::make(detector_type, slicer);
+ if (d_ted == NULL)
+ throw std::runtime_error("unable to create timing_error_detector");
+
+ // Interpolating Resampler
+ d_interp = interpolating_resampler_fff::make(interp_type,
+ d_ted->needs_derivative(),
+ n_filters, taps);
+ if (d_interp == NULL)
+ throw std::runtime_error("unable to create interpolating_resampler_fff");
+
+ // Block Internal Clocks
+ d_interps_per_symbol_n = boost::math::lcm(d_ted->inputs_per_symbol(),
+ d_osps_n);
+ d_interps_per_ted_input_n =
+ d_interps_per_symbol_n / d_ted->inputs_per_symbol();
+ d_interps_per_output_sample_n =
+ d_interps_per_symbol_n / d_osps_n;
+
+ d_interps_per_symbol = static_cast<float>(d_interps_per_symbol_n);
+ d_interps_per_ted_input = static_cast<float>(d_interps_per_ted_input_n);
+
+ d_interp_clock = d_interps_per_symbol_n - 1;
+ sync_reset_internal_clocks();
+ d_inst_interp_period = d_inst_clock_period / d_interps_per_symbol;
+
+ if (d_interps_per_symbol > sps)
+ GR_LOG_WARN(d_logger,
+ boost::format("block performing more interopolations per "
+ "symbol (%3f) than input samples per symbol"
+ "(%3f). Consider reducing osps or "
+ "increasing sps") % d_interps_per_symbol
+ % sps);
+
+ // Symbol Clock Tracking and Estimation
+ d_clock = new clock_tracking_loop(loop_bw,
+ sps + max_deviation,
+ sps - max_deviation,
+ sps,
+ damping_factor,
+ ted_gain);
+
+ // Timing Error Detector
+ d_ted->sync_reset();
+
+ // Interpolating Resampler
+ d_interp->sync_reset(sps);
+
+ // Tag Propagation and Clock Tracking Reset/Resync
+ set_relative_rate (d_osps / sps);
+ set_tag_propagation_policy(TPP_DONT);
+ d_filter_delay = (d_interp->ntaps() + 1) / 2;
+
+ set_output_multiple(d_osps_n);
+ }
+
+ symbol_sync_ff_impl::~symbol_sync_ff_impl()
+ {
+ delete d_ted;
+ delete d_interp;
+ delete d_clock;
+ }
+
+ //
+ // Block Internal Clocks
+ //
+ void
+ symbol_sync_ff_impl::update_internal_clock_outputs()
+ {
+ // a d_interp_clock boolean output would always be true.
+ d_ted_input_clock = (d_interp_clock % d_interps_per_ted_input_n == 0);
+ d_output_sample_clock =
+ (d_interp_clock % d_interps_per_output_sample_n == 0);
+ d_symbol_clock = (d_interp_clock % d_interps_per_symbol_n == 0);
+ }
+
+ void
+ symbol_sync_ff_impl::advance_internal_clocks()
+ {
+ d_interp_clock = (d_interp_clock + 1) % d_interps_per_symbol_n;
+ update_internal_clock_outputs();
+ }
+
+ void
+ symbol_sync_ff_impl::revert_internal_clocks()
+ {
+ if (d_interp_clock == 0)
+ d_interp_clock = d_interps_per_symbol_n - 1;
+ else
+ d_interp_clock--;
+ update_internal_clock_outputs();
+ }
+
+ void
+ symbol_sync_ff_impl::sync_reset_internal_clocks()
+ {
+ d_interp_clock = d_interps_per_symbol_n - 1;
+ update_internal_clock_outputs();
+ }
+
+ //
+ // Tag Propagation and Clock Tracking Reset/Resync
+ //
+ void
+ symbol_sync_ff_impl::collect_tags(uint64_t nitems_rd, int count)
+ {
+ // Get all the tags in offset order
+ // d_new_tags is used to look for time_est and clock_est tags.
+ // d_tags is used for manual tag propagation.
+ d_new_tags.clear();
+ get_tags_in_range(d_new_tags, 0, nitems_rd, nitems_rd + count);
+ std::sort(d_new_tags.begin(), d_new_tags.end(), tag_t::offset_compare);
+ d_tags.insert(d_tags.end(), d_new_tags.begin(), d_new_tags.end());
+ std::sort(d_tags.begin(), d_tags.end(), tag_t::offset_compare);
+ }
+
+ bool
+ symbol_sync_ff_impl::find_sync_tag(uint64_t nitems_rd, int iidx,
+ int distance,
+ uint64_t &tag_offset,
+ float &timing_offset,
+ float &clock_period)
+ {
+ bool found;
+ uint64_t soffset, eoffset;
+ std::vector<tag_t>::iterator t;
+ std::vector<tag_t>::iterator t2;
+
+ // PLL Reset/Resynchronization to time_est & clock_est tags
+ //
+ // Look for a time_est tag between the current interpolated input sample
+ // and the next predicted interpolated input sample. (both rounded up)
+ soffset = nitems_rd + d_filter_delay + static_cast<uint64_t>(iidx + 1);
+ eoffset = soffset + distance;
+ found = false;
+ for (t = d_new_tags.begin();
+ t != d_new_tags.end();
+ t = d_new_tags.erase(t)) {
+
+ if (t->offset > eoffset) // search finished
+ break;
+
+ if (t->offset < soffset) // tag is in the past of what we care about
+ continue;
+
+ if (not pmt::eq(t->key, d_time_est_key) and // not a time_est tag
+ not pmt::eq(t->key, d_clock_est_key) ) // not a clock_est tag
+ continue;
+
+ found = true;
+ tag_offset = t->offset;
+ if (pmt::eq(t->key, d_time_est_key)) {
+ // got a time_est tag
+ timing_offset = static_cast<float>(pmt::to_double(t->value));
+ // next instantaneous clock period estimate will be nominal
+ clock_period = d_clock->get_nom_avg_period();
+
+ // Look for a clock_est tag at the same offset,
+ // as we prefer clock_est tags
+ for (t2 = ++t; t2 != d_new_tags.end(); ++t2) {
+ if (t2->offset > t->offset) // search finished
+ break;
+ if (not pmt::eq(t->key, d_clock_est_key)) // not a clock_est
+ continue;
+ // Found a clock_est tag at the same offset
+ tag_offset = t2->offset;
+ timing_offset = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t2->value, 0)));
+ clock_period = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t2->value, 1)));
+ break;
+ }
+ } else {
+ // got a clock_est tag
+ timing_offset = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t->value, 0)));
+ clock_period = static_cast<float>(
+ pmt::to_double(pmt::tuple_ref(t->value, 1)));
+ }
+
+ if (not(timing_offset >= -1.0f and timing_offset <= 1.0f)) {
+ // the time_est/clock_est tag's payload is invalid
+ GR_LOG_WARN(d_logger,
+ boost::format("ignoring time_est/clock_est tag with"
+ " value %.2f, outside of allowed "
+ "range [-1.0, 1.0]") % timing_offset);
+ found = false;
+ continue;
+ }
+
+ if (t->offset == soffset and timing_offset < 0.0f) {
+ // already handled times earlier than this previously
+ found = false;
+ continue;
+ }
+
+ if (t->offset == eoffset and timing_offset >= 0.0f) {
+ // handle times greater than this later
+ found = false;
+ break;
+ }
+
+ if (found == true)
+ break;
+ }
+ return found;
+ }
+
+ void
+ symbol_sync_ff_impl::propagate_tags(uint64_t nitems_rd, int iidx,
+ float iidx_fraction,
+ float inst_output_period,
+ uint64_t nitems_wr, int oidx)
+ {
+ // Tag Propagation
+ //
+ // Onto this output sample, place all the remaining tags that
+ // came before the interpolated input sample, and all the tags
+ // on and after the interpolated input sample, up to half way to
+ // the next output sample.
+
+ uint64_t mid_period_offset = nitems_rd + d_filter_delay
+ + static_cast<uint64_t>(iidx)
+ + static_cast<uint64_t>(llroundf(iidx_fraction
+ + inst_output_period/2.0f));
+
+ uint64_t output_offset = nitems_wr + static_cast<uint64_t>(oidx);
+
+ int i;
+ std::vector<tag_t>::iterator t;
+ for (t = d_tags.begin();
+ t != d_tags.end() and t->offset <= mid_period_offset;
+ t = d_tags.erase(t)) {
+ t->offset = output_offset;
+ for (i = 0; i < d_noutputs; i++)
+ add_item_tag(i, *t);
+ }
+ }
+
+ void
+ symbol_sync_ff_impl::save_expiring_tags(uint64_t nitems_rd,
+ int consumed)
+ {
+ // Deferred Tag Propagation
+ //
+ // Only save away input tags that will not be available
+ // in the next call to general_work(). Otherwise we would
+ // create duplicate tags next time around.
+ // Tags that have already been propagated, have already been erased
+ // from d_tags.
+
+ uint64_t consumed_offset = nitems_rd + static_cast<uint64_t>(consumed);
+ std::vector<tag_t>::iterator t;
+
+ for (t = d_tags.begin(); t != d_tags.end(); ) {
+ if (t->offset < consumed_offset)
+ ++t;
+ else
+ t = d_tags.erase(t);
+ }
+ }
+
+ //
+ // Optional Diagnostic Outputs
+ //
+ void
+ symbol_sync_ff_impl::setup_optional_outputs(
+ gr_vector_void_star &output_items)
+ {
+ d_noutputs = output_items.size();
+ d_out_error = NULL;
+ d_out_instantaneous_clock_period = NULL;
+ d_out_average_clock_period = NULL;
+
+ if (d_noutputs < 2)
+ return;
+ d_out_error = (float *) output_items[1];
+
+ if (d_noutputs < 3)
+ return;
+ d_out_instantaneous_clock_period = (float *) output_items[2];
+
+ if (d_noutputs < 4)
+ return;
+ d_out_average_clock_period = (float *) output_items[3];
+ }
+
+ void
+ symbol_sync_ff_impl::emit_optional_output(int oidx,
+ float error,
+ float inst_clock_period,
+ float avg_clock_period)
+ {
+ if (d_noutputs < 2)
+ return;
+ d_out_error[oidx] = error;
+
+ if (d_noutputs < 3)
+ return;
+ d_out_instantaneous_clock_period[oidx] = inst_clock_period;
+
+ if (d_noutputs < 4)
+ return;
+ d_out_average_clock_period[oidx] = avg_clock_period;
+ }
+
+ void
+ symbol_sync_ff_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ unsigned ninputs = ninput_items_required.size();
+
+ // The '+ 2' in the expression below is an effort to always have at
+ // least one output sample, even if the main loop decides it has to
+ // revert one computed sample and wait for the next call to
+ // general_work().
+ // The d_clock->get_max_avg_period() is also an effort to do the same,
+ // in case we have the worst case allowable clock timing deviation on
+ // input.
+ int answer = static_cast<int>(
+ ceilf(static_cast<float>(noutput_items + 2)
+ * d_clock->get_max_avg_period() / d_osps))
+ + static_cast<int>(d_interp->ntaps());
+
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = answer;
+ }
+
+ int
+ symbol_sync_ff_impl::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ // max input to consume
+ int ni = ninput_items[0] - static_cast<int>(d_interp->ntaps());
+ if (ni <= 0)
+ return 0;
+
+ const float *in = (const float *)input_items[0];
+ float *out = (float *)output_items[0];
+
+ setup_optional_outputs(output_items);
+
+ int ii = 0; // input index
+ int oo = 0; // output index
+ float interp_output;
+ float interp_derivative = 0.0f;
+ float error;
+ float look_ahead_phase = 0.0f;
+ int look_ahead_phase_n = 0;
+ float look_ahead_phase_wrapped = 0.0f;
+
+ uint64_t nitems_rd = nitems_read(0);
+ uint64_t nitems_wr = nitems_written(0);
+ uint64_t sync_tag_offset;
+ float sync_timing_offset;
+ float sync_clock_period;
+
+ // Tag Propagation and Symbol Clock Tracking Reset/Resync
+ collect_tags(nitems_rd, ni);
+
+ while (oo < noutput_items) {
+ // Block Internal Clocks
+ advance_internal_clocks();
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ interp_output = d_interp->interpolate(&in[ii],
+ d_interp->phase_wrapped());
+ if (output_sample_clock())
+ out[oo] = interp_output;
+
+ // Timing Error Detector
+ if (ted_input_clock()) {
+ if (d_ted->needs_derivative())
+ interp_derivative =
+ d_interp->differentiate(&in[ii], d_interp->phase_wrapped());
+ d_ted->input(interp_output, interp_derivative);
+ }
+ if (symbol_clock() and d_ted->needs_lookahead()) {
+ // N.B. symbol_clock() == true implies ted_input_clock() == true
+ // N.B. symbol_clock() == true implies output_sample_clock() == true
+
+ // We must interpolate ahead to the *next* ted_input_clock, so the
+ // ted will compute the error for *this* symbol.
+ d_interp->next_phase(d_interps_per_ted_input
+ * (d_clock->get_inst_period()
+ / d_interps_per_symbol),
+ look_ahead_phase,
+ look_ahead_phase_n,
+ look_ahead_phase_wrapped);
+
+ if (ii + look_ahead_phase_n >= ni) {
+ // We can't compute the look ahead interpolated output
+ // because there's not enough input.
+ // Revert the actions we took in the loop so far, and bail out.
+
+ // Symbol Clock Tracking and Estimation
+ // We haven't advanced the clock loop yet; no revert needed.
+
+ // Timing Error Detector
+ d_ted->revert(true); // keep the error value; it's still good
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ // Nothing to do
+
+ // Block Internal Clocks
+ revert_internal_clocks();
+ break;
+ }
+ // Give the ted the look ahead input that it needs to compute
+ // the error for *this* symbol.
+ interp_output = d_interp->interpolate(&in[ii + look_ahead_phase_n],
+ look_ahead_phase_wrapped);
+ if (d_ted->needs_derivative())
+ interp_derivative =
+ d_interp->differentiate(&in[ii + look_ahead_phase_n],
+ look_ahead_phase_wrapped);
+ d_ted->input_lookahead(interp_output, interp_derivative);
+ }
+ error = d_ted->error();
+
+ if (symbol_clock()) {
+ // Symbol Clock Tracking and Estimation
+ d_clock->advance_loop(error);
+ d_inst_clock_period = d_clock->get_inst_period();
+ d_avg_clock_period = d_clock->get_avg_period();
+ d_clock->phase_wrap();
+ d_clock->period_limit();
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ d_inst_interp_period = d_inst_clock_period / d_interps_per_symbol;
+
+ // Tag Propagation
+ d_inst_output_period = d_inst_clock_period / d_osps;
+ }
+
+ // Symbol Clock, Interpolator Positioning & Alignment, and
+ // Tag Propagation
+ if (symbol_clock()) {
+ // N.B. symbol_clock() == true implies ted_input_clock() == true
+ // N.B. symbol_clock() == true implies output_sample_clock() == true
+
+ // This check and revert is needed either when
+ // a) the samples per symbol to get to the next symbol is greater
+ // than d_interp->ntaps() (normally 8); thus we would consume()
+ // more input than we were given to get there.
+ // b) we can't get to the next output so we can't do tag
+ // propagation properly.
+ d_interp->next_phase(d_inst_clock_period,
+ look_ahead_phase,
+ look_ahead_phase_n,
+ look_ahead_phase_wrapped);
+
+ if (ii + look_ahead_phase_n >= ni) {
+ // We can't move forward because there's not enough input.
+ // Revert the actions we took in the loop so far, and bail out.
+
+ // Symbol Clock Tracking and Estimation
+ d_clock->revert_loop();
+
+ // Timing Error Detector
+ d_ted->revert();
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ // Nothing to do;
+
+ // Block Internal Clocks
+ revert_internal_clocks();
+ break;
+ }
+ }
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ d_interp->advance_phase(d_inst_interp_period);
+
+ // Symbol Clock Tracking Reset/Resync to time_est and clock_est tags
+ if (find_sync_tag(nitems_rd, ii, d_interp->phase_n(), sync_tag_offset,
+ sync_timing_offset, sync_clock_period) == true ) {
+
+ // Block Internal Clocks
+ sync_reset_internal_clocks();
+
+ // Timing Error Detector
+ d_ted->sync_reset();
+ error = d_ted->error();
+
+ // Symbol Clock Tracking and Estimation
+
+ // NOTE: the + 1 below was determined empirically, but doesn't
+ // seem right on paper (maybe rounding in the computation of
+ // d_filter_delay is the culprit). Anyway, experiment trumps
+ // theory *every* time; so + 1 it is.
+ d_inst_clock_period = static_cast<float>(
+ static_cast<int>(sync_tag_offset - nitems_rd - d_filter_delay)
+ - ii + 1) + sync_timing_offset - d_interp->phase_wrapped();
+
+ d_clock->set_inst_period(d_inst_clock_period);
+ d_clock->set_avg_period(sync_clock_period);
+ d_avg_clock_period = d_clock->get_avg_period();
+ d_clock->set_phase(0.0f);
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ d_inst_interp_period = d_inst_clock_period;
+ d_interp->revert_phase();
+ d_interp->advance_phase(d_inst_interp_period);
+
+ // Tag Propagation
+ // Only needed if we reverted back to an output_sample_clock()
+ // as this is only used for tag propagation. Note that the
+ // next output will also be both an output_sample_clock() and a
+ // symbol_clock().
+ d_inst_output_period = d_inst_clock_period;
+ }
+
+ if (output_sample_clock()) {
+ // Diagnostic Output of Symbol Clock Tracking cycle results
+ emit_optional_output(oo, error, d_inst_clock_period,
+ d_avg_clock_period);
+ // Tag Propagation
+ propagate_tags(nitems_rd, ii,
+ d_interp->prev_phase_wrapped(), d_inst_output_period,
+ nitems_wr, oo);
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ oo++;
+ }
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ ii += d_interp->phase_n();
+ }
+
+ // Deferred Tag Propagation
+ save_expiring_tags(nitems_rd, ii);
+
+ // Symbol Clock and Interpolator Positioning & Alignment
+ consume_each(ii);
+ return oo;
+ }
+
+ } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/symbol_sync_ff_impl.h b/gr-digital/lib/symbol_sync_ff_impl.h
new file mode 100644
index 0000000000..b0fea13929
--- /dev/null
+++ b/gr-digital/lib/symbol_sync_ff_impl.h
@@ -0,0 +1,156 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_SYMBOL_SYNC_FF_IMPL_H
+#define INCLUDED_DIGITAL_SYMBOL_SYNC_FF_IMPL_H
+
+#include <gnuradio/digital/symbol_sync_ff.h>
+#include "clock_tracking_loop.h"
+#include "timing_error_detector.h"
+#include "interpolating_resampler.h"
+
+namespace gr {
+ namespace digital {
+
+ class symbol_sync_ff_impl : public symbol_sync_ff
+ {
+ public:
+ symbol_sync_ff_impl(enum ted_type detector_type,
+ float sps,
+ float loop_bw,
+ float damping_factor,
+ float ted_gain,
+ float max_deviation,
+ int osps,
+ constellation_sptr slicer,
+ ir_type interp_type,
+ int n_filters,
+ const std::vector<float> &taps);
+ ~symbol_sync_ff_impl();
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+ int general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ // Symbol Clock Tracking and Estimation
+ float loop_bandwidth() const { return d_clock->get_loop_bandwidth(); }
+ float damping_factor() const { return d_clock->get_damping_factor(); }
+ float ted_gain() const { return d_clock->get_ted_gain(); }
+ float alpha() const { return d_clock->get_alpha(); }
+ float beta() const { return d_clock->get_beta(); }
+
+ void set_loop_bandwidth (float omega_n_norm) {
+ d_clock->set_loop_bandwidth(omega_n_norm);
+ }
+ void set_damping_factor (float zeta) {
+ d_clock->set_damping_factor(zeta);
+ }
+ void set_ted_gain (float ted_gain) { d_clock->set_ted_gain(ted_gain); }
+ void set_alpha (float alpha) { d_clock->set_alpha(alpha); }
+ void set_beta (float beta) { d_clock->set_beta(beta); }
+
+ private:
+ // Timing Error Detector
+ timing_error_detector *d_ted;
+
+ // Symbol Clock Tracking and Estimation
+ clock_tracking_loop *d_clock;
+
+ // Interpolator and Interpolator Positioning and Alignment
+ interpolating_resampler_fff *d_interp;
+
+ // Block Internal Clocks
+ // 4 clocks that run synchronously, aligned to the Symbol Clock:
+ // Interpolator Clock (always highest rate)
+ // Timing Error Detector Input Clock
+ // Output Sample Clock
+ // Symbol Clock (always lowest rate)
+ int d_interp_clock;
+ float d_inst_interp_period;
+
+ float d_interps_per_ted_input;
+ int d_interps_per_ted_input_n;
+ bool d_ted_input_clock;
+
+ int d_interps_per_output_sample_n;
+ bool d_output_sample_clock;
+ float d_inst_output_period;
+
+ float d_interps_per_symbol;
+ int d_interps_per_symbol_n;
+ bool d_symbol_clock;
+ float d_inst_clock_period;
+ float d_avg_clock_period;
+
+ // Block output
+ float d_osps;
+ int d_osps_n;
+
+ // Tag Propagation and Symbol Clock Tracking Reset/Resync
+ uint64_t d_filter_delay; // interpolator filter delay
+ std::vector<tag_t> d_tags;
+ std::vector<tag_t> d_new_tags;
+ pmt::pmt_t d_time_est_key;
+ pmt::pmt_t d_clock_est_key;
+
+ // Optional Diagnostic Outputs
+ int d_noutputs;
+ float *d_out_error;
+ float *d_out_instantaneous_clock_period;
+ float *d_out_average_clock_period;
+
+ // Block Internal Clocks
+ void update_internal_clock_outputs();
+ void advance_internal_clocks();
+ void revert_internal_clocks();
+ void sync_reset_internal_clocks();
+ bool ted_input_clock() { return d_ted_input_clock; }
+ bool output_sample_clock() { return d_output_sample_clock; }
+ bool symbol_clock() { return d_symbol_clock; }
+
+ // Tag Propagation and Clock Tracking Reset/Resync
+ void collect_tags(uint64_t nitems_rd, int count);
+ bool find_sync_tag(uint64_t nitems_rd, int iidx,
+ int distance,
+ uint64_t &tag_offset,
+ float &timing_offset,
+ float &clock_period);
+ void propagate_tags(uint64_t nitems_rd, int iidx,
+ float iidx_fraction,
+ float inst_output_period,
+ uint64_t nitems_wr, int oidx);
+ void save_expiring_tags(uint64_t nitems_rd, int consumed);
+
+ // Optional Diagnostic Outputs
+ void setup_optional_outputs(gr_vector_void_star &output_items);
+ void emit_optional_output(int oidx,
+ float error,
+ float inst_clock_period,
+ float avg_clock_period);
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_SYMBOL_SYNC_FF_IMPL_H */
diff --git a/gr-digital/lib/timing_error_detector.cc b/gr-digital/lib/timing_error_detector.cc
new file mode 100644
index 0000000000..f3794888e8
--- /dev/null
+++ b/gr-digital/lib/timing_error_detector.cc
@@ -0,0 +1,443 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "timing_error_detector.h"
+#include <gnuradio/math.h>
+#include <stdexcept>
+
+namespace gr {
+ namespace digital {
+
+ timing_error_detector *
+ timing_error_detector::make(enum ted_type type,
+ constellation_sptr constellation)
+ {
+ timing_error_detector *ret = NULL;
+ switch (type) {
+ case TED_NONE:
+ break;
+ case TED_MUELLER_AND_MULLER:
+ ret = new ted_mueller_and_muller(constellation);
+ break;
+ case TED_MOD_MUELLER_AND_MULLER:
+ ret = new ted_mod_mueller_and_muller(constellation);
+ break;
+ case TED_ZERO_CROSSING:
+ ret = new ted_zero_crossing(constellation);
+ break;
+ case TED_GARDNER:
+ ret = new ted_gardner();
+ break;
+ case TED_EARLY_LATE:
+ ret = new ted_early_late();
+ break;
+ case TED_DANDREA_AND_MENGALI_GEN_MSK:
+ ret = new ted_generalized_msk();
+ break;
+ case TED_SIGNAL_TIMES_SLOPE_ML:
+ ret = new ted_signal_times_slope_ml();
+ break;
+ case TED_SIGNUM_TIMES_SLOPE_ML:
+ ret = new ted_signum_times_slope_ml();
+ break;
+ case TED_MENGALI_AND_DANDREA_GMSK:
+ ret = new ted_gaussian_msk();
+ break;
+ default:
+ break;
+ }
+ return ret;
+ }
+
+ timing_error_detector::timing_error_detector(
+ enum ted_type type,
+ int inputs_per_symbol,
+ int error_computation_depth,
+ bool needs_lookahead,
+ bool needs_derivative,
+ constellation_sptr constellation)
+ : d_type(type),
+ d_constellation(constellation),
+ d_error(0.0f),
+ d_prev_error(0.0f),
+ d_inputs_per_symbol(inputs_per_symbol),
+ d_error_depth(error_computation_depth),
+ d_input(),
+ d_decision(),
+ d_input_derivative(),
+ d_needs_lookahead(needs_lookahead),
+ d_needs_derivative(needs_derivative)
+ {
+ if (d_constellation && d_constellation->dimensionality() != 1)
+ throw std::invalid_argument(
+ "timing_error_detector: constellation dimensionality "
+ "(complex numbers per symbol) must be 1.");
+
+ switch (type) {
+ case TED_MUELLER_AND_MULLER:
+ case TED_MOD_MUELLER_AND_MULLER:
+ case TED_ZERO_CROSSING:
+ if (!d_constellation)
+ throw std::invalid_argument(
+ "timing_error_detector: slicer constellation required.");
+ break;
+ case TED_GARDNER:
+ case TED_EARLY_LATE:
+ case TED_DANDREA_AND_MENGALI_GEN_MSK:
+ case TED_SIGNAL_TIMES_SLOPE_ML:
+ case TED_SIGNUM_TIMES_SLOPE_ML:
+ case TED_MENGALI_AND_DANDREA_GMSK:
+ break;
+ case TED_NONE:
+ default:
+ throw std::invalid_argument(
+ "timing_error_detector: invalid timing error detector type.");
+ break;
+ }
+
+ sync_reset();
+ }
+
+ void
+ timing_error_detector::input(const gr_complex &x, const gr_complex &dx)
+ {
+ d_input.push_front(x);
+ d_input.pop_back();
+
+ if (d_constellation) {
+ d_decision.push_front(slice(d_input[0]));
+ d_decision.pop_back();
+ }
+
+ if (d_needs_derivative) {
+ d_input_derivative.push_front(dx);
+ d_input_derivative.pop_back();
+ }
+
+ advance_input_clock();
+ if (d_input_clock == 0 && d_needs_lookahead == false) {
+ d_prev_error = d_error;
+ d_error = compute_error_cf();
+ }
+ }
+
+ void
+ timing_error_detector::input(float x, float dx)
+ {
+ d_input.push_front(gr_complex(x, 0.0f));
+ d_input.pop_back();
+
+ if (d_constellation) {
+ d_decision.push_front(slice(d_input[0]));
+ d_decision.pop_back();
+ }
+
+ if (d_needs_derivative) {
+ d_input_derivative.push_front(gr_complex(dx, 0.0f));
+ d_input_derivative.pop_back();
+ }
+
+ advance_input_clock();
+ if (d_input_clock == 0 && d_needs_lookahead == false) {
+ d_prev_error = d_error;
+ d_error = compute_error_ff();
+ }
+ }
+
+ void
+ timing_error_detector::input_lookahead(const gr_complex &x,
+ const gr_complex &dx)
+ {
+ if (d_input_clock != 0 || d_needs_lookahead == false)
+ return;
+
+ d_input.push_front(x);
+ if (d_constellation)
+ d_decision.push_front(slice(d_input[0]));
+ if (d_needs_derivative)
+ d_input_derivative.push_front(dx);
+
+ d_prev_error = d_error;
+ d_error = compute_error_cf();
+
+ if (d_needs_derivative)
+ d_input_derivative.pop_front();
+ if (d_constellation)
+ d_decision.pop_front();
+ d_input.pop_front();
+ }
+
+ void
+ timing_error_detector::input_lookahead(float x, float dx)
+ {
+ if (d_input_clock != 0 || d_needs_lookahead == false)
+ return;
+
+ d_input.push_front(gr_complex(x, 0.0f));
+ if (d_constellation)
+ d_decision.push_front(slice(d_input[0]));
+ if (d_needs_derivative)
+ d_input_derivative.push_front(gr_complex(dx, 0.0f));
+
+ d_prev_error = d_error;
+ d_error = compute_error_ff();
+
+ if (d_needs_derivative)
+ d_input_derivative.pop_front();
+ if (d_constellation)
+ d_decision.pop_front();
+ d_input.pop_front();
+ }
+
+ void
+ timing_error_detector::revert(bool preserve_error)
+ {
+ if (d_input_clock == 0 and preserve_error != true)
+ d_error = d_prev_error;
+ revert_input_clock();
+
+ if (d_needs_derivative) {
+ d_input_derivative.push_back(d_input_derivative.back());
+ d_input_derivative.pop_front();
+ }
+
+ if (d_constellation) {
+ d_decision.push_back(d_decision.back());
+ d_decision.pop_front();
+ }
+
+ d_input.push_back(d_input.back());
+ d_input.pop_front();
+ }
+
+ void
+ timing_error_detector::sync_reset()
+ {
+ d_error = 0.0f;
+ d_prev_error = 0.0f;
+
+ d_input.assign(d_error_depth, gr_complex(0.0f, 0.0f));
+ d_input_derivative.assign(d_error_depth, gr_complex(0.0f, 0.0f));
+
+ if (d_constellation) {
+ std::deque<gr_complex>::iterator it;
+ d_decision.clear();
+ for (it = d_input.begin(); it != d_input.end(); ++it)
+ d_decision.push_back(gr_complex(0.0f, 0.0f));
+ //d_decision.push_back(slice(*it));
+ }
+
+ sync_reset_input_clock();
+ }
+
+ gr_complex
+ timing_error_detector::slice(const gr_complex &x)
+ {
+ unsigned int index;
+ gr_complex z(0.0f, 0.0f);
+
+ index = d_constellation->decision_maker(&x);
+ d_constellation->map_to_points(index, &z);
+ return z;
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_mueller_and_muller::compute_error_cf()
+ {
+ return ( d_decision[1].real() * d_input[0].real()
+ - d_decision[0].real() * d_input[1].real())
+ + ( d_decision[1].imag() * d_input[0].imag()
+ - d_decision[0].imag() * d_input[1].imag());
+ }
+
+ float
+ ted_mueller_and_muller::compute_error_ff()
+ {
+ return ( d_decision[1].real() * d_input[0].real()
+ - d_decision[0].real() * d_input[1].real());
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_mod_mueller_and_muller::compute_error_cf()
+ {
+ gr_complex u;
+
+ u = ((d_input[0] - d_input[2] ) * conj(d_decision[1]))
+ -((d_decision[0] - d_decision[2]) * conj(d_input[1] ));
+
+ return gr::branchless_clip(u.real(), 1.0f);
+ }
+
+ float
+ ted_mod_mueller_and_muller::compute_error_ff()
+ {
+ float u;
+
+ u = ((d_input[0].real() - d_input[2].real()) * d_decision[1].real())
+ -((d_decision[0].real() - d_decision[2].real()) * d_input[1].real());
+
+ return gr::branchless_clip(u/2.0f, 1.0f);
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_zero_crossing::compute_error_cf()
+ {
+ return
+ ((d_decision[2].real() - d_decision[0].real()) * d_input[1].real())
+ + ((d_decision[2].imag() - d_decision[0].imag()) * d_input[1].imag());
+ }
+
+ float
+ ted_zero_crossing::compute_error_ff()
+ {
+ return
+ ((d_decision[2].real() - d_decision[0].real()) * d_input[1].real());
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_gardner::compute_error_cf()
+ {
+ return ((d_input[2].real() - d_input[0].real()) * d_input[1].real())
+ + ((d_input[2].imag() - d_input[0].imag()) * d_input[1].imag());
+ }
+
+ float
+ ted_gardner::compute_error_ff()
+ {
+ return ((d_input[2].real() - d_input[0].real()) * d_input[1].real());
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_early_late::compute_error_cf()
+ {
+ return ((d_input[0].real() - d_input[2].real()) * d_input[1].real())
+ + ((d_input[0].imag() - d_input[2].imag()) * d_input[1].imag());
+ }
+
+ float
+ ted_early_late::compute_error_ff()
+ {
+ return ((d_input[0].real() - d_input[2].real()) * d_input[1].real());
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_generalized_msk::compute_error_cf()
+ {
+ gr_complex u;
+
+ u = (d_input[0] * d_input[0] * conj(d_input[2] * d_input[2]))
+ - (d_input[1] * d_input[1] * conj(d_input[3] * d_input[3]));
+
+ return gr::branchless_clip(u.real(), 3.0f);
+ }
+
+ float
+ ted_generalized_msk::compute_error_ff()
+ {
+ float u;
+
+ u = ( d_input[0].real() * d_input[0].real()
+ * d_input[2].real() * d_input[2].real())
+ - ( d_input[1].real() * d_input[1].real()
+ * d_input[3].real() * d_input[3].real());
+
+ return gr::branchless_clip(u, 3.0f);
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_gaussian_msk::compute_error_cf()
+ {
+ gr_complex u;
+
+ u = -(d_input[0] * d_input[0] * conj(d_input[2] * d_input[2]))
+ + (d_input[1] * d_input[1] * conj(d_input[3] * d_input[3]));
+
+ return gr::branchless_clip(u.real(), 3.0f);
+ }
+
+ float
+ ted_gaussian_msk::compute_error_ff()
+ {
+ float u;
+
+ u = -( d_input[0].real() * d_input[0].real()
+ * d_input[2].real() * d_input[2].real())
+ + ( d_input[1].real() * d_input[1].real()
+ * d_input[3].real() * d_input[3].real());
+
+ return gr::branchless_clip(u, 3.0f);
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_signal_times_slope_ml::compute_error_cf()
+ {
+ return ( d_input[0].real() * d_input_derivative[0].real()
+ + d_input[0].imag() * d_input_derivative[0].imag()) / 2.0f;
+ }
+
+ float
+ ted_signal_times_slope_ml::compute_error_ff()
+ {
+ return ( d_input[0].real() * d_input_derivative[0].real());
+ }
+
+ /*************************************************************************/
+
+ float
+ ted_signum_times_slope_ml::compute_error_cf()
+ {
+ return ( (d_input[0].real() < 0.0f ? -d_input_derivative[0].real()
+ : d_input_derivative[0].real())
+ + (d_input[0].imag() < 0.0f ? -d_input_derivative[0].imag()
+ : d_input_derivative[0].imag()))
+ / 2.0f;
+ }
+
+ float
+ ted_signum_times_slope_ml::compute_error_ff()
+ {
+ return (d_input[0].real() < 0.0f ? -d_input_derivative[0].real()
+ : d_input_derivative[0].real());
+ }
+
+ } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/timing_error_detector.h b/gr-digital/lib/timing_error_detector.h
new file mode 100644
index 0000000000..fd569ba360
--- /dev/null
+++ b/gr-digital/lib/timing_error_detector.h
@@ -0,0 +1,513 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DIGITAL_TIMING_ERROR_DETECTOR_H
+#define INCLUDED_DIGITAL_TIMING_ERROR_DETECTOR_H
+
+#include <gnuradio/gr_complex.h>
+#include <gnuradio/digital/timing_error_detector_type.h>
+#include <gnuradio/digital/constellation.h>
+#include <deque>
+
+namespace gr {
+ namespace digital {
+
+ /*!
+ * \brief Base class for the composite symbol clock timing error
+ * detector object used by the symbol_synchronizer_xx blocks.
+ * \ingroup internal
+ *
+ * \details
+ * This is the base class for the symbol clock timing error detector
+ * object used by the symbol_synchronizer_xx blocks to provide a
+ * user selectable timing error detector type.
+ *
+ * This base class provides the enumeration type for the available
+ * types of timing error detectors.
+ *
+ * This base class also provides most of the methods update, manage, and
+ * store the data points required to compute the symbol clock timing error,
+ * and the timing error result itself.
+ *
+ * The derived classes only have to provide the simple functions
+ * to actually compute the timing error.
+ */
+ class timing_error_detector
+ {
+ public:
+
+ /*!
+ * \brief Create a timing error detector object of the specified
+ * type
+ * \param type The type/algorithm to use for the timing error detector
+ * \param constellation A constellation to be used as a decision slicer
+ * for decision directed timing error detector
+ * algorithms
+ */
+ static timing_error_detector *make(enum ted_type type,
+ constellation_sptr constellation =
+ constellation_sptr());
+
+ virtual ~timing_error_detector() {};
+
+ /*!
+ * \brief Return the number of input samples per symbol this timing
+ * error detector algorithm requires.
+ */
+ virtual int inputs_per_symbol() { return d_inputs_per_symbol; }
+
+ /*!
+ * \brief Provide a complex input sample to the TED algorithm
+ * \param x the input sample
+ * \param dx the derivative at the input sample, if required by the
+ * timinig error detector algorithm
+ */
+ virtual void input(const gr_complex &x,
+ const gr_complex &dx = gr_complex(0.0f, 0.0f));
+
+ /*!
+ * \brief Provide a float input sample to the TED algorithm
+ * \param x the input sample
+ * \param dx the derivative at the input sample, if required by the
+ * timinig error detector algorithm
+ */
+ virtual void input(float x,
+ float dx = 0.0f);
+
+ /*!
+ * \brief Return if this timing error detector algorithm requires a
+ * look-ahead input sample to be input to produce a new error estimate
+ * for the symbol sampling instant.
+ */
+ virtual bool needs_lookahead() { return d_needs_lookahead; }
+
+ /*!
+ * \brief Provide a complex input lookahead sample to the TED algorithm
+ * \param x the input lookahead sample
+ * \param dx the derivative at the input lookahead sample, if required
+ * by the timinig error detector algorithm
+ */
+ virtual void input_lookahead(const gr_complex &x,
+ const gr_complex &dx =
+ gr_complex(0.0f, 0.0f));
+
+ /*!
+ * \brief Provide a float input lookahead sample to the TED algorithm
+ * \param x the input lookahead sample
+ * \param dx the derivative at the input lookahead sample, if required
+ * by the timinig error detector algorithm
+ */
+ virtual void input_lookahead(float x,
+ float dx = 0.0f);
+
+ /*!
+ * \brief Return if this timing error detector algorithm requires
+ * derivative input samples in addition to normal input samples.
+ */
+ virtual bool needs_derivative() { return d_needs_derivative; }
+
+ /*!
+ * \brief Return the current symbol timing error estimate
+ */
+ virtual float error() { return d_error; }
+
+ /*!
+ * \brief Revert the timing error detector processing state back one
+ * step.
+ * \param preserve_error If true, don't revert the error estimate.
+ */
+ virtual void revert(bool preserve_error = false);
+
+ /*!
+ * \brief Reset the timing error detector
+ */
+ virtual void sync_reset();
+
+ private:
+ enum ted_type d_type;
+
+ protected:
+ /*!
+ * \brief Create a timing error detector abstract base class object
+ * object
+ * \param type The type/algorithm to use for the timing error detector
+ * \param inputs_per_symbol The input samples per symbol this TED
+ * algorithm requires
+ * \param error_computation_depth The number of input samples this TED
+ * algorithm needs to compute the error
+ * \param needs_lookahead True if this TED algorithm needs a lookahead
+ * input sample to compute the error for the
+ * symbol sampling instant
+ * \param needs_derivative True if this TED algorithm needs a derivative
+ * input sample in addition to the normal input
+ * sample
+ * \param constellation A constellation to be used as a decision slicer
+ * for decision directed timing error detector
+ * algorithms
+ */
+ timing_error_detector(enum ted_type type,
+ int inputs_per_symbol,
+ int error_computation_depth,
+ bool needs_lookahead = false,
+ bool needs_derivative = false,
+ constellation_sptr constellation =
+ constellation_sptr());
+
+ /*!
+ * \brief Advance the TED input clock, so the input() methods will
+ * compute the TED error term at the proper symbol sampling instant.
+ */
+ void advance_input_clock() {
+ d_input_clock = (d_input_clock + 1) % d_inputs_per_symbol;
+ }
+
+ /*!
+ * \brief Revert the TED input clock one step
+ */
+ void revert_input_clock()
+ {
+ if (d_input_clock == 0)
+ d_input_clock = d_inputs_per_symbol - 1;
+ else
+ d_input_clock--;
+ }
+
+ /*!
+ * \brief Reset the TED input clock, so the next input clock advance
+ * corresponds to a symbol sampling instant.
+ */
+ void sync_reset_input_clock() {
+ d_input_clock = d_inputs_per_symbol - 1;
+ }
+
+ /*!
+ * \brief Convert the soft symbol sample into a hard symbol decision.
+ * \param x the soft input symbol sample
+ */
+ gr_complex slice(const gr_complex &x);
+
+ /*!
+ * \brief Compute the TED error term for complex input samples
+ */
+ virtual float compute_error_cf() = 0;
+
+ /*!
+ * \brief Compute the TED error term for float input samples
+ */
+ virtual float compute_error_ff() = 0;
+
+ constellation_sptr d_constellation;
+ float d_error;
+ float d_prev_error;
+ int d_inputs_per_symbol;
+ int d_input_clock;
+ int d_error_depth;
+ std::deque<gr_complex> d_input;
+ std::deque<gr_complex> d_decision;
+ std::deque<gr_complex> d_input_derivative;
+ bool d_needs_lookahead;
+ bool d_needs_derivative;
+ };
+
+ /*!
+ * \brief Mueller and Müller (M&M) timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Mueller and Müller (M&M) timing error detector algorithm
+ * class. It is a decision directed timing error detector, and requires
+ * an input slicer constellation to make decisions.
+ *
+ * See equation (49) of:
+ * Mueller, Kurt H., Müller, Markus, "Timing Recovery in Digital
+ * Synchronous Data Receivers", _IEEE_Transactions_on_Communications_,
+ * Vol. COM-24, No. 5, May 1976, pp. 516-531
+ */
+ class ted_mueller_and_muller : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Mueller and Müller (M&M) timing error detector
+ * \param constellation A constellation to be used as a decision slicer
+ */
+ ted_mueller_and_muller(constellation_sptr constellation)
+ : timing_error_detector(TED_MUELLER_AND_MULLER,
+ 1, 2, false, false, constellation)
+ {}
+ ~ted_mueller_and_muller() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Modified Mueller and Müller (M&M) timing error detector algorithm
+ * class
+ * \ingroup internal
+ *
+ * \details
+ * This is the modified Mueller and Müller (M&M) timing error detector
+ * algorithm class. It is a decision directed timing error detector, and
+ * requires an input slicer constellation to make decisions.
+ *
+ * The modification of the standard M&M TED is done to remove
+ * self-noise that is present in the standard M&M TED.
+ *
+ * See:
+ * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller
+ * and Muller algorithm," Electronics Letters, Vol. 31, no. 13, 22
+ * June 1995, pp. 1032 - 1033.
+ */
+ class ted_mod_mueller_and_muller : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a modified Mueller and Müller (M&M) timing error
+ * detector
+ * \param constellation A constellation to be used as a decision slicer
+ */
+ ted_mod_mueller_and_muller(constellation_sptr constellation)
+ : timing_error_detector(TED_MOD_MUELLER_AND_MULLER,
+ 1, 3, false, false, constellation)
+ {}
+ ~ted_mod_mueller_and_muller() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Zero Crossing timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Zero Crossing timing error detector algorithm class.
+ * It is a decision directed timing error detector, and
+ * requires an input slicer constellation to make decisions.
+ */
+ class ted_zero_crossing : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Zero Crossing timing error detector
+ * \param constellation A constellation to be used as a decision slicer
+ */
+ ted_zero_crossing(constellation_sptr constellation)
+ : timing_error_detector(TED_ZERO_CROSSING,
+ 2, 3, false, false, constellation)
+ {}
+ ~ted_zero_crossing() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Gardner timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Gardner timing error detector algorithm class.
+ *
+ * See:
+ * F.M. Gardner, “A BPSK/QPSK Timing Error Detector for Sampled Receivers”,
+ * IEEE Trans., COM-34, (5), 1988, pp. 423 – 429.
+ */
+ class ted_gardner : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Gardner timing error detector
+ */
+ ted_gardner()
+ : timing_error_detector(TED_GARDNER,
+ 2, 3, false, false,
+ constellation_sptr())
+ {}
+ ~ted_gardner() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Early-Late timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Early-Late timing error detector algorithm class.
+ * It requires a lookahead sample to compute the symbol timing error
+ * at the symbol sampling instant.
+ */
+ class ted_early_late : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Early-Late timing error detector
+ */
+ ted_early_late()
+ : timing_error_detector(TED_EARLY_LATE,
+ 2, 2, true, false,
+ constellation_sptr())
+ {}
+ ~ted_early_late() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Generalized MSK timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Generalized MSK timing error detector algorithm class.
+ * It operates on the CPM MSK signal directly and not the FM pulses.
+ *
+ * See:
+ * A.N. D'Andrea, U. Mengali, R. Reggiannini, "A digital approach to clock
+ * recovery in generalized minimum shift keying", IEEE Transactions on
+ * Vehicular Technology, Vol. 39, Issue 3, August 1990, pp. 227-234
+ */
+ class ted_generalized_msk : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Generalized MSK timing error detector
+ */
+ ted_generalized_msk()
+ : timing_error_detector(TED_DANDREA_AND_MENGALI_GEN_MSK,
+ 2, 4, false, false, constellation_sptr())
+ {}
+ ~ted_generalized_msk() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Gaussian MSK timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Gaussian MSK timing error detector algorithm class.
+ * It operates on the CPM MSK signal directly and not the FM pulses.
+ *
+ * See:
+ * U. Mengali, A.N. D'Andrea, _Synchronization_Techniques_for_Digital_
+ * Receviers_, New York, Plenum Press 1997
+ */
+ class ted_gaussian_msk : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Generalized MSK timing error detector
+ */
+ ted_gaussian_msk()
+ : timing_error_detector(TED_MENGALI_AND_DANDREA_GMSK,
+ 2, 4, false, false, constellation_sptr())
+ {}
+ ~ted_gaussian_msk() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Signal times Slope Maximum Likelyhood solution approximation
+ * timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Signal times Slope Maximum Likelyhood solution approximation
+ * timing error detector algorithm class. This approximation is good for
+ * small signals (< 1.0) and/or situations with low SNR.
+ *
+ * See equation (5) and the 2 following paragraphs of:
+ * Fredric J. Harris, Michael Rice, "Multirate Digital Filters for
+ * Symbol Timing Synchronization in Software Defined Radios",
+ * _IEEE_Journal_on_Selected_Areas_in_Communications_, Vol. 19, No. 12,
+ * December 2001, pp. 2346 - 2357
+ */
+ class ted_signal_times_slope_ml : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Signal times Slope Maximum Likelyhood solution
+ * approximation timing error detector
+ */
+ ted_signal_times_slope_ml()
+ : timing_error_detector(TED_SIGNAL_TIMES_SLOPE_ML,
+ 1, 1, false, true, constellation_sptr())
+ {}
+ ~ted_signal_times_slope_ml() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ /*!
+ * \brief Signum times Slope Maximum Likelyhood solution approximation
+ * timing error detector algorithm class
+ * \ingroup internal
+ *
+ * \details
+ * This is the Signum times Slope Maximum Likelyhood solution approximation
+ * timing error detector algorithm class. This approximation is good for
+ * large signals (> 1.0) and/or situations with high SNR.
+ *
+ * See equation (5) and the 2 following paragraphs of:
+ * Fredric J. Harris, Michael Rice, "Multirate Digital Filters for
+ * Symbol Timing Synchronization in Software Defined Radios",
+ * _IEEE_Journal_on_Selected_Areas_in_Communications_, Vol. 19, No. 12,
+ * December 2001, pp. 2346 - 2357
+ */
+ class ted_signum_times_slope_ml : public timing_error_detector
+ {
+ public:
+ /*!
+ * \brief Create a Signum times Slope Maximum Likelyhood solution
+ * approximation timing error detector
+ */
+ ted_signum_times_slope_ml()
+ : timing_error_detector(TED_SIGNUM_TIMES_SLOPE_ML,
+ 1, 1, false, true, constellation_sptr())
+ {}
+ ~ted_signum_times_slope_ml() {};
+
+ private:
+ float compute_error_cf();
+ float compute_error_ff();
+ };
+
+ } /* namespace digital */
+} /* namespace gr */
+
+#endif /* INCLUDED_DIGITAL_TIMING_ERROR_DETECTOR_H */
diff --git a/gr-digital/python/grc_gnuradio/blks2/packet.py b/gr-digital/python/grc_gnuradio/blks2/packet.py
index dc06544c19..298453a104 100644
--- a/gr-digital/python/grc_gnuradio/blks2/packet.py
+++ b/gr-digital/python/grc_gnuradio/blks2/packet.py
@@ -54,13 +54,21 @@ class _packet_encoder_thread(_threading.Thread):
self.start()
def run(self):
- sample = '' #residual sample
while self.keep_running:
+ sample = '' # residual sample
msg = self._msgq.delete_head() #blocking read of message queue
sample = sample + msg.to_string() #get the body of the msg as a string
+
while len(sample) >= self._payload_length:
payload = sample[:self._payload_length]
sample = sample[self._payload_length:]
+
+ #check if sample has remaining data to transmit that is shorter than the payload length
+ if len(sample) > 0 and len(sample) < self._payload_length:
+ #arbitrary padding to satisfy send on next loop for payload less than _payload_length
+ padding = ('x' * (self._payload_length - len(sample)))
+ sample = sample + padding
+
self._send(payload)
class packet_encoder(gr.hier_block2):
@@ -107,6 +115,7 @@ class packet_encoder(gr.hier_block2):
#connect
self.connect(msg_source, self)
+
print "Warning: the blks2.packet_encoder block is deprecated."
def send_pkt(self, payload):
@@ -197,9 +206,10 @@ class packet_mod_base(gr.hier_block2):
"""
def __init__(self, packet_source=None, payload_length=0):
+
if not payload_length: #get payload length
payload_length = DEFAULT_PAYLOAD_LEN
- if payload_length%self._item_size_in != 0: #verify that packet length is a multiple of the stream size
+ if (payload_length % self._item_size_in) != 0: #verify that packet length is a multiple of the stream size
raise ValueError, 'The payload length: "%d" is not a mutiple of the stream size: "%d".'%(payload_length, self._item_size_in)
#initialize hier2
gr.hier_block2.__init__(
diff --git a/gr-digital/swig/digital_swig2.i b/gr-digital/swig/digital_swig2.i
index c16cc6aafb..e035253640 100644
--- a/gr-digital/swig/digital_swig2.i
+++ b/gr-digital/swig/digital_swig2.i
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Free Software Foundation, Inc.
+ * Copyright 2016-2017 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -22,6 +22,7 @@
#define DIGITAL_API
#define ANALOG_API
#define BLOCKS_API
+#define FILTER_API
%include "gnuradio.i"
%include "stdint.i"
@@ -33,8 +34,15 @@
%{
#include <gnuradio/blocks/control_loop.h>
+#include "gnuradio/digital/constellation.h"
+#include "gnuradio/digital/timing_error_detector_type.h"
+#include "gnuradio/digital/interpolating_resampler_type.h"
%}
+
%include <gnuradio/blocks/control_loop.h>
+%include "gnuradio/digital/constellation.h"
+%include "gnuradio/digital/timing_error_detector_type.h"
+%include "gnuradio/digital/interpolating_resampler_type.h"
%{
#include "gnuradio/digital/mpsk_receiver_cc.h"
@@ -61,6 +69,8 @@
#include "gnuradio/digital/scrambler_bb.h"
#include "gnuradio/digital/simple_correlator.h"
#include "gnuradio/digital/simple_framer.h"
+#include "gnuradio/digital/symbol_sync_cc.h"
+#include "gnuradio/digital/symbol_sync_ff.h"
#include "gnuradio/digital/ofdm_serializer_vcc.h"
#include "gnuradio/digital/packet_headerparser_b.h"
#include "gnuradio/digital/header_payload_demux.h"
@@ -90,6 +100,8 @@
%include "gnuradio/digital/scrambler_bb.h"
%include "gnuradio/digital/simple_correlator.h"
%include "gnuradio/digital/simple_framer.h"
+%include "gnuradio/digital/symbol_sync_cc.h"
+%include "gnuradio/digital/symbol_sync_ff.h"
GR_SWIG_BLOCK_MAGIC2(digital, mpsk_receiver_cc);
GR_SWIG_BLOCK_MAGIC2(digital, mpsk_snr_est_cc);
@@ -107,6 +119,9 @@ GR_SWIG_BLOCK_MAGIC2(digital, probe_mpsk_snr_est_c);
GR_SWIG_BLOCK_MAGIC2(digital, scrambler_bb);
GR_SWIG_BLOCK_MAGIC2(digital, simple_correlator);
GR_SWIG_BLOCK_MAGIC2(digital, simple_framer);
+GR_SWIG_BLOCK_MAGIC2(digital, symbol_sync_cc);
+GR_SWIG_BLOCK_MAGIC2(digital, symbol_sync_ff);
// Properly package up non-block objects
%include "packet_header.i"
+%include "constellation.i"
diff --git a/gr-dtv/examples/germany-g1.grc b/gr-dtv/examples/germany-g1.grc
index 88c05b286b..63dd629cdb 100644
--- a/gr-dtv/examples/germany-g1.grc
+++ b/gr-dtv/examples/germany-g1.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g10.grc b/gr-dtv/examples/germany-g10.grc
index 7e4c56e312..47cd5337b1 100644
--- a/gr-dtv/examples/germany-g10.grc
+++ b/gr-dtv/examples/germany-g10.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g2.grc b/gr-dtv/examples/germany-g2.grc
index 1027eb96fa..3022a91675 100644
--- a/gr-dtv/examples/germany-g2.grc
+++ b/gr-dtv/examples/germany-g2.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g3.grc b/gr-dtv/examples/germany-g3.grc
index 71a67283a6..0464dd831a 100644
--- a/gr-dtv/examples/germany-g3.grc
+++ b/gr-dtv/examples/germany-g3.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g4.grc b/gr-dtv/examples/germany-g4.grc
index 7e20ab2767..cb8c153e49 100644
--- a/gr-dtv/examples/germany-g4.grc
+++ b/gr-dtv/examples/germany-g4.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g5.grc b/gr-dtv/examples/germany-g5.grc
index d1949bab7d..1f19144530 100644
--- a/gr-dtv/examples/germany-g5.grc
+++ b/gr-dtv/examples/germany-g5.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g6.grc b/gr-dtv/examples/germany-g6.grc
index 002bce4a90..f26a2e8d0b 100644
--- a/gr-dtv/examples/germany-g6.grc
+++ b/gr-dtv/examples/germany-g6.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g7.grc b/gr-dtv/examples/germany-g7.grc
index 2b656fe9c4..6c26874feb 100644
--- a/gr-dtv/examples/germany-g7.grc
+++ b/gr-dtv/examples/germany-g7.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g8.grc b/gr-dtv/examples/germany-g8.grc
index 2106a345d3..ae3ceccd58 100644
--- a/gr-dtv/examples/germany-g8.grc
+++ b/gr-dtv/examples/germany-g8.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/germany-g9.grc b/gr-dtv/examples/germany-g9.grc
index 2517259ff0..d7908313cf 100644
--- a/gr-dtv/examples/germany-g9.grc
+++ b/gr-dtv/examples/germany-g9.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv001-cr35.grc b/gr-dtv/examples/vv001-cr35.grc
index f2faa8cad6..64f044751d 100644
--- a/gr-dtv/examples/vv001-cr35.grc
+++ b/gr-dtv/examples/vv001-cr35.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv003-cr23.grc b/gr-dtv/examples/vv003-cr23.grc
index cbb8c7ab79..bf415ba42d 100644
--- a/gr-dtv/examples/vv003-cr23.grc
+++ b/gr-dtv/examples/vv003-cr23.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv004-8kfft.grc b/gr-dtv/examples/vv004-8kfft.grc
index 18e4abd643..d61fc9839b 100644
--- a/gr-dtv/examples/vv004-8kfft.grc
+++ b/gr-dtv/examples/vv004-8kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv005-8kfft.grc b/gr-dtv/examples/vv005-8kfft.grc
index 071d89f6f0..95471be171 100644
--- a/gr-dtv/examples/vv005-8kfft.grc
+++ b/gr-dtv/examples/vv005-8kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv007-16kfft.grc b/gr-dtv/examples/vv007-16kfft.grc
index ffb7a1909d..696590399d 100644
--- a/gr-dtv/examples/vv007-16kfft.grc
+++ b/gr-dtv/examples/vv007-16kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv008-16kfft.grc b/gr-dtv/examples/vv008-16kfft.grc
index b0f5f23b46..30990aa4e9 100644
--- a/gr-dtv/examples/vv008-16kfft.grc
+++ b/gr-dtv/examples/vv008-16kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv009-4kfft.grc b/gr-dtv/examples/vv009-4kfft.grc
index 02b90b2fb4..8760108e55 100644
--- a/gr-dtv/examples/vv009-4kfft.grc
+++ b/gr-dtv/examples/vv009-4kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv010-2kfft.grc b/gr-dtv/examples/vv010-2kfft.grc
index d643d15bdf..eb8ab55f3f 100644
--- a/gr-dtv/examples/vv010-2kfft.grc
+++ b/gr-dtv/examples/vv010-2kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv011-1kfft.grc b/gr-dtv/examples/vv011-1kfft.grc
index d2cbd3bbb1..92d661ef31 100644
--- a/gr-dtv/examples/vv011-1kfft.grc
+++ b/gr-dtv/examples/vv011-1kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv012-64qam45.grc b/gr-dtv/examples/vv012-64qam45.grc
index 0b4044dfae..311ede1645 100644
--- a/gr-dtv/examples/vv012-64qam45.grc
+++ b/gr-dtv/examples/vv012-64qam45.grc
@@ -2491,7 +2491,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv013-64qam56.grc b/gr-dtv/examples/vv013-64qam56.grc
index aeca680a21..b0dd6b8f79 100644
--- a/gr-dtv/examples/vv013-64qam56.grc
+++ b/gr-dtv/examples/vv013-64qam56.grc
@@ -2491,7 +2491,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv014-64qam34.grc b/gr-dtv/examples/vv014-64qam34.grc
index a14fca9cff..0c5a93e80c 100644
--- a/gr-dtv/examples/vv014-64qam34.grc
+++ b/gr-dtv/examples/vv014-64qam34.grc
@@ -2491,7 +2491,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv015-8kfft.grc b/gr-dtv/examples/vv015-8kfft.grc
index 6a50f9af6c..53a6157970 100644
--- a/gr-dtv/examples/vv015-8kfft.grc
+++ b/gr-dtv/examples/vv015-8kfft.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv016-256qam34.grc b/gr-dtv/examples/vv016-256qam34.grc
index 4fb1b2affb..aff61374f6 100644
--- a/gr-dtv/examples/vv016-256qam34.grc
+++ b/gr-dtv/examples/vv016-256qam34.grc
@@ -2491,7 +2491,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv017-paprtr.grc b/gr-dtv/examples/vv017-paprtr.grc
index b56cf38948..cbac8df252 100644
--- a/gr-dtv/examples/vv017-paprtr.grc
+++ b/gr-dtv/examples/vv017-paprtr.grc
@@ -2491,7 +2491,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv018-miso.grc b/gr-dtv/examples/vv018-miso.grc
index 8c31223762..f7babd3c79 100644
--- a/gr-dtv/examples/vv018-miso.grc
+++ b/gr-dtv/examples/vv018-miso.grc
@@ -1669,7 +1669,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
@@ -1889,7 +1889,7 @@
</param>
<param>
<key>center_freq1</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain1</key>
diff --git a/gr-dtv/examples/vv019-norot.grc b/gr-dtv/examples/vv019-norot.grc
index fdaec4f591..0e2b0c684f 100644
--- a/gr-dtv/examples/vv019-norot.grc
+++ b/gr-dtv/examples/vv019-norot.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv034-dtg016.grc b/gr-dtv/examples/vv034-dtg016.grc
index 013fcf886f..fab2052041 100644
--- a/gr-dtv/examples/vv034-dtg016.grc
+++ b/gr-dtv/examples/vv034-dtg016.grc
@@ -2412,7 +2412,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv035-dtg052.grc b/gr-dtv/examples/vv035-dtg052.grc
index 0d5f38cb5c..1d9d6a5511 100644
--- a/gr-dtv/examples/vv035-dtg052.grc
+++ b/gr-dtv/examples/vv035-dtg052.grc
@@ -2491,7 +2491,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 4000000)</value>
+ <value>uhd.tune_request(center_freq, 4000000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/examples/vv036-dtg091.grc b/gr-dtv/examples/vv036-dtg091.grc
index 75e0e42e51..7ae57c1434 100644
--- a/gr-dtv/examples/vv036-dtg091.grc
+++ b/gr-dtv/examples/vv036-dtg091.grc
@@ -2491,7 +2491,7 @@
</param>
<param>
<key>center_freq0</key>
- <value>uhd.tune_request(429000000, 3500000)</value>
+ <value>uhd.tune_request(center_freq, 3500000)</value>
</param>
<param>
<key>norm_gain0</key>
diff --git a/gr-dtv/include/gnuradio/dtv/dvb_bbheader_bb.h b/gr-dtv/include/gnuradio/dtv/dvb_bbheader_bb.h
index 0fb6c94f7a..c356210d7e 100644
--- a/gr-dtv/include/gnuradio/dtv/dvb_bbheader_bb.h
+++ b/gr-dtv/include/gnuradio/dtv/dvb_bbheader_bb.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015,2016 Free Software Foundation, Inc.
+ * Copyright 2015-2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ namespace gr {
* \ingroup dtv
*
* \details
- * Input: 188-byte MPEG-2 Transport Stream packets.
+ * Input: 188-byte MPEG-2 Transport Stream packets. \n
* Output: Variable length FEC baseband frames (BBFRAME). The output frame
* length is based on the FEC rate.
*/
diff --git a/gr-dtv/include/gnuradio/dtv/dvb_bbscrambler_bb.h b/gr-dtv/include/gnuradio/dtv/dvb_bbscrambler_bb.h
index f8ee7bdb30..0acba70cd5 100644
--- a/gr-dtv/include/gnuradio/dtv/dvb_bbscrambler_bb.h
+++ b/gr-dtv/include/gnuradio/dtv/dvb_bbscrambler_bb.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015,2016 Free Software Foundation, Inc.
+ * Copyright 2015-2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \ingroup dtv
*
* \details
- * Input: Variable length FEC baseband frames (BBFRAME).
+ * Input: Variable length FEC baseband frames (BBFRAME). \n
* Output: Scrambled variable length FEC baseband frames (BBFRAME).
*/
class DTV_API dvb_bbscrambler_bb : virtual public gr::sync_block
diff --git a/gr-dtv/include/gnuradio/dtv/dvb_bch_bb.h b/gr-dtv/include/gnuradio/dtv/dvb_bch_bb.h
index 59dd162545..34a8684fa4 100644
--- a/gr-dtv/include/gnuradio/dtv/dvb_bch_bb.h
+++ b/gr-dtv/include/gnuradio/dtv/dvb_bch_bb.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015,2016 Free Software Foundation, Inc.
+ * Copyright 2015-2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@ namespace gr {
* \ingroup dtv
*
* \details
- * Input: Variable length FEC baseband frames (BBFRAME).
+ * Input: Variable length FEC baseband frames (BBFRAME). \n
* Output: Variable length FEC baseband frames with appended BCH (BCHFEC).
*/
class DTV_API dvb_bch_bb : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvb_ldpc_bb.h b/gr-dtv/include/gnuradio/dtv/dvb_ldpc_bb.h
index 2ed17f3ed3..215c8deb93 100644
--- a/gr-dtv/include/gnuradio/dtv/dvb_ldpc_bb.h
+++ b/gr-dtv/include/gnuradio/dtv/dvb_ldpc_bb.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015,2016 Free Software Foundation, Inc.
+ * Copyright 2015-2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ namespace gr {
* \brief Encodes a LDPC (Low-Density Parity-Check) FEC.
* \ingroup dtv
*
- * Input: Variable length FEC baseband frames with appended BCH (BCHFEC).
+ * Input: Variable length FEC baseband frames with appended BCH (BCHFEC). \n
* Output: Normal, medium or short FEC baseband frames with appended LPDC (LDPCFEC).
*/
class DTV_API dvb_ldpc_bb : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbs2_interleaver_bb.h b/gr-dtv/include/gnuradio/dtv/dvbs2_interleaver_bb.h
index 3aba9daf86..665e6c5e0a 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbs2_interleaver_bb.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbs2_interleaver_bb.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ namespace gr {
* \brief Bit interleaves DVB-S2 FEC baseband frames.
* \ingroup dtv
*
- * Input: Normal or short FEC baseband frames with appended LPDC (LDPCFEC).
+ * Input: Normal or short FEC baseband frames with appended LPDC (LDPCFEC). \n
* Output: Bit interleaved baseband frames.
*/
class DTV_API dvbs2_interleaver_bb : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h b/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h
index a1f2c9e6fe..c794fc18df 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015,2016 Free Software Foundation, Inc.
+ * Copyright 2015-2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Modulates DVB-S2 frames.
* \ingroup dtv
*
- * Input: Bit interleaved baseband frames.
+ * Input: Bit interleaved baseband frames. \n
* Output: QPSK, 8PSK, 16APSK or 32APSK modulated complex IQ values (XFECFRAME).
*/
class DTV_API dvbs2_modulator_bc : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbs2_physical_cc.h b/gr-dtv/include/gnuradio/dtv/dvbs2_physical_cc.h
index 0893d0133d..5a46d24ef9 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbs2_physical_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbs2_physical_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Signals DVB-S2 physical layer frames.
* \ingroup dtv
*
- * Input: QPSK, 8PSK, 16APSK or 32APSK modulated complex IQ values (XFECFRAME).
+ * Input: QPSK, 8PSK, 16APSK or 32APSK modulated complex IQ values (XFECFRAME). \n
* Output: DVB-S2 PLFRAME.
*/
class DTV_API dvbs2_physical_cc : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_cellinterleaver_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_cellinterleaver_cc.h
index 2293349ca4..090180dd3e 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_cellinterleaver_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_cellinterleaver_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ namespace gr {
* \brief Cell and time interleaves QPSK/QAM modulated cells.
* \ingroup dtv
*
- * Input: QPSK, 16QAM, 64QAM or 256QAM modulated cells.
+ * Input: QPSK, 16QAM, 64QAM or 256QAM modulated cells. \n
* Output: Cell and time interleaved QPSK, 16QAM, 64QAM or 256QAM modulated cells.
*/
class DTV_API dvbt2_cellinterleaver_cc : virtual public gr::sync_block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h
index bf6e4db297..c1da566dc5 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Maps T2 frames.
* \ingroup dtv
*
- * Input: Cell and time interleaved QPSK, 16QAM, 64QAM or 256QAM modulated cells.
+ * Input: Cell and time interleaved QPSK, 16QAM, 64QAM or 256QAM modulated cells. \n
* Output: T2 frame.
*/
class DTV_API dvbt2_framemapper_cc : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h
index 766fe031a3..91f47e8e49 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Frequency interleaves a T2 frame.
* \ingroup dtv
*
- * Input: T2 frame.
+ * Input: T2 frame. \n
* Output: Frequency interleaved T2 frame.
*/
class DTV_API dvbt2_freqinterleaver_cc : virtual public gr::sync_block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_interleaver_bb.h b/gr-dtv/include/gnuradio/dtv/dvbt2_interleaver_bb.h
index 00c23cc972..b32aabd522 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_interleaver_bb.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_interleaver_bb.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ namespace gr {
* \brief Bit interleaves DVB-T2 FEC baseband frames.
* \ingroup dtv
*
- * Input: Normal or short FEC baseband frames with appended LPDC (LDPCFEC).
+ * Input: Normal or short FEC baseband frames with appended LPDC (LDPCFEC). \n
* Output: Bit interleaved (with column twist and bit to cell word de-multiplexed) cells.
*/
class DTV_API dvbt2_interleaver_bb : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h
index c16e711e9b..5edf077248 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,8 +33,8 @@ namespace gr {
* \brief Splits the stream for MISO (Multiple Input Single Output).
* \ingroup dtv
*
- * Input: Frequency interleaved T2 frame.
- * Output1: Frequency interleaved T2 frame (copy of input).
+ * Input: Frequency interleaved T2 frame. \n
+ * Output1: Frequency interleaved T2 frame (copy of input). \n
* Output2: Frequency interleaved T2 frame with modified Alamouti processing.
*/
class DTV_API dvbt2_miso_cc : virtual public gr::sync_block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_modulator_bc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_modulator_bc.h
index 226dbf55f8..82b36d90d1 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_modulator_bc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_modulator_bc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Modulates DVB-T2 cells.
* \ingroup dtv
*
- * Input: Bit interleaved (with column twist and bit to cell word de-multiplexing) cells.
+ * Input: Bit interleaved (with column twist and bit to cell word de-multiplexing) cells. \n
* Output: QPSK, 16QAM, 64QAM or 256QAM modulated complex IQ values (cells).
*/
class DTV_API dvbt2_modulator_bc : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h
index 84e0d4a268..f09e75ca40 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Inserts a P1 symbol.
* \ingroup dtv
*
- * Input: OFDM T2 frame.
+ * Input: OFDM T2 frame. \n
* Output: OFDM T2 frame with P1 symbol.
*/
class DTV_API dvbt2_p1insertion_cc : virtual public gr::block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h
index 5a39dfa565..c547b5f595 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Peak to Average Power Ratio (PAPR) reduction.
* \ingroup dtv
*
- * Input: A T2 frame of OFDM symbols.
+ * Input: A T2 frame of OFDM symbols. \n
* Output: A T2 frame of PAPR reduced OFDM symbols.
*/
class DTV_API dvbt2_paprtr_cc : virtual public gr::sync_block
diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h
index 19ae6d948f..6d44562d59 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2017 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ namespace gr {
* \brief Adds pilots to T2 frames.
* \ingroup dtv
*
- * Input: Frequency interleaved T2 frame.
+ * Input: Frequency interleaved T2 frame. \n
* Output: T2 frame with pilots (in time domain).
*/
class DTV_API dvbt2_pilotgenerator_cc : virtual public gr::block
diff --git a/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc b/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc
index 663301d614..9092321462 100644
--- a/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc
+++ b/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc
@@ -25,8 +25,6 @@
#include <gnuradio/io_signature.h>
#include "dvbt_reed_solomon_enc_impl.h"
-#define MPEG_TS_PKT_LENGTH 188
-
namespace gr {
namespace dtv {
@@ -55,7 +53,8 @@ namespace gr {
GR_LOG_FATAL(d_logger, "Reed-Solomon Encoder, cannot allocate memory for d_rs.");
throw std::bad_alloc();
}
- d_data = (unsigned char *) malloc(sizeof(unsigned char) * (d_s + MPEG_TS_PKT_LENGTH));
+ // The full input frame size (d_k) (no need to add in d_s, as the block input is the pre-shortedned K)
+ d_data = (unsigned char *) malloc(sizeof(unsigned char) * (d_k));
if (d_data == NULL) {
GR_LOG_FATAL(d_logger, "Reed-Solomon Encoder, cannot allocate memory for d_data.");
free_rs_char(d_rs);
@@ -83,11 +82,13 @@ namespace gr {
{
// Shortened Reed-Solomon: prepend zero bytes to message (discarded after encoding)
std::memset(d_data, 0, d_s);
- std::memcpy(&d_data[d_s], in, MPEG_TS_PKT_LENGTH);
+ // This is the number of data bytes we need from the input stream.
+ int shortened_k = d_k-d_s;
+ std::memcpy(&d_data[d_s], in, shortened_k);
// Copy input message to output then append Reed-Solomon bits
- std::memcpy(out, in, MPEG_TS_PKT_LENGTH);
- encode_rs_char(d_rs, d_data, &out[MPEG_TS_PKT_LENGTH]);
+ std::memcpy(out, in, shortened_k);
+ encode_rs_char(d_rs, d_data, &out[shortened_k]);
}
int
diff --git a/gr-fcd/lib/CMakeLists.txt b/gr-fcd/lib/CMakeLists.txt
index cc896792a1..a01331a74e 100644
--- a/gr-fcd/lib/CMakeLists.txt
+++ b/gr-fcd/lib/CMakeLists.txt
@@ -79,6 +79,8 @@ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
FIND_LIBRARY(IOKIT_LIBRARY IOKit)
list(APPEND fcd_libs ${IOKIT_LIBRARY})
+ FIND_LIBRARY(CF_LIBRARY CoreFoundation)
+ list(APPEND fcd_libs ${CF_LIBRARY})
elseif (NOT WIN32)
list(APPEND fcd_libs
${LIBUSB_LIBRARIES}
diff --git a/gr-fec/grc/variable_polar_code_configurator.xml b/gr-fec/grc/variable_polar_code_configurator.xml
index 24004b8a03..ee145b16f7 100644
--- a/gr-fec/grc/variable_polar_code_configurator.xml
+++ b/gr-fec/grc/variable_polar_code_configurator.xml
@@ -25,12 +25,14 @@
<param>
<name>Block size (N)</name>
<key>block_size</key>
+ <value>32</value>
<type>int</type>
</param>
<param>
- <name>#Info Bits (K)</name>
+ <name>Info Bits (K)</name>
<key>num_info_bits</key>
+ <value>16</value>
<type>int</type>
</param>
@@ -46,6 +48,12 @@
<key>mu</key>
<value>16</value>
<type>int</type>
- <hide>#if 'BEC' in $getVar('channel') then 'all' else 'none' #</hide>
</param>
-</block> \ No newline at end of file
+ <doc>This block serves as an interface to the underlying Python functions for channel construction.
+
+ Current channel types are: BEC/AWGN
+ Block size must be a power of 2!
+ Info Bits must be 0 smaller K smaller N
+ Design SNR does affect the target transmission SNR and thus performance.
+ The parameter mu is only relevant for AWGN channels. It is passed on to the corresponding Channel construction algorithm.</doc>
+</block>
diff --git a/gr-fft/lib/fft.cc b/gr-fft/lib/fft.cc
index 3b6d05c383..871ad9bcaa 100644
--- a/gr-fft/lib/fft.cc
+++ b/gr-fft/lib/fft.cc
@@ -26,7 +26,7 @@
#include <volk/volk.h>
#include <fftw3.h>
-#ifdef _MSC_VER //http://www.fftw.org/install/windows.html#DLLwisdom
+#ifdef _WIN32 //http://www.fftw.org/install/windows.html#DLLwisdom
static void my_fftw_write_char(char c, void *f) { fputc(c, (FILE *) f); }
#define fftw_export_wisdom_to_file(f) fftw_export_wisdom(my_fftw_write_char, (void*) (f))
#define fftwf_export_wisdom_to_file(f) fftwf_export_wisdom(my_fftw_write_char, (void*) (f))
@@ -40,7 +40,7 @@ static int my_fftw_read_char(void *f) { return fgetc((FILE *) f); }
#include <io.h>
#define O_NOCTTY 0
#define O_NONBLOCK 0
-#endif //_MSC_VER
+#endif //_WIN32
#include <stdlib.h>
#include <string.h>
diff --git a/gr-filter/include/gnuradio/filter/CMakeLists.txt b/gr-filter/include/gnuradio/filter/CMakeLists.txt
index e75f02b7a2..96c9701079 100644
--- a/gr-filter/include/gnuradio/filter/CMakeLists.txt
+++ b/gr-filter/include/gnuradio/filter/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2012,2014 Free Software Foundation, Inc.
+# Copyright (C) 2012,2014,2017 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -44,6 +44,8 @@ install(FILES
interpolator_taps.h
mmse_fir_interpolator_cc.h
mmse_fir_interpolator_ff.h
+ mmse_interp_differentiator_cc.h
+ mmse_interp_differentiator_ff.h
pm_remez.h
polyphase_filterbank.h
filterbank.h
diff --git a/gr-filter/include/gnuradio/filter/interp_differentiator_taps.h b/gr-filter/include/gnuradio/filter/interp_differentiator_taps.h
new file mode 100644
index 0000000000..cc63a93a74
--- /dev/null
+++ b/gr-filter/include/gnuradio/filter/interp_differentiator_taps.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * This file was machine generated by gen_interp_differentiator_taps.
+ * DO NOT EDIT BY HAND.
+ */
+
+static const int DNTAPS = 8;
+static const int DNSTEPS = 128;
+static const double DBANDWIDTH = 0.25;
+
+static const float Dtaps[DNSTEPS+1][DNTAPS] = {
+ // -4 -3 -2 -1 0 1 2 3 mu
+ { -1.97975e-02, 1.09180e-01, -3.53697e-01, 1.00394e+00, -1.76425e-01, -6.98940e-01, 1.60378e-01, -2.55693e-02 }, // 0/128
+ { -1.98041e-02, 1.09378e-01, -3.55314e-01, 1.01662e+00, -1.98983e-01, -6.86147e-01, 1.58694e-01, -2.53710e-02 }, // 1/128
+ { -1.98003e-02, 1.09519e-01, -3.56761e-01, 1.02906e+00, -2.21442e-01, -6.73286e-01, 1.56945e-01, -2.51608e-02 }, // 2/128
+ { -1.97862e-02, 1.09604e-01, -3.58039e-01, 1.04126e+00, -2.43798e-01, -6.60361e-01, 1.55133e-01, -2.49389e-02 }, // 3/128
+ { -1.97616e-02, 1.09633e-01, -3.59146e-01, 1.05322e+00, -2.66043e-01, -6.47378e-01, 1.53260e-01, -2.47055e-02 }, // 4/128
+ { -1.97267e-02, 1.09605e-01, -3.60080e-01, 1.06494e+00, -2.88174e-01, -6.34339e-01, 1.51327e-01, -2.44607e-02 }, // 5/128
+ { -1.96814e-02, 1.09520e-01, -3.60840e-01, 1.07640e+00, -3.10183e-01, -6.21250e-01, 1.49335e-01, -2.42049e-02 }, // 6/128
+ { -1.96258e-02, 1.09379e-01, -3.61425e-01, 1.08760e+00, -3.32066e-01, -6.08114e-01, 1.47287e-01, -2.39381e-02 }, // 7/128
+ { -1.95598e-02, 1.09180e-01, -3.61833e-01, 1.09855e+00, -3.53816e-01, -5.94935e-01, 1.45183e-01, -2.36607e-02 }, // 8/128
+ { -1.94834e-02, 1.08925e-01, -3.62064e-01, 1.10923e+00, -3.75429e-01, -5.81717e-01, 1.43025e-01, -2.33727e-02 }, // 9/128
+ { -1.93968e-02, 1.08612e-01, -3.62117e-01, 1.11965e+00, -3.96899e-01, -5.68465e-01, 1.40814e-01, -2.30745e-02 }, // 10/128
+ { -1.92998e-02, 1.08243e-01, -3.61990e-01, 1.12979e+00, -4.18221e-01, -5.55183e-01, 1.38553e-01, -2.27662e-02 }, // 11/128
+ { -1.91927e-02, 1.07816e-01, -3.61683e-01, 1.13966e+00, -4.39388e-01, -5.41875e-01, 1.36242e-01, -2.24481e-02 }, // 12/128
+ { -1.90753e-02, 1.07333e-01, -3.61195e-01, 1.14926e+00, -4.60397e-01, -5.28544e-01, 1.33883e-01, -2.21203e-02 }, // 13/128
+ { -1.89477e-02, 1.06793e-01, -3.60525e-01, 1.15857e+00, -4.81241e-01, -5.15195e-01, 1.31477e-01, -2.17832e-02 }, // 14/128
+ { -1.88101e-02, 1.06195e-01, -3.59672e-01, 1.16761e+00, -5.01915e-01, -5.01832e-01, 1.29027e-01, -2.14369e-02 }, // 15/128
+ { -1.86623e-02, 1.05541e-01, -3.58635e-01, 1.17635e+00, -5.22415e-01, -4.88459e-01, 1.26533e-01, -2.10816e-02 }, // 16/128
+ { -1.85046e-02, 1.04831e-01, -3.57414e-01, 1.18481e+00, -5.42735e-01, -4.75079e-01, 1.23997e-01, -2.07177e-02 }, // 17/128
+ { -1.83369e-02, 1.04064e-01, -3.56008e-01, 1.19297e+00, -5.62871e-01, -4.61698e-01, 1.21421e-01, -2.03452e-02 }, // 18/128
+ { -1.81593e-02, 1.03240e-01, -3.54416e-01, 1.20083e+00, -5.82817e-01, -4.48318e-01, 1.18806e-01, -1.99646e-02 }, // 19/128
+ { -1.79718e-02, 1.02361e-01, -3.52639e-01, 1.20840e+00, -6.02568e-01, -4.34944e-01, 1.16154e-01, -1.95759e-02 }, // 20/128
+ { -1.77746e-02, 1.01425e-01, -3.50676e-01, 1.21567e+00, -6.22120e-01, -4.21579e-01, 1.13466e-01, -1.91794e-02 }, // 21/128
+ { -1.75678e-02, 1.00434e-01, -3.48526e-01, 1.22263e+00, -6.41467e-01, -4.08229e-01, 1.10744e-01, -1.87754e-02 }, // 22/128
+ { -1.73513e-02, 9.93878e-02, -3.46188e-01, 1.22928e+00, -6.60606e-01, -3.94895e-01, 1.07989e-01, -1.83641e-02 }, // 23/128
+ { -1.71253e-02, 9.82862e-02, -3.43664e-01, 1.23563e+00, -6.79531e-01, -3.81583e-01, 1.05203e-01, -1.79458e-02 }, // 24/128
+ { -1.68899e-02, 9.71297e-02, -3.40952e-01, 1.24166e+00, -6.98238e-01, -3.68296e-01, 1.02387e-01, -1.75206e-02 }, // 25/128
+ { -1.66451e-02, 9.59188e-02, -3.38052e-01, 1.24738e+00, -7.16722e-01, -3.55037e-01, 9.95428e-02, -1.70889e-02 }, // 26/128
+ { -1.63911e-02, 9.46536e-02, -3.34965e-01, 1.25278e+00, -7.34980e-01, -3.41811e-01, 9.66721e-02, -1.66509e-02 }, // 27/128
+ { -1.61280e-02, 9.33347e-02, -3.31690e-01, 1.25786e+00, -7.53006e-01, -3.28622e-01, 9.37762e-02, -1.62068e-02 }, // 28/128
+ { -1.58558e-02, 9.19624e-02, -3.28227e-01, 1.26263e+00, -7.70796e-01, -3.15472e-01, 9.08568e-02, -1.57569e-02 }, // 29/128
+ { -1.55747e-02, 9.05371e-02, -3.24577e-01, 1.26707e+00, -7.88347e-01, -3.02366e-01, 8.79152e-02, -1.53014e-02 }, // 30/128
+ { -1.52848e-02, 8.90593e-02, -3.20739e-01, 1.27118e+00, -8.05653e-01, -2.89308e-01, 8.49529e-02, -1.48405e-02 }, // 31/128
+ { -1.49862e-02, 8.75294e-02, -3.16714e-01, 1.27497e+00, -8.22711e-01, -2.76300e-01, 8.19717e-02, -1.43747e-02 }, // 32/128
+ { -1.46789e-02, 8.59479e-02, -3.12502e-01, 1.27843e+00, -8.39517e-01, -2.63347e-01, 7.89727e-02, -1.39039e-02 }, // 33/128
+ { -1.43633e-02, 8.43153e-02, -3.08103e-01, 1.28156e+00, -8.56067e-01, -2.50452e-01, 7.59576e-02, -1.34286e-02 }, // 34/128
+ { -1.40393e-02, 8.26321e-02, -3.03518e-01, 1.28435e+00, -8.72357e-01, -2.37619e-01, 7.29278e-02, -1.29490e-02 }, // 35/128
+ { -1.37071e-02, 8.08990e-02, -2.98747e-01, 1.28682e+00, -8.88384e-01, -2.24851e-01, 6.98849e-02, -1.24653e-02 }, // 36/128
+ { -1.33668e-02, 7.91163e-02, -2.93791e-01, 1.28895e+00, -9.04143e-01, -2.12151e-01, 6.68302e-02, -1.19778e-02 }, // 37/128
+ { -1.30187e-02, 7.72849e-02, -2.88650e-01, 1.29074e+00, -9.19630e-01, -1.99523e-01, 6.37653e-02, -1.14867e-02 }, // 38/128
+ { -1.26627e-02, 7.54052e-02, -2.83325e-01, 1.29220e+00, -9.34844e-01, -1.86970e-01, 6.06916e-02, -1.09923e-02 }, // 39/128
+ { -1.22991e-02, 7.34779e-02, -2.77817e-01, 1.29332e+00, -9.49779e-01, -1.74496e-01, 5.76105e-02, -1.04948e-02 }, // 40/128
+ { -1.19280e-02, 7.15036e-02, -2.72125e-01, 1.29410e+00, -9.64433e-01, -1.62104e-01, 5.45235e-02, -9.99449e-03 }, // 41/128
+ { -1.15496e-02, 6.94831e-02, -2.66252e-01, 1.29453e+00, -9.78802e-01, -1.49797e-01, 5.14320e-02, -9.49163e-03 }, // 42/128
+ { -1.11640e-02, 6.74171e-02, -2.60198e-01, 1.29463e+00, -9.92883e-01, -1.37578e-01, 4.83374e-02, -8.98645e-03 }, // 43/128
+ { -1.07714e-02, 6.53061e-02, -2.53964e-01, 1.29439e+00, -1.00667e+00, -1.25450e-01, 4.52412e-02, -8.47921e-03 }, // 44/128
+ { -1.03719e-02, 6.31511e-02, -2.47551e-01, 1.29380e+00, -1.02017e+00, -1.13418e-01, 4.21447e-02, -7.97016e-03 }, // 45/128
+ { -9.96577e-03, 6.09527e-02, -2.40960e-01, 1.29287e+00, -1.03337e+00, -1.01483e-01, 3.90493e-02, -7.45954e-03 }, // 46/128
+ { -9.55311e-03, 5.87118e-02, -2.34191e-01, 1.29159e+00, -1.04627e+00, -8.96486e-02, 3.59565e-02, -6.94760e-03 }, // 47/128
+ { -9.13410e-03, 5.64291e-02, -2.27247e-01, 1.28997e+00, -1.05886e+00, -7.79181e-02, 3.28675e-02, -6.43460e-03 }, // 48/128
+ { -8.70893e-03, 5.41055e-02, -2.20128e-01, 1.28801e+00, -1.07115e+00, -6.62943e-02, 2.97837e-02, -5.92077e-03 }, // 49/128
+ { -8.27777e-03, 5.17418e-02, -2.12836e-01, 1.28570e+00, -1.08314e+00, -5.47801e-02, 2.67066e-02, -5.40637e-03 }, // 50/128
+ { -7.84082e-03, 4.93389e-02, -2.05372e-01, 1.28305e+00, -1.09481e+00, -4.33784e-02, 2.36373e-02, -4.89163e-03 }, // 51/128
+ { -7.39824e-03, 4.68976e-02, -1.97737e-01, 1.28005e+00, -1.10617e+00, -3.20920e-02, 2.05773e-02, -4.37681e-03 }, // 52/128
+ { -6.95024e-03, 4.44189e-02, -1.89933e-01, 1.27670e+00, -1.11721e+00, -2.09236e-02, 1.75279e-02, -3.86214e-03 }, // 53/128
+ { -6.49701e-03, 4.19036e-02, -1.81961e-01, 1.27302e+00, -1.12794e+00, -9.87606e-03, 1.44903e-02, -3.34787e-03 }, // 54/128
+ { -6.03873e-03, 3.93528e-02, -1.73823e-01, 1.26898e+00, -1.13834e+00, 1.04807e-03, 1.14658e-02, -2.83424e-03 }, // 55/128
+ { -5.57561e-03, 3.67674e-02, -1.65521e-01, 1.26461e+00, -1.14843e+00, 1.18461e-02, 8.45574e-03, -2.32148e-03 }, // 56/128
+ { -5.10786e-03, 3.41483e-02, -1.57056e-01, 1.25989e+00, -1.15819e+00, 2.25155e-02, 5.46133e-03, -1.80983e-03 }, // 57/128
+ { -4.63566e-03, 3.14966e-02, -1.48430e-01, 1.25482e+00, -1.16762e+00, 3.30537e-02, 2.48381e-03, -1.29954e-03 }, // 58/128
+ { -4.15923e-03, 2.88132e-02, -1.39644e-01, 1.24942e+00, -1.17672e+00, 4.34583e-02, -4.75572e-04, -7.90819e-04 }, // 59/128
+ { -3.67878e-03, 2.60992e-02, -1.30701e-01, 1.24367e+00, -1.18550e+00, 5.37267e-02, -3.41562e-03, -2.83916e-04 }, // 60/128
+ { -3.19451e-03, 2.33557e-02, -1.21603e-01, 1.23758e+00, -1.19395e+00, 6.38567e-02, -6.33513e-03, 2.20942e-04 }, // 61/128
+ { -2.70665e-03, 2.05837e-02, -1.12350e-01, 1.23115e+00, -1.20206e+00, 7.38460e-02, -9.23291e-03, 7.23528e-04 }, // 62/128
+ { -2.21539e-03, 1.77843e-02, -1.02946e-01, 1.22439e+00, -1.20984e+00, 8.36921e-02, -1.21078e-02, 1.22361e-03 }, // 63/128
+ { -1.72098e-03, 1.49587e-02, -9.33930e-02, 1.21728e+00, -1.21728e+00, 9.33930e-02, -1.49587e-02, 1.72098e-03 }, // 64/128
+ { -1.22361e-03, 1.21078e-02, -8.36921e-02, 1.20984e+00, -1.22439e+00, 1.02946e-01, -1.77843e-02, 2.21539e-03 }, // 65/128
+ { -7.23528e-04, 9.23291e-03, -7.38460e-02, 1.20206e+00, -1.23115e+00, 1.12350e-01, -2.05837e-02, 2.70665e-03 }, // 66/128
+ { -2.20942e-04, 6.33513e-03, -6.38567e-02, 1.19395e+00, -1.23758e+00, 1.21603e-01, -2.33557e-02, 3.19451e-03 }, // 67/128
+ { 2.83916e-04, 3.41562e-03, -5.37267e-02, 1.18550e+00, -1.24367e+00, 1.30701e-01, -2.60992e-02, 3.67878e-03 }, // 68/128
+ { 7.90819e-04, 4.75572e-04, -4.34583e-02, 1.17672e+00, -1.24942e+00, 1.39644e-01, -2.88132e-02, 4.15923e-03 }, // 69/128
+ { 1.29954e-03, -2.48381e-03, -3.30537e-02, 1.16762e+00, -1.25482e+00, 1.48430e-01, -3.14966e-02, 4.63566e-03 }, // 70/128
+ { 1.80983e-03, -5.46133e-03, -2.25155e-02, 1.15819e+00, -1.25989e+00, 1.57056e-01, -3.41483e-02, 5.10786e-03 }, // 71/128
+ { 2.32148e-03, -8.45574e-03, -1.18461e-02, 1.14843e+00, -1.26461e+00, 1.65521e-01, -3.67674e-02, 5.57561e-03 }, // 72/128
+ { 2.83424e-03, -1.14658e-02, -1.04807e-03, 1.13834e+00, -1.26898e+00, 1.73823e-01, -3.93528e-02, 6.03873e-03 }, // 73/128
+ { 3.34787e-03, -1.44903e-02, 9.87606e-03, 1.12794e+00, -1.27302e+00, 1.81961e-01, -4.19036e-02, 6.49701e-03 }, // 74/128
+ { 3.86214e-03, -1.75279e-02, 2.09236e-02, 1.11721e+00, -1.27670e+00, 1.89933e-01, -4.44189e-02, 6.95024e-03 }, // 75/128
+ { 4.37681e-03, -2.05773e-02, 3.20920e-02, 1.10617e+00, -1.28005e+00, 1.97737e-01, -4.68976e-02, 7.39824e-03 }, // 76/128
+ { 4.89163e-03, -2.36373e-02, 4.33784e-02, 1.09481e+00, -1.28305e+00, 2.05372e-01, -4.93389e-02, 7.84082e-03 }, // 77/128
+ { 5.40637e-03, -2.67066e-02, 5.47801e-02, 1.08314e+00, -1.28570e+00, 2.12836e-01, -5.17418e-02, 8.27777e-03 }, // 78/128
+ { 5.92077e-03, -2.97837e-02, 6.62943e-02, 1.07115e+00, -1.28801e+00, 2.20128e-01, -5.41055e-02, 8.70893e-03 }, // 79/128
+ { 6.43460e-03, -3.28675e-02, 7.79181e-02, 1.05886e+00, -1.28997e+00, 2.27247e-01, -5.64291e-02, 9.13410e-03 }, // 80/128
+ { 6.94760e-03, -3.59565e-02, 8.96486e-02, 1.04627e+00, -1.29159e+00, 2.34191e-01, -5.87118e-02, 9.55311e-03 }, // 81/128
+ { 7.45954e-03, -3.90493e-02, 1.01483e-01, 1.03337e+00, -1.29287e+00, 2.40960e-01, -6.09527e-02, 9.96577e-03 }, // 82/128
+ { 7.97016e-03, -4.21447e-02, 1.13418e-01, 1.02017e+00, -1.29380e+00, 2.47551e-01, -6.31511e-02, 1.03719e-02 }, // 83/128
+ { 8.47921e-03, -4.52412e-02, 1.25450e-01, 1.00667e+00, -1.29439e+00, 2.53964e-01, -6.53061e-02, 1.07714e-02 }, // 84/128
+ { 8.98645e-03, -4.83374e-02, 1.37578e-01, 9.92883e-01, -1.29463e+00, 2.60198e-01, -6.74171e-02, 1.11640e-02 }, // 85/128
+ { 9.49163e-03, -5.14320e-02, 1.49797e-01, 9.78802e-01, -1.29453e+00, 2.66252e-01, -6.94831e-02, 1.15496e-02 }, // 86/128
+ { 9.99449e-03, -5.45235e-02, 1.62104e-01, 9.64433e-01, -1.29410e+00, 2.72125e-01, -7.15036e-02, 1.19280e-02 }, // 87/128
+ { 1.04948e-02, -5.76105e-02, 1.74496e-01, 9.49779e-01, -1.29332e+00, 2.77817e-01, -7.34779e-02, 1.22991e-02 }, // 88/128
+ { 1.09923e-02, -6.06916e-02, 1.86970e-01, 9.34844e-01, -1.29220e+00, 2.83325e-01, -7.54052e-02, 1.26627e-02 }, // 89/128
+ { 1.14867e-02, -6.37653e-02, 1.99523e-01, 9.19630e-01, -1.29074e+00, 2.88650e-01, -7.72849e-02, 1.30187e-02 }, // 90/128
+ { 1.19778e-02, -6.68302e-02, 2.12151e-01, 9.04143e-01, -1.28895e+00, 2.93791e-01, -7.91163e-02, 1.33668e-02 }, // 91/128
+ { 1.24653e-02, -6.98849e-02, 2.24851e-01, 8.88384e-01, -1.28682e+00, 2.98747e-01, -8.08990e-02, 1.37071e-02 }, // 92/128
+ { 1.29490e-02, -7.29278e-02, 2.37619e-01, 8.72357e-01, -1.28435e+00, 3.03518e-01, -8.26321e-02, 1.40393e-02 }, // 93/128
+ { 1.34286e-02, -7.59576e-02, 2.50452e-01, 8.56067e-01, -1.28156e+00, 3.08103e-01, -8.43153e-02, 1.43633e-02 }, // 94/128
+ { 1.39039e-02, -7.89727e-02, 2.63347e-01, 8.39517e-01, -1.27843e+00, 3.12502e-01, -8.59479e-02, 1.46789e-02 }, // 95/128
+ { 1.43747e-02, -8.19717e-02, 2.76300e-01, 8.22711e-01, -1.27497e+00, 3.16714e-01, -8.75294e-02, 1.49862e-02 }, // 96/128
+ { 1.48406e-02, -8.49530e-02, 2.89308e-01, 8.05653e-01, -1.27118e+00, 3.20739e-01, -8.90593e-02, 1.52848e-02 }, // 97/128
+ { 1.53014e-02, -8.79152e-02, 3.02366e-01, 7.88347e-01, -1.26707e+00, 3.24577e-01, -9.05371e-02, 1.55747e-02 }, // 98/128
+ { 1.57569e-02, -9.08568e-02, 3.15472e-01, 7.70796e-01, -1.26263e+00, 3.28227e-01, -9.19624e-02, 1.58558e-02 }, // 99/128
+ { 1.62068e-02, -9.37762e-02, 3.28622e-01, 7.53006e-01, -1.25786e+00, 3.31690e-01, -9.33347e-02, 1.61280e-02 }, // 100/128
+ { 1.66509e-02, -9.66721e-02, 3.41811e-01, 7.34980e-01, -1.25278e+00, 3.34965e-01, -9.46536e-02, 1.63911e-02 }, // 101/128
+ { 1.70889e-02, -9.95428e-02, 3.55037e-01, 7.16722e-01, -1.24738e+00, 3.38052e-01, -9.59188e-02, 1.66451e-02 }, // 102/128
+ { 1.75206e-02, -1.02387e-01, 3.68296e-01, 6.98238e-01, -1.24166e+00, 3.40952e-01, -9.71297e-02, 1.68899e-02 }, // 103/128
+ { 1.79458e-02, -1.05203e-01, 3.81583e-01, 6.79531e-01, -1.23563e+00, 3.43664e-01, -9.82862e-02, 1.71253e-02 }, // 104/128
+ { 1.83641e-02, -1.07989e-01, 3.94895e-01, 6.60606e-01, -1.22928e+00, 3.46188e-01, -9.93878e-02, 1.73513e-02 }, // 105/128
+ { 1.87754e-02, -1.10744e-01, 4.08229e-01, 6.41467e-01, -1.22263e+00, 3.48526e-01, -1.00434e-01, 1.75678e-02 }, // 106/128
+ { 1.91794e-02, -1.13466e-01, 4.21579e-01, 6.22120e-01, -1.21567e+00, 3.50676e-01, -1.01425e-01, 1.77746e-02 }, // 107/128
+ { 1.95759e-02, -1.16154e-01, 4.34944e-01, 6.02568e-01, -1.20840e+00, 3.52639e-01, -1.02361e-01, 1.79718e-02 }, // 108/128
+ { 1.99646e-02, -1.18806e-01, 4.48318e-01, 5.82817e-01, -1.20083e+00, 3.54416e-01, -1.03240e-01, 1.81593e-02 }, // 109/128
+ { 2.03452e-02, -1.21421e-01, 4.61698e-01, 5.62871e-01, -1.19297e+00, 3.56008e-01, -1.04064e-01, 1.83369e-02 }, // 110/128
+ { 2.07177e-02, -1.23997e-01, 4.75079e-01, 5.42735e-01, -1.18481e+00, 3.57414e-01, -1.04831e-01, 1.85046e-02 }, // 111/128
+ { 2.10816e-02, -1.26533e-01, 4.88459e-01, 5.22415e-01, -1.17635e+00, 3.58635e-01, -1.05541e-01, 1.86623e-02 }, // 112/128
+ { 2.14369e-02, -1.29027e-01, 5.01832e-01, 5.01915e-01, -1.16761e+00, 3.59672e-01, -1.06195e-01, 1.88101e-02 }, // 113/128
+ { 2.17832e-02, -1.31477e-01, 5.15195e-01, 4.81241e-01, -1.15857e+00, 3.60525e-01, -1.06793e-01, 1.89477e-02 }, // 114/128
+ { 2.21203e-02, -1.33883e-01, 5.28544e-01, 4.60397e-01, -1.14926e+00, 3.61195e-01, -1.07333e-01, 1.90753e-02 }, // 115/128
+ { 2.24481e-02, -1.36242e-01, 5.41875e-01, 4.39388e-01, -1.13966e+00, 3.61683e-01, -1.07816e-01, 1.91927e-02 }, // 116/128
+ { 2.27662e-02, -1.38553e-01, 5.55183e-01, 4.18221e-01, -1.12979e+00, 3.61990e-01, -1.08243e-01, 1.92998e-02 }, // 117/128
+ { 2.30745e-02, -1.40814e-01, 5.68465e-01, 3.96899e-01, -1.11965e+00, 3.62117e-01, -1.08612e-01, 1.93968e-02 }, // 118/128
+ { 2.33727e-02, -1.43025e-01, 5.81717e-01, 3.75429e-01, -1.10923e+00, 3.62064e-01, -1.08925e-01, 1.94834e-02 }, // 119/128
+ { 2.36607e-02, -1.45183e-01, 5.94935e-01, 3.53816e-01, -1.09855e+00, 3.61833e-01, -1.09180e-01, 1.95598e-02 }, // 120/128
+ { 2.39381e-02, -1.47287e-01, 6.08114e-01, 3.32066e-01, -1.08760e+00, 3.61425e-01, -1.09379e-01, 1.96258e-02 }, // 121/128
+ { 2.42049e-02, -1.49335e-01, 6.21250e-01, 3.10183e-01, -1.07640e+00, 3.60840e-01, -1.09520e-01, 1.96814e-02 }, // 122/128
+ { 2.44607e-02, -1.51327e-01, 6.34339e-01, 2.88174e-01, -1.06494e+00, 3.60080e-01, -1.09605e-01, 1.97267e-02 }, // 123/128
+ { 2.47055e-02, -1.53260e-01, 6.47378e-01, 2.66043e-01, -1.05322e+00, 3.59146e-01, -1.09633e-01, 1.97616e-02 }, // 124/128
+ { 2.49389e-02, -1.55133e-01, 6.60361e-01, 2.43798e-01, -1.04126e+00, 3.58039e-01, -1.09604e-01, 1.97862e-02 }, // 125/128
+ { 2.51608e-02, -1.56945e-01, 6.73286e-01, 2.21442e-01, -1.02906e+00, 3.56761e-01, -1.09519e-01, 1.98003e-02 }, // 126/128
+ { 2.53710e-02, -1.58694e-01, 6.86147e-01, 1.98983e-01, -1.01662e+00, 3.55314e-01, -1.09378e-01, 1.98041e-02 }, // 127/128
+ { 2.55693e-02, -1.60378e-01, 6.98940e-01, 1.76425e-01, -1.00394e+00, 3.53697e-01, -1.09180e-01, 1.97975e-02 }, // 128/128
+};
+
diff --git a/gr-filter/include/gnuradio/filter/mmse_interp_differentiator_cc.h b/gr-filter/include/gnuradio/filter/mmse_interp_differentiator_cc.h
new file mode 100644
index 0000000000..5170264b2f
--- /dev/null
+++ b/gr-filter/include/gnuradio/filter/mmse_interp_differentiator_cc.h
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2007,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _MMSE_INTERP_DIFFERENTIATOR_CC_H_
+#define _MMSE_INTERP_DIFFERENTIATOR_CC_H_
+
+#include <gnuradio/filter/api.h>
+#include <gnuradio/filter/fir_filter.h>
+#include <gnuradio/gr_complex.h>
+#include <vector>
+
+namespace gr {
+ namespace filter {
+
+ /*!
+ * \brief Compute intermediate samples of the derivative of a signal
+ * between signal samples x(k*Ts)
+ * \ingroup filter_primitive
+ *
+ * \details
+ * This implements a Mininum Mean Squared Error interpolating
+ * differentiator with 8 taps. It is suitable for signals where the
+ * derivative of a signal has a bandwidth of interest in the range
+ * (-Fs/4, Fs/4), where Fs is the samples rate.
+ *
+ * Although mu, the fractional delay, is specified as a float, in
+ * the range [0.0, 1.0], it is actually quantized. That is, mu is
+ * quantized in the differentiate method to 128th's of a sample.
+ *
+ */
+ class FILTER_API mmse_interp_differentiator_cc
+ {
+ public:
+ mmse_interp_differentiator_cc();
+ ~mmse_interp_differentiator_cc();
+
+ unsigned ntaps() const;
+ unsigned nsteps() const;
+
+ /*!
+ * \brief compute a single interpolated differentiated output value.
+ *
+ * \p input must have ntaps() valid entries.
+ * input[0] .. input[ntaps() - 1] are referenced to compute the output
+ * value.
+ *
+ * \p mu must be in the range [0, 1] and specifies the fractional delay.
+ *
+ * \throws std::runtime_error if mu is not in the range [0, 1].
+ *
+ * \returns the interpolated differentiated output value.
+ */
+ gr_complex differentiate(const gr_complex input[], float mu) const;
+
+ protected:
+ std::vector<kernel::fir_filter_ccf *> filters;
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* _MMSE_INTERP_DIFFERENTIATOR_CC_H_ */
diff --git a/gr-filter/include/gnuradio/filter/mmse_interp_differentiator_ff.h b/gr-filter/include/gnuradio/filter/mmse_interp_differentiator_ff.h
new file mode 100644
index 0000000000..eb176cd753
--- /dev/null
+++ b/gr-filter/include/gnuradio/filter/mmse_interp_differentiator_ff.h
@@ -0,0 +1,79 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2007,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _MMSE_INTERP_DIFFERENTIATOR_FF_H_
+#define _MMSE_INTERP_DIFFERENTIATOR_FF_H_
+
+#include <gnuradio/filter/api.h>
+#include <gnuradio/filter/fir_filter.h>
+#include <vector>
+
+namespace gr {
+ namespace filter {
+
+ /*!
+ * \brief Compute intermediate samples of the derivative of a signal
+ * between signal samples x(k*Ts)
+ * \ingroup filter_primitive
+ *
+ * \details
+ * This implements a Mininum Mean Squared Error interpolating
+ * differentiator with 8 taps. It is suitable for signals where the
+ * derivative of a signal has a bandwidth of interest in the range
+ * (-Fs/4, Fs/4), where Fs is the samples rate.
+ *
+ * Although mu, the fractional delay, is specified as a float, in
+ * the range [0.0, 1.0], it is actually quantized. That is, mu is
+ * quantized in the differentiate method to 128th's of a sample.
+ *
+ */
+ class FILTER_API mmse_interp_differentiator_ff
+ {
+ public:
+ mmse_interp_differentiator_ff();
+ ~mmse_interp_differentiator_ff();
+
+ unsigned ntaps() const;
+ unsigned nsteps() const;
+
+ /*!
+ * \brief compute a single interpolated differentiated output value.
+ *
+ * \p input must have ntaps() valid entries.
+ * input[0] .. input[ntaps() - 1] are referenced to compute the output
+ * value.
+ *
+ * \p mu must be in the range [0, 1] and specifies the fractional delay.
+ *
+ * \throws std::runtime_error if mu is not in the range [0, 1].
+ *
+ * \returns the interpolated differentiated output value.
+ */
+ float differentiate(const float input[], float mu) const;
+
+ protected:
+ std::vector<kernel::fir_filter_fff *> filters;
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* _MMSE_INTERP_DIFFERENTIATOR_FF_H_ */
diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt
index 6847029e35..85da7fb7a0 100644
--- a/gr-filter/lib/CMakeLists.txt
+++ b/gr-filter/lib/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2012-2014 Free Software Foundation, Inc.
+# Copyright (C) 2012-2014,2017 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -59,6 +59,8 @@ list(APPEND filter_sources
iir_filter.cc
mmse_fir_interpolator_cc.cc
mmse_fir_interpolator_ff.cc
+ mmse_interp_differentiator_cc.cc
+ mmse_interp_differentiator_ff.cc
pm_remez.cc
polyphase_filterbank.cc
${generated_sources}
@@ -167,6 +169,8 @@ if(ENABLE_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/qa_fir_filter_with_buffer.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_cc.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_ff.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_interp_differentiator_cc.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_interp_differentiator_ff.cc
)
add_executable(test-gr-filter ${test_gr_filter_sources})
diff --git a/gr-filter/lib/gen_interpolator_taps/diff_objective_fct.c b/gr-filter/lib/gen_interpolator_taps/diff_objective_fct.c
new file mode 100644
index 0000000000..367aeeb356
--- /dev/null
+++ b/gr-filter/lib/gen_interpolator_taps/diff_objective_fct.c
@@ -0,0 +1,214 @@
+/* -*- c -*- */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * generate MMSE interpolating differentiator FIR table values
+ */
+
+#include <math.h>
+#include <assert.h>
+#include <gsl/gsl_integration.h>
+
+#define MU 0.5 /* the MU for which we're computing coeffs */
+
+#define Ts (1.0) /* sampling period */
+#define B (1.0/(4*Ts)) /* one-sided signal bandwidth */
+//#define B (1.0/(8./3*Ts)) /* one-sided signal bandwidth */
+
+static unsigned global_n;
+static double *global_h;
+double global_mu = MU;
+double global_B = B;
+
+gsl_integration_workspace *global_gsl_int_workspace = NULL;
+
+/*
+ * This function computes the difference squared between the ideal
+ * interpolating differentiator frequency response at frequency OMEGA and the
+ * approximation defined by the FIR coefficients in global_h[]
+ *
+ * See eqn (9-7), "Digital Communication Receivers", Meyr, Moeneclaey
+ * and Fechtel, Wiley, 1998. for the jist of what going on here.
+ *
+ * See eqns (7.99) and (7.100), "Discrete Time Signal Processing",
+ * Oppenheim, Alan V., Schafer, Ronald W., Prentice Hall 1989. for the
+ * (non-bandlimited) ideal differentiator.
+ *
+ * Andy Walls derived the expression for the h[n] for the bandlimited
+ * differentiator by performing an Inverse DTFT on the bandlimited ideal
+ * response. (Integration by parts.)
+ */
+
+static double
+integrand (double omega, void *params)
+{
+ double real_ideal;
+ double real_approx;
+ double real_diff;
+ double imag_ideal;
+ double imag_approx;
+ double imag_diff;
+
+ int i, n;
+ int I1;
+ double *h;
+
+ /*
+ * Ideal differentiator frequency response,
+ * with freq modulation to effect a time shift left (advance),
+ * and band limited to (-fc, fc).
+ * N.B. fc is global_B, mu is global_mu, Fs is 1/Ts, 2*pi*f is omega.
+ * fc and Fs are in Hz, and omega is in radians/second.
+ *
+ * H(f) = j*2*pi*f*Ts * exp(j*2*pi*f*Ts*mu) for |f| <= fc <= Fs/2
+ */
+ real_ideal = -omega * Ts * sin (omega * Ts * global_mu);
+ imag_ideal = omega * Ts * cos (omega * Ts * global_mu);
+
+ n = global_n;
+ h = global_h;
+ I1 = -(n / 2);
+
+ real_approx = 0;
+ imag_approx = 0;
+
+ for (i = 0; i < n; i++){
+ real_approx += h[i] * cos (-omega * Ts * (i + I1));
+ imag_approx += h[i] * sin (-omega * Ts * (i + I1));
+ }
+
+ real_diff = real_ideal - real_approx;
+ imag_diff = imag_ideal - imag_approx;
+
+ return real_diff * real_diff + imag_diff * imag_diff;
+}
+
+/*
+ * Integrate the difference squared over all frequencies of interest.
+ */
+double
+c_fcn (double *x, int n)
+{
+ gsl_function F;
+ double result, error;
+
+ F.function = integrand;
+ F.params = NULL;
+
+ assert ((n & 1) == 0); /* assert n is even */
+ global_n = n;
+ global_h = x;
+ // global_B is fc, the cutoff frequency in Hz. It defaults to Fs/4.0.
+ gsl_integration_qag(&F, -2 * M_PI * global_B, 2 * M_PI * global_B,
+ 0.0, 1e-12, 1000, GSL_INTEG_GAUSS61,
+ global_gsl_int_workspace, &result, &error);
+ return result;
+}
+
+/* this is the interface expected by the calling fortran code */
+
+double
+objective (double x[], int *ndim)
+{
+ return c_fcn (x, *ndim);
+}
+
+/*
+ * starting guess for optimization
+ */
+void initpt (double x[], int ndim)
+{
+ int i;
+ double w_c;
+ double start;
+ double t;
+ double arg;
+ double denom;
+
+ /* Bandlimited, time shifted, differentiator filter (infinitely long)
+ *
+ * Andy Walls derived the expression for the h[n] for the bandlimited
+ * differentiator by performing an Inverse DTFT on the bandlimited ideal
+ * response. (Integration by parts.)
+ *
+ * Ideal differentiator frequency response,
+ * with freq modulation to effect a time shift left (advance),
+ * and band limited to (-fc, fc).
+ * N.B. fc is global_B, mu is global_mu, Fs is 1/Ts.
+ * fc and Fs are in Hz, and omega is in radians/second.
+ *
+ * H(f) = j*2*pi*f*Ts * exp(j*2*pi*f*Ts*mu) for |f| <= fc <= Fs/2
+ * H(f) = 0 for |f| > fc <= Fs/2
+ *
+ * Substituting normalized radian frequency, w, for 2*pi*f*Ts, we get:
+ *
+ * H(w) = j*w * exp(j*w*mu) for |w| <= w_c = 2*pi*fc*Ts <= pi
+ * H(w) = 0 for |w| > w_c = 2*pi*fc*Ts <= pi
+ *
+ * and the Inverse Discrete Time Fourier Transform is:
+ *
+ * h[n] = (1/(2*pi)) * integral(-pi,pi)[ H(w)*exp(j*w*n)*dw ]
+ *
+ * Performing integration by parts of the above expression, using these hints:
+ * integral [u*dv] = u*v - integral [v*du]
+ * u = j*w
+ * dv = exp(j*w*(n+mu))*dw
+ *
+ * We eventually get an infinitely long, but decaying impulse response:
+ *
+ * h[n] = (w_c/pi)/(n+mu) * [cos(pi*(w_c/pi)*(n+mu)) - sinc((w_c/pi)*(n+mu))]
+ *
+ * = [ w_c*(n+mu)*cos(w_c*(n+mu)) - sin(w_c*(n+mu)) ] / (pi*(n+mu)^2)
+ *
+ * w_c is the normalized radian cutoff frequency:
+ * 2*pi*fc*Ts, with fc <= Fs/2 and Fs = 1/Ts, so w_c <= pi
+ *
+ * For the case of w_c = pi and mu = 0, the cos() term alternates
+ * between +/- 1 and the sinc() term goes to 0 except at n == 0, so
+ * we get the following:
+ *
+ * h[n] = (-1)^n / n for n != 0
+ * = 0 for n == 0
+ * or
+ *
+ * h[n] = ..., 1/5, -1/4, 1/3, -1/2, 1, 0, -1, 1/2, -1/3, 1/4, -1/5, ...
+ *
+ * Compare with:
+ * Eqns (7.99) and (7.100), "Discrete Time Signal Processing",
+ * Oppenheim, Alan V., Schafer, Ronald W., Prentice Hall 1989. for the
+ * non-bandlimited (w_c = pi) ideal differentiator.
+ */
+
+ /* Truncated, bandlimited, time shifted, differentiator filter */
+ w_c = 2.0 * M_PI * global_B * Ts;
+ start = (double)(-ndim/2) + global_mu;
+
+ for (i = 0; i < ndim; i++){
+ t = (double)(i) + start;
+ arg = w_c * t;
+ denom = M_PI*t*t; /* always >= 0.0 */
+ if (denom < 1e-9)
+ x[i] = 0.0;
+ else
+ x[i] = (arg * cos(arg) - sin(arg))/denom;
+ }
+}
diff --git a/gr-filter/lib/gen_interpolator_taps/gen_interp_differentiator_taps.c b/gr-filter/lib/gen_interpolator_taps/gen_interp_differentiator_taps.c
new file mode 100644
index 0000000000..d34ccea6c6
--- /dev/null
+++ b/gr-filter/lib/gen_interpolator_taps/gen_interp_differentiator_taps.c
@@ -0,0 +1,182 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <gsl/gsl_integration.h>
+
+#define NSTEPS 10 // how many steps of mu are in the generated table
+#define MAX_NSTEPS 256
+#define NTAPS 8 // # of taps in the interpolator
+#define MAX_NTAPS 128
+
+extern void initpt (double x[], int ntaps);
+extern double objective (double x[], int *ntaps);
+extern double global_mu;
+extern double global_B;
+extern gsl_integration_workspace *global_gsl_int_workspace;
+
+// fortran
+extern double prax2_ (double (fct)(double x[], int *ntaps),
+ double initv[], int *ntaps, double result[]);
+
+static void
+usage (char *name)
+{
+ fprintf (stderr, "usage: %s [-v] [-n <nsteps>] [-t <ntaps>] [-B <bw>]\n", name);
+ exit (1);
+}
+
+static void
+printline (double x[], int ntaps, int imu, int nsteps)
+{
+ int i;
+
+ printf (" { ");
+ for (i = 0; i < ntaps; i++){
+ printf ("%12.5e", x[i]);
+ if (i != ntaps - 1)
+ printf (", ");
+ else
+ printf (" }, // %3d/%d\n", imu, nsteps);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ double xx[MAX_NSTEPS+1][MAX_NTAPS];
+ int ntaps = NTAPS;
+ int nsteps = NSTEPS;
+ int i, j;
+ double result;
+ double step_size;
+ int c;
+ int verbose = 0;
+
+ global_B = 0.25;
+
+ while ((c = getopt (argc, argv, "n:t:B:v")) != EOF){
+ switch (c){
+ case 'n':
+ nsteps = strtol (optarg, 0, 0);
+ break;
+
+ case 't':
+ ntaps = strtol (optarg, 0, 0);
+ break;
+
+ case 'B':
+ global_B = strtod (optarg, 0);
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ default:
+ usage (argv[0]);
+ break;
+ }
+ }
+
+ if ((nsteps & 1) != 0){
+ fprintf (stderr, "%s: nsteps must be even\n", argv[0]);
+ exit (1);
+ }
+
+ if (nsteps > MAX_NSTEPS){
+ fprintf (stderr, "%s: nsteps must be < %d\n", argv[0], MAX_NSTEPS);
+ exit (1);
+ }
+
+ if ((ntaps & 1) != 0){
+ fprintf (stderr, "%s: ntaps must be even\n", argv[0]);
+ exit (1);
+ }
+
+ if (nsteps > MAX_NTAPS){
+ fprintf (stderr, "%s: ntaps must be < %d\n", argv[0], MAX_NTAPS);
+ exit (1);
+ }
+
+ if (global_B < 0 || global_B > 0.5){
+ fprintf (stderr, "%s: bandwidth must be in the range (0, 0.5)\n", argv[0]);
+ exit (1);
+ }
+
+ global_gsl_int_workspace = gsl_integration_workspace_alloc(4000);
+ if (global_gsl_int_workspace == NULL) {
+ fprintf (stderr, "%s: unable to allocate GSL integration work space\n",
+ argv[0]);
+ exit (1);
+ }
+
+ step_size = 1.0/nsteps;
+
+ // compute optimal values for mu <= 1.0
+
+ for (j = 0; j <= nsteps; j++){
+
+ global_mu = j * step_size; // this determines the MU for which we're computing the taps
+
+ // initialize X to a reasonable starting value
+
+ initpt (&xx[j][0], ntaps);
+
+ // find the value of X that minimizes the value of OBJECTIVE
+
+ result = prax2_ (objective, &xx[j][0], &ntaps, &xx[j][0]);
+
+ if (verbose){
+ fprintf (stderr, "Mu: %10.8f\t", global_mu);
+ fprintf (stderr, "Objective: %g\n", result);
+ }
+ }
+
+ gsl_integration_workspace_free(global_gsl_int_workspace);
+
+ // now print out the table
+
+ printf ("\
+/*\n\
+ * This file was machine generated by gen_interp_differentiator_taps.\n\
+ * DO NOT EDIT BY HAND.\n\
+ */\n\n");
+
+
+ printf ("static const int DNTAPS = %4d;\n", ntaps);
+ printf ("static const int DNSTEPS = %4d;\n", nsteps);
+ printf ("static const double DBANDWIDTH = %g;\n\n", global_B);
+
+ printf ("static const float Dtaps[DNSTEPS+1][DNTAPS] = {\n");
+ printf (" // -4 -3 -2 -1 0 1 2 3 mu\n");
+
+
+ for (i = 0; i <= nsteps; i++)
+ printline (xx[i], ntaps, i, nsteps);
+
+ printf ("};\n\n");
+
+ return 0;
+}
diff --git a/gr-filter/lib/gen_interpolator_taps/generate.sh b/gr-filter/lib/gen_interpolator_taps/generate.sh
new file mode 100755
index 0000000000..a7a6c6cafe
--- /dev/null
+++ b/gr-filter/lib/gen_interpolator_taps/generate.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# Copyright (C) 2017 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this file; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+gcc -c -o diff_objective_fct.o diff_objective_fct.c
+gfortran -c -o praxis.o praxis.f
+gcc -c -o gen_interp_differentiator_taps.o gen_interp_differentiator_taps.c
+
+gfortran -o gen_interp_differentiator_taps \
+ gen_interp_differentiator_taps.o praxis.o diff_objective_fct.o \
+ -lgsl -lgslcblas
+
+./gen_interp_differentiator_taps -n 128 -t 8 -B 0.25 \
+ > interp_differentiator_taps.h
+
+gcc -c -o simpson.o simpson.c
+gcc -c -o objective_fct.o objective_fct.c
+gcc -c -o gen_interpolator_taps.o gen_interpolator_taps.c
+
+gfortran -o gen_interpolator_taps \
+ gen_interpolator_taps.o praxis.o objective_fct.o simpson.o
+
+./gen_interpolator_taps -n 128 -t 8 -B 0.25 \
+ > interpolator_taps.h
+
diff --git a/gr-filter/lib/mmse_interp_differentiator_cc.cc b/gr-filter/lib/mmse_interp_differentiator_cc.cc
new file mode 100644
index 0000000000..2cdd390774
--- /dev/null
+++ b/gr-filter/lib/mmse_interp_differentiator_cc.cc
@@ -0,0 +1,78 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnuradio/filter/mmse_interp_differentiator_cc.h>
+#include "gnuradio/filter/interp_differentiator_taps.h"
+#include <stdexcept>
+
+namespace gr {
+ namespace filter {
+
+ mmse_interp_differentiator_cc::mmse_interp_differentiator_cc()
+ {
+ filters.resize (DNSTEPS + 1);
+
+ for(int i = 0; i < DNSTEPS + 1; i++) {
+ std::vector<float> t (&Dtaps[i][0], &Dtaps[i][DNTAPS]);
+ filters[i] = new kernel::fir_filter_ccf(1, t);
+ }
+ }
+
+ mmse_interp_differentiator_cc::~mmse_interp_differentiator_cc()
+ {
+ for(int i = 0; i < DNSTEPS + 1; i++)
+ delete filters[i];
+ }
+
+ unsigned
+ mmse_interp_differentiator_cc::ntaps() const
+ {
+ return DNTAPS;
+ }
+
+ unsigned
+ mmse_interp_differentiator_cc::nsteps() const
+ {
+ return DNSTEPS;
+ }
+
+ gr_complex
+ mmse_interp_differentiator_cc::differentiate(const gr_complex input[],
+ float mu) const
+ {
+ int imu = (int)rint(mu * DNSTEPS);
+
+ if((imu < 0) || (imu > DNSTEPS)) {
+ throw std::runtime_error(
+ "mmse_interp_differentiator_cc: imu out of bounds.\n");
+ }
+
+ gr_complex r = filters[imu]->filter(input);
+ return r;
+ }
+
+ } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/mmse_interp_differentiator_ff.cc b/gr-filter/lib/mmse_interp_differentiator_ff.cc
new file mode 100644
index 0000000000..247169fdba
--- /dev/null
+++ b/gr-filter/lib/mmse_interp_differentiator_ff.cc
@@ -0,0 +1,78 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnuradio/filter/mmse_interp_differentiator_ff.h>
+#include "gnuradio/filter/interp_differentiator_taps.h"
+#include <stdexcept>
+
+namespace gr {
+ namespace filter {
+
+ mmse_interp_differentiator_ff::mmse_interp_differentiator_ff()
+ {
+ filters.resize (DNSTEPS + 1);
+
+ for(int i = 0; i < DNSTEPS + 1; i++) {
+ std::vector<float> t (&Dtaps[i][0], &Dtaps[i][DNTAPS]);
+ filters[i] = new kernel::fir_filter_fff(1, t);
+ }
+ }
+
+ mmse_interp_differentiator_ff::~mmse_interp_differentiator_ff()
+ {
+ for(int i = 0; i < DNSTEPS + 1; i++)
+ delete filters[i];
+ }
+
+ unsigned
+ mmse_interp_differentiator_ff::ntaps() const
+ {
+ return DNTAPS;
+ }
+
+ unsigned
+ mmse_interp_differentiator_ff::nsteps() const
+ {
+ return DNSTEPS;
+ }
+
+ float
+ mmse_interp_differentiator_ff::differentiate(const float input[],
+ float mu) const
+ {
+ int imu = (int)rint(mu * DNSTEPS);
+
+ if((imu < 0) || (imu > DNSTEPS)) {
+ throw std::runtime_error(
+ "mmse_interp_differentiator_ff: imu out of bounds.\n");
+ }
+
+ float r = filters[imu]->filter(input);
+ return r;
+ }
+
+ } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/qa_filter.cc b/gr-filter/lib/qa_filter.cc
index b7760b19ea..e1cfefdbed 100644
--- a/gr-filter/lib/qa_filter.cc
+++ b/gr-filter/lib/qa_filter.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2012,2017 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -30,6 +30,8 @@
#include <qa_fir_filter_with_buffer.h>
#include <qa_mmse_fir_interpolator_cc.h>
#include <qa_mmse_fir_interpolator_ff.h>
+#include <qa_mmse_interp_differentiator_cc.h>
+#include <qa_mmse_interp_differentiator_ff.h>
CppUnit::TestSuite *
qa_gr_filter::suite ()
@@ -42,6 +44,8 @@ qa_gr_filter::suite ()
s->addTest(gr::filter::ccf::qa_fir_filter_with_buffer_ccf::suite());
s->addTest(gr::filter::qa_mmse_fir_interpolator_cc::suite());
s->addTest(gr::filter::qa_mmse_fir_interpolator_ff::suite());
+ s->addTest(gr::filter::qa_mmse_interp_differentiator_cc::suite());
+ s->addTest(gr::filter::qa_mmse_interp_differentiator_ff::suite());
return s;
}
diff --git a/gr-filter/lib/qa_mmse_interp_differentiator_cc.cc b/gr-filter/lib/qa_mmse_interp_differentiator_cc.cc
new file mode 100644
index 0000000000..55bb4e045b
--- /dev/null
+++ b/gr-filter/lib/qa_mmse_interp_differentiator_cc.cc
@@ -0,0 +1,130 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2007,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cppunit/TestAssert.h>
+#include <qa_mmse_interp_differentiator_cc.h>
+#include <gnuradio/filter/mmse_interp_differentiator_cc.h>
+#include <gnuradio/fft/fft.h>
+#include <volk/volk.h>
+#include <cstdio>
+#include <cmath>
+#include <stdexcept>
+#include <stdint.h>
+
+namespace gr {
+ namespace filter {
+
+ static const double k1 = 0.25 * 2 * M_PI;
+ static const double k2 = 0.125 * M_PI;
+ static const double k3 = 0.077 * 2 * M_PI;
+ static const double k4 = 0.3 * M_PI;
+
+ static double
+ phase_wrap(double arg)
+ {
+ while (arg >= 2.0*M_PI)
+ arg -= 2.0*M_PI;
+ while (arg <= 2.0*M_PI)
+ arg += 2.0*M_PI;
+ return arg;
+ }
+
+ static float
+ test_fcn_sin(double index)
+ {
+ double arg1 = phase_wrap(index * k1 + k2);
+ double arg2 = phase_wrap(index * k3 + k4);
+
+ return (2 * sin (arg1) + 3 * sin (arg2));
+ }
+
+ static float
+ test_fcn_cos(double index)
+ {
+ double arg1 = phase_wrap(index * k1 + k2);
+ double arg2 = phase_wrap(index * k3 + k4);
+
+ return (2 * cos (arg1) + 3 * cos (arg2));
+ }
+
+ static float
+ test_fcn_dsin(double index)
+ {
+ double arg1 = phase_wrap(index * k1 + k2);
+ double arg2 = phase_wrap(index * k3 + k4);
+
+ return (k1 * 2 * cos (arg1) + k3 * 3 * cos (arg2));
+ }
+
+ static float
+ test_fcn_dcos(double index)
+ {
+ double arg1 = phase_wrap(index * k1 + k2);
+ double arg2 = phase_wrap(index * k3 + k4);
+
+ return (-k1 * 2 * sin (arg1) - k3 * 3 * sin (arg2));
+ }
+
+ static gr_complex
+ test_fcn(double index)
+ {
+ return gr_complex(test_fcn_cos(index), test_fcn_sin(index));
+ }
+
+ static gr_complex
+ test_fcn_d(double index)
+ {
+ return gr_complex(test_fcn_dcos(index), test_fcn_dsin(index));
+ }
+
+ void
+ qa_mmse_interp_differentiator_cc::t1()
+ {
+ static const unsigned N = 100;
+ gr_complex *input = (gr_complex*)volk_malloc((N + 10)*sizeof(gr_complex),
+ volk_get_alignment());
+
+ for(unsigned i = 0; i < N+10; i++)
+ input[i] = test_fcn((double) i);
+
+ mmse_interp_differentiator_cc diffr;
+ float inv_nsteps = 1.0 / diffr.nsteps();
+
+ for(unsigned i = 0; i < N; i++) {
+ for(unsigned imu = 0; imu <= diffr.nsteps (); imu += 1) {
+ gr_complex expected = test_fcn_d((i + 3) + imu * inv_nsteps);
+ gr_complex actual = diffr.differentiate(&input[i], imu * inv_nsteps);
+
+ CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected, actual, 0.0103);
+ // printf ("%9.6f %9.6f %9.6f \n", expected.real(), actual.real(), expected.real() - actual.real());
+ // printf ("%9.6f %9.6f %9.6f \n", expected.imag(), actual.imag(), expected.imag() - actual.imag());
+ }
+ }
+ volk_free(input);
+ }
+
+ } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/qa_mmse_interp_differentiator_cc.h b/gr-filter/lib/qa_mmse_interp_differentiator_cc.h
new file mode 100644
index 0000000000..5074852933
--- /dev/null
+++ b/gr-filter/lib/qa_mmse_interp_differentiator_cc.h
@@ -0,0 +1,45 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2007,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _QA_MMSE_INTERP_DIFFERENTIATOR_CC_H_
+#define _QA_MMSE_INTERP_DIFFERENTIATOR_CC_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+namespace gr {
+ namespace filter {
+
+ class qa_mmse_interp_differentiator_cc : public CppUnit::TestCase
+ {
+ CPPUNIT_TEST_SUITE(qa_mmse_interp_differentiator_cc);
+ CPPUNIT_TEST(t1);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void t1();
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* _QA_MMSE_INTERP_DIFFERENTIATOR_CC_H_ */
diff --git a/gr-filter/lib/qa_mmse_interp_differentiator_ff.cc b/gr-filter/lib/qa_mmse_interp_differentiator_ff.cc
new file mode 100644
index 0000000000..6736d11baa
--- /dev/null
+++ b/gr-filter/lib/qa_mmse_interp_differentiator_ff.cc
@@ -0,0 +1,99 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2007,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cppunit/TestAssert.h>
+#include <qa_mmse_interp_differentiator_ff.h>
+#include <gnuradio/filter/mmse_interp_differentiator_ff.h>
+#include <gnuradio/fft/fft.h>
+#include <volk/volk.h>
+#include <cstdio>
+#include <cmath>
+#include <stdexcept>
+#include <stdint.h>
+
+namespace gr {
+ namespace filter {
+
+ static const double k1 = 0.25 * 2 * M_PI;
+ static const double k2 = 0.125 * M_PI;
+ static const double k3 = 0.077 * 2 * M_PI;
+ static const double k4 = 0.3 * M_PI;
+
+ static double
+ phase_wrap(double arg)
+ {
+ while (arg >= 2.0*M_PI)
+ arg -= 2.0*M_PI;
+ while (arg <= 2.0*M_PI)
+ arg += 2.0*M_PI;
+ return arg;
+ }
+
+ static float
+ test_fcn(double index)
+ {
+ double arg1 = phase_wrap(index * k1 + k2);
+ double arg2 = phase_wrap(index * k3 + k4);
+
+ return (2 * sin (arg1) + 3 * sin (arg2));
+ }
+
+ static float
+ test_fcn_d(double index)
+ {
+ double arg1 = phase_wrap(index * k1 + k2);
+ double arg2 = phase_wrap(index * k3 + k4);
+
+ return (k1 * 2 * cos (arg1) + k3 * 3 * cos (arg2));
+ }
+
+ void
+ qa_mmse_interp_differentiator_ff::t1()
+ {
+ static const unsigned N = 100;
+ float *input = (float*)volk_malloc((N + 10)*sizeof(float),
+ volk_get_alignment());
+
+ for(unsigned i = 0; i < N+10; i++)
+ input[i] = test_fcn((double) i);
+
+ mmse_interp_differentiator_ff diffr;
+ float inv_nsteps = 1.0 / diffr.nsteps();
+
+ for(unsigned i = 0; i < N; i++) {
+ for(unsigned imu = 0; imu <= diffr.nsteps (); imu += 1) {
+ float expected = test_fcn_d((i + 3) + imu * inv_nsteps);
+ float actual = diffr.differentiate(&input[i], imu * inv_nsteps);
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, 0.0103);
+ // printf ("%9.6f %9.6f %9.6f\n", expected, actual, expected - actual);
+ }
+ }
+ volk_free(input);
+ }
+
+ } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/qa_mmse_interp_differentiator_ff.h b/gr-filter/lib/qa_mmse_interp_differentiator_ff.h
new file mode 100644
index 0000000000..5f11c3955c
--- /dev/null
+++ b/gr-filter/lib/qa_mmse_interp_differentiator_ff.h
@@ -0,0 +1,45 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (C) 2002,2012,2017 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _QA_MMSE_INTERP_DIFFERENTIATOR_FF_H_
+#define _QA_MMSE_INTERP_DIFFERENTIATOR_FF_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+namespace gr {
+ namespace filter {
+
+ class qa_mmse_interp_differentiator_ff : public CppUnit::TestCase
+ {
+ CPPUNIT_TEST_SUITE(qa_mmse_interp_differentiator_ff);
+ CPPUNIT_TEST(t1);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void t1();
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* _QA_MMSE_INTERP_DIFFERENTIATOR_FF_H_ */
diff --git a/gr-qtgui/doc/qtgui.dox b/gr-qtgui/doc/qtgui.dox
index d0d7345f73..8cbbd7367a 100644
--- a/gr-qtgui/doc/qtgui.dox
+++ b/gr-qtgui/doc/qtgui.dox
@@ -50,13 +50,12 @@ with complex inputs. The time raster plots accept bits and floats.
Because the time raster plots are designed to show structure over time
in a signal, frame, packet, etc., they never drop samples. This is a
-
fairly taxing job and performance can be an issue. Since it is
expected that this block will work on a frame or packet structure, we
tend to be at the lowest possible rate at this point, so that will
help. Expect performance issues at high data rates.
-Note: There seem to be extra performance issue with the raster
+Note: There seem to be extra performance issues with the raster
plotters in QWT version 5 that were fixed with QWT version 6. As such,
the time raster plots have incredibly poor performance with QWT5 to
the point of almost being unusable. In the future, we may restrict
@@ -82,8 +81,8 @@ Each type of graph has a different set of menu items in the context
menu. Most have some way to change the appearance of the lines or
surfaces, such as changing the line width color, marker, and
transparency. Other common features can set the sampling rate, turn a
-grid on an off, pause and unpause (stop/start) the display update, and
-save the current figure. Specific feature are things like setting the
+grid on and off, pause and unpause (stop/start) the display update, and
+save the current figure. Specific features are things like setting the
number of points to display, setting the FFT size, FFT window, and any
FFT averaging.
@@ -96,9 +95,9 @@ specific stream tag such that whenever a tag of a given key is found,
the scope will trigger.
In the signal level mode, the trigger can be either 'auto' or 'normal'
-where the latter will only trigger when the even is seen. The 'auto'
+where the latter will only trigger when the event is seen. The 'auto'
mode will trigger on the event or every so often even if no trigger is
-found. The 'free' mode ignores ignores triggering and continuously
+found. The 'free' mode ignores triggering and continuously
plots.
By default, the triggers plot the triggering event at the x=0 (i.e.,
@@ -135,7 +134,7 @@ The QT GUI blocks require the following dependencies.
\section qtgui_usage Usage
-To use the qtgui interface, a bit of boiler-plate lines must be
+To use the QTGUI interface, a bit of boiler-plate lines must be
included. First, the sink is defined, then it must be exposed from C++
into Python using the "sip.wrapinstance" command, and finally, the
"show" method is run on the new Python object. This sets up the QT
@@ -205,9 +204,8 @@ type interface, GRC will hide certain parameters that are not usable
or settable anymore. For example, when plotting a message in the time
sink, the number of points shown in the time sink is determined by the
length of the vector in the message. Presetting this in the GUI would
-have no effect.
-
-The behavior in GRC is for convenience and to try and reduce confusion
+have no effect.
+This behavior in GRC is for convenience and to try and reduce confusion
about properties and settings in the message mode. However, all of the
API hooks are still there, so it is possible to set all of this
programmatically. The results would be harmless, however.
@@ -240,13 +238,13 @@ widgets. Most of the widgets are implemented directly in Python
through PyQT. However, GNU Radio is introducing more widgets, written
and therefore available in C++ that also produce messsages. The
Python-based widgets only act as variables and so as they are changed,
-any block using those widgets to set paramters has the callback (i.e.,
+any block using those widgets to set parameters has the callback (i.e.,
set_value()) function's called.
\subsection qtgui_widgets_python Python widgets:
\li Range: creates a slider and/or combo box to change to set/change
-the value of a parameter. This widget can set either float of int
+the value of a parameter. This widget can set either float or int
values.
\li Entry: An edit box that allows a user to directly set a
new value for the parameter.
@@ -266,7 +264,6 @@ span". Simply using "tab widget name@index" will put that widget into
the specific index (starting at 0) of the tab widget while adding the
"row, col, row span, col span" will allow the user to place them in
the tab grid.
-\li
\subsection qtgui_widgets_cpp C++ and Message-Passing Widgets
diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc
index bd56e992fd..2d347e3823 100644
--- a/gr-uhd/lib/usrp_sink_impl.cc
+++ b/gr-uhd/lib/usrp_sink_impl.cc
@@ -580,7 +580,8 @@ namespace gr {
usrp_sink_impl::start(void)
{
#ifdef GR_UHD_USE_STREAM_API
- _tx_stream = _dev->get_tx_stream(_stream_args);
+ if (not _tx_stream)
+ _tx_stream = _dev->get_tx_stream(_stream_args);
#endif
_metadata.start_of_burst = true;
diff --git a/grc/core/Param.py b/grc/core/Param.py
index afa478b3a2..00c9e7d827 100644
--- a/grc/core/Param.py
+++ b/grc/core/Param.py
@@ -135,6 +135,14 @@ class TemplateArg(object):
def __getitem__(self, item):
return str(self._param.get_opt(item)) if self._param.is_enum() else NotImplemented
+ def __getattr__(self, item):
+ if not self._param.is_enum():
+ raise AttributeError()
+ try:
+ return str(self._param.get_opt(item))
+ except KeyError:
+ raise AttributeError()
+
def __str__(self):
return str(self._param.to_code())
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index 5d48485238..017dab3346 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -626,9 +626,9 @@ class ActionHandler:
elif action == Actions.FLOW_GRAPH_KILL:
if page.get_proc():
try:
- page.get_proc().kill()
+ page.term_proc()
except:
- print "could not kill process: %d" % page.get_proc().pid
+ print "could not terminate process: %d" % page.get_proc().pid
elif action == Actions.PAGE_CHANGE: # pass and run the global actions
pass
elif action == Actions.RELOAD_BLOCKS:
diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py
index c9e8d0f186..79ad8bf207 100644
--- a/grc/gui/NotebookPage.py
+++ b/grc/gui/NotebookPage.py
@@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import pygtk
pygtk.require('2.0')
import gtk
+import gobject
import Actions
from StateCache import StateCache
from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT
@@ -152,6 +153,30 @@ class NotebookPage(gtk.HBox):
"""
self.process = process
+ def term_proc(self):
+ """
+ Terminate the subprocess object
+
+ Add a callback to kill the process
+ after 2 seconds if not already terminated
+ """
+ def kill(process):
+ """
+ Kill process if not already terminated
+
+ Called by gobject.timeout_add
+
+ Returns:
+ False to stop timeout_add periodic calls
+ """
+ is_terminated = process.poll()
+ if is_terminated is None:
+ process.kill()
+ return False
+
+ self.get_proc().terminate()
+ gobject.timeout_add(2000, kill, self.get_proc())
+
def get_flow_graph(self):
"""
Get the flow graph.