summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/doxygen/other/group_defs.dox1
-rw-r--r--docs/doxygen/other/main_page.dox2
-rw-r--r--docs/doxygen/other/pfb_intro.dox82
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h1
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_fff.h1
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h1
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h128
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h128
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h1
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h1
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h1
11 files changed, 232 insertions, 115 deletions
diff --git a/docs/doxygen/other/group_defs.dox b/docs/doxygen/other/group_defs.dox
index 646df6855..6288d1f0a 100644
--- a/docs/doxygen/other/group_defs.dox
+++ b/docs/doxygen/other/group_defs.dox
@@ -31,6 +31,7 @@
/*! \defgroup qtgui_blk QT Graphical Interfaces */
/*! \defgroup uhd_blk UHD Interface */
/*! \defgroup audio_blk Audio Interface */
+/*! \defgroup pfb_blk Polyphase Filterbank */
/*!
* \defgroup base_blk Base classes for GR Blocks
diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index f8d0dcf73..7d78bbbbb 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -15,5 +15,5 @@ More details on packages in GNU Radio:
\li \ref page_qtgui
\li \ref page_uhd
\li \ref page_vocoder
-
+\li \ref page_pfb
*/
diff --git a/docs/doxygen/other/pfb_intro.dox b/docs/doxygen/other/pfb_intro.dox
new file mode 100644
index 000000000..8b82d96d7
--- /dev/null
+++ b/docs/doxygen/other/pfb_intro.dox
@@ -0,0 +1,82 @@
+/*! \page page_pfb Polyphase Filterbanks
+
+\section Introduction
+
+Polyphase filterbanks (PFB) are a very powerful set of filtering tools
+that can efficiently perform many multi-rate signal processing
+tasks. GNU Radio has a set of polyphase filterbank blocks to be used
+in all sorts of applications. These blocks and their documentation can
+be found in \ref pfb_blk.
+
+\section Usage
+
+See the documentation for the individual blocks for details about what
+they can do and how they should be used. Furthermore, there are
+examples for these blocks in <b>gnuradio-examples/python/pfb</b>.
+
+The main issue when using the PFB blocks is defining the prototype
+filter, which is passed to all of the blocks as a vector of \p
+taps. The taps from the prototype filter which get partitioned among
+the \p N channels of the channelizer.
+
+An example of creating a set of filter taps for a PFB channelizer is
+found on line 49 of <b>gnuradio-examples/python/pfb/channelizer.py</b>
+and reproduced below. Notice that the sample rate is the sample rate
+at the input to the channelizer while the bandwidth and transition
+width are defined for the channel bandwidths. This makes a fairly long
+filter that is then split up between the \p N channels of the PFB.
+
+\code
+ self._fs = 9000 # input sample rate
+ self._M = 9 # Number of channels to channelize
+
+ self._taps = gr.firdes.low_pass_2(1, self._fs, 475.50, 50,
+ attenuation_dB=100,
+ window=gr.firdes.WIN_BLACKMAN_hARRIS)
+\endcode
+
+In this example, the signal into the channelizer is sampled at 9 ksps
+(complex, so 9 kHz of bandwidth). The filter uses 9 channels, so each
+output channel will have a bandwidth and sample rate of 1 kHz. We want
+to pass most of the channel, so we define the channel bandwidth to be
+a low pass filter with a bandwidth of 475.5 Hz and a transition
+bandwidth of 50 Hz, but we have defined this using a sample rate of
+the original 9 kHz. The prototype filter has 819 taps to be divided up
+between the 9 channels, so each channel uses 91 taps. This is probably
+over-kill for a channelizer, and we could reduce the amount of taps
+per channel to a couple of dozen with no ill effects.
+
+The basic rule when defining a set of taps for a PFB block is to think
+about the filter running at the highest rate it will see while the
+bandwidth is defined for the size of the channels. In the channelizer
+case, the highest rate is defined as the rate of the incoming signal,
+but in other PFB blocks, this is not so obvious.
+
+Two very useful blocks to use are the arbitrary resampler and the
+clock synchronizer (for PAM signals). These PFBs are defined with a
+set number of filters based on the fidelity required from them, not
+the rate changes. By default, the \p filter_size is set to 32 for
+these blocks, which is a reasonable default for most tasks. Because
+the PFB uses this number of filters in the filterbank, the maximum
+rate of the bank is defined from this (see the theory of a polyphase
+interpolator for a justification of this). So the prototype filter is
+defined to use a sample rate of \p filter_size times the signal's
+sampling rate.
+
+A helpful wrapper for the arbitrary resampler is found in
+<b>gnuradio-core/src/python/gnuradio/blks2impl/pfb_arb_resampler.py</b>,
+which is exposed in Python as <b>blks2.pfb_arb_resampler_ccf</b> and
+<b>blks2.pfb_arb_resampler_fff</b>. This block is set up so that the
+user only needs to pass it the real number \p rate as the resampling
+rate. With just this information, this hierarchical block
+automatically creates a filter that fully passes the signal bandwidth
+being resampled but does not pass any out-of-band noise. See the code
+for this block for details of how the filter is constructed.
+
+Of course, a user can create his or her own taps and use them in the
+arbitrary resampler for more specific requirements. Some of the UHD
+examples (<b>gr-uhd/examples</b>) use this ability to create a
+received matched filter or channel filter that also resamples the
+signal.
+
+*/
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
index 2c36c95f9..806c33d92 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
@@ -41,6 +41,7 @@ class gr_fir_ccf;
* gr_complex input, gr_complex output and float taps
*
* \ingroup filter_blk
+ * \ingroup pfb_blk
*
* This block takes in a signal stream and performs arbitrary
* resampling. The resampling rate can be any real
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_fff.h b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_fff.h
index 541df8aa4..69331a2c6 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_fff.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_fff.h
@@ -41,6 +41,7 @@ class gr_fir_fff;
* float input, float output and float taps
*
* \ingroup filter_blk
+ * \ingroup pfb_blk
*
* This block takes in a signal stream and performs arbitrary
* resampling. The resampling rate can be any real
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
index 751673bc7..68476ed3c 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
@@ -43,6 +43,7 @@ class gri_fft_complex;
* gr_complex input, gr_complex output and float taps
*
* \ingroup filter_blk
+ * \ingroup pfb_blk
*
* This block takes in complex inputs and channelizes it to <EM>M</EM>
* channels of equal bandwidth. Each of the resulting channels is
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 06a6f5720..674dee181 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
@@ -43,71 +43,85 @@ class gr_fir_ccf;
* \brief Timing synchronizer using polyphase filterbanks
*
* \ingroup filter_blk
+ * \ingroup pfb_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 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 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 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.
+ * 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
+ * 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.
+ * 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 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 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 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 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 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 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.
+ * 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.
*
*/
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 fa1279a7c..d7c646801 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
@@ -42,71 +42,85 @@ class gr_fir_fff;
* \brief Timing synchronizer using polyphase filterbanks
*
* \ingroup filter_blk
+ * \ingroup pfb_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 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.
+ * 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.
+ * 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 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 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 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 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.
+ * 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.
*
*/
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h
index 200adee3d..6b75c5859 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h
@@ -41,6 +41,7 @@ class gri_fft_complex;
* input, gr_complex output and float taps
*
* \ingroup filter_blk
+ * \ingroup pfb_blk
*
* This block takes in a signal stream and performs interger down-
* sampling (decimation) with a polyphase filterbank. The first input
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h
index d2efc591a..3dc52938e 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h
@@ -39,6 +39,7 @@ class gr_fir_ccf;
* gr_complex output and float taps
*
* \ingroup filter_blk
+ * \ingroup pfb_blk
*
* This block takes in a signal stream and performs interger up-
* sampling (interpolation) with a polyphase filterbank. The first
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h
index f5b1cbb94..7e3700921 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h
@@ -42,6 +42,7 @@ class gri_fft_complex;
* gr_complex input, gr_complex output and float taps
*
* \ingroup filter_blk
+ * \ingroup pfb_blk
*/
class gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator