Skip to content

Commit 0843908

Browse files
committed
Add additional drivers: Keysight8164B, PCD104
Adds drivers for the laser and power meter modules of the Keysight 8164B, as well as for the PCD 104 polarization stabilizer. Also: -Edits made to Measure.py to test the interoperability between the Keysight laser sweep. -init file for instruments edited to make modules accessible from GUI
1 parent c0a14d2 commit 0843908

File tree

4 files changed

+277
-19
lines changed

4 files changed

+277
-19
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import time
2+
import visa
3+
4+
class GenPhotPCD104(object):
5+
'''
6+
This class models the General Photonics Polarization Scrambler
7+
8+
.. note:: When using any laser command, remember to send shut-off-laser command at the end of each sweep command set.
9+
For Trigger Sweep, send shut-off-laser command after sweep ends (sweep end condition noted in TriggerSweepSetup function)
10+
'''
11+
12+
def __init__(self, res_manager, address='GPIB0::5::INSTR'):
13+
'''
14+
Constructor method
15+
16+
:param res_manager: PyVisa resource manager
17+
:type res_manager: PyVisa resourceManager object
18+
:param address: SCPI address of instrument
19+
:type address: string
20+
'''
21+
self.active = False
22+
self.gpib = res_manager.open_resource(address)
23+
self.gpib.write ('*IDN?')
24+
info = self.gpib.read()
25+
print ('Connection Successful: %s' % info)
26+
27+
def whoAmI(self):
28+
''':returns: reference to device'''
29+
return 'PolScramb'
30+
31+
def change_state(self):
32+
33+
if self.active == True:
34+
self.active = False
35+
else:
36+
self.active = True
37+
38+
def getWavelength(self):
39+
'''Get current Wavelength'''
40+
self.gpib.write('*WAV?')
41+
info = self.gpib.read()
42+
return info
43+
44+
def enable(self):
45+
'''Enable Scrambling'''
46+
self.gpib.write('*ENA#')
47+
48+
def disable(self):
49+
'''Disable Scrambling'''
50+
self.gpib.write('*DIS#')
51+
52+
def setWavelength(self, wavelength):
53+
'''
54+
Set Wavelength of Operation
55+
'''
56+
if wavelength != 980 and wavelength != 1060 and wavelength != 1310 and wavelength != 1480 and wavelength != 1550 and wavelength != 1600:
57+
return "Invalid wavelength. Please try again."
58+
else:
59+
self.gpib.write('*WAV ' + str(int(wavelength))+ '#')
60+
return "Success"
61+
62+
63+
#if __name__ == "__main__":
64+
65+
'''
66+
Copyright (C) 2017 Robert Polster
67+
This program is free software: you can redistribute it and/or modify
68+
it under the terms of the GNU General Public License as published by
69+
the Free Software Foundation, either version 3 of the License, or
70+
(at your option) any later version.
71+
72+
This program is distributed in the hope that it will be useful,
73+
but WITHOUT ANY WARRANTY; without even the implied warranty of
74+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75+
GNU General Public License for more details.
76+
77+
You should have received a copy of the GNU General Public License
78+
along with this program. If not, see <http://www.gnu.org/licenses/>.
79+
'''
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#import visa
2+
#import time
3+
#import sys
4+
import struct
5+
6+
class Keysight8164B_PowerMeter(object):
7+
'''
8+
This class models a Powermeter Agilent 8163A/B Lightwave Multimeter.
9+
'''
10+
CURRENT_CHANNEL = 1
11+
12+
def __init__(self,res_manager,address='GPIB0::1::INSTR', channel=1):
13+
'''
14+
Constructor method
15+
16+
:param res_manager: PyVisa resource manager
17+
:type res_manager: PyVisa resourceManager object
18+
:param address: SCPI address of instrument
19+
:type address: String
20+
'''
21+
self.active = False
22+
self.gpib = res_manager.open_resource(address)
23+
if '.' in str(channel):
24+
self.__channel = int(channel.split('.')[0])
25+
self.__port = int(channel.split('.')[1])
26+
else:
27+
self.__channel = channel
28+
self.__port = 1
29+
30+
# Set Power Unit to dbm
31+
32+
self.gpib.write('sens' + self.__channel + ':pow:unit 0')
33+
34+
def _checkChannel(self):
35+
36+
if CURRENT_CHANNEL != self.__channel:
37+
_setChannel(self.__channel)
38+
39+
def _setChannel(self, newChannel):
40+
'''
41+
The purpose of this method is to change channels
42+
The syntax of usage will depend on the particular device.
43+
'''
44+
CURRENT_CHANNEL = newChannel
45+
self.__channel = newChannel
46+
47+
48+
def whoAmI(self):
49+
''':returns: reference to device'''
50+
return 'PowerMeter'
51+
52+
def get_power(self,wavelength=1550):
53+
''' return power meter reading after setting correct wavelength'''
54+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':pow:wav '+str(wavelength)+'nm')
55+
return float(self.gpib.query('read'+str(int(self.__channel))+':chan'+str(int(self.__port))+':pow?'))
56+
57+
def get_feedback(self):
58+
return self.get_power()
59+
60+
61+
def close(self):
62+
'''
63+
Release resources
64+
'''
65+
self.gpib.close()
66+
67+
def change_state(self):
68+
69+
if self.active == True:
70+
self.active = False
71+
else:
72+
self.active = True
73+
74+
def config_meter(self, range):
75+
if self.__port != 2:
76+
range = int(range)
77+
78+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':pow:unit 0')
79+
print self.gpib.query('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':pow:unit?')
80+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':pow:range:auto 0') #Auto ranging turned off
81+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':pow:rang '+str(range)+'DBM')
82+
self.gpib.write('trig'+str(int(self.__channel))+':inp:rearm on')
83+
84+
def prep_measure_on_trigger(self, samples = 64):
85+
if self.__port != 2:
86+
self.gpib.write('*CLS')
87+
samples = int(samples)
88+
89+
#self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:stat stab,stop') #switch stab with logg depending
90+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:stat logg,stop') #switch stab with logg depending
91+
self.gpib.write('trig'+str(int(self.__channel))+':chan'+str(int(self.__port))+':inp sme') #Set up trigger
92+
print self.gpib.query('trig'+str(int(self.__channel))+':inp?')
93+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:par:logg '+str(samples)+',100us')
94+
print self.gpib.query('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:par:logg?')
95+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:stat logg,start')
96+
97+
print self.gpib.query('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:stat?')
98+
print self.gpib.query('syst:err?')
99+
100+
101+
def get_result_from_log(self,samples=64):
102+
103+
if self.__port != 2:
104+
print self.gpib.query('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:stat?')
105+
106+
self.gpib.write('sens'+str(int(self.__channel))+':chan'+str(int(self.__port))+':func:res?')
107+
data = self.gpib.read_raw()
108+
print self.gpib.query('syst:err?')
109+
110+
111+
samples = int(samples)
112+
113+
print data
114+
115+
NofDigits = int(data[1])
116+
117+
HexData = data[2+NofDigits:2+NofDigits+samples*4]
118+
119+
FloData = []
120+
121+
for x in range(0, samples*4-1,4):
122+
dat = HexData[x:x+4]
123+
val = struct.unpack('<f', struct.pack('4c', *dat))[0]
124+
print val
125+
FloData.append(val)
126+
127+
self.gpib.write('trig'+str(int(self.__channel))+':inp:rearm on')
128+
print FloData
129+
return FloData[1:]
130+
131+
132+
'''
133+
Copyright (C) 2017 Robert Polster
134+
This program is free software: you can redistribute it and/or modify
135+
it under the terms of the GNU General Public License as published by
136+
the Free Software Foundation, either version 3 of the License, or
137+
(at your option) any later version.
138+
139+
This program is distributed in the hope that it will be useful,
140+
but WITHOUT ANY WARRANTY; without even the implied warranty of
141+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
142+
GNU General Public License for more details.
143+
144+
You should have received a copy of the GNU General Public License
145+
along with this program. If not, see <http://www.gnu.org/licenses/>.
146+
'''

