Skip to content

Commit 42ecedf

Browse files
committed
Improve clock_error()
1 parent aa8f22f commit 42ecedf

File tree

1 file changed

+32
-30
lines changed

1 file changed

+32
-30
lines changed

src/sdr/_simulation/_impairment.py

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)