3 * Copyright 2005,2006 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 2, 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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include <gr_io_signature.h>
29 #include <gr_clock_recovery_mm_cc.h>
30 #include <gri_mmse_fir_interpolator_cc.h>
36 gr_clock_recovery_mm_cc_sptr
37 gr_make_clock_recovery_mm_cc(float omega, float gain_omega, float mu, float gain_mu,
38 float omega_relative_limit)
40 return gr_clock_recovery_mm_cc_sptr (new gr_clock_recovery_mm_cc (omega,
44 omega_relative_limit));
47 gr_clock_recovery_mm_cc::gr_clock_recovery_mm_cc (float omega, float gain_omega, float mu,
48 float gain_mu, float omega_relative_limit)
49 : gr_block ("clock_recovery_mm_cc",
50 gr_make_io_signature (1, 1, sizeof (gr_complex)),
51 gr_make_io_signature (1, 1, sizeof (gr_complex))),
52 d_mu (mu), d_omega(omega), d_gain_omega(gain_omega),
53 d_omega_relative_limit(omega_relative_limit),
54 d_gain_mu(gain_mu), d_last_sample(0), d_interp(new gri_mmse_fir_interpolator_cc()),
55 d_verbose(gr_prefs::singleton()->get_bool("clock_recovery_mm_cc", "verbose", false)),
56 d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0)
59 throw std::out_of_range ("clock rate must be > 0");
60 if (gain_mu < 0 || gain_omega < 0)
61 throw std::out_of_range ("Gains must be non-negative");
63 set_omega(omega); // also sets min and max omega
64 set_relative_rate (1.0 / omega);
65 set_history(3); // ensure 2 extra input sample is available
68 gr_clock_recovery_mm_cc::~gr_clock_recovery_mm_cc ()
74 gr_clock_recovery_mm_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required)
76 unsigned ninputs = ninput_items_required.size();
77 for (unsigned i=0; i < ninputs; i++)
78 ninput_items_required[i] =
79 (int) ceil((noutput_items * d_omega) + d_interp->ntaps());
83 gr_clock_recovery_mm_cc::slicer_0deg (gr_complex sample)
91 return gr_complex(real,imag);
95 gr_clock_recovery_mm_cc::slicer_45deg (gr_complex sample)
97 float real= -1, imag = -1;
100 if(sample.imag() > 0)
102 return gr_complex(real,imag);
106 Modified Mueller and Muller clock recovery circuit
108 G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller
109 algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033.
112 static const int FUDGE = 16;
115 gr_clock_recovery_mm_cc::general_work (int noutput_items,
116 gr_vector_int &ninput_items,
117 gr_vector_const_void_star &input_items,
118 gr_vector_void_star &output_items)
120 const gr_complex *in = (const gr_complex *) input_items[0];
121 gr_complex *out = (gr_complex *) output_items[0];
123 int ii = 0; // input index
124 int oo = 0; // output index
125 int ni = ninput_items[0] - d_interp->ntaps() - FUDGE; // don't use more input than this
133 while(oo < noutput_items && ii < ni) {
136 d_p_0T = d_interp->interpolate (&in[ii], d_mu);
140 d_c_0T = slicer_0deg(d_p_0T);
142 x = (d_c_0T - d_c_2T) * conj(d_p_1T);
143 y = (d_p_0T - d_p_2T) * conj(d_c_1T);
151 else if (mm_val < -1.0)
154 d_omega = d_omega + d_gain_omega * mm_val;
155 if (d_omega > d_max_omega)
156 d_omega = d_max_omega;
157 else if (d_omega < d_min_omega)
158 d_omega = d_min_omega;
160 d_mu = d_mu + d_omega + d_gain_mu * mm_val;
161 ii += (int)floor(d_mu);
165 printf("%f\t%f\n", d_omega, d_mu);
168 if (ii < 0) // clamp it. This should only happen with bogus input
173 if (ii > ninput_items[0]){
174 fprintf(stderr, "gr_clock_recovery_mm_cc: ii > ninput_items[0] (%d > %d)\n",
175 ii, ninput_items[0]);