summaryrefslogtreecommitdiff
path: root/gr-digital/lib/digital_fll_band_edge_cc.h
blob: 496289d903b34a5dda0e17f487ffd7fd15704118 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/* -*- c++ -*- */
/*
 * Copyright 2009,2011 Free Software Foundation, Inc.
 * 
 * This file is part of GNU Radio
 * 
 * GNU Radio is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 * 
 * GNU Radio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */


#ifndef INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H
#define	INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H

#include <gr_sync_block.h>

class digital_fll_band_edge_cc;
typedef boost::shared_ptr<digital_fll_band_edge_cc> digital_fll_band_edge_cc_sptr;
digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym,
							     float rolloff,
							     int filter_size,
							     float bandwidth);

/*!
 * \class digital_fll_band_edge_cc
 * \brief Frequency Lock Loop using band-edge filters
 *
 * \ingroup general
 *
 * The frequency lock loop derives a band-edge filter that covers the upper and lower bandwidths
 * of a digitally-modulated signal. The bandwidth range is determined by the excess bandwidth
 * (e.g., rolloff factor) of the modulated signal. The placement in frequency of the band-edges
 * is determined by the oversampling ratio (number of samples per symbol) and the excess bandwidth.
 * The size of the filters should be fairly large so as to average over a number of symbols.
 *
 * The FLL works by filtering the upper and lower band edges into x_u(t) and x_l(t), respectively.
 * These are combined to form cc(t) = x_u(t) + x_l(t) and ss(t) = x_u(t) - x_l(t). Combining
 * these to form the signal e(t) = Re{cc(t) \\times ss(t)^*} (where ^* is the complex conjugate)
 * provides an error signal at the DC term that is directly proportional to the carrier frequency.
 * We then make a second-order loop using the error signal that is the running average of e(t).
 *
 * In practice, the above equation can be simplified by just comparing the absolute value squared
 * of the output of both filters: abs(x_l(t))^2 - abs(x_u(t))^2 = norm(x_l(t)) - norm(x_u(t)).
 *
 * In theory, the band-edge filter is the derivative of the matched filter in frequency, 
 * (H_be(f) = \\frac{H(f)}{df}. In practice, this comes down to a quarter sine wave at the point
 * of the matched filter's rolloff (if it's a raised-cosine, the derivative of a cosine is a sine).
 * Extend this sine by another quarter wave to make a half wave around the band-edges is equivalent
 * in time to the sum of two sinc functions. The baseband filter fot the band edges is therefore
 * derived from this sum of sincs. The band edge filters are then just the baseband signal
 * modulated to the correct place in frequency. All of these calculations are done in the
 * 'design_filter' function.
 *
 * Note: We use FIR filters here because the filters have to have a flat phase response over the
 * entire frequency range to allow their comparisons to be valid.
 *
 * It is very important that the band edge filters be the derivatives of the pulse shaping filter,
 * and that they be linear phase. Otherwise, the variance of the error will be very large.
 *
 */

class digital_fll_band_edge_cc : public gr_sync_block
{
 private:
  /*!
   * Build the FLL
   * \param samps_per_sym    (float) Number of samples per symbol of signal
   * \param rolloff          (float) Rolloff factor of signal
   * \param filter_size      (int)   Size (in taps) of the filter
   * \param bandwidth        (float) Loop bandwidth
   */
  friend digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym,
								      float rolloff,
								      int filter_size,
								      float bandwidth);

  float                   d_sps;
  float                   d_rolloff;
  int                     d_filter_size;
  float                   d_max_freq;
  float                   d_min_freq;

  float                   d_loop_bw;
  float                   d_damping;
  float                   d_alpha;
  float                   d_beta;

  std::vector<gr_complex> d_taps_lower;
  std::vector<gr_complex> d_taps_upper;
  bool			  d_updated;

  float                   d_freq;
  float                   d_phase; 

  /*!
   * Build the FLL
   * \param samps_per_sym (float) number of samples per symbol
   * \param rolloff (float) Rolloff (excess bandwidth) of signal filter
   * \param filter_size (int) number of filter taps to generate
   * \param bandwidth (float) Loop bandwidth
   */
  digital_fll_band_edge_cc(float samps_per_sym, float rolloff,
			   int filter_size, float bandwidth);
  
  /*!
   * \brief Update the gains, alpha and beta, of the loop filter.
   */
  void update_gains();

  /*!
   * Design the band-edge filter based on the number of samples per symbol,
   * filter rolloff factor, and the filter size
   *
   * \param samps_per_sym    (float) Number of samples per symbol of signal
   * \param rolloff          (float) Rolloff factor of signal
   * \param filter_size      (int)   Size (in taps) of the filter
   */
  void design_filter(float samps_per_sym, float rolloff, int filter_size);

