Ejemplo n.º 1
0
    def setup_arb(
            self):  #, gate_bias, gate_pulse_amplitude, gate_pulse_duration):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        seg_ids_ch1 = []
        seg_ids_ch2 = []

        # For the measurements pulses along the channel
        wf = measure_pulse(amplitude=self.measure_amplitude,
                           duration=self.measure_duration,
                           frequency=self.measure_frequency)
        wf_data = KeysightM8190A.create_binary_wf_data(wf, sync_mkr=1)
        seg_id = self.arb.define_waveform(len(wf_data), channel=1)
        self.arb.upload_waveform(wf_data, seg_id, channel=1)
        seg_ids_ch1.append(seg_id)

        # Build in a delay between sequences
        settle_pts = 640 * np.int(
            np.ceil(self.repeat_time * self.sample_rate / 640))
        # settle_pts2 = 640*np.ceil(8*2.4e-9 * self.sample_rate / 640)

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=self.attempts * len(self.gate_amps) *
                       len(self.gate_durs))
        for si in seg_ids_ch1:
            seq.add_waveform(si)
            seq.add_idle(settle_pts, 0.0)
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0, channel=1)

        for amp in self.gate_amps:
            for dur in self.gate_durs:
                # For the switching pulses along the gate
                wf = switching_pulse(
                    amplitude=amp,
                    duration=dur)  #self.gate_pulse_duration.value)
                wf_data = KeysightM8190A.create_binary_wf_data(wf)
                seg_id = self.arb.define_waveform(len(wf_data), channel=2)
                self.arb.upload_waveform(wf_data, seg_id, channel=2)
                seg_ids_ch2.append(seg_id)

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=self.attempts)
        for si in seg_ids_ch2:
            seq.add_waveform(si)
            seq.add_idle(settle_pts, 0.0)
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0, channel=2)

        self.arb.set_sequence_mode("SCENARIO", channel=1)
        self.arb.set_scenario_advance_mode("SINGLE", channel=1)
        self.arb.set_scenario_start_index(0, channel=1)
        self.arb.set_sequence_mode("SCENARIO", channel=2)
        self.arb.set_scenario_advance_mode("SINGLE", channel=2)
        self.arb.set_scenario_start_index(0, channel=2)
        self.arb.initiate(channel=1)
        self.arb.initiate(channel=2)
        self.arb.advance()
Ejemplo n.º 2
0
    def setup_arb(self,volt):
        def arb_pulse(amplitude, duration, sample_rate=12e9):
            arb_voltage = arb_voltage_lookup()
            pulse_points = int(duration*sample_rate)
            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64*np.ceil(pulse_points/64.0))
            wf[:pulse_points] = np.sign(amplitude)*arb_voltage(abs(amplitude))
            return wf

        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        # Reset waveform
        reset_wf    = arb_pulse(-self.polarity*self.reset_amplitude, self.reset_duration)
        wf_data     = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id  = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        # Switching waveform
        switch_wf    = arb_pulse(self.polarity*volt, self.pulse_duration.value)
        wf_data     = KeysightM8190A.create_binary_wf_data(switch_wf)
        sw_segment_id  = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, sw_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200), sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640*np.ceil(self.settle_delay * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        #First try with reset flipping pulse
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0) # bonus non-contiguous memory delay
        seq.add_waveform(sw_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0) # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()
Ejemplo n.º 3
0
    def setup_daq(self):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        # Picosecond trigger waveform
        pspl_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                            samp_mkr=1)
        pspl_trig_segment_id = self.arb.define_waveform(len(pspl_trig_wf))
        self.arb.upload_waveform(pspl_trig_wf, pspl_trig_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))
        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        seq.add_waveform(pspl_trig_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # ===================
        #   Setup the NIDAQ
        # ===================
        self.analog_input = Task()
        self.read = int32()
        self.buf_points = self.samps_per_trig * self.attempts
        self.analog_input.CreateAIVoltageChan("Dev1/ai1", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()
Ejemplo n.º 4
0
class ResetSearchExperiment(Experiment):

    voltage = OutputConnector()
    field = FloatParameter(default=0, unit="T")
    duration = FloatParameter(default=5e-9, unit="s")

    repeats = 200
    amplitudes = np.arange(-0.01, 0.011, 0.01)  # Reset amplitudes
    samps_per_trig = 5
    settle_delay = 50e-6
    measure_current = 3e-6

    # Instruments
    arb = KeysightM8190A("192.168.5.108")
    mag = AMI430("192.168.5.109")
    keith = Keithley2400("GPIB0::25::INSTR")
    lock = SR865("USB0::0xB506::0x2000::002638::INSTR")

    polarity = -1

    def init_streams(self):
        # Baked in data axes
        descrip = DataStreamDescriptor()
        descrip.data_name = 'voltage'
        descrip.add_axis(DataAxis("sample", range(self.samps_per_trig)))
        descrip.add_axis(DataAxis("amplitude", self.amplitudes))
        descrip.add_axis(DataAxis("repeat", range(self.repeats)))
        self.voltage.set_descriptor(descrip)

    def init_instruments(self):
        # Set up Keithley
        self.keith.triad()
        self.keith.conf_meas_res(res_range=1e6)
        self.keith.conf_src_curr(comp_voltage=0.6, curr_range=1.0e-5)
        self.keith.current = self.measure_current
        self.mag.ramp()

        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.setup_AWG()

        self.analog_input = Task()
        self.read = int32()
        self.buf_points = len(
            self.amplitudes) * self.samps_per_trig * self.repeats
        self.analog_input.CreateAIVoltageChan("Dev1/ai1", "", DAQmx_Val_Diff,
                                              0.0, 0.5, DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.duration.assign_method(self.setup_AWG)

    def setup_AWG(self, *args):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0

        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")

        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        def arb_pulse(amplitude, sample_rate=12e9):
            pulse_points = int(self.duration.value * sample_rate)

            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64 * int(np.ceil(pulse_points / 64.0)))
            wf[:pulse_points] = amplitude
            return wf

        segment_ids = []
        arb_voltage = arb_voltage_lookup()
        for amp in self.amplitudes:
            waveform = arb_pulse(np.sign(amp) * arb_voltage(abs(amp)))
            wf_data = KeysightM8190A.create_binary_wf_data(waveform)
            segment_id = self.arb.define_waveform(len(wf_data))
            segment_ids.append(segment_id)
            self.arb.upload_waveform(wf_data, segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))
        start_idxs = [0]

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.repeats))
        for si in segment_ids:
            # seq = Sequence(sequence_loop_ct=int(1))
            seq.add_waveform(si)  # Apply switching pulse to the sample
            seq.add_idle(settle_pts, 0.0)  # Wait for the measurement to settle
            seq.add_waveform(
                nidaq_trig_segment_id)  # Trigger the NIDAQ measurement
            seq.add_idle(1 << 14, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)

        self.arb.upload_scenario(scenario, start_idx=start_idxs[-1])
        start_idxs.append(start_idxs[-1] + len(scenario.scpi_strings()))
        # The last entry is eroneous
        start_idxs = start_idxs[:-1]

        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.stop()
        self.arb.scenario_start_index = 0
        self.arb.run()

    async def run(self):
        # Establish buffers
        buffers = np.empty(self.buf_points)
        self.arb.advance()
        self.arb.trigger()
        self.analog_input.ReadAnalogF64(self.buf_points, -1,
                                        DAQmx_Val_GroupByChannel,
                                        buffers, self.buf_points,
                                        byref(self.read), None)
        logger.debug("Read a buffer of {} points".format(buffers.size))
        await self.voltage.push(buffers)
        # Seemingly we need to give the filters some time to catch up here...
        await asyncio.sleep(0.02)
        logger.debug("Stream has filled {} of {} points".format(
            self.voltage.points_taken, self.voltage.num_points()))

    def shutdown_instruments(self):
        try:
            self.analog_input.StopTask()
        except Exception as e:
            logger.warning("Warning failed to stop task. This is typical.")
            pass
        self.arb.stop()
        self.keith.current = 0.0
        self.mag.disconnect()
