Time shifting a signal in python

I am currently modeling FMCW (linear FM) and SFCW (stepped FM) chirps in python. For my project, I need to simulate those signals as a transmit chirp and a received one, scattered from point targets at some distance. I think I got it generally right for the linear chirps, where I am generating the transmit signal like this: \begin{aligned} s_{tx}(t) &= \exp(j2\pi(f_c+\frac{\alpha}{2}t)t) \\ &= \exp(j2\pi f_c t + j\pi \alpha t^2) \end{aligned} with $$\alpha=B/T$$ being the chirp rate, $$B$$ the total bandwidth, $$T$$ the chirp duration and $$f_c$$ the carrier frequency. As an experiment, I tried different ways to model the received signal. Lets say I have a point scatterer at a distance $$R$$. I get the time delay by: $$\tau = \frac{2R}{c}$$ where $$c$$ is my propagation speed. Thus, my received signal should be: \begin{aligned} s_{rx}(t) &= s_{tx}(t-\tau) \\ &= \exp(j2\pi f_c (t-\tau)+j\pi \alpha (t-\tau)^2)\\ &= s_{tx}(t) \cdot \exp(-j2\pi \tau (f_0 + \alpha t - \frac{\alpha}{2}\tau)) \end{aligned} which is nice, since I can just multiply my already generated transmit chirp by a phasor with a frequency component proportional to $$\alpha \tau$$ and some phase terms.

Another option I was wondering about, is using the fourier transform shift property: $$F\{s_{tx}(t-\tau)\}(s) = \exp(-2j\pi s \tau) \cdot F\{s(t)_{tx}\}(s)$$ From my understanding, calculating the FFT of $$s_{tx}(t)$$, applying the shift in frequency domain and then performing the IFFT should give me the same result. However, I get different results when I compare both methods. One difference I could pin out is the phase of the resulting receive signals:

While the one shifted via the model equation (orange) has a smooth phase, the one shifted with the FFT (red) not only has a different trajectory but also some sort of kink that occurs at the time by which the signal has been shifted.

Consequently, I get different results down the line when I do the deramping procedure. Upon deramping via: $$s_{if}(t) = s_{rx}(t) \cdot s^*_{tx}(t)$$ I optain a perfectly fine sinusoidal beat signal with the model-based method, but the FFT-based method has a distinct change:

which results in a secondary frequency component in the spectrum and some significant differences in the phase:

Upon further inspection, the two methods seem to do a different "shift" in time. This can be seen for this example plot of the two resulting shifted versions of the transmit signal. While the model-based shift seems to be symmetric around the time delay, the FFT-based shift looks like it just pushes the end of the chirp back into the beginning (similar to a circular shift) Note that the plot is zoomed and only the start of the chirp is shown for clarity.

Is there an alternative method that could be used to achieve fine time delays that does not result in this circular shift property?

Cheers!

EDIT For clarification the code to apply the shift in the FFT domain. Its not completely copy & pastable for readability but I hope the steps are clear.

S_tx = fftshift(fft(s_tx*win, n=nFFT)) # nFFT number of FFT points
sRes = fs/nFFT      # fs = sampling frequency
sAxis = np.arange(-fs/2, fs/2, sRes)

shift_phasor = np.exp(-2j*pi*sAxis*tDelay)
S_rx = shift_phasor * S_tx

s_rx = ifft(ifftshift(S_rx))

• Why not just convert the time delay of the target return and then use that to compute a number of samples to insert the return into your listen interval? This way you don't have to get into the weeds of using the FFT-based method. However if you do want to go that route, you need to be careful on how you are applying the phase-shift across the band. In the usual mathematical expression you have, you would need to operate on the array where DC is in the middle, which is NOT how some of the most popular DFT methods produce the output. You need to do an fftshift first. Commented Feb 19, 2023 at 3:05
• It's not clear to me how $\exp(-2j\pi s \tau) \cdot F\{s(t)_{tx}\}(s)$ in continuous-time, continuous-frequency translates to the discrete-time, discrete-frequency FFT domain. Can you share the code you use to do that?
– Peter K.
Commented Feb 19, 2023 at 17:43
• Hey @PeterK. I added a code snipped for the shift. I hope it was what you were asking. Commented Feb 20, 2023 at 8:29
• FFT approaches suffer from time domain aliasing, so is a flawed approach. Would you be interested in seeing a straightforward way to apply precision fractional sample time delays to your signal using fractional delay FIR filters or are you already familiar with that? Commented Feb 20, 2023 at 18:21
• Hello @DanBoschen, that would be very interesting! I am only vaguely familiar with that approach. Commented Feb 22, 2023 at 7:36

