@@ -406,39 +406,30 @@ def clock_error(
406406
407407 Arguments:
408408 x: The time-domain signal $x[n]$ to which the clock error is applied.
409-
410- .. warning::
411-
412- The signal must be a real passband signal or a complex baseband signal (with 0 Hz baseband frequency).
413-
414- If the signal is a real passband signal, time will be compressed resulting in a carrier frequency
415- change. If the signal is a complex baseband signal, time will similarly be compressed. However,
416- the zero-IF baseband signal will not observe a frequency shift, since it was always mixed to baseband.
417- Therefore, there is a subsequent frequency shift corresponding to the expected frequency shift at
418- passband.
419-
420- If a complex low-IF signal is provided, the IF frequency will be shifted during time compression.
421- This can become noticeable at high clock errors, e.g. 1,000 ppm or more. It is not advised to use
422- this function with complex low-IF signals.
423-
424409 error: The fractional clock error $\epsilon$, which is unitless, with 0 representing no clock error.
425410 For example, 1e-6 represents 1 ppm of clock error.
426411
427- The fractional clock error can be calculated from frequency offset $\Delta f = f_{c,\text{new}} - f_c$ and
428- carrier frequency $f_c$ as $\epsilon = \Delta f / f_c$. For example, a 1 kHz frequency error applied to a
429- signal with a 1 GHz carrier frequency is 1e-6 or 1 ppm.
412+ The fractional clock error can be calculated from a transmitter frequency offset $\Delta f = f_{c,\text{new}} - f_c$
413+ and carrier frequency $f_c$ as $\epsilon = \Delta f / f_c$. For example, a 1 kHz transmitter frequency
414+ error applied to a signal with a 1 GHz carrier frequency is 1e-6 or 1 ppm.
430415
431- The fractional clock error can also be calculated from sample rate offset $\Delta f_s = f_s - f_{s,\text{new}}$
432- and sample rate $f_s$ as $\epsilon = \Delta f_s / f_s$. For example, a -10 S/s sample rate error applied
433- to a signal with a 10 MS/s sample rate is -1e-6 or -1 ppm.
416+ The fractional clock error can also be calculated from transmitter sample rate offset $\Delta f_s = f_s - f_{s,\text{new}}$
417+ and sample rate $f_s$ as $\epsilon = \Delta f_s / f_s$. For example, a -10 S/s transmitter sample rate
418+ error applied to a signal with a 10 MS/s sample rate is -1e-6 or -1 ppm.
434419
435420 The fractional clock error can also be calculated from relative velocity $\Delta v$ and speed of light
436421 $c$ as $\epsilon = \Delta v / c$. For example, a 60 mph (or 26.82 m/s) relative velocity between the
437422 transmitter and receiver is 8.946e-8 or 8.9 ppb.
438423
424+ .. warning::
425+
426+ If specifying the transmitter clock error or Doppler effects, pass $\epsilon$. If specifying
427+ the receiver clock error, pass $\frac{-\epsilon}{1 + \epsilon}$. This is because the error effect is
428+ applied to the transmitted signal.
429+
439430 error_rate: The clock error $\Delta \epsilon / \Delta t$ in 1/s.
440- center_freq: The center frequency $f_c$ of the complex baseband signal in Hz. 0 Hz baseband frequency must
441- correspond to the signal's carrier frequency. If $x[n]$ is complex, this must be provided.
431+ center_freq: The center frequency $f_c$ of the complex baseband signal in Hz. If $x[n]$ is complex,
432+ this must be provided.
442433 sample_rate: The sample rate $f_s$ in samples/s. If $x[n]$ is complex, this must be provided.
443434
444435 Returns:
@@ -485,17 +476,23 @@ def clock_error(
485476 plt.xlim(80e3, 140e3);
486477
487478 This example demonstrates the effect of clock error on a complex baseband signal. The signal has a carrier
488- frequency of 1 MHz and sample rate of 2 MS/s. A frequency offset of 100 kHz is desired, corresponding to a
479+ frequency of 1 MHz and sample rate of 2 MS/s. A frequency offset of ~ 100 kHz is desired, corresponding to a
489480 clock error of 0.1. The clock error is added to the transmitter, and then removed at the receiver. Notice that
490481 the transmitted signal is compressed in time and shifted in frequency. Also notice that the corrected received
491482 signal matches the original.
492483
484+ Notice, however, that more than 100 kHz of frequency offset is realized with a 0.1 clock error. This is because
485+ the complex baseband signal is not zero-IF. The 10 kHz IF frequency is also shifted up in the frequency
486+ by the time compression. This is because the physical signal has a carrier frequency of 1.010 MHz. The resulting
487+ frequency after clock error is 1.1 * 1.010 MHz.
488+
493489 .. ipython:: python
494490
495491 sample_rate = 2e6; \
496492 center_freq = 1e6; \
493+ freq = 10e3; \
497494 duration = 1000e-6; \
498- x = sdr.sinusoid(duration, 0 , sample_rate=sample_rate)
495+ x = sdr.sinusoid(duration, freq , sample_rate=sample_rate)
499496
500497 freq_offset = 100e3; \
501498 error = freq_offset / center_freq; \
@@ -519,8 +516,8 @@ def clock_error(
519516 sdr.plot.dtft(x, sample_rate=sample_rate, label="No clock error"); \
520517 sdr.plot.dtft(y, sample_rate=sample_rate, label="Added Tx clock error"); \
521518 sdr.plot.dtft(z, sample_rate=sample_rate, label="Removed Tx clock error"); \
522- plt.axvline(0 , color="k", linestyle="--"); \
523- plt.axvline(freq_offset, color="k", linestyle="--"); \
519+ plt.axvline(freq , color="k", linestyle="--"); \
520+ plt.axvline(freq + freq_offset, color="k", linestyle="--"); \
524521 plt.xlim(-20e3, 120e3);
525522
526523 Group:
@@ -530,9 +527,14 @@ def clock_error(
530527 error = verify_arraylike (error , float = True )
531528 verify_scalar (error_rate , float = True )
532529
533- # Apply time compression using resampling
534- sr_offset = - error / (1 + error )
535- y = sample_rate_offset (x , sr_offset , 0 )
530+ # Apply time compression using resampling. If the error is positive, then the transmitted signal is compressed in
531+ # time. To create that effect on the perfect input signal, we suppose that the input signal was sampled at the
532+ # faster rate (transmitter rate) and then we resample it at our desired rate (receiver rate), which is -error
533+ # from 1 + error. All the values here are normalized to the sample rate. We don't use the sample rate, because
534+ # None can be passed in.
535+ sr_offset = - error # Normalized samples/s
536+ sr_offset_rate = - error_rate # Normalized samples/s^2
537+ y = sample_rate_offset (x , sr_offset , sr_offset_rate , sample_rate = 1 + error )
536538
537539 if np .issubdtype (x .dtype , np .floating ):
538540 verify_not_specified (center_freq )
0 commit comments