Jitter mode measurements
This simple Python script, jitter_mode.py, installs a simulated module and makes some Jitter measurements.
Script
Copy
jitter-mode.py
# -*- coding: utf-8 -*-
""" Example of making Jitter Mode measurements """
import time
import pyvisa as visa # import VISA library
ADDRESS = 'TCPIP0::localhost::hislip0,4880::INSTR'
#ADDRESS = 'TCPIP0::K-N1000A-30053::hislip0,4880::INSTR' # DCA-X
CHANNEL = '5A'
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)
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 all_channels_off(flexdca):
""" Turns all available channels off. """
for slot in '12345678':
for letter in 'ABCD':
channel = slot + letter
flexdca.write(':CHANnel' + channel + ':DISPlay OFF')
def install_simulated_module(flexdca, channel, model, signal='NRZ'):
""" Simplified installation of a simulated FlexDCA module.
model
Type of simulated module. "DEM" is a dual-electrical module.
"QEM" is a quad-electrical module. "DOM" is a dual-optical
module. "QEM" is a electrical-optical module.
signal
Format of signal. NRZ or PAM4.
"""
slot = channel[0]
flexdca.write(':EMODules:SLOT' + slot + ':SELection ' + model)
if signal in 'NRZ':
flexdca.write(':SOURce' + channel + ':FORMat NRZ')
else:
flexdca.write(':SOURce' + channel + ':FORMat PAM4')
flexdca.write(':SOURce' + channel + ':DRATe 9.95328E+9')
flexdca.write(':SOURce' + channel + ':WTYPe DATA')
flexdca.write(':SOURce' + channel + ':PLENgth 127')
flexdca.write(':SOURce' + channel + ':AMPLitude 90E-3')
flexdca.write(':SOURce' + channel + ':NOISe:RN 3.0E-6')
flexdca.write(':SOURce' + channel + ':JITTer:RJ 4.0E-12')
flexdca.write(':CHANnel' + channel + ':DISPlay ON')
def configure_FlexDCA(flexdca, channel):
""" Installs a simulated module and prepares FlexDCA for
measurements.
"""
flexdca.query(':SYSTem:DEFault;*OPC?')
all_channels_off(flexdca)
install_simulated_module(flexdca, channel, 'DEM')
flexdca.write(':CHAN' + channel + ':DISPlay ON')
flexdca.write(':ACQuire:RUN')
flexdca.write(':SYSTem:MODE EYE')
flexdca.query(':SYSTem:AUToscale;*OPC?')
flexdca.query(':TRIGger:PLOCk ON;*OPC?') # pattern lock on
flexdca.write(':SYSTem:MODE JITTer')
flexdca.write(':MEASure:AMPLitude:DEFine:ANALysis ON')
def return_scalar(flexdca, query):
""" Returns a FlexDCA scalar measurement result. Uses a loop that checks
the status of the measurement every 200 ms until the measurement
result is ready. If the status is invalid 'INV', the loop
continues waiting for the measurement to be ready.
If status is questionable 'QUES', an exception is thrown.
If a valid measurement cannot be returned within the Visa
timeout setting an exception is thrown.
"""
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 eng_notation(numstring, resolution):
""" Converts a string in scientific notation to engineering notation.
Unit multiplier character is appended to in final return string.
Args
====
numstring
Number string for conversion. For example, '12.3e-4'.
resolution
An real that indicates number of decimal places in
the result. For example, '0.01' would give '1.23 m'
Returns
=======
Str representing number with multiplier character.
"""
import decimal as dc
MU = '\u03BC' # μ
if numstring in '9.91E+37':
return ''
dc.getcontext().prec = 10 # prevent limiting of decimal places
multiplier = {12: 'T', 9: 'G', 6: 'M', 3: 'k', 0: '', -3: 'm',
-6: MU, -9: 'n', -12: 'p', -15: 'f'}
numberReal = dc.Decimal(numstring)
# absolute value is not between 0 and 1 (fraction)
if abs(numberReal) >= 1:
exponentMult = 0
while int(numberReal) != 0:
numberReal = numberReal / 1000
exponentMult += 1
numberReal *= 1000
exponentMult -= 1
elif (abs(numberReal) > 0) and (abs(numberReal) < 1): # fraction
exponentMult = 0
while int(numberReal) == 0:
numberReal = numberReal * 1000
exponentMult += 1
exponentMult *= -1
elif numberReal == 0: # number must be zero
exponentMult = 0
exponentMult *= 3
if exponentMult == -15:
n = numberReal.quantize(dc.Decimal('1'))
else:
n = numberReal.quantize(dc.Decimal(str(resolution)))
return str(n) + ' ' + multiplier[exponentMult]
def run_measurements(flexdca, channel):
""" Returns several Jitter measurements.
"""
print('\n' + '_' * 30)
print('Jitter Measurement Results')
meas = return_scalar(flexdca, ':MEASure:Jitter:EWIDth?')
print('Eye Width: ' + eng_notation(meas, '1.0') + 's')
meas = return_scalar(flexdca, ':MEASure:Jitter:TJ?')
print('TJ: ' + eng_notation(meas, '1.0') + 's')
print('_' * 30)
print('Amplitude Measurement Results')
flexdca.write(':MEASure:AMPLitude:EHEight:EYE EYE0')
meas = return_scalar(flexdca, ':MEASure:AMPLitude:EHEight?')
print('Eye Height: ' + eng_notation(meas, '1.00') + 'V')
flexdca.write(':MEASure:AMPLitude:TI:LEVel LEVel1')
meas = return_scalar(flexdca, ':MEASure:AMPLitude:TI?')
print('TI (level 1): ' + eng_notation(meas, '1.00') + 'V')
flexdca.write(':MEASure:AMPLitude:TI:LEVel LEVel0')
meas = return_scalar(flexdca, ':MEASure:AMPLitude:TI?')
print('TI (level 0): ' + eng_notation(meas, '1.00') + 'V')
flexdca.write(':ACQuire:STOP')
FlexDCA = open_flexdca_connection(ADDRESS)
configure_FlexDCA(FlexDCA, CHANNEL)
run_measurements(FlexDCA, CHANNEL)
FlexDCA.write('DISPlay:TSMode FSIZe')
FlexDCA.write(':SYSTem:GTLocal')
FlexDCA.close()