Skip to content

Commit ffd2249

Browse files
committed
Merge pull request Labber-software#24 from dlcampbel/master
New Driver for Keysight
2 parents 9bfec9a + 45ce75f commit ffd2249

File tree

3 files changed

+962
-0
lines changed

3 files changed

+962
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env python
2+
3+
def upgradeDriverCfg(version, dValue={}, dOption=[]):
4+
"""Upgrade the config given by the dict dValue and dict dOption to the
5+
latest version."""
6+
# the dQuantUpdate dict contains rules for replacing missing quantities
7+
dQuantReplace = {}
8+
# update quantities depending on version
9+
if version == '1.0':
10+
# convert version 1.0 -> 1.1
11+
# changes:
12+
# zero-span mode moved from bool to combo box with start-stop, center-span
13+
version = '1.1'
14+
# assume old value quantity was referring to a voltage
15+
if 'Zero-span mode' in dValue:
16+
bZeroSpan = dValue.pop('Zero-span mode')
17+
if bZeroSpan:
18+
dValue['Range type'] = 'Zero-span mode'
19+
else:
20+
dValue['Range type'] = 'Center - Span'
21+
# return new version and data
22+
return (version, dValue, dOption, dQuantReplace)
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#!/usr/bin/env python
2+
3+
import InstrumentDriver
4+
from VISA_Driver import VISA_Driver
5+
from InstrumentConfig import InstrumentQuantity
6+
import numpy as np
7+
8+
class Error(Exception):
9+
pass
10+
11+
class Driver(VISA_Driver):
12+
""" This class implements the Keysight N90xx instrument driver"""
13+
14+
def performSetValue(self, quant, value, sweepRate=0.0, options={}):
15+
"""Perform the Set Value instrument operation. This function should return the actual value set by the instrument"""
16+
if quant.name in ('Range type',):
17+
if quant.getValueString(value) == 'Zero-span mode':
18+
# set span to zero
19+
self.sendValueToOther('Span', 0.0)
20+
self.sendValueToOther('# of points', 2.0)
21+
#sweep time should be set to a small value (for example, 10 ms)
22+
self.writeAndLog(':SWE:TIME 1E-3;')
23+
else:
24+
# set lowest possible span to get out of zero-span mode
25+
if self.getValue('Span') < 10:
26+
self.sendValueToOther('Span', 1000000)
27+
if self.getValue('# of points') == 2:
28+
self.sendValueToOther('# of points', 1001)
29+
# sweep time should be set to auto
30+
self.writeAndLog(':SWE:TIME:AUTO 1;')
31+
elif quant.name in ('Wait for new trace',):
32+
# turn on continous acquisition if not waiting
33+
if value == False:
34+
self.writeAndLog(':INIT:CONT ON;')
35+
elif quant.name in ('Trace type CS', 'Trace type CW', 'Measurement Type'):
36+
pass
37+
else:
38+
# run standard VISA case
39+
value = VISA_Driver.performSetValue(self, quant, value, sweepRate, options)
40+
return value
41+
42+
43+
def performGetValue(self, quant, options={}):
44+
"""Perform the Get Value instrument operation"""
45+
# check type of quantity
46+
#if quant.name in ('Zero-span mode',):
47+
if quant.name in ('Range type',):
48+
# check if span is zero
49+
span = self.readValueFromOther('Span')
50+
if span == 0:
51+
value = 'Zero-span mode'
52+
else:
53+
# return old value if not in zero span
54+
value = quant.getValueString()
55+
if value == 'Zero-span mode':
56+
value = 'Center - Span'
57+
elif quant.name in ('Signal', 'Signal - Zero span'):
58+
# if not in continous mode, trig from computer
59+
bWaitTrace = self.getValue('Wait for new trace')
60+
bAverage = self.getValue('Average')
61+
# wait for trace, either in averaging or normal mode
62+
if bAverage:
63+
# clear averages
64+
self.writeAndLog(':SENS:AVER:CLE;')
65+
self.writeAndLog(':ABOR;:INIT:CONT OFF;:INIT:IMM;*OPC')
66+
# wait some time before first check
67+
self.thread().msleep(30)
68+
bDone = False
69+
while (not bDone) and (not self.isStopped()):
70+
# check if done
71+
stb = int(self.askAndLog('*ESR?'))
72+
bDone = (stb & 1) > 0
73+
if not bDone:
74+
self.thread().msleep(50)
75+
# if stopped, don't get data
76+
if self.isStopped():
77+
self.writeAndLog('*CLS;:INIT:CONT ON;')
78+
return []
79+
# get data as float32, convert to numpy array
80+
self.write(':FORM REAL,32;TRAC:DATA? TRACE1', bCheckError=False)
81+
sData = self.read(ignore_termination=True)
82+
if bWaitTrace and not bAverage:
83+
self.writeAndLog(':INIT:CONT ON;')
84+
# strip header to find # of points
85+
i0 = sData.find('#')
86+
nDig = int(sData[i0+1])
87+
nByte = int(sData[i0+2:i0+2+nDig])
88+
nPts = nByte/4
89+
# get data to numpy array
90+
vData = np.frombuffer(sData[(i0+2+nDig):(i0+2+nDig+nByte)],
91+
dtype='>f', count=nPts)
92+
# get start/stop frequencies
93+
startFreq = self.readValueFromOther('Start frequency')
94+
stopFreq = self.readValueFromOther('Stop frequency')
95+
# sweepType = self.readValueFromOther('Sweep type')
96+
# # if log scale, take log of start/stop frequencies
97+
# if sweepType == 'Log':
98+
# startFreq = np.log10(startFreq)
99+
# stopFreq = np.log10(stopFreq)
100+
# check if return trace or trace average
101+
if quant.name == 'Signal - Zero span':
102+
# return average
103+
value = np.average(vData)
104+
else:
105+
# create a trace dict
106+
value = InstrumentQuantity.getTraceDict(vData, t0=startFreq,
107+
dt=(stopFreq-startFreq)/(nPts-1))
108+
elif quant.name in ('Signal - CW'):
109+
# if not in continous mode, trig from computer
110+
bWaitTrace = self.getValue('Wait for new trace')
111+
bAverage = self.getValue('Average CW')
112+
# wait for trace, either in averaging or normal mode
113+
if bAverage:
114+
# clear averages
115+
self.writeAndLog(':WAV:AVER:CLE;')
116+
self.writeAndLog(':ABOR;:INIT:CONT OFF;:INIT:IMM;*OPC')
117+
# wait some time before first check
118+
self.thread().msleep(30)
119+
bDone = False
120+
while (not bDone) and (not self.isStopped()):
121+
# check if done
122+
stb = int(self.askAndLog('*ESR?'))
123+
bDone = (stb & 1) > 0
124+
if not bDone:
125+
self.thread().msleep(50)
126+
# if stopped, don't get data
127+
if self.isStopped():
128+
self.writeAndLog('*CLS;:INIT:CONT ON;')
129+
return []
130+
# get data as float32, convert to numpy array
131+
sTraceNum = self.getTraceDict(quant)
132+
sWrite = ':FORM REAL,32;READ:WAV'+sTraceNum+'?'
133+
self.write(sWrite, bCheckError=False)
134+
sData = self.read(ignore_termination=True)
135+
if bWaitTrace and not bAverage:
136+
self.writeAndLog(':INIT:CONT ON;')
137+
# strip header to find # of points
138+
i0 = sData.find('#')
139+
nDig = int(sData[i0+1])
140+
nByte = int(sData[i0+2:i0+2+nDig])
141+
nPts = nByte/4
142+
# get data to numpy array
143+
vData = np.frombuffer(sData[(i0+2+nDig):(i0+2+nDig+nByte)],
144+
dtype='>f', count=nPts)
145+
# get start/stop frequencies
146+
#duration = self.readValueFromOther('Measurement Time IQ')
147+
sampleFreq = self.readValueFromOther('Sample Rate CW')
148+
# sweepType = self.readValueFromOther('Sweep type')
149+
# # if log scale, take log of start/stop frequencies
150+
# if sweepType == 'Log':
151+
# startFreq = np.log10(startFreq)
152+
# stopFreq = np.log10(stopFreq)
153+
# check if return trace or trace average
154+
# create a trace dict
155+
if self.getValue('Trace type CW') == 'unprocessed IQ trace data (V)':
156+
#the trace is complex. I values are even indices while Q values are odd indices.
157+
realData = vData[0:nPts:2]
158+
imagData = vData[1:nPts:2]
159+
cData = realData +1j*imagData
160+
samplePeriod = (2/sampleFreq)
161+
else:
162+
#the trace is a simple vector.
163+
cData = vData +1j*np.zeros(vData.shape)
164+
samplePeriod = (1/sampleFreq)
165+
166+
value = InstrumentQuantity.getTraceDict(cData, t0=0.0, dt=samplePeriod)
167+
168+
elif quant.name in ('Signal - CS'):
169+
# if not in continous mode, trig from computer
170+
bWaitTrace = self.getValue('Wait for new trace')
171+
bAverage = self.getValue('Average CS')
172+
# wait for trace, either in averaging or normal mode
173+
if bAverage:
174+
# clear averages
175+
self.writeAndLog(':SPEC:AVER:CLE;')
176+
self.writeAndLog(':ABOR;:INIT:CONT OFF;:INIT:IMM;*OPC')
177+
# wait some time before first check
178+
self.thread().msleep(30)
179+
bDone = False
180+
while (not bDone) and (not self.isStopped()):
181+
# check if done
182+
stb = int(self.askAndLog('*ESR?'))
183+
bDone = (stb & 1) > 0
184+
if not bDone:
185+
self.thread().msleep(50)
186+
# if stopped, don't get data
187+
if self.isStopped():
188+
self.writeAndLog('*CLS;:INIT:CONT ON;')
189+
return []
190+
# get data as float32, convert to numpy array
191+
sTraceNum = self.getTraceDict(quant)
192+
sWrite = ':FORM REAL,32;READ:SPEC'+sTraceNum+'?'
193+
self.write(sWrite, bCheckError=False)
194+
sData = self.read(ignore_termination=True)
195+
if bWaitTrace and not bAverage:
196+
self.writeAndLog(':INIT:CONT ON;')
197+
# strip header to find # of points
198+
i0 = sData.find('#')
199+
nDig = int(sData[i0+1])
200+
nByte = int(sData[i0+2:i0+2+nDig])
201+
nPts = nByte/4
202+
# get data to numpy array
203+
vData = np.frombuffer(sData[(i0+2+nDig):(i0+2+nDig+nByte)],
204+
dtype='>f', count=nPts)
205+
# get start/stop frequencies
206+
#duration = self.readValueFromOther('Measurement Time IQ')
207+
centerFreq = self.getValue('Center frequency CS')
208+
span = self.getValue('Span CS')
209+
startFreq = centerFreq - span/2
210+
stopFreq = centerFreq + span/2
211+
# sweepType = self.readValueFromOther('Sweep type')
212+
# # if log scale, take log of start/stop frequencies
213+
# if sweepType == 'Log':
214+
# startFreq = np.log10(startFreq)
215+
# stopFreq = np.log10(stopFreq)
216+
# check if return trace or trace average
217+
# create a trace dict
218+
if self.getValue('Trace type CS') in ('unprocessed IQ trace data (V)', 'processed I/Q trace vs. time'):
219+
#the trace is complex. I values are even indices while Q values are odd indices.
220+
realData = vData[0:nPts:2]
221+
imagData = vData[1:nPts:2]
222+
cData = realData +1j*imagData
223+
nPts_new = nPts/2
224+
else:
225+
#the trace is a simple vector.
226+
cData = vData +1j*np.zeros(vData.shape)
227+
nPts_new = nPts
228+
229+
if self.getValue('Trace type CS') in ('log-mag vs. Freq.', 'avged log-mag vs. Freq.', 'phase of FFT vs. Freq.', 'linear spectrum (V RMS)', 'avged linear spectrum (V RMS)'):
230+
startValue=startFreq
231+
delta=(stopFreq-startFreq)/(nPts_new-1)
232+
else:
233+
startValue=0
234+
delta = 1
235+
236+
237+
value = InstrumentQuantity.getTraceDict(cData, t0=startValue,
238+
dt=delta)
239+
240+
elif quant.name in ('Wait for new trace',):
241+
# do nothing, return local value
242+
value = quant.getValue()
243+
elif quant.name in ('Trace type CS', 'Trace type CW', 'Measurement Type'):
244+
value = self.getValue(quant.name)
245+
else:
246+
# for all other cases, call VISA driver
247+
value = VISA_Driver.performGetValue(self, quant, options)
248+
return value
249+
250+
def getTraceDict(self, quant):
251+
if quant.name in ('Signal - CS'):
252+
traceDict = {'unprocessed IQ trace data (V)': '0',
253+
'log-mag vs. time': '2',
254+
'processed I/Q trace vs. time': '3',
255+
'log-mag vs. Freq.': '4',
256+
'avged log-mag vs. Time': '5',
257+
'avged log-mag vs. Freq.': '7',
258+
'shape of FFT window': '9',
259+
'phase of FFT vs. Freq.': '10',
260+
'linear spectrum (V RMS)': '11',
261+
'avged linear spectrum (V RMS)': '12'
262+
}
263+
sTraceType = self.getValue('Trace type CS')
264+
elif quant.name in ('Signal - CW'):
265+
traceDict = {'unprocessed IQ trace data (V)': '0',
266+
'log-mag vs. time': '2',
267+
}
268+
sTraceType = self.getValue('Trace type CW')
269+
return traceDict[sTraceType]
270+
271+
272+
273+
if __name__ == '__main__':
274+
pass

0 commit comments

Comments
 (0)