Imported Upstream version 3.0
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blksimpl / 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 2, 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_block):
38     """
39     Uniformly modulated polyphase DFT filter bank: synthesis
40
41     See http://cnx.rice.edu/content/m10424/latest
42     """
43     def __init__(self, fg, 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
87         if taps is None:
88             taps = _generate_synthesis_taps(mpoints)
89
90         # pad taps to multiple of mpoints
91         r = len(taps) % mpoints
92         if r != 0:
93             taps = taps + (mpoints - r) * (0,)
94
95         # split in mpoints separate set of taps
96         sub_taps = _split_taps(taps, mpoints)
97
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)
103
104         fg.connect(self.ss2v, self.ifft, self.v2ss)
105
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))
111
112         gr.hier_block.__init__(self, fg, self.ss2v, self.ss2s)
113
114
115 class analysis_filterbank(gr.hier_block):
116     """
117     Uniformly modulated polyphase DFT filter bank: analysis
118
119     See http://cnx.rice.edu/content/m10424/latest
120     """
121     def __init__(self, fg, mpoints, taps=None):
122         """
123         Takes 1 complex stream in, produces M complex streams out
124         that runs at 1/M times the input sample rate
125
126         @param fg:      flow_graph
127         @param mpoints: number of freq bins/interpolation factor/subbands
128         @param taps:    filter taps for subband filter
129
130         Same channel to frequency mapping as described above.
131         """
132         item_size = gr.sizeof_gr_complex
133
134         if taps is None:
135             taps = _generate_synthesis_taps(mpoints)
136
137         # pad taps to multiple of mpoints
138         r = len(taps) % mpoints
139         if r != 0:
140             taps = taps + (mpoints - r) * (0,)
141         
142         # split in mpoints separate set of taps
143         sub_taps = _split_taps(taps, mpoints)
144
145         # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps) 
146         
147         self.s2ss = gr.stream_to_streams(item_size, mpoints)
148         # filters here
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)
152
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))
158
159         fg.connect(self.ss2v, self.fft, self.v2ss)
160         gr.hier_block.__init__(self, fg, self.s2ss, self.v2ss)