diff options
author | Marcus Müller <mmueller@gnuradio.org> | 2019-08-07 21:45:12 +0200 |
---|---|---|
committer | Marcus Müller <marcus@hostalia.de> | 2019-08-09 23:04:28 +0200 |
commit | f7bbf2c1d8d780294f3e016aff239ca35eb6516e (patch) | |
tree | e09ab6112e02b2215b2d59ac24d3d6ea2edac745 /gr-digital/lib/clock_tracking_loop.h | |
parent | 78431dc6941e3acc67c858277dfe4a0ed583643c (diff) |
Tree: clang-format without the include sorting
Diffstat (limited to 'gr-digital/lib/clock_tracking_loop.h')
-rw-r--r-- | gr-digital/lib/clock_tracking_loop.h | 1492 |
1 files changed, 746 insertions, 746 deletions
diff --git a/gr-digital/lib/clock_tracking_loop.h b/gr-digital/lib/clock_tracking_loop.h index 2b8aa0949c..3d5fa98871 100644 --- a/gr-digital/lib/clock_tracking_loop.h +++ b/gr-digital/lib/clock_tracking_loop.h @@ -24,758 +24,758 @@ #define INCLUDED_DIGITAL_CLOCK_TRACKING_LOOP_H namespace gr { - namespace digital { +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 intended to act as a parent class to blocks + * which need a symbol clock tracking loop to determine the optimal + * instant to sample a received symbol from an input sample + * stream (i.e. *_clock_recovery* and *_clock_sync* blocks). + * It takes in an expected timing error detector gain, a normalized loop + * bandwidth and damping factor, as well as clock period bounds, and + * provides the functions that control the update of the loop. + * + * This control loop runs at the rate of the output clock, so + * each step of the loop produces estimates about the output clock, + * and the clock phase/timing error input must come at a rate of + * once per output clock. + * + * This class does not include a timing error detector, and the + * caller is expected to provide the clock phase/timing error input + * for each step of the loop. + * + * The loop's low pass filter is a Proportional-Integral (PI) filter. + * The proportional and integral gains of the filter are termed alpha + * and beta respectively. These gains are calculated using the input + * expected timing error detector gain, loop bandwidth and damping factor. + * If needed, the alpha and beta gain values can be set using their + * respective #set_alpha or #set_beta functions. + * + * The class estimates the average clock period, T_avg; the instantaneous + * clock period, T_inst; and the instantaneous clock phase, tau; of a + * symbol clock based on an error signal from an external clock phase/ + * timing error detector which provides one error signal sample per + * clock (one error sample at the end of every T_inst clock cycle). + * The error calculation is unique for each TED algorithm and is + * calculated externally and passed to the advance_loop function, + * which uses this to update its estimates. + * + * This class also provides the functions #phase_wrap and + * #period_limit to easily keep the clock phase estimate, tau, and the + * average clock period estimate, T_avg, within set bounds (phase_wrap + * keeps the phase within +/-T_avg/2). + * + * The clock tracking loop, with its PI filter, when properly implemented, has + * a digital loop phase-transfer function, in terms of the timing error + * detector gain, \f$K_{ted}\f$; proportional gain, \f$\alpha\f$; and the + * integral gain, \f$\beta\f$, as follows: + * + * \f{align*} + * H(z) &= \dfrac {\Theta_o(z)}{\Theta_i(z)} + * = K_{ted}(\alpha + \beta)z^{-1} \cdot + * \dfrac{ + * 1 + * - \dfrac{\alpha}{\alpha + \beta} z^{-1} + * } + * { + * 1 + * - 2 \left(1 - K_{ted}\dfrac{\alpha + \beta}{2}\right) z^{-1} + * + (1 - K_{ted}\alpha) z^{-2} + * } \\ + * \f} + * + * Mapping the above phase-transfer function to the standard form of a transfer + * function for an analog second order control loop mapped to the digital domain + * with the mapping \f$z = e^{sT}\f$ applied to the s-plane poles, + * \f$s_{1,2} = -\zeta\omega_{n} \pm \omega_{n}\sqrt{\zeta^{2}-1}\f$, one obtains an + * alternate form of the transfer function, directly related to the damping factor + * \f$\zeta\f$, the natural radian frequency \f$\omega_{n}\f$, the damped radian frequency + * of oscillation \f$\omega_{d}\f$, and the symbol clock period \f$T\f$: + * + * \f{align*} + * H(z) &= + * \begin{cases} + * \dfrac{ + * [2 -2\cos(\omega_{d}T)e^{-\zeta\omega_{n}T}] z + * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T} + * } + * { + * z^{2} + * - 2 \cos(\omega_{d}T) e^{-\zeta\omega_{n}T} z + * + e^{-2\zeta\omega_{n}T} + * } + * & \quad \text{for} \quad \zeta < 1 \quad \text{with} + * \quad \omega_{d}T = \omega_{n}T \sqrt{1 - \zeta^{2}} + * \\ + * \\ + * \dfrac{ + * [2 -2(1)e^{-\zeta\omega_{n}T}] z + * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T} + * } + * { + * z^{2} + * - 2(1)e^{-\zeta\omega_{n}T} z + * + e^{-2\zeta\omega_{n}T} + * } + * & \quad \text{for} \quad \zeta = 1 \quad \text{with} + * \quad \omega_{d}T = 0 + * \\ + * \\ + * \dfrac{ + * [2 -2\cosh(\omega_{d}T)e^{-\zeta\omega_{n}T}] z + * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T} + * } + * { + * z^{2} + * - 2 \cosh(\omega_{d}T) e^{-\zeta\omega_{n}T} z + * + e^{-2\zeta\omega_{n}T} + * } + * & \quad \text{for} \quad \zeta > 1 \quad \text{with} + * \quad \omega_{d}T = \omega_{n}T \sqrt{\zeta^{2} - 1} + * \\ + * \end{cases} + * \\ + * \f} + * + * The PI filter gains, expressed in terms of the damping factor, \f$\zeta\f$; + * the natural radian frequency, \f$\omega_{n}\f$; the damped radian frequency of + * oscillation, \f$\omega_{d}\f$; the timing error detector gain \f$K_{ted}\f$; + * and the clock period \f$T\f$ are: + * + * \f{align*} + * \alpha &= \dfrac{2}{K_{ted}}e^{-\zeta\omega_{n}T} \sinh(\zeta\omega_{n}T) \\ + * \\ + * \beta &= + * \begin{cases} + * \dfrac{2}{K_{ted}} \left(1 - + * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + \cos(\omega_{d}T)] + * \right) & + * \text{for} \quad \zeta < 1 \quad (under \: damped)\\ \\ + * \dfrac{2}{K_{ted}} \left(1 - + * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + 1] + * \right) & + * \text{for} \quad \zeta = 1 \quad (critically \: damped)\\ \\ + * \dfrac{2}{K_{ted}} \left(1 - + * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) +\cosh(\omega_{d}T)] + * \right) & + * \text{for} \quad \zeta > 1 \quad (over \: damped)\\ + * \end{cases} \\ + * \\ + * \f} + * + * It should be noted that the clock period \f$T\f$ is being estimated by the clock + * tracking loop and can vary over time, so that setting the loop bandwidth + * directly can be a problem. However, we specify loop bandwidth in terms + * of the normalized digital natural radian frequency \f$\omega_{n\_norm}\f$ of the loop. + * \f$\omega_{n\_norm}\f$ can only usefully be a small positive number, close to + * zero. The damping factor, \f$\zeta\f$, dictates the maximum value + * \f$\omega_{n\_norm}\f$ can practically take on. In the extreme a case of + * \f$\zeta = 0.0\f$, \f$\omega_{n\_norm}\f$ is practically limited to the range + * \f$(0, \pi)\f$, as \f$\pi\f$ then corresponds to the Nyquist frequency + * of the clock. However, whatever the damping factor, large values of + * \f$\omega_{n\_norm}\f$ are usually not useful and yield poor results. + * + * \f{align*} + * \omega_{n}T = \omega_{n\_norm} = 2 \pi f_{n\_norm} = 2 \pi f_{n} T = + * \pi \dfrac{f_{n}}{\left(\dfrac{F_{c}}{2}\right)} + * \f} + * + * In practice, the timing error detector (TED) of the symbol clock + * tracking loop is implemented with an estimator of symbol clock phase + * error, which has some gain \f$K_{ted}\f$. The gain, \f$K_{ted}\f$, is + * defined as the slope of a TED's S-curve plot at a symbol clock phase + * offset of \f$\tau = 0\f$. The S-curve shape and central slope, and + * hence the gain \f$K_{ted}\f$, depend on the TED's estimator espression, + * the input signal level, the pulse shaping filter, and the \f$E_s/N_0\f$ + * of the incomping signal. The user must determine the TED's + * S-curve by analysis or simulation of the particular situation, in order + * to determine an appropriate value for \f$K_{ted}\f$. + * + * * A note on symbol clock phase vs. interpolating resampler sample phase, + * since most GNURadio symbol synchronization blocks seem to have the same + * implementation error: + * + * In general, the symbol clock phase, that the symbol clock tracking loop + * estimates and tracks, cannot be used alone to derive the interpolating resampler + * sample phase used in symbol synchronization, except in the very special case of + * the symbol clock period being exactly divisible by the input sample stream + * sample period. Since this is never guaranteed in tracking real symbol clocks, + * one should not use the symbol clock phase alone to compute the interpolating + * resampler sample phase. + * + * Consider, in the analog time domain, the optimum symbol sampling instants + * \f$t_{k}\f$, of an analog input signal \f$x(t)\f$, at an optimal symbol clock + * phase \f$\tau_{0}\f$ and the symbol clock period \f$T_{c}\f$: + * + * \f{align*} + * t_{k} &= \tau_{0} + k T_{c} \\ + * y_{k} &= x(t_{k}) = x(\tau_{0} + k T_{c}) \\ + * \f} + * + * If one divides the \f$t_{k}\f$ times by the input sample stream sample period + * \f$T_{i}\f$, the correct interpolating resampler sample phase \f$\tau_{0\_i}\f$ will + * get a contribution from the term \f$T_{c\_remainder}\f$ (which is an error) as shown + * below: + * + * \f{align*} + * \dfrac{t_{k}}{T_{i}} &= \dfrac{\tau_{0}}{T_{i}} + \dfrac{k T_{c}}{T_{i}} \\ + * &= (m + \tau_{0\_remainder}) + (n + T_{c\_remainder}) \\ + * &= \tau_{0\_remainder} + T_{c\_remainder} + (m + n) \\ + * &= \tau_{0\_i} + k^{\prime} + * \f} + * + * So instead of using the symbol clock sample phase alone to obtain the + * interpolating resampler sample phase, one should use the previous interpolating + * resampler sample phase and the instantaneous clock period estimate provided by + * the symbol clock tracking loop. + * + */ +class clock_tracking_loop +{ +protected: + // Estimate of the average clock period, T_avg, in units of + // input sample clocks (so this is the average number of + // input samples per output symbol, aka samples/symbol). + // To convert to seconds, divide by the input sample rate: F_s_input. + float d_avg_period; + + // Limits on how far the average clock period estimate can wander, + // and the nominal average clock period, in units of input sample clocks. + // To convert to seconds, divide by the input sample rate: F_s_input. + float d_max_avg_period, d_min_avg_period; + float d_nom_avg_period; + + // Instantaneous clock period estimate, T_inst, in units of + // input sample clocks (so this is the intantaneous number of + // input samples per output symbol, aka instantaneous samples/symbol). + // To convert to seconds, divide by the input sample rate: F_s_input. + float d_inst_period; + + // Instantaneous clock phase estimate, tau, in units of + // input sample clocks. + // To convert to seconds, divide by the input sample rate: F_s_input. + // To wrap, add or subtract a multiple of the estimate of the + // average clock period, T_avg. + // To convert to a normalized (but not wrapped) clock phase estimate, + // divide by the estimate of the average clock period, T_avg. + // To further convert the normalized clock phase estimate to radians, + // multiply the normalized clock phase estimate by 2*pi. + float d_phase; + + // Damping factor of the 2nd order loop transfer function. + // Zeta in the range (0.0, 1.0) yields an under-damped loop. + // Zeta in the range (1.0, Inf) yields an over-damped loop. + // Zeta equal to 1.0 yields a crtically-damped loop. + float d_zeta; + + // Normalized natural radian frequency of the 2nd order loop transfer + // function. It should be a small positive number, corresponding to + // the normalized natural radian frequency of the loop as digital + // low-pass filter that is filtering the clock phase/timing error signal. + // omega_n_norm = omega_n*T = 2*pi*f_n*T = 2*pi*f_n_norm + float d_omega_n_norm; + + // Expected gain of the timing error detector in use, given the + // TED estimator expression, the expected input amplitude, the + // input pulse shape, and the expected input Es/No. (This value is the + // slope of the TED's S-curve plot at a timing offset of tau = 0, and + // must be determined by analysis and/or simulation by the user.) + float d_ted_gain; + + // Proportional gain of the PI loop filter (aka gain_mu) + // (aka gain_mu in some clock recovery blocks) + float d_alpha; + + // Integral gain of the PI loop filter + // (aka gain_omega in some clock recovery blocks) + float d_beta; + + // For reverting the loop state one iteration (only) + float d_prev_avg_period; + float d_prev_inst_period; + float d_prev_phase; + +public: + clock_tracking_loop(void) {} + + /*! \brief Construct a clock_tracking_loop object. + * + * \details + * This function instantiates a clock_tracking_loop object. + * + * \param loop_bw + * Normalized approximate loop bandwidth. + * It should be a small positive number, corresponding to the normalized + * natural radian frequency of the loop as digital low-pass filter that is + * filtering the clock phase/timing error. + * + * Technically this parameter corresponds to the natural radian frequency + * of the 2nd order loop transfer function (scaled by Fs), + * which is the radius of the pole locations in the s-plane of an + * underdamped analog 2nd order system. + * + * \param max_period + * Maximum limit for the estimated clock period, in units of + * input stream sample periods. (i.e. maximum samples/symbol) + * + * \param min_period + * Minimum limit for the estimated clock period, in units of + * input stream sample periods. (i.e. minimum samples/symbol) + * + * \param nominal_period + * Nominal value for the estimated clock period, in units of + * input stream sample periods. (i.e. nominal samples/symbol) + * If not specified, this value will be set to the average of + * min_period and max_period, + * + * \param damping + * Damping factor of the 2nd order loop transfer function. + * Damping in the range (0.0, 1.0) yields an under-damped loop. + * Damping in the range (1.0, Inf) yields an over-damped loop. + * Damping equal to 1.0 yields a crtically-damped loop. + * Under-damped loops are not generally useful for clock tracking. + * This parameter defaults to 1.0, if not specified. + * + * \param ted_gain + * Expected gain of the timing error detector, given the TED in use + * and the anticipated input amplitude, pulse shape, and Es/No. + * This value is the slope of the TED's S-curve at timing offset tau = 0. + * This value is normally computed by the user analytically or by + * simulation in a tool outside of GNURadio. + * This value must be correct for the loop filter gains to be computed + * properly from the desired input loop bandwidth and damping factor. + * This parameter defaults to 1.0, if not specified. + */ + clock_tracking_loop(float loop_bw, + float max_period, + float min_period, + float nominal_period = 0.0f, + float damping = 1.0f, + float ted_gain = 1.0f); + + virtual ~clock_tracking_loop(); + + /*! \brief Update the gains from the ted_gain, loop bw and damping factor. + * + * \details + * This function updates the gains based on the loop + * bandwidth and damping factor of the system. These two + * factors can be set separately through their own set + * functions. + */ + void update_gains(); + + /*! \brief Advance the loop based on the current gain + * settings and the input error signal. + */ + void advance_loop(float error); + + /*! \brief Undo a single, prior advance_loop() call. + * + * \details + * Reverts a single, prior call to advance_loop(). + * It cannot usefully called again, until after the next call + * to advance_loop(). + * + * This method is needed so clock recovery/sync blocks can + * perform correctly given the constraints of GNURadio's streaming + * engine, interpolation filtering, and tag propagation. + */ + void revert_loop(); + + /*! \brief + * Keep the clock phase estimate, tau, between -T_avg/2 and T_avg/2. + * + * \details + * This function keeps the clock phase estimate, tau, between + * -T_avg/2 and T_avg/2, by wrapping it modulo the estimated + * average clock period, T_avg. (N.B. Wrapping an estimated phase + * by an *estimated*, *average* period.) + * + * This function can be called after advance_loop to keep the + * phase value small. It is set as a separate method in case + * another way is desired as this is fairly heavy-handed. + * Clock recovery/sync blocks usually do not need the phase of the + * clock, and this class doesn't actually use the phase at all, + * so calling this is optional. + */ + void phase_wrap(); + + /*! \brief + * Keep the estimated average clock period, T_avg, between T_avg_min + * and T_avg_max. + * + * \details + * This function keeps the estimated average clock period, T_avg, + * between T_avg_min and T_avg_max. It accomplishes this by hard limiting. + * This is needed because T_avg is essentially computed by the + * integrator portion of an IIR filter, so T_avg could potentially + * wander very far during periods of noise/nonsense input. + * + * This function is called in advance_loop to keep the + * estimated average clock period, T_avg, in the specified range. + * It is set as a separate virtual method in case another way is desired + * as this is fairly heavy-handed. + */ + virtual 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 A second-order control loop implementation class. + * \brief Set the expected gain of the Timing Error Detector. * * \details - * This class implements most of a second order symbol clock - * tracking loop and is intended to act as a parent class to blocks - * which need a symbol clock tracking loop to determine the optimal - * instant to sample a received symbol from an input sample - * stream (i.e. *_clock_recovery* and *_clock_sync* blocks). - * It takes in an expected timing error detector gain, a normalized loop - * bandwidth and damping factor, as well as clock period bounds, and - * provides the functions that control the update of the loop. - * - * This control loop runs at the rate of the output clock, so - * each step of the loop produces estimates about the output clock, - * and the clock phase/timing error input must come at a rate of - * once per output clock. - * - * This class does not include a timing error detector, and the - * caller is expected to provide the clock phase/timing error input - * for each step of the loop. - * - * The loop's low pass filter is a Proportional-Integral (PI) filter. - * The proportional and integral gains of the filter are termed alpha - * and beta respectively. These gains are calculated using the input - * expected timing error detector gain, loop bandwidth and damping factor. - * If needed, the alpha and beta gain values can be set using their - * respective #set_alpha or #set_beta functions. - * - * The class estimates the average clock period, T_avg; the instantaneous - * clock period, T_inst; and the instantaneous clock phase, tau; of a - * symbol clock based on an error signal from an external clock phase/ - * timing error detector which provides one error signal sample per - * clock (one error sample at the end of every T_inst clock cycle). - * The error calculation is unique for each TED algorithm and is - * calculated externally and passed to the advance_loop function, - * which uses this to update its estimates. - * - * This class also provides the functions #phase_wrap and - * #period_limit to easily keep the clock phase estimate, tau, and the - * average clock period estimate, T_avg, within set bounds (phase_wrap - * keeps the phase within +/-T_avg/2). - * - * The clock tracking loop, with its PI filter, when properly implemented, has - * a digital loop phase-transfer function, in terms of the timing error - * detector gain, \f$K_{ted}\f$; proportional gain, \f$\alpha\f$; and the - * integral gain, \f$\beta\f$, as follows: - * - * \f{align*} - * H(z) &= \dfrac {\Theta_o(z)}{\Theta_i(z)} - * = K_{ted}(\alpha + \beta)z^{-1} \cdot - * \dfrac{ - * 1 - * - \dfrac{\alpha}{\alpha + \beta} z^{-1} - * } - * { - * 1 - * - 2 \left(1 - K_{ted}\dfrac{\alpha + \beta}{2}\right) z^{-1} - * + (1 - K_{ted}\alpha) z^{-2} - * } \\ - * \f} - * - * Mapping the above phase-transfer function to the standard form of a transfer - * function for an analog second order control loop mapped to the digital domain - * with the mapping \f$z = e^{sT}\f$ applied to the s-plane poles, - * \f$s_{1,2} = -\zeta\omega_{n} \pm \omega_{n}\sqrt{\zeta^{2}-1}\f$, one obtains an - * alternate form of the transfer function, directly related to the damping factor - * \f$\zeta\f$, the natural radian frequency \f$\omega_{n}\f$, the damped radian frequency - * of oscillation \f$\omega_{d}\f$, and the symbol clock period \f$T\f$: - * - * \f{align*} - * H(z) &= - * \begin{cases} - * \dfrac{ - * [2 -2\cos(\omega_{d}T)e^{-\zeta\omega_{n}T}] z - * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T} - * } - * { - * z^{2} - * - 2 \cos(\omega_{d}T) e^{-\zeta\omega_{n}T} z - * + e^{-2\zeta\omega_{n}T} - * } - * & \quad \text{for} \quad \zeta < 1 \quad \text{with} - * \quad \omega_{d}T = \omega_{n}T \sqrt{1 - \zeta^{2}} - * \\ - * \\ - * \dfrac{ - * [2 -2(1)e^{-\zeta\omega_{n}T}] z - * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T} - * } - * { - * z^{2} - * - 2(1)e^{-\zeta\omega_{n}T} z - * + e^{-2\zeta\omega_{n}T} - * } - * & \quad \text{for} \quad \zeta = 1 \quad \text{with} - * \quad \omega_{d}T = 0 - * \\ - * \\ - * \dfrac{ - * [2 -2\cosh(\omega_{d}T)e^{-\zeta\omega_{n}T}] z - * -2\sinh(\zeta\omega_{n}T)e^{-\zeta\omega_{n}T} - * } - * { - * z^{2} - * - 2 \cosh(\omega_{d}T) e^{-\zeta\omega_{n}T} z - * + e^{-2\zeta\omega_{n}T} - * } - * & \quad \text{for} \quad \zeta > 1 \quad \text{with} - * \quad \omega_{d}T = \omega_{n}T \sqrt{\zeta^{2} - 1} - * \\ - * \end{cases} - * \\ - * \f} - * - * The PI filter gains, expressed in terms of the damping factor, \f$\zeta\f$; - * the natural radian frequency, \f$\omega_{n}\f$; the damped radian frequency of - * oscillation, \f$\omega_{d}\f$; the timing error detector gain \f$K_{ted}\f$; - * and the clock period \f$T\f$ are: - * - * \f{align*} - * \alpha &= \dfrac{2}{K_{ted}}e^{-\zeta\omega_{n}T} \sinh(\zeta\omega_{n}T) \\ - * \\ - * \beta &= - * \begin{cases} - * \dfrac{2}{K_{ted}} \left(1 - - * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + \cos(\omega_{d}T)] - * \right) & - * \text{for} \quad \zeta < 1 \quad (under \: damped)\\ \\ - * \dfrac{2}{K_{ted}} \left(1 - - * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) + 1] - * \right) & - * \text{for} \quad \zeta = 1 \quad (critically \: damped)\\ \\ - * \dfrac{2}{K_{ted}} \left(1 - - * e^{-\zeta\omega_{n}T} [\sinh(\zeta\omega_{n}T) +\cosh(\omega_{d}T)] - * \right) & - * \text{for} \quad \zeta > 1 \quad (over \: damped)\\ - * \end{cases} \\ - * \\ - * \f} - * - * It should be noted that the clock period \f$T\f$ is being estimated by the clock - * tracking loop and can vary over time, so that setting the loop bandwidth - * directly can be a problem. However, we specify loop bandwidth in terms - * of the normalized digital natural radian frequency \f$\omega_{n\_norm}\f$ of the loop. - * \f$\omega_{n\_norm}\f$ can only usefully be a small positive number, close to - * zero. The damping factor, \f$\zeta\f$, dictates the maximum value - * \f$\omega_{n\_norm}\f$ can practically take on. In the extreme a case of - * \f$\zeta = 0.0\f$, \f$\omega_{n\_norm}\f$ is practically limited to the range - * \f$(0, \pi)\f$, as \f$\pi\f$ then corresponds to the Nyquist frequency - * of the clock. However, whatever the damping factor, large values of - * \f$\omega_{n\_norm}\f$ are usually not useful and yield poor results. - * - * \f{align*} - * \omega_{n}T = \omega_{n\_norm} = 2 \pi f_{n\_norm} = 2 \pi f_{n} T = - * \pi \dfrac{f_{n}}{\left(\dfrac{F_{c}}{2}\right)} - * \f} - * - * In practice, the timing error detector (TED) of the symbol clock - * tracking loop is implemented with an estimator of symbol clock phase - * error, which has some gain \f$K_{ted}\f$. The gain, \f$K_{ted}\f$, is - * defined as the slope of a TED's S-curve plot at a symbol clock phase - * offset of \f$\tau = 0\f$. The S-curve shape and central slope, and - * hence the gain \f$K_{ted}\f$, depend on the TED's estimator espression, - * the input signal level, the pulse shaping filter, and the \f$E_s/N_0\f$ - * of the incomping signal. The user must determine the TED's - * S-curve by analysis or simulation of the particular situation, in order - * to determine an appropriate value for \f$K_{ted}\f$. - * - * * A note on symbol clock phase vs. interpolating resampler sample phase, - * since most GNURadio symbol synchronization blocks seem to have the same - * implementation error: - * - * In general, the symbol clock phase, that the symbol clock tracking loop - * estimates and tracks, cannot be used alone to derive the interpolating resampler - * sample phase used in symbol synchronization, except in the very special case of - * the symbol clock period being exactly divisible by the input sample stream - * sample period. Since this is never guaranteed in tracking real symbol clocks, - * one should not use the symbol clock phase alone to compute the interpolating - * resampler sample phase. - * - * Consider, in the analog time domain, the optimum symbol sampling instants - * \f$t_{k}\f$, of an analog input signal \f$x(t)\f$, at an optimal symbol clock - * phase \f$\tau_{0}\f$ and the symbol clock period \f$T_{c}\f$: - * - * \f{align*} - * t_{k} &= \tau_{0} + k T_{c} \\ - * y_{k} &= x(t_{k}) = x(\tau_{0} + k T_{c}) \\ - * \f} - * - * If one divides the \f$t_{k}\f$ times by the input sample stream sample period - * \f$T_{i}\f$, the correct interpolating resampler sample phase \f$\tau_{0\_i}\f$ will - * get a contribution from the term \f$T_{c\_remainder}\f$ (which is an error) as shown - * below: - * - * \f{align*} - * \dfrac{t_{k}}{T_{i}} &= \dfrac{\tau_{0}}{T_{i}} + \dfrac{k T_{c}}{T_{i}} \\ - * &= (m + \tau_{0\_remainder}) + (n + T_{c\_remainder}) \\ - * &= \tau_{0\_remainder} + T_{c\_remainder} + (m + n) \\ - * &= \tau_{0\_i} + k^{\prime} - * \f} - * - * So instead of using the symbol clock sample phase alone to obtain the - * interpolating resampler sample phase, one should use the previous interpolating - * resampler sample phase and the instantaneous clock period estimate provided by - * the symbol clock tracking loop. + * Sets the expected gain of the timing error detector, given the TED in + * use and the anticipated input amplitude, pulse shape, and Es/No. + * This value is the slope of the TED's S-curve at timing offset tau = 0. + * This value is normally computed by the user analytically or by + * simulation in a tool outside of GNURadio. + * This value must be correct for the loop filter gains to be computed + * properly from the desired input loop bandwidth and damping factor. + * + * When a new ted_gain is set, the gains, alpha and beta, + * of the loop are automatcally recalculated. + * + * \param ted_gain expected gain of the timing error detector + */ + void set_ted_gain(float ted_gain); + + /*! + * \brief Set the PI filter proportional gain, alpha. + * + * \details + * Sets the PI filter proportional gain, alpha. + * This gain directly mutliplies the clock phase/timing error + * term in the PI filter when advancing the loop. + * It most directly affects the instantaneous clock period estimate, + * T_inst, and instantaneous clock phase estimate, tau. + * + * This value would normally be adjusted by setting the loop + * bandwidth and damping factor and calling update_gains(). However, + * it can be set here directly if desired. + * + * Setting this parameter directly is probably only feasible if + * the user is directly observing the estimates of average clock + * period and instantaneous clock period over time in response to + * an impulsive change in the input stream (i.e. watching the loop + * transient behavior at the start of a data burst). + * + * \param alpha PI filter proportional gain + */ + void set_alpha(float alpha); + + /*! + * \brief Set the PI filter integral gain, beta. + * + * \details + * Sets the PI filter integral gain, beta. + * This gain is used when integrating the clock phase/timing error + * term in the PI filter when advancing the loop. + * It most directly affects the average clock period estimate, + * T_avg. + * + * This value would normally be adjusted by setting the loop + * bandwidth and damping factor and calling update_gains(). However, + * it can be set here directly if desired. + * + * Setting this parameter directly is probably only feasible if + * the user is directly observing the estimates of average clock + * period and instantaneous clock period over time in response to + * an impulsive change in the input stream (i.e. watching the loop + * transient behavior at the start of a data burst). + * + * \param beta PI filter integral gain + */ + void set_beta(float beta); + + /*! + * \brief Set the average clock period estimate, T_avg. + * + * \details + * Directly sets the average clock period estimate, T_avg, + * in units of input stream sample clocks (so the average number of + * input samples per output symbol, aka samples/symbol). + * + * The average clock period estimate, T_avg, is normally updated by + * the advance_loop() and period_limit() calls. This method is used + * manually reset the estimate when needed. * + * \param period + * Average clock period, T_avg, in units of input stream sample clocks. */ - class clock_tracking_loop - { - protected: - // Estimate of the average clock period, T_avg, in units of - // input sample clocks (so this is the average number of - // input samples per output symbol, aka samples/symbol). - // To convert to seconds, divide by the input sample rate: F_s_input. - float d_avg_period; - - // Limits on how far the average clock period estimate can wander, - // and the nominal average clock period, in units of input sample clocks. - // To convert to seconds, divide by the input sample rate: F_s_input. - float d_max_avg_period, d_min_avg_period; - float d_nom_avg_period; - - // Instantaneous clock period estimate, T_inst, in units of - // input sample clocks (so this is the intantaneous number of - // input samples per output symbol, aka instantaneous samples/symbol). - // To convert to seconds, divide by the input sample rate: F_s_input. - float d_inst_period; - - // Instantaneous clock phase estimate, tau, in units of - // input sample clocks. - // To convert to seconds, divide by the input sample rate: F_s_input. - // To wrap, add or subtract a multiple of the estimate of the - // average clock period, T_avg. - // To convert to a normalized (but not wrapped) clock phase estimate, - // divide by the estimate of the average clock period, T_avg. - // To further convert the normalized clock phase estimate to radians, - // multiply the normalized clock phase estimate by 2*pi. - float d_phase; - - // Damping factor of the 2nd order loop transfer function. - // Zeta in the range (0.0, 1.0) yields an under-damped loop. - // Zeta in the range (1.0, Inf) yields an over-damped loop. - // Zeta equal to 1.0 yields a crtically-damped loop. - float d_zeta; - - // Normalized natural radian frequency of the 2nd order loop transfer - // function. It should be a small positive number, corresponding to - // the normalized natural radian frequency of the loop as digital - // low-pass filter that is filtering the clock phase/timing error signal. - // omega_n_norm = omega_n*T = 2*pi*f_n*T = 2*pi*f_n_norm - float d_omega_n_norm; - - // Expected gain of the timing error detector in use, given the - // TED estimator expression, the expected input amplitude, the - // input pulse shape, and the expected input Es/No. (This value is the - // slope of the TED's S-curve plot at a timing offset of tau = 0, and - // must be determined by analysis and/or simulation by the user.) - float d_ted_gain; - - // Proportional gain of the PI loop filter (aka gain_mu) - // (aka gain_mu in some clock recovery blocks) - float d_alpha; - - // Integral gain of the PI loop filter - // (aka gain_omega in some clock recovery blocks) - float d_beta; - - // For reverting the loop state one iteration (only) - float d_prev_avg_period; - float d_prev_inst_period; - float d_prev_phase; - - public: - clock_tracking_loop(void) {} - - /*! \brief Construct a clock_tracking_loop object. - * - * \details - * This function instantiates a clock_tracking_loop object. - * - * \param loop_bw - * Normalized approximate loop bandwidth. - * It should be a small positive number, corresponding to the normalized - * natural radian frequency of the loop as digital low-pass filter that is - * filtering the clock phase/timing error. - * - * Technically this parameter corresponds to the natural radian frequency - * of the 2nd order loop transfer function (scaled by Fs), - * which is the radius of the pole locations in the s-plane of an - * underdamped analog 2nd order system. - * - * \param max_period - * Maximum limit for the estimated clock period, in units of - * input stream sample periods. (i.e. maximum samples/symbol) - * - * \param min_period - * Minimum limit for the estimated clock period, in units of - * input stream sample periods. (i.e. minimum samples/symbol) - * - * \param nominal_period - * Nominal value for the estimated clock period, in units of - * input stream sample periods. (i.e. nominal samples/symbol) - * If not specified, this value will be set to the average of - * min_period and max_period, - * - * \param damping - * Damping factor of the 2nd order loop transfer function. - * Damping in the range (0.0, 1.0) yields an under-damped loop. - * Damping in the range (1.0, Inf) yields an over-damped loop. - * Damping equal to 1.0 yields a crtically-damped loop. - * Under-damped loops are not generally useful for clock tracking. - * This parameter defaults to 1.0, if not specified. - * - * \param ted_gain - * Expected gain of the timing error detector, given the TED in use - * and the anticipated input amplitude, pulse shape, and Es/No. - * This value is the slope of the TED's S-curve at timing offset tau = 0. - * This value is normally computed by the user analytically or by - * simulation in a tool outside of GNURadio. - * This value must be correct for the loop filter gains to be computed - * properly from the desired input loop bandwidth and damping factor. - * This parameter defaults to 1.0, if not specified. - */ - clock_tracking_loop(float loop_bw, - float max_period, float min_period, - float nominal_period = 0.0f, - float damping = 1.0f, - float ted_gain = 1.0f); - - virtual ~clock_tracking_loop(); - - /*! \brief Update the gains from the ted_gain, loop bw and damping factor. - * - * \details - * This function updates the gains based on the loop - * bandwidth and damping factor of the system. These two - * factors can be set separately through their own set - * functions. - */ - void update_gains(); - - /*! \brief Advance the loop based on the current gain - * settings and the input error signal. - */ - void advance_loop(float error); - - /*! \brief Undo a single, prior advance_loop() call. - * - * \details - * Reverts a single, prior call to advance_loop(). - * It cannot usefully called again, until after the next call - * to advance_loop(). - * - * This method is needed so clock recovery/sync blocks can - * perform correctly given the constraints of GNURadio's streaming - * engine, interpolation filtering, and tag propagation. - */ - void revert_loop(); - - /*! \brief - * Keep the clock phase estimate, tau, between -T_avg/2 and T_avg/2. - * - * \details - * This function keeps the clock phase estimate, tau, between - * -T_avg/2 and T_avg/2, by wrapping it modulo the estimated - * average clock period, T_avg. (N.B. Wrapping an estimated phase - * by an *estimated*, *average* period.) - * - * This function can be called after advance_loop to keep the - * phase value small. It is set as a separate method in case - * another way is desired as this is fairly heavy-handed. - * Clock recovery/sync blocks usually do not need the phase of the - * clock, and this class doesn't actually use the phase at all, - * so calling this is optional. - */ - void phase_wrap(); - - /*! \brief - * Keep the estimated average clock period, T_avg, between T_avg_min - * and T_avg_max. - * - * \details - * This function keeps the estimated average clock period, T_avg, - * between T_avg_min and T_avg_max. It accomplishes this by hard limiting. - * This is needed because T_avg is essentially computed by the - * integrator portion of an IIR filter, so T_avg could potentially - * wander very far during periods of noise/nonsense input. - * - * This function is called in advance_loop to keep the - * estimated average clock period, T_avg, in the specified range. - * It is set as a separate virtual method in case another way is desired - * as this is fairly heavy-handed. - */ - virtual void period_limit(); - - /******************************************************************* - * SET FUNCTIONS - *******************************************************************/ - - /*! - * \brief Set the normalized approximate loop bandwidth. - * - * \details - * Set the normalized approximate loop bandwidth. - * Useful values are usually close to 0.0, e.g. 2*pi*0.045. - * - * It should be a small positive number, corresponding to the normalized - * natural radian frequency of the loop as digital low-pass filter that is - * filtering the clock phase/timing error. - * - * Technically this parameter corresponds to the natural radian frequency - * of the 2nd order loop transfer function (scaled by Fs), - * which is the radius of the pole locations in the s-plane of an - * underdamped analog 2nd order system. - * - * The input parameter corresponds to omega_n_norm in the following - * relation: - * - * omega_n_norm = omega_n*T = 2*pi*f_n*T = 2*pi*f_n_norm - * - * where T is the period of the clock being estimated by this - * clock tracking loop, and omega_n is the natural radian frequency - * of the 2nd order loop transfer function. - * - * When a new loop bandwidth is set, the gains, alpha and beta, - * of the loop are recalculated by a call to update_gains(). - * - * \param bw normalized approximate loop bandwidth - */ - virtual void set_loop_bandwidth(float bw); - - /*! - * \brief Set the loop damping factor. - * - * \details - * Set the damping factor of the loop. - * Damping in the range (0.0, 1.0) yields an under-damped loop. - * Damping in the range (1.0, Inf) yields an over-damped loop. - * Damping equal to 1.0 yields a crtically-damped loop. - * Under-damped loops are not generally useful for clock tracking. - * For clock tracking, as a first guess, set the damping factor to 2.0, - * or 1.5 or 1.0. - * - * Damping factor of the 2nd order loop transfer function. - * When a new damping factor is set, the gains, alpha and beta, - * of the loop are recalculated by a call to update_gains(). - * - * \param df loop damping factor - */ - void set_damping_factor(float df); - - /*! - * \brief Set the expected gain of the Timing Error Detector. - * - * \details - * Sets the expected gain of the timing error detector, given the TED in - * use and the anticipated input amplitude, pulse shape, and Es/No. - * This value is the slope of the TED's S-curve at timing offset tau = 0. - * This value is normally computed by the user analytically or by - * simulation in a tool outside of GNURadio. - * This value must be correct for the loop filter gains to be computed - * properly from the desired input loop bandwidth and damping factor. - * - * When a new ted_gain is set, the gains, alpha and beta, - * of the loop are automatcally recalculated. - * - * \param ted_gain expected gain of the timing error detector - */ - void set_ted_gain (float ted_gain); - - /*! - * \brief Set the PI filter proportional gain, alpha. - * - * \details - * Sets the PI filter proportional gain, alpha. - * This gain directly mutliplies the clock phase/timing error - * term in the PI filter when advancing the loop. - * It most directly affects the instantaneous clock period estimate, - * T_inst, and instantaneous clock phase estimate, tau. - * - * This value would normally be adjusted by setting the loop - * bandwidth and damping factor and calling update_gains(). However, - * it can be set here directly if desired. - * - * Setting this parameter directly is probably only feasible if - * the user is directly observing the estimates of average clock - * period and instantaneous clock period over time in response to - * an impulsive change in the input stream (i.e. watching the loop - * transient behavior at the start of a data burst). - * - * \param alpha PI filter proportional gain - */ - void set_alpha(float alpha); - - /*! - * \brief Set the PI filter integral gain, beta. - * - * \details - * Sets the PI filter integral gain, beta. - * This gain is used when integrating the clock phase/timing error - * term in the PI filter when advancing the loop. - * It most directly affects the average clock period estimate, - * T_avg. - * - * This value would normally be adjusted by setting the loop - * bandwidth and damping factor and calling update_gains(). However, - * it can be set here directly if desired. - * - * Setting this parameter directly is probably only feasible if - * the user is directly observing the estimates of average clock - * period and instantaneous clock period over time in response to - * an impulsive change in the input stream (i.e. watching the loop - * transient behavior at the start of a data burst). - * - * \param beta PI filter integral gain - */ - void set_beta(float beta); - - /*! - * \brief Set the average clock period estimate, T_avg. - * - * \details - * Directly sets the average clock period estimate, T_avg, - * in units of input stream sample clocks (so the average number of - * input samples per output symbol, aka samples/symbol). - * - * The average clock period estimate, T_avg, is normally updated by - * the advance_loop() and period_limit() calls. This method is used - * manually reset the estimate when needed. - * - * \param period - * Average clock period, T_avg, in units of input stream sample clocks. - */ - void set_avg_period(float period); - - /*! - * \brief Set the instantaneous clock period estimate, T_inst. - * - * \details - * Directly sets the instantaneous clock period estimate, T_inst, - * in units of input stream sample clocks (so the instantaneous number of - * input samples per output symbol, aka instantaneous samples/symbol). - * - * The instantaneous clock period estimate, T_inst, is normally updated by - * the advance_loop() call. This method is used manually reset the - * estimate when needed. - * - * \param period - * Instantaneous clock period, T_inst, in units of input stream sample - * clocks. - */ - void set_inst_period(float period); - - /*! - * \brief Set the instantaneous clock phase estimate, tau. - * - * \details - * Directly sets the instantaneous clock phase estimate, tau, - * in units of input stream sample clocks. - * - * The instantaneous clock phase estimate, tau, is normally updated by - * the advance_loop() call. This method is used manually reset the - * estimate when needed. - * - * \param phase - * Instantaneous clock phase, tau, in units of input stream sample clocks. - * - */ - void set_phase(float phase); - - /*! - * \brief Set the maximum average clock period estimate limit, T_avg_max. - * - * \details - * Sets the maximum average clock period estimate limit, T_avg_max - * in units of input stream sample clocks (so the maximum average number - * of input samples per output symbol, aka maximum samples/symbol). - * - * This limit is needed because T_avg is essentially computed by the - * integrator portion of an IIR filter, so T_avg could potentially - * wander very far during periods of noise/nonsense input. - * - * \param period - * Maximum average clock period, T_avg_max, in units of input stream - * sample clocks. - */ - void set_max_avg_period(float period); - - /*! - * \brief Set the minimum average clock period estimate limit, T_avg_min. - * - * \details - * Sets the minimum average clock period estimate limit, T_avg_min - * in units of input stream sample clocks (so the minimum average number - * of input samples per output symbol, aka minimum samples/symbol). - * - * This limit is needed because T_avg is essentially computed by the - * integrator portion of an IIR filter, so T_avg could potentially - * wander very far during periods of noise/nonsense input. - * - * \param period - * Minimum average clock period, T_avg_min, in units of input stream - * sample clocks. - */ - void set_min_avg_period(float period); - - /*! - * \brief Set the nominal average clock period estimate limit, T_avg_nom. - * - * \details - * Sets the nominal average clock period estimate limit, T_avg_nom - * in units of input stream sample clocks (so the nominal average number - * of input samples per output symbol, aka minimum samples/symbol). - * - * \param period - * Nominal average clock period, T_avg_nom, in units of input stream - * sample clocks. - */ - void set_nom_avg_period(float period); - - /******************************************************************* - * GET FUNCTIONS - *******************************************************************/ - - /*! - * \brief Returns the normalized approximate loop bandwidth. - * - * \details - * See the documentation 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 documentation for set_damping_factor() for more details. - * - * Note that if set_alpha() or set_beta() were called to directly - * set gains, the value returned by this method will be inaccurate/stale. - */ - float get_damping_factor() const; - - /*! - * \brief Returns the user providded expected gain of the Timing Error - * Detector. - * - * \details - * See the documentation for set_ted_gain() for more details. - */ - float get_ted_gain() const; - - /*! - * \brief Returns the PI filter proportional gain, alpha. - * - * \details - * See the documentation for set_alpha() for more details. - */ - float get_alpha() const; - - /*! - * \brief Returns the PI filter integral gain, beta. - * - * \details - * See the documentation 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 documentation 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 documentation 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 */ + 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 documentation 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 documentation for set_damping_factor() for more details. + * + * Note that if set_alpha() or set_beta() were called to directly + * set gains, the value returned by this method will be inaccurate/stale. + */ + float get_damping_factor() const; + + /*! + * \brief Returns the user providded expected gain of the Timing Error + * Detector. + * + * \details + * See the documentation for set_ted_gain() for more details. + */ + float get_ted_gain() const; + + /*! + * \brief Returns the PI filter proportional gain, alpha. + * + * \details + * See the documentation for set_alpha() for more details. + */ + float get_alpha() const; + + /*! + * \brief Returns the PI filter integral gain, beta. + * + * \details + * See the documentation 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 documentation 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 documentation 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 */ |