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);
154 mm_val = gr_branchless_clip(mm_val,1.0);
155 d_omega = d_omega + d_gain_omega * mm_val;
156 d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
158 d_mu = d_mu + d_omega + d_gain_mu * mm_val;
159 ii += (int)floor(d_mu);
162 // write the error signal to the second output
163 foptr[oo-1] = gr_complex(d_mu,0);
165 if (ii < 0) // clamp it. This should only happen with bogus input
169 // This loop does not write to the second output (ugly, but faster)
171 while(oo < noutput_items && ii < ni) {
174 d_p_0T = d_interp->interpolate (&in[ii], d_mu);
178 d_c_0T = slicer_0deg(d_p_0T);
180 x = (d_c_0T - d_c_2T) * conj(d_p_1T);
181 y = (d_p_0T - d_p_2T) * conj(d_c_1T);
187 mm_val = gr_branchless_clip(mm_val,1.0);
189 d_omega = d_omega + d_gain_omega * mm_val;
190 d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
192 d_mu = d_mu + d_omega + d_gain_mu * mm_val;
193 ii += (int)floor(d_mu);
197 printf("%f\t%f\n", d_omega, d_mu);
200 if (ii < 0) // clamp it. This should only happen with bogus input
206 if (ii > ninput_items[0]){
207 fprintf(stderr, "gr_clock_recovery_mm_cc: ii > ninput_items[0] (%d > %d)\n",
208 ii, ninput_items[0]);