Revision a27f67c7 gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h

b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
43 43
 * \brief Timing synchronizer using polyphase filterbanks
44 44
 *
45 45
 * \ingroup filter_blk
46
 * \ingroup pfb_blk
46 47
 * 
47
 * This block performs timing synchronization for PAM signals by minimizing the
48
 * derivative of the filtered signal, which in turn maximizes the SNR and 
49
 * minimizes ISI.
48
 * This block performs timing synchronization for PAM signals by
49
 * minimizing the derivative of the filtered signal, which in turn
50
 * maximizes the SNR and minimizes ISI.
50 51
 *
51
 * This approach works by setting up two filterbanks; one filterbank contains the 
52
 * signal's pulse shaping matched filter (such as a root raised cosine filter),
53
 * where each branch of the filterbank contains a different phase of the filter.
54
 * The second filterbank contains the derivatives of the filters in the first 
55
 * filterbank. Thinking of this in the time domain, the first filterbank contains
56
 * filters that have a sinc shape to them. We want to align the output signal to
57
 * be sampled at exactly the peak of the sinc shape. The derivative of the sinc
58
 * contains a zero at the maximum point of the sinc (sinc(0) = 1, sinc(0)' = 0).
59
 * Furthermore, the region around the zero point is relatively linear. We make
60
 * use of this fact to generate the error signal.
52
 * This approach works by setting up two filterbanks; one filterbank
53
 * contains the signal's pulse shaping matched filter (such as a root
54
 * raised cosine filter), where each branch of the filterbank contains
55
 * a different phase of the filter.  The second filterbank contains
56
 * the derivatives of the filters in the first filterbank. Thinking of
57
 * this in the time domain, the first filterbank contains filters that
58
 * have a sinc shape to them. We want to align the output signal to be
59
 * sampled at exactly the peak of the sinc shape. The derivative of