ProberControl/prober/instruments/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
'TektronixCSA8000',
4040
'PIXe_4140',
4141
'PIXe_4322',
42-
'PSY_201'
42+
'PSY_201',
43+
'GenPhotPCD104',
44+
'Keysight8164B_PowerMeter',
45+
'Keysight8164B_Laser'
4346
]
4447

4548
pipe_instrument_groups = {

ProberControl/prober/procedures/Measure.py

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@
1010
# Getting Global_MeasureHandler (singleton)instance; Do not change this!
1111
gh = g()
1212

13+
14+
def testPM(maitre):
15+
16+
laser = gh.get_instrument('Laser')
17+
print "laser "+str(laser)
18+
#pm = gh.get_instrument_triggered_by(laser, 'PowerMeter')
19+
pm = gh.get_instrument('PowerMeter')
20+
print "PM "+str(pm)
21+
gh.connect_instruments(laser, pm)
22+
data = pm.get_power(float(1550))
23+
print data
24+
25+
26+
1327
def test(maitre,data):
1428
pl = NBPlot()
1529
data = [data,data,data]
@@ -49,16 +63,18 @@ def get_o_spectrum_OSA(maitre,start, stop, step, result_path = 0):
4963

5064
return DataList
5165

52-
def get_o_spectrum_PowerMeter(maitre,start, stop, step, channels, result_path = 0):
66+
def get_o_spectrum_triggered_PowerMeter(maitre,start, stop, step, channels = 1, result_path = 0):
5367

5468
start = float(start)
5569
stop = float(stop)
5670
step = float(step)
57-
71+
72+
laser = gh.get_instrument('Laser')
73+
laser.sweepWavelengthsContinuousTriggerOut(start, stop, step, speed = 5)
74+
5875
channels = int(channels)
5976

60-
sweepWidth = stop-start
61-
sampleNumber = sweepWidth/(step) + 1
77+
sampleNumber = laser.numberOfTriggers()
6278

6379
pms = []
6480
for i in xrange(channels):
@@ -67,15 +83,19 @@ def get_o_spectrum_PowerMeter(maitre,start, stop, step, channels, result_path =
6783
pm.prep_measure_on_trigger(sampleNumber)
6884
pms.append(pm)
6985

86+
#t0 = time.time()
87+
#osa = gh.get_instrument('OSA')
88+
#OSAData = osa.get_o_spectrum(start, stop, step)
7089

90+
laser.startSweep()
7191

72-
t0 = time.time()
73-
osa = gh.get_instrument('OSA')
74-
OSAData = osa.get_o_spectrum(start, stop, step)
75-
76-
time.sleep(3)
77-
78-
AllDataList = [OSAData]
92+
while laser.checkSweepStatus() == False:
93+
pass
94+
95+
laser.reset()
96+
#AllDataList = [OSAData]
97+
AllDataList = []
98+
7999
for i in xrange(channels):
80100
PowerList = pms[i].get_result_from_log(sampleNumber)
81101

@@ -95,10 +115,12 @@ def get_o_spectrum_PowerMeter(maitre,start, stop, step, channels, result_path =
95115
AllDataList.append(DataList)
96116

97117
#pl.plot(OSAData,'Optical Spectrum for OSA', 'Wavelength [nm]','Measured Power [dBm]')
118+
119+
98120

99121
if result_path != 0:
100122

101-
_write_data(OSAData,str(result_path)+'_OSA.txt')
123+
#_write_data(OSAData,str(result_path)+'_OSA.txt')
102124
for i in range(len(AllDataList)):
103125
_write_data(AllDataList[i],str(result_path)+'_PM'+str(i)+'.txt')
104126

@@ -110,24 +132,32 @@ def get_current(maitre):
110132
data = dc.get_current()
111133
return data
112134

113-
def get_o_spectrum(maitre,start,stop,step,result_path=0):
135+
def get_o_spectrum_manual_PowerMeter(maitre,start,stop,step,result_path=0):
114136

115137
laser = gh.get_instrument('Laser')
116-
pm = gh.get_instrument_triggered_by(laser, 'PowerMeter')
138+
print "laser "+str(laser)
139+
#pm = gh.get_instrument_triggered_by(laser, 'PowerMeter')
140+
pm = gh.get_instrument('PowerMeter')
141+
print "PM "+str(pm)
142+
gh.connect_instruments(laser, pm)
117143

118144
init_wavelength = float(laser.getwavelength())
119145

120-
laser.sweepWavelengthsTriggerSetup(float(start),float(stop),float(step))
146+
laser.sweepWavelengthsManual(float(start),float(stop),float(step))
121147

122148
DataList = []
149+
123150

151+
print ("Sweeping"),
124152
for x in np.arange(float(start),float(stop)+float(step),float(step)):
125-
laser.trigger()
126-
DataList.append([x,pm.get_o_power(x,True)])
153+
print ("."),
154+
laser.step()
155+
DataList.append([x, pm.get_power(x)])
156+
print ("Sweeping Complete")
127157

128158

129159
laser.setwavelength(init_wavelength)
130-
pm.get_power(init_wavelength,channel)
160+
pm.get_power(init_wavelength)
131161

132162
pl = NBPlot()
133163
pl.plot(

0 commit comments

Comments
 (0)