def __init__( self, program: Loop, device_properties: Mapping, channels: Tuple[Optional[ChannelID], Optional[ChannelID]], markers: Tuple[Optional[ChannelID], Optional[ChannelID]], amplitudes: Tuple[float, float], offsets: Tuple[float, float], voltage_transformations: Tuple[Optional[callable], Optional[callable]], sample_rate: TimeType, mode: TaborSequencing = None, repetition_mode: str = "infinite", ): if len(channels) != device_properties['chan_per_part']: raise TaborException( 'TaborProgram only supports {} channels'.format( device_properties['chan_per_part'])) if len(markers) != device_properties['chan_per_part']: raise TaborException( 'TaborProgram only supports {} markers'.format( device_properties['chan_per_part'])) used_channels = frozenset(set(channels).union(markers) - {None}) if program.repetition_count > 1 or program.depth() == 0: program.encapsulate() if mode is None: if program.depth() > 1: mode = TaborSequencing.ADVANCED else: mode = TaborSequencing.SINGLE super().__init__( loop=program, channels=channels, markers=markers, amplitudes=amplitudes, offsets=offsets, voltage_transformations=voltage_transformations, sample_rate=sample_rate, waveforms=[] # no sampling happens here ) self._used_channels = used_channels self._parsed_program = None # type: Optional[ParsedProgram] self._mode = None self._device_properties = device_properties self._repetition_mode = repetition_mode assert mode in (TaborSequencing.ADVANCED, TaborSequencing.SINGLE), "Invalid mode" if mode == TaborSequencing.SINGLE: self.setup_single_sequence_mode() else: self.setup_advanced_sequence_mode() self._sampled_segments = self._calc_sampled_segments()
def parse_single_seq_program(program: Loop, used_channels: FrozenSet[ChannelID]) -> ParsedProgram: assert program.depth() == 1 sequencer_table = [] waveforms = OrderedDict() volatile_parameter_positions = {} for position, (waveform, repetition_definition, volatile_repetition) in enumerate( (waveform_loop.waveform.get_subset_for_channels(used_channels), waveform_loop.repetition_definition, waveform_loop.volatile_repetition) for waveform_loop in program): if waveform in waveforms: waveform_index = waveforms[waveform] else: waveform_index = len(waveforms) waveforms[waveform] = waveform_index sequencer_table.append((TableDescription(repetition_count=int(repetition_definition), element_id=waveform_index, jump_flag=0), volatile_repetition)) if volatile_repetition is not None: volatile_parameter_positions[(0, position)] = repetition_definition return ParsedProgram( advanced_sequencer_table=[TableEntry(repetition_count=program.repetition_count, element_number=1, jump_flag=0)], sequencer_tables=[sequencer_table], waveforms=tuple(waveforms.keys()), volatile_parameter_positions=volatile_parameter_positions )
def parse_program(program: Loop, channels: Tuple[Optional[ChannelID], ...], markers: Tuple[Tuple[Optional[ChannelID], Optional[ChannelID]], ...], sample_rate: TimeType, amplitudes: Tuple[float, ...], voltage_transformations: Tuple[Callable, ...], offsets: Tuple[float, ...] = None) -> Tuple[Sequence[tek_awg.SequenceEntry], Sequence[tek_awg.Waveform]]: """Convert the program into a sequence of sequence table entries and a sequence of waveforms that can be uploaded to the device.""" assert program.depth() == 1, ("Invalid program depth: %d" % program.depth()) assert program.repetition_count == 1, ("Cannot repeat program a finite number of times (only once not %d)" % program.repetition_count) # For backward compatibility # EDIT: I think this is not needed? (Simon) if offsets is None: offsets = (0.,) * len(amplitudes) assert len(channels) == len(markers) == len(amplitudes) == len(voltage_transformations) == len(offsets) sequencing_elements = [] ch_waveforms = {} bin_waveforms = {} sample_rate_in_GHz = sample_rate / 10**9 time_array, n_samples = get_sample_times([loop.waveform for loop in program], sample_rate_in_GHz=sample_rate_in_GHz) channel_wise_kwargs = [dict(voltage_to_uint16_kwargs=dict(output_amplitude=amplitude, output_offset=offset, resolution=14), voltage_transformation=voltage_trafo) for amplitude, offset, voltage_trafo in zip(amplitudes, offsets, voltage_transformations)] # List of Tuple[positional channel tuple, set chs to sample] channel_infos = [((channel, marker_1, marker_2), {channel, marker_1, marker_2} - {None}) for channel, (marker_1, marker_2) in zip(channels, markers)] for n_sample, loop in zip(n_samples, program): entries = [] for (positional_chs, chs_to_sample), kwargs in zip(channel_infos, channel_wise_kwargs): if not chs_to_sample: entries.append(n_sample) bin_waveforms[n_sample] = None else: ch_waveform = loop.waveform.get_subset_for_channels(chs_to_sample) if ch_waveform not in ch_waveforms: bin_waveform = _make_binary_waveform(ch_waveform, time_array[:n_sample], *positional_chs, **kwargs) if bin_waveform in bin_waveforms: # use identical binary waveform already created to save memory bin_waveform = ch_waveforms[bin_waveforms[bin_waveform]] else: bin_waveforms[bin_waveform] = ch_waveform ch_waveforms[ch_waveform] = bin_waveform entries.append(ch_waveforms[ch_waveform]) sequencing_elements.append( tek_awg.SequenceEntry(entries=entries, loop_count=loop.repetition_count) ) return tuple(sequencing_elements), tuple(bin_waveforms.keys())