Modules in pybert package

A package of Python modules, used by the PyBERT application.

Original Author: David Banas <capn.freako@gmail.com>

Original Date: 17 June 2014

Testing by: Mark Marlett <mark.marlett@gmail.com>

Copyright (c) 2014 by David Banas; All rights reserved World wide.

pybert - PyBERT class definition.

Bit error rate tester (BERT) simulator, written in Python.

Original Author: David Banas <capn.freako@gmail.com> Original Date: 17 June 2014 Testing by: Mark Marlett <mark.marlett@gmail.com>

This Python script provides a GUI interface to a BERT simulator, which can be used to explore the concepts of serial communication link design.

The application source is divided among several files, as follows:

pybert.py - This file. It contains:
  • independent variable declarations
  • default initialization
  • the definitions of those dependent variables, which are handled automatically by the Traits/UI machinery.
pybert_view.py - Contains the main window layout definition, as
well as the definitions of user invoked actions (i.e.- buttons).
pybert_cntrl.py - Contains the definitions for those dependent
variables, which are updated not automatically by the Traits/UI machinery, but rather by explicit user action (i.e. - button clicks).

pybert_util.py - Contains general purpose utility functionality.

dfe.py - Contains the decision feedback equalizer model.

cdr.py - Contains the clock data recovery unit model.

Copyright (c) 2014 by David Banas; All rights reserved World wide.

class pybert.pybert.PyBERT[source]

A serial communication link bit error rate tester (BERT) simulator with a GUI interface.

Useful for exploring the concepts of serial communication link design.

pybert_cntrl - Model control logic.

pybert.pybert_cntrl.my_run_simulation(self, initial_run=False)[source]

Runs the simulation.

Inputs:

  • initial_run If True, don’t update the eye diagrams, since they haven’t been created, yet.

    (Optional; default = False.)

pybert.pybert_cntrl.update_results(self)[source]

Updates all plot data used by GUI.

pybert.pybert_cntrl.update_eyes(self)[source]

Update the heat plots representing the eye diagrams.

pybert_view - Main GUI window layout definition.

class pybert.pybert_view.MyHandler[source]

This handler is instantiated by the View and handles user button clicks.

pybert_util - Various utilities used by other modules.

pybert.pybert_util.moving_average(a, n=3)[source]

Calculates a sliding average over the input vector.

pybert.pybert_util.find_crossing_times(t, x, min_delay=0.0, rising_first=True, min_init_dev=0.1, thresh=0.0)[source]

Finds the threshold crossing times of the input signal.

Inputs:

  • t Vector of sample times. Intervals do NOT need to be uniform.

  • x Sampled input vector.

  • min_delay Minimum delay required, before allowing crossings.

    (Helps avoid false crossings at beginning of signal.) Optional. Default = 0.

  • rising_first When True, start with the first rising edge found.

    Optional. Default = True. When this option is True, the first rising edge crossing is the first crossing returned. This is the desired behavior for PyBERT, because we always initialize the bit stream with [0, 1, 1], in order to provide a known synchronization point for jitter analysis.

  • min_init_dev The minimum initial deviation from zero, which must

    be detected, before searching for crossings. Normalized to maximum input signal magnitude. Optional. Default = 0.1.

  • thresh Vertical crossing threshold.

Outputs:

  • xings The crossing times.
pybert.pybert_util.find_crossings(t, x, amplitude, min_delay=0.0, rising_first=True, min_init_dev=0.1, mod_type=0)[source]

Finds the crossing times in a signal, according to the modulation type.

Inputs:

Required:

  • t: The times associated with each signal sample.

  • x: The signal samples.

  • amplitude: The nominal signal amplitude.

    (Used for determining thresholds, in the case of some modulation types.)

Optional:

  • min_delay: The earliest possible sample time we want returned.

    Default = 0.

  • rising_first When True, start with the first rising edge found.

    When this option is True, the first rising edge crossing is the first crossing returned. This is the desired behavior for PyBERT, because we always initialize the bit stream with [0, 1, 1], in order to provide a known synchronization point for jitter analysis. Default = True.

  • min_init_dev The minimum initial deviation from zero, which must

    be detected, before searching for crossings. Normalized to maximum input signal magnitude. Default = 0.1.

  • mod_type: The modulation type. Allowed values are: (Default = 0.)
    • 0: NRZ
    • 1: Duo-binary
    • 2: PAM-4

