N109X-Series Oscilloscope with acquisition limit test

This Python example uses an N109X-series DCA-M oscilloscope to perform an eye measurement (bit rate) on channel 6A. The programs performs the following tasks:

  • Places FlexDCA to its default settings. This places the FlexDCA triggering to front panel which is required to view a valid eye diagram, and then makes all the required setting to view an eye diagram.
  • Queries the N109X to see if it supports pattern locking (option PLK) and then turns on pattern locking if available.
  • Returns the measured trigger rate that is input to the N109X.
  • Runs an acquisition limit test and then activates the bit-rate measurement on the data.

About the :TRIGger:MRATe? query

The :TRIGger:MRATe? query returns the baud rate of the N109X’s clock input signal. For this query to work, at least one of the N109X’s input channels must be turned on, but a signal does not need to be connected to the channel. Also, the N109X’s data acquisition must be in Run mode, or, if in single mode, a single acquisition must first be run to ensure valid data for the measurement.

To run this program

  • Run this program on a PC that has FlexDCA running. In the following listing, FlexDCA is identified by the red text: localhost.
  • If you change localhost to an 86100D, you can run the program on a PC to control FlexDCA on an 86100D. Connect the N109X to the 86100D.

  • Install an N109X-series oscilloscope to FlexDCA’s slot 6. Change the DCAMSLT constant if you want to use a different slot.
  • Data in is expected to be 10.3125 GBd, but you can change this to any acceptable rate for the oscilloscope.
  • Connect valid signal to channel 6A on the N1090X.
  • Connect a clock to the N1090X’s Clock In.
  • Display an eye diagram on FlexDCA.

Example Script

Copy

DCA-M-eye-meas.py

# -*- coding: utf-8 -*-
""" Demonstrates measurements on DCA-M oscilloscope.
- Requres a N109X-series DCA-M oscilloscope with valid eye diagram displayed.
- Change the CHANNEL constant to match your setup.
- ADDRESS constant is set for FlexDCA and DCA-M on PC.
- Change ADDRESS constant to DCA-X's address if DCA-M is connected
to the DCA-X.
Data in is expected to be 10.3125 Gb/s, but you can change this
to any acceptable rate for the oscilloscope.
The default setup command places the DCA-M triggering to front
panel which is required to view a valid eye diagram.
"""
import pyvisa as visa  # import VISA library
ADDRESS = 'TCPIP0::localhost::hislip0,4880::INSTR'
#ADDRESS = 'TCPIP0::K-86100D-00003::hislip0,4880::INSTR'
CHANNEL = '5A'  # N109X's channel


def open_flexdca_connection(address):
    """ Opens visa connection to FlexFlexDCA. """
    print('Connecting to Flexdca ...')
    try:
        rm = visa.ResourceManager()
        connection = rm.open_resource(address)
        connection.timeout = 20000  # Set connection timeout to 20s
        connection.read_termination = '\n'
        connection.write_termination = '\n'
        inst_id = connection.query('*IDN?')
        print('\nFlexDCA connection established to:\n' + inst_id, flush=True)
        connection.write(':SYSTem:DEFault')
        connection.query('*OPC?')
    except (visa.VisaIOError, visa.InvalidSession):
        print('\nVISA ERROR: Cannot open instrument address.\n', flush=True)
        return None
    except Exception as other:
        print('\nVISA ERROR: Cannot connect to instrument:', other, flush=True)
        print('\n')
        return None
    return connection


def show_module_information(FlexDCA, channel):
    """ Queries information from the DCA-M. Returns a string
    of DCA-M's options. """
    slot = channel[0]
    print('\nDCA-M Device ID: ', FlexDCA.query(':EMODules:DCAM' + slot + ':DEVice?'))
    print('DCA-M model: ', FlexDCA.query(':SYSTem:MODel? SLOT' + slot))
    print('Options: ', FlexDCA.query(':SYSTem:OPTions? SLOT' + slot))
    print('Trigger source: ', FlexDCA.query(':SLOT' + slot + ':TRIGger:SOURce?'))
    clockrate = FlexDCA.query(':SLOT' + slot + ':TRIG:MRATe?')
    if '-1.00' in clockrate or '0.00' in clockrate:
        print('ERROR: DCA-M is not triggered. Check inputs.')
    else:
        print('Measured clock rate: ', clockrate)


def return_scalar(FlexDCA, query):
    """ Returns a FlexDCA scalar measurement result. """
    import time

    class ScalarMeasQuestionableException(Exception):
        """ A scalar measurement result is questionable. """
        pass

    class ScalarMeasTimeOutException(Exception):
        """ A scalar measurement has timed out. """
        pass

    timeout = FlexDCA.timeout / 1000  # convert ms to s
    query = query.strip('?')
    start_time = time.time()  # time in seconds
    while(True):
        time.sleep(0.2)
        status = FlexDCA.query(query + ':STATus?')
        if 'CORR' in status:  # valid measurement result
            return FlexDCA.query(query + '?')  # get measurement
        elif 'QUES' in status:  # questionable results
            s = query + '\nReason: ' + FlexDCA.query(query + ':STATus:REASon?')
            raise ScalarMeasQuestionableException(s)
        elif (int(time.time() - start_time)) > timeout:  # IO timout
            s = query + '\nReason: ' + FlexDCA.query(query + ':STATus:REASon?')
            raise ScalarMeasTimeOutException(s)


def make_measurements(FlexDCA, slot):
    """ Displays four measurements in FlexDCA's results panel.
    Returns the result of each measurement. """
    FlexDCA.write(':MEASure:EYE:LIST:CLEar')
    FlexDCA.write(':MEASure:EYE:BITRate')
    FlexDCA.write(':MEASure:EYE:FALLtime')
    FlexDCA.write(':MEASure:EYE:RISetime')
    FlexDCA.write(':MEASure:EYE:AMPLitude')
    print('-' * 20, '\nMeasured:')
    meas = return_scalar(FlexDCA, ':MEASure:EYE:BITRate?')
    print('Eye Bit Rate: ' + meas + ' b/s')
    meas = return_scalar(FlexDCA, ':MEASure:EYE:FALLtime?')
    print('Fall Time: ' + meas + 's')
    meas = return_scalar(FlexDCA, ':MEASure:EYE:RISetime?')
    print('Rise Time: ' + meas + 's')
    meas = return_scalar(FlexDCA, ':MEASure:EYE:AMPLitude?')
    print('Eye Amplitude: ' + meas)


FlexDCA = open_flexdca_connection(ADDRESS)
show_module_information(FlexDCA, CHANNEL)
print('Acquiring data...')
make_measurements(FlexDCA, CHANNEL[0])
FlexDCA.write(':SYSTem:GTLocal')
FlexDCA.close()