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 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()
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()
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()
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()
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()
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
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
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()
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")
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))
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
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