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