As the OP observed, a shift in the FFT in one domain produces a circular linear phase ramp in the other domain. The shift is clear by seeing how we can for example shift frequency by multiplying by a phase ramp in time $$(e^{j\omega_\Delta t})$$, which is intuitively consistent when we understand a single fixed tone in the time domain at radian frequency $$\omega_1$$ is represented as $$(e^{j\omega_1 t})$$. Thus the product in time is the expected shift in frequency:

$$(e^{j\omega_\Delta t})(e^{j\omega_1 t}) = (e^{j(\omega_\Delta+\omega_1) t}) \tag{1} \label{1}$$

For that we only need to remember that exponents add with such a product. So we have confirmed the known Fourier relationship where above $$x(t) = e^{j\omega_1 t}$$:

$$e^{j\omega_\Delta t}x(t) \leftrightarrow X(\omega+\omega_{\Delta})\tag{2} \label{2}$$

Similarly we can shift in time (delay) by multiplying in the frequency domain by $$e^{-j\omega \tau}$$. We get the exact result as above other than a sign change due to the complex conjugate in the Fourier and inverse Fourier transforms. Specifically a negative phase ramp in the frequency domain is a positive shift in time (delay):

$$e^{-j\omega t_\Delta}X(\omega) \leftrightarrow x(t+t_{\Delta})\tag{3} \label{3}$$

However with the Discrete Fourier Transform (DFT), both the time and frequency domain are circular (or similarly periodic if we extended the axis toward $$\pm \infty$$): In the frequency domain as the DFT result, if we were to increase the highest frequency component beyond the highest bin, with all bins given as $$k=0\ldots N-1$$, the resulting bin would be modulo $$N$$. To say this again with an example: if we had a waveform sampled at 100 Hz, and computed a $$N=100$$ point FFT (the FFT is an algorithm that computes the DFT, the result is the DFT), each of the 100 bins would be associated with frequencies from DC ($$k=0$$) to 99 Hz in steps of 1 Hz. If we had a tone at 99 Hz and were able to shift it upward by 1 Hz (using a time product with the shift property above), the result would be at 0 Hz. If we had a tone at 90 Hz and shifted it upward by 15 Hz, the result would be $$(90+15) mod 100 = 5$$.

For FMCW radar, we sweep a frequency ramp (chirp) at the trasmitter, and multiply this with the (time complex conjugate) ramp in the receiver. The result of a product is the difference in frequencies as we see with equation \ref{1}. (So an FFT is used on the resulting product to convert frequency bins to range bins). So to simulate a delay on the chirp waveform itself, there would be a shift in time resulting in a frequency difference in the result. But note importantly that the frequency difference can never exceed the frequency range of the ramp itself, and for the case when the transmitted chirp is continuously repeated, the periodic nature of the FFT and the OP's result is actually consistent with what we would expect to get due to the periodicity of the chirp itself! And further, knowing this periodicity, the result below is also consistent with a constant frequency such that the result everywhere as shown is $$f_R(t)-f_T(t)$$ (received frequency minus transmitted frequency).

If the Chirp is not repeating, then we will have time regions where the result is meaningless anyway and should be blanked (not included in the derived result):

So the OP's result is actually consistent with the circular nature of FMCW regardless, in that if the chirp is repeating, the entire time capture will be circular regardless of FFT processing, and if it is not repeating, there are portions of the time capture that would not be used (when the chirps don't overlap). The error in the OP's result is that the regions where no overlap occurs were not accounted for resulting in an omitted phase offset: frequency is the time derivative of phase, but the derivative can also include an unknown constant.

What Can be Done to Achieve Realistic Delay

With all that understood, if we still want to create a simulation of the time domain waveform as received with the proper delay we have these additional options in addition to simulating directly in the time domain as the OP has first done:

Option 1: Time delay the waveform in the frequency domain as a product with a rotating phasor (vs frequency) as the OP has described, but include the phase offset term as well.

The phasor in the frequency ramp (as the Fourier Transform of the delay in time) needs to also include the accumulated phase offset at time zero based on the delay (resulting in subtracting that phase from the FFT result).

Option 2: Delay the time domain result (the transmitted chirp) with time domain fractional delay filters. My favored approaches for simulating a precision time delay are to use a bank of polyphase filters, or if a continuously variable delay is desired, a Farrow Filter. These approaches along with further links are detailed at this post: Sampling Time Offset estimation for OFDM signal