summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Walls <awalls.cx18@gmail.com>2017-07-24 19:52:29 -0400
committerAndy Walls <awalls.cx18@gmail.com>2017-07-24 19:52:29 -0400
commitada34c9d6b31ae5e9e3097ce4b088c4ad8d4b0e2 (patch)
treebffbdd5feb868376b952a2136ffdb6a21640e931
parent3b3a403e8871bdb83f8cd9bdc904626de14a7cca (diff)
digital: Add expected TED gain for computing symbol sync loop gains
The computation of proportional (alpha) and intergal (beta) loop gains in the symbol synchronizer blocks neglected to account for the timing error detector gain. Add expected timing error detector gain as a user configurable parameter.
-rw-r--r--gr-digital/examples/demod/symbol_sync_test_complex.grc231
-rw-r--r--gr-digital/examples/demod/symbol_sync_test_float.grc225
-rw-r--r--gr-digital/grc/digital_symbol_sync_xx.xml11
-rw-r--r--gr-digital/include/gnuradio/digital/symbol_sync_cc.h40
-rw-r--r--gr-digital/include/gnuradio/digital/symbol_sync_ff.h40
-rw-r--r--gr-digital/lib/clock_tracking_loop.cc36
-rw-r--r--gr-digital/lib/clock_tracking_loop.h114
-rw-r--r--gr-digital/lib/symbol_sync_cc_impl.cc6
-rw-r--r--gr-digital/lib/symbol_sync_cc_impl.h3
-rw-r--r--gr-digital/lib/symbol_sync_ff_impl.cc6
-rw-r--r--gr-digital/lib/symbol_sync_ff_impl.h3
11 files changed, 517 insertions, 198 deletions
diff --git a/gr-digital/examples/demod/symbol_sync_test_complex.grc b/gr-digital/examples/demod/symbol_sync_test_complex.grc
index 1b7ac50f8d..cd0ca99e23 100644
--- a/gr-digital/examples/demod/symbol_sync_test_complex.grc
+++ b/gr-digital/examples/demod/symbol_sync_test_complex.grc
@@ -239,7 +239,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(2304, 572)</value>
+ <value>(2288, 588)</value>
</param>
<param>
<key>_rotation</key>
@@ -247,11 +247,11 @@
</param>
<param>
<key>id</key>
- <value>gain_mu</value>
+ <value>integral_gain</value>
</param>
<param>
<key>value</key>
- <value>2.0*math.exp(-zeta*omega_n_norm)*math.sinh(zeta*omega_n_norm)</value>
+ <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>
@@ -262,7 +262,7 @@
</param>
<param>
<key>value</key>
- <value>"%8.6f" % gain_mu</value>
+ <value>"%8.6f" % integral_gain</value>
</param>
<param>
<key>_enabled</key>
@@ -274,77 +274,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(2808, 572)</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>gain_mu_label</value>
- </param>
- <param>
- <key>label</key>
- <value>Gain Mu</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>(2304, 636)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- <param>
- <key>id</key>
- <value>gain_omega</value>
- </param>
- <param>
- <key>value</key>
- <value>2.0-gain_mu-2.0*math.exp(-zeta*omega_n_norm)*(math.cosh(omega_d_norm) if zeta &gt; 1.0 else math.cos(omega_d_norm))</value>
- </param>
- </block>
- <block>
- <key>variable_qtgui_label</key>
- <param>
- <key>comment</key>
- <value></value>
- </param>
- <param>
- <key>value</key>
- <value>"%8.6f" % gain_omega</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>formatter</key>
- <value>None</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(2640, 572)</value>
+ <value>(2760, 484)</value>
</param>
<param>
<key>gui_hint</key>
@@ -356,11 +286,11 @@
</param>
<param>
<key>id</key>
- <value>gain_omega_label</value>
+ <value>integral_gain_label</value>
</param>
<param>
<key>label</key>
- <value>Gain Omega</value>
+ <value>Integral Gain</value>
</param>
<param>
<key>type</key>
@@ -379,7 +309,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(2304, 508)</value>
+ <value>(2288, 460)</value>
</param>
<param>
<key>_rotation</key>
@@ -402,7 +332,7 @@
</param>
<param>
<key>value</key>
- <value>0.54</value>
+ <value>0.25</value>
</param>
<param>
<key>_enabled</key>
@@ -531,6 +461,76 @@
</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>
@@ -558,7 +558,70 @@
</param>
<param>
<key>value</key>
- <value>1.0/math.sqrt(2.0)*0+1.3</value>
+ <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>
@@ -837,7 +900,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(2752, 320)</value>
+ <value>(2752, 328)</value>
</param>
<param>
<key>_rotation</key>
@@ -1707,12 +1770,16 @@
<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, 296)</value>
+ <value>(2376, 292)</value>
</param>
<param>
<key>_rotation</key>
diff --git a/gr-digital/examples/demod/symbol_sync_test_float.grc b/gr-digital/examples/demod/symbol_sync_test_float.grc
index f81111b957..5507cbf848 100644
--- a/gr-digital/examples/demod/symbol_sync_test_float.grc
+++ b/gr-digital/examples/demod/symbol_sync_test_float.grc
@@ -239,76 +239,6 @@
</param>
<param>
<key>_coordinate</key>
- <value>(1800, 484)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- <param>
- <key>id</key>
- <value>gain_mu</value>
- </param>
- <param>
- <key>value</key>
- <value>2.0*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" % gain_mu</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>formatter</key>
- <value>None</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(2168, 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>gain_mu_label</value>
- </param>
- <param>
- <key>label</key>
- <value>Gain Mu</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, 548)</value>
</param>
<param>
@@ -317,11 +247,11 @@
</param>
<param>
<key>id</key>
- <value>gain_omega</value>
+ <value>integral_gain</value>
</param>
<param>
<key>value</key>
- <value>2.0-gain_mu-2.0*math.exp(-zeta*omega_n_norm)*(math.cosh(omega_d_norm) if zeta &gt; 1.0 else math.cos(omega_d_norm))</value>
+ <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>
@@ -332,7 +262,7 @@
</param>
<param>
<key>value</key>
- <value>"%8.6f" % gain_omega</value>
+ <value>"%8.6f" % integral_gain</value>
</param>
<param>
<key>_enabled</key>
@@ -344,7 +274,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(2168, 420)</value>
+ <value>(2296, 420)</value>
</param>
<param>
<key>gui_hint</key>
@@ -356,11 +286,11 @@
</param>
<param>
<key>id</key>
- <value>gain_omega_label</value>
+ <value>integral_gain_label</value>
</param>
<param>
<key>label</key>
- <value>Gain Omega</value>
+ <value>Integral Gain</value>
</param>
<param>
<key>type</key>
@@ -402,7 +332,7 @@
</param>
<param>
<key>value</key>
- <value>0.58</value>
+ <value>0.07</value>
</param>
<param>
<key>_enabled</key>
@@ -531,6 +461,76 @@
</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>
@@ -558,7 +558,70 @@
</param>
<param>
<key>value</key>
- <value>1.0/math.sqrt(2.0)*0+1.5</value>
+ <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>
@@ -1527,12 +1590,16 @@
<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, 280)</value>
+ <value>(1944, 276)</value>
</param>
<param>
<key>_rotation</key>
diff --git a/gr-digital/grc/digital_symbol_sync_xx.xml b/gr-digital/grc/digital_symbol_sync_xx.xml
index 1f597ef8ce..ffd2f5daff 100644
--- a/gr-digital/grc/digital_symbol_sync_xx.xml
+++ b/gr-digital/grc/digital_symbol_sync_xx.xml
@@ -26,10 +26,11 @@
<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, $max_dev, $osps, $constellation, $resamp_type, $nfilters, $pfb_mf_taps)</make>
+ <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>
@@ -112,6 +113,12 @@
<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>
@@ -120,7 +127,7 @@
<param>
<name>Damping Factor</name>
<key>damping</key>
- <value>1.0/math.sqrt(2.0)</value>
+ <value>1.0</value>
<type>real</type>
</param>
<param>
diff --git a/gr-digital/include/gnuradio/digital/symbol_sync_cc.h b/gr-digital/include/gnuradio/digital/symbol_sync_cc.h
index 5e51c3cdf1..dc856ecaf6 100644
--- a/gr-digital/include/gnuradio/digital/symbol_sync_cc.h
+++ b/gr-digital/include/gnuradio/digital/symbol_sync_cc.h
@@ -97,6 +97,15 @@ namespace gr {
* 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.
@@ -126,7 +135,8 @@ namespace gr {
static sptr make(enum ted_type detector_type,
float sps,
float loop_bw,
- float damping_factor = 2.0f,
+ float damping_factor = 1.0f,
+ float ted_gain = 1.0f,
float max_deviation = 1.5f,
int osps = 1,
constellation_sptr slicer = constellation_sptr(),
@@ -157,6 +167,15 @@ namespace gr {
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
@@ -224,6 +243,25 @@ namespace gr {
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
diff --git a/gr-digital/include/gnuradio/digital/symbol_sync_ff.h b/gr-digital/include/gnuradio/digital/symbol_sync_ff.h
index 2fdac08e2d..f551c0a96c 100644
--- a/gr-digital/include/gnuradio/digital/symbol_sync_ff.h
+++ b/gr-digital/include/gnuradio/digital/symbol_sync_ff.h
@@ -97,6 +97,15 @@ namespace gr {
* 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.
@@ -126,7 +135,8 @@ namespace gr {
static sptr make(enum ted_type detector_type,
float sps,
float loop_bw,
- float damping_factor = 2.0f,
+ float damping_factor = 1.0f,
+ float ted_gain = 1.0f,
float max_deviation = 1.5f,
int osps = 1,
constellation_sptr slicer = constellation_sptr(),
@@ -157,6 +167,15 @@ namespace gr {
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
@@ -224,6 +243,25 @@ namespace gr {
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
diff --git a/gr-digital/lib/clock_tracking_loop.cc b/gr-digital/lib/clock_tracking_loop.cc
index d74e4b2120..51a1db9e71 100644
--- a/gr-digital/lib/clock_tracking_loop.cc
+++ b/gr-digital/lib/clock_tracking_loop.cc
@@ -34,7 +34,8 @@ namespace gr {
clock_tracking_loop::clock_tracking_loop(float loop_bw,
float max_period, float min_period,
float nominal_period,
- float damping)
+ float damping,
+ float ted_gain)
: d_avg_period(nominal_period),
d_max_avg_period(max_period),
d_min_avg_period(min_period),
@@ -43,6 +44,7 @@ namespace gr {
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),
@@ -64,6 +66,10 @@ namespace gr {
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();
}
@@ -74,12 +80,15 @@ namespace gr {
void
clock_tracking_loop::update_gains()
{
- float omega_n_T, omega_d_T, zeta_omega_n_T, k1, cosx_omega_d_T;
+ 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;
- k1 = 2.0f * expf(-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)
@@ -100,8 +109,8 @@ namespace gr {
// cos ----------^^^
}
- alpha = k1 * sinhf(zeta_omega_n_T);
- beta = 2.0f - (alpha + k1 * cosx_omega_d_T);
+ 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);
@@ -180,6 +189,17 @@ namespace gr {
}
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;
@@ -256,6 +276,12 @@ namespace gr {
}
float
+ clock_tracking_loop::get_ted_gain() const
+ {
+ return d_ted_gain;
+ }
+
+ float
clock_tracking_loop::get_alpha() const
{
return d_alpha;
diff --git a/gr-digital/lib/clock_tracking_loop.h b/gr-digital/lib/clock_tracking_loop.h
index 84c77e197a..1a20713c48 100644
--- a/gr-digital/lib/clock_tracking_loop.h
+++ b/gr-digital/lib/clock_tracking_loop.h
@@ -35,9 +35,9 @@ namespace gr {
* 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 a normalized loop bandwidth and damping factor
- * as well as clock period bounds and provides the functions that
- * control the update of the loop.
+ * 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,
@@ -51,9 +51,9 @@ namespace gr {
* 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
- * 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.
+ * 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
@@ -70,20 +70,21 @@ namespace gr {
* 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 proportional gain
- * \f$\alpha\f$ and the integral gain \f$\beta\f$ as follows:
+ * 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)}
- * = (\alpha + \beta)z^{-1} \cdot
+ * = K_{ted}(\alpha + \beta)z^{-1} \cdot
* \dfrac{
* 1
* - \dfrac{\alpha}{\alpha + \beta} z^{-1}
* }
* {
* 1
- * - 2 \left(1 - \dfrac{\alpha + \beta}{2}\right) z^{-1}
- * + (1 - \alpha) z^{-2}
+ * - 2 \left(1 - K_{ted}\dfrac{\alpha + \beta}{2}\right) z^{-1}
+ * + (1 - K_{ted}\alpha) z^{-2}
* } \\
* \f}
*
@@ -140,23 +141,27 @@ namespace gr {
* \\
* \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$, and the clock period \f$T\f$ are:
+ * 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 &= 2e^{-\zeta\omega_{n}T} \sinh(\zeta\omega_{n}T) \\
+ * \alpha &= \dfrac{2}{K_{ted}}e^{-\zeta\omega_{n}T} \sinh(\zeta\omega_{n}T) \\
* \\
* \beta &=
* \begin{cases}
- * 2
- * -2e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + \cos(\omega_{d}T)] &
- * \text{for} \quad \zeta < 1 \quad (under \: damped)\\
- * 2
- * -2e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + 1] &
- * \text{for} \quad \zeta = 1 \quad (critically \: damped)\\
- * 2
- * -2e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) +\cosh(\omega_{d}T)] &
+ * \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} \\
* \\
@@ -179,6 +184,17 @@ namespace gr {
* \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:
@@ -263,6 +279,13 @@ namespace gr {
// 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;
@@ -315,16 +338,27 @@ namespace gr {
* 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 2.0, if not specified.
+ * 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 = 2.0f);
+ float damping = 1.0f,
+ float ted_gain = 1.0f);
virtual ~clock_tracking_loop();
- /*! \brief Update the gains from the loop bandwidth and damping factor.
+ /*! \brief Update the gains from the ted_gain, loop bw and damping factor.
*
* \details
* This function updates the gains based on the loop
@@ -445,6 +479,25 @@ namespace gr {
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
@@ -621,6 +674,15 @@ namespace gr {
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
diff --git a/gr-digital/lib/symbol_sync_cc_impl.cc b/gr-digital/lib/symbol_sync_cc_impl.cc
index 3df84be134..986a7e97de 100644
--- a/gr-digital/lib/symbol_sync_cc_impl.cc
+++ b/gr-digital/lib/symbol_sync_cc_impl.cc
@@ -38,6 +38,7 @@ namespace gr {
float sps,
float loop_bw,
float damping_factor,
+ float ted_gain,
float max_deviation,
int osps,
constellation_sptr slicer,
@@ -50,6 +51,7 @@ namespace gr {
sps,
loop_bw,
damping_factor,
+ ted_gain,
max_deviation,
osps,
slicer,
@@ -63,6 +65,7 @@ namespace gr {
float sps,
float loop_bw,
float damping_factor,
+ float ted_gain,
float max_deviation,
int osps,
constellation_sptr slicer,
@@ -146,7 +149,8 @@ namespace gr {
sps + max_deviation,
sps - max_deviation,
sps,
- damping_factor);
+ damping_factor,
+ ted_gain);
// Timing Error Detector
d_ted->sync_reset();
diff --git a/gr-digital/lib/symbol_sync_cc_impl.h b/gr-digital/lib/symbol_sync_cc_impl.h
index e0b85069d2..a146f7ed2e 100644
--- a/gr-digital/lib/symbol_sync_cc_impl.h
+++ b/gr-digital/lib/symbol_sync_cc_impl.h
@@ -38,6 +38,7 @@ namespace gr {
float sps,
float loop_bw,
float damping_factor,
+ float ted_gain,
float max_deviation,
int osps,
constellation_sptr slicer,
@@ -55,6 +56,7 @@ namespace gr {
// 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(); }
@@ -64,6 +66,7 @@ namespace gr {
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); }
diff --git a/gr-digital/lib/symbol_sync_ff_impl.cc b/gr-digital/lib/symbol_sync_ff_impl.cc
index 48509e4ba9..2497e52359 100644
--- a/gr-digital/lib/symbol_sync_ff_impl.cc
+++ b/gr-digital/lib/symbol_sync_ff_impl.cc
@@ -38,6 +38,7 @@ namespace gr {
float sps,
float loop_bw,
float damping_factor,
+ float ted_gain,
float max_deviation,
int osps,
constellation_sptr slicer,
@@ -50,6 +51,7 @@ namespace gr {
sps,
loop_bw,
damping_factor,
+ ted_gain,
max_deviation,
osps,
slicer,
@@ -63,6 +65,7 @@ namespace gr {
float sps,
float loop_bw,
float damping_factor,
+ float ted_gain,
float max_deviation,
int osps,
constellation_sptr slicer,
@@ -146,7 +149,8 @@ namespace gr {
sps + max_deviation,
sps - max_deviation,
sps,
- damping_factor);
+ damping_factor,
+ ted_gain);
// Timing Error Detector
d_ted->sync_reset();
diff --git a/gr-digital/lib/symbol_sync_ff_impl.h b/gr-digital/lib/symbol_sync_ff_impl.h
index f4bd6658b3..b0fea13929 100644
--- a/gr-digital/lib/symbol_sync_ff_impl.h
+++ b/gr-digital/lib/symbol_sync_ff_impl.h
@@ -38,6 +38,7 @@ namespace gr {
float sps,
float loop_bw,
float damping_factor,
+ float ted_gain,
float max_deviation,
int osps,
constellation_sptr slicer,
@@ -55,6 +56,7 @@ namespace gr {
// 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(); }
@@ -64,6 +66,7 @@ namespace gr {
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); }