Error Handling
Error handling by querying the error queue
Introduction
In different situations errors can occur and if this happens error codes are written in a dedicated queue which can be queried.
It´s important to query often the error queue in order to be able to react properly to a situation which otherwise would remain unnoticed and lead to an unexpected behavior.
Error codes
The list of the used error codes is available in the Error and Event Types section.
Example in Phyton
This is an example in Python about the querying of the error queue. The relevant lines are :
anyErrors = visaSession.query(":SYSTem:ERRor?")
if anyErrors != '0,\"No error\"':
print("Some errors are present in the queue, please act accordingly: " + anyErrors)
# add appropriate error handling here
used included in the LookForErrors(vs) method which gets the visaSession object as argument
# use pyvisa or similar package
import pyvisa
import win32com.client
import locale
import time
import datetime
# *** TO DO: adapt IP address and SCPI port according to your needs ***
import pyvisa
import win32com.client
import locale
import time
import datetime
# *** TO DO: adapt IP address and SCPI port according to your needs ***
SCPI_server_IP = '172.22.44.46'
SCPI_Port = '5025'
SCPI_timeout = 20000 # milliseconds
VISA_resource_name = 'TCPIP::' + SCPI_server_IP + '::' + SCPI_Port + '::SOCKET'
# Start and Stop frequencies can be set either as strings or as double. In the latter case a conversion to string will be required before assemblying the SCPI command using them
# if the values are entered as numbers then the "." (dot) shall be used as decimal separator.
# Alternative: entering the values as string e.g. '10MAHz' no conversion to string shall be used building the SCPI command later on
Start_frequency = '10kHz'
Stop_frequency = 10000000.0
Number_of_measurement_points = 201 # the minimum amount of measurement points is 2!
Sweep_type = 'LOG'
Receiver_bandwidth = '300Hz'
Number_of_measurement_cycles = 2
def LookForErrors(vs):
howManyErrors = vs.query(":SYSTem:ERRor:COUNt?") # gets the number of errors in the queue
if int(howManyErrors) > 0:
lastError = vs.query(":SYSTem:ERRor?")
print("Some errors are present in the queue, please act accordingly: " + lastError)
# add appropriate error handling here
else:
print("No errors found in the queue!")
def Init():
start_time = time.time()
print('Trying to connect to VISA resource: ' + VISA_resource_name + '. Be sure that IP address and port number are correct!')
visaSession = pyvisa.ResourceManager().open_resource(VISA_resource_name)
visaSession.timeout = SCPI_timeout
visaSession.read_termination = '\n'
LookForErrors(visaSession)
print('SCPI client connected to SCPI server: ' + visaSession.query("*IDN?"))
print()
print("Number of measurement cycles to perform: " + str(Number_of_measurement_cycles))
lockOk = visaSession.query(":SYST:LOCK:REQ?")
if lockOk != "1":
print("Locking was not successful, exiting!")
LookForErrors(visaSession)
return
else:
print("Locking was successful!")
# Here comes the measurement configuration data for measurement sweep
visaSession.write("*ESE 255") # bitmask to enables all error codes.
visaSession.write("*CLS") # clears the error queue deleting all older errors
visaSession.write(':CALC:PAR:DEF S11') # sets the measurement type
visaSession.write(':SENS:FREQ:STAR ' + Start_frequency) # Start_frequency is already string and doesn´t require any conversion
visaSession.write(':SENS:FREQ:STOP ' + str(Stop_frequency)) # Stop_frequency is a number and must be converted to string
visaSession.write(':SENS:SWE:POIN ' + str(Number_of_measurement_points))
visaSession.write(':SENS:SWE:TYPE ' + Sweep_type)
LookForErrors(visaSession)
visaSession.write(':SENS:BAND ' + Receiver_bandwidth)
visaSession.write(':CALC:PAR:DEF Z') # configuring 'one-port' impedance measurement
visaSession.write(":CALC:FORM SLIN") # linear magnitude in Ohms + phase(deg)
actStartFreq = visaSession.query(':SENS:FREQ:STAR?')
actStopFreq = visaSession.query(':SENS:FREQ:STOP?')
print("Actual start/top frequencies are: " + actStartFreq + " and " + actStopFreq)
actMeasMod = visaSession.query(':CALC:PAR:DEF?')
print("Actual measurement mode is: " + actMeasMod)
LookForErrors(visaSession)
print()
visaSession.write(':TRIG:SOUR BUS') # Intializes trigger system to use BUS - to be used in combination with TRIG:SING and OPC
visaSession.write(':INIT:CONT ON') # Sets the trigger in continous mode. This way after a measurement the trigges gets back in state "ready" and waits for a further measurement.
LookForErrors(visaSession)
for i in range(Number_of_measurement_cycles):
visaSession.write(':TRIG:SING') # triggers a single sweep
visaSession.query('*OPC?') # this command waits for all pending operations to finish and afterwards returns an 1
LookForErrors(visaSession)
allResults = visaSession.query(":CALC:DATA:SDAT?")
frequencyValues = visaSession.query(":SENS:FREQ:DATA?")
LookForErrors(visaSession)
# Magnitude and phase from the results (first to the list, then out of the list to the FLOAT array)
allResults_list_raw = list(map(float, allResults.split(",")))
magnitude_raw = allResults_list_raw[0:Number_of_measurement_points - 1]
phase_raw = allResults_list_raw[Number_of_measurement_points:len(allResults_list_raw)]
# Frequency raw data to list
freq_list_raw = list(map(float, frequencyValues.split(",")))
# Printing just the first results of each measurement cycle
print ("Measurement number: " + str(i + 1) + "; " + "\tFrequency: " + str(freq_list_raw[0]) + " Hz;" + "\tMagnitude: " + str(magnitude_raw[0]) + " Ω;" + "\tPhase: " + str(phase_raw[0]) + "°")
visaSession.write(':SYSTem:LOCK:RELease')
print("Start OPC: " + str(datetime.datetime.now().time()))
visaSession.query('*OPC?')
# time.sleep(5)
print("End OPC: " + str(datetime.datetime.now().time()))
LookForErrors(visaSession)
visaSession.close()
print()
print("---Measurement time: %s seconds ---" % (time.time() - start_time))
if __name__ == "__main__":
Init()
Error handling by querying the status register
Introduction
There are a few abnormal conditions which don´t trigger errors, but might require the user attention.
First of all the status byte needs to be queried and, depending on which bits are raised, a further analysis of the reason is required.
In case the bit # 3
is raised (counting starts from 0) then the questionable status register shall be queried.
Possible conditions are:
an overload during measurement
a frequency range reaching under 10Hz where the calibration is only extrapolated.
In case the bit # 5
is raised some error condition is present and the error queue shall be queried.
Example
This is an example in Python about the querying of the error queue. The relevant lines are :
# Checks the status byte which is a summary of different registries
# A corresspondent bit is raised if the related register is not zero AND enabled
def CheckStatusByte(vs):
print("Checking status byte:")
stb = int(vs.query("*STB?"))
print ("STB value: " + str(stb))
if (stb & 32 == 32):
LookForErrors(vs)
if (stb & 8 == 8):
CheckQuestionableRegistry(vs)
# Checks the questionable registry value
# bits are raised if the corresponding condition occurs AND if they are enabled
def CheckQuestionableRegistry(vs):
print("Checking questionable registry:")
ques = int(vs.query(":STATus:QUEStionable?"))
if (ques & 256 == 256):
print("*** The quality of the calibration cannot be guaranteed sind the meas. freq. goes under 10Hz. ***")
if (ques & 1 == 1):
print("*** An overload did occur during the measurement. ***")
# use pyvisa or similar package
import pyvisa
import locale
import time
import datetime
from pip._internal.utils.misc import pairwise
# *** TO DO: adapt IP address and SCPI port according to your needs ***
SCPI_server_IP = '192.168.0.201' # '172.22.44.46'
SCPI_Port = '5025'
SCPI_timeout = 20000 # milliseconds
VISA_resource_name = 'TCPIP::' + SCPI_server_IP + '::' + SCPI_Port + '::SOCKET'
Start_frequency = '1kHz'
Stop_frequency = 10000.0
Number_of_measurement_points = 201
Sweep_type = 'LOG'
Receiver_bandwidth = '300Hz'
Number_of_measurement_cycles = 2
# Checks the status byte which is a summary of different registries
# A corresspondent bit is raised if the related register is not zero AND enabled
def CheckStatusByte(vs):
print("Checking status byte:")
stb = int(vs.query("*STB?"))
print ("STB value: " + str(stb))
if (stb & 32 == 32):
LookForErrors(vs)
if (stb & 8 == 8):
CheckQuestionableRegistry(vs)
# Checks the questionable registry value
# bits are raised if the corresponding condition occurs AND if they are enabled
def CheckQuestionableRegistry(vs):
print("Checking questionable registry:")
ques = int(vs.query(":STATus:QUEStionable?"))
if (ques & 256 == 256):
print("*** The quality of the calibration cannot be guaranteed since the meas. freq. goes under 10Hz. ***")
if (ques & 1 == 1):
print("*** An overload did occur during the measurement. ***")
# Queries the error queue
# If there are no error the queue contains "0, NoError"
# otherwise a list with alternate error numbers and names
def LookForErrors(vs):
allErrors = vs.query(":SYSTem:ERRor:ALL?")
print("Raw error list: " + allErrors)
errorList = allErrors.split(',')
if (errorList[0] == "0"):
print ("No error detected")
else:
print("List of detected errors:")
for i,j in pairwise(errorList):
print(i, " ", j)
print("Some errors are present in the queue, please act accordingly.")
# *** add appropriate error handling here ***
# Tries to get alock on the Bode in order to use it
# If the bode is free the lock shall succeed, if the Bode is already in use the lock won´´t be possible
def LockTheBode(vs):
lockOk = vs.query(":SYST:LOCK:REQ?")
if lockOk != "1":
print("Locking was not successful, exiting!")
print("#1")
LookForErrors(vs) # Overload and unguaranteed calibration don´t apply here so we just check for errors
return
else:
print("Locking was successful!")
# Starts and sets up the connection to the bode
def ConnectToBode():
visaSession = pyvisa.ResourceManager().open_resource(VISA_resource_name)
visaSession.timeout = SCPI_timeout
visaSession.read_termination = '\n'
return visaSession
def ReleaseBode(vs):
releaseReply = vs.write(':SYSTem:LOCK:RELease?')
vs.close()
# Enables error queue for all arrors and the status registry bitwise for unwarranted calibration and overload
def PrepareErrorQueueAndRegisters(vs):
vs.write("*RST")
vs.write(":STATus:QUEStionable:PTRansition 257") # activate the relevant bits 0 and 8
vs.write(":STATus:QUEStionable:ENABle 257") # activate the relevant bits 0 and 8
vs.write("*CLS") # clears the error queue deleting all older errors
vs.write("*ESE 255") # bitmask to enables all error codes.
# Defines and sets up the measurement
def SetUpMeasurement(vs):
vs.write(':CALC:PAR:DEF S11') # sets the measurement type
vs.write(':SENS:FREQ:STAR ' + Start_frequency) # Sets the start frequency
vs.write(':SENS:FREQ:STOP ' + str(Stop_frequency)) # Sets the stop frequency
vs.write(':SENS:SWE:POIN ' + str(Number_of_measurement_points))
vs.write(':SENS:SWE:TYPE ' + Sweep_type)
vs.write(':INPut:ATTenuation:CH1 0')
vs.write(':INPut:ATTenuation:CH2 0')
vs.write(':SOURce:POWer 16') # High output and low attenuation lead to an overload
vs.write(':SENS:BAND ' + Receiver_bandwidth)
def Init():
# start_time = time.time()
print('Trying to connect to VISA resource: ' + VISA_resource_name + '. Be sure that IP address and port number are correct!')
visaSession = ConnectToBode()
print('SCPI client connected to SCPI server: ' + visaSession.query("*IDN?"))
print("Number of measurement cycles to perform: " + str(Number_of_measurement_cycles))
LockTheBode(visaSession)
PrepareErrorQueueAndRegisters(visaSession)
SetUpMeasurement(visaSession)
CheckStatusByte(visaSession)
visaSession.write(':TRIG:SOUR BUS') # Intializes trigger system to use BUS - to be used in combination with TRIG:SING and OPC
visaSession.write(':INIT:CONT ON') # Sets the trigger in continous mode. This way after a measurement the trigges gets back in state "ready" and waits for a further measurement.
for i in range(Number_of_measurement_cycles):
visaSession.write(':TRIG:SING')
visaSession.query('*OPC?')
CheckStatusByte(visaSession)
allResults = visaSession.query(":CALC:DATA:SDAT?")
frequencyValues = visaSession.query(":SENS:FREQ:DATA?")
CheckStatusByte(visaSession)
# Magnitude and phase from the results (first as list, then to a FLOAT array)
allResults_list_raw = list(map(float, allResults.split(",")))
magnitude_raw = allResults_list_raw[0:Number_of_measurement_points - 1]
phase_raw = allResults_list_raw[Number_of_measurement_points:len(allResults_list_raw)]
# Frequency raw data to list
freq_list_raw = list(map(float, frequencyValues.split(",")))
# Printing just the first results of each measurement cycle
print ("Measurement number: " + str(i + 1) + "; " + "\tFrequency: " + str(freq_list_raw[0]) + " Hz;" + "\tMagnitude: " + str(magnitude_raw[0]) + " Ω;" + "\tPhase: " + str(phase_raw[0]) + "°")
CheckStatusByte(visaSession)
ReleaseBode(visaSession)
if __name__ == "__main__":
Init()