60
 * the sinc contains a zero at the maximum point of the sinc (sinc(0)
61
 * = 1, sinc(0)' = 0).  Furthermore, the region around the zero point
62
 * is relatively linear. We make use of this fact to generate the
63
 * error signal.
61 64
 *
62
 * If the signal out of the derivative filters is d_i[n] for the ith filter, and
63
 * the output of the matched filter is x_i[n], we calculate the error as:
64
 *    e[n] = (Re{x_i[n]} * Re{d_i[n]} + Im{x_i[n]} * Im{d_i[n]}) / 2.0
65
 * This equation averages the error in the real and imaginary parts. There are two
66
 * reasons we multiply by the signal itself. First, if the symbol could be positive
67
 * or negative going, but we want the error term to always tell us to go in the 
68
 * same direction depending on which side of the zero point we are on. The sign of
69
 * x_i[n] adjusts the error term to do this. Second, the magnitude of x_i[n] scales
70
 * the error term depending on the symbol's amplitude, so larger signals give us
71
 * a stronger error term because we have more confidence in that symbol's value.
72
 * Using the magnitude of x_i[n] instead of just the sign is especially good for
73
 * signals with low SNR.
65
 * If the signal out of the derivative filters is d_i[n] for the ith
66
 * filter, and the output of the matched filter is x_i[n], we
67
 * calculate the error as: e[n] = (Re{x_i[n]} * Re{d_i[n]} +
68
 * Im{x_i[n]} * Im{d_i[n]}) / 2.0 This equation averages the error in
69
 * the real and imaginary parts. There are two reasons we multiply by
70
 * the signal itself. First, if the symbol could be positive or
71
 * negative going, but we want the error term to always tell us to go
72
 * in the same direction depending on which side of the zero point we
73
 * are on. The sign of x_i[n] adjusts the error term to do
74
 * this. Second, the magnitude of x_i[n] scales the error term
75
 * depending on the symbol's amplitude, so larger signals give us a
76
 * stronger error term because we have more confidence in that
77
 * symbol's value.  Using the magnitude of x_i[n] instead of just the
78
 * sign is especially good for signals with low SNR.
74 79
 *
75
 * The error signal, e[n], gives us a value proportional to how far away from the zero
76
 * point we are in the derivative signal. We want to drive this value to zero, so we
77
 * set up a second order loop. We have two variables for this loop; d_k is the filter
78
 * number in the filterbank we are on and d_rate is the rate which we travel through
79
 * the filters in the steady state. That is, due to the natural clock differences between
80
 * the transmitter and receiver, d_rate represents that difference and would traverse
81
 * the filter phase paths to keep the receiver locked. Thinking of this as a second-order
82
 * PLL, the d_rate is the frequency and d_k is the phase. So we update d_rate and d_k
83
 * using the standard loop equations based on two error signals, d_alpha and d_beta.
84
 * We have these two values set based on each other for a critically damped system, so in
85
 * the block constructor, we just ask for "gain," which is d_alpha while d_beta is
86
 * equal to (gain^2)/4.
80
 * The error signal, e[n], gives us a value proportional to how far
81
 * away from the zero point we are in the derivative signal. We want
82
 * to drive this value to zero, so we set up a second order loop. We
83
 * have two variables for this loop; d_k is the filter number in the
84
 * filterbank we are on and d_rate is the rate which we travel through
85
 * the filters in the steady state. That is, due to the natural clock
86
 * differences between the transmitter and receiver, d_rate represents
87
 * that difference and would traverse the filter phase paths to keep
88
 * the receiver locked. Thinking of this as a second-order PLL, the
89
 * d_rate is the frequency and d_k is the phase. So we update d_rate
90
 * and d_k using the standard loop equations based on two error
91
 * signals, d_alpha and d_beta.  We have these two values set based on
92
 * each other for a critically damped system, so in the block
93
 * constructor, we just ask for "gain," which is d_alpha while d_beta
94
 * is equal to (gain^2)/4.
87 95
 *
88
 * The clock sync block needs to know the number of samples per symbol (sps), because it
89
 * only returns a single point representing the symbol. The sps can be any positive real
90
 * number and does not need to be an integer. The filter taps must also be specified. The
91
 * taps are generated by first conceiving of the prototype filter that would be the signal's
92
 * matched filter. Then interpolate this by the number of filters in the filterbank. These
93
 * are then distributed among all of the filters. So if the prototype filter was to have
94
 * 45 taps in it, then each path of the filterbank will also have 45 taps. This is easily
95
 * done by building the filter with the sample rate multiplied by the number of filters
96
 * to use.
96
 * The clock sync block needs to know the number of samples per symbol
97
 * (sps), because it only returns a single point representing the
98
 * symbol. The sps can be any positive real number and does not need
99
 * to be an integer. The filter taps must also be specified. The taps
100
 * are generated by first conceiving of the prototype filter that
101
 * would be the signal's matched filter. Then interpolate this by the
102
 * number of filters in the filterbank. These are then distributed
103
 * among all of the filters. So if the prototype filter was to have 45
104
 * taps in it, then each path of the filterbank will also have 45
105
 * taps. This is easily done by building the filter with the sample
106
 * rate multiplied by the number of filters to use.
97 107
 *
98
 * The number of filters can also be set and defaults to 32. With 32 filters, you get a
99
 * good enough resolution in the phase to produce very small, almost unnoticeable, ISI.
100
 * Going to 64 filters can reduce this more, but after that there is very little gained
101
 * for the extra complexity.
108
 * The number of filters can also be set and defaults to 32. With 32
109
 * filters, you get a good enough resolution in the phase to produce
110
 * very small, almost unnoticeable, ISI.  Going to 64 filters can
111
 * reduce this more, but after that there is very little gained for
112
 * the extra complexity.
102 113
 *
103
 * The initial phase is another settable parameter and refers to the filter path the
104
 * algorithm initially looks at (i.e., d_k starts at init_phase). This value defaults 
105
 * to zero, but it might be useful to start at a different phase offset, such as the mid-
106
 * point of the filters.
114
 * The initial phase is another settable parameter and refers to the
115
 * filter path the algorithm initially looks at (i.e., d_k starts at
116
 * init_phase). This value defaults to zero, but it might be useful to
117
 * start at a different phase offset, such as the mid- point of the
118
 * filters.
107 119
 *
108
 * The final parameter is the max_rate_devitation, which defaults to 1.5. This is how far
109
 * we allow d_rate to swing, positive or negative, from 0. Constraining the rate can help
110
 * keep the algorithm from walking too far away to lock during times when there is no signal.
120
 * The final parameter is the max_rate_devitation, which defaults to
121
 * 1.5. This is how far we allow d_rate to swing, positive or
122
 * negative, from 0. Constraining the rate can help keep the algorithm
123
 * from walking too far away to lock during times when there is no
124
 * signal.
111 125
 *
112 126
 */
113 127

Also available in: Unified diff