Frequency Content of an Averaged, Jittered Step


Understanding the frequency content of a measured step function is important in applications such as time-domain reflection (TDR) and time-domain transmission (TDT) measurement. This frequency content is particularly important to understand in cases where frequency domain values, such as S-parameters, are being extracted from the TDR/TDT measurements.

It is typical to remove voltage noise and jitter by averaging multiple acquired signal traces. This works well for voltage noise; sufficient averaging can reduce random voltage noise to arbitray small values. However, as described in a previous note, averaged jitter results in an increase in rise time. In fact, the combination of jitter and averaging is equivalent to convolution of the unjittered signal with a Gaussian with a width equal to the RMS value of the jitter.

In this note the effect of jitter on the frequency content of a step signal with finite rise time is investigated. The combined effects on frequency content turn out to have the same form as either the effects of random jitter or finite rise time on their own, with the controlling parameter $\tau$ being related to the parameters of jitter and risetime by $\tau = \sqrt{{\tau_j}^2 + {\tau_r}^2}$. Here, $\tau_j$ is simply the RMS value of the jitter, while $\tau_r$ is related to the signal risetime as described in the Appendix.


Consider a step function with finite rise time $t_r$ and random jitter with an RMS value of $\tau_j$. Without loss of generality, we will assume the step function is centered around $y=0$ with a height of $1$. That is, it is approaches $-1/2$ for large negative times and $1/2$ for large positive times. The unjittered signal $V_0(t)$ will be modelled as a vertically offset Heavyside step function $H(t)$ convolved with a a Gaussian of width $\tau_{r}$: $$ \begin{align} H'(t) & \equiv H(t) - 1/2 \\ V_0(t) &= H'(t) * \frac{1}{\tau_r\sqrt{2\pi}} e^{-t^2 / {2{\tau_r}^2}} \\ \Rightarrow \hat{V}_0(f) &= \hat{H'}(f) e^{-\omega^2{\tau_r}^2 / 2} \end{align} $$ Here $\tau_r \approx t_{r_{2080}} / 1.68$ where $t_{r_{2080}}$ is the 20%-80% rise time of the step as described in the Appendix. In a previous note, it was shown that averaging a signal with Gaussian jitter with an RMS value of $\tau_j$ is equivalent to multiplying the frequency content by $e^{-\omega^2{\tau_{j}}^2/2}$. Combining this with the above result yields: $$ \begin{align} \bar{\hat{V}}(t) &= \hat{H'}(f) e^{-\omega^2({\tau_r}^2 + {\tau_j}^2)/ 2} \\ &= \hat{H'}(f) e^{-\omega^2\tau^2/ 2} \\ &= \frac{1}{j\omega} e^{-\omega^2\tau^2/ 2} \end{align}$$ Here $\tau^2 \equiv {\tau_r}^2 + {\tau_j}^2$. This results in the following expression for the effective risetime of the averaged, jittered step: $$ \bar{t}_{r_{2080}} \approx 1.68 \tau = 1.68\sqrt{{\tau_r}^2 + {\tau_j}^2}$$

Frequency Content

In order to examine the frequency content, we normalize $\bar{\hat{V}}(t)$ by $\tau$ to obtain: $$ \begin{align} \bar{\hat{V}}(t) / \tau &= \frac{1}{j\omega\tau} e^{-\omega^2\tau^2/ 2} \\ \end{align} $$ This allows us to plot the general shape of the frequency content for averaged step functions with arbitray values of rise time and jitter in terms of $\omega\tau$.

In [1]:
%matplotlib inline
from matplotlib import pyplot as plt
import numpy as np

omega_tau = 10**np.linspace(-2, 1, 64)
mag_V_over_tau = 20 * np.log10(np.exp(-omega_tau**2) / omega_tau)
REF_DB = mag_V_over_tau[0]

plt.plot(omega_tau, mag_V_over_tau, 'b', 
         omega_tau, 20*np.log10(1/omega_tau), 'k--')
plt.xlabel(r"$\omega \tau$")
_ = plt.ylabel(r"$|\hat{V}|/\tau$ (dB)")

Figure 1: The frequency content of an averaged, jittered step with finite risetime. Note the dramatic loss of amplitude for $\omega\tau > 1$. For lower frequencies the amplitude is dominated by the intrinsic frequency content of the ideal step and falls off at 20 dB per decade.


The above results are now checked against results obtained by directly simulating the effect of averaging jittered signals. A set of waveforms with a specified risetime is generated with randomly chosen values of jitter. These waveforms are then averaged to obtain a simulated version of an averaged jittered step. The resultant rise time and frequency spectrum are then compared with the expected valus.

Generate the Unjittered Step

In [2]:
# Choose tau_r and tau_j such that we expect tau to be 0.5
tau_r = 0.3
tau_j = 0.4
tau = 0.5

t = np.linspace(-12, 12, 2401)
dt = t[1] - t[0]
t1 = np.linspace(-10,10,2001)
t2 = np.linspace(-2,2,401)
# Create a Heavyside step function H
H = np.zeros_like(t)
H[t > 0] = 1 
# Convolve with a Gaussian of with tau to generate step with finite edge frequency
def Gaussian(t, tau, dt):
    return np.exp(-((t-dt)/tau)**2/2) / (tau * np.sqrt(2*np.pi))

def step(offset):
    G = Gaussian(t2, tau_r, offset)
    return np.convolve(H, G * dt, "valid")

V0 = step(0)

plt.plot(t, H, 'k--',
         t1, V0, 'k' )
plt.xlim(-10, 10)
_ = plt.ylim(-.1, 1.1)

Figure 2: The unjittered step compared with a step function.

Create the Averaged, Jittered Signals

In [3]:
def jittered_signals(count=10000):
    signals = []
    for i in range(count):
        dt = np.random.normal(0, tau_j)
    return np.asarray(signals)

# Compute a large number of signals with random jitter
# and average them to see the effect on risetime.

signals = jittered_signals()
averaged = signals.mean(axis=0)

# Plot

f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True)

