GNU Radio C++ API Reference  gcd20ee2
The Free & Open Software Radio Ecosystem
fll_band_edge_cc.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2009,2011,2012 Free Software Foundation, Inc.
4  * Copyright 2025 Daniel Estevez <daniel@destevez.net>
5  *
6  * This file is part of GNU Radio
7  *
8  * SPDX-License-Identifier: GPL-3.0-or-later
9  *
10  */
11 
12 #ifndef INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H
13 #define INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H
14 
16 #include <gnuradio/digital/api.h>
17 #include <gnuradio/sync_block.h>
18 
19 namespace gr {
20 namespace digital {
21 
22 /*!
23  * \brief Frequency Lock Loop using band-edge filters
24  * \ingroup synchronizers_blk
25  *
26  * \details
27  * The frequency lock loop derives a band-edge filter that covers
28  * the upper and lower bandwidths of a digitally-modulated
29  * signal. The bandwidth range is determined by the excess
30  * bandwidth (e.g., rolloff factor) of the modulated signal. The
31  * placement in frequency of the band-edges is determined by the
32  * oversampling ratio (number of samples per symbol) and the
33  * excess bandwidth. The size of the filters should be fairly
34  * large so as to average over a number of symbols.
35  *
36  * The FLL works by filtering the upper and lower band edges into
37  * x_u(t) and x_l(t), respectively. These are combined to form
38  * cc(t) = x_u(t) + x_l(t) and ss(t) = x_u(t) - x_l(t). Combining
39  * these to form the signal e(t) = Re{cc(t) \\times ss(t)^*}
40  * (where ^* is the complex conjugate) provides an error signal at
41  * the DC term that is directly proportional to the carrier
42  * frequency. We then make a second-order loop using the error
43  * signal that is the running average of e(t).
44  *
45  * In practice, the above equation can be simplified by just
46  * comparing the absolute value squared of the output of both
47  * filters: abs(x_l(t))^2 - abs(x_u(t))^2 = norm(x_l(t)) -
48  * norm(x_u(t)).
49  *
50  * In theory, the band-edge filter is the derivative of the
51  * matched filter in frequency, (H_be(f) = frac{H(f)}{df}). In
52  * practice, this comes down to a quarter sine wave at the point
53  * of the matched filter's rolloff (if it's a raised-cosine, the
54  * derivative of a cosine is a sine). Extend this sine by another
55  * quarter wave to make a half wave around the band-edges is
56  * equivalent in time to the sum of two sinc functions. The
57  * baseband filter for the band edges is therefore derived from
58  * this sum of sincs. The band edge filters are then just the
59  * baseband signal modulated to the correct place in
60  * frequency. All of these calculations are done in the
61  * 'design_filter' function.
62  *
63  * Note: We use FIR filters here because the filters have to have
64  * a flat phase response over the entire frequency range to allow
65  * their comparisons to be valid.
66  *
67  * It is very important that the band edge filters be the
68  * derivatives of the pulse shaping filter, and that they be
69  * linear phase. Otherwise, the variance of the error will be very
70  * large.
71  */
72 class DIGITAL_API fll_band_edge_cc : virtual public sync_block,
73  virtual public blocks::control_loop
74 {
75 public:
76  // gr::digital::fll_band_edge_cc::sptr
77  typedef std::shared_ptr<fll_band_edge_cc> sptr;
78 
79  /*!
80  * Make an FLL block.
81  *
82  * \param samps_per_sym (float) number of samples per symbol
83  * \param rolloff (float) Rolloff (excess bandwidth) of signal filter
84  * \param filter_size (int) number of filter taps to generate
85  * \param bandwidth (float) Loop bandwidth. This paramter is BL*T, where BL
86  * is the loop noise bandwidth in Hz, and T is the sampling period in seconds.
87  */
88  static sptr
89  make(float samps_per_sym, float rolloff, int filter_size, float bandwidth);
90 
91  /*******************************************************************
92  SET FUNCTIONS
93  *******************************************************************/
94 
95  /*!
96  * \brief Set the number of samples per symbol
97  *
98  * Set's the number of samples per symbol the system should
99  * use. This value is used to calculate the filter taps and will
100  * force a recalculation.
101  *
102  * \param sps (float) new samples per symbol
103  */
104  virtual void set_samples_per_symbol(float sps) = 0;
105 
106  /*!
107  * \brief Set the rolloff factor of the shaping filter
108  *
109  * This sets the rolloff factor that is used in the pulse
110  * shaping filter and is used to calculate the filter
111  * taps. Changing this will force a recalculation of the filter
112  * taps.
113  *
114  * This should be the same value that is used in the
115  * transmitter's pulse shaping filter. It must be between 0 and
116  * 1 and is usually between 0.2 and 0.5 (where 0.22 and 0.35 are
117  * commonly used values).
118  *
119  * \param rolloff (float) new shaping filter rolloff factor [0,1]
120  */
121  virtual void set_rolloff(float rolloff) = 0;
122 
123  /*!
124  * \brief Set the number of taps in the filter
125  *
126  * This sets the number of taps in the band-edge
127  * filters. Setting this will force a recalculation of the
128  * filter taps.
129  *
130  * This should be about the same number of taps used in the
131  * transmitter's shaping filter and also not very large. A large
132  * number of taps will result in a large delay between input and
133  * frequency estimation, and so will not be as accurate. Between
134  * 30 and 70 taps is usual.
135  *
136  * \param filter_size (float) number of taps in the filters
137  */
138  virtual void set_filter_size(int filter_size) = 0;
139 
140  /*******************************************************************
141  GET FUNCTIONS
142  *******************************************************************/
143 
144  /*!
145  * \brief Returns the number of sampler per symbol used for the filter
146  */
147  virtual float samples_per_symbol() const = 0;
148 
149  /*!
150  * \brief Returns the rolloff factor used for the filter
151  */
152  virtual float rolloff() const = 0;
153 
154  /*!
155  * \brief Returns the number of taps of the filter
156  */
157  virtual int filter_size() const = 0;
158 
159  /*!
160  * Print the taps to screen.
161  */
162  virtual void print_taps() = 0;
163 };
164 
165 } /* namespace digital */
166 } /* namespace gr */
167 
168 #endif /* INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H */
A second-order control loop implementation class.
Definition: control_loop.h:51
Frequency Lock Loop using band-edge filters.
Definition: fll_band_edge_cc.h:74
virtual void set_filter_size(int filter_size)=0
Set the number of taps in the filter.
virtual int filter_size() const =0
Returns the number of taps of the filter.
virtual void set_rolloff(float rolloff)=0
Set the rolloff factor of the shaping filter.
static sptr make(float samps_per_sym, float rolloff, int filter_size, float bandwidth)
virtual void set_samples_per_symbol(float sps)=0
Set the number of samples per symbol.
virtual float samples_per_symbol() const =0
Returns the number of sampler per symbol used for the filter.
virtual float rolloff() const =0
Returns the rolloff factor used for the filter.
std::shared_ptr< fll_band_edge_cc > sptr
Definition: fll_band_edge_cc.h:77
synchronous 1:1 input to output with history
Definition: sync_block.h:26
#define DIGITAL_API
Definition: gr-digital/include/gnuradio/digital/api.h:18
GNU Radio logging wrapper.
Definition: basic_block.h:29