Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blks2impl / filterbank.py
1 #
2 # Copyright 2005,2007 Free Software Foundation, Inc.
3
4 # This file is part of GNU Radio
5
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)
9 # any later version.
10
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.
15
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.
20
21
22 import sys
23 from gnuradio import gr, gru
24
25 def _generate_synthesis_taps(mpoints):
26     return []   # FIXME
27
28
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]
35
36
37 class synthesis_filterbank(gr.hier_block2):
38     """
39     Uniformly modulated polyphase DFT filter bank: synthesis
40
41     See http://cnx.org/content/m10424/latest
42     """
43     def __init__(self, mpoints, taps=None):
44         """
45         Takes M complex streams in, produces single complex stream out
46         that runs at M times the input sample rate
47
48         @param mpoints: number of freq bins/interpolation factor/subbands
49         @param taps:    filter taps for subband filter
50
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.
54
55         Output stream to frequency mapping:
56         
57           channel zero is at zero frequency.
58
59           if mpoints is odd:
60             
61             Channels with increasing positive frequencies come from
62             channels 1 through (N-1)/2.
63
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.
67
68           if mpoints is even:
69
70             Channels with increasing positive frequencies come from
71             channels 1 through (N/2)-1.
72
73             Channel (N/2) is evenly split between the max positive and
74             negative bins.
75
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.
79
80             Channels near the frequency extremes end up getting cut
81             off by subsequent filters and therefore have diminished
82             utility.
83         """
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
88
89
90         if taps is None:
91             taps = _generate_synthesis_taps(mpoints)
92
93         # pad taps to multiple of mpoints
94         r = len(taps) % mpoints
95         if r != 0:
96             taps = taps + (mpoints - r) * (0,)
97
98         # split in mpoints separate set of taps
99         sub_taps = _split_taps(taps, mpoints)
100
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)
106
107         for i in range(mpoints):
108             self.connect((self, i), (self.ss2v, i))
109             
110         self.connect(self.ss2v, self.ifft, self.v2ss)
111
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))
117
118         self.connect(self.ss2s, self)
119         
120 class analysis_filterbank(gr.hier_block2):
121     """
122     Uniformly modulated polyphase DFT filter bank: analysis
123
124     See http://cnx.org/content/m10424/latest
125     """
126     def __init__(self, mpoints, taps=None):
127         """
128         Takes 1 complex stream in, produces M complex streams out
129         that runs at 1/M times the input sample rate
130
131         @param mpoints: number of freq bins/interpolation factor/subbands
132         @param taps:    filter taps for subband filter
133
134         Same channel to frequency mapping as described above.
135         """
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
140         
141         if taps is None:
142             taps = _generate_synthesis_taps(mpoints)
143
144         # pad taps to multiple of mpoints
145         r = len(taps) % mpoints
146         if r != 0:
147             taps = taps + (mpoints - r) * (0,)
148         
149         # split in mpoints separate set of taps
150         sub_taps = _split_taps(taps, mpoints)
151
152         # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps) 
153         
154         self.s2ss = gr.stream_to_streams(item_size, mpoints)
155         # filters here
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)
159
160         self.connect(self, self.s2ss)
161         
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))
168             
169         self.connect(self.ss2v, self.fft, self.v2ss)