summaryrefslogtreecommitdiff
path: root/gr-digital/lib/clock_tracking_loop.h
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital/lib/clock_tracking_loop.h')
-rw-r--r--gr-digital/lib/clock_tracking_loop.h719
1 files changed, 719 insertions, 0 deletions
diff --git a/gr-digital/lib/clock_tracking_loop.h b/gr-digital/lib/clock_tracking_loop.h
new file mode 100644
index 0000000000..84c77e197a
--- /dev/null
+++ b/gr-digital/lib/clock_tracking_loop.h
@@ -0,0 +1,719 @@
+/* -*- 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 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
+ * 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 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
+ * \dfrac{
+ * 1
+ * - \dfrac{\alpha}{\alpha + \beta} z^{-1}
+ * }
+ * {
+ * 1
+ * - 2 \left(1 - \dfrac{\alpha + \beta}{2}\right) z^{-1}
+ * + (1 - \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$, and the clock period \f$T\f$ are:
+ *
+ * \f{align*}
+ * \alpha &= 2e^{-\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)] &
+ * \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}
+ *
+ * * 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;
+
+ // 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 2.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);
+
+ virtual ~clock_tracking_loop();
+
+ /*! \brief Update the gains from the loop bandwidth 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 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 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 */