X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=gnuradio-core%2Fsrc%2Flib%2Ffilter%2Fgr_pfb_clock_sync_fff.h;h=fa1279a7cb77a927228b740ab4bfd499a758edfa;hb=d522829d8cd5a386b4426de5157b46d5d1856900;hp=913f798fefccb6fdac3c7de4622f047ff3fad971;hpb=0b9a0ba3594c8a4226319402f3c02d53d404c5a2;p=debian%2Fgnuradio diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h index 913f798f..fa1279a7 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -43,6 +43,71 @@ class gr_fir_fff; * * \ingroup filter_blk * + * This block performs timing synchronization for PAM signals by minimizing the + * derivative of the filtered signal, which in turn maximizes the SNR and + * minimizes ISI. + * + * This approach works by setting up two filterbanks; one filterbanke contains the + * signal's pulse shaping matched filter (such as a root raised cosine filter), + * where each branch of the filterbank contains a different phase of the filter. + * The second filterbank contains the derivatives of the filters in the first + * filterbank. Thinking of this in the time domain, the first filterbank contains + * filters that have a sinc shape to them. We want to align the output signal to + * be sampled at exactly the peak of the sinc shape. The derivative of the sinc + * contains a zero at the maximum point of the sinc (sinc(0) = 1, sinc(0)' = 0). + * Furthermore, the region around the zero point is relatively linear. We make + * use of this fact to generate the error signal. + * + * If the signal out of the derivative filters is d_i[n] for the ith filter, and + * the output of the matched filter is x_i[n], we calculate the error as: + * e[n] = (Re{x_i[n]} * Re{d_i[n]} + Im{x_i[n]} * Im{d_i[n]}) / 2.0 + * This equation averages the error in the real and imaginary parts. There are two + * reasons we multiply by the signal itself. First, if the symbol could be positive + * or negative going, but we want the error term to always tell us to go in the + * same direction depending on which side of the zero point we are on. The sign of + * x_i[n] adjusts the error term to do this. Second, the magnitude of x_i[n] scales + * the error term depending on the symbol's amplitude, so larger signals give us + * a stronger error term because we have more confidence in that symbol's value. + * Using the magnitude of x_i[n] instead of just the sign is especially good for + * signals with low SNR. + * + * The error signal, e[n], gives us a value proportional to how far away from the zero + * point we are in the derivative signal. We want to drive this value to zero, so we + * set up a second order loop. We have two variables for this loop; d_k is the filter + * number in the filterbank we are on and d_rate is the rate which we travel through + * the filters in the steady state. That is, due to the natural clock differences between + * the transmitter and receiver, d_rate represents that difference and would traverse + * the filter phase paths to keep the receiver locked. Thinking of this as a second-order + * PLL, the d_rate is the frequency and d_k is the phase. So we update d_rate and d_k + * using the standard loop equations based on two error signals, d_alpha and d_beta. + * We have these two values set based on each other for a critically damped system, so in + * the block constructor, we just ask for "gain," which is d_alpha while d_beta is + * equal to (gain^2)/4. + * + * The clock sync block needs to know the number of samples per second (sps), because it + * only returns a single point representing the sample. The sps can be any positive real + * number and does not need to be an integer. The filter taps must also be specified. The + * taps are generated by first conceiving of the prototype filter that would be the signal's + * matched filter. Then interpolate this by the number of filters in the filterbank. These + * are then distributed among all of the filters. So if the prototype filter was to have + * 45 taps in it, then each path of the filterbank will also have 45 taps. This is easily + * done by building the filter with the sample rate multiplied by the number of filters + * to use. + * + * The number of filters can also be set and defaults to 32. With 32 filters, you get a + * good enough resolution in the phase to produce very small, almost unnoticeable, ISI. + * Going to 64 filters can reduce this more, but after that there is very little gained + * for the extra complexity. + * + * The initial phase is another settable parameter and refers to the filter path the + * algorithm initially looks at (i.e., d_k starts at init_phase). This value defaults + * to zero, but it might be useful to start at a different phase offset, such as the mid- + * point of the filters. + * + * The final parameter is the max_rate_devitation, which defaults to 1.5. This is how far + * we allow d_rate to swing, positive or negative, from 0. Constraining the rate can help + * keep the algorithm from walking too far away to lock during times when there is no signal. + * */ class gr_pfb_clock_sync_fff : public gr_block @@ -50,6 +115,14 @@ class gr_pfb_clock_sync_fff : public gr_block private: /*! * Build the polyphase filterbank timing synchronizer. + * \param sps (double) The number of samples per second in the incoming signal + * \param gain (float) The alpha gain of the control loop; beta = (gain^2)/4 by default. + * \param taps (vector) The filter taps. + * \param filter_size (uint) The number of filters in the filterbank (default = 32). + * \param init_phase (float) The initial phase to look at, or which filter to start + * with (default = 0). + * \param max_rate_deviation (float) Distance from 0 d_rate can get (default = 1.5). + * */ friend gr_pfb_clock_sync_fff_sptr gr_make_pfb_clock_sync_fff (double sps, float gain, const std::vector &taps, @@ -96,29 +169,53 @@ public: void set_taps (const std::vector &taps, std::vector< std::vector > &ourtaps, std::vector &ourfilter); + + /*! + * Returns the taps of the matched filter + */ std::vector channel_taps(int channel); + + /*! + * Returns the taps in the derivative filter + */ std::vector diff_channel_taps(int channel); /*! * Print all of the filterbank taps to screen. */ void print_taps(); + + /*! + * Print all of the filterbank taps of the derivative filter to screen. + */ void print_diff_taps(); + /*! + * Set the gain value alpha for the control loop + */ void set_alpha(float alpha) { d_alpha = alpha; } + + /*! + * Set the gain value beta for the control loop + */ void set_beta(float beta) { d_beta = beta; } + /*! + * Set the maximum deviation from 0 d_rate can have + */ void set_max_rate_deviation(float m) { d_max_dev = m; } - + + bool check_topology(int ninputs, int noutputs); + int general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items,