Ejemplo n.º 5
0
    def setup_AWG(self, *args):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0

        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")

        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        def arb_pulse(amplitude, sample_rate=12e9):
            pulse_points = int(self.duration.value * sample_rate)

            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64 * int(np.ceil(pulse_points / 64.0)))
            wf[:pulse_points] = amplitude
            return wf

        segment_ids = []
        arb_voltage = arb_voltage_lookup()
        for amp in self.amplitudes:
            waveform = arb_pulse(np.sign(amp) * arb_voltage(abs(amp)))
            wf_data = KeysightM8190A.create_binary_wf_data(waveform)
            segment_id = self.arb.define_waveform(len(wf_data))
            segment_ids.append(segment_id)
            self.arb.upload_waveform(wf_data, segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))
        start_idxs = [0]

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.repeats))
        for si in segment_ids:
            # seq = Sequence(sequence_loop_ct=int(1))
            seq.add_waveform(si)  # Apply switching pulse to the sample
            seq.add_idle(settle_pts, 0.0)  # Wait for the measurement to settle
            seq.add_waveform(
                nidaq_trig_segment_id)  # Trigger the NIDAQ measurement
            seq.add_idle(1 << 14, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)

        self.arb.upload_scenario(scenario, start_idx=start_idxs[-1])
        start_idxs.append(start_idxs[-1] + len(scenario.scpi_strings()))
        # The last entry is eroneous
        start_idxs = start_idxs[:-1]

        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.stop()
        self.arb.scenario_start_index = 0
        self.arb.run()
