diff options
-rw-r--r-- | gr-digital/examples/demod/symbol_sync_test_complex.grc | 231 | ||||
-rw-r--r-- | gr-digital/examples/demod/symbol_sync_test_float.grc | 225 | ||||
-rw-r--r-- | gr-digital/grc/digital_symbol_sync_xx.xml | 11 | ||||
-rw-r--r-- | gr-digital/include/gnuradio/digital/symbol_sync_cc.h | 40 | ||||
-rw-r--r-- | gr-digital/include/gnuradio/digital/symbol_sync_ff.h | 40 | ||||
-rw-r--r-- | gr-digital/lib/clock_tracking_loop.cc | 36 | ||||
-rw-r--r-- | gr-digital/lib/clock_tracking_loop.h | 114 | ||||
-rw-r--r-- | gr-digital/lib/symbol_sync_cc_impl.cc | 6 | ||||
-rw-r--r-- | gr-digital/lib/symbol_sync_cc_impl.h | 3 | ||||
-rw-r--r-- | gr-digital/lib/symbol_sync_ff_impl.cc | 6 | ||||
-rw-r--r-- | gr-digital/lib/symbol_sync_ff_impl.h | 3 |
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 > 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 > 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 > 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 > 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); } |