public:
  ~digital_fll_band_edge_cc ();

  /*******************************************************************
    SET FUNCTIONS
  *******************************************************************/
  
  /*!
   * \brief Set the loop bandwidth
   *
   * Set the loop filter's bandwidth to \p bw. This should be between 
   * 2*pi/200 and 2*pi/100  (in rads/samp). It must also be a positive
   * number.
   *
   * When a new damping factor is set, the gains, alpha and beta, of the loop
   * are recalculated by a call to update_gains().
   *
   * \param bw    (float) new bandwidth
   *
   */
  void set_loop_bandwidth(float bw);

  /*!
   * \brief Set the loop damping factor
   *
   * Set the loop filter's damping factor to \p df. The damping factor
   * should be sqrt(2)/2.0 for critically damped systems.
   * Set it to anything else only if you know what you are doing. It must
   * be a number between 0 and 1.
   *
   * When a new damping factor is set, the gains, alpha and beta, of the loop
   * are recalculated by a call to update_gains().
   *
   * \param df    (float) new damping factor
   *
   */
  void set_damping_factor(float df);

  /*!
   * \brief Set the loop gain alpha
   *
   * Set's the loop filter's alpha gain parameter.
   *
   * This value should really only be set by adjusting the loop bandwidth
   * and damping factor.
   *
   * \param alpha    (float) new alpha gain
   *
   */
  void set_alpha(float alpha);

  /*!
   * \brief Set the loop gain beta
   *
   * Set's the loop filter's beta gain parameter.
   *
   * This value should really only be set by adjusting the loop bandwidth
   * and damping factor.
   *
   * \param beta    (float) new beta gain
   *
   */
  void set_beta(float beta);

  /*!
   * \brief Set the number of samples per symbol
   *
   * Set's the number of samples per symbol the system should use. This value
   * is uesd to calculate the filter taps and will force a recalculation.
   *
   * \param sps    (float) new samples per symbol
   *
   */
  void set_samples_per_symbol(float sps);

  /*!
   * \brief Set the rolloff factor of the shaping filter
   *
   * This sets the rolloff factor that is used in the pulse shaping filter
   * and is used to calculate the filter taps. Changing this will force a
   * recalculation of the filter taps.
   *
   * This should be the same value that is used in the transmitter's pulse
   * shaping filter. It must be between 0 and 1 and is usually between
   * 0.2 and 0.5 (where 0.22 and 0.35 are commonly used values).
   *
   * \param rolloff    (float) new shaping filter rolloff factor [0,1]
   *
   */
  void set_rolloff(float rolloff);

  /*!
   * \brief Set the number of taps in the filter
   *
   * This sets the number of taps in the band-edge filters. Setting this will
   * force a recalculation of the filter taps.
   *
   * This should be about the same number of taps used in the transmitter's
   * shaping filter and also not very large. A large number of taps will
   * result in a large delay between input and frequency estimation, and
   * so will not be as accurate. Between 30 and 70 taps is usual.
   *
   * \param filter_size    (float) number of taps in the filters
   *
   */
  void set_filter_size(int filter_size);

  /*!
   * \brief Set the FLL's frequency.
   *
   * Set's the FLL's frequency. While this is normally updated by the
   * inner loop of the algorithm, it could be useful to manually initialize,
   * set, or reset this under certain circumstances.
   *
   * \param freq    (float) new frequency
   *
   */
  void set_frequency(float freq);

  /*!
   * \brief Set the FLL's phase.
   *
   * Set's the FLL's phase. While this is normally updated by the
   * inner loop of the algorithm, it could be useful to manually initialize,
   * set, or reset this under certain circumstances.
   *
   * \param phase    (float) new phase
   *
   */
  void set_phase(float phase);

  /*******************************************************************
    GET FUNCTIONS
  *******************************************************************/

  /*!
   * \brief Returns the loop bandwidth
   */
  float get_loop_bandwidth() const;

  /*!
   * \brief Returns the loop damping factor
   */
  float get_damping_factor() const;

  /*!
   * \brief Returns the loop gain alpha
   */
  float get_alpha() const;

  /*!
   * \brief Returns the loop gain beta
   */
  float get_beta() const;

  /*!
   * \brief Returns the number of sampler per symbol used for the filter
   */
  float get_samples_per_symbol() const;

  /*!
   * \brief Returns the rolloff factor used for the filter
   */
  float get_rolloff() const;

  /*!
   * \brief Returns the number of taps of the filter
   */
  int get_filter_size() const;

  /*!
   * \brief Get the FLL's frequency estimate
   */
  float get_frequency() const;

  /*!
   * \brief Get the FLL's phase estimate
   */
  float get_phase() const;

  /*!
   * Print the taps to screen.
   */
  void print_taps();
   
  int work (int noutput_items,
	    gr_vector_const_void_star &input_items,
	    gr_vector_void_star &output_items);
};

#endif