Ejemplo n.º 6
0
    def setup_daq(self, attempt):
        def arb_pulse(amplitude, duration, sample_rate=12e9):
            arb_voltage = arb_voltage_lookup()
            pulse_points = int(duration * sample_rate)
            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64 * np.ceil(pulse_points / 64.0))
            wf[:pulse_points] = np.sign(amplitude) * arb_voltage(
                abs(amplitude))
            return wf

        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        reset_wf = arb_pulse(-self.polarity * self.reset_amplitude,
                             self.reset_duration)
        wf_data = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        # no_reset_wf = arb_pulse(0.0, 3.0/12e9)
        # wf_data     = KeysightM8190A.create_binary_wf_data(no_reset_wf)
        # no_rst_segment_id  = self.arb.define_waveform(len(wf_data))
        # self.arb.upload_waveform(wf_data, no_rst_segment_id)

        # Picosecond trigger waveform
        pspl_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                            samp_mkr=1)
        pspl_trig_segment_id = self.arb.define_waveform(len(pspl_trig_wf))
        self.arb.upload_waveform(pspl_trig_wf, pspl_trig_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(attempt))
        #First try with reset flipping pulse
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        seq.add_waveform(pspl_trig_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # ===================
        #   Setup the NIDAQ
        # ===================

        self.analog_input = Task()
        self.read = int32()
        self.buf_points = 2 * self.samps_per_trig * attempt
        self.analog_input.CreateAIVoltageChan("Dev1/ai1", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()
Ejemplo n.º 7
0
class SwitchSearchLockinExperiment(Experiment):
    voltage = OutputConnector()

    sample = "CSHE2"
    comment = "Search PSPL Switch Voltage"
    # PARAMETERS: Confirm these before running
    field = FloatParameter(default=0.0, unit="T")
    pulse_voltage  = FloatParameter(default=0, unit="V")
    pulse_duration = FloatParameter(default=5.0e-9, unit="s")
    measure_current = 3e-6

    circuit_attenuation = 20.0
    pspl_base_attenuation = 30.0
    settle_delay = 100e-6

    attempts = 1 << 8 # Number of attemps
    samps_per_trig = 10 # Samples per trigger

    # Instruments
    arb   = KeysightM8190A("192.168.5.108")
    pspl  = Picosecond10070A("GPIB0::24::INSTR")
    mag   = AMI430("192.168.5.109")
    # keith = Keithley2400("GPIB0::25::INSTR")
    lock  = SR865("USB0::0xB506::0x2000::002638::INSTR")
    atten = Attenuator("calibration/RFSA2113SB_HPD_20160901.csv", lock.set_ao2, lock.set_ao3)

    min_daq_voltage = -10
    max_daq_voltage = 10

    def init_instruments(self):
        # ===================
        #    Setup the Lockin
        # ===================
        self.lock.tc = 30e-6
        time.sleep(0.5)

        # self.keith.triad()
        # self.keith.conf_meas_res(res_range=1e5)
        # self.keith.conf_src_curr(comp_voltage=0.5, curr_range=1.0e-5)
        # self.keith.current = self.measure_current
        self.mag.ramp()

        # ===================
        #    Setup the AWG
        # ===================

        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        # ===================
        #   Setup the PSPL
        # ===================

        self.pspl.amplitude = 7.5*np.power(10, -self.pspl_base_attenuation/20.0)
        self.pspl.trigger_source = "EXT"
        self.pspl.trigger_level = 0.1
        self.pspl.output = True

        self.setup_daq()

        def set_voltage(voltage):
            # Calculate the voltage controller attenuator setting
            self.pspl.amplitude = np.sign(voltage)*7.5*np.power(10, -self.pspl_base_attenuation/20.0)
            vc_atten = abs(20.0 * np.log10(abs(voltage)/7.5)) - self.pspl_base_attenuation - self.circuit_attenuation
            if vc_atten <= 6.0:
                logger.error("Voltage controlled attenuation under range (6dB).")
                raise ValueError("Voltage controlled attenuation under range (6dB).")
            self.atten.set_attenuation(vc_atten)
            time.sleep(0.02)

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.pulse_duration.assign_method(self.pspl.set_duration)
        self.pulse_voltage.assign_method(set_voltage)

        # Create hooks for relevant delays
        self.pulse_duration.add_post_push_hook(lambda: time.sleep(0.1))

    def setup_daq(self):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        # Picosecond trigger waveform
        pspl_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200), samp_mkr=1)
        pspl_trig_segment_id = self.arb.define_waveform(len(pspl_trig_wf))
        self.arb.upload_waveform(pspl_trig_wf, pspl_trig_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200), sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640*np.ceil(self.settle_delay * 12e9 / 640))
        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        seq.add_waveform(pspl_trig_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0) # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # ===================
        #   Setup the NIDAQ
        # ===================
        self.analog_input = Task()
        self.read = int32()
        self.buf_points = self.samps_per_trig*self.attempts
        self.analog_input.CreateAIVoltageChan("Dev1/ai0", "", DAQmx_Val_Diff,
            self.min_daq_voltage, self.max_daq_voltage, DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps , self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

    def init_streams(self):
        # Baked in data axes
        descrip = DataStreamDescriptor()
        descrip.add_axis(DataAxis("sample", range(self.samps_per_trig)))
        descrip.add_axis(DataAxis("attempts", range(self.attempts)))
        self.voltage.set_descriptor(descrip)

    async def run(self):
        self.arb.advance()
        self.arb.trigger()
        buf = np.empty(self.buf_points)
        self.analog_input.ReadAnalogF64(self.buf_points, -1, DAQmx_Val_GroupByChannel,
                                        buf, self.buf_points, byref(self.read), None)
        logger.debug("Read a buffer of {} points".format(buf.size))
        await self.voltage.push(buf)
        # Seemingly we need to give the filters some time to catch up here...
        await asyncio.sleep(0.02)
        logger.debug("Stream has filled {} of {} points".format(self.voltage.points_taken, self.voltage.num_points()))

    def shutdown_instruments(self):
        try:
            self.analog_input.StopTask()
        except Exception as e:
            logger.warning("Warning failed to stop task, which is quite typical (!)")

        self.arb.stop()
        # self.keith.current = 0.0
        # self.mag.zero()
        self.pspl.output = False
Ejemplo n.º 8
0
class SWERExperiment(Experiment):
    """ Experiment class for Switching probability measurment
    Determine switching probability for V << V0
    with varying V (and durations?)
    """

    field          = FloatParameter(default=0.0, unit="T")
    pulse_duration = FloatParameter(default=1.0e-9, unit="s")
    pulse_voltage  = FloatParameter(default=0.1, unit="V")
    repeats        = IntParameter(default = 1) # Dummy parameter for repeating
    voltage     = OutputConnector()

    attempts        = 1 << 12
    settle_delay    = 100e-6
    measure_current = 3.0e-6
    samps_per_trig  = 5

    polarity        = 1

    min_daq_voltage = 0.0
    max_daq_voltage = 0.4

    reset_amplitude = 0.1
    reset_duration  = 5.0e-9

    mag   = AMI430("192.168.5.109")
    lock  = SR865("USB0::0xB506::0x2000::002638::INSTR")
    # pspl  = Picosecond10070A("GPIB0::24::INSTR")
    arb   = KeysightM8190A("192.168.5.108")
    keith = Keithley2400("GPIB0::25::INSTR")

    def init_streams(self):
        # Baked in data axes
        descrip = DataStreamDescriptor()
        descrip.add_axis(DataAxis("sample", range(self.samps_per_trig)))
        descrip.add_axis(DataAxis("state", range(2)))
        descrip.add_axis(DataAxis("attempt", range(self.attempts)))
        self.voltage.set_descriptor(descrip)

    def init_instruments(self):

        # ===================
        #    Setup the Keithley
        # ===================

        self.keith.triad()
        self.keith.conf_meas_res(res_range=1e5)
        self.keith.conf_src_curr(comp_voltage=0.5, curr_range=1.0e-5)
        self.keith.current = self.measure_current
        self.mag.ramp()

        # ===================
        #    Setup the AWG
        # ===================

        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.continuous_mode = False
        self.arb.gate_mode = False
        self.setup_arb(self.pulse_voltage.value)

        # ===================
        #   Setup the NIDAQ
        # ===================

        self.analog_input = Task()
        self.read = int32()
        self.buf_points = 2*self.samps_per_trig*self.attempts
        self.analog_input.CreateAIVoltageChan("Dev1/ai1", "", DAQmx_Val_Diff,
            self.min_daq_voltage, self.max_daq_voltage, DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps , self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.pulse_voltage.assign_method(self.setup_arb)

    def setup_arb(self,volt):
        def arb_pulse(amplitude, duration, sample_rate=12e9):
            arb_voltage = arb_voltage_lookup()
            pulse_points = int(duration*sample_rate)
            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64*np.ceil(pulse_points/64.0))
            wf[:pulse_points] = np.sign(amplitude)*arb_voltage(abs(amplitude))
            return wf

        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        # Reset waveform
        reset_wf    = arb_pulse(-self.polarity*self.reset_amplitude, self.reset_duration)
        wf_data     = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id  = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        # Switching waveform
        switch_wf    = arb_pulse(self.polarity*volt, self.pulse_duration.value)
        wf_data     = KeysightM8190A.create_binary_wf_data(switch_wf)
        sw_segment_id  = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, sw_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200), sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640*np.ceil(self.settle_delay * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        #First try with reset flipping pulse
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0) # bonus non-contiguous memory delay
        seq.add_waveform(sw_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0) # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

    async def run(self):
        # Keep track of the previous values
        logger.debug("Waiting for filters.")
        await asyncio.sleep(1.0)
        self.arb.advance()
        self.arb.trigger()
        buf = np.empty(self.buf_points)
        self.analog_input.ReadAnalogF64(self.buf_points, -1, DAQmx_Val_GroupByChannel,
                                        buf, self.buf_points, byref(self.read), None)
        await self.voltage.push(buf)
        # Seemingly we need to give the filters some time to catch up here...
        await asyncio.sleep(0.002)
        logger.debug("Stream has filled {} of {} points".format(self.voltage.points_taken, self.voltage.num_points() ))

    def shutdown_instruments(self):
        self.keith.current = 0.0e-5
        # self.mag.zero()
        self.arb.stop()
        try:
            self.analog_input.StopTask()
        except Exception as e:
            print("Warning: failed to stop task (this normally happens with no consequences when taking multiple samples per trigger).")
            pass
