Binary transfer of waveform data in float format

This example script demonstrates using the :WAVeform:YFORmat:IBLock:FLOat:YDATa? query to transfer waveform data in 32-bit single-precision floating-point (float) format to the script's folder.

This example script uses the PyVISA read_raw() method to read the binary data.

Example Script

waveform-data-float-format.py

#!python3

"""This program illustrates getting waveform data in 32-bit
single-precision floating-point (float) format values
in the Infiniium XR8 oscilloscope.
"""

# Import modules.
import pyvisa
import sys
import struct
import numpy as np
import time
import platformdirs

# Global variables.
# oscilloscope_visa_address = "TCPIP0::lab-zir-p1z-2.cos.is.keysight.com::inst0::INSTR"
oscilloscope_visa_address = "TCPIP0::localhost::hislip0,4880::INSTR"
timeout = 20000  # 20 seconds.

# Save Locations
base_file_name = "my_data"
local_base_directory = f"{platformdirs.user_documents_dir()}\\"


def exit_program():
    """Exit program."""

    # Close connection to oscilloscope.
    sys.stdout.write("Closing oscilloscope connection.\n")
    Infiniium.write(":SYSTem:GTLocal")  # Unlock GUI.
    Infiniium.clear()  # Clear oscilloscope communications interface.
    Infiniium.close()  # Close communications interface to oscilloscope.
    rm.close()  # Close resource manager.
    print("End of program.")
    sys.exit()


def check_error_queue(when):
    """Check error queue."""

    errors_found = False
    while True:
        # Keep reading errors until "No error".
        error_string = Infiniium.query(":SYSTem:ERRor:NEXT? DIAGnostic")
        if error_string:  # If there is an error string value.

            if error_string.find("0,", 0, 2) == -1:  # Not "No error".
                errors_found = True
                print(f"ERROR: {error_string}")

            else:  # "No error"
                break

        else:  # :SYSTem:ERRor:NEXT? DIAGnostic should always return string.
            errors_found = True
            print("ERROR: :SYSTem:ERRor:NEXT? DIAGnostic returned nothing.")
            break

    if errors_found:
        print(f"Exited because error(s) found when: '{when}'")
        exit_program()


# ==========================================================
# Main program:
# ==========================================================

# Connect and initialize oscilloscope.
rm = pyvisa.ResourceManager("C:\\Windows\\System32\\visa64.dll")
try:
    Infiniium = rm.open_resource(oscilloscope_visa_address)
except Exception:
    print(
        f"Unable to connect to oscilloscope at {oscilloscope_visa_address}. Aborting program."
    )
    sys.exit()

Infiniium.timeout = timeout  # Set global timeout.
Infiniium.clear()  # Clear the instrument bus.
# Lock GUI happens automatically.

# Default Setup.
print("Default Setup.")
Infiniium.write(":SYSTem:DEFault")

# Use auto-scale to automatically set up oscilloscope.
print("Autoscale.")
Infiniium.query(":SYSTem:AUToscale;*OPC?")

# Stop acquisitions and clear the display.
Infiniium.write(":ACQuire:STOP")
Infiniium.write(":ACQuire:CDISplay")

# Capture an acquisition.
Infiniium.write(":ACQuire:POINts:AUTO OFF")
Infiniium.write(":ACQuire:POINts 1048576")
Infiniium.write(":TIMebase:INTerpolate:AUTO OFF")
Infiniium.write(":TIMebase:INTerpolate:METHod NONE")
Infiniium.query(":ACQuire:SINGle;*OPC?")

# Download waveform data.

# Specify the system byte order.
Infiniium.write(":SYSTem:BORDer LENDian")
qresult = Infiniium.query(":SYSTem:BORDer?").strip()
print(f"System byte order: {qresult}")

# Disable sinx/x interpolation.
Infiniium.write(f":TIMebase:INTerpolate:AUTO OFF")
Infiniium.write(f":TIMebase:INTerpolate:METHod NONE")

# Set the waveform source.
channel = "CHANnel1"
Infiniium.write(f":WAVeform:SOURce {channel}")  # Set waveform source to channel.
qresult = Infiniium.query(":WAVeform:SOURce?").strip()
print(f"Waveform source: {qresult}")

# Get the number of waveform points.
points = int(Infiniium.query(":WAVeform:YFORmat:POINts?"))
print(f"Waveform points: {points}")

# Get numeric values for later calculations.
x_increment = float(Infiniium.query(":WAVeform:YFORmat:XINCrement?"))
print(f"Waveform X increment: {x_increment:f}")
x_origin = float(Infiniium.query(":WAVeform:YFORmat:XORigin?"))
print(f"Waveform X origin: {x_origin:f}")

# Create time axis.
data_times = (np.linspace(0, points - 1, points) * x_increment) + x_origin

# Get the waveform data.
Infiniium.write(":WAVeform:YFORmat:IBLock:FLOat:YDATa?")
raw_bytes = Infiniium.read_raw()
if not raw_bytes.startswith(b"#0"):
    raise ValueError("Invalid indefinite-length block header received.")

# Unpack into list of data values.
data_values = struct.unpack("%df" % points, raw_bytes[2:-1])
print(f"Number of data values: {len(data_values)}")
np_data_values = np.array(data_values)

# Save as CSV.
header = f"Time (s),{channel} (V)\n"
now = time.time()  # To show how long it takes to save.
filename = f"{local_base_directory}{base_file_name}_{channel}.csv"
# Using "with open" takes care of a lot of stuff, and no need to explicitly close.
with open(filename, "w") as filehandle:  # 'w' means open for writing; can overwrite.
    filehandle.write(header)
    np.savetxt(filehandle, np.vstack((data_times, data_values)).T, delimiter=",")
    # np.vstack basically concatenates the timing info and analog data
    # into one 2D array, but it will be shape (2 rows, NPoints columns),
    # and typically one wants (NPoints rows,2 columns), and
    # the .T (transpose) at the end takes care of that.
print(f"It took {str(time.time() - now)} seconds to save {channel} in csv format.")

# To read the csv data back into Python:
# with open(filename, 'r') as filehandle:   # r means open for reading.
# recalled_csv_ch = np.loadtxt(filehandle,delimiter=',',skiprows=1)   # Skiprows keeps it from pulling the header in.

del filehandle, filename, header

# Save as a NumPy binary file.
now = time.time()  # To show how long it takes to save.
filename = f"{local_base_directory}{base_file_name}_{channel}.npy"
with open(
    filename, "wb"
) as filehandle:  # 'wb' means open for writing in binary; can overwrite.
    np.save(
        filehandle, np.vstack((data_times, data_values)).T
    )  # See comment above regarding np.vstack and .T.
print(f"It took {str(time.time() - now)} seconds to save {channel} in binary format.")

# To read the NumPy binary data back into Python:
# with open(filename, 'rb') as filehandle:   # rb means open for reading binary.
#  recalled_NPY_ch = np.load(filehandle)

# Check error queue.
check_error_queue("End of program")

# Exit program.
exit_program()

For more information, read the information on the :WAVeform:YFORmat:IBLock:FLOat:YDATa? query