-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdaq.py
528 lines (403 loc) · 18.2 KB
/
daq.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
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
####################################
# Author: Christian Dorfer
# Email: [email protected]
####################################
from time import sleep, time
import datetime
from _thread import start_new_thread
import numpy as np
import h5py
class DataHandling(object):
"""
Usage:
dh = DataHandling()
dh.createFile()
t = np.random.random(size=1000)
dh.setTimScale(t)
a = np.random.random(size=(400,1000))
dh.addScanPointData(a)
dh.addScanPointData(a)
dh.addScanPointData(a)
dh.closeFile()
"""
def __init__(self, conf, livemon):
self.hdf = None
self.tctdata = None
self.spcount = 1
self.runnumber = self.readRunNumber()+1
self.config = conf
self.livemon = livemon
#parameters that are set through the GUI (at startup read from configuration file)
self.diamond_name = self.config['AcquisitionControl']['diamond_name']
self.side = int(self.config['AcquisitionControl']['side'])
self.bias_voltage = float(self.config['AcquisitionControl']['bias_voltage'])
self.amplifier = self.config['AcquisitionControl']['amplifier']
self.scan_type = self.config['AcquisitionControl']['scan_type']
self.laser_pulse_energy = float(self.config['AcquisitionControl']['laser_pulse_energy'])
self.pcb = self.config['AcquisitionControl']['pcb']
self.nwf = int(self.config['AcquisitionControl']['number_of_waveforms'])
#self.createFile()
def createFile(self, comment):
#reset old one
self.hdf= None
self.tctdata = None
self.spcount = 0
#read and increase run number
self.runnumber = self.increaseRunNumber()
print('Run number: ', self.runnumber)
#create new h5py file
fname = 'data/run' + str(self.runnumber) + ".hdf5"
self.hdf = h5py.File(fname, "w", libver='latest')
self.hdf.attrs['timestamp'] = '{:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now())
self.tctdata = self.hdf.create_group("tctdata")
self.tctdata.attrs['diamond_name'] = self.diamond_name
self.tctdata.attrs['bias_voltage'] = self.bias_voltage
self.tctdata.attrs['number_of_waveforms'] = self.nwf
self.tctdata.attrs['laser_pulse_energy'] = self.laser_pulse_energy
self.tctdata.attrs['side'] = self.side
self.tctdata.attrs['amplifier'] = self.amplifier
self.tctdata.attrs['scan_type'] = self.scan_type
self.tctdata.attrs['pcb'] = self.pcb
self.tctdata.attrs['comments'] = comment
print('File ', fname, ' created.')
def addScanPointData(self, timestamp, x,y,z, time_axis, wfarr):
sp = str(self.spcount)
self.tctdata.create_dataset(sp, data=wfarr, compression="gzip")
self.tctdata[sp].attrs['timestamp'] = timestamp
self.tctdata[sp].attrs['x'] = x
self.tctdata[sp].attrs['y'] = y
self.tctdata[sp].attrs['z'] = z
self.tctdata[sp].attrs['time_axis'] = time_axis
self.spcount += 1
#print('Scanpoint ', sp, ' written to file.')
#send data to online monitor
self.livemon.setWaveform(time_axis, wfarr[0:len(time_axis)], wfarr[len(wfarr)-len(time_axis):len(wfarr)]) #wf plot
#self.livemon.setScanPoint(x, y, z, np.sum(wfarr[0:len(time_axis)]))
self.livemon.setScanPoint(x, y, z, np.sum(wfarr[0:len(time_axis)]))
#start_new_thread(self.livemon.updatePlots, ())
return sp
def setTemperature(self, val):
self.tctdata.attrs['temperature'] = val
print('Setting temperature: {}'.format(val))
def increaseRunNumber(self):
with open('data/runnumber.dat', "r+") as f:
runnumber = int(f.readline())
f.seek(0)
f.write(str(runnumber+1))
return (runnumber+1)
def readRunNumber(self):
with open('data/runnumber.dat', "r") as f:
return int(f.readline())
def closeFile(self):
self.hdf.flush()
self.hdf.close()
self.livemon.resetPlots()
print('File for run ', str(self.runnumber), ' closed.')
#setter methods to write GUI values back to the configuration file
def setDiamondName(self, val):
self.diamond_name = val
self.config['AcquisitionControl']['diamond_name'] = val
self.config.write()
def setSide(self, val):
self.side = val
self.config['AcquisitionControl']['side'] = int(val)
self.config.write()
def setBiasVoltage(self, val):
self.bias_voltage = val
self.config['AcquisitionControl']['bias_voltage'] = val
self.config.write()
def setLaserPulseEnergy(self, val):
self.laser_pulse_energy = val
self.config['AcquisitionControl']['laser_pulse_energy'] = val
self.config.write()
''' function replaced by set scan type
def setAmplifier(self, val):
self.amplifier = val
self.config['AcquisitionControl']['amplifier'] = val
self.config.write()
'''
def setScanType(self, val):
self.scan_type = val
self.config['AcquisitionControl']['scan_type'] = val
self.config.write()
def setPCB(self, val):
self.pcb = val
self.config['AcquisitionControl']['pcb'] = val
self.config.write()
def setNWf(self, val):
self.nwf = val
self.config['AcquisitionControl']['number_of_waveforms'] = int(val)
self.config.write()
class PositionControl(object):
def __init__(self, stage, axes, config):
self.config = config
self.stage = stage
self.xaxis = axes[0]
self.yaxis = axes[1]
self.zaxis = axes[2]
self.xStepSize = float(config['PositionControl']['xStepSize'])
self.yStepSize = float(config['PositionControl']['yStepSize'])
self.zStepSize = float(config['PositionControl']['zStepSize'])
#hardware limits:
self.xlimlow = float(config['PositionControl']['xLimLow'])
self.xlimhigh = float(config['PositionControl']['xLimHigh'])
self.ylimlow = float(config['PositionControl']['yLimLow'])
self.ylimhigh = float(config['PositionControl']['yLimHigh'])
self.zlimlow = float(config['PositionControl']['zLimLow'])
self.zlimhigh = float(config['PositionControl']['zLimHigh'])
def moveAbsoluteX(self, position):
self.xaxis.on()
self.xaxis.move_to((position), wait=True)
def moveAbsoluteY(self, position):
self.yaxis.on()
self.yaxis.move_to((position), wait=True)
def moveAbsoluteZ(self, position):
self.zaxis.on()
self.zaxis.move_to((position), wait=True)
def moveStepX(self, step):
self.xaxis.on()
self.xaxis.move_by((step), wait=True)
def moveStepY(self, step):
self.yaxis.move_by((step), wait=True)
def moveStepZ(self, step):
self.zaxis.move_by((step), wait=True)
#getter methods do not return class variables but read back values from Newport table
def getXPosition(self):
return self.xaxis.position
def getYPosition(self):
return self.yaxis.position
def getZPosition(self):
return self.zaxis.position
def getXMax(self):
return self.xlimhigh
def getYMax(self):
return self.ylimhigh
def getZMax(self):
return self.zlimhigh
def getXMin(self):
return self.xlimlow
def getYMin(self):
return self.ylimlow
def getZMin(self):
return self.zlimlow
def getCurrentHome(self):
return (self.xaxis.home, self.yaxis.home, self.zaxis.home)
def setHome(self):
self.xlimlow = self.xlimlow -self.xaxis.position
self.xlimhigh = self.xlimhigh - self.xaxis.position
self.xaxis.home = 0
#print(self.xlimlow, self.xaxis.position, self.xlimhigh)
self.ylimlow = self.ylimlow - self.yaxis.position
self.ylimhigh = self.ylimhigh - self.yaxis.position
self.yaxis.home = 0
#print(self.ylimlow, self.yaxis.position, self.ylimhigh)
self.zlimlow = self.zlimlow - self.zaxis.position
self.zlimhigh = self.zlimhigh - self.zaxis.position
self.zaxis.home = 0
#print(self.zlimlow, self.zaxis.position, self.zlimhigh)
def goHome(self):
self.xaxis.home_search(0)
self.yaxis.home_search(0)
self.zaxis.home_search(0)
def findHardwareLimits(self):
self.xaxis.on()
self.yaxis.on()
self.zaxis.on()
sleep(1)
self.xaxis.move_to_hardware_limit(-1, wait=True)
self.xlimlow = self.xaxis.position
self.xaxis.move_to_hardware_limit(1, wait=True)
self.xlimhigh = self.xaxis.position
self.xaxis.move_to((self.xlimlow+self.xlimhigh)/2, wait=True)
self.zaxis.move_to_hardware_limit(-1, wait=True)
self.zlimlow = self.zaxis.position
self.zaxis.move_to_hardware_limit(1, wait=True)
self.zlimhigh = self.zaxis.position
self.zaxis.move_to((self.zlimlow+self.zlimhigh)/2, wait=True)
self.yaxis.move_to_hardware_limit(-1, wait=True)
self.ylimlow = self.yaxis.position
self.yaxis.move_to_hardware_limit(1, wait=True)
self.ylimhigh = self.yaxis.position
self.yaxis.move_to((self.ylimlow+self.ylimhigh)/2, wait=True)
#save the limits in the config
self.config['PositionControl']['xLimLow'] = self.xlimlow
self.config['PositionControl']['xLimHigh'] = self.xlimhigh
self.config['PositionControl']['yLimLow'] = self.ylimlow
self.config['PositionControl']['yLimHigh'] = self.ylimhigh
self.config['PositionControl']['zLimLow'] = self.zlimlow
self.config['PositionControl']['zLimHigh'] = self.zlimhigh
self.config.write()
class AcquisitionControl(object):
def __init__(self, stage, axes, tektronix, datahandler, configuration, arduino): # plus osci later
self.stage = stage
self.xaxis = axes[0]
self.yaxis = axes[1]
self.zaxis = axes[2]
self.tek = tektronix
self.dh = datahandler
self.config = configuration
self.ard = arduino
self.xScanMin = float(self.config['AcquisitionControl']['xMin'])
self.xScanMax = float(self.config['AcquisitionControl']['xMax'])
self.xScanStep = float(self.config['AcquisitionControl']['xStep'])
self.yScanMin = float(self.config['AcquisitionControl']['yMin'])
self.yScanMax = float(self.config['AcquisitionControl']['yMax'])
self.yScanStep = float(self.config['AcquisitionControl']['yStep'])
self.zScanMin = float(self.config['AcquisitionControl']['zMin'])
self.zScanMax = float(self.config['AcquisitionControl']['zMax'])
self.zScanStep = float(self.config['AcquisitionControl']['zStep'])
self.xactive = False
self.yactive = False
self.zactive = False
self.running = False
self.nScanPoints = 0
def startScan(self, stop_event, arg):
self.dh.setTemperature(self.ard.getStoredTemperature())
#some sanity checks
if(self.xactive):
if (self.xScanMax > self.xScanMin and self.xScanStep <= 0) or (self.xScanMin > self.xScanMax and self.xScanStep >= 0) or (abs(self.xScanStep) > abs(self.xScanMax - self.xScanMin)):
print('Check x-limits and step direction/size.')
return
self.xaxis.on()
if(self.yactive):
if (self.yScanMax > self.yScanMin and self.yScanStep <= 0) or (self.yScanMin > self.yScanMax and self.yScanStep >= 0) or (abs(self.yScanStep) > abs(self.yScanMax - self.yScanMin)):
print('Check y-limits and step direction/size.')
return
self.yaxis.on()
if(self.zactive):
if (self.zScanMax > self.zScanMin and self.zScanStep <= 0) or (self.zScanMin > self.zScanMax and self.zScanStep >= 0) or (abs(self.zScanStep) > abs(self.zScanMax - self.zScanMin)):
print('Check z-limits and step direction/size.')
return
self.zaxis.on()
sleep(1)
#calculate number of required steps
xsteps = abs((self.xScanMin - self.xScanMax)/self.xScanStep)
ysteps = abs((self.yScanMin - self.yScanMax)/self.yScanStep)
zsteps = abs((self.zScanMin - self.zScanMax)/self.zScanStep)
#scan along focus axis
if not self.zactive:
zsteps = 0
if not self.yactive:
ysteps = 0
if not self.xactive:
xsteps = 0
for idz in range(int(zsteps)+1):
if self.zactive:
znext = self.zScanMin+idz*self.zScanStep
self.zaxis.move_to(znext, wait=True)
#along y-axis (up - down)
for idy in range(int(ysteps)+1):
if self.yactive:
ynext = self.yScanMin+idy*self.yScanStep
self.yaxis.move_to(ynext, wait=True)
#along x-axis (left - right)
for idx in range(int(xsteps)+1):
if self.xactive:
xnext = self.xScanMin+idx*self.xScanStep
self.xaxis.move_to(xnext, wait=True)
#check if thread was terminated
startt = datetime.datetime.now()
if stop_event.wait(0.005):
print('Scan finished.')
return
#bias to zero
#expose to UV
#bias on again
#take aseries of waveforms
#print("x: %.2f" %self.xaxis.position, " y: %.2f" %self.yaxis.position, " z: %.2f" %self.zaxis.position)
nsp = self.collectNWfs()
endt = datetime.datetime.now()
print('Scanpoint ', nsp, '/', self.nScanPoints, ' written to file (', round(((endt-startt).total_seconds()*1000),1), ' ms )')
print('Scan finished.')
return 1
def openTek(self):
self.tek.open()
def closeTek(self):
self.tek.reset()
self.tek.close()
def configureTek(self):
self.tek.configure()
def collectNWfs(self):
timestamp = time()
#print('1: targety: ', round(xnext,4), 'actualy: ', self.yaxis.position, 'difference=', round(xnext-self.yaxis.position,4))
(scaleddata, scaledtime) = self.tek.acquireWaveforms()
nsp = self.dh.addScanPointData(timestamp, self.xaxis.position, self.yaxis.position, self.zaxis.position, scaledtime, scaleddata)
#print('2: targety: ', round(xnext,4), 'actualy: ', self.yaxis.position, 'difference=', round(xnext-self.yaxis.position,4))
return nsp
def setXactive(self, val):
self.xactive = val
self.estimateScanSteps()
def setYactive(self, val):
self.yactive = val
self.estimateScanSteps()
def setZactive(self, val):
self.zactive = val
self.estimateScanSteps()
#setter methods
def setXmin(self, val):
self.xScanMin = val
self.config['AcquisitionControl']['xMin'] = val
self.config.write()
self.estimateScanSteps()
def setXmax(self, val):
self.xScanMax = val
self.config['AcquisitionControl']['xMax'] = val
self.config.write()
self.estimateScanSteps()
def setYmin(self, val):
self.yScanMin = val
self.config['AcquisitionControl']['yMin'] = val
self.config.write()
self.estimateScanSteps()
def setYmax(self, val):
self.yScanMax = val
self.config['AcquisitionControl']['yMax'] = val
self.config.write()
self.estimateScanSteps()
def setZmin(self, val):
self.zScanMin = val
self.config['AcquisitionControl']['zMin'] = val
self.config.write()
self.estimateScanSteps()
def setZmax(self, val):
self.zScanMax = val
self.config['AcquisitionControl']['zMax'] = val
self.config.write()
self.estimateScanSteps()
def setStepX(self, val):
self.xScanStep = val
self.config['AcquisitionControl']['xStep'] = val
self.config.write()
self.estimateScanSteps()
def setStepY(self, val):
self.yScanStep = val
self.config['AcquisitionControl']['yStep'] = val
self.config.write()
self.estimateScanSteps()
def setStepZ(self, val):
self.zScanStep = val
self.config['AcquisitionControl']['zStep'] = val
self.config.write()
self.estimateScanSteps()
def estimateScanSteps(self):
#calculate a time extimate for the scan
zpts = 1
if self.zactive and self.zScanStep != 0:
if self.zScanMax >= self.zScanMin:
zpts = abs(self.zScanMax-self.zScanMin)/abs(self.zScanStep) + 1
else:
zpts = abs(self.zScanMin-self.zScanMax)/abs(self.zScanStep) + 1
ypts = 1
if self.yactive and self.yScanStep != 0:
if self.yScanMax >= self.yScanMin:
ypts = abs(self.yScanMax-self.yScanMin)/abs(self.yScanStep) + 1
else:
ypts = abs(self.yScanMin-self.yScanMax)/abs(self.yScanStep) + 1
xpts = 1
if self.xactive and self.xScanStep != 0:
if self.xScanMax >= self.xScanMin:
xpts = abs(self.xScanMax-self.xScanMin)/abs(self.xScanStep) + 1
else:
xpts = abs(self.xScanMin-self.xScanMax)/abs(self.xScanStep) + 1
self.nScanPoints = int(zpts*ypts*xpts)
print("Scan steps: ", self.nScanPoints)