diff options
author | Johnathan Corgan | 2009-10-31 10:17:20 -0700 |
---|---|---|
committer | Johnathan Corgan | 2009-10-31 10:28:19 -0700 |
commit | 0b9a0ba3594c8a4226319402f3c02d53d404c5a2 (patch) | |
tree | 93990c2ae645f0ec0baf3224b165f2592243a9e1 /gnuradio-core/src | |
parent | adea1236b66851b2fff0f3c313d18d1435cfe8bf (diff) | |
download | gnuradio-0b9a0ba3594c8a4226319402f3c02d53d404c5a2.tar.gz gnuradio-0b9a0ba3594c8a4226319402f3c02d53d404c5a2.tar.bz2 gnuradio-0b9a0ba3594c8a4226319402f3c02d53d404c5a2.zip |
core: added gr.pfb_clock_sync_fff based on _ccf version, updated example
Diffstat (limited to 'gnuradio-core/src')
-rw-r--r-- | gnuradio-core/src/lib/filter/Makefile.am | 7 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc | 4 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc | 281 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h | 128 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.i | 54 |
5 files changed, 470 insertions, 4 deletions
diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index d5afd571b..9cd6e9f38 100644 --- a/gnuradio-core/src/lib/filter/Makefile.am +++ b/gnuradio-core/src/lib/filter/Makefile.am @@ -206,7 +206,8 @@ libfilter_la_common_SOURCES = \ gr_pfb_decimator_ccf.cc \ gr_pfb_interpolator_ccf.cc \ gr_pfb_arb_resampler_ccf.cc \ - gr_pfb_clock_sync_ccf.cc + gr_pfb_clock_sync_ccf.cc \ + gr_pfb_clock_sync_fff.cc libfilter_qa_la_common_SOURCES = \ qa_filter.cc \ @@ -286,7 +287,8 @@ grinclude_HEADERS = \ gr_pfb_decimator_ccf.h \ gr_pfb_interpolator_ccf.h \ gr_pfb_arb_resampler_ccf.h \ - gr_pfb_clock_sync_ccf.h + gr_pfb_clock_sync_ccf.h \ + gr_pfb_clock_sync_fff.h noinst_HEADERS = \ assembly.h \ @@ -342,6 +344,7 @@ swiginclude_HEADERS = \ gr_pfb_interpolator_ccf.i \ gr_pfb_arb_resampler_ccf.i \ gr_pfb_clock_sync_ccf.i \ + gr_pfb_clock_sync_fff.i \ $(GENERATED_I) endif diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc index 433b7d613..59454afe5 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc @@ -45,8 +45,8 @@ gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain, max_rate_deviation)); } -int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; -std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); +static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; +static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (double sps, float gain, const std::vector<float> &taps, unsigned int filter_size, diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc new file mode 100644 index 000000000..d1d2f05db --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc @@ -0,0 +1,281 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <cstdio> +#include <cmath> + +#include <gr_pfb_clock_sync_fff.h> +#include <gr_fir_fff.h> +#include <gr_fir_util.h> +#include <gr_io_signature.h> +#include <gr_math.h> + +gr_pfb_clock_sync_fff_sptr gr_make_pfb_clock_sync_fff (double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation) +{ + return gr_pfb_clock_sync_fff_sptr (new gr_pfb_clock_sync_fff (sps, gain, taps, + filter_size, + init_phase, + max_rate_deviation)); +} + +static int ios[] = {sizeof(float), sizeof(float), sizeof(float), sizeof(float)}; +static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); +gr_pfb_clock_sync_fff::gr_pfb_clock_sync_fff (double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation) + : gr_block ("pfb_clock_sync_fff", + gr_make_io_signature (1, 1, sizeof(float)), + gr_make_io_signaturev (1, 4, iosig)), + d_updated (false), d_nfilters(filter_size), + d_max_dev(max_rate_deviation) +{ + d_nfilters = filter_size; + d_sps = floor(sps); + + // Store the last filter between calls to work + // The accumulator keeps track of overflow to increment the stride correctly. + // set it here to the fractional difference based on the initial phaes + set_alpha(gain); + set_beta(0.25*gain*gain); + d_k = init_phase; + d_rate = (sps-floor(sps))*(double)d_nfilters; + d_rate_i = (int)floor(d_rate); + d_rate_f = d_rate - (float)d_rate_i; + d_filtnum = (int)floor(d_k); + + d_filters = std::vector<gr_fir_fff*>(d_nfilters); + d_diff_filters = std::vector<gr_fir_fff*>(d_nfilters); + + // Create an FIR filter for each channel and zero out the taps + std::vector<float> vtaps(0, d_nfilters); + for(int i = 0; i < d_nfilters; i++) { + d_filters[i] = gr_fir_util::create_gr_fir_fff(vtaps); + d_diff_filters[i] = gr_fir_util::create_gr_fir_fff(vtaps); + } + + // Now, actually set the filters' taps + std::vector<float> dtaps; + create_diff_taps(taps, dtaps); + set_taps(taps, d_taps, d_filters); + set_taps(dtaps, d_dtaps, d_diff_filters); +} + +gr_pfb_clock_sync_fff::~gr_pfb_clock_sync_fff () +{ + for(int i = 0; i < d_nfilters; i++) { + delete d_filters[i]; + } +} + +void +gr_pfb_clock_sync_fff::set_taps (const std::vector<float> &newtaps, + std::vector< std::vector<float> > &ourtaps, + std::vector<gr_fir_fff*> &ourfilter) +{ + int i,j; + + unsigned int ntaps = newtaps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilters); + + // Create d_numchan vectors to store each channel's taps + ourtaps.resize(d_nfilters); + + // Make a vector of the taps plus fill it out with 0's to fill + // each polyphase filter with exactly d_taps_per_filter + std::vector<float> tmp_taps; + tmp_taps = newtaps; + while((float)(tmp_taps.size()) < d_nfilters*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(i = 0; i < d_nfilters; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + ourtaps[d_nfilters-1-i] = std::vector<float>(d_taps_per_filter, 0); + for(j = 0; j < d_taps_per_filter; j++) { + ourtaps[d_nfilters - 1 - i][j] = tmp_taps[i + j*d_nfilters]; + } + + // Build a filter for each channel and add it's taps to it + ourfilter[i]->set_taps(ourtaps[d_nfilters-1-i]); + } + + // Set the history to ensure enough input items for each filter + set_history (d_taps_per_filter + d_sps); + + d_updated = true; +} + +void +gr_pfb_clock_sync_fff::create_diff_taps(const std::vector<float> &newtaps, + std::vector<float> &difftaps) +{ + float maxtap = 1e-20; + difftaps.clear(); + difftaps.push_back(0); //newtaps[0]); + for(unsigned int i = 1; i < newtaps.size()-1; i++) { + float tap = newtaps[i+1] - newtaps[i-1]; + difftaps.push_back(tap); + if(tap > maxtap) { + maxtap = tap; + } + } + difftaps.push_back(0);//-newtaps[newtaps.size()-1]); + + // Scale the differential taps; helps scale error term to better update state + // FIXME: should this be scaled this way or use the same gain as the taps? + for(unsigned int i = 0; i < difftaps.size(); i++) { + difftaps[i] /= maxtap; + } +} + +void +gr_pfb_clock_sync_fff::print_taps() +{ + int i, j; + printf("[ "); + for(i = 0; i < d_nfilters; i++) { + printf("[%.4e, ", d_taps[i][0]); + for(j = 1; j < d_taps_per_filter-1; j++) { + printf("%.4e,", d_taps[i][j]); + } + printf("%.4e],", d_taps[i][j]); + } + printf(" ]\n"); +} + +void +gr_pfb_clock_sync_fff::print_diff_taps() +{ + int i, j; + printf("[ "); + for(i = 0; i < d_nfilters; i++) { + printf("[%.4e, ", d_dtaps[i][0]); + for(j = 1; j < d_taps_per_filter-1; j++) { + printf("%.4e,", d_dtaps[i][j]); + } + printf("%.4e],", d_dtaps[i][j]); + } + printf(" ]\n"); +} + + +std::vector<float> +gr_pfb_clock_sync_fff::channel_taps(int channel) +{ + std::vector<float> taps; + for(int i = 0; i < d_taps_per_filter; i++) { + taps.push_back(d_taps[channel][i]); + } + return taps; +} + +std::vector<float> +gr_pfb_clock_sync_fff::diff_channel_taps(int channel) +{ + std::vector<float> taps; + for(int i = 0; i < d_taps_per_filter; i++) { + taps.push_back(d_dtaps[channel][i]); + } + return taps; +} + + +int +gr_pfb_clock_sync_fff::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + float *in = (float *) input_items[0]; + float *out = (float *) output_items[0]; + + float *err, *outrate, *outk; + if(output_items.size() > 2) { + err = (float *) output_items[1]; + outrate = (float*)output_items[2]; + outk = (float*)output_items[3]; + } + + if (d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + // We need this many to process one output + int nrequired = ninput_items[0] - d_taps_per_filter; + + int i = 0, count = 0; + float error; + + // produce output as long as we can and there are enough input samples + while((i < noutput_items) && (count < nrequired)) { + d_filtnum = (int)floor(d_k); + + // Keep the current filter number in [0, d_nfilters] + // If we've run beyond the last filter, wrap around and go to next sample + // If we've go below 0, wrap around and go to previous sample + while(d_filtnum >= d_nfilters) { + d_k -= d_nfilters; + d_filtnum -= d_nfilters; + count += 1; + } + while(d_filtnum < 0) { + d_k += d_nfilters; + d_filtnum += d_nfilters; + count -= 1; + } + + out[i] = d_filters[d_filtnum]->filter(&in[count]); + float diff = d_diff_filters[d_filtnum]->filter(&in[count]); + error = out[i] * diff; + + // Run the control loop to update the current phase (k) and tracking rate + d_k = d_k + d_alpha*error + d_rate_i + d_rate_f; + d_rate_f = d_rate_f + d_beta*error; + + // Keep our rate within a good range + d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev); + + i++; + count += (int)floor(d_sps); + + if(output_items.size() > 2) { + err[i] = error; + outrate[i] = d_rate_f; + outk[i] = d_k; + } + } + consume_each(count); + + return i; +} diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h new file mode 100644 index 000000000..913f798fe --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h @@ -0,0 +1,128 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_GR_PFB_CLOCK_SYNC_FFF_H +#define INCLUDED_GR_PFB_CLOCK_SYNC_FFF_H + +#include <gr_block.h> + +class gr_pfb_clock_sync_fff; +typedef boost::shared_ptr<gr_pfb_clock_sync_fff> gr_pfb_clock_sync_fff_sptr; +gr_pfb_clock_sync_fff_sptr gr_make_pfb_clock_sync_fff (double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size=32, + float init_phase=0, + float max_rate_deviation=1.5); + +class gr_fir_fff; + +/*! + * \class gr_pfb_clock_sync_fff + * + * \brief Timing synchronizer using polyphase filterbanks + * + * \ingroup filter_blk + * + */ + +class gr_pfb_clock_sync_fff : public gr_block +{ + private: + /*! + * Build the polyphase filterbank timing synchronizer. + */ + friend gr_pfb_clock_sync_fff_sptr gr_make_pfb_clock_sync_fff (double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation); + + bool d_updated; + double d_sps; + double d_sample_num; + float d_alpha; + float d_beta; + int d_nfilters; + std::vector<gr_fir_fff*> d_filters; + std::vector<gr_fir_fff*> d_diff_filters; + std::vector< std::vector<float> > d_taps; + std::vector< std::vector<float> > d_dtaps; + float d_k; + float d_rate; + float d_rate_i; + float d_rate_f; + float d_max_dev; + int d_filtnum; + int d_taps_per_filter; + + /*! + * Build the polyphase filterbank timing synchronizer. + */ + gr_pfb_clock_sync_fff (double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation); + + void create_diff_taps(const std::vector<float> &newtaps, + std::vector<float> &difftaps); + +public: + ~gr_pfb_clock_sync_fff (); + + /*! + * Resets the filterbank's filter taps with the new prototype filter + */ + void set_taps (const std::vector<float> &taps, + std::vector< std::vector<float> > &ourtaps, + std::vector<gr_fir_fff*> &ourfilter); + std::vector<float> channel_taps(int channel); + std::vector<float> diff_channel_taps(int channel); + + /*! + * Print all of the filterbank taps to screen. + */ + void print_taps(); + void print_diff_taps(); + + void set_alpha(float alpha) + { + d_alpha = alpha; + } + void set_beta(float beta) + { + d_beta = beta; + } + + void set_max_rate_deviation(float m) + { + d_max_dev = m; + } + + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.i b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.i new file mode 100644 index 000000000..d6bb7873c --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.i @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +GR_SWIG_BLOCK_MAGIC(gr,pfb_clock_sync_fff); + +gr_pfb_clock_sync_fff_sptr gr_make_pfb_clock_sync_fff (double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size=32, + float init_phase=0, + float max_rate_deviation=1.5); + +class gr_pfb_clock_sync_fff : public gr_block +{ + private: + gr_pfb_clock_sync_fff (double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation); + + public: + ~gr_pfb_clock_sync_fff (); + + void set_taps (const std::vector<float> &taps, + std::vector< std::vector<float> > &ourtaps, + std::vector<gr_fir_fff*> &ourfilter); + + std::vector<float> channel_taps(int channel); + std::vector<float> diff_channel_taps(int channel); + void print_taps(); + void print_diff_taps(); + void set_alpha(float alpha); + void set_beta(float beta); + void set_max_rate_deviation(float m); +}; |