Programming the 9103 With Python – Part 2: Switching Between Standard and High-Speed Modes

In part 1 of our series on programming the 9103 with Python, we wrote a simple application to control the 9103 and sample at standard speeds (as fast as 40 samples/second). Before we look at programming a 9103 in high-speed mode, we’ll program a utility to determine which speed mode the 9103 is currently set for, and provide a means to switch speed modes. All python samples for the 9103 can be found here.

(The high-speed option for the 9103 provides up to 500 samples/second and is available as an option when purchasing. The 9103 is also available with a high-voltage option and 90 V fixed or external bias)

Programming the 9103 with Python

A Python Utility App for Switching Speed Modes

The 9103 with the high-speed option recalls the last speed mode (standard or high) at which it was operated at. This makes it easier to program applications that normally only operate in one speed mode. However, because the different modes open the serial ports at different baud rates (57.6k for standard, 230.4k for high) it may not be known what mode the 9103 was last operating in, so an application could fail if it assumes the incorrect speed.

Since you can’t query the 9103 speed mode without opening the port, one way to get around the issue is to catch a port failure, and try a different baud rate.
This utility tries to open the port for standard speed, and if that fails, high speed. In either case, if the port is successfully opened and communications with the 9103 established, the user is prompted to switch the speed mode.

Exception Handling for the Win

The 9103 firmware recalls the last port speed and communicates at that speed. However, the driver for the virtual USB port can be successfully opened as long as the device is connected to the port, even if there is a speed mismatch

So, as always, we create a try/except handler to first attempt to open the correct port:

try:
    port=serial.Serial(
        'com' + port_number,
        baudrate=57600,
        bytesize=serial.EIGHTBITS,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        xonxoff=False,
        timeout=0)
except:
    port_open = False
    do_nothing = input('9103 standard speed not found. Press enter to continue...')

In order to determine if we are communicating at the correct baud rate, we’ll try to write and read from the 9103. The simplest way to do that is to send a query and look for a valid status response:

standard_speed = False;
timeout = 3   # seconds
timeout_start = time.time()
try:
    command_query_status()

    while time.time() < timeout_start + timeout:
        msg=port.readline().decode('utf-8').rstrip()

        if msg == "RBD Instruments: PicoAmmeter":
            print(msg)
            standard_speed = True;

The command_query_status() call simply sends a ‘&Q’ query message to the 9103.

If this throws an exception, we basically do the same thing again, this time opening the port at the faster 230.4k baud rate, then testing it by writing / reading. If either case is successful, we prompt the user to see if they want to switch to the other speed.

If you know you’re only ever typically going to operate the 9103 in one speed mode, you can simply use this utility once, and normally should not have to use it again unless you swap your 9103 with another that is running at a different speed. Otherwise, you can integrate this into your application. Normally, if you may need a higher sampling rate, there’s no reason not to simply operate in the higher-speed mode – the slower sampling rates are still available and can the messages for those rates can be parsed the same as with the standard speed.

Also, note that, although this code is agnostic about the operating system it’s running on, the exception conditions might be subtly different depending on the OS and FTDI USB serial port driver, and you may need to make some modifications.

Next, we’ll look at how to sample using the high-speed mode, and how to parse messages at the faster rates.

Programming the 9103 With Python – Part 1: Standard Speed

New sample Python code for the 9103 is now available on RBD’s website. The 9103’s API is easy to program with any language and documented fully, but as always with any device programming, a few examples always help. We chose Python because it’s well supported, easy to understand even if you’re using another language and compatible with a number of popular lab control and analysis environments.

The sample code we provide is open-source and free for you to use and distribute as you see fit.

(If you haven’t taken a look at the 9103 USB auto-ranging picoammeter, everything you need to know can be found here. Measure bi-polar DC current from picoamps to milliamps, with optional built-in bias and 5 kV isolation.)

Programming the 9103 with Python

A Quick Look at the Standard Speed Sampling Code

