quarchCalibration 1.1.26__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quarchCalibration/BK9832B.py +627 -0
- quarchCalibration/Docs/CHANGES.rst +113 -0
- quarchCalibration/Docs/Makefile +20 -0
- quarchCalibration/Docs/__init__.py +0 -0
- quarchCalibration/Docs/_build/doctrees/CHANGES.doctree +0 -0
- quarchCalibration/Docs/_build/doctrees/environment.pickle +0 -0
- quarchCalibration/Docs/_build/doctrees/readme.doctree +0 -0
- quarchCalibration/Docs/_build/doctrees/source/changelog.doctree +0 -0
- quarchCalibration/Docs/_build/html/.buildinfo +4 -0
- quarchCalibration/Docs/_build/html/CHANGES.html +198 -0
- quarchCalibration/Docs/_build/html/_sources/CHANGES.rst.txt +75 -0
- quarchCalibration/Docs/_build/html/_sources/readme.rst.txt +38 -0
- quarchCalibration/Docs/_build/html/_sources/source/changelog.rst.txt +1 -0
- quarchCalibration/Docs/_build/html/_static/alabaster.css +703 -0
- quarchCalibration/Docs/_build/html/_static/basic.css +925 -0
- quarchCalibration/Docs/_build/html/_static/custom.css +1 -0
- quarchCalibration/Docs/_build/html/_static/doctools.js +156 -0
- quarchCalibration/Docs/_build/html/_static/documentation_options.js +13 -0
- quarchCalibration/Docs/_build/html/_static/file.png +0 -0
- quarchCalibration/Docs/_build/html/_static/language_data.js +199 -0
- quarchCalibration/Docs/_build/html/_static/minus.png +0 -0
- quarchCalibration/Docs/_build/html/_static/plus.png +0 -0
- quarchCalibration/Docs/_build/html/_static/pygments.css +83 -0
- quarchCalibration/Docs/_build/html/_static/searchtools.js +574 -0
- quarchCalibration/Docs/_build/html/_static/sphinx_highlight.js +154 -0
- quarchCalibration/Docs/_build/html/genindex.html +98 -0
- quarchCalibration/Docs/_build/html/objects.inv +6 -0
- quarchCalibration/Docs/_build/html/readme.html +128 -0
- quarchCalibration/Docs/_build/html/search.html +117 -0
- quarchCalibration/Docs/_build/html/searchindex.js +1 -0
- quarchCalibration/Docs/_build/html/source/changelog.html +198 -0
- quarchCalibration/Docs/conf.py +59 -0
- quarchCalibration/Docs/make.bat +35 -0
- quarchCalibration/Docs/readme.rst +38 -0
- quarchCalibration/Docs/source/changelog.rst +1 -0
- quarchCalibration/ET2260.py +209 -0
- quarchCalibration/Keithley_DMM6500_control.py +623 -0
- quarchCalibration/Keysight_AC6804B_control.py +623 -0
- quarchCalibration/PowerModuleCalibration.py +607 -0
- quarchCalibration/QTL1944_06_hd_plus_ppm.py +1858 -0
- quarchCalibration/QTL1944_hd_ppm.py +1756 -0
- quarchCalibration/QTL2347_pcie.py +1157 -0
- quarchCalibration/QTL2525_sff.py +948 -0
- quarchCalibration/QTL2536_6_way_switchbox.py +101 -0
- quarchCalibration/QTL2582_3ph_ac.py +1046 -0
- quarchCalibration/QTL2621_2ch_mezz.py +961 -0
- quarchCalibration/QTL2626_4ch_mezz.py +783 -0
- quarchCalibration/QTL2628_ext_mezz_dimm.py +796 -0
- quarchCalibration/QTL2631_ext_mezz.py +771 -0
- quarchCalibration/QTL2631_pcie.py +802 -0
- quarchCalibration/QTL2673_edsff.py +855 -0
- quarchCalibration/QTL2843_iec_ac.py +1052 -0
- quarchCalibration/QTL3216_pcie.py +1061 -0
- quarchCalibration/__init__.py +10 -0
- quarchCalibration/__main__.py +3 -0
- quarchCalibration/_version.py +1 -0
- quarchCalibration/acHelpers.py +183 -0
- quarchCalibration/ac_pam.py +1156 -0
- quarchCalibration/calibrationConfig.py +27 -0
- quarchCalibration/calibrationUtil.py +533 -0
- quarchCalibration/deviceHelpers.py +125 -0
- quarchCalibration/elpaSine.py +456 -0
- quarchCalibration/keithley_2460_control.py +972 -0
- quarchCalibration/pamCommon.py +554 -0
- quarchCalibration/pamHelpers.py +36 -0
- quarchCalibration/threePhaseSwitchBox.py +218 -0
- quarchcalibration-1.1.26.dist-info/METADATA +143 -0
- quarchcalibration-1.1.26.dist-info/RECORD +70 -0
- quarchcalibration-1.1.26.dist-info/WHEEL +5 -0
- quarchcalibration-1.1.26.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
#import telnetlib
|
|
2
|
+
import socket
|
|
3
|
+
import time
|
|
4
|
+
import logging,os
|
|
5
|
+
import sys
|
|
6
|
+
from quarchCalibration.deviceHelpers import locateMdnsInstr
|
|
7
|
+
from quarchpy.user_interface import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
#'''
|
|
11
|
+
#Prints out a list of calibration instruments nicely onto the terminal, numbering each unit
|
|
12
|
+
#'''
|
|
13
|
+
#def listCalInstruments(scanDictionary):
|
|
14
|
+
# if (not scanDictionary):
|
|
15
|
+
# print ("No instruments found to display")
|
|
16
|
+
# else:
|
|
17
|
+
# x = 1
|
|
18
|
+
# for k, v in scanDictionary.items():
|
|
19
|
+
# # these items should all be Keithley 2460 SMUs
|
|
20
|
+
# # form of the value is 'Keithley 2460 #04412428._http._tcp.local.'
|
|
21
|
+
# # we want to extract name, serial number and ip address
|
|
22
|
+
# ip = k
|
|
23
|
+
# # if we recognise the device, pull out Keithley serial number
|
|
24
|
+
# if "Keithley 2460 " in v[:14]: # currently we don't get here without this being true, but that may not be the case in future
|
|
25
|
+
# id = v[:14] + "\t" + v[14:].split(".")[0] # ignore the name we've just matched, and take everything up to the first '.' this should be the serial number
|
|
26
|
+
# else:
|
|
27
|
+
# id = v # else we don't recognise the device, return the whole identifier unmodified
|
|
28
|
+
# print (str(x) + " - " + id + "\t" + ip)
|
|
29
|
+
# x += 1
|
|
30
|
+
|
|
31
|
+
#'''
|
|
32
|
+
#Allows the user to select a test instrument
|
|
33
|
+
#'''
|
|
34
|
+
#def userSelectCalInstrument(scanDictionary=None, scanFilterStr="2460", title=None, message=None, tableHeaders= None, additionalOptions = None, nice=False):
|
|
35
|
+
# #Initiate values. Originals must be stored for the case of a rescan.
|
|
36
|
+
# originalOptions = additionalOptions
|
|
37
|
+
# if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
|
|
38
|
+
# nice = False
|
|
39
|
+
# if message is None: message = "Select the calibration instrument to use:"
|
|
40
|
+
# if title is None: title = "Select a calibration instrument"
|
|
41
|
+
# while(True): #breaks when valid user input given
|
|
42
|
+
# # Scan first, if no list is supplied
|
|
43
|
+
# if (scanDictionary is None):
|
|
44
|
+
# printText ("Scanning for instruments...")
|
|
45
|
+
# scanDictionary = foundDevices = locateMdnsInstr(scanFilterStr)
|
|
46
|
+
|
|
47
|
+
# deviceList = []
|
|
48
|
+
|
|
49
|
+
# if nice: #prep data for nice list selection,
|
|
50
|
+
# if additionalOptions is None: additionalOptions = ["Rescan", "Quit"]
|
|
51
|
+
# if (not scanDictionary):
|
|
52
|
+
# deviceList.append(["No instruments found to display"])
|
|
53
|
+
# else:
|
|
54
|
+
# for k, v in scanDictionary.items():
|
|
55
|
+
# # these items should all be Keithley 2460 SMUs
|
|
56
|
+
# # form of the value is 'Keithley 2460 #04412428._http._tcp.local.'
|
|
57
|
+
# # we want to extract name, serial number and ip address
|
|
58
|
+
# ip = k
|
|
59
|
+
# # if we recognise the device, pull out Keithley serial number
|
|
60
|
+
# if "Keithley 2460 " in v[:14]: # currently we don't get here without this being true, but that may not be the case in future
|
|
61
|
+
# name =v[:14]
|
|
62
|
+
# serialNo = v[14:].split(".")[0]
|
|
63
|
+
# deviceList.append([name,serialNo,ip])
|
|
64
|
+
# else:
|
|
65
|
+
# id = v # else we don't recognise the device, return the whole identifier unmodified
|
|
66
|
+
# deviceList.append([ip + "=" + id + " " + ip])
|
|
67
|
+
# adOp = []
|
|
68
|
+
# for option in additionalOptions:
|
|
69
|
+
# adOp.append([option]*3)
|
|
70
|
+
# userStr = listSelection(title=title, message=message, selectionList=deviceList, tableHeaders=["Name","Serial","IP Address"], nice=nice, indexReq=True, additionalOptions=adOp)[3] #Address will allways be 3 in this format
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# else: #Prep data for test center
|
|
74
|
+
# if (not scanDictionary):
|
|
75
|
+
# deviceList.append("1=No instruments found to display")
|
|
76
|
+
# else:
|
|
77
|
+
|
|
78
|
+
# x = 1
|
|
79
|
+
# for k, v in scanDictionary.items():
|
|
80
|
+
# # these items should all be Keithley 2460 SMUs
|
|
81
|
+
# # form of the value is 'Keithley 2460 #04412428._http._tcp.local.'
|
|
82
|
+
# # we want to extract name, serial number and ip address
|
|
83
|
+
# ip = k
|
|
84
|
+
# # if we recognise the device, pull out Keithley serial number
|
|
85
|
+
# if "Keithley 2460 " in v[:14]: # currently we don't get here without this being true, but that may not be the case in future
|
|
86
|
+
# id = v[:14] + "\t" + v[14:].split(".")[0] # ignore the name we've just matched, and take everything up to the first '.' this should be the serial number
|
|
87
|
+
# else:
|
|
88
|
+
# id = v # else we don't recognise the device, return the whole identifier unmodified
|
|
89
|
+
# deviceList.append(ip + "=" + id + "\t" + ip)
|
|
90
|
+
# x += 1
|
|
91
|
+
# if additionalOptions is None:
|
|
92
|
+
# additionalOptions = "Rescan=Rescan,Quit=Quit"
|
|
93
|
+
# deviceList = ",".join(deviceList)
|
|
94
|
+
# userStr = listSelection(title=title,message=message,selectionList=deviceList, additionalOptions=additionalOptions)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# # Process the user response
|
|
99
|
+
# if (userStr == 'q' or userStr.lower() in "quit"):
|
|
100
|
+
# return "quit"
|
|
101
|
+
# elif (userStr == 'r' or userStr.lower() in "rescan"):
|
|
102
|
+
# scanDictionary = None
|
|
103
|
+
# additionalOptions = originalOptions
|
|
104
|
+
# else:
|
|
105
|
+
# # Return the address string of the selected instrument
|
|
106
|
+
# return userStr
|
|
107
|
+
|
|
108
|
+
'''
|
|
109
|
+
Class for control of BK Precision 9832B AC Power Source for calibration purposes
|
|
110
|
+
'''
|
|
111
|
+
class BK9832B:
|
|
112
|
+
|
|
113
|
+
'''
|
|
114
|
+
Init the class
|
|
115
|
+
'''
|
|
116
|
+
def __init__(self, connectionString):
|
|
117
|
+
self.conString = connectionString
|
|
118
|
+
self.connection = None
|
|
119
|
+
self.idnString = "B&K PRECISION,9832B,"
|
|
120
|
+
self.BUFFER_SIZE = 1024
|
|
121
|
+
self.TIMEOUT = 120 #Changed to allow AIC calibration due to delay of meas:curr? when calibrating leakage.
|
|
122
|
+
|
|
123
|
+
'''
|
|
124
|
+
Open the connection to the instrument
|
|
125
|
+
'''
|
|
126
|
+
def openConnection (self, connectionString = None):
|
|
127
|
+
# Connect TCP
|
|
128
|
+
if (connectionString is not None):
|
|
129
|
+
self.conString = connectionString
|
|
130
|
+
self.connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
|
131
|
+
self.connection.settimeout(self.TIMEOUT)
|
|
132
|
+
logging.debug(os.path.basename(__file__) + ": opening connection: " + self.conString)
|
|
133
|
+
self.connection.connect((self.conString,5025))
|
|
134
|
+
# Clear errors, set to default state
|
|
135
|
+
response = self.sendCommand ("*RST") # The BK9832B does not list a *RST command, but it does not complain and this still clears the input buffer. it doesn't list *IDN? either but that works
|
|
136
|
+
# Send the IDN? command
|
|
137
|
+
response = self.sendCommandQuery ("*IDN?")
|
|
138
|
+
# Verify this looks like the expected instrument
|
|
139
|
+
if (response.find (self.idnString) == -1):
|
|
140
|
+
raise ValueError ("Connected device does not appear to be a BK9832B")
|
|
141
|
+
|
|
142
|
+
'''
|
|
143
|
+
Close the connection to the instrument
|
|
144
|
+
'''
|
|
145
|
+
def closeConnection (self):
|
|
146
|
+
logging.debug(os.path.basename(__file__) + ": closing connection to BK9832B ")
|
|
147
|
+
self.connection.close()
|
|
148
|
+
|
|
149
|
+
'''
|
|
150
|
+
Attempts to force close any existing (LAN) socket connections
|
|
151
|
+
'''
|
|
152
|
+
def closeDeadConnections (self):
|
|
153
|
+
deadSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
|
154
|
+
deadSocket.settimeout(self.TIMEOUT)
|
|
155
|
+
deadSocket.connect((self.conString,5030))
|
|
156
|
+
deadSocket.close()
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
'''
|
|
160
|
+
Send a command to the instrument and return the response from the query
|
|
161
|
+
This should only be used for commands which expect a response
|
|
162
|
+
'''
|
|
163
|
+
def sendCommandQuery (self, commandString):
|
|
164
|
+
self.openConnection()
|
|
165
|
+
retries = 1
|
|
166
|
+
while retries < 5:
|
|
167
|
+
try:
|
|
168
|
+
# Send the command
|
|
169
|
+
startTime= int(round(time.time() * 1000))
|
|
170
|
+
logging.debug(os.path.basename(__file__) + ": sending command: " + commandString)
|
|
171
|
+
self.connection.send((commandString + "\r\n").encode('latin-1'))
|
|
172
|
+
# Read back the response data
|
|
173
|
+
resultStr = self.connection.recv(self.BUFFER_SIZE).decode("utf-8")
|
|
174
|
+
endTime = int(round(time.time() * 1000))
|
|
175
|
+
logging.debug(os.path.basename(__file__) + ": received: " + resultStr)
|
|
176
|
+
logging.debug(os.path.basename(__file__) + ": Time Taken : " + str(endTime-startTime) + " mS")
|
|
177
|
+
resultStr = resultStr.strip ('\r\n\t')
|
|
178
|
+
# If no response came back
|
|
179
|
+
if (resultStr is None or resultStr == ""):
|
|
180
|
+
raise ValueError ("The BK9832B did not return a response")
|
|
181
|
+
return resultStr
|
|
182
|
+
except socket.timeout:
|
|
183
|
+
logging.debug(os.path.basename(__file__) + ": BK9832B command timed out: " + commandString + ", closing connection and retrying")
|
|
184
|
+
# reset connections to BK9832B
|
|
185
|
+
self.closeDeadConnections()
|
|
186
|
+
# reopen connection to BK9832B
|
|
187
|
+
self.connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
|
188
|
+
self.connection.settimeout(self.TIMEOUT)
|
|
189
|
+
self.connection.connect((self.conString,5025))
|
|
190
|
+
# increment retry counter
|
|
191
|
+
retries = retries + 1
|
|
192
|
+
raise TimeoutError (os.path.basename(__file__) + ": timed out while expecting a response")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
'''
|
|
196
|
+
Sends a command to the instrument where a response is not expected.
|
|
197
|
+
Status byte check is used to verify that the command does not flag an error
|
|
198
|
+
If an error is found, it will be flushed and the first error text returned
|
|
199
|
+
'OK' is returned on success
|
|
200
|
+
'''
|
|
201
|
+
def sendCommand (self, commandString, expectedResponse = True):
|
|
202
|
+
retries = 1
|
|
203
|
+
while retries < 5:
|
|
204
|
+
try:
|
|
205
|
+
# Send the command
|
|
206
|
+
logging.debug(os.path.basename(__file__) + ": sending command: " + commandString)
|
|
207
|
+
self.connection.send((commandString + "\r\n").encode('latin-1'))
|
|
208
|
+
return "OK"
|
|
209
|
+
except socket.timeout:
|
|
210
|
+
logging.debug(os.path.basename(__file__) + ": BK9832B command timed out: " + commandString + ", closing connection and retrying")
|
|
211
|
+
# reset connections to BK9832B
|
|
212
|
+
self.closeDeadConnections()
|
|
213
|
+
# reopen connection to BK9832B
|
|
214
|
+
self.connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
|
215
|
+
self.connection.settimeout(self.TIMEOUT)
|
|
216
|
+
self.connection.connect((self.conString,5025))
|
|
217
|
+
# increment retry counter
|
|
218
|
+
retries = retries + 1
|
|
219
|
+
raise TimeoutError (os.path.basename(__file__) + ": timed out while sending command to BK9832B")
|
|
220
|
+
|
|
221
|
+
'''
|
|
222
|
+
Reset the instrument
|
|
223
|
+
'''
|
|
224
|
+
def reset (self):
|
|
225
|
+
result = self.sendCommand("*RST")
|
|
226
|
+
return result
|
|
227
|
+
|
|
228
|
+
'''
|
|
229
|
+
Enable/disable the outputs
|
|
230
|
+
'''
|
|
231
|
+
def setOutputEnable (self, enableState):
|
|
232
|
+
if (enableState == True):
|
|
233
|
+
result = self.sendCommand("OUTP ON")
|
|
234
|
+
else:
|
|
235
|
+
result = self.sendCommand("OUTP OFF")
|
|
236
|
+
|
|
237
|
+
return result
|
|
238
|
+
|
|
239
|
+
'''
|
|
240
|
+
Return the output enable state as a boolean
|
|
241
|
+
'''
|
|
242
|
+
def getOutputEnable (self):
|
|
243
|
+
result = self.sendCommandQuery ("OUTP?")
|
|
244
|
+
if (result == "ON"):
|
|
245
|
+
return True
|
|
246
|
+
elif (result == "OFF"):
|
|
247
|
+
return False
|
|
248
|
+
else:
|
|
249
|
+
raise ValueError("Unexpected response received: " + result)
|
|
250
|
+
|
|
251
|
+
'''
|
|
252
|
+
Set the output AC voltage limit, in volts
|
|
253
|
+
This limit applies to AC and AC+DC modes and limits based on the RMS output voltage.
|
|
254
|
+
voltValue should be a float, max value 306.0
|
|
255
|
+
'''
|
|
256
|
+
def setACVoltageLimit (self, voltValue):
|
|
257
|
+
try:
|
|
258
|
+
if float(voltValue) < 0 or float(voltValue) > 310:
|
|
259
|
+
raise ValueError("invalid voltage supplied to setACVoltageLimit, must be a float in range 0 to 306.0")
|
|
260
|
+
else:
|
|
261
|
+
return self.sendCommand("OUTP:LIM:VOLT:AC " + str(float(voltValue)))
|
|
262
|
+
except:
|
|
263
|
+
raise ValueError("invalid voltage supplied to setACVoltageLimit, must be a float in range 0 to 306.0")
|
|
264
|
+
|
|
265
|
+
'''
|
|
266
|
+
Return the ouput AC voltage limit in volts
|
|
267
|
+
'''
|
|
268
|
+
def getACVoltageLimit (self):
|
|
269
|
+
result = self.sendCommandQuery ("OUTP:LIM:VOLT:AC?")
|
|
270
|
+
return float(result)
|
|
271
|
+
|
|
272
|
+
'''
|
|
273
|
+
Set the upper DC voltage limit, in volts
|
|
274
|
+
This limit applies to AC and AC+DC modes and limits based on the RMS output voltage.
|
|
275
|
+
voltValue should be a float, value 0 - 427.0
|
|
276
|
+
'''
|
|
277
|
+
def setUpperDCVoltageLimit (self, voltValue):
|
|
278
|
+
try:
|
|
279
|
+
if float(voltValue) < 0 or float(voltValue) > 427:
|
|
280
|
+
raise ValueError("invalid voltage supplied to setUpperDCVoltageLimit, must be a float in range 0 to 427.0")
|
|
281
|
+
else:
|
|
282
|
+
return self.sendCommand("OUTP:LIM:VOLT:DC:POS " + str(float(voltValue)))
|
|
283
|
+
except:
|
|
284
|
+
raise ValueError("invalid voltage supplied to setUpperDCVoltageLimit, must be a float in range 0 to 427.0")
|
|
285
|
+
|
|
286
|
+
'''
|
|
287
|
+
Return the upper DC voltage limit in volts
|
|
288
|
+
'''
|
|
289
|
+
def getUpperDCVoltageLimit (self):
|
|
290
|
+
result = self.sendCommandQuery ("OUTP:LIM:VOLT:DC:POS?")
|
|
291
|
+
return float(result)
|
|
292
|
+
|
|
293
|
+
'''
|
|
294
|
+
Set the lower DC voltage limit, in volts
|
|
295
|
+
This limit applies to AC and AC+DC modes and limits based on the RMS output voltage.
|
|
296
|
+
voltValue should be a float, value -427.0 - 0
|
|
297
|
+
'''
|
|
298
|
+
def setLowerDCVoltageLimit (self, voltValue):
|
|
299
|
+
try:
|
|
300
|
+
if float(voltValue) < -427 or float(voltValue) > 0:
|
|
301
|
+
raise ValueError("invalid voltage supplied to setLowerDCVoltageLimit, must be a float in range 0 to 427.0")
|
|
302
|
+
else:
|
|
303
|
+
return self.sendCommand("OUTP:LIM:VOLT:DC:NEG " + str(float(voltValue)))
|
|
304
|
+
except:
|
|
305
|
+
raise ValueError("invalid voltage supplied to setLowerDCVoltageLimit, must be a float in range 0 to 427.0")
|
|
306
|
+
|
|
307
|
+
'''
|
|
308
|
+
Return the lower DC voltage limit in volts
|
|
309
|
+
'''
|
|
310
|
+
def getLowerDCVoltageLimit (self):
|
|
311
|
+
result = self.sendCommandQuery ("OUTP:LIM:VOLT:DC:NEG?")
|
|
312
|
+
return float(result)
|
|
313
|
+
|
|
314
|
+
'''
|
|
315
|
+
Switch the output mode
|
|
316
|
+
Set the waveform operation to output.
|
|
317
|
+
'''
|
|
318
|
+
def setOutputMode (self, modeString):
|
|
319
|
+
modeString = modeString.upper()
|
|
320
|
+
# validate modestring
|
|
321
|
+
if modeString in ["NORMAL","STEP","LIST","PULSE"]:
|
|
322
|
+
# set the mode
|
|
323
|
+
return self.sendCommand("OUTP:MOD " + modeString)
|
|
324
|
+
else:
|
|
325
|
+
raise ValueError ("Invalid mode type specified: " + modeString)
|
|
326
|
+
|
|
327
|
+
'''
|
|
328
|
+
Return the output mode
|
|
329
|
+
query the waveform operation to output
|
|
330
|
+
'''
|
|
331
|
+
def getOutputMode (self):
|
|
332
|
+
return self.sendCommandQuery("OUTP:MOD?");
|
|
333
|
+
|
|
334
|
+
#'''
|
|
335
|
+
#Changes the instrument into the specified measurement mode
|
|
336
|
+
#'''
|
|
337
|
+
#def setMeasurementMode (self, measModeString):
|
|
338
|
+
# measModeString = measModeString.upper()
|
|
339
|
+
# if (measModeString == "VOLT"):
|
|
340
|
+
# result = self.sendCommand("SENS:FUNC \"VOLT\"")
|
|
341
|
+
# elif (measModeString == "CURR"):
|
|
342
|
+
# result = self.sendCommand("SENS:FUNC \"CURR\"")
|
|
343
|
+
# else:
|
|
344
|
+
# raise ValueError ("Invalid mode type specified: " + measModeString)
|
|
345
|
+
|
|
346
|
+
# return result
|
|
347
|
+
|
|
348
|
+
#'''
|
|
349
|
+
#Return the current measurement mode as a string
|
|
350
|
+
#'''
|
|
351
|
+
#def getMeasurementMode (self):
|
|
352
|
+
# return self.sendCommandQuery("SENS:FUNC?").strip('\"')
|
|
353
|
+
|
|
354
|
+
#'''
|
|
355
|
+
#Changes the instrument into the specified source/output mode
|
|
356
|
+
#'''
|
|
357
|
+
#def setSourceMode (self, sourceModeString):
|
|
358
|
+
# sourceModeString = sourceModeString.upper()
|
|
359
|
+
# if sourceModeString in ["VOLT","CURR"]:
|
|
360
|
+
# result = self.sendCommand("SOUR:FUNC " + sourceModeString)
|
|
361
|
+
# else:
|
|
362
|
+
# raise ValueError ("Invalid mode type specified: " + sourceModeString)
|
|
363
|
+
# return result
|
|
364
|
+
|
|
365
|
+
#'''
|
|
366
|
+
#Return the source mode, as a string
|
|
367
|
+
#'''
|
|
368
|
+
#def getSourceMode (self):
|
|
369
|
+
# return self.sendCommandQuery("SOUR:FUNC?")
|
|
370
|
+
|
|
371
|
+
#'''
|
|
372
|
+
#Sets the number of measurements to be averaged together to return one voltage measurement
|
|
373
|
+
#'''
|
|
374
|
+
#def setAverageVoltageCount (self, measCount=1):
|
|
375
|
+
# self.sendCommand("VOLT:AVER:COUNT " + str(measCount))
|
|
376
|
+
# self.sendCommand("VOLT:AVER ON")
|
|
377
|
+
|
|
378
|
+
#'''
|
|
379
|
+
#Sets the number of measurements to be averaged together to return one current measurement
|
|
380
|
+
#'''
|
|
381
|
+
#def setAverageCurrentCount (self, measCount=1):
|
|
382
|
+
# self.sendCommand("CURR:AVER:COUNT " + str(measCount))
|
|
383
|
+
# self.sendCommand("CURR:AVER ON")
|
|
384
|
+
|
|
385
|
+
#'''
|
|
386
|
+
#Set the load/drain current to supply
|
|
387
|
+
#'''
|
|
388
|
+
#def setLoadCurrent (self, ampValue):
|
|
389
|
+
# #load current should always be negative
|
|
390
|
+
# if (ampValue <= 0):
|
|
391
|
+
# ampValue = -ampValue
|
|
392
|
+
|
|
393
|
+
# # set source current
|
|
394
|
+
# return self.sendCommand("SOUR:CURR -" + str(ampValue));
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
#'''
|
|
398
|
+
#Set the load/drain current range
|
|
399
|
+
#'''
|
|
400
|
+
#def setLoadCurrentRange(self, ampValue):
|
|
401
|
+
# # load current should always be negative
|
|
402
|
+
# if (ampValue <= 0):
|
|
403
|
+
# ampValue = -ampValue
|
|
404
|
+
# # set source current range
|
|
405
|
+
# val = self.sendCommand("SOUR:CURR:RANG " + str(ampValue));
|
|
406
|
+
# return val
|
|
407
|
+
|
|
408
|
+
#'''
|
|
409
|
+
#Set the load/drain current range to auto
|
|
410
|
+
#'''
|
|
411
|
+
#def setLoadCurrentRangeAuto(self):
|
|
412
|
+
# # set source current range to auto
|
|
413
|
+
# val = self.sendCommand("SOUR:CURR:RANG:AUTO ON");
|
|
414
|
+
# return val
|
|
415
|
+
|
|
416
|
+
#'''
|
|
417
|
+
#Sets the limit for the load current in Amps
|
|
418
|
+
#'''
|
|
419
|
+
#def setLoadCurrentLimit (self, ampValue):
|
|
420
|
+
# return self.sendCommand("SOUR:VOLT:ILIM " + str(ampValue));
|
|
421
|
+
|
|
422
|
+
#'''
|
|
423
|
+
#Gets the limit for the load current in Amps (float)
|
|
424
|
+
#'''
|
|
425
|
+
#def getLoadCurrentLimit (self):
|
|
426
|
+
# return self.sendCommandQuery("SOUR:VOLT:ILIM?");
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
#'''
|
|
430
|
+
#Gets the current load current, as set
|
|
431
|
+
#'''
|
|
432
|
+
#def getLoadCurrent (self):
|
|
433
|
+
# result = float((self.sendCommandQuery("SOUR:CURR?")))
|
|
434
|
+
# return -result
|
|
435
|
+
|
|
436
|
+
'''
|
|
437
|
+
Measures and returns a current value
|
|
438
|
+
'''
|
|
439
|
+
def measureACCurrent (self):
|
|
440
|
+
result = float((self.sendCommandQuery("MEAS:CURR:AC?")))
|
|
441
|
+
return result
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
'''
|
|
445
|
+
Sets the AC voltage range high or low
|
|
446
|
+
'''
|
|
447
|
+
def setACRange (self, range):
|
|
448
|
+
if str(range).upper() in ["HIGH","LOW"]:
|
|
449
|
+
return self.sendCommand("SOUR:VOLT:RANG " + str(range).upper())
|
|
450
|
+
else:
|
|
451
|
+
raise ValueError("invalid range supplied to setACRange")
|
|
452
|
+
|
|
453
|
+
'''
|
|
454
|
+
Gets the AC range
|
|
455
|
+
'''
|
|
456
|
+
def getACRange (self):
|
|
457
|
+
result = self.sendCommandQuery("SOUR:VOLT:RANG?")
|
|
458
|
+
return result
|
|
459
|
+
|
|
460
|
+
'''
|
|
461
|
+
Sets the AC output voltage in Volts
|
|
462
|
+
'''
|
|
463
|
+
def setACVoltage (self, voltValue):
|
|
464
|
+
try:
|
|
465
|
+
range = self.sendCommandQuery("SOUR:VOLT:RANG?")
|
|
466
|
+
if (range == "HIGH" and (float(voltValue) < 0 or float(voltValue) > 300)) or (range == "LOW" and (float(voltValue) < 0 or float(voltValue) > 150)):
|
|
467
|
+
raise ValueError("voltage parameter to setACVoltage is outside of the availabe range")
|
|
468
|
+
else:
|
|
469
|
+
return self.sendCommand("SOUR:VOLT:AC " + str(voltValue))
|
|
470
|
+
except:
|
|
471
|
+
raise ValueError("voltage parameter to setACVoltage is out of range: " + voltValue)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
'''
|
|
475
|
+
Gets the AC ouput voltage value
|
|
476
|
+
'''
|
|
477
|
+
def getACVoltage (self):
|
|
478
|
+
result = float((self.sendCommandQuery("SOUR:VOLT:AC?")))
|
|
479
|
+
return result
|
|
480
|
+
|
|
481
|
+
'''
|
|
482
|
+
Measures the current load voltage value
|
|
483
|
+
'''
|
|
484
|
+
def measureACVoltage (self):
|
|
485
|
+
result = float(self.sendCommandQuery("MEAS:VOLT:AC?"))
|
|
486
|
+
return result
|
|
487
|
+
|
|
488
|
+
#'''
|
|
489
|
+
#Returns the status byte from the instrument (the result of the *STB? command)
|
|
490
|
+
#This is used to tell if the module is ready or has errored
|
|
491
|
+
#'''
|
|
492
|
+
#def getStatusByte (self, retries=4):
|
|
493
|
+
# tryCount = 0
|
|
494
|
+
# while tryCount <= retries:
|
|
495
|
+
# tryCount +=1
|
|
496
|
+
# # Read status byte
|
|
497
|
+
# resultStr = self.sendCommandQuery ("*STB?")
|
|
498
|
+
# # If we get junk, try again
|
|
499
|
+
# try:
|
|
500
|
+
# statInt = int(resultStr)
|
|
501
|
+
# return statInt
|
|
502
|
+
# except:
|
|
503
|
+
# logging.debug("BK9832B is not responding with valid data retry " + str(tryCount))
|
|
504
|
+
|
|
505
|
+
# #If we have reached here we have excepet on every try and should raise a value error
|
|
506
|
+
# logging.error("BK9832B is not responding with valid data : " + str(resultStr))
|
|
507
|
+
# raise ValueError ("BK9832B is not responding with valid data")
|
|
508
|
+
|
|
509
|
+
#def printInstrumentStatus (self):
|
|
510
|
+
# stat = self.getStatusByte ()
|
|
511
|
+
# if (stat&1 != 0):
|
|
512
|
+
# print ("Measurement Summary Flag Set")
|
|
513
|
+
# if (stat&2 != 0):
|
|
514
|
+
# print ("Reserved Flag 1 Set")
|
|
515
|
+
# if (stat&4 != 0):
|
|
516
|
+
# print ("Error Available Flag Set")
|
|
517
|
+
# if (stat&8 != 0):
|
|
518
|
+
# print ("Questionable Event Flag Set")
|
|
519
|
+
# if (stat&16 != 0):
|
|
520
|
+
# print ("Message Available Flag Set")
|
|
521
|
+
# if (stat&32 != 0):
|
|
522
|
+
# print ("Enabled Standard Event Flag Set")
|
|
523
|
+
# if (stat&64 != 0):
|
|
524
|
+
# print ("Enabled Summary Bit Flag Set")
|
|
525
|
+
# if (stat&128 != 0):
|
|
526
|
+
# print ("Enabled Operation event Flag Set")
|
|
527
|
+
# if (stat == 0):
|
|
528
|
+
# print ("Status flags are clear")
|
|
529
|
+
|
|
530
|
+
#'''
|
|
531
|
+
#Returns the Measurement Summary Bit of the status information
|
|
532
|
+
#'''
|
|
533
|
+
#def getStatusMsbFlag (self):
|
|
534
|
+
# stat = self.getStatusByte ()
|
|
535
|
+
# # Meas bit is LSb
|
|
536
|
+
# if (stat&1 != 0):
|
|
537
|
+
# return True
|
|
538
|
+
# else:
|
|
539
|
+
# return False;
|
|
540
|
+
|
|
541
|
+
#'''
|
|
542
|
+
#Returns the Question Summary Bit of the status information
|
|
543
|
+
#'''
|
|
544
|
+
#def getStatusQsbFlag (self):
|
|
545
|
+
# stat = self.getStatusByte ()
|
|
546
|
+
# # Meas bit is LSb
|
|
547
|
+
# if (stat&8 != 0):
|
|
548
|
+
# return True
|
|
549
|
+
# else:
|
|
550
|
+
# return False;
|
|
551
|
+
|
|
552
|
+
#'''
|
|
553
|
+
#Returns the Error Available Bit of the status information
|
|
554
|
+
#'''
|
|
555
|
+
#def getStatusEavFlag (self):
|
|
556
|
+
# stat = self.getStatusByte ()
|
|
557
|
+
# # Meas bit is LSb
|
|
558
|
+
# if (stat&4 != 0):
|
|
559
|
+
# return True
|
|
560
|
+
# else:
|
|
561
|
+
# return False;
|
|
562
|
+
|
|
563
|
+
#'''
|
|
564
|
+
#Gets the next error from the instrument in a nice text form
|
|
565
|
+
#'''
|
|
566
|
+
#def getNextError (self):
|
|
567
|
+
# errorStr = self.sendCommandQuery ("SYSTem:ERRor:NEXT?")
|
|
568
|
+
# return errorStr
|
|
569
|
+
|
|
570
|
+
#'''
|
|
571
|
+
#Clears all errors from the queue, so the status EAV flag is cleared
|
|
572
|
+
#'''
|
|
573
|
+
#def clearErrors (self):
|
|
574
|
+
# self.sendCommand (":SYSTem:CLEar")
|
|
575
|
+
# #loop = 0
|
|
576
|
+
# # Loop through and flush our all current errors
|
|
577
|
+
# #while (self.getStatusEavFlag () == True and loop < 10):
|
|
578
|
+
# # print (self.getNextError ())
|
|
579
|
+
# # loop += 1
|
|
580
|
+
|
|
581
|
+
#'''
|
|
582
|
+
#Sets the instrument to zero load current and returns the voltage
|
|
583
|
+
#Move to generic class?
|
|
584
|
+
#'''
|
|
585
|
+
#def measureNoLoadVoltage (self):
|
|
586
|
+
# self.setOutputEnable(False)
|
|
587
|
+
# self.setSourceMode("CURR")
|
|
588
|
+
# self.setLoadCurrent(0)
|
|
589
|
+
# self.setLoadVoltageLimit(15)
|
|
590
|
+
# self.setOutputEnable(True)
|
|
591
|
+
# return self.measureLoadVoltage()
|
|
592
|
+
|
|
593
|
+
#'''
|
|
594
|
+
#Sets the instrument load current
|
|
595
|
+
#Move to generic class?
|
|
596
|
+
#'''
|
|
597
|
+
#def setReferenceCurrent (self,value):
|
|
598
|
+
# if value >= 0:
|
|
599
|
+
# self.setOutputEnable(False)
|
|
600
|
+
# self.setSourceMode("CURR")
|
|
601
|
+
# self.setLoadVoltageLimit(15)
|
|
602
|
+
# self.setLoadCurrent(value)
|
|
603
|
+
# self.setOutputEnable(True)
|
|
604
|
+
# else:
|
|
605
|
+
# raise ValueError ("negative load current requested")
|
|
606
|
+
|
|
607
|
+
#'''
|
|
608
|
+
#Sets the instrument output voltage
|
|
609
|
+
#Move to generic class?
|
|
610
|
+
#'''
|
|
611
|
+
#def setReferenceVoltage (self,value,currentLimit="1e-1"):
|
|
612
|
+
# if value >= 0:
|
|
613
|
+
# self.setOutputEnable(False)
|
|
614
|
+
# self.setSourceMode("VOLT")
|
|
615
|
+
# self.setLoadCurrentLimit(currentLimit)
|
|
616
|
+
# self.setLoadVoltageLimit(15)
|
|
617
|
+
# self.setLoadVoltage(value)
|
|
618
|
+
# self.setOutputEnable(True)
|
|
619
|
+
# else:
|
|
620
|
+
# raise ValueError ("negative voltage requested") # this is possible but a bad idea unless we really want it
|
|
621
|
+
|
|
622
|
+
'''
|
|
623
|
+
Puts the into a safe state
|
|
624
|
+
Move to generic class?
|
|
625
|
+
'''
|
|
626
|
+
def disable (self):
|
|
627
|
+
self.setOutputEnable(False)
|