sdr.clock_error(x: ArrayLike, error: ArrayLike, error_rate: float = 0.0, center_freq: float | None = None, sample_rate: float | None = None) NDArray

Applies a clock error to the time-domain signal \(x[n]\).

This clock error could be caused by transmitter clock error, receiver clock error, or Doppler effects.

Parameters:
x: ArrayLike

The time-domain signal \(x[n]\) to which the clock error is applied.

error: ArrayLike

The fractional clock error \(\epsilon\), which is unitless, with 0 representing no clock error. For example, 1e-6 represents 1 ppm of clock error.

The fractional clock error can be calculated from a transmitter frequency offset \(\Delta f = f_{c,\text{new}} - f_c\) and carrier frequency \(f_c\) as \(\epsilon = \Delta f / f_c\). For example, a 1 kHz transmitter frequency error applied to a signal with a 1 GHz carrier frequency is 1e-6 or 1 ppm.

The fractional clock error can also be calculated from transmitter sample rate offset \(\Delta f_s = f_s - f_{s,\text{new}}\) and sample rate \(f_s\) as \(\epsilon = \Delta f_s / f_s\). For example, a -10 S/s transmitter sample rate error applied to a signal with a 10 MS/s sample rate is -1e-6 or -1 ppm.

The fractional clock error can also be calculated from relative velocity \(\Delta v\) and speed of light \(c\) as \(\epsilon = \Delta v / c\). For example, a 60 mph (or 26.82 m/s) relative velocity between the transmitter and receiver (they are moving toward each other) is 8.946e-8 or 8.9 ppb.

Note

  • For positive transmitter clock error \(\epsilon\), pass \(\epsilon\) for error.

  • For positive relative velocity \(\Delta v\) between the transmitter and receiver (they are moving toward each other), pass \(\Delta v / c\) for error.

  • For positive receiver clock error \(\epsilon\), pass \(-\epsilon / (1 + \epsilon)\) for error. This is because the error effect in this function is applied to the transmitted signal.

error_rate: float = 0.0

The clock error \(\Delta \epsilon / \Delta t\) in 1/s.

center_freq: float | None = None

The center frequency \(f_c\) of the complex baseband signal in Hz. If \(x[n]\) is complex, this must be provided.

sample_rate: float | None = None

The sample rate \(f_s\) in samples/s. If \(x[n]\) is complex, this must be provided.

Returns:

The signal \(x[n]\) with clock error applied.

Examples

This example demonstrates the effect of clock error on a real passband signal. The signal has a carrier frequency of 100 kHz. A frequency offset of 20 kHz is desired, corresponding to a clock error or 0.2. The clock error is added to the transmitter, and then removed at the receiver. Notice that the transmitted signal is compressed in time and shifted in frequency. Also notice that the corrected received signal matches the original.

In [1]: sample_rate = 2e6; \
   ...: freq = 100e3; \
   ...: duration = 1000e-6; \
   ...: x = sdr.sinusoid(duration, freq, sample_rate=sample_rate, complex=False)
   ...: 

In [2]: freq_offset = 20e3; \
   ...: error = freq_offset / freq; \
   ...: print("Clock error:", error); \
   ...: y = sdr.clock_error(x, error)
   ...: 
Clock error: 0.2

In [3]: error = -error / (1 + error); \
   ...: print("Clock error:", error); \
   ...: z = sdr.clock_error(y, error)
   ...: 
Clock error: -0.16666666666666669

In [4]: plt.figure(); \
   ...: sdr.plot.time_domain(x - 0, sample_rate=sample_rate, label="No clock error"); \
   ...: sdr.plot.time_domain(y - 3, sample_rate=sample_rate, label="Added Tx clock error"); \
   ...: sdr.plot.time_domain(z - 6, sample_rate=sample_rate, label="Removed Tx clock error"); \
   ...: plt.legend(loc="lower left"); \
   ...: plt.title("Real passband signals with and without clock error");
   ...: 

In [5]: plt.figure(); \
   ...: sdr.plot.dtft(x, sample_rate=sample_rate, label="No clock error"); \
   ...: sdr.plot.dtft(y, sample_rate=sample_rate, label="Added Tx clock error"); \
   ...: sdr.plot.dtft(z, sample_rate=sample_rate, label="Removed Tx clock error"); \
   ...: plt.axvline(freq, color="k", linestyle="--"); \
   ...: plt.axvline(freq + freq_offset, color="k", linestyle="--"); \
   ...: plt.xlim(80e3, 140e3);
   ...: 
../../_images/sdr_clock_error_1.svg ../../_images/sdr_clock_error_2.svg

This example demonstrates the effect of clock error on a complex baseband signal. The signal has a carrier frequency of 1 MHz and sample rate of 2 MS/s. A frequency offset of 100 kHz is desired, corresponding to a clock error of ~0.1. The clock error is added to the transmitter, and then removed at the receiver. Notice that the transmitted signal is compressed in time and shifted in frequency. Also notice that the corrected received signal matches the original.

In [6]: sample_rate = 2e6; \
   ...: center_freq = 1e6; \
   ...: freq = 10e3; \
   ...: duration = 1000e-6; \
   ...: x = sdr.sinusoid(duration, freq, sample_rate=sample_rate)
   ...: 

In [7]: freq_offset = 100e3; \
   ...: error = freq_offset / (center_freq + freq); \
   ...: print("Clock error:", error); \
   ...: y = sdr.clock_error(x, error, 0, center_freq, sample_rate=sample_rate)
   ...: 
Clock error: 0.09900990099009901

In [8]: error = -error / (1 + error); \
   ...: print("Clock error:", error); \
   ...: z = sdr.clock_error(y, error, 0, center_freq, sample_rate=sample_rate)
   ...: 
Clock error: -0.09009009009009009

In [9]: plt.figure(); \
   ...: sdr.plot.time_domain(x - 0 - 0j, sample_rate=sample_rate, label="No clock error"); \
   ...: sdr.plot.time_domain(y - 3 - 3j, sample_rate=sample_rate, label="Added Tx clock error"); \
   ...: sdr.plot.time_domain(z - 6 - 6j, sample_rate=sample_rate, label="Removed Tx clock error"); \
   ...: plt.legend(loc="lower left"); \
   ...: plt.title("Complex baseband signals with and without clock error");
   ...: 

In [10]: plt.figure(); \
   ....: sdr.plot.dtft(x, sample_rate=sample_rate, label="No clock error"); \
   ....: sdr.plot.dtft(y, sample_rate=sample_rate, label="Added Tx clock error"); \
   ....: sdr.plot.dtft(z, sample_rate=sample_rate, label="Removed Tx clock error"); \
   ....: plt.axvline(freq, color="k", linestyle="--"); \
   ....: plt.axvline(freq + freq_offset, color="k", linestyle="--"); \
   ....: plt.xlim(-20e3, 120e3);
   ....: 
../../_images/sdr_clock_error_3.svg ../../_images/sdr_clock_error_4.svg