Example #1
0
    def test_get_pulses(self):
        pulse_sequence = PulseSequence()
        self.assertListEqual(pulse_sequence.get_pulses(), [])
        pulse1 = DCPulse(name='dc1', amplitude=1.5, duration=10, t_start=1)
        pulse2 = DCPulse(name='dc2', amplitude=2.5, duration=10, t_start=1)
        pulse3 = TriggerPulse(name='trig', duration=12, t_start=1)
        pulse_sequence.add(pulse1, pulse2, pulse3)

        subset_pulses = pulse_sequence.get_pulses()
        self.assertEqual(subset_pulses[0], pulse1)
        self.assertListEqual(subset_pulses, [pulse1, pulse2, pulse3])
        subset_pulses = pulse_sequence.get_pulses(t_start=1)
        self.assertListEqual(subset_pulses, [pulse1, pulse2, pulse3])
        subset_pulses = pulse_sequence.get_pulses(duration=10)
        self.assertListEqual(subset_pulses, [pulse1, pulse2])
        subset_pulses = pulse_sequence.get_pulses(amplitude=1.5)
        self.assertListEqual(subset_pulses, [pulse1])
        subset_pulses = pulse_sequence.get_pulses(amplitude=('>', 1.5))
        self.assertListEqual(subset_pulses, [pulse2])
        subset_pulses = pulse_sequence.get_pulses(amplitude=('>=', 1.5))
        self.assertListEqual(subset_pulses, [pulse1, pulse2])

        pulse = pulse_sequence.get_pulse(amplitude=1.5)
        self.assertEqual(pulse, pulse1)
        pulse = pulse_sequence.get_pulse(duration=12)
        self.assertEqual(pulse, pulse3)
        with self.assertRaises(RuntimeError):
            pulse_sequence.get_pulse(duration=10)
Example #2
0
    def get_additional_pulses(self, connections) -> list:
        """Additional pulses required for instrument, e.g. trigger pulses.

        Args:
            connections: List of all connections in the layout

        Returns:
            * Empty list if there are no acquisition pulses.
            * A single trigger pulse at start of acquisition if using triggered
              acquisition controller.
            * AcquisitionPulse and TriggerWaitPulse if using the steered
              initialization controller

        Raises:
            NotImplementedError
                Using continous acquisition controller
        """
        if not self.pulse_sequence.get_pulses(acquire=True):
            # No pulses need to be acquired
            return []
        elif self.acquisition_controller() == 'Triggered':
            # Add a single trigger pulse when starting acquisition
            if not self.capture_full_trace():
                t_start = min(pulse.t_start for pulse in
                              self.pulse_sequence.get_pulses(acquire=True))
            else:
                t_start = 0
            return [TriggerPulse(t_start=t_start,
                                 connection_requirements={
                                     'input_instrument': self.instrument_name(),
                                     'trigger': True})]
        elif self.acquisition_controller() == 'Continuous':
            raise NotImplementedError("Continuous mode not implemented")
        elif self.acquisition_controller() == 'SteeredInitialization':
            # TODO add possibility of continuous acquisition having correct
            # timing even if it should acquire for the entire duration of the
            #  pulse sequence.
            t_start = min(pulse.t_start for pulse in
                          self.pulse_sequence.get_pulses(acquire=True))
            t_stop = max(pulse.t_stop for pulse in
                         self.pulse_sequence.get_pulses(acquire=True))
            # Add a marker high for readout stage
            # Get steered initialization pulse
            initialization = self.pulse_sequence.get_pulse(initialize=True)

            acquisition_pulse = MarkerPulse(
                t_start=t_start, t_stop=t_stop,
                connection_requirements={
                    'connection': initialization.trigger_connection})
            trigger_wait_pulse = TriggerWaitPulse(
                t_start=self.pulse_sequence.duration,
                connection_requirements={
                    'output_arg': 'ATS.software_trig_out'})

            return [acquisition_pulse, trigger_wait_pulse]
        else:
            raise Exception("No controller found")
    def _get_trigger_pulse(self, t: float) -> TriggerPulse:
        """Create input trigger pulse

        Args:
            t: trigger start time

        Returns:
            Trigger pulse with specified start time
        """
        trigger_pulse = TriggerPulse(t_start=t,
                                     duration=self.trigger_in_duration(),
                                     connection_requirements={
                                         'input_instrument':
                                         self.instrument_name(),
                                         'trigger': True
                                     })
        return trigger_pulse
