diff options
Diffstat (limited to 'gr-digital/lib/fll_band_edge_cc_impl.cc')
-rw-r--r-- | gr-digital/lib/fll_band_edge_cc_impl.cc | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/gr-digital/lib/fll_band_edge_cc_impl.cc b/gr-digital/lib/fll_band_edge_cc_impl.cc new file mode 100644 index 0000000000..980d3ab464 --- /dev/null +++ b/gr-digital/lib/fll_band_edge_cc_impl.cc @@ -0,0 +1,276 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2012 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 "fll_band_edge_cc_impl.h" +#include <gr_io_signature.h> +#include <gr_expj.h> +#include <cstdio> + +namespace gr { + namespace digital { + +#define M_TWOPI (2*M_PI) + + float sinc(float x) + { + if(x == 0) + return 1; + else + return sin(M_PI*x)/(M_PI*x); + } + + fll_band_edge_cc::sptr + fll_band_edge_cc::make(float samps_per_sym, float rolloff, + int filter_size, float bandwidth) + { + return gnuradio::get_initial_sptr + (new fll_band_edge_cc_impl(samps_per_sym, rolloff, + filter_size, bandwidth)); + } + + static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; + static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); + fll_band_edge_cc_impl::fll_band_edge_cc_impl(float samps_per_sym, float rolloff, + int filter_size, float bandwidth) + : gr_sync_block("fll_band_edge_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signaturev(1, 4, iosig)), + gri_control_loop(bandwidth, M_TWOPI*(2.0/samps_per_sym), + -M_TWOPI*(2.0/samps_per_sym)), + d_updated(false) + { + // Initialize samples per symbol + if(samps_per_sym <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid number of sps. Must be > 0."); + } + d_sps = samps_per_sym; + + // Initialize rolloff factor + if(rolloff < 0 || rolloff > 1.0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1]."); + } + d_rolloff = rolloff; + + // Initialize filter length + if(filter_size <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid filter size. Must be > 0."); + } + d_filter_size = filter_size; + + // Build the band edge filters + design_filter(d_sps, d_rolloff, d_filter_size); + d_output_hist.resize(filter_size,0); + } + + fll_band_edge_cc_impl::~fll_band_edge_cc_impl() + { + } + + /******************************************************************* + SET FUNCTIONS + *******************************************************************/ + + void + fll_band_edge_cc_impl::set_samples_per_symbol(float sps) + { + if(sps <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid number of sps. Must be > 0."); + } + d_sps = sps; + design_filter(d_sps, d_rolloff, d_filter_size); + } + + void + fll_band_edge_cc_impl::set_rolloff(float rolloff) + { + if(rolloff < 0 || rolloff > 1.0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1]."); + } + d_rolloff = rolloff; + design_filter(d_sps, d_rolloff, d_filter_size); + } + + void + fll_band_edge_cc_impl::set_filter_size(int filter_size) + { + if(filter_size <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid filter size. Must be > 0."); + } + d_filter_size = filter_size; + design_filter(d_sps, d_rolloff, d_filter_size); + } + + /******************************************************************* + GET FUNCTIONS + *******************************************************************/ + + float + fll_band_edge_cc_impl::samples_per_symbol() const + { + return d_sps; + } + + float + fll_band_edge_cc_impl::rolloff() const + { + return d_rolloff; + } + + int + fll_band_edge_cc_impl::filter_size() const + { + return d_filter_size; + } + + /******************************************************************* + *******************************************************************/ + + void + fll_band_edge_cc_impl::design_filter(float samps_per_sym, + float rolloff, int filter_size) + { + int M = rint(filter_size / samps_per_sym); + float power = 0; + + // Create the baseband filter by adding two sincs together + std::vector<float> bb_taps; + for(int i = 0; i < filter_size; i++) { + float k = -M + i*2.0/samps_per_sym; + float tap = sinc(rolloff*k - 0.5) + sinc(rolloff*k + 0.5); + power += tap; + + bb_taps.push_back(tap); + } + + d_taps_lower.resize(filter_size); + d_taps_upper.resize(filter_size); + + // Create the band edge filters by spinning the baseband + // filter up and down to the right places in frequency. + // Also, normalize the power in the filters + int N = (bb_taps.size() - 1.0)/2.0; + for(int i = 0; i < filter_size; i++) { + float tap = bb_taps[i] / power; + + float k = (-N + (int)i)/(2.0*samps_per_sym); + + gr_complex t1 = tap * gr_expj(-M_TWOPI*(1+rolloff)*k); + gr_complex t2 = tap * gr_expj(M_TWOPI*(1+rolloff)*k); + + d_taps_lower[filter_size-i-1] = t1; + d_taps_upper[filter_size-i-1] = t2; + } + + d_updated = true; + + // Set the history to ensure enough input items for each filter + set_history(filter_size+1); + d_filter_upper = new gr::filter::kernel::fir_filter_ccc(1, d_taps_upper); + d_filter_lower = new gr::filter::kernel::fir_filter_ccc(1, d_taps_lower); + } + + void + fll_band_edge_cc_impl::print_taps() + { + unsigned int i; + + printf("Upper Band-edge: ["); + for(i = 0; i < d_taps_upper.size(); i++) { + printf(" %.4e + %.4ej,", d_taps_upper[i].real(), d_taps_upper[i].imag()); + } + printf("]\n\n"); + + printf("Lower Band-edge: ["); + for(i = 0; i < d_taps_lower.size(); i++) { + printf(" %.4e + %.4ej,", d_taps_lower[i].real(), d_taps_lower[i].imag()); + } + printf("]\n\n"); + } + + int + fll_band_edge_cc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + d_fllbuffer.reserve(d_filter_size+noutput_items); + + float *frq = NULL; + float *phs = NULL; + float *err = NULL; + if(output_items.size() == 4) { + frq = (float*)output_items[1]; + phs = (float*)output_items[2]; + err = (float*)output_items[3]; + } + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + int i; + float error; + gr_complex nco_out; + gr_complex out_upper, out_lower; + gr_complex out_uppersse, out_lowersse; + copy(d_output_hist.begin(), d_output_hist.end(), d_fllbuffer.begin()); + + for(i = 0; i < noutput_items; i++) { + nco_out = gr_expj(d_phase); + d_fllbuffer[i+d_filter_size] = in[i] * nco_out; + // Perform the dot product of the output with the filters + out_upper = 0; + out_lower = 0; + + out_upper = d_filter_lower->filter(&d_fllbuffer[i]); + out_lower = d_filter_upper->filter(&d_fllbuffer[i]); + + error = norm(out_lower) - norm(out_upper); + + advance_loop(error); + phase_wrap(); + frequency_limit(); + + if(output_items.size() == 4) { + frq[i] = d_freq; + phs[i] = d_phase; + err[i] = error; + } + } + + copy(d_fllbuffer.begin(), d_fllbuffer.begin()+noutput_items, out); + copy(d_fllbuffer.begin()+noutput_items, + d_fllbuffer.begin()+noutput_items+d_filter_size, + d_output_hist.begin()); + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ |