Instrumentation Programming with Python

This knowledge base article introduces programming a Magna-Power programmable power product with Python programming language. Python is a popular programming language, known for its simplicity, code readability, and not requiring any special compilation. Python’s ease of use and quick learning curve make is an excellent language for creating programs to control, take measurements, and even create plots for programmable instrumentation. Furthermore, Magna-Power’s extensive support for Standard Commands for Programmable Instrumentation (SCPI) means the company’s products can be easily controlled in Python with simple, intuitive commands.

Magna-Power’s products support a variety of different communication interfaces, including: RS-232, TCP/IP Ethernet, USB, RS-485, and IEEE-488 GPIB. Despite these different interfaces, the SCPI commands are identical for a particular product series. The SCPI commands are documented in the respective product series’ user manual. When creating a Python program, the only difference between interfaces will be the settings for the device connection.

USB, Serial, or RS-485, which will use pySerial to create a serial connection to the instrument:


import serial
conn = serial.Serial(port='COM8', baudrate=115200)

The serial baud rate for MagnaLOAD products is 115200, while the serial baud rate for MagnaDC products is 19200. The port location is defined by your operating system. In Windows, this port can be found in the Device Manager.

Subsequent sending and receiving of commands over serial connection will be as follows:


conn.write('*IDN?\n')
print conn.readline()

The TCP/IP Ethernet connection settings will be as follows:


import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.0.205', 50505))

Subsequent sending and receiving of commands over TCP/IP Ethernet connection will be as follows:


s.sendall('*IDN?\n')
print s.recv()

The IEEE-488 GPIB connection will require PyVISA, with connection as follows:


import visa
rm = visa.ResourceManager()
inst = rm.open_resource('GPIB0::12::INSTR')

Subsequent sending and receiving of commands over IEEE-488 GPIB connection will be as follows:


print(inst.query("*IDN?"))

The following examples provide more in-depth example Python programs using a MagnaLOAD DC electronic load. Programming a MagnaDC programmable DC power supply in Python will be almost identical, with subtle changes to the SCPI commands as documented in the respective product series’ user manual.

The following basic example creates a TCP/IP Ethernet connection, sends some initialization commands, enables the DC input, raises the current level to 5 Adc, waits 20 seconds, then shuts down.


# Import time: Time access and conversions to allow for pausing
# Import socket: Low-level networking interface to allow for socket programming
import time, socket
# Create socket object s with (host, port)
# Define host as hostname in Internet domain
# Define socket type as stream, allowing a port number to be defined
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to product's IP address address at default 50505 socket
s.connect(('192.168.0.205', 50505))
# Send SCPI command requesting the product to identify itself
s.sendall('*IDN?\n')
# Receive the product's response and display it in the terminal
print s.recv()
# Send SCPI command to configure the MagnaLOAD for voltage control mode
s.sendall('CONF:CONT 2\n')
# Send SCPI command to set the DC input current to 0 Adc before enabling DC input
s.sendall('CURR 0\n')
# Send SCPI command to enable the MagnaLOAD's DC input
s.sendall('INP:START\n')
# Send SCPI command to set the DC input current to 5 Adc
s.sendall('CURR 5\n')
# Wait 20 seconds
time.sleep(20)
# Send SCPI command to disable the DC input
s.sendall('INP:STOP\n')
# Close the communication channel to the product
s.close()

The following example creates a serial connection to the product, determines what product it is, and then sends a sequence of current commands with 20 seconds between each current level. This type of program can be expanded to cycle through voltage, power, and resistance values as well.


# Import pySerial, which encapsulates the serial port access
# Import time: Time access and conversions to allow for pausing
import serial, time
# Create serial connection object with default baudrate for MagnaLOADs
conn = serial.Serial(port='COM201', baudrate=115200)
# Send SCPI command requesting the product to identify itself
conn.write('*IDN?\n')
# Receive the product's response and display it in the terminal
print conn.readline()
# Create array of current set points
currSetPoints = [50, 100, 150, 250]
# Send SCPI command to configure the MagnaLOAD for current control
conn.write('CONF:CONT 2\n')
# Send SCPI command to enable the MagnaLOAD's DC input
conn.write('INP:START\n')
# For each entry in currSetPoints array
# Print static text and current set point to the terminal
# Send the new set point to the MagnaLOAD
# Wait 20 seconds
for currSetpoint in currSetPoints:
    print 'Setting Current to %s A' % currSetpoint
    conn.write('CURR {0}\n'.format(currSetpoint))
    time.sleep(20)