Example #4
0
    def get_additional_pulses(self, **kwargs):
        # Currently the only supported sequence_mode is `once`, i.e. one trigger
        # at the start of the pulse sequence

        # Request a single trigger at the start of the pulse sequence
        logger.info(f"Creating trigger for Keysight 81180A: {self.name}")
        return [
            TriggerPulse(
                name=self.name + "_trigger",
                t_start=0,
                duration=self.trigger_in_duration(),
                connection_requirements={
                    "input_instrument": self.instrument_name(),
                    "trigger": True,
                },
            )
        ]
Example #5
0
    def get_additional_pulses(self, connections) -> List[Pulse]:
        """Get list of pulses required by instrument (trigger pulses)

        A trigger pulse is returned for each pulse start and stop time.
        """
        assert self.use_trig_in(
        ), "Interface not yet programmed for pxi triggering"
        # Get list of unique pulse start and stop times
        t_list = self.pulse_sequence.t_list
        trigger_pulses = [
            TriggerPulse(t_start=t,
                         duration=self.trigger_in_duration(),
                         connection_requirements={
                             'input_instrument': self.instrument.name,
                             'input_channel': self._input_channels['trig_in']
                         }) for t in t_list
            if t != self.pulse_sequence.duration
        ]
        return trigger_pulses
Example #6
0
    def get_additional_pulses(self, connections) -> List[Pulse]:
        """Additional pulses needed by instrument after targeting of main pulses

        Args:
            connections: List of all connections in the layout

        Returns:
            List containing trigger pulse if not primary instrument
        """
        # Request one trigger at the start if not primary
        if not self.is_primary():
            return [
                TriggerPulse(t_start=0,
                             connection_requirements={
                                 'input_instrument': self.instrument_name(),
                                 'trigger': True
                             })
            ]
        else:
            return []
    def get_additional_pulses(self, connections) -> List[Pulse]:
        """Additional pulses needed by instrument after targeting of main pulses

        Trigger pulses are requested if trigger mode is hardware.
        Trigger at t_start is requested if there is a connection.trigger.
        Trigger at t=0 is requested if there is a connection.trigger_start/

        Args:
            connections: List of all connections in the layout

        Returns:
            List of additional pulses, empty by default.
        """
        if self.is_primary():
            # Instrument does not require triggers
            return []
        elif not self.pulse_sequence:
            # AWG does not output pulses
            return []
        elif self.trigger_mode() in ['software', 'none']:
            return []
        else:  # Hardware trigger
            if self.input_pulse_sequence.get_pulses(trigger=True) \
                    or self.input_pulse_sequence.get_pulses(trigger_start=True):
                logger.warning(f'Trigger(s) manually defined for {self.name}: '
                               f'{self.input_pulse_sequence.get_pulses(trigger=True)}')
                return []

            trigger_connection = next(
                connection for connection in connections
                if (connection.trigger or connection.trigger_start) and
                connection.input['instrument'] == self.instrument_name())

            return [TriggerPulse(name=f'{self.name}_trigger',
                                 t_start=0,
                                 duration=15e-6,
                                 connection=trigger_connection)]