for s in signals[::20]:
    ax1.plot(t1, s, 'k', alpha=0.01)

ax2.plot(t1, V0, 'k--', label="unjittered")
ax2.plot(t1, averaged, 'k', linewidth=2, label="averaged")
ax2.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
_ = ax1.set_ylim(-.1, 1.1)

Figure 3: The jitered step (top) and a comparison of unjiterred with the jittered, averaged steps.


The rise times of the the simulated step functions are measured in order to compare them with the formulas developed above. The Fourier transforms are also compared, although not directly. Since the step is neither periodic nor time-limited, using an FFT on the step function will not work. There are several approaches that can be taken to compare the frequency content of non time-limited signals, but here the simple expedient of looking at the derivative of the step is used. The resultant signal is time limited and suitable the application of an FFT as long as a sufficiently long time period is used to avoid excessive aliasing.

In [4]:
# Time-Domain comparison

def measure_20_80_risetime(t, y):
    # normalize y to [0,1]. Not strictly necessary since step
    # already has this range, but just in case I reuse this later.
    y = y - y.min()
    y = y / y.max()
    # This assumes that y is monotonic
    i1, i2 = np.searchsorted(y, [0.2,0.8])
    t1, t2 = t[i1], t[i2]
    return t2 - t1

tau_r_sim = measure_20_80_risetime(t1, V0) / 1.68
tau_sim = measure_20_80_risetime(t1, averaged) / 1.68
tau_j_sim = np.sqrt(tau_sim**2 - tau_r_sim**2)

print("Simulated tau: {0:.3} versus expected: {1:.3f} ".format(tau_sim, tau))
print("Simulated tau_r: {0:.3} versus expected: {1:.3f} ".format(tau_r_sim, tau_r))
print("Simulated tau_j: {0:.3} versus expected: {1:.3f} ".format(tau_j_sim, tau_j))
Simulated tau: 0.494 versus expected: 0.500 
Simulated tau_r: 0.298 versus expected: 0.300 
Simulated tau_j: 0.394 versus expected: 0.400 
In [5]:
# Frequency-Domain comparison

t_range = t1[-2] - t1[0]
delta_f = 1.0 / t_range
EPSILON = 1e-10 # Used to avoid division by zero
f = np.arange(len(t1)-1) * delta_f + EPSILON

# Compute the derivaties of the ideal, finite-risetime and jittered steps. 
# In the frequency domain, this is equivalent to mulitplying by j*omega.
# The resulting function are thus approximately time limited and suitable
# for using an FFT as long as a suffiecient time period is used to avoid
# excessive aliasing. The resultant FFTs are then divided by 1/j*omega
# to get the frequency content of the jittered step.

FT_H = np.ones_like(f)

dV0 = (V0[1:] - V0[:-1]) 
FT_V0 = np.fft.fft(dV0) / (2j*np.pi*f)

dAvg = (averaged[1:] - averaged[:-1])
FT_Avg = np.fft.fft(dAvg) / (2j*np.pi*f)

# These are the expected values from the theoretical section above.

