# How can I apply a phase shift to an LFM pulse?

I am modelling radar scenarios in python and am trying to make a model which retains phase information. To do so, I'm envisioning something which works like this:

1. Generate samples of an LFM waveform at RF in a numpy array
2. Calculate the distance to the target (two way)
3. Divide the time take for the echo to return by the RF sampling rate to figure out the number of samples which the delay corresponds to
4. Model the returned waveform as some SNR coefficient (unimportant for context of this question) multiplied by a copy of the transmitted waveform, and shift the elements in the array such that the echo is preceeded by a number of zero elements equal to the number of samples the delay corresponds to
5. Do something with the phase...

It is this step 5 I am a little stuck with. In the steps leading up to this, I have accounted for the delay in a very 'discrete' way. That is, in time increments of the entire sample length. However, the true delay does not correspond to an integer number of samples. Therefore, I need to perform the sample shifting AND apply some phase shift to account for the fact that, due to the non-integer number of samples the shift corresponds to, the additional amount of shift can be represented by an offset in where in the waveform the sample is taken.

For example: say the delay corresponds to 37.465 samples. I can't shift the elements by this much, but I can shift them by 38 samples and say that, in each element, the point of the waveform at which the sample is measured is offset by a phase angle equivalent to this additional proportion of the wavelength.

As an example to illustrate what I mean: Assume the carrier frequency is 1 GHz. In this case, the period of the wavelength is 1/1e9. If we say the same rate is 2 GHz, each sample takes 1/2e9 seconds. Previously, I gave the example of a delay corresponding to 37.465 samples. 0.465 of a sample corresponds to a time of 0.465*1/2e9 seconds. In this length of time, the waveform cycles through (1/1e9) / (0.465 * 1/2e9) of a wavelength. I can calculate this as a phase angle and apply a phase shift to the array representing the returned signal to account for this.

Assuming this makes sense, my problem is then two-fold: Firstly, how do I apply such a phase shift? Secondly, how would this work for the LFM pulse where the frequency is changing over time (since, this means that the wavelength is changing over time and therefore the proportion of the wavelength which corresponds to that 0.465 of a sample changes from sample to sample within the waveform)?

Any help with how to approach this, in particular any actual code implementations would be highly appreciated. I will include the code I have so far in case that helps to understand how I'm modelling things.

Side note: I know real systems don't digitize at RF but I'm trying to create a model which allows the retention of full phase information, so I can't model at baseband.

CODE:

from numpy import *

# This function determines the number of samples which will be needed to model the waveform to allow a target up to the maximum range of interest
def find_chirp_sampling_requirements(max_range, carrier, bw):
sample_rate = 2*(carrier+bw)
time_per_sample = 1/rf_sample_rate
num_samples_required = int(ceil(((2*max_range)/299792458)/rf_time_per_sample))
return sample_rate, time_per_sample, num_samples_required

# This function returns the waveform as a numpy array
def generate_lfm(samples, time_per_sample, duty_cycle, bandwidth, carrier_frequency):
pulse_width_in_samples = int(samples*duty_cycle)
pulse_width_time = pulse_width_in_samples*time_per_sample
t_s = linspace(0,pulse_width_time,pulse_width_in_samples)
chirp_rate = bandwidth/pulse_width_time
f_low = carrier_frequency
initial_phase_offset = 0
phase_angle = 2*pi*(((chirp_rate*t_s**2)/2)+(f_low*t_s))+initial_phase_offset
complex_chirp = exp(1j*phase_angle)
waveform = zeros((samples), dtype=complex)
waveform[:shape(complex_chirp)[0]] += complex_chirp
return waveform

# This function returns the amount of phase angle which corresponds to the two way distance to the target
def calculate_two_way_phase_angle(distance, carrier_frequency):
wavelength = 299792458/carrier
wavelengths_in_distance = distance/wavelength
return wavelengths_in_distance*2*pi

def calculate_two_way_delay(distance):
return distance/299792458

