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 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.
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, 2, 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];
122 gr_complex *foptr = (gr_complex *) output_items[1];
124 bool write_foptr = output_items.size() >= 2;
126 int ii = 0; // input index
127 int oo = 0; // output index
128 int ni = ninput_items[0] - d_interp->ntaps() - FUDGE; // don't use more input than this
136 // This loop writes the error to the second output, if it exists
138 while(oo < noutput_items && ii < ni) {
141 d_p_0T = d_interp->interpolate (&in[ii], d_mu);
145 d_c_0T = slicer_0deg(d_p_0T);
147 x = (d_c_0T - d_c_2T) * conj(d_p_1T);
148 y = (d_p_0T - d_p_2T) * conj(d_c_1T);
156 else if (mm_val < -1.0)
159 d_omega = d_omega + d_gain_omega * mm_val;
160 if (d_omega > d_max_omega)
161 d_omega = d_max_omega;
162 else if (d_omega < d_min_omega)
163 d_omega = d_min_omega;
165 d_mu = d_mu + d_omega + d_gain_mu * mm_val;
166 ii += (int)floor(d_mu);
170 printf("%f\t%f\n", d_omega, d_mu);
173 // write the error signal to the second output
174 foptr[oo-1] = gr_complex(d_mu,0);
176 if (ii < 0) // clamp it. This should only happen with bogus input
180 // This loop does not write to the second output (ugly, but faster)
182 while(oo < noutput_items && ii < ni) {
185 d_p_0T = d_interp->interpolate (&in[ii], d_mu);
189 d_c_0T = slicer_0deg(d_p_0T);
191 x = (d_c_0T - d_c_2T) * conj(d_p_1T);
192 y = (d_p_0T - d_p_2T) * conj(d_c_1T);
200 else if (mm_val < -1.0)
203 d_omega = d_omega + d_gain_omega * mm_val;
204 if (d_omega > d_max_omega)
205 d_omega = d_max_omega;
206 else if (d_omega < d_min_omega)
207 d_omega = d_min_omega;
209 d_mu = d_mu + d_omega + d_gain_mu * mm_val;
210 ii += (int)floor(d_mu);
214 printf("%f\t%f\n", d_omega, d_mu);
217 if (ii < 0) // clamp it. This should only happen with bogus input
223 if (ii > ninput_items[0]){
224 fprintf(stderr, "gr_clock_recovery_mm_cc: ii > ninput_items[0] (%d > %d)\n",
225 ii, ninput_items[0]);