Using Python for Test and Measurement Setups Stephan Nigg,MSc. Dipl. El. Ing FH Abstract—The article shows how a test and measurement installation can be set-up in a few simple steps with the popular high-level programming language python. A simple design approach for the automation of such setups will be introduced. It will also be shown that even sophisticated setups can be addressed with the same simple approach keeping the over all complexity low. At last the problematic of delayed communication is discussed and a possible solution using multithreading is presented. Index Terms—Computer Society, Python, IVI, VXI-11, LXI, Ethernet, USBTMC, Multi-Threading, GPIB I. I NTRODUCTION Test and measurement setups (TMS) are part of an engineers and scientists daily business. Figure 1 shows an example of a simple temperature logging scenario. The device under test (DUT) is powered with a power supply (PSU) and the temperature is measured by a digital multi meter (DMM). The DMM is connected via USB or Ethernet to a PC and where a piece of software reads out the temperature periodically and writes it to a file. This piece of software can we written in any language. This paper shows how python can be used for such setups. Pythons design philosophy emphasizes code readability. This is especially beneficial for people not constantly writing code as is often the case with engineers outside information technology. It is available for free, is Open Source and runs on almost any CPU architecture and operating system. Python offers a huge and still increasing amount of powerful libraries (modules) especially but not exclusive in the area of mathematics and science [1], [2]. With python the data can be acquired and analyzed in the same development environment. Often setups get much more complex than just simply logging one parameter. In such advanced setups, automation has an even greater relevance, as it can save a lot of time conducting extensive parameter combinations. The number of measurements increase exponentially with the count of different parameters. As an automated measurement setup can be rerun, its results are reproducible. If post processing raises questions on the validity of some data, the setup can be rerun for double-checking. Figure 2 shows an example of a more complex TMS. The PSU is controllable and delivers information on the power consumption. The DUT is stimulated or controlled with defined data sets. Instead of only recording one parameter with a DMM, we have a digital storage oscilloscope (DSO) capable of recording what we here call events. These events are short time series showing a fast process instead of just a single value. An example would be the measurement of the slope of a rising edge or the timing of a communication process such as SPI. First we take a look how to tackle the simple temperature logging example of Figure 1 with python including some programming hints in Section II. In section III the example is extended towards the more advanced setup from Figure 2. In this paper the ivi module by Alex Forencich is used to access ivi-compliant instruments. It is a python implementation of the Interchangeable Virtual Instrument standard. The module depends on communication modules such as VXI11 for ethernet, USBTMC for USB or pySerial for RS232 communication [3], [4], [5]. The installation is straight forward and not covered here. Section IV covers methods to implement generic instruments. The method is shown by seamlessly extend the approach used in Sections II and III with a fixedperiod measurement instrument. Fig. 1. Simple Temperature logging. II. S IMPLE S ETUP The piece of software to control the setup shown in Figure 1 opens a communication channel to the instrument, polls values in a 10 seconds interval and stores them in a file. This is done in 7 lines of code (see Listing 1). Compared to C or Java it is very short and clean providing excellent readability. As python can be used in interactive mode, a setup can be created or tested step by step in the command line. This is a huge advantage compared to compiled languages. Line 3 creates an object of the digital multimeter (DMM) of the type Agilent34410A. If the exact type is not available (check the ivi documentation [6]), a similar type that is available can be tried. In most cases basic functions will work. The first part of the connection string on line 3 indicates the connection method being TCP/IP. To establish TCP/IP connection the ivi module will load the vxi-11 communication module in the background. Line 4 opens the log-file for writing. More precisely it is in appendage mode, meaning that if it does not exist it is created otherwise data is appended without loosing its prior content. This seemingly little detail is essential in TMS. If a script is rerun by accident or intention without saving the data of the last run, the is lost and even with data forensics almost impossible to retrieve. Line 5 defines an infinite loop. Infinite may seem strange at first but is actually a feasible method to run a function without predetermined length. Python’s garbage collector always does a clean up upon termination. The infinite measurement-loop can be stopped at any time by triggering a keyboard interrupt with Ctrl-D. Beware that operating systems use writing buffers to optimize IO performance. This has the side effect that data written to a file is not written to disk immediately. If the file had to be read during the measurement, a log.flush() after the write operation would be necessary. If the data is extremely precious this needs to be done anyway to ensure the datas safety in case of a system failure. The premature flushing may have a performance penalty. 1 2 3 4 5 6 7 import i v i import t i m e dmm = i v i . a g i l e n t . a g i l e n t 3 4 4 1 0 A ( ” TCPIP : : 1 0 . 1 . 1 . 2 : : INSTR” ) l o g = open ( ” l o g . t x t ” , ” a ” ) while True : l o g . w r i t e ( ” %0.4 f ◦C\n ” % dmm . m e a s u r e m e n t . read (0) ) time . sleep (10) Listing 1. VXI-11 connection example III. A DVANCED S ETUP Now lets examine the advanced example of Figure 2. Suppose the DUT is a mobile device. As such devices are normally powered by a single lithium polymer cell, the supply range we need to verify is from 3.6 to 4.4Volt. The DUT has a communication interface with four signals where we need to verify the timing. The interface can be configured with different driver strength between 20mA to 50mA at different speed from 100 to 800 kHz. Suppose we want to verify the interface timing at 5 voltage levels, 4 driver settings and 4 different speeds. This results in 80 measurements to capture and analyze. Manually going through all these combinations is tedious. In this example the temperature shall be recorded at each setting. This increases the amount of time considerably. Due to the long temperature settling time of 60 seconds, the measurement takes more than 80 minutes. Listing 2 shows one possible approach to get the expected results. It uses three nested for loops one for each parameter space. The correct timing is achieved with simple sleeps. To control the DUT a module named myDUT is imported. All we need to know for this example is that it talks to the DUT. On line 19 and 20 the supply voltage and communication parameters are set. Line 21 informs the user about the current status. Line 23 could be replaced with a for-loop printing a dot or a ’z’ every 5 seconds have something similar to a progress bar. After the thermal settling time the trigger on the DSO is set for a single shot on line 24. After getting the current the DUT consumes and temperature on line 25 and 26, the script waits for 5 seconds to be sure the trigger has fired. After the waveform data is retrieved from the four observed channels. At this point all the data needed for a timing analysis is collected. Line 30 to 34 demonstrate how easy it is, to fetch a scope image and save it to the local disk. Such scope snapshots are useful for engineers to get a quick overview of the a measurement. As post-processing is not covered in this article, the analysis and storage of the result is only indicated by line 35. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import i v i from t i m e import s l e e p import myDUT sup volt =[3.6 , 3.8 , 4.0 , 4.2 , 4.4] d r i v c u r = [ 20 e −3, 30 e −3, 40 e −3, 50 e −3] speed =[100 ,200 ,400 ,800] dmm= i v i . a g i l e n t . a g i l e n t 3 4 4 1 0 A ( ” TCPIP : : 1 0 . 1 . 1 . 2 : : INSTR” ) d s o = i v i . l e c r o y . lecroyWR62XIA ( ” TCPIP : : 1 0 . 1 . 1 . 3 : : INSTR” ) p s u = i v i . a g i l e n t . a g i l e n t E 3 6 4 9 A ( ” TCPIP : : 1 0 . 1 . 1 . 4 : : INSTR” ) d u t =myDUT . i n i t ( ) c h a n = range ( 4 ) psu . o u t p u t s [ 0 ] . v o l t a g e l e v e l = s u p v o l t [ 0 ] psu . o u t p u t s [ 0 ] . e n a b l e d =True for sv in s u p v o l t : f o r dc i n d r i v c u r : for sp in speed : psu . o u t p u t s [ 0 ] . v o l t a g e l e v e l =sv d u t . s e t ( d r i v e r =dc , s p e e d = s p ) p r i n t ” Wait a t %.1fV , %imA , %ikHz ” % ( sv , dc ∗ 1 0 0 0 , s p ) dut . s t a r t t x ( ) sleep (55) d s o . t r i g g e r . mode=single s y s i =psu . o u t p u t s [ 0 ] . g e t c u r r e n t ( ) s y s t =dmm . m e a s u r e m e n t . r e a d ( 0 ) sleep (5) f o r c i n range ( 4 ) : chan [ c ]= dso . c h a n n e l s [ c ] . measurement . fetch waveform ( ) png= d s o . d i s p l a y . f e t c h s c r e e n s h o t ( ) p i c n a m e =” r u n %.1 fV %imA %ikHz . png ” % ( sv , dc ∗ 1 0 0 0 , s p ) f =open ( pic name , wb ) f . w r i t e ( png ) f . close () p r o c s a v e ( sv , dc , sp , chan , s y s i , s y s t ) Listing 2. VXI-11 connection example Fig. 2. Advanced Test and Measurement Setup. IV. I NTEGRATING G ENERIC D EVICES The instruments used so far are controlled via the Standard Commands for Programmable Instrumentation (SCPI). This communication standard originating from GPIB (IEEE-488) devices, use the requestresponse principle (see Figure 3(a)). Hence, to get a value a request is sent to the instrument and an answer comes back accordingly. This may lead to a short delay, but we can request a value at any time. There are other instruments offering a computer interface not supporting the requestresponse method. One popular representative of that device class are low-range digital multimeter. Such devices send measurement values periodically over RS232, USB or Bluetooth (see Figure 3(b)). This raises a problem. When opening such a port, the input buffer has to be read periodically for proper operation. Directly using such a device in Listing 1 might be possible due to the periodic nature but it certainly does not fit into Listing 2. Suppose we extend a perfectly working setup with such a device, rewriting the hole code using dummy reads and inner loops completely conflicts with our paradigm of clean an simple code. In a situations like this, multithreading should be considered. A. Multithreading The multithreading functionality in python is very easy to use. While generally considered an advanced programming technique, a multithreaded approach can keep a TMS simple. The idea is to spawn a thread for the DMM object, that independently takes care of the device communication. The thread-object updates an externally accessible variable with the most recent value. Listing 3 shows a crude example of such a thread-object. This example works for a device sending a string like ”5.234 V\n” every second. Line 1 imports the serial module pyserial [4]. The threading module is part of pythons standard library. Line 8 is called when we first create the object. It opens the requested com port. Line 9 reads 100 bytes without using them. It ensures empty buffers. Calling the start-function of a thread-object as seen in line 3 of Listing 4 causes the runfunction of that object to run independently. In Listing 3 at line 10 we see the definition of the loop reading the measurement values that once started will run forever. While Listing 3 serves demonstration only, lets focus on one nasty detail. In line 13 of Listing 3 we try to convert the first 6 characters (0 to 5 as the 6th is not included in the slice) of the string to a floating point number. This is a process very prone to errors. If for some reason the measurement range on the instrument changes and we get a whitespace inside the cropped string, the float-command will fail with an error. Such a conversion has to be done in a robust way. Python offers plenty of possible approaches depending on the exact use case. For example a try-catch enclosure or regular expression to name a few. In the given example at the very least a test for the presence of the line-break symbol should be implemented. 1 2 3 4 5 6 7 8 9 10 11 12 import s e r i a l from t h r e a d i n g import T h r e a d from t i m e import s l e e p c l a s s PeriodicDMM ( T h r e a d ) : value = 0 def init ( self , device ) : s e l f . com= s e r i a l . S e r i a l ( d e v i c e , 9 6 0 0 , timeout =.1) n i l = s e l f . port . read (100) def run ( s e l f ) : while True : res = s e l f . port . read (10) (a) SCPI based communication. (b) Periodic communication. Fig. 3. Sequence Diagram (UML style). 13 14 15 16 s e l f . value= f l o a t ( res [ 0 : 6 ] ) sleep (0.8) def get value ( s e l f ) : return s e l f . value Listing 3. Multithreading Instrument Object. 1 2 3 4 5 import p e r i o d i c d m m dmm= p e r i o d i c d m m . PeriodicDMM ( ” / dev / ttyUSB0 ” ) dmm . s t a r t ( ) ... p r i n t dmm . g e t v a l u e ( ) Listing 4. Using the Multithreading Object. B. Integration of Slow Instruments There is an other type of issue where multithreading can be beneficial. As a consequence of the requestresponse principle there is a delay reading a value. The code execution is blocked until the instruments response is correctly received. In Figure 3(a) this time is visible between the GET arrow and the RES arrow on the dashed time line. While this delay for most cases is negligible, even for very fast devices the delay can be in the range of 10 milliseconds. Suppose we have a setup with 3 slow instruments (A, B and C). Instrument B is known to have an additional unpredictable response delay due to internal calculations. Using these instruments in the simple loop-setup seen in Section II and III can lead to timing violations (see Figure 4(a)). Since reading a single value from a variable updated by a thread-object is considerably faster, the multithread approach can be used to have device objects with a so called nonblocking interface. The request to the instrument can either be generated internally or initiated via a function call. But instead of initiating the request and then wait for the answer, code execution is continued right away and the response can then be read when available. This way the delays are not combined to one very long delay but only the single longest delay has to be considered as depicted in Figure 4(b). Listing 5 shows an exemplary code snippet on how the setup from Figure 4(b) could be handled. To stress the issue the sampling period only is 200 milliseconds (line 9). (a) Slow instruments handled in main thread. (b) Slow instruments in a multi threading setup. Fig. 4. Setup with very slow measurement instruments. 1 2 3 4 5 6 7 8 9 10 dmmA=slowdmm . SlowDMM( ” / dev / ttyUSB0 ” ) dmmB=slowdmm . SlowDMM( ” / dev / ttyUSB1 ” ) dmmC=slowdmm . SlowDMM( ” / dev / ttyUSB2 ” ) # init () dmmA. s t a r t ( ) dmmB . s t a r t ( ) dmmC . s t a r t ( ) while True : sleep (0.2) s a v e R e s (dmmA. g e t ( ) ,dmmB . g e t ( ) ,dmmC . g e t ( ) ) Listing 5. Multithreading Approach for Slow Devices. V. C ONCLUSION The first two sections showed that test and measurement setups can be developed with few lines of python code, keeping the essence of the approach clear to the reader. The trivial loop-approach can be used for both simple and complex use cases. Even spacial cases such as fixed periodic transfers and long communication delays can be handled by using multithreading. While already in heavy use for data analysis, this paper demonstrated how simple data acquisition can be with python. ACKNOWLEDGMENT The authors would like to thank Beat Bolli for his encouragement to get involved with python and Alex Forencich for his work on PythonIVI, Python VXI-11 and Python USBTMC. Further thanks go to Peter Schlachter for his support on setting up the necessary python environment in the Institute of Microelectronics. R EFERENCES [1] Numpy: Base n-dimensional array package. [Online]. Available: http://www.numpy.org [2] Scipy: Fundamental library for scientific computing. [Online]. Available: http://www.scipy.org [3] Python vxi-11 driver for controlling instruments over ethernet. [Online]. Available: https://pypi.python.org/pypi/python-vxi11 [4] (2015) Serial port access-module for pyhton. [Online]. Available: http://pyserial.sourceforge.net [5] (2015) Usbtmc driver for controlling instruments over usb. [Online]. Available: https://github.com/python-ivi/python-usbtmc [6] (2015, Feb) Python implementation of the interchangeable virtual instrument standard. [Online]. Available: https://github.com/pythonivi/python-ivi