diff options
Diffstat (limited to 'gnuradio-core')
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc | 23 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h | 81 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h | 80 |
3 files changed, 124 insertions, 60 deletions
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc index 633c5be07..b5379144d 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc @@ -60,7 +60,7 @@ gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (double sps, float loop_bw, gr_make_io_signaturev (1, 4, iosig)), d_updated (false), d_nfilters(filter_size), d_max_dev(max_rate_deviation), - d_osps(osps), d_error(0) + d_osps(osps), d_error(0), d_out_idx(0) { d_nfilters = filter_size; d_sps = floor(sps); @@ -376,8 +376,8 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items, float error_r, error_i; // produce output as long as we can and there are enough input samples - while((i < noutput_items-d_osps) && (count < nrequired)) { - for(int k = 0; k < d_osps; k++) { + while((i < noutput_items) && (count < nrequired)) { + while(d_out_idx < d_osps) { d_filtnum = (int)floor(d_k); // Keep the current filter number in [0, d_nfilters] @@ -394,16 +394,27 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items, count -= 1; } - out[i+k] = d_filters[d_filtnum]->filter(&in[count+k]); + out[i+d_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]); d_k = d_k + d_rate_i + d_rate_f; // update phase - + d_out_idx++; + if(output_items.size() == 4) { err[i] = d_error; outrate[i] = d_rate_f; outk[i] = d_k; } + + // We've run out of output items we can create; return now. + if(i+d_out_idx >= noutput_items) { + consume_each(count); + return i; + } } + // reset here; if we didn't complete a full osps samples last time, + // the early return would take care of it. + d_out_idx = 0; + // Update the phase and rate estimates for this symbol gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]); error_r = out[i].real() * diff.real(); @@ -421,7 +432,7 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items, i+=d_osps; count += (int)floor(d_sps); } - consume_each(count); + consume_each(count); return i; } diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h index 514f580ba..1e1bbca10 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h @@ -94,36 +94,61 @@ class gr_fir_ccf; * 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 symbol - * (sps), because it only returns a single point representing the - * symbol. 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 block's parameters are: * - * 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. + * \li \p sps: The clock sync block needs to know the number of samples per + * symbol, because it defaults to return a single point representing + * the symbol. The sps can be any positive real number and does not + * need to be an integer. * - * 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. + * \li \p loop_bw: The loop bandwidth is used to set the gain of the + * inner control loop (see: + * http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html). + * This should be set small (a value of around 2pi/100 is suggested in + * that blog post as the step size for the number of radians around + * the unit circle to move relative to the error). * - * 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. + * \li \p taps: One of the most important parameters for this block is + * the taps of the filter. One of the benefits of this algorithm is + * that you can put the matched filter in here as the taps, so you get + * both the matched filter and sample timing correction in one go. So + * create your normal matched filter. For a typical digital + * modulation, this is a root raised cosine filter. The number of taps + * of this filter is based on how long you expect the channel to be; + * that is, how many symbols do you want to combine to get the current + * symbols energy back (there's probably a better way of stating + * that). It's usually 5 to 10 or so. That gives you your filter, but + * now we need to think about it as a filter with different phase + * profiles in each filter. So take this number of taps and multiply + * it by the number of filters. This is the number you would use to + * create your prototype filter. When you use this in the PFB + * filerbank, it segments these taps into the filterbanks in such a + * way that each bank now represents the filter at different phases, + * equally spaced at 2pi/N, where N is the number of filters. * + * \li \p filter_size (default=32): 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. + * + * \li \p init_phase (default=0): 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. + * + * \li \p max_rate_deviation (default=1.5): The next 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. + * + * \li \p osps (default=1): The osps is the number of output samples per symbol. By default, + * the algorithm produces 1 sample per symbol, sampled at the exact + * sample value. This osps value was added to better work with + * equalizers, which do a better job of modeling the channel if they + * have 2 samps/sym. */ class GR_CORE_API gr_pfb_clock_sync_ccf : public gr_block @@ -141,6 +166,7 @@ class GR_CORE_API gr_pfb_clock_sync_ccf : public gr_block * \param osps (int) The number of output samples per symbol (default=1). * */ + friend GR_CORE_API gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float loop_bw, const std::vector<float> &taps, unsigned int filter_size, @@ -171,7 +197,8 @@ class GR_CORE_API gr_pfb_clock_sync_ccf : public gr_block int d_filtnum; int d_osps; float d_error; - + int d_out_idx; + /*! * Build the polyphase filterbank timing synchronizer. */ 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 447d3e59d..43d382713 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 @@ -49,7 +49,7 @@ class gr_fir_fff; * 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 + * This approach works by setting up two filterbanks; one filterbank * 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 @@ -93,36 +93,62 @@ class gr_fir_fff; * 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 block's parameters are: * - * 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. + * \li \p sps: The clock sync block needs to know the number of samples per + * symbol, because it defaults to return a single point representing + * the symbol. The sps can be any positive real number and does not + * need to be an integer. * - * 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. + * \li \p loop_bw: The loop bandwidth is used to set the gain of the + * inner control loop (see: + * http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html). + * This should be set small (a value of around 2pi/100 is suggested in + * that blog post as the step size for the number of radians around + * the unit circle to move relative to the error). * - * 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. + * \li \p taps: One of the most important parameters for this block is + * the taps of the filter. One of the benefits of this algorithm is + * that you can put the matched filter in here as the taps, so you get + * both the matched filter and sample timing correction in one go. So + * create your normal matched filter. For a typical digital + * modulation, this is a root raised cosine filter. The number of taps + * of this filter is based on how long you expect the channel to be; + * that is, how many symbols do you want to combine to get the current + * symbols energy back (there's probably a better way of stating + * that). It's usually 5 to 10 or so. That gives you your filter, but + * now we need to think about it as a filter with different phase + * profiles in each filter. So take this number of taps and multiply + * it by the number of filters. This is the number you would use to + * create your prototype filter. When you use this in the PFB + * filerbank, it segments these taps into the filterbanks in such a + * way that each bank now represents the filter at different phases, + * equally spaced at 2pi/N, where N is the number of filters. * + * \li \p filter_size (default=32): 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. + * + * \li \p init_phase (default=0): 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. + * + * \li \p max_rate_deviation (default=1.5): The next 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. + * + * \li \p osps: note that unlike the ccf version of this algorithm, + * this block does \a not have a setting for the number of output + * samples per symbol. This is mostly because it should not be + * necessary as the reason for having multiple output sps is to + * perform equalization and the equalizers will take in complex + * numbers in order to do magnitude and phase correction. */ class GR_CORE_API gr_pfb_clock_sync_fff : public gr_block |