1 """Simulation protocol waveforms, same as QuB/PythonScripts/AcquisitionProtocol.
2
3 Copyright 2008-2014 Research Foundation State University of New York
4 This file is part of QUB Express.
5
6 QUB Express is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 QUB Express is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License,
17 named LICENSE.txt, in the QUB Express program directory. If not, see
18 <http://www.gnu.org/licenses/>.
19
20 """
21
22 import traceback
23 from numpy import *
24 import qubx.pyenv
25 import qubx.tree
26 import qubx.data_types
27
28
29
30
31
32
33
34
35
36
37
38 Shapes = []
41
42
58
59
60
62 if rep_index >= base_data.count:
63 rep_extra = rep_index - base_data.count + 1
64 return (base_data[base_data.count-1] + incr * rep_extra) * pow(factor, rep_extra)
65 else:
66 return base_data[rep_index]
67
68
69
71 name = '(missing)'
72
73 - def __init__(self, properties=None, defaults=[('Duration', 1.0)]):
74 if not properties:
75 properties = qubx.tree.Node('Shape')
76 if properties.name != 'Shape':
77 properties.name = 'Shape'
78 if str(properties.data) != self.name:
79 properties.data = self.name
80 for prop in defaults:
81 if properties.find(prop[0]).isNull:
82 properties[prop[0]].data = prop[1]
83 self.properties = properties
84
85 self.setup()
86
88 if properties:
89 for oldName in renames.keys():
90 properties.find(oldName).name = renames[oldName]
91
92
93 - def get(self, prop):
94 rtn = '0.0'
95 try:
96 rtn = str(self.properties[prop].data)
97 except:
98 pass
99 return rtn
100
101 - def set(self, prop, valstr):
115
117
118 pass
119
121 return self.properties['Duration'].data[0] or 1.0
122
123 - def count(self, t_start, sampling, rep_index):
125
128
129 - def generate(self, first, last, t_start, sampling, rep_index):
130 count = SampleCount(t_start, sampling, self.duration(rep_index))
131 first = min(first, count-1)
132 last = min(last, count-1)
133 if last < 0:
134 last = first - 1
135 remain = last - first + 1
136
137 node = qubx.tree.Node()
138 node.data.setup(qubx.tree.QTR_TYPE_DOUBLE, count, 1)
139
140 self.generateInto(first, last, t_start, sampling, rep_index, node, 0)
141 return node
142
143 - def generateInto(self, first, last, t_start, sampling, rep_index, node, i_start):
155
156
158 name = 'Custom'
159
161 self.renameProperties(properties, {'f(x)' : 'f(x,i)'})
162 defaults = [('f(x,i)', 'x * x'),
163 ('x from', 0.0),
164 ('x to', 1.0),
165 ('Duration', 1.0)]
166 Shape.__init__(self, properties, defaults)
167
169 try:
170 self.xfrom = self.properties['x from'].data[0]
171 self.xto = self.properties['x to'].data[0]
172 self.dur = self.properties['Duration'].data[0]
173 self.xfact = (self.xto - self.xfrom) / self.dur
174 self.xfunc = eval('lambda x, i: ' + str(self.properties['f(x,i)'].data), qubx.pyenv.env.globals)
175 self.tfunc = lambda t, i: self.xfunc( t * self.xfact + self.xfrom, i )
176 except:
177 traceback.print_exc()
178 self.tfunc = lambda t, i: 0
179
181 return self.dur or 1.0
182
184 return self.tfunc(t, rep_index)
185
186
188 name = 'Step'
189
191 self.currRep = 0
192
193 self.renameProperties(properties, {'predur' : 'preDuration',
194 'prelvl' : 'preAmp',
195 'dur' : 'Duration',
196 'lvl' : 'Amp',
197 'delta_lvl' : 'Amp incr',
198 'deltaAmp' : 'Amp incr',
199 'postdur' : 'postDuration',
200 'postlvl' : 'postAmp'})
201 defaults = [('Duration', 0.5),
202 ('Duration incr', 0.0),
203 ('Duration factor', 1.0),
204 ('Amp', 1.0),
205 ('Amp incr', 0.0),
206 ('Amp factor', 1.0),
207 ('preDuration', 0.25),
208 ('preDuration incr', 0.0),
209 ('preDuration factor', 1.0),
210 ('preAmp', 0.0),
211 ('preAmp incr', 0.0),
212 ('preAmp factor', 1.0),
213 ('postDuration', 0.25),
214 ('postDuration incr', 0.0),
215 ('postDuration factor', 1.0),
216 ('postAmp', 0.0),
217 ('postAmp incr', 0.0),
218 ('postAmp factor', 1.0)]
219
220 Shape.__init__(self, properties, defaults)
221
223
224 preDur = IncrAndScale( self.properties['preDuration'].data,
225 self.properties['preDuration incr'].data[0],
226 self.properties['preDuration factor'].data[0],
227 self.currRep )
228 preAmp = IncrAndScale( self.properties['preAmp'].data,
229 self.properties['preAmp incr'].data[0],
230 self.properties['preAmp factor'].data[0],
231 self.currRep )
232 pre2Dur = preDur + IncrAndScale( self.properties['Duration'].data,
233 self.properties['Duration incr'].data[0],
234 self.properties['Duration factor'].data[0],
235 self.currRep )
236 amp = IncrAndScale( self.properties['Amp'].data,
237 self.properties['Amp incr'].data[0],
238 self.properties['Amp factor'].data[0],
239 self.currRep )
240 postAmp = IncrAndScale( self.properties['postAmp'].data,
241 self.properties['postAmp incr'].data[0],
242 self.properties['postAmp factor'].data[0],
243 self.currRep )
244
245 def tfunc(t):
246 if t < preDur:
247 return preAmp
248 elif t < pre2Dur:
249 return amp
250 else:
251 return postAmp
252 self.tfunc = tfunc
253
255 return ( IncrAndScale( self.properties['preDuration'].data,
256 self.properties['preDuration incr'].data[0],
257 self.properties['preDuration factor'].data[0],
258 rep_index )
259 + IncrAndScale( self.properties['Duration'].data,
260 self.properties['Duration incr'].data[0],
261 self.properties['Duration factor'].data[0],
262 rep_index )
263 + IncrAndScale( self.properties['postDuration'].data,
264 self.properties['postDuration incr'].data[0],
265 self.properties['postDuration factor'].data[0],
266 rep_index ) ) or 1.0
267
269 if rep_index != self.currRep:
270 self.currRep = rep_index
271 self.setup()
272 return self.tfunc(t)
273
274 - def generateInto(self, first, last, t_start, sampling, rep_index, node, i_start):
275 count = SampleCount(t_start, sampling, self.duration(rep_index))
276 first = min(first, count-1)
277 last = min(last, count-1)
278 if last < 0:
279 last = first - 1
280 remain = last - first + 1
281 t_off = t_start % sampling
282
283 preDur = IncrAndScale( self.properties['preDuration'].data,
284 self.properties['preDuration incr'].data[0],
285 self.properties['preDuration factor'].data[0],
286 rep_index )
287 preAmp = IncrAndScale( self.properties['preAmp'].data,
288 self.properties['preAmp incr'].data[0],
289 self.properties['preAmp factor'].data[0],
290 rep_index )
291 pre2Dur = preDur + IncrAndScale( self.properties['Duration'].data,
292 self.properties['Duration incr'].data[0],
293 self.properties['Duration factor'].data[0],
294 rep_index )
295 amp = IncrAndScale( self.properties['Amp'].data,
296 self.properties['Amp incr'].data[0],
297 self.properties['Amp factor'].data[0],
298 rep_index )
299 postAmp = IncrAndScale( self.properties['postAmp'].data,
300 self.properties['postAmp incr'].data[0],
301 self.properties['postAmp factor'].data[0],
302 rep_index )
303
304 preDur_i = int(ceil((preDur - t_off)/sampling)) - first
305 pre2Dur_i = int(ceil((pre2Dur - t_off)/sampling)) - first
306 if preDur_i > 0:
307 node.storage.data[i_start:i_start+preDur_i,0] = preAmp
308 if pre2Dur_i > preDur_i:
309 node.storage.data[i_start+max(0,preDur_i):i_start+pre2Dur_i,0] = amp
310 if pre2Dur_i < remain:
311 node.storage.data[i_start+max(0,pre2Dur_i):i_start+remain,0] = postAmp
312
313
314
316 name = 'Sine'
317
319 self.currRep = 0
320
321 self.renameProperties(properties, {'dur' : 'Duration',
322 'ampl' : 'Amp',
323 'delta_ampl' : 'Amp incr',
324 'deltaAmp' : 'Amp incr',
325 'freq' : 'Freq',
326 'delta_freq' : 'Freq incr',
327 'deltaFreq' : 'Freq incr',
328 't_offset' : 'Phase',
329 'delta_t_offset' : 'Phase incr',
330 'deltaPhase' : 'Phase incr'})
331 defaults = [('Duration', 1.0),
332 ('Duration incr', 0.0),
333 ('Duration factor', 1.0),
334 ('Amp', 1.0),
335 ('Amp incr', 0.0),
336 ('Amp factor', 1.0),
337 ('Freq', 60.0),
338 ('Freq incr', 0.0),
339 ('Freq factor', 1.0),
340 ('Phase', 0.0),
341 ('Phase incr', 0.0),
342 ('Phase factor', 1.0),
343 ('Offset', 0.0),
344 ('Offset incr', 0.0),
345 ('Offset factor', 1.0)]
346
347 Shape.__init__(self, properties, defaults)
348
350
351 dur = IncrAndScale( self.properties['Duration'].data,
352 self.properties['Duration incr'].data[0],
353 self.properties['Duration factor'].data[0],
354 self.currRep )
355 amp = IncrAndScale( self.properties['Amp'].data,
356 self.properties['Amp incr'].data[0],
357 self.properties['Amp factor'].data[0],
358 self.currRep )
359 freq2pi = 2 * pi * IncrAndScale( self.properties['Freq'].data,
360 self.properties['Freq incr'].data[0],
361 self.properties['Freq factor'].data[0],
362 self.currRep )
363 phase = IncrAndScale( self.properties['Phase'].data,
364 self.properties['Phase incr'].data[0],
365 self.properties['Phase factor'].data[0],
366 self.currRep )
367 off = IncrAndScale( self.properties['Offset'].data,
368 self.properties['Offset incr'].data[0],
369 self.properties['Offset factor'].data[0],
370 self.currRep )
371 pi2 = 2 * pi
372 self.tfunc = lambda t: off + amp * sin(t * freq2pi + phase)
373
375 return IncrAndScale( self.properties['Duration'].data,
376 self.properties['Duration incr'].data[0],
377 self.properties['Duration factor'].data[0],
378 rep_index ) or 1.0
379
381 if rep_index != self.currRep:
382 self.currRep = rep_index
383 self.setup()
384 return self.tfunc(t)
385
386 - def generateInto(self, first, last, t_start, sampling, rep_index, node, i_start):
387 count = SampleCount(t_start, sampling, self.duration(rep_index))
388 first = min(first, count-1)
389 last = min(last, count-1)
390 if last < 0:
391 last = first - 1
392 remain = last - first + 1
393 t_off = t_start % sampling
394
395 amp = IncrAndScale( self.properties['Amp'].data,
396 self.properties['Amp incr'].data[0],
397 self.properties['Amp factor'].data[0],
398 rep_index )
399 freq = IncrAndScale( self.properties['Freq'].data,
400 self.properties['Freq incr'].data[0],
401 self.properties['Freq factor'].data[0],
402 rep_index )
403 phase = IncrAndScale( self.properties['Phase'].data,
404 self.properties['Phase incr'].data[0],
405 self.properties['Phase factor'].data[0],
406 rep_index )
407 off = IncrAndScale( self.properties['Offset'].data,
408 self.properties['Offset incr'].data[0],
409 self.properties['Offset factor'].data[0],
410 rep_index )
411 T = t_off + sampling * (first + arange(remain, dtype='float64'))
412 node.storage.data[i_start:i_start+remain,0] = off + amp * sin(T * freq*2*pi + phase)
413
414
415
417 name = 'Ramp'
418
420 self.currRep = 0
421
422 self.renameProperties(properties, {'dur' : 'Duration',
423 'from_lvl' : 'FromAmp',
424 'to_lvl' : 'ToAmp',
425 'delta_to' : 'ToAmp incr',
426 'deltaToAmp' : 'ToAmp incr'})
427 defaults = [('Duration', 1.0),
428 ('Duration incr', 0.0),
429 ('Duration factor', 1.0),
430 ('FromAmp', 0.0),
431 ('FromAmp incr', 0.0),
432 ('FromAmp factor', 1.0),
433 ('ToAmp', 1.0),
434 ('ToAmp incr', 0.0),
435 ('ToAmp factor', 1.0)]
436
437 Shape.__init__(self, properties, defaults)
438
440
441 dur = IncrAndScale( self.properties['Duration'].data,
442 self.properties['Duration incr'].data[0],
443 self.properties['Duration factor'].data[0],
444 self.currRep )
445 frm = IncrAndScale( self.properties['FromAmp'].data,
446 self.properties['FromAmp incr'].data[0],
447 self.properties['FromAmp factor'].data[0],
448 self.currRep )
449 to = IncrAndScale( self.properties['ToAmp'].data,
450 self.properties['ToAmp incr'].data[0],
451 self.properties['ToAmp factor'].data[0],
452 self.currRep )
453 slope = (to - frm) / dur
454 self.tfunc = lambda t: frm + t * slope
455
457 return IncrAndScale( self.properties['Duration'].data,
458 self.properties['Duration incr'].data[0],
459 self.properties['Duration factor'].data[0],
460 rep_index ) or 1.0
461
463 if rep_index != self.currRep:
464 self.currRep = rep_index
465 self.setup()
466 return self.tfunc(t)
467
468 - def generateInto(self, first, last, t_start, sampling, rep_index, node, i_start):
469 count = SampleCount(t_start, sampling, self.duration(rep_index))
470 first = min(first, count-1)
471 last = min(last, count-1)
472 if last < 0:
473 last = first - 1
474 remain = last - first + 1
475 t_off = t_start % sampling
476
477 fromAmp = IncrAndScale( self.properties['FromAmp'].data,
478 self.properties['FromAmp incr'].data[0],
479 self.properties['FromAmp factor'].data[0],
480 rep_index )
481 toAmp = IncrAndScale( self.properties['ToAmp'].data,
482 self.properties['ToAmp incr'].data[0],
483 self.properties['ToAmp factor'].data[0],
484 rep_index )
485 dur = IncrAndScale( self.properties['Duration'].data,
486 self.properties['Duration incr'].data[0],
487 self.properties['Duration factor'].data[0],
488 rep_index )
489 slope = (toAmp - fromAmp) / dur
490
491 T = t_off + sampling * (first + arange(remain,dtype='float64'))
492 node.storage.data[i_start:i_start+remain,0] = fromAmp + slope * T
493
494
495
497 name = 'Hold'
498
500 self.currRep = 0
501
502 self.renameProperties(properties, {'dur' : 'Duration',
503 'lvl' : 'Amp',
504 'deltalvl' : 'Amp incr',
505 'deltaAmp' : 'Amp incr'})
506 defaults = [('Duration', 1.0),
507 ('Duration incr', 0.0),
508 ('Duration factor', 1.0),
509 ('Amp', 0.0),
510 ('Amp incr', 0.0),
511 ('Amp factor', 1.0)]
512
513 Shape.__init__(self, properties, defaults)
514
516
517 amp = IncrAndScale( self.properties['Amp'].data,
518 self.properties['Amp incr'].data[0],
519 self.properties['Amp factor'].data[0],
520 self.currRep )
521 self.tfunc = lambda t: amp
522
524 return IncrAndScale( self.properties['Duration'].data,
525 self.properties['Duration incr'].data[0],
526 self.properties['Duration factor'].data[0],
527 rep_index ) or 1.0
528
530 if rep_index != self.currRep:
531 self.currRep = rep_index
532 self.setup()
533 return self.tfunc(t)
534
535 - def generateInto(self, first, last, t_start, sampling, rep_index, node, i_start):
549
550
551
553 name = 'Bits'
554
556 self.currRep = 0
557
558 defaults = [('Duration', 1.0),
559 ('Duration incr', 0.0),
560 ('Duration factor', 1.0),
561 ('Amp', 1.0),
562 ('Amp incr', 0.0),
563 ('Amp factor', 1.0)]
564
565 Shape.__init__(self, properties, defaults)
566
568
569 amp = IncrAndScale( self.properties['Amp'].data,
570 self.properties['Amp incr'].data[0],
571 self.properties['Amp factor'].data[0],
572 self.currRep )
573 self.tfunc = lambda t: amp
574
576 return IncrAndScale( self.properties['Duration'].data,
577 self.properties['Duration incr'].data[0],
578 self.properties['Duration factor'].data[0],
579 rep_index ) or 1.0
580
582 if rep_index != self.currRep:
583 self.currRep = rep_index
584 self.setup()
585 return self.tfunc(t)
586
587 - def generateInto(self, first, last, t_start, sampling, rep_index, node, i_start):
601
602
603 AddShape( CustomShape )
604 AddShape( Step )
605 AddShape( Sine )
606 AddShape( Ramp )
607 AddShape( Hold )
608
609
610
611
612
614 name = 'File'
615
617 self.currRep = 0
618
619 defaults = [('Path', ' '),
620 ('Signal', 0),
621 ('Segment', 0),
622 ('Segment incr', 1)]
623
624 self.__file = None
625 self.__path = ' '
626
627 Shape.__init__(self, properties, defaults)
628
630
631 path = str(self.properties['Path'].data)
632 if self.__path != path:
633 if path:
634 try:
635 self.__file = qubx.data_types.Open(path)
636 self.__path = path
637 except:
638 traceback.print_exc()
639 else:
640 self.__path = ' '
641 self.__file = None
642
656
672
673 - def generateInto(self, first, last, t_start, sampling, rep_index, node, i_start):
687
688 AddShape(File)
689