[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Discuss-gnuradio] DDC and Polyphase Channelizer

From: Jimmy Richardson
Subject: Re: [Discuss-gnuradio] DDC and Polyphase Channelizer
Date: Wed, 29 Dec 2010 17:32:03 +0800
User-agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv: Gecko/20101207 Lightning/1.0b2 Thunderbird/3.1.7

Hi, Tom:

Please see my comments below.


On 12/29/2010 12:58 AM, Tom Rondeau wrote:
On Mon, Dec 27, 2010 at 3:48 AM, Jimmy Richardson<address@hidden>  wrote:

I'm learning about polyphase channelizer, and I have been reading fred
harris' paper "Digital Receivers and Transmitters Using Polyphase Filter
Banks for Wireless Communications". I have also played with the Matlab
programs at the end of the paper. What I'm trying to do next is to use
GNURadio to do the channelization. I made two attempts, one uses
freq_xlating_fir_filter_ccf to implement a DDC channelizer, another uses
pfb_channelizer_ccf, running against the data in appendix III of harris'
paper. I'm hoping the channelizer result from GNURadio code would match the
result from Matlab, but I failed on both, I wonder if someone could help me
spot the problem.

1. DDC Channelizer:

Using the frequency xlating filters here is not recommended. You'll
need to use much longer filters than when using the channelizer. That

Could you clarify? Does this mean I need to change the parameter to gr.firdes.low_pass, maybe reduce _cutoff_freq?

said, I'm not sure what would cause the problem you identified below.
In my opinion, it's not worth doing it this way.

Ok, the reason I did this is because I want a way to verify the result from pfb channelizer is correct, since I'm not sure if I'm using it correctly.

1.1 Code: The following is the core part of the code (input parsing and
various other stuff are omitted), the value for the variables can be found
in 1.2
        self._filter_taps = gr.firdes.low_pass(1, self._input_rate,
self._cutoff_freq, self._trans_width,

        print "Number of taps:   _filter_taps = ", len(self._filter_taps)

        # Blocks
        self.ddc_filter = list()
        # i = 0 to M-1
        for i in xrange(self._M):
            offset = self._channel_bandwidth * (float(self._M)/2 - i)
            print "Channel ", i, "'s offset (Hz): ", offset


  self._filter_taps, offset, self._input_rate))
            self.connect(self.head, self.ddc_filter[i], self.output_files[i])

1.2 Variable values:
Input sampling freq (Hz):  _input_rate =  1120000000.0
Resampling ratio:          _resampling_ratio =  28
Output sampling freq (Hz): _output_rate =  40000000.0
Transition width (Hz):     _trans_width =  2000000.0
Number of channels:        _M =  40
Number of samples:         _N =  11200
Oversample rate:           _oversample_rate =  1.42857142857
Channel bandwidth (HZ):    _channel_bandwidth =  28000000.0
Cutoff freq (HZ):          _cutoff_freq =  13000000.0
Number of taps:   _filter_taps =  561
Channel  0 's offset (Hz):  560000000.0
Channel  1 's offset (Hz):  532000000.0
1.3 Result: The result from GNURadio code is saved to output files, one for
each channel. Then the results time-domain are plotted in Matlab (-10 to
+10, time 1 to 200), and compared to the result plot from harris' code, they
are similar, but not the same. Channel 0 to 5, 17, 18, 34 to 39 do not have
any strong signal, this is reflected in both plots, channel 20's signal is
exactly the same, but all other channels' plot are different.

