Return Scalar Measurement
This script can control N1010A FlexDCA on a PC or a DCA-X. This script opens a connection to FlexDCA, installs a simulated module and, in Eye mode, returns NRZ eye height measurement. The following diagram shows a Script-on-PC connection. In this configuration any DCA-M module must be connected to the DCA-X before it can be controlled. DCA-M modules connected to the PC cannot be seen.
Example Script
Copy
return-scalar-measurement.py
""" Script on PC controls FlexDCA or DCA-X from PC).
This script opens a connection to FlexDCA, installs a simulated module
and, in Eye mode, returns NRZ eye height measurement.
"""
import pyvisa as visa # import VISA library
import time
ADDRESS = 'TCPIP0::localhost::hislip0,4880::INSTR'
# ADDRESS = 'TCPIP0::K-N1000A-00003::hislip0,4880::INSTR' # DCA-X
CHANNEL = '5A'
def open_flexdca_connection(address):
""" Opens visa connection to FlexFlexDCA. """
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 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 return_scalar(FlexDCA, query):
""" Returns a FlexDCA scalar measurement result. """
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 measure_eye_height(FlexDCA):
""" Makes an eye height measurement. """
FlexDCA.write(':MEASure:EYE:LIST:CLEar')
FlexDCA.write(':MEASure:EYE:EHEight')
meas = return_scalar(FlexDCA, ':MEASure:EYE:EHEight?')
meas = eng_notation(meas, 0.01)
print('Eye Height: ' + meas + 'V')
FlexDCA = open_flexdca_connection(ADDRESS)
FlexDCA.query(':SYSTem:DEFault;*OPC?')
all_channels_off(FlexDCA)
install_simulated_module(FlexDCA, CHANNEL, 'DEM')
FlexDCA.write(':ACQuire:RUN')
FlexDCA.query(':SYSTem:MODE EYE;*OPC?') # Switch to Eye/Mask mode
FlexDCA.query(':SYSTEM:AUToscale;*OPC?')
measure_eye_height(FlexDCA)
FlexDCA.write(':SYSTem:GTLocal')
FlexDCA.close()