Using PyBERT as a Library

This Jupyter notebook provides an example of using the functionality of the PyBERT Python package, not as a stand alone GUI application, but rather as a library, importing into a higher level Python script.

Original author: David Banas capn.freako@gmail.com
Original date: June 28, 2021

Copyright © 2021 David Banas, Inc.; all rights reserved World wide.

Table of Contents

Introduction

In the typical use case, PyBERT is run as a stand alone GUI application. However, it is also possible to draw from the PyBERT package, as a library, importing only certain needed features into a larger Python script. This Jupyter notebook provides an example of doing just that.

Furthermore, this example shows how to import PyBERT functionality into a higher level Python script, when IBIS-AMI models are being used, in place of PyBERT's native Tx/Rx models.

We'll take as our design goal PyBERT's default: attempting to move a 10 Gbps symbol stream through 1 meter of 28 gauge unshielded twisted pair (UTP) cabling.

Global Defines

If you get lucky, you might get away w/ only editing this section.

Imports

Here, we import everything we'll need. (I'm not sure why, but these notebooks tend to work more smoothly if you import everything first, before executing any other Python code.)

In this section we conduct our first IBIS-AMI link simulation using PyBERT.

The IBIS-AMI simulation community uses some very specific nomenclature, to describe different parts of a serial communication link. And correct usage of this nomenclature is necessary, in order to avoid confusion. The diagram below illustrates how a serial communication link is conceptualized by an IBIS-AMI modeler and provides the correct nomenclature.

IBIS-AMI Link Diagram & Nomenclature

PyBERT Object

Here, we instantiate and configure our PyBERT object and run a trial simulation of its default channel.

Note: You may need to dismiss some GUI dialog alerts.

Notes

  1. Channel delay: {{f"{(myPyBERT.chnl_dly * 1e9):5.2f} ns"}}

  2. Tx driver output impedance: {{f"{myPyBERT.Rs:5.0f} Ohms"}}

  3. Tx driver parasitic capacitance: {{f"{myPyBERT.Cs*1e12:5.1f} pF"}}

  4. Rx input resistance: {{f"{myPyBERT.RL:5.0f} Ohms"}}

  5. Rx input capacitance: {{f"{myPyBERT.Cp*1e12:5.1f} pF"}}

Interconnect Frequency Response & Characteristic Impedance

Here we plot the calculated raw frequency response and characteristic impedance for the interconnect, for sanity checking.

Notes:

  1. The frequency response shown here would be equivalent to the $S_{21}$ of a 2-port network representing just the interconnect and with port impedances precisely matched to the interconnect characteristic impedance, at every frequency. That is why no ripples are observed.

  2. Note that this interconnect has a raw bandwidth below 1 GHz.

    Question: Would you expect it to support our target Baud rate (10 GBaud)?

  3. Our native PyBERT interconnect has a characteristic impedance slightly larger than the reference: $100 \Omega$.

Interconnect S-parameters

Here we generate and plot the calculated 2-port network for the interconnect, for sanity checking.

Notes:

  1. This does not include the actual termination at the Rx input.
    (Here, the line is assumed to be terminated into the reference impedance.)

  2. The reference impedance is set equal to the Tx output driver differential impedance and assumed real.

  3. Because the network is calculated, as opposed to measured, it is perfectly symmetrical. Therefore, S11 perfectly overlaps S22 and likewise for S21/S12. That is why only two traces seem to be present.

Interconnect Z-parameters

Here we plot the calculated 2-port Z-parameters of the interconnect, for sanity checking. The plot characteristics can be explained as follows:

  1. The resonance peaks are due to multiple full positive reflections at both ends of the line.

    • Z-parameters of a 2-port network are taken with a current source driving one port and the other port open circuited. And both of those terminations exhibit infinite impedance.

    • The position of the first resonance peak is correct, as per:

      $$ \begin{eqnarray} f =& \frac{1}{\tau_{round trip}} \\ =& \frac{1}{10 ns} \\ =& 100 MHz \end{eqnarray} $$

  2. The decay in the amplitude of the resonance peaks is due to increasing loss through the interconnect at high frequency, which lessens the number of significant reflections contributing to the superposition.

  3. The trend toward infinite impedance at very low frequency is real and correct and due to the lack of any d.c. shunt path in the interconnect itself.

  4. The asymptotic decay of Z11/Z22 to approximately 100 $\Omega$ is due the high frequency loss through the interconnect being so great that not even the first reflection makes it back to the driven port with any significant amplitude, and all that is "seen" by the entering wave is the characteristic impedance of the interconnect.

  5. The asymptotic decay to zero of Z21/Z12 is for the same reason: no appreciable energy is making it to the far end of the interconnect, at those high frequencies.

Complete Channel Frequency Response

Here we plot the frequency response of the complete channel, including the real Tx and Rx terminations (including their parasitic capacitance), for sanity checking.

Notes:

  1. The ripples are due to multiple reflections caused by the imperfect Tx and Rx terminations.

  2. The inclusion of the parasitic capacitances of the Tx and Rx terminations has not appreciably shifted the bandwidth of this interconnect.

Channel Step Response

Here we plot the channel step response corresponding to the simulation just run.

