2 # Copyright 2005,2007 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.org/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
48 @param mpoints: number of freq bins/interpolation factor/subbands
49 @param taps: filter taps for subband filter
51 The channel spacing is equal to the input sample rate.
52 The total bandwidth and output sample rate are equal the input
53 sample rate * nchannels.
55 Output stream to frequency mapping:
57 channel zero is at zero frequency.
61 Channels with increasing positive frequencies come from
62 channels 1 through (N-1)/2.
64 Channel (N+1)/2 is the maximum negative frequency, and
65 frequency increases through N-1 which is one channel lower
66 than the zero frequency.
70 Channels with increasing positive frequencies come from
71 channels 1 through (N/2)-1.
73 Channel (N/2) is evenly split between the max positive and
76 Channel (N/2)+1 is the maximum negative frequency, and
77 frequency increases through N-1 which is one channel lower
78 than the zero frequency.
80 Channels near the frequency extremes end up getting cut
81 off by subsequent filters and therefore have diminished
84 item_size = gr.sizeof_gr_complex
85 gr.hier_block2.__init__(self, "synthesis_filterbank",
86 gr.io_signature(mpoints, mpoints, item_size), # Input signature
87 gr.io_signature(1, 1, item_size)) # Output signature
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)
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))
118 self.connect(self.ss2s, self)
120 class analysis_filterbank(gr.hier_block2):
122 Uniformly modulated polyphase DFT filter bank: analysis
124 See http://cnx.org/content/m10424/latest
126 def __init__(self, mpoints, taps=None):
128 Takes 1 complex stream in, produces M complex streams out
129 that runs at 1/M times the input sample rate
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), # Input signature
139 gr.io_signature(mpoints, mpoints, item_size)) # Output signature
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))
167 self.connect((self.v2ss, i), (self, i))
169 self.connect(self.ss2v, self.fft, self.v2ss)