Statistics
| Branch: | Tag: | Revision:

root / gr-digital / lib / digital_clock_recovery_mm_cc.cc @ 461725e5

History | View | Annotate | Download (6.3 kB)

1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2005,2006,2010,2011 Free Software Foundation, Inc.
4
 *
5
 * This file is part of GNU Radio
6
 *
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)
10
 * any later version.
11
 *
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.
16
 *
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.
21
 */
22
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
27
#include <gr_io_signature.h>
28
#include <gr_prefs.h>
29
#include <digital_clock_recovery_mm_cc.h>
30
#include <gri_mmse_fir_interpolator_cc.h>
31
#include <stdexcept>
32
#include <cstdio>
33
34
35
// Public constructor
36
static const int FUDGE = 16;
37
38
digital_clock_recovery_mm_cc_sptr 
39
digital_make_clock_recovery_mm_cc(float omega, float gain_omega,
40
                                  float mu, float gain_mu,
41
                                  float omega_relative_limit)
42
{
43
  return gnuradio::get_initial_sptr(new digital_clock_recovery_mm_cc (omega, 
44
                                                                      gain_omega, 
45
                                                                      mu,
46
                                                                      gain_mu,
47
                                                                      omega_relative_limit));
48
}
49
50
digital_clock_recovery_mm_cc::digital_clock_recovery_mm_cc (float omega, float gain_omega,
51
                                                            float mu, float gain_mu,
52
                                                            float omega_relative_limit)
53
  : gr_block ("clock_recovery_mm_cc",
54
              gr_make_io_signature (1, 1, sizeof (gr_complex)),
55
              gr_make_io_signature2 (1, 2, sizeof (gr_complex), sizeof(float))),
56
    d_mu (mu), d_omega(omega), d_gain_omega(gain_omega), 
57
    d_omega_relative_limit(omega_relative_limit), 
58
    d_gain_mu(gain_mu), d_last_sample(0), d_interp(new gri_mmse_fir_interpolator_cc()),
59
    d_verbose(gr_prefs::singleton()->get_bool("clock_recovery_mm_cc", "verbose", false)),
60
    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
{
62
  if (omega <= 0.0)
63
    throw std::out_of_range ("clock rate must be > 0");
64
  if (gain_mu <  0  || gain_omega < 0)
65
    throw std::out_of_range ("Gains must be non-negative");
66
67
  set_omega(omega);                        // also sets min and max omega
68
  set_relative_rate (1.0 / omega);
69
  set_history(3);                        // ensure 2 extra input sample is available
70
}
71
72
digital_clock_recovery_mm_cc::~digital_clock_recovery_mm_cc ()
73
{
74
  delete d_interp;
75
}
76
77
void
78
digital_clock_recovery_mm_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required)
79
{
80
  unsigned ninputs = ninput_items_required.size();
81
  for (unsigned i=0; i < ninputs; i++)
82
    ninput_items_required[i] =
83
      (int) ceil((noutput_items * d_omega) + d_interp->ntaps()) + FUDGE;
84
}
85
86
gr_complex
87
digital_clock_recovery_mm_cc::slicer_0deg (gr_complex sample)
88
{
89
  float real=0, imag=0;
90
91
  if(sample.real() > 0)
92
    real = 1;
93
  if(sample.imag() > 0)
94
    imag = 1;
95
  return gr_complex(real,imag);
96
}
97
98
gr_complex
99
digital_clock_recovery_mm_cc::slicer_45deg (gr_complex sample)
100
{
101
  float real= -1, imag = -1;
102
  if(sample.real() > 0)
103
    real=1;
104
  if(sample.imag() > 0)
105
    imag = 1;
106
  return gr_complex(real,imag);
107
}
108
109
/*
110
  Modified Mueller and Muller clock recovery circuit
111
  Based:
112
     G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller 
113
     algorithm,"  Electronics Letters, Vol. 31, no. 13,  22 June 1995, pp. 1032 - 1033.
114
*/
115
116
int
117
digital_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)
121
{
122
  const gr_complex *in = (const gr_complex *) input_items[0];
123
  gr_complex *out = (gr_complex *) output_items[0];
124
  float *foptr = (float *) output_items[1];
125
126
  bool write_foptr = output_items.size() >= 2;
127
  
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
131
132
  assert(d_mu >= 0.0);
133
  assert(d_mu <= 1.0);
134
135
  float mm_val=0;
136
  gr_complex u, x, y;
137
138
  // This loop writes the error to the second output, if it exists
139
  if (write_foptr) {
140
    while(oo < noutput_items && ii < ni) {
141
      d_p_2T = d_p_1T;
142
      d_p_1T = d_p_0T;
143
      d_p_0T = d_interp->interpolate (&in[ii], d_mu);
144
145
      d_c_2T = d_c_1T;
146
      d_c_1T = d_c_0T;
147
      d_c_0T = slicer_0deg(d_p_0T);
148
      
149
      x = (d_c_0T - d_c_2T) * conj(d_p_1T);
150
      y = (d_p_0T - d_p_2T) * conj(d_c_1T);
151
      u = y - x;
152
      mm_val = u.real();
153
      out[oo++] = d_p_0T;
154
      
155
      // limit mm_val
156
      mm_val = gr_branchless_clip(mm_val,4.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
159
160
      d_mu = d_mu + d_omega + d_gain_mu * mm_val;
161
      ii += (int)floor(d_mu);
162
      d_mu -= floor(d_mu);
163
            
164
      // write the error signal to the second output
165
      foptr[oo-1] = mm_val;
166
      
167
      if (ii < 0)        // clamp it.  This should only happen with bogus input
168
        ii = 0;
169
    }
170
  }
171
  // This loop does not write to the second output (ugly, but faster)
172
  else {
173
    while(oo < noutput_items && ii < ni) {
174
      d_p_2T = d_p_1T;
175
      d_p_1T = d_p_0T;
176
      d_p_0T = d_interp->interpolate (&in[ii], d_mu);
177
178
      d_c_2T = d_c_1T;
179
      d_c_1T = d_c_0T;
180
      d_c_0T = slicer_0deg(d_p_0T);
181
      
182
      x = (d_c_0T - d_c_2T) * conj(d_p_1T);
183
      y = (d_p_0T - d_p_2T) * conj(d_c_1T);
184
      u = y - x;
185
      mm_val = u.real();
186
      out[oo++] = d_p_0T;
187
      
188
      // limit mm_val
189
      mm_val = gr_branchless_clip(mm_val,1.0);
190
      
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
193
      
194
      d_mu = d_mu + d_omega + d_gain_mu * mm_val;
195
      ii += (int)floor(d_mu);
196
      d_mu -= floor(d_mu);
197
      
198
      if(d_verbose) {
199
        printf("%f\t%f\n", d_omega, d_mu);
200
      }
201
            
202
      if (ii < 0)        // clamp it.  This should only happen with bogus input
203
        ii = 0;
204
    }
205
  }
206
207
  if (ii > 0){
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]);
211
      assert(0);
212
    }
213
    consume_each (ii);
214
  }
215
216
  return oo;
217
}