Outputs:

  • xings: The crossing times.
pybert.pybert_util.calc_jitter(ui, nbits, pattern_len, ideal_xings, actual_xings, rel_thresh=6, num_bins=99, zero_mean=True)[source]

Calculate the jitter in a set of actual zero crossings, given the ideal crossings and unit interval.

Inputs:

  • ui : The nominal unit interval.
  • nbits : The number of unit intervals spanned by the input signal.
  • pattern_len : The number of unit intervals, before input bit stream repeats.
  • ideal_xings : The ideal zero crossing locations of the edges.
  • actual_xings : The actual zero crossing locations of the edges.
  • rel_thresh : (optional) The threshold for determining periodic jitter spectral components (sigma).
  • num_bins : (optional) The number of bins to use, when forming histograms.
  • zero_mean : (optional) Force the mean jitter to zero, when True.

Outputs:

  • jitter : The total jitter.
  • t_jitter : The times (taken from ‘ideal_xings’) corresponding to the returned jitter values.
  • isi : The peak to peak jitter due to intersymbol interference.
  • dcd : The peak to peak jitter due to duty cycle distortion.
  • pj : The peak to peak jitter due to uncorrelated periodic sources.
  • rj : The standard deviation of the jitter due to uncorrelated unbounded random sources.
  • tie_ind : The data independent jitter.
  • thresh : Threshold for determining periodic components.
  • jitter_spectrum : The spectral magnitude of the total jitter.
  • tie_ind_spectrum : The spectral magnitude of the data independent jitter.
  • spectrum_freqs : The frequencies corresponding to the spectrum components.
  • hist : The histogram of the actual jitter.
  • hist_synth : The histogram of the extrapolated jitter.
  • bin_centers : The bin center values for both histograms.
pybert.pybert_util.make_uniform(t, jitter, ui, nbits)[source]

Make the jitter vector uniformly sampled in time, by zero-filling where necessary.

The trick, here, is creating a uniformly sampled input vector for the FFT operation, since the jitter samples are almost certainly not uniformly sampled. We do this by simply zero padding the missing samples.

Inputs:

  • t : The sample times for the ‘jitter’ vector.
  • jitter : The input jitter samples.
  • ui : The nominal unit interval.
  • nbits : The desired number of unit intervals, in the time domain.

Output:

  • y : The uniformly sampled, zero padded jitter vector.
  • y_ix : The indices where y is valid (i.e. - not zero padded).
pybert.pybert_util.calc_gamma(R0, w0, Rdc, Z0, v0, Theta0, ws)[source]

Calculates propagation constant from cross-sectional parameters.

The formula’s applied are taken from Howard Johnson’s “Metallic Transmission Model” (See “High Speed Signal Propagation”, Sec. 3.1.)

Inputs:
  • R0 skin effect resistance (Ohms/m)
  • w0 cross-over freq.
  • Rdc d.c. resistance (Ohms/m)
  • Z0 characteristic impedance in LC region (Ohms)
  • v0 propagation velocity (m/s)
  • Theta0 loss tangent
  • ws frequency sample points vector
Outputs:
  • gamma frequency dependent propagation constant
  • Zc frequency dependent characteristic impedance
pybert.pybert_util.calc_G(H, Rs, Cs, Zc, RL, Cp, CL, ws)[source]

Calculates fully loaded transfer function of complete channel.

Inputs:
  • H unloaded transfer function of interconnect
  • Rs source series resistance
  • Cs source parallel (parasitic) capacitance
  • Zc frequency dependent characteristic impedance of the interconnect
  • RL load resistance (differential)
  • Cp load parallel (parasitic) capacitance (single ended)
  • CL load series (d.c. blocking) capacitance (single ended)
  • ws frequency sample points vector
Outputs:
  • G frequency dependent transfer function of channel
pybert.pybert_util.calc_eye(ui, samps_per_ui, height, ys, clock_times=None)[source]

Calculates the “eye” diagram of the input signal vector.

Inputs:
  • ui unit interval (s)

  • samps_per_ui # of samples per unit interval

  • height height of output image data array

  • ys signal vector of interest

  • clock_times (optional)

    vector of clock times to use for eye centers. If not provided, just use mean zero-crossing and assume constant UI and no phase jumps. (This allows the same function to be used for eye diagram creation, for both pre and post-CDR signals.)

