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>
38 gr_clock_recovery_mm_cc_sptr
39 gr_make_clock_recovery_mm_cc(float omega, float gain_omega, float mu, float gain_mu,
40 float omega_relative_limit)
42 return gr_clock_recovery_mm_cc_sptr (new gr_clock_recovery_mm_cc (omega,
46 omega_relative_limit));
49 gr_clock_recovery_mm_cc::gr_clock_recovery_mm_cc (float omega, float gain_omega, float mu,
50 float gain_mu, float omega_relative_limit)
51 : gr_block ("clock_recovery_mm_cc",
52 gr_make_io_signature (1, 1, sizeof (gr_complex)),
53 gr_make_io_signature (1, 2, sizeof (gr_complex))),
54 d_mu (mu), d_omega(omega), d_gain_omega(gain_omega),
55 d_omega_relative_limit(omega_relative_limit),
56 d_gain_mu(gain_mu), d_last_sample(0), d_interp(new gri_mmse_fir_interpolator_cc()),
57 d_verbose(gr_prefs::singleton()->get_bool("clock_recovery_mm_cc", "verbose", false)),
58 d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0)
61 throw std::out_of_range ("clock rate must be > 0");
62 if (gain_mu < 0 || gain_omega < 0)
63 throw std::out_of_range ("Gains must be non-negative");
65 set_omega(omega); // also sets min and max omega
66 set_relative_rate (1.0 / omega);
67 set_history(3); // ensure 2 extra input sample is available
70 gr_clock_recovery_mm_cc::~gr_clock_recovery_mm_cc ()
76 gr_clock_recovery_mm_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required)
78 unsigned ninputs = ninput_items_required.size();
79 for (unsigned i=0; i < ninputs; i++)
80 ninput_items_required[i] =
81 (int) ceil((noutput_items * d_omega) + d_interp->ntaps());
85 gr_clock_recovery_mm_cc::slicer_0deg (gr_complex sample)
93 return gr_complex(real,imag);
97 gr_clock_recovery_mm_cc::slicer_45deg (gr_complex sample)
99 float real= -1, imag = -1;
100 if(sample.real() > 0)
102 if(sample.imag() > 0)
104 return gr_complex(real,imag);
108 Modified Mueller and Muller clock recovery circuit
110 G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller
111 algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033.
114 static const int FUDGE = 16;
117 gr_clock_recovery_mm_cc::general_work (int noutput_items,
118 gr_vector_int &ninput_items,
119 gr_vector_const_void_star &input_items,
120 gr_vector_void_star &output_items)
122 const gr_complex *in = (const gr_complex *) input_items[0];
123 gr_complex *out = (gr_complex *) output_items[0];
124 gr_complex *foptr = (gr_complex *) output_items[1];
126 bool write_foptr = output_items.size() >= 2;
128 int ii = 0; // input index
129 int oo = 0; // output index
130 int ni = ninput_items[0] - d_interp->ntaps() - FUDGE; // don't use more input than this
138 // This loop writes the error to the second output, if it exists
140 while(oo < noutput_items && ii < ni) {
143 d_p_0T = d_interp->interpolate (&in[ii], d_mu);
147 d_c_0T = slicer_0deg(d_p_0T);
149 x = (d_c_0T - d_c_2T) * conj(d_p_1T);
150 y = (d_p_0T - d_p_2T) * conj(d_c_1T);
156 mm_val = gr_branchless_clip(mm_val,1.0);
157 d_omega = d_omega + d_gain_omega * mm_val;
158 d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
160 d_mu = d_mu + d_omega + d_gain_mu * mm_val;
161 ii += (int)floor(d_mu);
164 // write the error signal to the second output
165 foptr[oo-1] = gr_complex(d_mu,0);
167 if (ii < 0) // clamp it. This should only happen with bogus input
171 // This loop does not write to the second output (ugly, but faster)
173 while(oo < noutput_items && ii < ni) {
176 d_p_0T = d_interp->interpolate (&in[ii], d_mu);
180 d_c_0T = slicer_0deg(d_p_0T);
182 x = (d_c_0T - d_c_2T) * conj(d_p_1T);
183 y = (d_p_0T - d_p_2T) * conj(d_c_1T);
189 mm_val = gr_branchless_clip(mm_val,1.0);
191 d_omega = d_omega + d_gain_omega * mm_val;
192 d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
194 d_mu = d_mu + d_omega + d_gain_mu * mm_val;
195 ii += (int)floor(d_mu);
199 printf("%f\t%f\n", d_omega, d_mu);
202 if (ii < 0) // clamp it. This should only happen with bogus input
208 if (ii > ninput_items[0]){
209 fprintf(stderr, "gr_clock_recovery_mm_cc: ii > ninput_items[0] (%d > %d)\n",
210 ii, ninput_items[0]);