# This function creates a time and phase shifted copy of the transmitted signal to model the received signal
def get_phase_and_sample_shifted_waveform(original_waveform, sample_shift, phase_shift):
# Perform phase shifting step
phase_shifted_waveform = DO SOMETHING TO 'original_waveform' HERE
# Perform integer number of samples shifting step
new_waveform = zeros_like(phase_shifted_waveform, dtype=complex)
new_waveform[sample_shift:] = phase_shifted_waveform[:-sample_shift]
return new_waveform

max_range = 10000
bandwidth = 0.05*10**9
carrier_frequency = 1*10**9

duty_cycle = 0.1

# Generate chirp waveform
sample_rate, time_per_sample, num_samples_required = find_chirp_sampling_requirements(max_range, carrier_frequency, bandwidth)
my_waveform = generate_lfm(num_samples_required, time_per_sample, duty_cycle, bandwidth, carrier_frequency)

distance_to_target = 5000

two_way_phase_angle = calculate_two_way_phase_angle(distance_to_target, carrier_frequency)
two_way_delay = calculate_two_way_delay(distance_to_target)
two_way_delay_in_samples = two_way_delay/time_per_sample

sample_remainder = int(ceil(two_way_delay_in_samples))-two_way_delay_in_samples
remainder_time = sample_remainder*time_per_sample
time_per_wavelength = 1/carrier_frequency
fraction_of_wavelength = remainder_time/time_per_wavelength
phase_shift = 2*pi*fraction_of_wavelength

phase_and_sample_shifted_waveform = get_phase_and_sample_shifted_waveform(my_waveform, two_way_delay_in_samples, phase_shift)

$$$$
`
• Btw, your comment about real systems not digitizing at RF is false. We do it all the time. Aug 1, 2023 at 22:29
• @Envidia Forgive my comment; that would be my inexperience with working with real systems showing. From a textbook standpoint (and granted, most were written long enough ago that ADC tech have been the limiting factor), it always looks like digitization only occurs at baseband. Anyway, would I be correct in assuming that, even if you digitize at RF, you still downconvert prior to doing any signal processing/matched filtering due to the data quantity? Thank you for your comment
– Jim
Aug 2, 2023 at 10:30
• I have a textbook from 2014 that gushes at the idea of having a 1 GHz 11-bit ADC by 2020, and boy was that prediction wrong. By 2020 we were already doing 4 GHz with 12-bit words by COTS parts, forget about custom ASICs. To your question, yes you're correct. Even at RF you would eventually mix down to baseband and decimate. Aug 2, 2023 at 16:41

You are off in your approach. First things first, however:

For example: say the delay corresponds to 37.465 samples. I can't shift the elements by this much, but I can shift them by 38 samples and say that, in each element, the point of the waveform at which the sample is measured is offset by a phase angle equivalent to this additional proportion of the wavelength.

This is not true in general and, moreover, there is no reason why you can't shift by $$37.465$$ samples. Simply apply the appropriate linear phase in the frequency domain:

$$x(t - \tau) = x(t) \ast \delta( t - \tau) = \mathcal{F}^{-1} \left( \mathcal{F}(x) \cdot e^{j2\pi f \tau} \right)$$

As to how to simulate this kind thing ... You can do it at the carrier if you want, but that is usually memory intensive and unnecessary. You transmit some baseband waveform $$w(t)$$ on some carrier frequency $$f_0$$, that is, $$w(t) \cdot e^{j2\pi f_0 t}$$. The signal that comes back to the radar is delayed by $$\tau$$ seconds: $$w(t-\tau) \cdot e^{j2\pi f_0 (t-\tau) }$$. The first thing the radar will do is baseband this signal so that it can be digitized. Assuming you have a coherent radar, which nearly all are nowadays, this means that what gets digitized is

$$w(t-\tau) \cdot e^{j2\pi f_0 (t-\tau) } \cdot e^{-j2\pi f_0 t} = w(t-\tau) \cdot e^{-j2\pi f_0 \tau}.$$

So all you have to do is shift your waveform by $$\tau$$ seconds (see above) and then mix it with the carrier phase term $$e^{-j2\pi f_0 \tau}$$.

• Perfectly clear and concise answer. Thank you
– Jim
Aug 1, 2023 at 18:46