2. Polyphase Channelizer:
2.1 Code:
        self._filter_taps = gr.firdes.low_pass(1, self._input_rate,
self._cutoff_freq, self._trans_width,

        # Calculate the number of taps per channel for our own information
        self._taps_per_channel = scipy.ceil(float(len(self._filter_taps)) /
        print "Number of taps:   _filter_taps = ", len(self._filter_taps)
        print "Taps per channel: _taps_per_channel = ",

        # Construct the channelizer filter
        self.pfb = blks2.pfb_channelizer_ccf(self._M, self._filter_taps,

        # Connect the blocks
        self.connect(self.head, self.pfb)
        # i = 0 to M-1
        for i in xrange(self._M):
            self.connect((self.pfb, i), self.output_files[i])

2.2 Variable values:
Input sampling freq (Hz):  _input_rate =  1120000000.0
Resampling ratio:          _resampling_ratio =  28
Output sampling freq (Hz): _output_rate =  40000000.0
Transition width (Hz):     _trans_width =  2000000.0
Number of channels:        _M =  40
Number of samples:         _N =  11200
Oversample rate:           _oversample_rate =  1.42857142857
Channel bandwidth (HZ):    _channel_bandwidth =  28000000.0
Cutoff freq (HZ):          _cutoff_freq =  13000000.0
Number of taps:   _filter_taps =  561
Taps per channel: _taps_per_channel =  15.0

2.3 Result: The GNURadio program failed with:
"terminate called after throwing an instance of 'std::invalid_argument'
  what():  gr_pfb_channelizer: oversample rate must be N/i for i in [1, N]

This application has requested the Runtime to terminate it in an unusual
Please contact the application's support team for more information."

This doesn't seem to make sense, since in this case N = 40, oversample rate
=1.42857142857, i = 28

The "oversample_rate" is not exactly what you are specifying here. The
default behavior of this PFB channelizer implementation is to be
critically sampled; that is, the sample rate equals the bandwidth. For
many applications, you want to have the output sample rate be some
other rate, most notably, 2x the bandwidth. The oversample_rate allows
you to specify a number real number, but this cannot be an arbitrary
number in this case. Because of the way the samples are fed to the
filters, the oversample rate, O, has to be set such that the number of
filters, N, can be evenly divided by an integer to to get O; that is,
N/i = O for i in [1,N]. Take the example in in fred's paper where he
has 64 channels and a 1/48 resampling rate. So he's using a 48-to-1
downsampling in 64 channels, so his rate is 4/3, which means that the
output sampling rate is (4/3)*bw, where bw is the channel bandwidth.

Sorry, false alarm here, it looks like a problem with MinGW's compiler, it didn't compile double comparison with 0.0 correctly or something. I tried the program under Ubuntu and the error disappeared. I think the number I used is the correct number since in my case N=40, i = 28, and O = N/i = 1.42857142857

If you specified that the rate was 2.0, you would feed 32 of the 64
channels and have a sample rate that is twice the bandwidth. I notice
in the remarks in fred's paper that he's outputting the channels at 2
samples/symbol, so the oversample_rate here should be 2.

I'm using fred's example in appendix III, not the 64 channels example. The comment summaries the example as below:
% receiver_40z is a demo of a 40 channel receiver, demodulating 30 channels,
% of nominal symbol rate 20 MHz, separated by 28 MHz centers (1.4 times symbol rate)
% input sample rate is 40*28 = 1120 MHz.
% receiver performs a 40 point transform on the output of a 40-stage polyphase filter % the polyphase filter operates at input rate but outputs at 2 samples/symbol or % 40 MHz. The resampling rate is 1120/40 = 28-to-1, thus output from 40-channels are % computed once for every 28 input samples. channelizer is not matched filter, % prototype filter is 10% wider than two sided bandwidth of input signal to accommodate
% frequency uncertainty of separate channel centers.

I hope that makes sense and you can figure out from there what you
need to do to get it to work. I've worked with fred for a while now,
but I find his Matlab to be almost unreadable (I've told him this
before), so I can't quite tell you from a quick look over the code he
has in this paper what's really going on.

I got passed the error, thanks, but still have problems with channelizer, see below...

Also, keep in mind that fred always develops he own filters straight
from the remez algorithm. If you are using gr.firdes.low_pass, you're
not going to get the same output filters. Closer would be to use the
blcks2.optfir.low_pass, which uses the PM algorithm (which in turn
uses Remez), but I couldn't give you the specs you need to build the
same _exact_ filter as in fred's paper. But you'll get close enough
that the basic shapes of the signals will be the same, if not every

Thanks for the suggestion, I modified filter statement to:

        self._filter_taps = blks2.optfir.low_pass(1, self._input_rate,
self._cutoff_freq - self._trans_width/2, self._cutoff_freq + self._trans_width/2,
                                                  0.9, 60, 400)

Note I have to use 400 as extra taps otherwise remez won't work (too many extremals -- cannot continue)

I got the result, but still not the same as the one from Matlab:
1. The channels seem to be shifted by 20 then wrapped around, i.e. assuming channel # starts with 1, the pfb result's channel 1 seems to be matlab's channel 21, and channel 20 in pfb result seems to be matlab's channel 40, channel 21 in pfb result seems to be matlab's channel 1. 2. Assuming the channel shift/wrap is done, the time-domain plot still are not the same, pfb channel 1 (matlab's channel 21)'s plot seems to be the same, and no signal channels do fit, but other channels' plot are not the same (i.e. the situation is similar to my result of DDC).

Is this because the filter taps in GNURadio is different from Matlab? Is there a way I can create a filter in GNURadio from a list of numbers exported from Matlab?


reply via email to

[Prev in Thread] Current Thread [Next in Thread]