3 * Copyright 2002 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
23 #include <GrAtscFPLL.h>
25 #include "fpll_btloop_coupling.h"
28 * I strongly suggest that you not mess with these...
30 * They are strongly coupled into the symbol timing code and
31 * their value also sets the level of the symbols going
32 * into the equalizer and viterbi decoder.
34 static const float FPLL_AGC_REFERENCE = 2.5 * FPLL_BTLOOP_COUPLING_CONST;
35 static const float FPLL_AGC_RATE = 0.25e-6;
38 GrAtscFPLL::GrAtscFPLL (double a_initial_freq)
39 : VrSigProc (1, sizeof (iType), sizeof (oType)),
40 initial_phase(0), debug_no_update(false)
42 initial_freq = a_initial_freq;
43 agc.set_rate (FPLL_AGC_RATE);
44 agc.set_reference (FPLL_AGC_REFERENCE);
46 if (_FPLL_DIAG_OUTPUT_){
47 fp = fopen ("fpll.out", "w");
57 GrAtscFPLL::initialize ()
59 float Fs = getInputSamplingFrequencyN (0);
61 float alpha = 1 - exp(-1.0 / Fs / 5e-6);
63 afci.set_taps (alpha);
64 afcq.set_taps (alpha);
66 nco.set_freq (initial_freq / Fs * 2 * M_PI);
67 nco.set_phase (initial_phase);
71 GrAtscFPLL::work (VrSampleRange output, void *ao[],
72 VrSampleRange inputs[], void *ai[])
74 iType *in = ((iType **)ai)[0];
75 oType *out = ((oType **)ao)[0];
79 for (k = 0; k < output.size; k++){
83 float input = agc.scale (in[k]);
85 nco.step (); // increment phase
86 nco.sincos (a_sin, a_cos); // compute cos and sin
88 float I = input * a_sin;
89 float Q = input * a_cos;
93 float filtered_I = afci.filter (I);
94 float filtered_Q = afcq.filter (Q);
98 float x = atan2 (filtered_Q, filtered_I);
100 // avoid slamming filter with big transitions
102 static const float limit = M_PI / 2;
109 // static const float alpha = 0.037; // Max value
110 // static const float alpha = 0.005; // takes about 5k samples to pull in, stddev = 323
111 // static const float alpha = 0.002; // takes about 15k samples to pull in, stddev = 69
112 // or about 120k samples on noisy data,
113 static const float alpha = 0.001;
114 static const float beta = alpha * alpha / 4;
117 if (!debug_no_update){
118 nco.adjust_phase (alpha * x);
119 nco.adjust_freq (beta * x);
122 if (_FPLL_DIAG_OUTPUT_){
123 #if 0 // lots of data...
125 iodata[0] = nco.get_freq () * getSamplingFrequency () * (1.0 / (2 * M_PI));
130 iodata[5] = filtered_I;
131 iodata[6] = filtered_Q;
133 if (fwrite (iodata, sizeof (iodata), 1, fp) != 1){
134 perror ("fwrite: fpll");
137 #else // just the frequency
139 iodata[0] = nco.get_freq () * getSamplingFrequency () * (1.0 / (2 * M_PI));
140 if (fwrite (iodata, sizeof (iodata), 1, fp) != 1){
141 perror ("fwrite: fpll");