Updated license from GPL version 2 or later to GPL version 3 or later.
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blksimpl2 / filterbank.py
1 #
2 # Copyright 2005 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.rice.edu/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 fg:      flow_graph
49         @param mpoints: number of freq bins/interpolation factor/subbands
50         @param taps:    filter taps for subband filter
51
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.
55
56         Output stream to frequency mapping:
57         
58           channel zero is at zero frequency.
59
60           if mpoints is odd:
61             
62             Channels with increasing positive frequencies come from
63             channels 1 through (N-1)/2.
64
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.
68
69           if mpoints is even:
70
71             Channels with increasing positive frequencies come from
72             channels 1 through (N/2)-1.
73
74             Channel (N/2) is evenly split between the max positive and
75             negative bins.
76
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.
80
81             Channels near the frequency extremes end up getting cut
82             off by subsequent filters and therefore have diminished
83             utility.
84         """
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))
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, self)
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
119 class analysis_filterbank(gr.hier_block2):
120     """
121     Uniformly modulated polyphase DFT filter bank: analysis
122
123     See http://cnx.rice.edu/content/m10424/latest
124     """
125     def __init__(self, mpoints, taps=None):
126         """
127         Takes 1 complex stream in, produces M complex streams out
128         that runs at 1/M times the input sample rate
129
130         @param fg:      flow_graph
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),
139                                 gr.io_signature(mpoints, mpoints, item_size))
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
168         self.connect(self.ss2v, self.fft, self.v2ss)
169
170         for i in range(mpoints):
171             self.connect((self.v2ss, i), (self, i))
172
173
174