示例#1
0
    def __init__(self,
                 program: Loop,
                 channels: Sequence[ChannelID],
                 markers: Sequence[Tuple[ChannelID, ChannelID]],
                 sample_rate: TimeType,
                 amplitudes: Sequence[float],
                 voltage_transformations: Sequence[Callable],
                 offsets: Sequence[float] = None):
        assert len(channels) == len(markers) and all(len(marker) == 2 for marker in markers),\
            "Driver can currently only handle awgs wth two markers per channel"

        assert len(channels) == len(amplitudes)

        self._program = program.copy_tree_structure()
        self._sample_rate = sample_rate
        self._amplitudes = tuple(amplitudes)
        self._offsets = tuple(offsets) if offsets is not None else None
        self._channels = tuple(channels)
        self._markers = tuple(markers)
        self._voltage_transformations = tuple(voltage_transformations)

        self._sequencing_elements = None
        self._waveforms = None

        make_compatible(self._program, 250, 1, sample_rate / 10**9)
        self._program.flatten_and_balance(1)

        self._sequencing_elements, self._waveforms = parse_program(program=self._program,
                                                                   channels=self.channels,
                                                                   markers=self.markers,
                                                                   sample_rate=self._sample_rate,
                                                                   amplitudes=self._amplitudes,
                                                                   voltage_transformations=self._voltage_transformations,
                                                                   offsets=self._offsets)
示例#2
0
    def test_make_compatible(self):
        program = Loop()
        pub_kwargs = dict(minimal_waveform_length=5,
                          waveform_quantum=10,
                          sample_rate=time_from_float(1.))
        priv_kwargs = dict(min_len=5,
                           quantum=10,
                           sample_rate=time_from_float(1.))

        with mock.patch(
                'qupulse._program._loop._is_compatible',
                return_value=_CompatibilityLevel.incompatible) as mocked:
            with self.assertRaisesRegex(ValueError,
                                        'cannot be made compatible'):
                make_compatible(program, **pub_kwargs)
            mocked.assert_called_once_with(program, **priv_kwargs)

        with mock.patch(
                'qupulse._program._loop._is_compatible',
                return_value=_CompatibilityLevel.action_required) as is_compat:
            with mock.patch(
                    'qupulse._program._loop._make_compatible') as make_compat:
                make_compatible(program, **pub_kwargs)

                is_compat.assert_called_once_with(program, **priv_kwargs)
                make_compat.assert_called_once_with(program, **priv_kwargs)
    def test_regression_duration_conversion(self):
        old_value = qupulse._program.waveforms.PULSE_TO_WAVEFORM_ERROR

        try:
            qupulse._program.waveforms.PULSE_TO_WAVEFORM_ERROR = 1e-6
            for duration_in_samples in [64, 936320, 24615392]:
                p = ConstantPulseTemplate(duration_in_samples / 2.4, {'a': 0})
                number_of_samples = p.create_program().duration * 2.4
                make_compatible(p.create_program(), 8, 8, 2.4)
                self.assertEqual(number_of_samples.denominator, 1)

                p2 = ConstantPulseTemplate((duration_in_samples + 1) / 2.4, {'a': 0})
                self.assertNotEqual(p.create_program().duration, p2.create_program().duration)
        finally:
            qupulse._program.waveforms.PULSE_TO_WAVEFORM_ERROR = old_value
示例#4
0
    def test_make_compatible_repetition_count(self):
        wf1 = DummyWaveform(duration=1.5)
        wf2 = DummyWaveform(duration=2.0)

        program = Loop(children=[
            Loop(waveform=wf1, repetition_count=2),
            Loop(waveform=wf2)
        ])
        duration = program.duration
        _make_compatible(program,
                         min_len=1,
                         quantum=1,
                         sample_rate=time_from_float(1.))
        self.assertEqual(program.duration, duration)

        wf2 = DummyWaveform(duration=2.5)
        program = Loop(children=[
            Loop(waveform=wf1, repetition_count=3),
            Loop(waveform=wf2)
        ])
        duration = program.duration
        with self.assertWarns(MakeCompatibleWarning):
            make_compatible(program,
                            minimal_waveform_length=1,
                            waveform_quantum=1,
                            sample_rate=time_from_float(1.))
        self.assertEqual(program.duration, duration)

        program = Loop(children=[
            Loop(waveform=wf1, repetition_count=3),
            Loop(waveform=wf2)
        ],
                       repetition_count=3)
        duration = program.duration
        _make_compatible(program,
                         min_len=1,
                         quantum=3,
                         sample_rate=time_from_float(1.))
        self.assertEqual(program.duration, duration)
