summaryrefslogtreecommitdiff
path: root/gr-digital/lib/digital_pfb_clock_sync_ccf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital/lib/digital_pfb_clock_sync_ccf.cc')
-rw-r--r--gr-digital/lib/digital_pfb_clock_sync_ccf.cc440
1 files changed, 0 insertions, 440 deletions
diff --git a/gr-digital/lib/digital_pfb_clock_sync_ccf.cc b/gr-digital/lib/digital_pfb_clock_sync_ccf.cc
deleted file mode 100644
index 1a2d5970b..000000000
--- a/gr-digital/lib/digital_pfb_clock_sync_ccf.cc
+++ /dev/null
@@ -1,440 +0,0 @@
-/* -*- 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 <cstdio>
-#include <cmath>
-
-#include <digital_pfb_clock_sync_ccf.h>
-#include <gr_fir_ccf.h>
-#include <gr_fir_util.h>
-#include <gr_io_signature.h>
-#include <gr_math.h>
-
-digital_pfb_clock_sync_ccf_sptr
-digital_make_pfb_clock_sync_ccf(double sps, float loop_bw,
- const std::vector<float> &taps,
- unsigned int filter_size,
- float init_phase,
- float max_rate_deviation,
- int osps)
-{
- return gnuradio::get_initial_sptr(new digital_pfb_clock_sync_ccf
- (sps, loop_bw, taps,
- filter_size,
- init_phase,
- max_rate_deviation,
- osps));
-}
-
-static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)};
-static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
-digital_pfb_clock_sync_ccf::digital_pfb_clock_sync_ccf (double sps, float loop_bw,
- const std::vector<float> &taps,
- unsigned int filter_size,
- float init_phase,
- float max_rate_deviation,
- int osps)
- : gr_block ("pfb_clock_sync_ccf",
- gr_make_io_signature (1, 1, sizeof(gr_complex)),
- gr_make_io_signaturev (1, 4, iosig)),
- d_updated (false), d_nfilters(filter_size),
- d_max_dev(max_rate_deviation),
- d_osps(osps), d_error(0), d_out_idx(0)
-{
- d_nfilters = filter_size;
- d_sps = floor(sps);
-
- // Set the damping factor for a critically damped system
- d_damping = sqrtf(2.0f)/2.0f;
-
- // Set the bandwidth, which will then call update_gains()
- set_loop_bandwidth(loop_bw);
-
- // 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
- 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_ccf*>(d_nfilters);
- d_diff_filters = std::vector<gr_fir_ccf*>(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_ccf(vtaps);
- d_diff_filters[i] = gr_fir_util::create_gr_fir_ccf(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);
-}
-
-digital_pfb_clock_sync_ccf::~digital_pfb_clock_sync_ccf ()
-{
- for(int i = 0; i < d_nfilters; i++) {
- delete d_filters[i];
- delete d_diff_filters[i];
- }
-}
-
-bool
-digital_pfb_clock_sync_ccf::check_topology(int ninputs, int noutputs)
-{
- return noutputs == 1 || noutputs == 4;
-}
-
-
-
-/*******************************************************************
- SET FUNCTIONS
-*******************************************************************/
-
-
-void
-digital_pfb_clock_sync_ccf::set_loop_bandwidth(float bw)
-{
- if(bw < 0) {
- throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid bandwidth. Must be >= 0.");
- }
-
- d_loop_bw = bw;
- update_gains();
-}
-
-void
-digital_pfb_clock_sync_ccf::set_damping_factor(float df)
-{
- if(df < 0 || df > 1.0) {
- throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid damping factor. Must be in [0,1].");
- }
-
- d_damping = df;
- update_gains();
-}
-
-void
-digital_pfb_clock_sync_ccf::set_alpha(float alpha)
-{
- if(alpha < 0 || alpha > 1.0) {
- throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid alpha. Must be in [0,1].");
- }
- d_alpha = alpha;
-}
-
-void
-digital_pfb_clock_sync_ccf::set_beta(float beta)
-{
- if(beta < 0 || beta > 1.0) {
- throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid beta. Must be in [0,1].");
- }
- d_beta = beta;
-}
-
-/*******************************************************************
- GET FUNCTIONS
-*******************************************************************/
-
-
-float
-digital_pfb_clock_sync_ccf::get_loop_bandwidth() const
-{
- return d_loop_bw;
-}
-
-float
-digital_pfb_clock_sync_ccf::get_damping_factor() const
-{
- return d_damping;
-}
-
-float
-digital_pfb_clock_sync_ccf::get_alpha() const
-{
- return d_alpha;
-}
-
-float
-digital_pfb_clock_sync_ccf::get_beta() const
-{
- return d_beta;
-}
-
-float
-digital_pfb_clock_sync_ccf::get_clock_rate() const
-{
- return d_rate_f;
-}
-
-/*******************************************************************
-*******************************************************************/
-
-void
-digital_pfb_clock_sync_ccf::update_gains()
-{
- float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw);
- d_alpha = (4*d_damping*d_loop_bw) / denom;
- d_beta = (4*d_loop_bw*d_loop_bw) / denom;
-}
-
-
-void
-digital_pfb_clock_sync_ccf::set_taps (const std::vector<float> &newtaps,
- std::vector< std::vector<float> > &ourtaps,
- std::vector<gr_fir_ccf*> &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[i] = std::vector<float>(d_taps_per_filter, 0);
- for(j = 0; j < d_taps_per_filter; j++) {
- ourtaps[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[i]);
- }
-
- // Set the history to ensure enough input items for each filter
- set_history (d_taps_per_filter + d_sps);
-
- // Make sure there is enough output space for d_osps outputs/input.
- set_output_multiple(d_osps);
-
- d_updated = true;
-}
-
-void
-digital_pfb_clock_sync_ccf::create_diff_taps(const std::vector<float> &newtaps,
- std::vector<float> &difftaps)
-{
- std::vector<float> diff_filter(3);
- diff_filter[0] = -1;
- diff_filter[1] = 0;
- diff_filter[2] = 1;
-
- float pwr = 0;
- difftaps.push_back(0);
- for(unsigned int i = 0; i < newtaps.size()-2; i++) {
- float tap = 0;
- for(int j = 0; j < 3; j++) {
- tap += diff_filter[j]*newtaps[i+j];
- pwr += fabsf(tap);
- }
- difftaps.push_back(tap);
- }
- difftaps.push_back(0);
-
- for(unsigned int i = 0; i < difftaps.size(); i++) {
- difftaps[i] *= pwr;
- }
-}
-
-std::string
-digital_pfb_clock_sync_ccf::get_taps_as_string()
-{
- int i, j;
- std::stringstream str;
- str.precision(4);
- str.setf(std::ios::scientific);
-
- str << "[ ";
- for(i = 0; i < d_nfilters; i++) {
- str << "[" << d_taps[i][0] << ", ";
- for(j = 1; j < d_taps_per_filter-1; j++) {
- str << d_taps[i][j] << ", ";
- }
- str << d_taps[i][j] << "],";
- }
- str << " ]" << std::endl;
-
- return str.str();
-}
-
-std::string
-digital_pfb_clock_sync_ccf::get_diff_taps_as_string()
-{
- int i, j;
- std::stringstream str;
- str.precision(4);
- str.setf(std::ios::scientific);
-
- str << "[ ";
- for(i = 0; i < d_nfilters; i++) {
- str << "[" << d_dtaps[i][0] << ", ";
- for(j = 1; j < d_taps_per_filter-1; j++) {
- str << d_dtaps[i][j] << ", ";
- }
- str << d_dtaps[i][j] << "],";
- }
- str << " ]" << std::endl;
-
- return str.str();
-}
-
-std::vector< std::vector<float> >
-digital_pfb_clock_sync_ccf::get_taps()
-{
- return d_taps;
-}
-
-std::vector< std::vector<float> >
-digital_pfb_clock_sync_ccf::get_diff_taps()
-{
- return d_dtaps;
-}
-
-std::vector<float>
-digital_pfb_clock_sync_ccf::get_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>
-digital_pfb_clock_sync_ccf::get_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
-digital_pfb_clock_sync_ccf::general_work(int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
-{
- gr_complex *in = (gr_complex *) input_items[0];
- gr_complex *out = (gr_complex *) output_items[0];
-
- float *err = NULL, *outrate = NULL, *outk = NULL;
- if(output_items.size() == 4) {
- 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 - d_osps;
-
- int i = 0, count = 0;
- float error_r, error_i;
-
- // produce output as long as we can and there are enough input samples
- while((i < noutput_items) && (count < nrequired)) {
- while(d_out_idx < d_osps) {
- 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_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]);
- d_k = d_k + d_rate_i + d_rate_f; // update phase
- d_out_idx++;
-
- if(output_items.size() == 4) {
- err[i] = d_error;
- outrate[i] = d_rate_f;
- outk[i] = d_k;
- }
-
- // We've run out of output items we can create; return now.
- if(i+d_out_idx >= noutput_items) {
- consume_each(count);
- return i;
- }
- }
-
- // reset here; if we didn't complete a full osps samples last time,
- // the early return would take care of it.
- d_out_idx = 0;
-
- // Update the phase and rate estimates for this symbol
- gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]);
- error_r = out[i].real() * diff.real();
- error_i = out[i].imag() * diff.imag();
- d_error = (error_i + error_r) / 2.0; // average error from I&Q channel
-
- // Run the control loop to update the current phase (k) and
- // tracking rate estimates based on the error value
- d_rate_f = d_rate_f + d_beta*d_error;
- d_k = d_k + d_alpha*d_error;
-
- // Keep our rate within a good range
- d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev);
-
- i+=d_osps;
- count += (int)floor(d_sps);
- }
-
- consume_each(count);
- return i;
-}