# Send SCPI command to disable the MagnaLOAD's DC input
conn.write('INP:STOP\n')
# Close the communication channel to the product
conn.close()

In the final in-depth example, a MagnaLOAD is programmed to discharge a battery using set points and times read from a comma-separate value (.csv) file, measure the DC input using the product’s high accuracy measurement commands, and then provide a plot of the measured data versus time. This program could be further expanded to generate a PDF test report, integrating the measured data, plots, as well as information from other instruments.


# Import plotting library Matplotlib
# Import .csv parser
# Import pySerial, which encapsulates the access for the serial port
# Import time: Time access and conversions to allow for pausing
# Import numpy for mathemetical manipulation of arrays
import matplotlib.pyplot as plt
import csv, serial, time
import numpy as np

# Create serial connection object with default baudrate for MagnaLOADs
conn = serial.Serial(port='COM8', baudrate=115200)
# Create an empty numpy data array 999 rows, 4 columns
outputSamples = np.empty([999, 3])
iSample = 0

# Send SCPI command to set the MagnaLOAD to current control
conn.write('CONF:CONT 2\n')
# Send SCPI command to set the MagnaLOAD to its Low Power Range
conn.write('CONF:RANG 0\n')
# Send SCPI command to enable the MagnaLOAD's DC input
conn.write('INP:START\n')

# Open data stream to .csv file. .csv has two columns:
# Column 1: Current set point in amperes
# Column 2: Time in seconds
# The first row is headers
with open('example_profile.csv', 'r') as csvfile:
	# Read the .csv file using comma (,) as the delimeter
    dataset = csv.reader(csvfile, delimiter=',')
	# Skip the header row
    next(dataset)
	# Split the dataset up to rows
    rows = list(dataset)
	# Create an empty array for measurements, the same length as .csv row numbers
    inputSamples = np.empty([len(rows), 2], dtype=float)
	# Record the time that the measurements began
    testStartTime = time.time()
	# Run for loop while there are still rows of data left
    for idx, data in enumerate(rows):
		# Store row data to array
        inputSamples[idx] = [data[0], data[1]]
		# Send SCPI command to MagnaLOAD to current set point at present row
        conn.write('CURR {0}\n'.format(data[0]))
		# Determine how long the MagnaLOAD should stay at this current set point
        stopTime = testStartTime + int(data[1])
		# Run while loop while there is still time left
        while time.time() < stopTime:
			# Send SCPI command to MagnaLOAD to measure all DC input variables
            conn.write('MEAS:ALL?\n')
			# Get the MagnaLOAD's response and split it up into its respective variables
            [curr, volt, res, pwr] = (conn.readline()).split(',')
			# Round measurements and store them to array, along with with time
            outputSamples[iSample] = ([round(float(curr), 2), round(float(volt), 2), round(time.time() - testStartTime, 2)])
            iSample += 1
            time.sleep(0.5)

# Send SCPI command to disable MagnaLOAD's DC input 
conn.write('INP:STOP\n')

# Create a plot series of current vs. time
plt.subplot(2, 1, 1)
plt.plot(outputSamples[0:iSample, 2], outputSamples[0:iSample, 0], 'r--')
plt.ylabel('Output Current(A)')
plt.title('I-V Profile')

# Create a plot series of voltage vs. time
plt.subplot(2, 1, 2)
plt.plot(outputSamples[0:iSample, 2], outputSamples[0:iSample, 1], 'b--')
plt.xlabel('Time (s)')
plt.ylabel('Output Voltage(V)')

# Show the plot
plt.show()