summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/lib
diff options
context:
space:
mode:
authorTom Rondeau2012-01-02 11:34:45 -0500
committerTom Rondeau2012-01-02 11:34:45 -0500
commita64f22095bb5263fc939dec41eb0c00a26e0692a (patch)
tree3c45765481fbb628f59d20b297c435ab503a2aac /gnuradio-core/src/lib
parent9838bb040af5eb21cd88dbc9aae8d4bdf2838854 (diff)
parentcece444e4de92535a53152fd090e9fa33f60b692 (diff)
downloadgnuradio-a64f22095bb5263fc939dec41eb0c00a26e0692a.tar.gz
gnuradio-a64f22095bb5263fc939dec41eb0c00a26e0692a.tar.bz2
gnuradio-a64f22095bb5263fc939dec41eb0c00a26e0692a.zip
Merge branch 'maint'
Diffstat (limited to 'gnuradio-core/src/lib')
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc23
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h81
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h80
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