class SwitchSearchLockinExperiment(Experiment):
    voltage = OutputConnector()

    sample = "CSHE2"
    comment = "Search PSPL Switch Voltage"

    field = FloatParameter(default=0.0, unit="T")
    pulse_voltage = FloatParameter(default=0, unit="V")
    pulse_duration = FloatParameter(default=5.0e-9, unit="s")

    # Default values for lockin measurement. These will need to be changed in a notebook to match the MR and switching current of the sample being measured
    res_reference = 1e3
    sample_resistance = 50
    measure_current = 10e-6
    fdB = 18
    tc = 100e-3

    circuit_attenuation = 20.0
    pspl_base_attenuation = 30.0

    attempts = 1 << 8  # Number of attemps
    samps_per_trig = 10  # Samples per trigger

    # Instruments
    arb = KeysightM8190A("192.168.5.108")
    pspl = Picosecond10070A("GPIB0::24::INSTR")
    mag = AMI430("192.168.5.109")
    lock = SR865("USB0::0xB506::0x2000::002638::INSTR")
    atten = RFMDAttenuator("calibration/RFSA2113SB_HPD_20160901.csv")

    min_daq_voltage = 0
    max_daq_voltage = 10

    def init_instruments(self):
        # ===================
        #    Setup the Lockin
        # ===================
        self.lock.tc = self.tc
        self.lock.filter_slope = self.fdB
        self.lock.amp = (self.res_reference +
                         self.sample_resistance) * self.measure_current
        sense_vals = np.array(self.lock.SENSITIVITY_VALUES)
        self.lock.sensitivity = sense_vals[np.argmin(
            np.absolute(sense_vals - 2 * self.sample_resistance *
                        self.measure_current * np.ones(sense_vals.size)))]
        time.sleep(20 * self.lock.measure_delay())

        # Rescale lockin analogue output for NIDAQ
        self.lock.r_offset_enable = True
        self.lock.r_expand = 100
        self.lock.auto_offset("R")
        self.lock.r_offset = 0.99 * self.lock.r_offset
        #self.lock.r_offset = 100 * ((self.sample_resistance*self.measure_current/self.lock.sensitivity) - (0.05/self.lock.r_expand))
        time.sleep(20 * self.lock.measure_delay())

        # Ramp magnet to set point
        self.mag.ramp()

        #Set attenuator control methods
        self.atten.set_supply_method(self.lock.set_ao2)
        self.atten.set_control_method(self.lock.set_ao3)

        # ===================
        #    Setup the AWG
        # ===================

        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        # ===================
        #   Setup the PSPL
        # ===================
        # PSPL Max amplitude is 7.5 V
        self.pspl.amplitude = 7.5 * np.power(
            10, -self.pspl_base_attenuation / 20.0)
        self.pspl.trigger_source = "EXT"
        self.pspl.trigger_level = 0.1
        self.pspl.output = True

        self.setup_daq()

        def set_voltage(voltage):
            # Calculate the voltage controller attenuator setting
            self.pspl.amplitude = np.sign(voltage) * 7.5 * np.power(
                10, -self.pspl_base_attenuation / 20.0)
            vc_atten = abs(
                20.0 * np.log10(abs(voltage) / 7.5)
            ) - self.pspl_base_attenuation - self.circuit_attenuation

            if vc_atten <= self.atten.minimum_atten():
                logger.error(
                    "Voltage controlled attenuation {} under range.".format(
                        vc_atten))
                raise ValueError(
                    "Voltage controlled attenuation {} under range.".format(
                        vc_atten))

            if self.atten.maximum_atten() < vc_atten:
                logger.error(
                    "Voltage controlled attenuation {} over range.".format(
                        vc_atten))
                raise ValueError(
                    "Voltage controlled attenuation {} over range.".format(
                        vc_atten))

            self.atten.set_attenuation(vc_atten)
            time.sleep(0.02)

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.pulse_duration.assign_method(self.pspl.set_duration)
        self.pulse_voltage.assign_method(set_voltage)

        # Create hooks for relevant delays
        self.pulse_duration.add_post_push_hook(lambda: time.sleep(0.1))

    def setup_daq(self):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        # Picosecond trigger waveform
        pspl_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                            samp_mkr=1)
        pspl_trig_segment_id = self.arb.define_waveform(len(pspl_trig_wf))
        self.arb.upload_waveform(pspl_trig_wf, pspl_trig_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.lock.measure_delay() * 12e9 / 640))
        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        seq.add_waveform(pspl_trig_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # ===================
        #   Setup the NIDAQ
        # ===================
        self.analog_input = Task()
        self.read = int32()
        self.buf_points = self.samps_per_trig * self.attempts
        self.analog_input.CreateAIVoltageChan("Dev1/ai0", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

    def init_streams(self):
        # Baked in data axes
        descrip = DataStreamDescriptor()
        descrip.add_axis(DataAxis("sample", range(self.samps_per_trig)))
        descrip.add_axis(DataAxis("attempts", range(self.attempts)))
        self.voltage.set_descriptor(descrip)

    async def run(self):
        self.arb.advance()
        self.arb.trigger()
        buf = np.empty(self.buf_points)
        self.analog_input.ReadAnalogF64(self.buf_points, -1,
                                        DAQmx_Val_GroupByChannel, buf,
                                        self.buf_points, byref(self.read),
                                        None)
        logger.debug("Read a buffer of {} points".format(buf.size))
        await self.voltage.push(buf)
        # Seemingly we need to give the filters some time to catch up here...
        await asyncio.sleep(0.02)
        logger.debug("Stream has filled {} of {} points".format(
            self.voltage.points_taken, self.voltage.num_points()))

    def shutdown_instruments(self):
        try:
            self.analog_input.StopTask()
        except Exception as e:
            logger.warning(
                "Warning failed to stop task, which is quite typical (!)")

        self.arb.stop()
        self.pspl.output = False
        self.lock.amp = 0
    def setup_arb(self, vpeak):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        reset_wf = arb_pulse(-self.polarity * self.reset_amplitude,
                             self.reset_duration)
        wf_data = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        no_reset_wf = arb_pulse(0.0, 3.0 / 12e9)
        wf_data = KeysightM8190A.create_binary_wf_data(no_reset_wf)
        no_rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, no_rst_segment_id)

        # nTron waveforms
        volt = self.polarity * self.nTron_control_voltage(vpeak)
        logger.debug("Set nTron pulse: {}V -> AWG {}V, {}s".format(
            vpeak, volt, self.nTron_duration.value))
        ntron_wf = ntron_pulse(amplitude=volt,
                               fall_time=self.nTron_duration.value)
        wf_data = KeysightM8190A.create_binary_wf_data(ntron_wf)
        ntron_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, ntron_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts.value))
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        # seq.add_waveform(pspl_trig_segment_id)
        seq.add_waveform(ntron_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)

        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # ===================
        #   Setup the NIDAQ
        # ===================

        self.analog_input = Task()
        self.read = int32()
        self.buf_points = 2 * self.samps_per_trig * self.attempts.value
        self.analog_input.CreateAIVoltageChan("Dev1/ai1", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()
class nTronBERExperiment(Experiment):

    # Sample information
    sample = "CSHE"
    comment = "Bit Error Rate with nTron pulses"
    # Parameters
    field = FloatParameter(default=0.0, unit="T")
    nTron_voltage = FloatParameter(default=0.2, unit="V")
    nTron_duration = FloatParameter(default=1e-9, unit="s")
    attempts = IntParameter(default=1 << 10)

    # Constants (set with attribute access if you want to change these!)
    settle_delay = 200e-6
    measure_current = 3.0e-6
    samps_per_trig = 5

    polarity = 1

    min_daq_voltage = 0.0
    max_daq_voltage = 0.4

    reset_amplitude = 0.2
    reset_duration = 5.0e-9

    # Things coming back
    daq_buffer = OutputConnector()

    # Instrument resources
    mag = AMI430("192.168.5.109")
    # lock  = SR865("USB0::0xB506::0x2000::002638::INSTR")
    # pspl  = Picosecond10070A("GPIB0::24::INSTR")
    # atten = Attenuator("calibration/RFSA2113SB_HPD_20160706.csv", lock.set_ao2, lock.set_ao3)
    arb = KeysightM8190A("192.168.5.108")
    keith = Keithley2400("GPIB0::25::INSTR")

    def init_instruments(self):

        # ===================
        #    Setup the Keithley
        # ===================

        self.keith.triad()
        self.keith.conf_meas_res(res_range=1e5)
        self.keith.conf_src_curr(comp_voltage=0.5, curr_range=1.0e-5)
        self.keith.current = self.measure_current
        self.mag.ramp()

        # ===================
        #    Setup the AWG
        # ===================

        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        self.nTron_control_voltage = nTron_voltage_lookup()
        self.setup_arb(self.nTron_voltage.value)

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.nTron_voltage.assign_method(self.setup_arb)

    def setup_arb(self, vpeak):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        reset_wf = arb_pulse(-self.polarity * self.reset_amplitude,
                             self.reset_duration)
        wf_data = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        no_reset_wf = arb_pulse(0.0, 3.0 / 12e9)
        wf_data = KeysightM8190A.create_binary_wf_data(no_reset_wf)
        no_rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, no_rst_segment_id)

        # nTron waveforms
        volt = self.polarity * self.nTron_control_voltage(vpeak)
        logger.debug("Set nTron pulse: {}V -> AWG {}V, {}s".format(
            vpeak, volt, self.nTron_duration.value))
        ntron_wf = ntron_pulse(amplitude=volt,
                               fall_time=self.nTron_duration.value)
        wf_data = KeysightM8190A.create_binary_wf_data(ntron_wf)
        ntron_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, ntron_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts.value))
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        # seq.add_waveform(pspl_trig_segment_id)
        seq.add_waveform(ntron_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)

        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # ===================
        #   Setup the NIDAQ
        # ===================

        self.analog_input = Task()
        self.read = int32()
        self.buf_points = 2 * self.samps_per_trig * self.attempts.value
        self.analog_input.CreateAIVoltageChan("Dev1/ai1", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

    def init_streams(self):
        # Baked in data axes
        descrip = DataStreamDescriptor()
        descrip.add_axis(DataAxis("samples", range(self.samps_per_trig)))
        descrip.add_axis(DataAxis("state", range(2)))
        descrip.add_axis(DataAxis("attempts", range(self.attempts.value)))
        self.daq_buffer.set_descriptor(descrip)

    async def run(self):
        """This is run for each step in a sweep."""
        self.arb.advance()
        self.arb.trigger()
        buf = np.empty(self.buf_points)
        self.analog_input.ReadAnalogF64(self.buf_points, -1,
                                        DAQmx_Val_GroupByChannel, buf,
                                        self.buf_points, byref(self.read),
                                        None)
        await self.daq_buffer.push(buf)
        # Seemingly we need to give the filters some time to catch up here...
        await asyncio.sleep(0.02)
        logger.debug("Stream has filled {} of {} points".format(
            self.daq_buffer.points_taken, self.daq_buffer.num_points()))

    def shutdown_instruments(self):
        self.keith.current = 0.0e-5
        # self.mag.zero()
        self.arb.stop()
        try:
            self.analog_input.StopTask()
        except Exception as e:
            print(
                "Warning: failed to stop task (this normally happens with no consequences when taking multiple samples per trigger)."
            )
            pass
Ejemplo n.º 12
0
class nTronSwitchingExperiment(Experiment):

    # Parameters
    channel_bias = FloatParameter(default=0.05, unit="V")  # On the 33220A
    gate_bias = FloatParameter(default=0.0, unit="V")  # On the M8190A

    # Constants (set with attribute access if you want to change these!)
    attempts = 1 << 8
    samples = 384  #1024 + 16*20
    measure_amplitude = 0.1
    measure_duration = 250.0e-9
    measure_frequency = 100e6

    # arb
    sample_rate = 12e9
    repeat_time = 4 * 2.4e-6  # Picked very carefully for 100ns alignment

    # Things coming back
    voltage = OutputConnector()

    # Instrument resources
    arb = KeysightM8190A("192.168.5.108")
    awg = Agilent33220A("192.168.5.198")
    alz = AlazarATS9870("1")

    def __init__(self, gate_amps, gate_durs):
        self.gate_amps = gate_amps
        self.gate_durs = gate_durs
        super(nTronSwitchingExperiment, self).__init__()

    def init_instruments(self):

        self.awg.function = 'Pulse'
        self.awg.frequency = 0.5e6
        self.awg.pulse_width = 1e-6
        self.awg.low_voltage = 0.0
        self.awg.high_voltage = self.channel_bias.value
        self.awg.burst_state = True
        self.awg.burst_cycles = 1
        self.awg.trigger_source = "External"
        self.awg.output = True

        self.ch = AlazarChannel({'channel': 1})
        self.alz.add_channel(self.ch)
        alz_cfg = {
            'acquire_mode': 'digitizer',
            'bandwidth': 'Full',
            'clock_type': 'ref',
            'delay': 850e-9,
            'enabled': True,
            'label': "Alazar",
            'record_length': self.samples,
            'nbr_segments': len(self.gate_amps) * len(self.gate_durs),
            'nbr_waveforms': 1,
            'nbr_round_robins': self.attempts,
            'sampling_rate': 1e9,
            'trigger_coupling': 'DC',
            'trigger_level': 125,
            'trigger_slope': 'rising',
            'trigger_source': 'Ext',
            'vertical_coupling': 'AC',
            'vertical_offset': 0.0,
            'vertical_scale': 0.1,
        }
        self.alz.set_all(alz_cfg)
        self.loop.add_reader(self.alz.get_socket(self.ch),
                             self.alz.receive_data, self.ch, self.voltage)

        self.arb.set_output(True, channel=2)
        self.arb.set_output(True, channel=1)
        self.arb.sample_freq = self.sample_rate
        self.arb.set_waveform_output_mode("WSPEED", channel=1)
        self.arb.set_waveform_output_mode("WSPEED", channel=2)
        self.arb.set_output_route("DC", channel=1)
        self.arb.set_output_route("DC", channel=2)
        self.arb.set_output_complement(False, channel=1)
        self.arb.set_output_complement(False, channel=2)
        self.arb.set_voltage_amplitude(1.0, channel=1)
        self.arb.set_voltage_amplitude(1.0, channel=2)
        self.arb.continuous_mode = False
        self.arb.gate_mode = False
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.set_marker_level_low(0.0, channel=2, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=2, marker_type="sync")

        self.setup_arb(
        )  #self.gate_bias.value, self.gate_pulse_amplitude.value, self.gate_pulse_duration.value) # Sequencing goes here

    def setup_arb(
            self):  #, gate_bias, gate_pulse_amplitude, gate_pulse_duration):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        seg_ids_ch1 = []
        seg_ids_ch2 = []

        # For the measurements pulses along the channel
        wf = measure_pulse(amplitude=self.measure_amplitude,
                           duration=self.measure_duration,
                           frequency=self.measure_frequency)
        wf_data = KeysightM8190A.create_binary_wf_data(wf, sync_mkr=1)
        seg_id = self.arb.define_waveform(len(wf_data), channel=1)
        self.arb.upload_waveform(wf_data, seg_id, channel=1)
        seg_ids_ch1.append(seg_id)

        # Build in a delay between sequences
        settle_pts = 640 * np.int(
            np.ceil(self.repeat_time * self.sample_rate / 640))
        # settle_pts2 = 640*np.ceil(8*2.4e-9 * self.sample_rate / 640)

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=self.attempts * len(self.gate_amps) *
                       len(self.gate_durs))
        for si in seg_ids_ch1:
            seq.add_waveform(si)
            seq.add_idle(settle_pts, 0.0)
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0, channel=1)

        for amp in self.gate_amps:
            for dur in self.gate_durs:
                # For the switching pulses along the gate
                wf = switching_pulse(
                    amplitude=amp,
                    duration=dur)  #self.gate_pulse_duration.value)
                wf_data = KeysightM8190A.create_binary_wf_data(wf)
                seg_id = self.arb.define_waveform(len(wf_data), channel=2)
                self.arb.upload_waveform(wf_data, seg_id, channel=2)
                seg_ids_ch2.append(seg_id)

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=self.attempts)
        for si in seg_ids_ch2:
            seq.add_waveform(si)
            seq.add_idle(settle_pts, 0.0)
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0, channel=2)

        self.arb.set_sequence_mode("SCENARIO", channel=1)
        self.arb.set_scenario_advance_mode("SINGLE", channel=1)
        self.arb.set_scenario_start_index(0, channel=1)
        self.arb.set_sequence_mode("SCENARIO", channel=2)
        self.arb.set_scenario_advance_mode("SINGLE", channel=2)
        self.arb.set_scenario_start_index(0, channel=2)
        self.arb.initiate(channel=1)
        self.arb.initiate(channel=2)
        self.arb.advance()

    def init_streams(self):
        # Baked in data axes
        descrip = DataStreamDescriptor()
        descrip.add_axis(DataAxis("time", 1e-9 * np.arange(self.samples)))
        if len(self.gate_durs) > 1:
            descrip.add_axis(DataAxis("gate_pulse_duration", self.gate_durs))
        descrip.add_axis(DataAxis("gate_pulse_amplitude", self.gate_amps))
        descrip.add_axis(DataAxis("attempt", range(self.attempts)))

        self.voltage.set_descriptor(descrip)

    async def run(self):
        # self.arb.stop()
        self.arb.set_scenario_start_index(0, channel=1)
        self.arb.set_scenario_start_index(0, channel=2)
        self.arb.advance()
        await asyncio.sleep(0.3)
        self.alz.acquire()
        await asyncio.sleep(0.3)
        self.arb.trigger()
        await self.alz.wait_for_acquisition(10.0)
        await asyncio.sleep(0.8)
        self.alz.stop()
        # Seemingly we need to give the filters some time to catch up here...
        await asyncio.sleep(0.02)
        logger.info("Stream has filled {} of {} points".format(
            self.voltage.points_taken, self.voltage.num_points()))

    def shutdown_instruments(self):
        self.awg.output = False

        self.arb.stop()
        self.loop.remove_reader(self.alz.get_socket(self.ch))

        for name, instr in self._instruments.items():
            instr.disconnect()