示例#5
0
    def upload(self, name: str,
               program: Loop,
               channels: Tuple[Optional[ChannelID], ...],
               markers: Tuple[Optional[ChannelID], ...],
               voltage_transformation: Tuple[Callable, ...],
               force: bool = False) -> None:
        """Upload a program to the AWG.

        Physically uploads all waveforms required by the program - excluding those already present -
        to the device and sets up playback sequences accordingly.
        This method should be cheap for program already on the device and can therefore be used
        for syncing. Programs that are uploaded should be fast(~1 sec) to arm.

        Args:
            name: A name for the program on the AWG.
            program: The program (a sequence of instructions) to upload.
            channels: Tuple of length num_channels that ChannelIDs of  in the program to use. Position in the list
            corresponds to the AWG channel
            markers: List of channels in the program to use. Position in the List in the list corresponds to
            the AWG channel
            voltage_transformation: transformations applied to the waveforms extracted rom the program. Position
            in the list corresponds to the AWG channel
            force: If a different sequence is already present with the same name, it is
                overwritten if force is set to True. (default = False)

        Known programs are handled in host memory most of the time. Only when uploading the
        device memory is touched at all.

        Returning from setting user register in seqc can take from 50ms to 60 ms. Fluctuates heavily. Not a good way to
        have deterministic behaviour "setUserReg(PROG_SEL, PROG_IDLE);".
        """
        if len(channels) != self.num_channels:
            raise HDAWGValueError('Channel ID not specified')
        if len(markers) != self.num_markers:
            raise HDAWGValueError('Markers not specified')
        if len(voltage_transformation) != self.num_channels:
            raise HDAWGValueError('Wrong number of voltage transformations')

        if name in self.programs and not force:
            raise HDAWGValueError('{} is already known on {}'.format(name, self.identifier))

        # Go to qupulse nanoseconds time base.
        q_sample_rate = self.sample_rate / 10**9

        # Adjust program to fit criteria.
        make_compatible(program,
                        minimal_waveform_length=self.MIN_WAVEFORM_LEN,
                        waveform_quantum=self.WAVEFORM_LEN_QUANTUM,
                        sample_rate=q_sample_rate)

        if self._amplitude_offset_handling == AWGAmplitudeOffsetHandling.IGNORE_OFFSET:
            voltage_offsets = (0.,) * self.num_channels
        elif self._amplitude_offset_handling == AWGAmplitudeOffsetHandling.CONSIDER_OFFSET:
            voltage_offsets = self.offsets()
        else:
            raise ValueError('{} is invalid as AWGAmplitudeOffsetHandling'.format(self._amplitude_offset_handling))

        amplitudes = self.amplitudes()

        if name in self._program_manager.programs:
            self._program_manager.remove(name)

        self._program_manager.add_program(name,
                                          program,
                                          channels=channels,
                                          markers=markers,
                                          voltage_transformations=voltage_transformation,
                                          sample_rate=q_sample_rate,
                                          amplitudes=amplitudes,
                                          offsets=voltage_offsets)

        self._required_seqc_source = self._program_manager.to_seqc_program()
        self._program_manager.waveform_memory.sync_to_file_system(self.device.waveform_file_system)

        # start compiling the source (non-blocking)
        self._start_compile_and_upload()
示例#6
0
文件: tabor.py 项目: qutech/qupulse
    def upload(self, name: str,
               program: Loop,
               channels: Tuple[Optional[ChannelID], Optional[ChannelID]],
               markers: Tuple[Optional[ChannelID], Optional[ChannelID]],
               voltage_transformation: Tuple[Callable, Callable],
               force: bool = False) -> None:
        """Upload a program to the AWG.

        The policy is to prefer amending the unknown waveforms to overwriting old ones."""

        if len(channels) != self.num_channels:
            raise ValueError('Channel ID not specified')
        if len(markers) != self.num_markers:
            raise ValueError('Markers not specified')
        if len(voltage_transformation) != self.num_channels:
            raise ValueError('Wrong number of voltage transformations')

        # adjust program to fit criteria
        sample_rate = self.device.sample_rate(self._channels[0])
        make_compatible(program,
                        minimal_waveform_length=192,
                        waveform_quantum=16,
                        sample_rate=fractions.Fraction(sample_rate, 10**9))

        if name in self._known_programs:
            if force:
                self.free_program(name)
            else:
                raise ValueError('{} is already known on {}'.format(name, self.identifier))

        # They call the peak to peak range amplitude
        ranges = (self.device.amplitude(self._channels[0]),
                  self.device.amplitude(self._channels[1]))

        voltage_amplitudes = (ranges[0]/2, ranges[1]/2)

        if self._amplitude_offset_handling == AWGAmplitudeOffsetHandling.IGNORE_OFFSET:
            voltage_offsets = (0, 0)
        elif self._amplitude_offset_handling == AWGAmplitudeOffsetHandling.CONSIDER_OFFSET:
            voltage_offsets = (self.device.offset(self._channels[0]),
                               self.device.offset(self._channels[1]))
        else:
            raise ValueError('{} is invalid as AWGAmplitudeOffsetHandling'.format(self._amplitude_offset_handling))

        # parse to tabor program
        tabor_program = TaborProgram(program,
                                     channels=tuple(channels),
                                     markers=markers,
                                     device_properties=self.device.dev_properties,
                                     sample_rate=sample_rate / 10**9,
                                     amplitudes=voltage_amplitudes,
                                     offsets=voltage_offsets,
                                     voltage_transformations=voltage_transformation)

        segments, segment_lengths = tabor_program.get_sampled_segments()

        waveform_to_segment, to_amend, to_insert = self._find_place_for_segments_in_memory(segments,
                                                                                           segment_lengths)

        self._segment_references[waveform_to_segment[waveform_to_segment >= 0]] += 1

        for wf_index in np.flatnonzero(to_insert > 0):
            segment_index = to_insert[wf_index]
            self._upload_segment(to_insert[wf_index], segments[wf_index])
            waveform_to_segment[wf_index] = segment_index

        if np.any(to_amend):
            segments_to_amend = [segments[idx] for idx in np.flatnonzero(to_amend)]
            waveform_to_segment[to_amend] = self._amend_segments(segments_to_amend)

        self._known_programs[name] = TaborProgramMemory(waveform_to_segment=waveform_to_segment,
                                                        program=tabor_program)