Intro
I would like to retrieve binary data from an instrument (SR620) using RS-232. The data is an histogram made of 250 bins. The python program I did works well when no data is acquired (I get 250 zeros), but as soon I actually start a measurement, the output is weird and I cannot use it. I will explain the data acquisition, the structure of the binary data and give a short version of the program with all relevant elements. Then I describe the output, and the error I get, the troubleshouting I did.
I understood that the problem came from a conversion of number above 127 being wrong see edit 4
My questions are :
- are there another commands I could/should use to retrieve the binary data ?
- is this related to the other commands, the algorithm, the device etc ?
- where does the problem comes from, the program, the device itself ?
The result histogram I am expecting. Some periodic signal for three periods and then zeros in the last 2.5 us.
Data acquisition
I connect to the Time-to-Amplitude Converter (TAC) SR620 using the pyvisa module in python. I can set the instrument properly (set values of parameters, measurement mode ...). Everything in the front panel changes accordingly. I connect using this
rm = pyvisa.ResourceManager()
## Connecting to counter
TAC = rm.open_resource(self.TAC_address,
baud_rate = 19200,
data_bits = 8,
stop_bits = StopBits(20),
parity = Parity(0))
In this experiment, I count the delays between a reference and an event on a detector (typically in the range of microseconds). I want N_Samples samples and retrieve the histogram of the delays. I start the measurement with TAC.write("STRT"). Note that when I collect the histogram directly in integer from the machine (using the dedicated function HSPT) it works well, but it is 'slow'. In binary this is much faster, but it is 'buggy'.
Data structure
To get my histogram in binary format I use the dedicated command XHST. The documentation tells us
XHST? j
The XHST? query returns section j (j=0 to 9) of the histogram display as 4 byte binary integers least significant byte first. Each section consists of the data for 25 histogram points (100 bytes total plus terminator). There is no separator between successive points.
If the rs232 interface is being used an 8 bit data word must be chosen to correctly transmit this data. The data returned is binned into 250 bins- not the number set by the front panel. This command allows one to rapidly read the entire contents of the histogram display. If the histogram is blank the illegal numbars -0 are returned.
So from there I understand I have to collect 10 sections made of 25 4-byte integers in binary. With a terminator (\r\n) in the end of each section that I remove not to mix integers with '\r\n'. The base fot this step is for j in range(0,10): data = TAC.query("XHST? "+str(j)).
Program
## imports
import pyvisa
from pyvisa.constants import StopBits, Parity
import struct
import time
## Connecting to counter
rm = pyvisa.ResourceManager()
TAC = rm.open_resource(self.TAC_address,
baud_rate = 19200,
data_bits = 8,
stop_bits = StopBits(20),
parity = Parity(0))
## Setting parameters
TAC.write(f"SCLR") ## clear measurement and display
TAC.write(f"WAIT 2") ## 2*2 ms delay between words
TAC.write(f"MODE 0") # 0 time mode
TAC.write(f"SIZE 10000") # number of samples
TAC.write(f"GSCL 2,250") # number of bins
## Starting measurement (acquisition)
TAC.write("SRCE 0") # Input A
TAC.write(f"SCEN 1") # 1 single acquisition
TAC.write(f"AUTM 0") # no auto restart
TAC.write("STRT")
## Wait for the end of measurement
state = 0
while state != 1:
state = int(TAC.query("*STB? 0"))
## returns 0 as long as measurement in progress
print(f'State : {state}')
time.sleep(5)
## retrieve data
self.meanlist = [] # result is stored here
for j in range(0,10):
data = TAC.query("XHST? "+str(j))
time.sleep(0.1)
data = data.rstrip("\r\n") # remove terminator to not mix integers and \r\n
data = data.encode() # convert to bytes
print(data)
# data = struct.unpack("<25i", data) # unpack as 25 4-byte integers
# have to comment it otherwise I have struct.error
self.meanlist.append(data)
Output without start measurement
Each print(data) gives
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Which is the right thing, 25 4-byte integers. From that I say that my program works. In the end I can reconstitute my 250 bins histogram. It is all zero of course because I never started the acquisition.
But then if I make an acquisition first it does not make sense.
Output with start measurement
The print(data) in the for loop gives
b'\x08\x00\x00\x00\x07\x00\x00\x00'
b'\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\t\x00\x00\x00\x08\x00\x00\x00\x0b\x00\x00\x00\t\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x05\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\x0b\x00\x00\x00\x08\x00\x00\x00\r\x00\x00\x00'
b'\x00\x00\x00\t\x00\x00\x00\x0b\x00\x00\x00\x07\x00\x00\x00'
b'\x00\x00\x00\t\x00\x00\x00\x06\x00\x00\x00\x0b\x00\x00\x00'
b'\t\x00\x00\x00\t\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00'
b'\x00\x00\x00\x0c\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x05\x00\x00\x00'
b'\x0b\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x12\x00\x00\x00'
b'\x00\x00\x00\x0e\x00\x00\x00'
b'\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00'
b'\x00\x00\x00'
Description of the error
If the line data = struct.unpack("<25i", data) is not commented I get the error struct.error: unpack requires a buffer of 100 bytes.
This is why I print the data, and you can see the length of each output is different, also there are some \r, \n and '\t' sneaking into the output, which is weird. When redoing, the length are different, sometimes there is even empty outputs and also a complete one from time to time.
Some more (inefficient) troubleshooting
I have two different SR620 TAC that have the same weird behaviour. I tried to add delays, pauses, to change bit parity, encoding but always have this behaviour.
How can this be possible ? Where can it come from ? I start an acquisition, wait for the acquisition to be complete, then ask for the output. Output looks like it is cut before being complete. And why those extra characters showing up from time to time ? This does not happen when I just retrieve an histogram without acquisition.
Outlook
Do you have some propositions for improvements or an alternative ? I can still work with the HSPT function for the moment but using binary should save me a lot of time.
Edit 1 (print(repr(data)))
I print(repr(data)) just after the query. Here are the first lines that come out.
'\x1e\x00\x00\x001\x00\x00\x00+\x00\x00\x00*\x00\x00\x00)\x00\x00\x00+\x00\x00\x00$\x00\x00\x00\x1f\x00\x00\x00(\x00\x00\x00"\x00\x00\x00$\x00\x00\x00-\x00\x00\x00-\x00\x00\x00&\x00\x00\x00$\x00\x00\x00.\x00\x00\x000\x00\x00\x00.\x00\x00\x007\x00\x00\x00-\x00\x00\x00!\x00\x00\x00#\x00\x00\x00&\x00\x00\x00(\x00\x00\x00.\x00\x00\x00\r\n'
'%\x00\x00\x008\x00\x00\x00*\x00\x00\x00)\x00\x00\x00,\x00\x00\x00)\x00\x00\x00\'\x00\x00\x00!\x00\x00\x006\x00\x00\x00/\x00\x00\x00\x18\x00\x00\x00\x1d\x00\x00\x00\x1f\x00\x00\x00)\x00\x00\x00"\x00\x00\x00\x1e\x00\x00\x000\x00\x00\x00#\x00\x00\x00!\x00\x00\x00$\x00\x00\x00\x1e\x00\x00\x00,\x00\x00\x00(\x00\x00\x00.\x00\x00\x00#\x00\x00\x00\r\n'
'\x18\x00\x00\x00!\x00\x00\x00\x1e\x00\x00\x00"\x00\x00\x00\x19\x00\x00\x00"\x00\x00\x00\'\x00\x00\x00-\x00\x00\x003\x00\x00\x000\x00\x00\x00!\x00\x00\x00%\x00\x00\x00.\x00\x00\x00\x1b\x00\x00\x00"\x00\x00\x002\x00\x00\x001\x00\x00\x00%\x00\x00\x00(\x00\x00\x00 \x00\x00\x00%\x00\x00\x00!\x00\x00\x00\x1e\x00\x00\x00(\x00\x00\x00$\x00\x00\x00\r\n'
'\x1d\x00\x00\x00.\x00\x00\x00\x1e\x00\x00\x00"\x00\x00\x00\x1d\x00\x00\x00\x12\x00\x00\x00\'\x00\x00\x00"\x00\x00\x00*\x00\x00\x00\'\x00\x00\x00%\x00\x00\x00-\x00\x00\x00)\x00\x00\x00)\x00\x00\x00\'\x00\x00\x00\x1e\x00\x00\x00"\x00\x00\x00\'\x00\x00\x00-\x00\x00\x00"\x00\x00\x00\x18\x00\x00\x00\x1f\x00\x00\x00#\x00\x00\x00\x1a\x00\x00\x00\'\x00\x00\x00\r\n'
Previously it was
"\x14\x00\x00/\x00=\x00\x00\x00'\x00\x00\x00#\x00\x00\x00.\x00\x00\x00&\x00\x00\x00(\x00\x00\x00'\x00\x00\x000\x00\x00\x00(\x00\x00\x00*\x00\x00\x00#\x00\x00\x00\x1e\x00\x00\x00\x1e\x00\x00\x00!\x00\x00\x00$\x00\x00\x00,\x00\x00\x00(\x00\x00\x00,\x00\x00\x00'\x00\x00\x00 \x00\x00\x00'\x00\x00\x00*\x00\x00\x00$\x00\x00\x00,\x00\x00\x00\r\n"
b"\x14\x00\x00\x00=\x00\x00\x00'\x00\x00\x00#\x00\x00\x00.\x00\x00\x00&\x00\x00\x00(\x00\x00\x00'\x00\x00\x000\x00\x00\x00(\x00\x00\x00*\x00\x00\x00#\x00\x00\x00\x1e\x00\x00\x00\x1e\x00\x00\x00!\x00\x00\x00$\x00\x00\x00,\x00\x00\x00(\x00\x00\x00,\x00\x00\x00'\x00\x00\x00 \x00\x00\x00'\x00\x00\x00*\x00\x00\x00$\x00\x00\x00,\x00\x00\x00"
"0\x00\x00\x006\x00\x00\x00*\x00\x00\x00%\x00\x00\x00(\x00\x00\x00+\x00\x00\x00.\x00\x00\x004\x00\x00\x00(\x00\x00\x00(\x00\x00\x005\x00\x00\x000\x00\x00\x00#\x00\x00\x00!\x00\x00\x00.\x00\x00\x00)\x00\x00\x00(\x00\x00\x00(\x00\x00\x00'\x00\x00\x00#\x00\x00\x00+\x00\x00\x000\x00\x00\x00.\x00\x00\x00*\x00\x00\x00-\x00\x00\x00\r\n"
Edit 2
Following comment from @ukBaz I do print(TAC.read_termination). The output is None.
Then I do
for j in range(0,10):
TAC.write(f'XHST? {j}')
values = TAC.read_bytes(102)
print(f'[{j}]: {values}')
You can see there are 10 outputs, binary, with termination \r\n. The last three outputs are mostly zeros which is expected anyway.
[0]: b'6\x00\x00\x00\x03\x00\x00\x00\x02\x00\x00\x00\x0f\x00\x00\x00r\x00\x00\x00|\x00\x00\x00\x02\x00\x00\x00r\x00\x00\x00x\x00\x00\x00\x16\x00\x00\x00v\x00\x00\x00v\x00\x00\x00\x7f\x00\x00\x00g\x00\x00\x00r\x00\x00\x00x\x00\x00\x00y\x00\x00\x00s\x00\x00\x00`\x00\x00\x00b\x00\x00\x00|\x00\x00\x00p\x00\x00\x00d\x00\x00\x00s\x00\x00\x00j\x00\x00\x00\r\n'
[1]: b'x\x00\x00\x00]\x00\x00\x00j\x00\x00\x00`\x00\x00\x00f\x00\x00\x00l\x00\x00\x00c\x00\x00\x00\\\x00\x00\x00[\x00\x00\x00[\x00\x00\x00a\x00\x00\x00o\x00\x00\x00t\x00\x00\x00]\x00\x00\x00s\x00\x00\x00c\x00\x00\x00\x06\x00\x00\x00t\x00\x00\x00\x01\x00\x00\x00s\x00\x00\x00r\x00\x00\x00s\x00\x00\x00n\x00\x00\x00W\x00\x00\x00\t\x00\x00\x00\r\n'
[2]: b'o\x00\x00\x00l\x00\x00\x00\n\x00\x00\x00\x7f\x00\x00\x00\x04\x00\x00\x00\x0c\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00o\x00\x00\x00e\x00\x00\x00o\x00\x00\x00h\x00\x00\x00j\x00\x00\x00\x7f\x00\x00\x00\\\x00\x00\x00\x0c\x00\x00\x00o\x00\x00\x00\x00\x00\x00\x00p\x00\x00\x00}\x00\x00\x00c\x00\x00\x00{\x00\x00\x00\x02\x00\x00\x00j\x00\x00\x00q\x00\x00\x00\r\n'
[3]: b'|\x00\x00\x00p\x00\x00\x00\\\x00\x00\x00o\x00\x00\x00m\x00\x00\x00]\x00\x00\x00g\x00\x00\x00v\x00\x00\x00g\x00\x00\x00c\x00\x00\x00O\x00\x00\x00k\x00\x00\x00[\x00\x00\x00a\x00\x00\x00n\x00\x00\x00c\x00\x00\x00S\x00\x00\x00h\x00\x00\x00`\x00\x00\x00w\x00\x00\x00e\x00\x00\x00S\x00\x00\x00w\x00\x00\x00s\x00\x00\x00V\x00\x00\x00\r\n'
[4]: b'j\x00\x00\x00v\x00\x00\x00v\x00\x00\x00q\x00\x00\x00q\x00\x00\x00t\x00\x00\x00u\x00\x00\x00e\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00q\x00\x00\x00{\x00\x00\x00\x03\x00\x00\x00f\x00\x00\x00v\x00\x00\x00{\x00\x00\x00j\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00i\x00\x00\x00\x0b\x00\x00\x00s\x00\x00\x00m\x00\x00\x00\x18\x00\x00\x00\r\n'
[5]: b'z\x00\x00\x00\n\x00\x00\x00r\x00\x00\x00y\x00\x00\x00e\x00\x00\x00s\x00\x00\x00h\x00\x00\x00t\x00\x00\x00|\x00\x00\x00k\x00\x00\x00k\x00\x00\x00p\x00\x00\x00p\x00\x00\x00g\x00\x00\x00Z\x00\x00\x00p\x00\x00\x00a\x00\x00\x00]\x00\x00\x00k\x00\x00\x00~\x00\x00\x00c\x00\x00\x00i\x00\x00\x00m\x00\x00\x00b\x00\x00\x00c\x00\x00\x00\r\n'
[6]: b'o\x00\x00\x00}\x00\x00\x00^\x00\x00\x00r\x00\x00\x00z\x00\x00\x00{\x00\x00\x00d\x00\x00\x00s\x00\x00\x00k\x00\x00\x00Z\x00\x00\x00y\x00\x00\x00s\x00\x00\x00s\x00\x00\x00d\x00\x00\x00{\x00\x00\x00e\x00\x00\x00q\x00\x00\x00\x02\x00\x00\x00p\x00\x00\x00w\x00\x00\x00\x05\x00\x00\x00\x7f\x00\x00\x00o\x00\x00\x00h\x00\x00\x00g\x00\x00\x00\r\n'
[7]: b'j\x00\x00\x00\x07\x00\x00\x00p\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\n'
[8]: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\n'
[9]: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\n'
Edit 3 (new function from pyvisa)
Checking the documentation of pyvisa I found this function query_binary_values that is devoted to query of binary, that returns a list of numbers. It works for extraction and give a result close to the expected but there is always some values that are completely messed up. Either they are too close to 0 or too high by few orders of magnitude.
for j in range(0,10):
data = TAC.query_binary_values("XHST? "+str(j)+";*WAI",
datatype='i',
is_big_endian=False,
data_points=25,
header_fmt = 'empty', expect_termination = True)
The result is shown below as an histogram, and also the output of both TAC.write(f'XHST? {j}') ; print(f'[{j}]: {TAC.read_bytes(102)}') and print(data). In the histogram you can recognize the periodic pattern but you have some very low value in the middle and some huge values. Sometimes those huge values shows up several time and it looks like they are periodic.
[62, 14, 36, 11, 12, 12, 7, 123, 122, 111, 15, 112, 120, 103, 110, 95, 115, 87, 90, 93, 68, 95, 85, 76, 95]
[88, 74, 95, 100, 75, 88, 85, 76, 89, 91, 87, 94, 102, 117, 94, 116, 113, 124, 125, 120, 0, 125, 7, 117, 127]
[108, 123, 122, 1, 6, 2, 116, 23, 23, 21, 123, 24, 0, 7, 34, 20, 112, 9, 121, 6, 121, 2, 112, 106, 103]
[94, 107, 89, 114, 90, 105, 84, 96, 70, 71, 69, 87, 84, 97, 81, 87, 102, 107, 93, 107, 82, 108, 105, 112, 87]
[103, 115, 122, 106, 118, 105, 124, 112, 127, 113, 100, 112, 4, 3, 2, 4, 10, 119, 0, 35, 125, 20, 23, 10, 4]
[2573, 131072, 262144, 393216, 7929856, 8060928, 65536, 8126464, 7274496, 7471104, 6881280, 5242880, 6094848, 5767168, 6750208, 5570560, 5308416, 5373952, 5570560, 6422528, 4784128, 7012352, 6750208, 5898240, 5963776]
[168624128, 101, 94, 107, 83, 117, 115, 110, 111, 102, 116, 3, 118, 10, 121, 0, 126, 117, 106, 119, 122, 117, 108, 15, 101]
[30, 8325645, 1835008, 917504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 168624128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 2573, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Edit 4
Here is the first numbers retrieved as ascii
'4.4E1'
'1.13E2'
'1.14E2'
'1.18E2'
'1.31E2'
'1.31E2'
'1.20E2'
and their equivalent in binary
,x00\x00\x00
q\x00\x00\x00
r\x00\x00\x00
v\x00\x00\x00
\x03\x00\x00\x00
\x03\x00\x00\x00
x\x00\x00\x00
The output of my program for those numbers is 44, 113, 114, 118, 3, 3, 120.
As you notice, '1.31E2' is represented by \x03\x00\x00\x00 which is transformed into 3. By the query_binary_values function ? I want to understand why it is so. I thought with a 4 byte integer I would be able to represent numbers much bigger than 127 ...



print(repr(data))immediately after theTAC.query(). I suspect that the binary data is getting misread as CRLF terminators at some point. Also why do you need the"WAIT 2"command at the start?"at the beginning and end of the pasted data - don't do that please). All that data looks ok. Perhaps to guard from accidental missing data, perhaps you could just do:if len(data) == 100: data = struct.unpack("<25i", data)read()might see CRLF in the data and stop too early.forloop 10 times, I would expect to seeprint(repr(data))output 10 lines from the 10 histogram sections queried. Why does your output not show that? Maybe have the print line asprint(f"[{j}]: {repr(data)}")to make it clear what is being printed in each loopNameError: name 'self' is not defined