Outputs:
  • img_array The “heat map” representing the eye diagram.

    Each grid location contains a value indicating the number of times the signal passed through that location.

pybert.pybert_util.make_ctle(rx_bw, peak_freq, peak_mag, w)[source]

Generate the frequency response of a continuous time linear equalizer (CTLE), given the:

  • signal path bandwidth,
  • peaking specification, and
  • list of frequencies of interest.

We use the ‘invres()’ function from scipy.signal, as it suggests itself as a natural approach, given our chosen use model of having the user provide the peaking frequency and degree of peaking.

That is, we define our desired frequency response using one zero and two poles, where:

  • The pole locations are equal to:
    • the signal path natural bandwidth, and
    • the user specified peaking frequency.
  • The zero location is chosen, so as to provide the desired degree of peaking.

Inputs:

  • rx_bw The natural (or, unequalized) signal path bandwidth (Hz).

  • peak_freq The location of the desired peak in the frequency

    response (Hz).

  • peak_mag The desired relative magnitude of the peak (dB). (mag(H(0)) = 1)

  • w The list of frequencies of interest (rads./s).

Outputs:

  • w, H The resultant complex frequency response, at the

    given frequencies.

pybert.pybert_util.trim_impulse(g, Ts, chnl_dly=0.0)[source]
Trim impulse response, for more useful display, by:
  • eliminating 90% of the overall delay from the beginning, and
  • clipping off the tail, after 99.9% of the total power has been captured.

Inputs:

  • g impulse response
  • Ts sample interval (same units as ‘chnl_dly’)
  • chnl_dly (optional) channel delay

Outputs:

  • g_trim trimmed impulse response
  • start_ix index of first returned sample

dfe - DFE behavioral model.

Behavioral model of a decision feedback equalizer (DFE).

Original Author: David Banas <capn.freako@gmail.com> Original Date: 17 June 2014

This Python script provides a behavioral model of a decision feedback equalizer (DFE). The class defined, here, is intended for integration into the larger ‘PyBERT’ framework.

Copyright (c) 2014 by David Banas; All rights reserved World wide.

class pybert.dfe.LfilterSS(b, a)[source]

A single steppable version of scipy.signal.lfilter().

step(x)[source]

Step the filter, using the supplied next input value, and return the next output value.

class pybert.dfe.DFE(n_taps, gain, delta_t, alpha, ui, n_spb, decision_scaler, mod_type=0, bandwidth=100000000000.0, n_ave=10, n_lock_ave=500, rel_lock_tol=0.01, lock_sustain=500, ideal=True)[source]

Behavioral model of a decision feedback equalizer (DFE).

decide(x)[source]

Make the bit decisions, according to modulation type.

Inputs:
  • x: The signal value, at the decision time.
Outputs:
  • decision: One of:

    {-1, 1} (NRZ) {-1, 0, +1} (Duo-binary) {-1, -1/3, +1/3, +1} (PAM-4)

    , according to what the ideal signal level should have been. (‘decision_scaler’ normalized)

  • bits: The list of bits recovered.

run(sample_times, signal)[source]

Run the DFE on the input signal.

step(decision, error, update)[source]

Step the DFE, according to the new decision and error inputs.

cdr - CDR behavioral model.

Behavioral model of a “bang-bang” clock data recovery (CDR) unit.

Original Author: David Banas <capn.freako@gmail.com> Original Date: 17 June 2014

This Python script provides a behavioral model of a “bang-bang” clock data recovery (CDR) unit. The class defined, here, is intended for integration into the larger ‘PyBERT’ framework.

Copyright (c) 2014 by David Banas; All rights reserved World wide.

class pybert.cdr.CDR(delta_t, alpha, ui, n_lock_ave=500, rel_lock_tol=0.01, lock_sustain=500)[source]

A class providing behavioral modeling of a ‘bang- bang’ clock data recovery (CDR) unit.

adapt(samples)[source]

Adapt period/phase, according to 3 samples.

Synopsis:
(ui, locked) = adapt(samples)

Should be called, when the clock has just struck.

Inputs:

  • samples a list of 3 samples of the input waveform: - at the last clock time - at the last unit interval boundary time - at the current clock time

Outputs:

  • ui the new unit interval estimate
  • locked Boolean flag indicating ‘locked’ status
locked

The current locked state.

ui

The current unit interval estimate.