-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathTSL550.py
449 lines (349 loc) · 15 KB
/
TSL550.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
from __future__ import division
import sys
import serial
class TSL550:
# continuous, two-way, external trigger, constant frequency interval
SWEEP_MODE_MAP = {
(True, False, False, False): 1,
(True, True, False, False): 2,
(False, False, False, False): 3,
(False, True, False, False): 4,
(False, False, False, True): 5,
(False, True, False, True): 6,
(True, False, True, False): 7,
(True, True, True, False): 8,
(False, False, True, False): 9,
(False, True, True, False): 10,
(False, False, True, True): 11,
(False, True, True, True): 12
}
SWEEP_MODE_MAP_REV = {num: settings for settings, num in SWEEP_MODE_MAP.items()}
# Sweep mode statuses
SWEEP_OFF = 0
SWEEP_RUNNING = 1
SWEEP_PAUSED = 2
SWEEP_TRIGGER_WAIT = 3
SWEEP_JUMP = 4
def __init__(self, address, baudrate=9600, terminator="\r"):
"""
Connect to the TSL550. Address is the serial port, baudrate
can be set on the device, terminator is the string the marks
the end of the command.
"""
self.device = serial.Serial(address, baudrate=baudrate, timeout=0)
if sys.version_info.major >= 3: # Python 3 compatibility: convert to bytes
terminator = terminator.encode("ASCII")
self.terminator = terminator
# Make sure the laser is off
self.is_on = False
self.off()
# Set power management to auto
self.power_control = "auto"
self.power_auto()
# Set sweep mode to continuous, two-way, trigger off
self.sweep_set_mode()
def write(self, command):
"""
Write a command to the TSL550. Returns the response (if any).
"""
# Convert to bytes (Python 3 compatibility)
if sys.version_info.major >= 3:
command = command.encode("ASCII")
# Write the command
self.device.write(command + self.terminator)
# Read response
response = ""
in_byte = self.device.read()
while in_byte != self.terminator:
if sys.version_info.major >= 3:
response += in_byte.decode("ASCII")
else:
response += in_byte
in_byte = self.device.read()
return response
def _set_var(self, name, precision, val):
"""
Generic function to set a floating-point variable on the
laser, or return the current value.
"""
if val is not None:
command = ("{}{:."+str(precision)+"f}").format(name, val)
else:
command = name
response = self.write(command)
return float(response)
def on(self):
"""Turn on the laser diode"""
self.is_on = True
self.write("LO")
def off(self):
"""Turn off the laser diode"""
self.is_on = False
self.write("LF")
def wavelength(self, val=None):
"""
Tune the laser to a new wavelength. If a value is not
specified, return the current one. Units: nm.
"""
return self._set_var("WA", 4, val)
def frequency(self, val=None):
"""
Tune the laser to a new wavelength. If a value is not
specified, return the current one. Units: THz.
"""
return self._set_var("FQ", 5, val)
def power_mW(self, val=None):
"""
Set the output optical power in milliwatts. If a value is not
specified, return the current one.
"""
return self._set_var("LP", 2, val)
def power_dBm(self, val=None):
"""
Set the output optical power in decibel-milliwatts. If a value
is not specified, return the current one.
"""
return self._set_var("OP", 2, val)
def power_auto(self):
"""Turn on automatic power control."""
self.power_control = "auto"
self.write("AF")
def power_manual(self):
"""Turn on manual power control."""
self.power_control = "manual"
self.write("AO")
def sweep_wavelength(self, start, stop, duration, number=1,
delay=0, continuous=True, step_size=1,
twoway=False, trigger=False):
r"""
Conduct a sweep between two wavelengths. This method goes from
the start wavelength to the stop wavelength (units:
manometres). The sweep is then repeated the number of times
set in the number parameter.
If delay (units: seconds) is specified, there is a pause of
that duration between each sweep.
If the parameter continuous is False, then the sweep will be
conducted in steps of fixed size as set by the step_size
parameter (units: nanometres).
In continuous mode, the duration is interpreted as the time
for one sweep. In stepwise mode, it is used as the dwell time
for each step. In both cases it has units of seconds and
should be specified in 100 microsecond intervals.
If the twoway parameter is True then one sweep is considered
to be going from the start wavelength to the stop wavelength
and then back to the start; if it is False then one sweep
consists only of going from the start to the top, and the
laser will simply jump back to the start wavelength at the
start of the next sweep.
If the trigger parameter is False then the sweep will execute
immediately. If it is true, the laser will wait for an
external trigger before starting.
To illustrate the different sweep modes:
Continuous, one-way Continuous, two-way
/ / /\ /\ <-- stop frequency
/ / / \ / \
/ / / \/ \ <-- start frequency
<-> duration <----> duration
Stepwise, one-way Stepwise, two-way
__| __| _||_ _||_ <-- stop frequency
__| __| _| |_ _| |_ } step size
__| __| _| |__| |_ <-- start frequency
<-> duration <> duration
Continuous, one-way, delay Continuous, two-way, delay
/ / /\ /\
/ / / \ / \
/ ___/ / \___/ \
<-> delay <-> delay
"""
# Set start and end wavelengths
self.sweep_start_wavelength(start)
self.sweep_end_wavelength(stop)
# Set timing
self.sweep_delay(delay)
if continuous: # Calculate speed
speed = abs(stop - start) / duration
if twoway: # Need to go twice as fast to go up then down in the same time
speed *= 2
self.sweep_speed(speed)
else: # Interpret as time per step
self.sweep_step_time(duration)
self.sweep_set_mode(continuous=continuous, twoway=twoway,
trigger=trigger, const_freq_step=False)
if not self.is_on: # Make sure the laser is on
self.on()
self.sweep_start(number)
def sweep_frequency(self, start, stop, duration, number=1,
delay=0, continuous=True, step_size=1,
twoway=False, trigger=False):
r"""
Conduct a sweep between two frequencies. This method goes from
the start frequency to the stop frequency (units: terahertz).
The sweep is then repeated the number of times set in the
number parameter.
If delay (units: seconds) is specified, there is a pause of
that duration between each sweep.
If the parameter continuous is False, then the sweep will be
conducted in steps of fixed size as set by the step_size
parameter (units: terahertz).
In continuous mode, the duration is interpreted as the time
for one sweep. In stepwise mode, it is used as the dwell time
for each step. In both cases it has units of seconds and
should be specified in 100 microsecond intervals.
If the twoway parameter is True then one sweep is considered
to be going from the start frequency to the stop frequency and
then back to the start; if it is False then one sweep consists
only of going from the start to the top, and the laser will
simply jump back to the start frequency at the start of the
next sweep.
If the trigger parameter is False then the sweep will execute
immediately. If it is true, the laser will wait for an
external trigger before starting.
To illustrate the different sweep modes:
Continuous, one-way Continuous, two-way
/ / /\ /\ <-- stop frequency
/ / / \ / \
/ / / \/ \ <-- start frequency
<-> duration <----> duration
Stepwise, one-way Stepwise, two-way
__| __| _||_ _||_ <-- stop frequency
__| __| _| |_ _| |_ } step size
__| __| _| |__| |_ <-- start frequency
<-> duration <> duration
Continuous, one-way, delay Continuous, two-way, delay
/ / /\ /\
/ / / \ / \
/ ___/ / \___/ \
<-> delay <-> delay
"""
# Set start and end frequencies
self.sweep_start_frequency(start)
self.sweep_end_frequency(stop)
# Set timing
self.sweep_delay(delay)
if continuous: # Calculate speed
speed = abs(3e8/stop - 3e8/start) / duration # Convert to wavelength
if twoway: # Need to go twice as fast to go up then down in the same time
speed *= 2
self.sweep_speed(speed)
else: # Interpret as time per step
self.sweep_step_time(duration)
self.sweep_set_mode(continuous=continuous, twoway=twoway,
trigger=trigger, const_freq_step=not continuous)
if not self.is_on: # Make sure the laser is on
self.on()
self.sweep_start(number)
def sweep_start(self, num=1):
"""
Sweep between two wavelengths one or more times. Set the start
and end wavelengths with
sweep_(start|end)_(wavelength|frequency), and the sweep
operation mode with sweep_set_mode.
"""
self.write("SZ{:d}".format(num)) # Set number of sweeps
self.write("SG") # Start sweeping
def sweep_pause(self):
"""
Pause the sweep. Use sweep_resume to resume.
"""
self.write("SP")
def sweep_resume(self):
"""
Resume a paused sweep.
"""
self.write("SR")
def sweep_stop(self, immediate=True):
"""
Prematurely quit a sweep. If the parameter immediate is True,
the sweep will stop at once. If the parameter is False and the
sweep is continuous, the sweep will stop once if finishes the
current sweep.
"""
if immediate:
self.sweep_pause()
self.write("SQ")
def sweep_status(self):
"""
Check on the current condition of the sweeping function. It
will return one of TSL550.SWEEP_OFF, TSL550.SWEEP_RUNNING,
TSL550.SWEEP_PAUSED, TSL550.SWEEP_TRIGGER_WAIT,
TSL550.SWEEP_JUMP. The first three states are
self-explanatory, but the last two require more detail. If the
status is TSL550.SWEEP_TRIGGER_WAIT, that means that the sweep
has been set to start on an external trigger and that trigger
has not yet been received. If the status is TSL550.SWEEP_JUMP,
that means that the laser is transitioning between the end of
one sweep and the start of the next in one-way sweep mode.
"""
return int(self.write("SK"))
def sweep_set_mode(self, continuous=True, twoway=True, trigger=False, const_freq_step=False):
r"""
Set the mode of the sweep. Options:
- Continuous or stepwise:
/ _|
/ vs _|
/ _|
- Two-way:
/\ / /
/ \ vs / /
/ \ / /
- Constant frequency interval (requires stepwise mode)
- Start from external trigger
"""
try:
mode = TSL550.SWEEP_MODE_MAP[(continuous, twoway, trigger, const_freq_step)]
except KeyError:
raise AttributeError("Invalid sweep configuration.")
self.write("SM{}".format(mode))
def sweep_get_mode(self):
"""
Return the current sweep configuration as a dictionary. See
sweep_set_mode for what the parameters mean.
"""
mode_num = int(self.write("SM"))
mode_settings = TSL550.SWEEP_MODE_MAP_REV[mode_num]
return {
"continuous": mode_settings[0],
"twoway": mode_settings[1],
"trigger": mode_settings[2],
"const_freq_step": mode_settings[3]
}
def sweep_speed(self, val=None):
"""
Set the speed of the continuous sweep, in nm/s. If a new value
is not provided, the current one will be returned.
"""
return self._set_var("SN", 1, val)
def sweep_step_wavelength(self, val=None):
"""
Set the size of each step in the stepwise sweep. If a new
value is not provided, the current one will be returned.
Units: nm
"""
return self._set_var("WW", 4, val)
def sweep_step_frequency(self, val=None):
"""
Set the size of each step in the stepwise sweep when constant
frequency intervals are enabled. If a new value is not
provided, the current one will be returned. Units: THz
"""
return self._set_var("WF", 5, val)
def sweep_step_time(self, val=None):
"""
Set the duration of each step in the stepwise sweep. If a new
value is not provided, the current one will be returned.
"""
return self._set_var("SB", 1, val)
def sweep_delay(self, val=None):
"""
Set the time between consecutive sweeps in continuous mode. If
a new value is not provided, the current one will be returned. Units: s
"""
return self._set_var("SA", 1, val)
def sweep_start_wavelength(self, val=None):
return self._set_var("SS", 4, val)
def sweep_start_frequency(self, val=None):
return self._set_var("FS", 5, val)
def sweep_end_wavelength(self, val=None):
return self._set_var("SE", 4, val)
def sweep_end_frequency(self, val=None):
return self._set_var("FF", 5, val)