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_block2):
39 Uniformly modulated polyphase DFT filter bank: synthesis
41 See http://cnx.rice.edu/content/m10424/latest
43 def __init__(self, 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
86 gr.hier_block2.__init__(self, "synthesis_filterbank",
87 gr.io_signature(mpoints, mpoints, item_size),
88 gr.io_signature(1, 1, item_size))
91 taps = _generate_synthesis_taps(mpoints)
93 # pad taps to multiple of mpoints
94 r = len(taps) % mpoints
96 taps = taps + (mpoints - r) * (0,)
98 # split in mpoints separate set of taps
99 sub_taps = _split_taps(taps, mpoints)
101 self.ss2v = gr.streams_to_vector(item_size, mpoints)
102 self.ifft = gr.fft_vcc(mpoints, False, [])
103 self.v2ss = gr.vector_to_streams(item_size, mpoints)
104 # mpoints filters go in here...
105 self.ss2s = gr.streams_to_stream(item_size, mpoints)
107 for i in range(mpoints):
108 self.connect((self, i), (self.ss2v, i))
110 self.connect(self.ss2v, self.ifft, self.v2ss, self)
112 # build mpoints fir filters...
113 for i in range(mpoints):
114 f = gr.fft_filter_ccc(1, sub_taps[i])
115 self.connect((self.v2ss, i), f)
116 self.connect(f, (self.ss2s, i))
119 class analysis_filterbank(gr.hier_block2):
121 Uniformly modulated polyphase DFT filter bank: analysis
123 See http://cnx.rice.edu/content/m10424/latest
125 def __init__(self, mpoints, taps=None):
127 Takes 1 complex stream in, produces M complex streams out
128 that runs at 1/M times the input sample rate
130 @param fg: flow_graph
131 @param mpoints: number of freq bins/interpolation factor/subbands
132 @param taps: filter taps for subband filter
134 Same channel to frequency mapping as described above.
136 item_size = gr.sizeof_gr_complex
137 gr.hier_block2.__init__(self, "analysis_filterbank",
138 gr.io_signature(1, 1, item_size),
139 gr.io_signature(mpoints, mpoints, item_size))
142 taps = _generate_synthesis_taps(mpoints)
144 # pad taps to multiple of mpoints
145 r = len(taps) % mpoints
147 taps = taps + (mpoints - r) * (0,)
149 # split in mpoints separate set of taps
150 sub_taps = _split_taps(taps, mpoints)
152 # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps)
154 self.s2ss = gr.stream_to_streams(item_size, mpoints)
156 self.ss2v = gr.streams_to_vector(item_size, mpoints)
157 self.fft = gr.fft_vcc(mpoints, True, [])
158 self.v2ss = gr.vector_to_streams(item_size, mpoints)
160 self.connect(self, self.s2ss)
162 # build mpoints fir filters...
163 for i in range(mpoints):
164 f = gr.fft_filter_ccc(1, sub_taps[mpoints-i-1])
165 self.connect((self.s2ss, i), f)
166 self.connect(f, (self.ss2v, i))
168 self.connect(self.ss2v, self.fft, self.v2ss)
170 for i in range(mpoints):
171 self.connect((self.v2ss, i), (self, i))