# Symbol Timing Recovery with Fractional Sample per Second

I'm trying to write symbol timing recovery loop and taking help from "Digital Communications A Discrete-Time Approach" by Miachel Rice. MATLAB communication toolbox has also implemented the same algorithm in comm.SymbolSynchronizer.

In both the implementations (given in the book as well as MATLAB's), the samples-per-symbol is assumed to be an integer greater than 1. However, in my application, the samples-per-symbol is fractional (specifically 1.9729), while it has to be an integer for as per the documentation of MATLAB's synchronization code. The algorithms using module-1 counter interpolation control and its implementation is given in the code below: , where $$N$$ is the number of samples-per-symbol and is supposed to be an integer.

taken from Analog Devices Software Defined Radio Book.

My question is how can we change the interpolation control so that we can support fractional sample-per-symbol values as well. I have already tried using the same code with $$N$$ fractional and it doesn't work. All the mathematics given in the book and implementation points toward this value being an integer.

Relevant sections of Miachel Rice's book are given in the following link (I'm not sure I'll be violating copyrights for the book if I post its image):

My implementation includes Farrow structure for cubic interpolator and Gardner's timing error detector. The input is coming at 1.9729 samples per symbol and after the interpolator, I'm getting it down to 1 sample per symbol.

Since ultimately the recovered time must be symbol synchronous (in the end we need one sample per symbol and that sample should be at the correct sampling location to minimize error), it would make sense to operate the timing recovery with an integer number of samples per symbol. This implies the waveform sampled at 1.9729 samples per symbol could be resampled to 2 samples per symbol. Since such resampling/ interpolation is part of timing recovery anyway, this is being done regardless! (No matter what the OP seeks to get one sample per symbol from some form of an interpolator, so if we have 1 sample per symbol, we also have two samples per symbol etc). Please refer to this post for specific details on implementing polyphase retiming filters which can operate at a non-integer number of samples per symbol and provide a properly retimed output to any precision at an integer symbol sampling rate without actually changing actual sampling clock.

There is no requirement for general timing recovery that the sampling rate be an integer number of samples, but this is often the choice due to convenience that once recovered each subsequent $$N$$ samples will be at the correct timing location assuming no timing drift. Two samples per symbol is more than sufficient and often the choice in implementations using implementations such as the Gardner Loop which is my favored approach. (The OP is implementing a derivative matched filter timing recovery implementation that I have detailed in this post.) Another consideration is to use a Mueller and Mueller synchronizer which only requires one sample per symbol (but must have most of the carrier offset removed from a carrier recovery loop, while the Gardner in contrast can operate with relatively large carrier offsets).

So in summary my suggestion resample to an integer number of samples per symbol with a precision interpolator that can be used as part as t the timing recovery loop, and use whatever precision is required in the resampler for the allowing maximum timing error by symbol (based on modulation choice and minimum EVM required). Whatever favored approach for interpolation, it can be used as the timing adjustment mechanism for the actual timing loop itself. The timing error detector (Gardner or otherwise) can then operate on the retimed samples at $$N$$ samples per symbol with $$N$$ being an integer. (Again not necessary but convenient to do so given those samples are being established anyway).

I don't see a fundamental reason the Gardner cannot provide a timing error with fractional samples per symbol, but I do see potential complexities that can be avoided by resampling to integer samples per symbol. I have never implemented it other than integer samples per symbol, so these are suspicions not experience: the challenge may be the introduced underlying drift rate compared to the timing loop bandwidth. On its own at 1.9729 samples per symbol, without correction the error is 0.0271 symbols per symbol, so the timing loop bandwidth needs to be wide enough to keep up with that, or the delay slope must be added to the interpolator to be introduced on every update (which then is back to basically being equivalent to resampling to two samples per symbol). Without any correction the samples cycle completely past the symbols every 37 symbols! Note from the graphic below the relationship of Gardner TED self-noise and timing error. What we see in the plot on the left is measured results on a Garnder TED error signal versus timing offset with the long term average given by the negative sine wave in white (buried in the noise of the TED on a sample by sample basis!). The plots on the right show the spectrums of this noise for the case when there is no time offset and for a small offset. With no offset and a tight loop bandwidth (filtering) we achieve a noise shaping advantage. Ultimately we just need to be sure the self noise is low enough to not degrade our EVM targets.

• Thanks @dan for the answer. I have updated my post and corrected a typo (which as I understand doesn't change your answer). My input is at 1.9729 samples per symbol and I'm using Farrow structure for cubic interpolator with Gardner's timing error detector. A little history is that I have worked at a place where they made such a recovery loop with fractional samples per symbol by incorporating the fractional part in the update of fractional delay to the interpolator without changing rate. I have read recursive control in the Rice's book, but don't know how to implement it in such a loop. Apr 13, 2022 at 5:06
• I'm just worried if the received EVM is affected by using samples per symbol value of 2 instead of 1.972 or would it remain the same? Apr 13, 2022 at 5:07
• @ubaabd The EVM can only be degraded if you do the resampling incorrectly. This would be simplest to me since the goal of “clock recovery” is to recover the symbol clock. I did not realize you are using the Gardner since the link you provided suggests otherwise. My concern with fractional samples is the Gardner requires a tighter loop BW due to its self noise so the drift rate due to offset may be too high— I’ll add further thoughts on that at the bottom of my answer Apr 13, 2022 at 7:33
• personally I really like the polyphase resampler for this application; not sure how familiar you are with that-- you keep the same sampling rate and decide the precision needed based on EVM targets (how close do you need to get to the actual "best sample"). This sets how many polyphase filters to use in the bank, but implementation is done with just one filter and coefficient memory storage for all the filters. Each "filter" divides the symbol duration evenly so that you can continuously "roll" as needed to keep up with the underlying drift, Apr 13, 2022 at 8:01
• and samples get effectively skipped or held to reestablish symbol time (nothing is lost since you have nearly two samples per symbol). The output of the polyphase would then be exactly 2 samples per symbol- which is what is fed into the Gardner TED, producing the error which goes to a loop filter which sets the filter bank selection in the polyphase (control value). Apr 13, 2022 at 8:04

I think you are implementing the Gardner algorithm. In the algorithm section provided by you, the sample shift per sampling is denoted by "1/N" where N denotes the number of sample per symbol. If you want to implement fractional symbol period (in terms of sample), "N" must be declared as fractional.

• Yes $N$ denotes the number of samples per symbol, but when provided as 3.9 instead of 4, the loop doesn't converge. If I use MATLAB's implementation, it just throws the error that it is supposed to be an integer and not a fraction. Apr 12, 2022 at 10:44
• This is because you write a fractional $N$ as an index to an array. If a variable is composed of $N$ and used for the index in an array, round it and use the most likely integer as the index. Apr 12, 2022 at 10:54