Python’s pySerial module abstracts the calls to class-compliant USB serial COM port drivers, so setting up communications with the 9103 is a matter of a few simple calls:

port=serial.Serial(
    'com' + port_number,
    baudrate=57600,
    bytesize=serial.EIGHTBITS,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    xonxoff=False,
    timeout=1)

With the addition of a few helper functions for handling ASCII, it’s simple to write functions to send individual commands to the 9103. The following sets the auto-range and filter settings:

def message(message_string):
return bytes('&'+ message_string + '\n','utf-8')

def command_range_auto():
port.write(message('R0')) # put in autorange

def command_default_filter_32():
port.write(message('F032'))

Similarly, with the addition of a few helper functions, the 9103 samples can be read with a simple loop that reads lines from the port buffer: In this case, we’ve setup the 9103 to read in interval mode, and poll the port for incoming samples, with a simple keyboard interrupt. This code also writes the sample information to a text file.

try:
while True:
msg=port.readline().decode('utf-8').rstrip()
print(msg)
parsed = parse_message_for_sample(msg)
if parsed:
samplefile.write( parsed + '\n')

except KeyboardInterrupt:
pass

All of the code is commented and documented in the Python file.

Using Python with LabView and MATLAB

The Python code samples can be helpful to both LabView and MATLAB users.
LabVIEW now supports Python through the Python Node, which features low-latency calls from a LabVIEW Block Diagram using LabVIEW primitives.

The MATLAB Engine API for Python allows you to call MATLAB as a computational engine from Python, and you can call functions and objects in Python from MATLAB.

More to Come…

Next up we’ll be posting some sample code to write and read using the high-speed version of the 9103. Since high-speed data from the 9103 arrives in packets, there are some minor differences in parsing the message samples.

High-speed Support Improved in Latest Actuel Release (1.7) for the 9103 Picoammeter

RBD has released Actuel version 1.7 for the 9103 Picoammeter, with improvements for high-speed data acquisition and (especially) data logging and graphing.

The latest version can be found here.

If you do not have a high-speed 9103 Picoammeter and are already running Actuel version 1.6, there no reason to download the latest version. However, high-speed users will find a number of improvements.


Oscilloscope emulation


Although Actuel was not designed to have an oscilloscope emulation (with features such as triggering), at higher speeds you can come close to emulating scope current monitoring.

In the Data Window, click the Show Options button and select “Last” from the Graph Options. You can scroll in increments as low as 0.1 second, but you can type in a smaller increment, such as “0.05” in order to display at higher resolution.

Last time option in Actuel
Using the “Last” time option in Actuel


(Note: The graph display options can get out of sync with data collection if you change and option when recording or after stopping and clearing data – it may be necessary to re-enter the value or reset recording. We’re working to make this smoother in the next version.)

For smoother real-time graphing, use standard-speed at 25 mS unless faster rates are needed

The 9103 can run as fast as 25 mS per sample in standard-speed mode, and 2 mS per sample in high-speed. In order to optimize faster data acquisition in high-speed mode, the 9103 collects 10 samples per message, as opposed to 1.

However, note that if you are collecting data at 25 mS in Standard-speed, your PC will be updated with new data every 25 mS. In High-speed, you’ll be updated every 250 mS.

For that reason, the Acutel software always collects data in standard-speed mode at 25 mS and above, regardless of the high-speed mode settings. It is recommended you do the same if you are writing your own software to control the 9103.

That also means that for real-time graphing, you may not want to sample at a rate of, for example, 24 mS, if you can achieve the same results at 25 mS. At faster rates, the delay in caused by receiving 10 samples per message is less noticeable, but it’s visible at rates of 20 mS- 25 mS if you are graphing only the latest points in relatively high resolution:

Actuel 25 mS Standard Speed

Actuel – 25 mS Standard Speed

Actuel 25 mS High Speed

Actuel – 24 mS High Speed