def _calc_sampled_segments(self) -> Tuple[Sequence[TaborSegment], Sequence[int]]: """ Returns: (segments, segment_lengths) """ time_array, segment_lengths = get_sample_times(self._parsed_program.waveforms, self._sample_rate) if np.any(segment_lengths % 16 > 0) or np.any(segment_lengths < 192): raise TaborException('At least one waveform has a length that is smaller 192 or not a multiple of 16') segments = [] for i, waveform in enumerate(self._parsed_program.waveforms): t = time_array[:segment_lengths[i]] marker_time = t[::2] segment_a = self._channel_data(waveform, t, 0) segment_b = self._channel_data(waveform, t, 1) assert (len(segment_a) == len(t)) assert (len(segment_b) == len(t)) marker_a = self._marker_data(waveform, marker_time, 0) marker_b = self._marker_data(waveform, marker_time, 1) segment = TaborSegment.from_sampled(ch_a=segment_a, ch_b=segment_b, marker_a=marker_a, marker_b=marker_b) segments.append(segment) return segments, segment_lengths
def _sample_waveforms(self, waveforms: Sequence[Waveform]) -> List[Tuple[Tuple[numpy.ndarray, ...], Tuple[numpy.ndarray, ...]]]: sampled_waveforms = [] time_array, segment_lengths = get_sample_times(waveforms, self._sample_rate) for waveform, segment_length in zip(waveforms, segment_lengths): wf_time = time_array[:segment_length] sampled_channels = [] for channel, trafo, amplitude, offset in zip(self._channels, self._voltage_transformations, self._amplitudes, self._offsets): if channel is None: sampled_channels.append(self._sample_empty_channel(wf_time)) else: sampled = waveform.get_sampled(channel, wf_time) if trafo is not None: sampled = trafo(sampled) sampled = sampled - offset sampled /= amplitude sampled_channels.append(waveform.get_sampled(channel, wf_time)) sampled_markers = [] for marker in self._markers: if marker is None: sampled_markers.append(self._sample_empty_marker(wf_time)) else: sampled_markers.append(waveform.get_sampled(marker, wf_time) != 0) sampled_waveforms.append((tuple(sampled_channels), tuple(sampled_markers))) return sampled_waveforms
def test_get_sample_times_single_wf(self): sample_rate = TimeType(12, 10) wf = DummyWaveform(duration=TimeType(40, 12)) expected_times = np.arange(4) / 1.2 times, n_samples = get_sample_times(wf, sample_rate_in_GHz=sample_rate) np.testing.assert_equal(times, expected_times) np.testing.assert_equal(n_samples, np.asarray(4))
def __init__(self, loop: Loop, channels: Tuple[Optional[ChannelID], ...], markers: Tuple[Optional[ChannelID], ...], amplitudes: Tuple[float, ...], offsets: Tuple[float, ...], voltage_transformations: Tuple[Optional[Callable], ...], sample_rate: TimeType): assert len(channels) == len(amplitudes) == len(offsets) == len(voltage_transformations) self._channels = tuple(channels) self._markers = tuple(markers) self._amplitudes = tuple(amplitudes) self._offsets = tuple(offsets) self._voltage_transformations = tuple(voltage_transformations) self._sample_rate = sample_rate self._loop = loop self._waveforms = {node.waveform: None for node in loop.get_depth_first_iterator() if node.is_leaf()} time_array, segment_lengths = get_sample_times(self._waveforms.keys(), sample_rate) for waveform, segment_length in zip(self._waveforms.keys(), segment_lengths): wf_time = time_array[:segment_length] sampled_channels = [] for channel, trafo, amplitude, offset in zip(channels, voltage_transformations, amplitudes, offsets): if channel is None: sampled_channels.append(None) else: sampled = waveform.get_sampled(channel, wf_time) if trafo: sampled = trafo(sampled) sampled = sampled - offset sampled /= amplitude sampled_channels.append(waveform.get_sampled(channel, wf_time)) sampled_markers = [] for marker in markers: if marker is None: sampled_markers.append(None) else: sampled_markers.append(waveform.get_sampled(marker, wf_time) != 0) self._waveforms[waveform] = (tuple(sampled_channels), tuple(sampled_markers))
def test_get_sample_times(self): sample_rate = TimeType.from_fraction(12, 10) wf1 = DummyWaveform(duration=TimeType.from_fraction(20, 12)) wf2 = DummyWaveform(duration=TimeType.from_fraction(400000000001, 120000000000)) wf3 = DummyWaveform(duration=TimeType.from_fraction(1, 10**15)) expected_times = np.arange(4) / 1.2 times, n_samples = get_sample_times([wf1, wf2], sample_rate_in_GHz=sample_rate) np.testing.assert_equal(expected_times, times) np.testing.assert_equal(n_samples, np.asarray([2, 4])) with self.assertRaises(AssertionError): get_sample_times([], sample_rate_in_GHz=sample_rate) with self.assertRaisesRegex(ValueError, "non integer length"): get_sample_times([wf1, wf2], sample_rate_in_GHz=sample_rate, tolerance=0.) with self.assertRaisesRegex(ValueError, "length <= zero"): get_sample_times([wf1, wf3], sample_rate_in_GHz=sample_rate)
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())