[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:1.9.2.13) Gecko/20101207 Lightning/1.0b2 Thunderbird/3.1.7 |
Hi, Tom:
Please see my comments below.
Thanks
On 12/29/2010 12:58 AM, Tom Rondeau wrote:
On Mon, Dec 27, 2010 at 3:48 AM, Jimmy Richardson<address@hidden> wrote:
Hi,:
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,
window=gr.firdes.WIN_BLACKMAN_hARRIS)
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.ddc_filter.append(gr.freq_xlating_fir_filter_ccf(self._resampling_ratio,
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,
window=gr.firdes.WIN_BLACKMAN_hARRIS)
# Calculate the number of taps per channel for our own information
self._taps_per_channel = scipy.ceil(float(len(self._filter_taps)) /
float(self._M))
print "Number of taps: _filter_taps = ", len(self._filter_taps)
print "Taps per channel: _taps_per_channel = ",
self._taps_per_channel
# Construct the channelizer filter
self.pfb = blks2.pfb_channelizer_ccf(self._M, self._filter_taps,
self._oversample_rate)
# 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
way.
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
Thanks
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
point.
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?
Tom