Merge branch 'resampler'
[debian/gnuradio] / gnuradio-core / src / lib / filter / gr_pfb_arb_resampler_ccf.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2009 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gr_pfb_arb_resampler_ccf.h>
28 #include <gr_fir_ccf.h>
29 #include <gr_fir_util.h>
30 #include <gr_io_signature.h>
31 #include <cstdio>
32
33 gr_pfb_arb_resampler_ccf_sptr gr_make_pfb_arb_resampler_ccf (float rate, 
34                                                              const std::vector<float> &taps,
35                                                              unsigned int filter_size)
36 {
37   return gr_pfb_arb_resampler_ccf_sptr (new gr_pfb_arb_resampler_ccf (rate, taps,
38                                                                       filter_size));
39 }
40
41
42 gr_pfb_arb_resampler_ccf::gr_pfb_arb_resampler_ccf (float rate, 
43                                                     const std::vector<float> &taps,
44                                                     unsigned int filter_size)
45   : gr_block ("pfb_arb_resampler_ccf",
46               gr_make_io_signature (1, 1, sizeof(gr_complex)),
47               gr_make_io_signature (1, 1, sizeof(gr_complex))),
48     d_updated (false)
49 {
50   /* The number of filters is specified by the user as the filter size;
51      this is also the interpolation rate of the filter. We use it and the
52      rate provided to determine the decimation rate. This acts as a
53      rational resampler. The flt_rate is calculated as the residual
54      between the integer decimation rate and the real decimation rate and
55      will be used to determine to interpolation point of the resampling
56      process.
57   */
58   d_int_rate = filter_size;
59   d_dec_rate = (unsigned int)floor(d_int_rate/rate);
60   d_flt_rate = (d_int_rate/rate) - d_dec_rate;
61
62   // Store the last filter between calls to work
63   d_last_filter = 0;
64
65   d_start_index = 0;
66   
67   d_filters = std::vector<gr_fir_ccf*>(d_int_rate);
68   d_diff_filters = std::vector<gr_fir_ccf*>(d_int_rate);
69
70   // Create an FIR filter for each channel and zero out the taps
71   std::vector<float> vtaps(0, d_int_rate);
72   for(int i = 0; i < d_int_rate; i++) {
73     d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
74     d_diff_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
75   }
76
77   // Now, actually set the filters' taps
78   std::vector<float> dtaps;
79   create_diff_taps(taps, dtaps);
80   set_taps(taps, d_taps, d_filters);
81   set_taps(dtaps, d_dtaps, d_diff_filters);
82 }
83
84 gr_pfb_arb_resampler_ccf::~gr_pfb_arb_resampler_ccf ()
85 {
86   for(unsigned int i = 0; i < d_int_rate; i++) {
87     delete d_filters[i];
88   }
89 }
90
91 void
92 gr_pfb_arb_resampler_ccf::set_taps (const std::vector<float> &newtaps,
93                                     std::vector< std::vector<float> > &ourtaps,
94                                     std::vector<gr_fir_ccf*> &ourfilter)
95 {
96   int i,j;
97
98   unsigned int ntaps = newtaps.size();
99   d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate);
100
101   // Create d_numchan vectors to store each channel's taps
102   ourtaps.resize(d_int_rate);
103   
104   // Make a vector of the taps plus fill it out with 0's to fill
105   // each polyphase filter with exactly d_taps_per_filter
106   std::vector<float> tmp_taps;
107   tmp_taps = newtaps;
108   while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) {
109     tmp_taps.push_back(0.0);
110   }
111   
112   // Partition the filter
113   for(i = 0; i < d_int_rate; i++) {
114     // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
115     ourtaps[d_int_rate-1-i] = std::vector<float>(d_taps_per_filter, 0);
116     for(j = 0; j < d_taps_per_filter; j++) {
117       ourtaps[d_int_rate - 1 - i][j] = tmp_taps[i + j*d_int_rate];
118     }
119     
120     // Build a filter for each channel and add it's taps to it
121     ourfilter[i]->set_taps(ourtaps[d_int_rate-1-i]);
122   }
123
124   // Set the history to ensure enough input items for each filter
125   set_history (d_taps_per_filter + 1);
126
127   d_updated = true;
128 }
129
130 void
131 gr_pfb_arb_resampler_ccf::create_diff_taps(const std::vector<float> &newtaps,
132                                            std::vector<float> &difftaps)
133 {
134   float maxtap = 1e-20;
135   difftaps.clear();
136   difftaps.push_back(0); //newtaps[0]);
137   for(unsigned int i = 1; i < newtaps.size()-1; i++) {
138     float tap = newtaps[i+1] - newtaps[i-1];
139     difftaps.push_back(tap);
140     if(tap > maxtap) {
141       maxtap = tap;
142     }
143   }
144   difftaps.push_back(0);//-newtaps[newtaps.size()-1]);
145
146   // Scale the differential taps; helps scale error term to better update state
147   // FIXME: should this be scaled this way or use the same gain as the taps?
148   for(unsigned int i = 0; i < difftaps.size(); i++) {
149     difftaps[i] /= maxtap;
150   }
151 }
152
153 void
154 gr_pfb_arb_resampler_ccf::print_taps()
155 {
156   unsigned int i, j;
157   for(i = 0; i < d_int_rate; i++) {
158     printf("filter[%d]: [", i);
159     for(j = 0; j < d_taps_per_filter; j++) {
160       printf(" %.4e", d_taps[i][j]);
161     }
162     printf("]\n");
163   }
164 }
165
166 int
167 gr_pfb_arb_resampler_ccf::general_work (int noutput_items,
168                                         gr_vector_int &ninput_items,
169                                         gr_vector_const_void_star &input_items,
170                                         gr_vector_void_star &output_items)
171 {
172   gr_complex *in = (gr_complex *) input_items[0];
173   gr_complex *out = (gr_complex *) output_items[0];
174
175   if (d_updated) {
176     d_updated = false;
177     return 0;                // history requirements may have changed.
178   }
179
180   int i = 0, j, count = d_start_index;
181   gr_complex o0, o1;
182
183   // Restore the last filter position
184   j = d_last_filter;
185
186   // produce output as long as we can and there are enough input samples
187   while((i < noutput_items) && (count < ninput_items[0]-1)) {
188
189     // start j by wrapping around mod the number of channels
190     while((j < d_int_rate) && (i < noutput_items)) {
191       // Take the current filter output
192       o0 = d_filters[j]->filter(&in[count]);
193       o1 = d_diff_filters[j]->filter(&in[count]);
194
195       out[i] = o0 + o1*d_flt_rate;     // linearly interpolate between samples
196       i++;
197       
198       j += d_dec_rate;
199     }
200     if(i < noutput_items) {              // keep state for next entry
201       float ss = (int)(j / d_int_rate);  // number of items to skip ahead by
202       count += ss;                       // we have fully consumed another input
203       j = j % d_int_rate;                // roll filter around
204     }
205   }
206
207   // Store the current filter position and start of next sample
208   d_last_filter = j;
209   d_start_index = std::max(0, count - ninput_items[0]);
210
211   // consume all we've processed but no more than we can
212   consume_each(std::min(count, ninput_items[0]));
213   return i;
214 }