• General
    • Automated Measurements Overview
    • System Requirements
    • Measurement Modes and Default Settings
  • Bode Automation Interface
    • Documentation
    • Command Reference
    • Changelog
  • SCPI
    • Documentation
    • Command Reference
    • Error Handling
    • Changelog

    Show / Hide Table of Contents
    • SCPI Overview
    • Getting Connected
      • Start SCPI server
      • Setup Connection
      • Usage of NI I/O Trace to monitor the SCPI traffic
    • Command Syntax
      • Introduction to the SCPI language
      • Data Formats
      • Data Transmission Formats
      • Suffixes
    • Status & Error Handling
      • Status Register System
      • Error and Event System
      • Error Handling
    • The Trigger System & Data Sychronization
      • Trigger System
      • Select the correct trigger source for :TRIG:SING
      • Synchronization
    • Coding & Examples
      • Reading the query buffer
      • Read buffer size
      • SCPI Python examples
      • Error Handling
    • List of Abbreviations
    • SCPI Changelog

    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()
    
    Back to top Generated by DocFX