I ran a number of simulations for symbol timing synchronization in the past. I used GNU Radio mainly. Now, I'm trying to do the same thing in C++. To achieve that, I need a way to introduce symbol offset to the symbols. So suppose I have a complex array of $M$ samples acquired at a sampling rate of $N$ samples per symbol. How do I introduce a symbol offset of say $\mu = 100 \ \rm ppm$ of the symbol time? Pseudocode, C++, or MATLAB script will suffice.
If you postulate that receiever's clock is perfect, then you want to make the transmitter send symbols every $T_s \pm \varepsilon$ seconds, where $T_s$ is the symbol period according to the receiver.
This is easily achieved by using a very high sampling rate in the transmitter. Let's assume $T_s=1$ and you need a deviation of $\pm 0.01$. This deviation corresponds to one sample, if the sampling interval is $0.01$. So, use a sampling rate of $1/.01 = 100$ samples per time unit, and have the transmitter send a new symbol every 99 samples (for a faster clock) or every 101 samples (for a slower clock). Then, have the receiver sample every 100 samples, and you're done.
By making the sampling rate fast enough, you can easily accomodate any delay you need. Using this method, it is also easy to simulate a time-varying clock drift in the transmitter and/or receiver.
In front of a modem inside a lab, to control the symbol offset you can synchronize the transmitter and the receiver with a 10 MHz reference, and then shift the symbol rate (or bitrate or sampling frequency) by a delta of the wanted ppm. Of course if the rate is programmable.
Implementing a symbol offset in a simulation program in C++ is to design a rational resampler. I would proceed the following way.
I keep in mind that x ppm offset, it can be +/- x an offset. 100 ppm for 1,000,000 sps is 1,000,100 sps or 999,900 sps.
If the ppm is positive it is an interpolation. If the ppm is negative it is a decimation.
I would create an associated array representing the time instant of the ideal sampling rate. For 1e6 sps, the period is 1 us: A table with 1 us 2 us 3 us 4us 5us etc.... values associated to the M samples
I would create another array representing the time instant of the offset sample rate. At 100 ppm, it becomes 1,000,100 sps and the period is 0.9999 us: A table of 0.999 us 1.998 us 2.997 us 3.996 us etc... values I rounded the period in the previous line. Exactly it should be 1/1,000,100
Having the new time instant, now it's time to interpolate or decimate the M samples to get the M' ones associated to offset instants. To do so there are several of interpolation:
A website by Paul Bourke with an article "inteprolation methods" provides some codes in C to implement those interpolations. With both previous time arrays, it is possible to calculate mu described in his article.
I don't know if there is a more efficient way to implement it in a computer, but I did so in an old project and worked. Paul Breeuwsma coefficients from the website article gives good spectrum results.
For negative ppm, same process can be used to decimate.