Skip to content

Commit f54abe1

Browse files
committed
Adjust code based on testing
1 parent 7a17683 commit f54abe1

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed

exopy_hqc_legacy/manifest.enaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,7 @@ enamldef HqcLegacyManifest(PluginManifest):
488488
task = 'run_awg:RunAWGTask'
489489
view = 'views.run_awg_views:RunAWGView'
490490
instruments = ['exopy_hqc_legacy.Legacy.AWG']
491+
Task:
492+
task = 'transfer_awg_file_task:TransferAWGFileTask'
493+
view = 'views.transfer_awg_file_task_view:TransferAWGFileView'
494+
instruments = ['exopy_hqc_legacy.Legacy.AWG']

exopy_hqc_legacy/pulses/contexts/awg_context.py

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,263 @@ def compile_and_transfer_sequence(self, sequence, driver=None):
190190

191191
return self._transfer_sequences(driver, to_send, infos)
192192

193+
def compile_loop(self, sequence, for_file=False, factor=True, **kwargs):
194+
""" Transform a sequence of pulse to a dict of waveform suitable for
195+
sequence mode of the AWG
196+
197+
Parameters
198+
----------
199+
pulses : list(Pulse)
200+
List of pulse generated by the compilation of a sequence.
201+
202+
Returns
203+
-------
204+
result : bool
205+
Boolean indicating whether or not the compilation succeeded.
206+
207+
to_send or traceback : dict
208+
Dict of {channel: array of (bytearrays,intarray,intarray)} to send
209+
to the AWG in case of success containing waveform, position(s) and
210+
repeat(s) or the traceback of the issues in case of failure.
211+
212+
213+
"""
214+
items, errors = self.preprocess_sequence(sequence)
215+
216+
if errors:
217+
return False, {}, errors
218+
219+
duration = max([pulse.stop for pulse in items])
220+
if sequence.time_constrained:
221+
# Total length of the sequence to send to the AWG
222+
duration = sequence.duration
223+
224+
# Collect the channels used in the pulses' sequence
225+
used_channels = set([pulse.channel[:3] for pulse in items])
226+
227+
# Coefficient to convert the start and stop of pulses in second and
228+
# then in index integer for array
229+
time_to_index = TIME_CONVERSION[self.time_unit]['s'] * \
230+
self.sampling_frequency
231+
232+
# Length of the sequence
233+
sequence_length = int(round(duration * time_to_index))
234+
235+
# make zero space a multiple repeat of 256 zero samples
236+
zero_length = 256
237+
azeros = np.ones(zero_length, dtype=np.uint16)*(2**13)
238+
mzeros = np.zeros(zero_length, dtype=np.int8)
239+
array_analog = {}
240+
array_M1 = {}
241+
array_M2 = {}
242+
repeats = []
243+
for channel in used_channels:
244+
array_analog[channel] = []
245+
array_M1[channel] = []
246+
array_M2[channel] = []
247+
intervals_to_pulses_a = {}
248+
intervals_to_pulses_m1 = {}
249+
intervals_to_pulses_m2 = {}
250+
for channel in used_channels:
251+
intervals_to_pulses_a[channel] = {}
252+
intervals_to_pulses_m1[channel] = {}
253+
intervals_to_pulses_m2[channel] = {}
254+
255+
if factor:
256+
# intervals are places that have pulses on at least one channel
257+
intervals = []
258+
for pulse in [i for i in items if i.duration != 0.0]:
259+
260+
waveform = pulse.waveform
261+
start_index = int(round(pulse.start*time_to_index))
262+
stop_index = start_index + len(waveform)
263+
intervals.append((start_index, stop_index))
264+
# sort and merge intervals
265+
# XXX this is mostly duplicated and should be refactored
266+
intervals.sort()
267+
i = 1
268+
while i < len(intervals):
269+
while i < len(intervals) and intervals[i][0] < intervals[i-1][1]:
270+
newlast = intervals[i][1]
271+
del intervals[i]
272+
intervals[i-1] = (intervals[i-1][0],
273+
max(newlast, intervals[i-1][1]))
274+
i += 1
275+
276+
# check that the minimum length of the each pulse and space between
277+
# them are > 256 samples fix if the condition is not satisfied
278+
self.merge_intervals(intervals, sequence_length)
279+
280+
# fill up the space between start of sequence and first sample of pulse
281+
# with zero samples
282+
if intervals[0][0] != 1:
283+
zcount = int((intervals[0][0] - 1) / zero_length) - 1
284+
zrem = zero_length + (intervals[0][0] - 1) % zero_length
285+
azrem = np.ones(zrem, dtype=np.uint16)*(2**13)
286+
mzrem = np.zeros(zrem, dtype=np.int8)
287+
if zcount > 0:
288+
repeats.append(zcount)
289+
repeats.append(1)
290+
for channel in used_channels:
291+
if zcount > 0:
292+
array_analog[channel].append(azeros)
293+
array_M1[channel].append(mzeros)
294+
array_M2[channel].append(mzeros)
295+
array_analog[channel].append(azrem)
296+
array_M1[channel].append(mzrem)
297+
array_M2[channel].append(mzrem)
298+
299+
for idx, interval in enumerate(intervals):
300+
for channel in used_channels:
301+
afill = 2**13*np.ones(interval[1] - interval[0],
302+
dtype=np.uint16)
303+
mfill1 = np.zeros(interval[1] - interval[0], dtype=np.int8)
304+
mfill2 = np.zeros(interval[1] - interval[0], dtype=np.int8)
305+
array_analog[channel].append(afill)
306+
array_M1[channel].append(mfill1)
307+
array_M2[channel].append(mfill2)
308+
intervals_to_pulses_a[channel][interval] = afill
309+
intervals_to_pulses_m1[channel][interval] = mfill1
310+
intervals_to_pulses_m2[channel][interval] = mfill2
311+
312+
remaining = 0
313+
if idx + 1 == len(intervals):
314+
remaining = sequence_length - interval[1] + 1
315+
else:
316+
remaining = intervals[idx+1][0] - intervals[idx][1]
317+
zcount = int(remaining / zero_length) - 1
318+
zrem = zero_length + remaining % zero_length
319+
azrem = np.ones(zrem, dtype=np.uint16)*(2**13)
320+
mzrem = np.zeros(zrem, dtype=np.int8)
321+
repeats.append(1)
322+
if zcount > 0:
323+
repeats.append(zcount)
324+
repeats.append(1)
325+
326+
if remaining != 0:
327+
for channel in used_channels:
328+
if zcount > 0:
329+
array_analog[channel].append(azeros)
330+
array_M1[channel].append(mzeros)
331+
array_M2[channel].append(mzeros)
332+
array_analog[channel].append(azrem)
333+
array_M1[channel].append(mzrem)
334+
array_M2[channel].append(mzrem)
335+
else:
336+
start_index = 0
337+
stop_index = sequence_length
338+
intervals = [(start_index, stop_index)]
339+
for channel in used_channels:
340+
a_fill = np.ones(sequence_length, dtype=np.uint16)*(2**13)
341+
m1_fill = np.zeros(sequence_length, dtype=np.int8)
342+
m2_fill = np.zeros(sequence_length, dtype=np.int8)
343+
array_analog[channel].append(a_fill)
344+
array_M1[channel].append(m1_fill)
345+
array_M2[channel].append(m2_fill)
346+
intervals_to_pulses_a[channel][intervals[0]]=a_fill
347+
intervals_to_pulses_m1[channel][intervals[0]]=m1_fill
348+
intervals_to_pulses_m2[channel][intervals[0]]=m2_fill
349+
repeats = [1]
350+
351+
for pulse in [i for i in items if i.duration != 0.0]:
352+
waveform = pulse.waveform
353+
channel = pulse.channel[:3]
354+
channeltype = pulse.channel[4:]
355+
356+
start_index = int(round(pulse.start*time_to_index))
357+
stop_index = start_index + len(waveform)
358+
359+
interval_i = 0
360+
while intervals[interval_i][1] < start_index:
361+
interval_i += 1
362+
interval = intervals[interval_i]
363+
364+
wav_slice = slice(start_index - interval[0],
365+
stop_index - interval[0])
366+
if channeltype == 'A' and pulse.kind == 'Analogical':
367+
intervals_to_pulses_a[channel][interval][wav_slice] +=\
368+
(np.rint(8191*waveform)).astype(np.uint16)
369+
elif channeltype == 'M1' and pulse.kind == 'Logical':
370+
intervals_to_pulses_m1[channel][interval][wav_slice] +=\
371+
waveform
372+
elif channeltype == 'M2' and pulse.kind == 'Logical':
373+
intervals_to_pulses_m2[channel][interval][wav_slice] +=\
374+
waveform
375+
else:
376+
msg = 'Selected channel does not match kind for pulse {} ({}).'
377+
return (False, None, None, dict(),
378+
{'Kind issue': msg.format(pulse.index,
379+
(pulse.kind, pulse.channel))}
380+
)
381+
382+
# Check the overflows
383+
traceback = {}
384+
for channel in used_channels:
385+
for i in range(len(array_analog[channel])):
386+
analog = array_analog[channel][i]
387+
m1 = array_M1[channel][i]
388+
m2 = array_M2[channel][i]
389+
if analog.max() > 16383 or analog.min() < 0:
390+
mes = 'Analogical values out of range.'
391+
traceback['{}_A'.format(channel)] = mes
392+
393+
elif m1.max() > 1 or m1.min() < 0:
394+
mes = 'Overflow in marker 1.'
395+
traceback['{}_M1'.format(channel)] = mes
396+
397+
elif m2.max() > 1 or m2.min() < 0:
398+
mes = 'Overflow in marker 2.'
399+
traceback['{}_M2'.format(channel)] = mes
400+
401+
if traceback:
402+
return False, None, None, dict(), traceback
403+
404+
# Invert marked logical channels.
405+
for i_ch in self.inverted_log_channels:
406+
ch, m = i_ch.split('_')
407+
if m == 'M1':
408+
for waveform in array_M1[ch]:
409+
np.logical_not(waveform, waveform)
410+
else:
411+
for waveform in array_M2[ch]:
412+
np.logical_not(waveform, waveform)
413+
414+
# Byte arrays to send to the AWG
415+
wfs = {}
416+
already_added = {}
417+
for channel in used_channels:
418+
wfs[int(channel[-1])] = []
419+
for i in range(len(array_analog[channel])):
420+
addr = id(array_analog[channel][i])
421+
if addr in already_added:
422+
added = already_added[addr]
423+
wfs[int(channel[-1])].append(added)
424+
425+
else:
426+
waveform_new = (array_analog[channel][i] +
427+
array_M1[channel][i]*(2**14) +
428+
array_M2[channel][i]*(2**15))
429+
aux = np.empty(2*len(waveform_new), dtype=np.uint8)
430+
if for_file:
431+
wfadded = waveform_new
432+
else:
433+
aux[::2] = waveform_new % 2**8
434+
aux[1::2] = waveform_new // 2**8
435+
wfadded = bytearray(aux)
436+
wfs[int(channel[-1])].append(wfadded)
437+
already_added[addr] = wfadded
438+
439+
# Build sequence infos
440+
name = self._cache['sequence_name']
441+
infos = dict(sampling_frequency=self.sampling_frequency,
442+
sequence_ch1='',
443+
sequence_ch2='',
444+
sequence_ch3='',
445+
sequence_ch4='')
446+
for c in used_channels:
447+
infos['sequence_ch%s' % c[2]] = name + '_' + c
448+
return True, wfs, repeats, infos, traceback
449+
193450
def list_sequence_infos(self):
194451
"""List the sequence infos returned after a successful completion.
195452

0 commit comments

Comments
 (0)