-
Notifications
You must be signed in to change notification settings - Fork 1
/
collect.py
132 lines (101 loc) · 4.34 KB
/
collect.py
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# -*- coding: utf-8 -*-
"""
Collects raw data of channels 1 and 2 from Rigol DS1000E series oscilloscopes.
Also records a metadata file with timescale and voltagescale
information to allow other programs to interpret the raw data.
Do not adjust the oscilloscope controls while the program is running.
@author: Aidan Montare <[email protected]>
Based on
http://www.righto.com/2013/07/rigol-oscilloscope-hacks-with-python.html
and
https://www.cibomahto.com/2010/04/controlling-a-rigol-oscilloscope-using-linux-and-python/
"""
import pyvisa
import sys
import os
import time
import datetime
import json
def readWaveform(scope, channel):
"""
Read the raw waveform from the given scope and channel
scope: the opened scope resource
channel: an integer channel number
returns: the raw data
"""
scope.write(":STOP")
scope.write(":WAV:DATA? CHAN" + str(channel))[10:]
rawdata = scope.read_raw()
scope.write(":RUN")
return rawdata
rm = pyvisa.ResourceManager()
instruments = rm.list_resources()
usb = tuple(filter(lambda x: 'USB' in x, instruments))
if len(usb) != 1:
print('Bad instrument list', instruments)
sys.exit(-1)
scope = rm.open_resource(usb[0], timeout=20, chunk_size=1024000) # bigger timeout for long mem
print('Device in use:')
scope_name = scope.query("*IDN?")
print(scope_name)
# configure scope
scope.write(":WAV:POIN:MODE RAW")
# Get metadata
timescale = scope.query_ascii_values(":TIM:SCAL?")[0]
timeoffset = scope.query_ascii_values(":TIM:OFFS?")[0]
voltscale = [scope.query_ascii_values(':CHAN1:SCAL?')[0],
scope.query_ascii_values(':CHAN2:SCAL?')[0]]
voltoffset = [scope.query_ascii_values(":CHAN1:OFFS?")[0],
scope.query_ascii_values(":CHAN2:OFFS?")[0]]
samplerate = scope.query_ascii_values(':ACQ:SAMP?')[0]
metadata = {"timescale": timescale, "timeoffset": timeoffset,
"voltscale": voltscale, "voltoffset": voltoffset,
"samplerate": samplerate}
# the last datetime for which we recorded data
lastSecondRecorded = (datetime.datetime.now(datetime.timezone.utc)
.replace(microsecond=0))
try:
# The main loop runs continuously, but useful code is only
# executed if the current UTC second is more than half over
# and we have not recorded data for this second yet.
# This translates to recording data once a second at the half-
# second mark.
while True:
now = datetime.datetime.now(datetime.timezone.utc)
if now > now.replace(microsecond=500000) and \
now.replace(microsecond=0) > lastSecondRecorded:
print("recording data for", now.isoformat(), end="\t[")
lastSecondRecorded = now.replace(microsecond=0)
folder = os.path.join("data",
now.date().isoformat(),
now.hour)
if not os.path.exists(folder):
os.makedirs(folder)
# read and record data for each channel
for channel in [1, 2]:
rawdata = readWaveform(scope, channel)
filename = os.path.join(folder,
now.strftime("%Y-%m-%dT%H-%M-%S%Z") + \
"chan" + str(channel) + ".bin")
with open(filename, "wb") as f:
f.write(rawdata)
print("*", end="")
# check if we ran too long
check = datetime.datetime.now(datetime.timezone.utc)
if check.replace(microsecond=0) > lastSecondRecorded:
print('\nRead operation took too long: possible data errors in the last set of files')
sys.exit(-1)
metadata_filename = os.path.join(folder,
now.strftime("%Y-%m-%dT%H-%M-%S%Z") + ".json")
with open(metadata_filename, "w") as f:
json.dump(metadata, f, indent=1)
f.write("\n")
print("*]")
else:
None
time.sleep(.1)
except KeyboardInterrupt:
# If the user interrupts the program, end gracefully.
print("Ending collection...", end="")
scope.close()
print("Scope closed.")