expected_V0 = np.exp(-(2*np.pi*f)**2*tau_r**2/2)/ (2j*np.pi*f)
expected_avg = np.exp(-(2*np.pi*f)**2*tau**2/2) / (2j*np.pi*f)

# Plot

fig, (ax1) = plt.subplots(1, sharex=True)

ax1.plot(f[1::2], abs(FT_V0[1::2]), 'r', linewidth=2, label="Base Step")
ax1.plot(f, abs(expected_V0), 'k--', linewidth=2)
ax1.plot(f[1::2], abs(FT_Avg[1::2]), 'b', linewidth=2, label="Jittered Step")
ax1.plot(f, abs(expected_avg), 'k--', linewidth=2)

ax1.set_ylim(1e-3, 20)
_ = ax1.legend(loc=0)

Figure 4: Comparison of the Fourier transform magnitude of the unjittered and jittered step with their theoretical values. Nearly exact agreement is observed over the plotted range.


At low frequencies, the frequency content of a jittered step with finite rise time follow that of the ideal step. However, at frequencies above $\omega\tau$ the content falls off dramatically. The quantity $\tau$ is the root-mean-square of the time scales associated with jitter and the rise time of the the unjittered step. Mathematically: $$\begin{align} \bar{\hat{V}}(t) &= \frac{1}{j\omega} e^{-\omega^2\tau^2/ 2} \\ \bar{V}(t) &= H'(t) * \frac{1}{\tau\sqrt{2\pi}} e^{-t^2 / {2\tau^2}} \\ \tau^2 &\equiv {\tau_r}^2 + {\tau_j}^2 \\ \tau_r &\approx t_{r_{2080}} / 1.68 \end{align}$$


Consider a step function with a finite rise time. This will be modelled as the Heavyside step function $H(t)$ convolved with a Gaussion of width $\tau$. The value of $\tau$ is dependent on the desired rise time of the step $t_r$.

Unfortunately, there are many definitions of rise time. Two are common in high-speed digital electronics: the 10%-90% rise time and the 20%-80% rise time. The latter has become increasinly popular in recent rears as signal speeds have increased and signal edges have degraded. The latter definition will be used here unless otherwise specified.

The relationship between the rise time $t_r$ and $\tau$ can be derived by using the fact that convolution in the time domain is equivalent to multiplication in the frequency domain: $$\begin{align} & V(t) = H(t) * \frac{1}{\tau\sqrt{2\pi}} e^{-t^2 / {2\tau^2}} \\ \Rightarrow & \hat{V}(f) = \hat{H}(f) e^{-(2\pi f)^2\tau^2 / 2} \end{align}$$

The relationship between $\tau$ and rise time is now derived by examining the convolution: $$\DeclareMathOperator{\erf}{erf} \begin{align} V(t) &= H(t) * \frac{1}{\tau\sqrt{2\pi}} e^{-t^2 / {2\tau^2}} \\ &= \frac{1}{\tau\sqrt{2\pi}} \int_0^{\infty}{e^{-(t-x)^2 / {2\tau^2}} dx} \\ &= \frac{1}{\sqrt\pi} \int_{-\infty}^{t/(\tau\sqrt{2})}{e^{-x'^2} dx'} \\ &= \frac{1}{2}\left(1 + \erf({t/(\tau\sqrt{2}}) \right) \end{align} $$ Where $x' \equiv (t-x)/(\tau\sqrt 2)$. Due to the symmetry of the error function, if $V(t) = 1-\delta$ at time $t_1$, then $V(t) = \delta$ at time $-t_1$. Thus the rise time $t_r=2 t_1$ and: $$ 2 (1-\delta) - 1 = 1 - 2\delta = \erf({t_1/(\tau\sqrt{2})}) $$ $$ \Rightarrow t_1/(\tau\sqrt{2}) = \erf^{-1}{(1 - 2\delta)} $$ $$\begin{align} \Rightarrow t_r &= 2 t_1 \\ &= 2 \sqrt{2}\tau \erf^{-1}{(1 - 2\delta)} \\ &= 2 \sqrt{2}\tau \erf^{-1}(\Delta) \end{align} $$ Here $\Delta$ is the difference between the two fractions in the rise time specification. Thus $\Delta=0.6$ for 20%-80% rise time, resulting in: $$ t_{r_{2080}} \approx 2\sqrt 2 \tau \cdot 0.595 \approx 1.68 \cdot \tau $$

Note that the above derivation is partially based on that shown in the Wikipedia entry on rise time. Numerical values were computed using Wolfram Alpha.