Example #8
0
    def get_additional_pulses(self, **kwargs):
        # Return empty list if no pulses are in the pulse sequence
        if not self.pulse_sequence or self.is_primary():
            return []

        active_channels = list(
            set(pulse.connection.output['channel'].name
                for pulse in self.pulse_sequence))

        connections = {
            ch: self.pulse_sequence.get_connection(
                output_instrument=self.instrument.name, output_channel=ch)
            for ch in active_channels
        }

        # If a pulse starts on one channel and needs a trigger while another
        # pulse is still active on the other channel, this would cause the other
        # pulse to move onto the next pulse prematurely. This only happens if
        # the other pulse finished its waveform and is waiting for a trigger.
        # Here we check that this does not occur.

        if len(active_channels) > 1:
            t = 0
            gap_pulses = []
            for t_start in self.pulse_sequence.t_start_list:

                if t_start < t:
                    raise RuntimeError(
                        f'Pulse starting before end of previous pulse {t}')
                elif t_start > t:
                    # Add gap pulses for each channel
                    for ch in active_channels:
                        gap_pulse = DCPulse(t_start=t,
                                            t_stop=t_start,
                                            amplitude=0,
                                            connection=connections[ch])
                        gap_pulses.append(
                            self.get_pulse_implementation(gap_pulse))
                    t = t_start

                pulses = {
                    ch: self.pulse_sequence.get_pulse(t_start=t_start,
                                                      output_channel=ch)
                    for ch in active_channels
                }

                if pulses['ch1'] is None and pulses['ch2'] is None:
                    raise RuntimeError(
                        f"pulse sequence has t_start={t_start}, "
                        "but couldn't find pulse for either channel")
                elif pulses['ch1'] is not None and pulses['ch2'] is not None:
                    assert pulses['ch1'].t_stop == pulses['ch2'].t_stop, \
                        f"t_stop of pulses starting at {t_start} must be equal." \
                        f"This is a current limitation of the AWG interface."
                    t = pulses['ch1'].t_stop
                elif pulses['ch1'] is not None:
                    # add gap pulse for ch2
                    gap_pulse = DCPulse(t_start=t_start,
                                        t_stop=pulses['ch1'].t_stop,
                                        amplitude=0,
                                        connection=connections['ch2'])
                    gap_pulses.append(self.get_pulse_implementation(gap_pulse))
                    t = pulses['ch1'].t_stop
                else:
                    # add gap pulse for ch1
                    gap_pulse = DCPulse(t_start=t_start,
                                        t_stop=pulses['ch2'].t_stop,
                                        amplitude=0,
                                        connection=connections['ch1'])
                    gap_pulses.append(self.get_pulse_implementation(gap_pulse))
                    t = pulses['ch2'].t_stop
        else:
            ch = active_channels[0]
            # only add gap pulses for active channel
            connection = self.pulse_sequence.get_connection(
                output_instrument=self.instrument.name, output_channel=ch)
            gap_pulses = []
            t = 0
            for t_start in self.pulse_sequence.t_start_list:
                if t_start < t:
                    raise RuntimeError('Pulse starting before previous pulse '
                                       f'finished {t} s')
                elif t_start > t:
                    # Add gap pulse
                    gap_pulse = DCPulse(t_start=t,
                                        t_stop=t_start,
                                        amplitude=0,
                                        connection=connection)
                    gap_pulses.append(self.get_pulse_implementation(gap_pulse))

                pulse = self.pulse_sequence.get_pulse(t_start=t_start,
                                                      output_channel=ch)
                # Pulse will be None if the pulse sequence has a final delay
                if pulse is not None:
                    t = pulse.t_stop

        if t != self.pulse_sequence.duration:
            for ch in active_channels:
                gap_pulse = DCPulse(t_start=t,
                                    t_stop=self.pulse_sequence.duration,
                                    amplitude=0,
                                    connection=connections[ch])
                gap_pulses.append(self.get_pulse_implementation(gap_pulse))

        if gap_pulses:
            self.pulse_sequence.add(*gap_pulses)

        # TODO test if first waveform needs trigger as well
        additional_pulses = [
            TriggerPulse(t_start=t_start,
                         duration=self.trigger_in_duration(),
                         connection_requirements={
                             'input_instrument': self.instrument_name(),
                             'trigger': True
                         }) for t_start in self.pulse_sequence.t_start_list +
            [self.pulse_sequence.duration]
        ]

        return additional_pulses