/* -*- c++ -*- */ /* * Copyright 2002 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. */ #include #include #include "fpll_btloop_coupling.h" #include #include #include #include using std::abs; static const int DEC = 2; // nominal decimation factor /* * I strongly suggest that you not mess with these... */ static const double DEFAULT_TIMING_RATE = 2.19e-4 / FPLL_BTLOOP_COUPLING_CONST; static const double DEFAULT_LOOP_TAP = 0.05; GrAtscBitTimingLoop::GrAtscBitTimingLoop () : VrDecimatingSigProc (1, DEC), next_input(0), w (1.0), mu (0.5), last_right(0), debug_no_update (false) { d_timing_rate = DEFAULT_TIMING_RATE; loop.set_taps (DEFAULT_LOOP_TAP); history = 1500; // spare input samples in case we need them. #ifdef _BT_DIAG_OUTPUT_ fp_loop = fopen ("loop.out", "w"); if (fp_loop == 0){ perror ("loop.out"); exit (1); } fp_ps = fopen ("ps.out", "w"); if (fp_ps == 0){ perror ("ps.out"); exit (1); } #endif } // // We are nominally a 2x decimator, but our actual rate varies slightly // depending on the difference between the transmitter and receiver // sampling clocks. Hence, we need to compute our input ranges // explictly. int GrAtscBitTimingLoop::forecast(VrSampleRange output, VrSampleRange inputs[]) { /* dec:1 ratio with history */ for(unsigned int i=0;i limit) e = limit; else if (e < -limit) e = -limit; return loop.filter (e); } int GrAtscBitTimingLoop::work (VrSampleRange output, void *ao[], VrSampleRange inputs[], void *ai[]) { iType *in = ((iType **)ai)[0]; oType *out = ((oType **)ao)[0]; // Force in-order computation of output stream. // This is required because of our slightly variable decimation factor sync (output.index); // We are tasked with producing output.size output samples. // We will consume approximately 2 * output.size input samples. unsigned int ii = 0; // input index unsigned int k; // output index // We look at a window of 3 samples that we call left (oldest), // middle, right (newest). Each time through the loop, the previous // right becomes the new left, and the new samples are middle and // right. // // The basic game plan is to drive the average difference between // right and left to zero. Given that all transitions are // equiprobable (the data is white) and that the composite matched // filter is symmetric (raised cosine) it turns out that in the // average, if we drive that difference to zero, (implying that the // average slope at the middle point is zero), we'll be sampling // middle at the maximum or minimum point in the pulse. iType left; iType middle; iType right = last_right; for (k = 0; k < output.size; k++){ left = right; middle = produce_sample (in, ii); right = produce_sample (in, ii); // assert (ii < inputs[0].size); if (!(ii < inputs[0].size)){ fprintf (stderr, "ii < inputs[0].size\n"); fprintf (stderr, "ii = %d, inputs[0].size = %lu, k = %d, output.size = %lu\n", ii, inputs[0].size, k, output.size); assert (0); } out[k] = middle; // produce our output double timing_error = -middle * ((double) right - left); // update_timing_control_word double filtered_timing_error = filter_error (timing_error); if (!debug_no_update){ mu += filtered_timing_error * d_timing_rate; } #ifdef _BT_DIAG_OUTPUT_ float iodata[8]; iodata[0] = left; iodata[1] = middle; iodata[2] = right; iodata[3] = timing_error; iodata[4] = filtered_timing_error; iodata[5] = mu; iodata[6] = w; iodata[7] = 0; if (fwrite (iodata, sizeof (iodata), 1, fp_loop) != 1){ perror ("fwrite: loop"); exit (1); } #endif } last_right = right; next_input += ii; // update next_input so forecast can get us what we need return output.size; } /*! * Produce samples equally spaced in time that are referenced * to the transmitter's sample clock, not ours. * * See pp 523-527 of "Digital Communication Receivers", Meyr, * Moeneclaey and Fechtel, Wiley, 1998. */ GrAtscBitTimingLoop::iType GrAtscBitTimingLoop::produce_sample (const iType *in, unsigned int &index) { // update mu and index as function of control word, w double sum = mu + w; double f = floor (sum); int incr = (int) f; // mostly 1, rarely 0 or 2 mu = sum - f; assert (0 <= incr && incr <= 2); assert (0.0 <= mu && mu <= 1.0); index += incr; iType n = intr.interpolate (&in[index], mu); #if defined(_BT_DIAG_OUTPUT_) && 0 float iodata[4]; iodata[0] = incr; iodata[1] = mu; iodata[2] = w; iodata[3] = 0; if (fwrite (iodata, sizeof (iodata), 1, fp_ps) != 1){ perror ("fwrite: ps"); exit (1); } #endif return n; }