2 # Copyright 2005 Free Software Foundation, Inc.
4 # This file is part of GNU Radio
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING. If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
23 from gnuradio import gr, gru
25 def _generate_synthesis_taps(mpoints):
29 def _split_taps(taps, mpoints):
30 assert (len(taps) % mpoints) == 0
31 result = [list() for x in range(mpoints)]
32 for i in xrange(len(taps)):
33 (result[i % mpoints]).append(taps[i])
34 return [tuple(x) for x in result]
37 class synthesis_filterbank(gr.hier_block):
39 Uniformly modulated polyphase DFT filter bank: synthesis
41 See http://cnx.rice.edu/content/m10424/latest
43 def __init__(self, fg, mpoints, taps=None):
45 Takes M complex streams in, produces single complex stream out
46 that runs at M times the input sample rate
49 @param mpoints: number of freq bins/interpolation factor/subbands
50 @param taps: filter taps for subband filter
52 The channel spacing is equal to the input sample rate.
53 The total bandwidth and output sample rate are equal the input
54 sample rate * nchannels.
56 Output stream to frequency mapping:
58 channel zero is at zero frequency.
62 Channels with increasing positive frequencies come from
63 channels 1 through (N-1)/2.
65 Channel (N+1)/2 is the maximum negative frequency, and
66 frequency increases through N-1 which is one channel lower
67 than the zero frequency.
71 Channels with increasing positive frequencies come from
72 channels 1 through (N/2)-1.
74 Channel (N/2) is evenly split between the max positive and
77 Channel (N/2)+1 is the maximum negative frequency, and
78 frequency increases through N-1 which is one channel lower
79 than the zero frequency.
81 Channels near the frequency extremes end up getting cut
82 off by subsequent filters and therefore have diminished
85 item_size = gr.sizeof_gr_complex
88 taps = _generate_synthesis_taps(mpoints)
90 # pad taps to multiple of mpoints
91 r = len(taps) % mpoints
93 taps = taps + (mpoints - r) * (0,)
95 # split in mpoints separate set of taps
96 sub_taps = _split_taps(taps, mpoints)
98 self.ss2v = gr.streams_to_vector(item_size, mpoints)
99 self.ifft = gr.fft_vcc(mpoints, False, [])
100 self.v2ss = gr.vector_to_streams(item_size, mpoints)
101 # mpoints filters go in here...
102 self.ss2s = gr.streams_to_stream(item_size, mpoints)
104 fg.connect(self.ss2v, self.ifft, self.v2ss)
106 # build mpoints fir filters...
107 for i in range(mpoints):
108 f = gr.fft_filter_ccc(1, sub_taps[i])
109 fg.connect((self.v2ss, i), f)
110 fg.connect(f, (self.ss2s, i))
112 gr.hier_block.__init__(self, fg, self.ss2v, self.ss2s)
115 class analysis_filterbank(gr.hier_block):
117 Uniformly modulated polyphase DFT filter bank: analysis
119 See http://cnx.rice.edu/content/m10424/latest
121 def __init__(self, fg, mpoints, taps=None):
123 Takes 1 complex stream in, produces M complex streams out
124 that runs at 1/M times the input sample rate
126 @param fg: flow_graph
127 @param mpoints: number of freq bins/interpolation factor/subbands
128 @param taps: filter taps for subband filter
130 Same channel to frequency mapping as described above.
132 item_size = gr.sizeof_gr_complex
135 taps = _generate_synthesis_taps(mpoints)
137 # pad taps to multiple of mpoints
138 r = len(taps) % mpoints
140 taps = taps + (mpoints - r) * (0,)
142 # split in mpoints separate set of taps
143 sub_taps = _split_taps(taps, mpoints)
145 # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps)
147 self.s2ss = gr.stream_to_streams(item_size, mpoints)
149 self.ss2v = gr.streams_to_vector(item_size, mpoints)
150 self.fft = gr.fft_vcc(mpoints, True, [])
151 self.v2ss = gr.vector_to_streams(item_size, mpoints)
153 # build mpoints fir filters...
154 for i in range(mpoints):
155 f = gr.fft_filter_ccc(1, sub_taps[mpoints-i-1])
156 fg.connect((self.s2ss, i), f)
157 fg.connect(f, (self.ss2v, i))
159 fg.connect(self.ss2v, self.fft, self.v2ss)
160 gr.hier_block.__init__(self, fg, self.s2ss, self.v2ss)