root / gnuradio-core / src / lib / filter / gr_pfb_arb_resampler_ccf.cc @ a151e3e1
History | View | Annotate | Download (6.6 kB)
| 1 | /* -*- c++ -*- */
|
|---|---|
| 2 | /*
|
| 3 | * Copyright 2009,2010 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 gnuradio::get_initial_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 | d_acc = 0; // start accumulator at 0 |
| 51 | |
| 52 | /* The number of filters is specified by the user as the filter size;
|
| 53 | this is also the interpolation rate of the filter. We use it and the |
| 54 | rate provided to determine the decimation rate. This acts as a |
| 55 | rational resampler. The flt_rate is calculated as the residual |
| 56 | between the integer decimation rate and the real decimation rate and |
| 57 | will be used to determine to interpolation point of the resampling |
| 58 | process. |
| 59 | */ |
| 60 | d_int_rate = filter_size; |
| 61 | set_rate(rate); |
| 62 | |
| 63 | // Store the last filter between calls to work
|
| 64 | d_last_filter = 0;
|
| 65 | |
| 66 | d_start_index = 0;
|
| 67 | |
| 68 | d_filters = std::vector<gr_fir_ccf*>(d_int_rate); |
| 69 | d_diff_filters = std::vector<gr_fir_ccf*>(d_int_rate); |
| 70 | |
| 71 | // Create an FIR filter for each channel and zero out the taps
|
| 72 | std::vector<float> vtaps(0, d_int_rate); |
| 73 | for(unsigned int i = 0; i < d_int_rate; i++) { |
| 74 | d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); |
| 75 | d_diff_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); |
| 76 | } |
| 77 | |
| 78 | // Now, actually set the filters' taps
|
| 79 | std::vector<float> dtaps;
|
| 80 | create_diff_taps(taps, dtaps); |
| 81 | create_taps(taps, d_taps, d_filters); |
| 82 | create_taps(dtaps, d_dtaps, d_diff_filters); |
| 83 | } |
| 84 | |
| 85 | gr_pfb_arb_resampler_ccf::~gr_pfb_arb_resampler_ccf () |
| 86 | {
|
| 87 | for(unsigned int i = 0; i < d_int_rate; i++) { |
| 88 | delete d_filters[i];
|
| 89 | } |
| 90 | } |
| 91 | |
| 92 | void
|
| 93 | gr_pfb_arb_resampler_ccf::create_taps (const std::vector<float> &newtaps, |
| 94 | std::vector< std::vector<float> > &ourtaps,
|
| 95 | std::vector<gr_fir_ccf*> &ourfilter) |
| 96 | {
|
| 97 | unsigned int ntaps = newtaps.size(); |
| 98 | d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate); |
| 99 | |
| 100 | // Create d_numchan vectors to store each channel's taps
|
| 101 | ourtaps.resize(d_int_rate); |
| 102 | |
| 103 | // Make a vector of the taps plus fill it out with 0's to fill
|
| 104 | // each polyphase filter with exactly d_taps_per_filter
|
| 105 | std::vector<float> tmp_taps;
|
| 106 | tmp_taps = newtaps; |
| 107 | while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) { |
| 108 | tmp_taps.push_back(0.0); |
| 109 | } |
| 110 | |
| 111 | // Partition the filter
|
| 112 | for(unsigned int i = 0; i < d_int_rate; i++) { |
| 113 | // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
|
| 114 | ourtaps[d_int_rate-1-i] = std::vector<float>(d_taps_per_filter, 0); |
| 115 | for(unsigned int j = 0; j < d_taps_per_filter; j++) { |
| 116 | ourtaps[d_int_rate - 1 - i][j] = tmp_taps[i + j*d_int_rate];
|
| 117 | } |
| 118 | |
| 119 | // Build a filter for each channel and add it's taps to it
|
| 120 | ourfilter[i]->set_taps(ourtaps[d_int_rate-1-i]);
|
| 121 | } |
| 122 | |
| 123 | // Set the history to ensure enough input items for each filter
|
| 124 | set_history (d_taps_per_filter + 1);
|
| 125 | |
| 126 | d_updated = true;
|
| 127 | } |
| 128 | |
| 129 | void
|
| 130 | gr_pfb_arb_resampler_ccf::create_diff_taps(const std::vector<float> &newtaps, |
| 131 | std::vector<float> &difftaps)
|
| 132 | {
|
| 133 | // Calculate the differential taps (derivative filter) by taking the difference
|
| 134 | // between two taps. Duplicate the last one to make both filters the same length.
|
| 135 | float tap;
|
| 136 | difftaps.clear(); |
| 137 | for(unsigned int i = 0; i < newtaps.size()-1; i++) { |
| 138 | tap = newtaps[i+1] - newtaps[i];
|
| 139 | difftaps.push_back(tap); |
| 140 | } |
| 141 | difftaps.push_back(tap); |
| 142 | } |
| 143 | |
| 144 | void
|
| 145 | gr_pfb_arb_resampler_ccf::print_taps() |
| 146 | {
|
| 147 | unsigned int i, j; |
| 148 | for(i = 0; i < d_int_rate; i++) { |
| 149 | printf("filter[%d]: [", i);
|
| 150 | for(j = 0; j < d_taps_per_filter; j++) { |
| 151 | printf(" %.4e", d_taps[i][j]);
|
| 152 | } |
| 153 | printf("]\n");
|
| 154 | } |
| 155 | } |
| 156 | |
| 157 | int
|
| 158 | gr_pfb_arb_resampler_ccf::general_work (int noutput_items,
|
| 159 | gr_vector_int &ninput_items, |
| 160 | gr_vector_const_void_star &input_items, |
| 161 | gr_vector_void_star &output_items) |
| 162 | {
|
| 163 | gr_complex *in = (gr_complex *) input_items[0];
|
| 164 | gr_complex *out = (gr_complex *) output_items[0];
|
| 165 | |
| 166 | if (d_updated) {
|
| 167 | d_updated = false;
|
| 168 | return 0; // history requirements may have changed. |
| 169 | } |
| 170 | |
| 171 | int i = 0, count = d_start_index; |
| 172 | unsigned int j; |
| 173 | gr_complex o0, o1; |
| 174 | |
| 175 | // Restore the last filter position
|
| 176 | j = d_last_filter; |
| 177 | |
| 178 | // produce output as long as we can and there are enough input samples
|
| 179 | int max_input = ninput_items[0]-(int)d_taps_per_filter; |
| 180 | while((i < noutput_items) && (count < max_input)) {
|
| 181 | // start j by wrapping around mod the number of channels
|
| 182 | while((j < d_int_rate) && (i < noutput_items)) {
|
| 183 | // Take the current filter and derivative filter output
|
| 184 | o0 = d_filters[j]->filter(&in[count]); |
| 185 | o1 = d_diff_filters[j]->filter(&in[count]); |
| 186 | |
| 187 | out[i] = o0 + o1*d_acc; // linearly interpolate between samples
|
| 188 | i++; |
| 189 | |
| 190 | // Adjust accumulator and index into filterbank
|
| 191 | d_acc += d_flt_rate; |
| 192 | j += d_dec_rate + (int)floor(d_acc);
|
| 193 | d_acc = fmodf(d_acc, 1.0); |
| 194 | } |
| 195 | if(i < noutput_items) { // keep state for next entry |
| 196 | float ss = (int)(j / d_int_rate); // number of items to skip ahead by |
| 197 | count += ss; // we have fully consumed another input
|
| 198 | j = j % d_int_rate; // roll filter around
|
| 199 | } |
| 200 | } |
| 201 | |
| 202 | // Store the current filter position and start of next sample
|
| 203 | d_last_filter = j; |
| 204 | d_start_index = std::max(0, count - ninput_items[0]); |
| 205 | |
| 206 | // consume all we've processed but no more than we can
|
| 207 | consume_each(std::min(count, ninput_items[0]));
|
| 208 | return i;
|
| 209 | } |