Ejemplo n.º 13
0

def measure_pulse(amplitude, duration, frequency, sample_rate=12e9):
    pulse_points = int(duration * sample_rate)
    if pulse_points < 320:
        wf = np.zeros(320)
    else:
        wf = np.zeros(64 * np.ceil(pulse_points / 64.0))
    wf[:pulse_points] = amplitude * np.sin(
        2.0 * np.pi * frequency * np.arange(pulse_points) / sample_rate)
    wf = np.append(np.zeros(1 << 13), wf)
    return wf


# Instrument resources
arb = KeysightM8190A("192.168.5.108")
arb.connect()

arb.set_output(True, channel=2)
arb.set_output(True, channel=1)
arb.sample_freq = 10.0e9
arb.set_waveform_output_mode("WSPEED", channel=1)
arb.set_waveform_output_mode("WSPEED", channel=2)
arb.set_output_route("DC", channel=1)
arb.set_output_route("DC", channel=2)
arb.set_output_complement(False, channel=1)
arb.set_output_complement(False, channel=2)
arb.voltage_amplitude = 1.0
arb.continuous_mode = False
arb.gate_mode = False
arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
Ejemplo n.º 14
0
    def init_instruments(self):
        # ===================
        #    Setup the Lockin
        # ===================
        self.lock.tc = self.tc
        self.lock.filter_slope = self.fdB
        self.lock.amp = self.res_reference * self.measure_current
        sense_vals = np.array(self.lock.SENSITIVITY_VALUES)
        self.lock.sensitivity = sense_vals[np.argmin(
            np.absolute(sense_vals - 2 * self.sample_resistance *
                        self.measure_current * np.ones(sense_vals.size)))]
        time.sleep(20 * self.lock.measure_delay())

        # Rescale lockin analogue output for NIDAQ
        self.lock.r_offset_enable = True
        #self.lock.r_expand = 10
        #self.lock.r_offset = 100 * ((self.sample_resistance*self.measure_current/self.lock.sensitivity) - (0.5/self.lock.r_expand))
        self.lock.r_expand = 100
        self.lock.auto_offset("R")
        self.lock.r_offset = 0.995 * self.lock.r_offset
        time.sleep(20 * self.lock.measure_delay())

        self.mag.ramp()
        self.atten.set_supply_method(self.lock.set_ao2)
        self.atten.set_control_method(self.lock.set_ao3)

        # Setup the AWG
        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()
        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        def arb_pulse(amplitude, duration, sample_rate=12e9):
            arb_voltage = arb_voltage_lookup()
            pulse_points = int(duration * sample_rate)
            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64 * np.ceil(pulse_points / 64.0))
            wf[:pulse_points] = np.sign(amplitude) * arb_voltage(
                abs(amplitude))
            return wf

        reset_wf = arb_pulse(
            -self.polarity * abs(self.reset_amplitude) *
            np.power(10.0, self.circuit_attenuation / 20.0),
            self.reset_duration)
        wf_data = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        # Picosecond trigger waveform
        pspl_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                            samp_mkr=1)
        pspl_trig_segment_id = self.arb.define_waveform(len(pspl_trig_wf))
        self.arb.upload_waveform(pspl_trig_wf, pspl_trig_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.lock.measure_delay() * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        #First try with reset flipping pulse
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        seq.add_waveform(pspl_trig_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # Setup the NIDAQ
        self.analog_input = Task()
        self.read = int32()
        self.buf_points = 2 * self.samps_per_trig * self.attempts
        self.analog_input.CreateAIVoltageChan("Dev1/ai0", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

        # Setup the PSPL
        self.pspl.amplitude = self.polarity * 7.5 * np.power(
            10, (-self.pspl_base_attenuation) / 20.0)
        self.pspl.trigger_source = "EXT"
        self.pspl.trigger_level = 0.1
        self.pspl.output = True

        def set_voltage(voltage):
            # Calculate the voltage controller attenuator setting
            self.pspl.amplitude = self.polarity * 7.5 * np.power(
                10, -self.pspl_base_attenuation / 20.0)
            vc_atten = abs(
                20.0 * np.log10(abs(voltage) / 7.5)
            ) - self.pspl_base_attenuation - self.circuit_attenuation

            if vc_atten <= self.atten.minimum_atten():
                logger.error(
                    "Voltage controlled attenuation {} under range.".format(
                        vc_atten))
                raise ValueError(
                    "Voltage controlled attenuation {} under range.".format(
                        vc_atten))

            if self.atten.maximum_atten() < vc_atten:
                logger.error(
                    "Voltage controlled attenuation {} over range.".format(
                        vc_atten))
                raise ValueError(
                    "Voltage controlled attenuation {} over range.".format(
                        vc_atten))

            self.atten.set_attenuation(vc_atten)
            time.sleep(0.02)

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.pulse_duration.assign_method(self.pspl.set_duration)
        self.pulse_voltage.assign_method(set_voltage)

        # Create hooks for relevant delays
        self.pulse_duration.add_post_push_hook(lambda: time.sleep(0.1))
Ejemplo n.º 15
0
class SwitchingExperiment(Experiment):

    # Parameters and outputs
    field = FloatParameter(default=0.0, unit="T")
    pulse_duration = FloatParameter(default=5.0e-9, unit="s")
    pulse_voltage = FloatParameter(default=0.1, unit="V")
    voltage = OutputConnector()

    # Constants (set with attribute access if you want to change these!)
    attempts = 1 << 9
    settle_delay = 100e-6
    measure_current = 3.0e-6
    samps_per_trig = 15
    polarity = 1
    pspl_atten = 4
    min_daq_voltage = -1
    max_daq_voltage = 1
    reset_amplitude = 0.2
    reset_duration = 5.0e-9
    circuit_attenuation = 20.0
    tc = 300e-6

    # Instrument Resources
    mag = AMI430("192.168.5.109")
    lock = SR865("USB0::0xB506::0x2000::002638::INSTR")
    pspl = Picosecond10070A("GPIB0::24::INSTR")
    atten = Attenuator("calibration/RFSA2113SB_HPD_20160901.csv", lock.set_ao2,
                       lock.set_ao3)
    arb = KeysightM8190A("192.168.5.108")

    # keith = Keithley2400("GPIB0::25::INSTR")

    def init_streams(self):
        descrip = DataStreamDescriptor()
        descrip.data_name = 'voltage'
        descrip.add_axis(DataAxis("sample", range(self.samps_per_trig)))
        descrip.add_axis(DataAxis("state", range(2)))
        descrip.add_axis(DataAxis("attempt", range(self.attempts)))
        self.voltage.set_descriptor(descrip)

    def init_instruments(self):
        self.lock.tc = self.tc

        # Setup the Keithley
        # self.keith.triad()
        # self.keith.conf_meas_res(res_range=1e5)
        # self.keith.conf_src_curr(comp_voltage=0.5, curr_range=1.0e-5)
        # self.keith.current = self.measure_current
        self.mag.ramp()

        # Setup the AWG
        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()
        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        def arb_pulse(amplitude, duration, sample_rate=12e9):
            arb_voltage = arb_voltage_lookup()
            pulse_points = int(duration * sample_rate)
            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64 * np.ceil(pulse_points / 64.0))
            wf[:pulse_points] = np.sign(amplitude) * arb_voltage(
                abs(amplitude))
            return wf

        reset_wf = arb_pulse(
            -self.polarity * self.reset_amplitude *
            np.power(10.0, self.circuit_attenuation / 20.0),
            self.reset_duration)
        wf_data = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        # no_reset_wf = arb_pulse(0.0, 3.0/12e9)
        # wf_data     = KeysightM8190A.create_binary_wf_data(no_reset_wf)
        # no_rst_segment_id  = self.arb.define_waveform(len(wf_data))
        # self.arb.upload_waveform(wf_data, no_rst_segment_id)

        # Picosecond trigger waveform
        pspl_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                            samp_mkr=1)
        pspl_trig_segment_id = self.arb.define_waveform(len(pspl_trig_wf))
        self.arb.upload_waveform(pspl_trig_wf, pspl_trig_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        #First try with reset flipping pulse
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        seq.add_waveform(pspl_trig_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # Setup the NIDAQ
        self.analog_input = Task()
        self.read = int32()
        self.buf_points = 2 * self.samps_per_trig * self.attempts
        self.analog_input.CreateAIVoltageChan("Dev1/ai0", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

        # Setup the PSPL
        self.pspl.amplitude = self.polarity * 7.5 * np.power(
            10, (-self.pspl_atten) / 20.0)
        self.pspl.trigger_source = "EXT"
        self.pspl.trigger_level = 0.1
        self.pspl.output = True

        def set_voltage(voltage):
            # Calculate the voltage controller attenuator setting
            vc_atten = abs(20.0 * np.log10(abs(voltage) / 7.5)
                           ) - self.pspl_atten - self.circuit_attenuation
            if vc_atten <= 6.0:
                raise ValueError(
                    "Voltage controlled attenuation under range (6dB).")
            self.atten.set_attenuation(vc_atten)
            time.sleep(0.02)

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.pulse_duration.assign_method(self.pspl.set_duration)
        self.pulse_voltage.assign_method(set_voltage)

        # Create hooks for relevant delays
        self.pulse_duration.add_post_push_hook(lambda: time.sleep(0.1))

    async def run(self):
        """This is run for each step in a sweep."""
        self.arb.advance()
        self.arb.trigger()
        buf = np.empty(self.buf_points)
        self.analog_input.ReadAnalogF64(self.buf_points, -1,
                                        DAQmx_Val_GroupByChannel, buf,
                                        self.buf_points, byref(self.read),
                                        None)
        await self.voltage.push(buf)
        # Seemingly we need to give the filters some time to catch up here...
        await asyncio.sleep(0.02)
        logger.debug("Stream has filled {} of {} points".format(
            self.voltage.points_taken, self.voltage.num_points()))

    def shutdown_instruments(self):
        # self.keith.current = 0.0e-5
        # self.mag.zero()
        self.arb.stop()
        self.pspl.output = False
        try:
            self.analog_input.StopTask()
        except Exception as e:
            print(
                "Warning: failed to stop task (this normally happens with no consequences when taking multiple samples per trigger)."
            )
            pass
Ejemplo n.º 16
0
    def init_instruments(self):
        self.lock.tc = self.tc

        # Setup the Keithley
        # self.keith.triad()
        # self.keith.conf_meas_res(res_range=1e5)
        # self.keith.conf_src_curr(comp_voltage=0.5, curr_range=1.0e-5)
        # self.keith.current = self.measure_current
        self.mag.ramp()

        # Setup the AWG
        self.arb.set_output(True, channel=1)
        self.arb.set_output(False, channel=2)
        self.arb.sample_freq = 12.0e9
        self.arb.waveform_output_mode = "WSPEED"
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()
        self.arb.set_output_route("DC", channel=1)
        self.arb.voltage_amplitude = 1.0
        self.arb.set_marker_level_low(0.0, channel=1, marker_type="sync")
        self.arb.set_marker_level_high(1.5, channel=1, marker_type="sync")
        self.arb.continuous_mode = False
        self.arb.gate_mode = False

        def arb_pulse(amplitude, duration, sample_rate=12e9):
            arb_voltage = arb_voltage_lookup()
            pulse_points = int(duration * sample_rate)
            if pulse_points < 320:
                wf = np.zeros(320)
            else:
                wf = np.zeros(64 * np.ceil(pulse_points / 64.0))
            wf[:pulse_points] = np.sign(amplitude) * arb_voltage(
                abs(amplitude))
            return wf

        reset_wf = arb_pulse(
            -self.polarity * self.reset_amplitude *
            np.power(10.0, self.circuit_attenuation / 20.0),
            self.reset_duration)
        wf_data = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        # no_reset_wf = arb_pulse(0.0, 3.0/12e9)
        # wf_data     = KeysightM8190A.create_binary_wf_data(no_reset_wf)
        # no_rst_segment_id  = self.arb.define_waveform(len(wf_data))
        # self.arb.upload_waveform(wf_data, no_rst_segment_id)

        # Picosecond trigger waveform
        pspl_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                            samp_mkr=1)
        pspl_trig_segment_id = self.arb.define_waveform(len(pspl_trig_wf))
        self.arb.upload_waveform(pspl_trig_wf, pspl_trig_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))

        scenario = Scenario()
        seq = Sequence(sequence_loop_ct=int(self.attempts))
        #First try with reset flipping pulse
        seq.add_waveform(rst_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        seq.add_waveform(pspl_trig_segment_id)
        seq.add_idle(settle_pts, 0.0)
        seq.add_waveform(nidaq_trig_segment_id)
        seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
        scenario.sequences.append(seq)
        self.arb.upload_scenario(scenario, start_idx=0)
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "REPEAT"
        self.arb.scenario_start_index = 0
        self.arb.run()

        # Setup the NIDAQ
        self.analog_input = Task()
        self.read = int32()
        self.buf_points = 2 * self.samps_per_trig * self.attempts
        self.analog_input.CreateAIVoltageChan("Dev1/ai0", "", DAQmx_Val_Diff,
                                              self.min_daq_voltage,
                                              self.max_daq_voltage,
                                              DAQmx_Val_Volts, None)
        self.analog_input.CfgSampClkTiming("", 1e6, DAQmx_Val_Rising,
                                           DAQmx_Val_FiniteSamps,
                                           self.samps_per_trig)
        self.analog_input.CfgInputBuffer(self.buf_points)
        self.analog_input.CfgDigEdgeStartTrig("/Dev1/PFI0", DAQmx_Val_Rising)
        self.analog_input.SetStartTrigRetriggerable(1)
        self.analog_input.StartTask()

        # Setup the PSPL
        self.pspl.amplitude = self.polarity * 7.5 * np.power(
            10, (-self.pspl_atten) / 20.0)
        self.pspl.trigger_source = "EXT"
        self.pspl.trigger_level = 0.1
        self.pspl.output = True

        def set_voltage(voltage):
            # Calculate the voltage controller attenuator setting
            vc_atten = abs(20.0 * np.log10(abs(voltage) / 7.5)
                           ) - self.pspl_atten - self.circuit_attenuation
            if vc_atten <= 6.0:
                raise ValueError(
                    "Voltage controlled attenuation under range (6dB).")
            self.atten.set_attenuation(vc_atten)
            time.sleep(0.02)

        # Assign methods
        self.field.assign_method(self.mag.set_field)
        self.pulse_duration.assign_method(self.pspl.set_duration)
        self.pulse_voltage.assign_method(set_voltage)

        # Create hooks for relevant delays
        self.pulse_duration.add_post_push_hook(lambda: time.sleep(0.1))
    def setup_arb(self):
        self.arb.abort()
        self.arb.delete_all_waveforms()
        self.arb.reset_sequence_table()

        reset_wf = arb_pulse(-self.polarity * self.reset_amplitude,
                             self.reset_duration)
        wf_data = KeysightM8190A.create_binary_wf_data(reset_wf)
        rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, rst_segment_id)

        no_reset_wf = arb_pulse(0.0, 3.0 / 12e9)
        wf_data = KeysightM8190A.create_binary_wf_data(no_reset_wf)
        no_rst_segment_id = self.arb.define_waveform(len(wf_data))
        self.arb.upload_waveform(wf_data, no_rst_segment_id)

        # nTron waveforms
        nTron_control_voltage = pulse_voltage_lookup()
        nTron_segment_ids = []
        for dur, vpeak in zip(self.pulse_durations, self.pulse_voltages):
            volt = self.polarity * nTron_control_voltage(vpeak)
            logger.debug("Set nTron pulse: {}V -> AWG {}V, {}s".format(
                vpeak, volt, dur))
            ntron_wf = ntron_pulse(amplitude=volt, fall_time=dur)
            wf_data = KeysightM8190A.create_binary_wf_data(ntron_wf)
            ntron_segment_id = self.arb.define_waveform(len(wf_data))
            self.arb.upload_waveform(wf_data, ntron_segment_id)
            nTron_segment_ids.append(ntron_segment_id)

        # NIDAQ trigger waveform
        nidaq_trig_wf = KeysightM8190A.create_binary_wf_data(np.zeros(3200),
                                                             sync_mkr=1)
        nidaq_trig_segment_id = self.arb.define_waveform(len(nidaq_trig_wf))
        self.arb.upload_waveform(nidaq_trig_wf, nidaq_trig_segment_id)

        settle_pts = int(640 * np.ceil(self.settle_delay * 12e9 / 640))

        self.start_idxs = [0]
        self.start_id = 0
        for si in nTron_segment_ids:
            scenario = Scenario()
            seq = Sequence(sequence_loop_ct=int(self.attempts))
            seq.add_waveform(rst_segment_id)
            seq.add_idle(settle_pts, 0.0)
            seq.add_waveform(nidaq_trig_segment_id)
            seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
            # seq.add_waveform(pspl_trig_segment_id)
            seq.add_waveform(si)
            seq.add_idle(settle_pts, 0.0)
            seq.add_waveform(nidaq_trig_segment_id)
            seq.add_idle(1 << 16, 0.0)  # bonus non-contiguous memory delay
            scenario.sequences.append(seq)
            self.arb.upload_scenario(scenario, start_idx=self.start_idxs[-1])
            self.start_idxs.append(self.start_idxs[-1] +
                                   len(scenario.scpi_strings()))

        # The last entry is eroneous
        self.start_idxs = self.start_idxs[:-1]
        self.arb.sequence_mode = "SCENARIO"
        self.arb.scenario_advance_mode = "SINGLE"
        self.arb.scenario_start_index = 0