Notes:

  1. The Channel step response includes everything through and including the Rx analog termination, but no equalization.

  2. Don't be alarmed that the position of the edge in the step response doesn't agree with the reported channel delay, above. PyBERT "trims" the step response for convenience/efficiency.

Channel Eye Diagram

Let's take a look at the "eye" diagram for the channel alone. That will give us some idea of whether or not we need to add any equalization.

Notes

  1. The eye is completely closed. (This shouldn't come as a surprise, given that the bandwidth of our interconnect is < 1 GHz and, yet, we're attempting to push a 10 GBaud symbol stream through it.)

Tx Deemphasis

The eye above is completely closed. Here we investigate the effect of adding Tx deemphasis on the system eye.

Note: If you changed the Tx IBIS file name, above, then you'll probably get an error like this, the first time you run this cell:

ValueError: Failed parameter tree search looking for: <ParamName>; available keys: dict_keys(['tx_tap_nm2', 'tx_tap_np1', 'tx_tap_units', 'tx_tap_nm1'])

Just swap in one of the listed available keys, in lines 2/3, and you should be good to go.

Notes

  1. We've been able to open our eye nicely, using Tx deemphasis.

Rx CTLE

Here, we investigate the effectiveness of the Rx CTLE as an alternative to the Tx FFE.

Notes

  1. We've also been able to open our eye, using the Rx CTLE, although this results is a distinctly different shape to our eye.

Combined Tx/Rx Equalization

Here, we investigate the effectiveness of using both the Tx Deemphasis and the Rx CTLE.

Notes

  1. The combined usage of both Tx deemphasis and Rx CTLE has yielded a nicely open eye.

DFE

Given the quality of the eye above, there's no real need for a DFE. However, we'll try one here, for the sake of completeness.

Notes

  1. Eye quality is roughly equivalent to the Combined Tx/Rx Equalization case. And, since DFEs are often expensive and power hungry components, we elect to forgo a DFE for this link design.

  2. The DFE: not present line in the output above may be confusing. That line is coming from the IBIS-AMI model and we have that model's DFE deselected, in favor of using PyBERT's native DFE modeling, instead.

Jitter Decomposition & Bathtub Curve Plotting

Here, we decompose the observed jitter into its different components and use that information to plot "bathtub" curves. For this, we'll return to the pre-DFE simulation configuration.

Final Touches

The eye, jitter histogram, and bathtub curves above look great. One might think we're done. However, we've omitted two very important real World effects present in any serial communication link:

  1. random noise

    Any real World link will have some amount of noise present that is completely independent of the data being sent. We typically model this sort of noise as being truly random, even though it really isn't.

  2. CDR induced jitter

    When transmitting data serially, we don't transmit a separate clock. Instead, the receiver must "extract" the clock from the incoming data stream. The circuity that does this clock extraction often injects its own additional jitter into the system, and this must also be modeled.

Let's add these final two finishing touches now...

Random Noise

PyBERT has a parameter for setting the standard deviation of the random vertical noise that it will add to the Tx output signal: rn. Let's set that parameter to some non-zero value and see how it changes what we observe...

Note how the eye now looks much more like something we'd actually observe on a scope in the lab.

Let's see how the jitter distribution has been affected...

Note how the jitter distribution now looks much more like a typical dual-Dirac distribution you may have seen displayed on a BERT scope.

Also, note the non-zero value being reported for RJ.
(If you check above then you'll see that this value was previously being reported as zero.)
Question: Why is this value not equal to: 0.5, the value we assigned to rn?

Finally, let's see how the bathtub curves have been affected by our addition of random noise...

Note that the "walls" of the bathtub curves now have a shape we're more accustomed to seeing, having lost their vertical "cliffs"; this is directly due to the addition of random noise.

CDR Induced Jitter

The circuitry that extracts the original clock signal from the incoming symbol stream is called the clock from data recovery (CDR) circuit. And it introduces some jitter of its own, which we must include in our analysis.

Now, the exact relationship between this CDR induced jitter and that of the incoming symbol stream is quite complicated. And that makes a correlated analysis beyond the scope of this simple treatment. So, instead, we offer a simpler uncorrelated analysis, asking the reader to take it on faith that this leads to a conservative estimation of BER.

An uncorrelated analysis of CDR induced jitter proceeds as follows:

  1. Assemble a time interval error (TIE) track for the sampling instants produced by the CDR, just as we do for the zero crossings of the incoming symbol stream.

  2. Instead of decomposing the TIE, as we do for the incoming symbol stream crossings, just measure the variance of this new TIE: $\sigma^2_{CDR}$.

  3. Model the CDR induced jitter as a Gaussian random process having variance: $\sigma^2_{CDR}$.

  4. Repeat the jitter extrapolation and associated bathtub curve generation process, after horizontally perturbing the crossing times of the incoming symbol stream with sampled values from our new "noise" generator.

    Note the difference, here, wrt/ previous applications of "random" noise: there, we were vertically perturbing the samples of the incoming symbol stream.

Note that in this case the CDR is not contributing any appreciable extra jitter to the system. That's because its inherent "flywheel" action is sufficiently momentous to filter out the jitter in the incoming symbol stream and provide a rock steady "heart beat" for signal sampling.