diff --git a/pulse_lib/tests/channel_timing/__init__.py b/pulse_lib/tests/channel_timing/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/channel_timing/test_delays.py b/pulse_lib/tests/channel_timing/test_delays.py new file mode 100644 index 0000000000000000000000000000000000000000..0095200c298dbb7f3b347a9c13076436ded884ba --- /dev/null +++ b/pulse_lib/tests/channel_timing/test_delays.py @@ -0,0 +1,38 @@ + +from pulse_lib.tests.configurations.test_configuration import context + +def test(): + pulse = context.init_pulselib(n_gates=2, n_qubits=3, n_sensors=2, n_markers=1) + + s = pulse.mk_segment() + + s.P1.add_block(0, 20, 100) + s.P2.add_block(0, 20, -100) + s.M1.add_marker(0, 20) + s.q1.add_MW_pulse(0, 20, 100, 2.450e9) + s.q3.add_MW_pulse(0, 20, 100, 2.650e9) + s.SD1.acquire(0, 100) + s.SD2.acquire(0, 100) + +# context.plot_segments([s]) + + sequence = pulse.mk_sequence([s]) + sequence.n_rep = 1 + context.add_hw_schedule(sequence) + context.plot_awgs(sequence, print_acquisitions=True) + + # now with other delays + pulse.add_channel_delay('P1', -20) + pulse.add_channel_delay('M1', 40) + pulse.add_channel_delay('SD1', 20) + pulse.add_channel_delay('SD2', 20) + + sequence = pulse.mk_sequence([s]) + sequence.n_rep = 1 + context.add_hw_schedule(sequence) + context.plot_awgs(sequence, print_acquisitions=True) + + return None + +if __name__ == '__main__': + ds = test() diff --git a/pulse_lib/tests/configurations/__init__.py b/pulse_lib/tests/configurations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/configurations/configurations.yaml b/pulse_lib/tests/configurations/configurations.yaml new file mode 100644 index 0000000000000000000000000000000000000000..105c7486d98533160f658fa7c0d3732e3017673f --- /dev/null +++ b/pulse_lib/tests/configurations/configurations.yaml @@ -0,0 +1,92 @@ +default: KeysightMocked + +KeysightMocked: + station: keysight_mocked.yaml + backend: Keysight + awg_channels: + AWG1: [P1,P2,P3,] + AWG2: [P4,P5,P6,P7] + AWG3: [I1,Q1,I2,Q2] + markers: + M1: [AWG1,4] + M_IQ: [AWG3,0] + sensors: + SD1: [Dig1,1] + SD2: [Dig1,2] + rf: + SD2: + output: M1 + startup_time: 500 + runner: qcodes + + +KeysightQSMocked: + station: keysight_qs_mocked.yaml + backend: Keysight_QS + awg_channels: + AWG1: [P1,P2,P3,] + AWG2: [P4,P5,P6,P7] + AWG3: [I1,Q1,I2,Q2] + markers: + M1: [AWG1,4] + M_IQ: [AWG3,0] + sensors: + SD1: [Dig1,1] + SD2: [Dig1,2] + runner: core_tools + + +QbloxMocked: + station: qblox_mocked.yaml + backend: Qblox + awg_channels: + QCM1: [P1,P2,P3,] + QCM2: [P4,P5,P6,P7] + QCM3: [I1,Q1,I2,Q2] + markers: + M1: [QCM1,1] + M_IQ: [QCM3,1] + sensors: + SD1: [QRM1,1] + SD2: [QRM1,2] + rf: + SD2: + output: [QRM1,1] + frequency: 2e6 + amplitude: 400 + startup_time: 0 + runner: core_tools + + +TektronixMocked: + station: tektronix_mocked.yaml + backend: Tektronix_5014 + awg_channels: + AWG1: [P1,P2,P3,] + AWG2: [P4,P5,P6,P7] + AWG3: [I1,Q1,I2,Q2] + markers: + M1: [AWG1,[1,1]] + M_M4i: [AWG1,[4,2]] + M_IQ: [AWG3,[1,1]] + sensors: + SD1: [Dig1,1] + SD2: [Dig1,2] + runner: qcodes + + +QbloxV1: + station: qblox_v1.yaml + backend: Qblox + awg_channels: + Qblox_module2: [P1,P2,P3,] + Qblox_module4: [P4,P5,P6,P7] + Qblox_module6: [I1,Q1,I2,Q2] + markers: + M1: [Qblox_module2,1] + M_IQ: [Qblox_module6,1] + dig_channels: + SD1: [Qblox_module8,1] + SD2: [Qblox_module8,2] + runner: core_tools + diff --git a/pulse_lib/tests/configurations/ct_config.yaml b/pulse_lib/tests/configurations/ct_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2ff964bbc3ee502fa95d4dd221eb66efa79f17ee --- /dev/null +++ b/pulse_lib/tests/configurations/ct_config.yaml @@ -0,0 +1,16 @@ +# selection used in databrowser. Any is an allowed value here. +setup: Test +project: Pulselib +sample: yaml_configuration + +local_database: + user: sdesnoo + password: FastSp!ns + database: sds_test + +logging: + disabled: true + +databrowser: + datasource: local # required value + diff --git a/pulse_lib/tests/configurations/keysight_mocked.yaml b/pulse_lib/tests/configurations/keysight_mocked.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6d5b3f552d3d077894bed21395986b46472d4498 --- /dev/null +++ b/pulse_lib/tests/configurations/keysight_mocked.yaml @@ -0,0 +1,89 @@ +instruments: + + sig_gen1: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + sig_gen2: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + AWG1: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 2 + + AWG2: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 3 + + AWG3: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 4 + + AWG4: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 5 + + AWG5: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 6 + + AWG6: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 7 + + AWG7: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 8 + + AWG8: + type: pulse_lib.tests.mock_m3202a.MockM3202A_fpga + enable_forced_reconnect : True + init: + chassis : 1 + slot : 9 + + Dig1: + type: pulse_lib.tests.mock_m3102a.MockM3102A + enable_forced_reconnect: true + init: + chassis: 1 + slot: 11 + + Dig2: + type: pulse_lib.tests.mock_m3102a.MockM3102A + enable_forced_reconnect: true + init: + chassis: 1 + slot: 12 diff --git a/pulse_lib/tests/configurations/keysight_qs_mocked.yaml b/pulse_lib/tests/configurations/keysight_qs_mocked.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8143a2dbbd23fd28fe7d3f7e40d86ce4a326cdaa --- /dev/null +++ b/pulse_lib/tests/configurations/keysight_qs_mocked.yaml @@ -0,0 +1,89 @@ +instruments: + + sig_gen1: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + sig_gen2: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + AWG1: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 2 + + AWG2: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 3 + + AWG3: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 4 + + AWG4: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 5 + + AWG5: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 6 + + AWG6: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 7 + + AWG7: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 8 + + AWG8: + type: pulse_lib.tests.mock_m3202a_qs.MockM3202A_QS + enable_forced_reconnect : True + init: + chassis : 1 + slot : 9 + + Dig1: + type: pulse_lib.tests.mock_m3102a_qs.MockM3102A_QS + enable_forced_reconnect: true + init: + chassis: 1 + slot: 11 + + Dig2: + type: pulse_lib.tests.mock_m3102a_qs.MockM3102A_QS + enable_forced_reconnect: true + init: + chassis: 1 + slot: 12 diff --git a/pulse_lib/tests/configurations/qblox_mocked.yaml b/pulse_lib/tests/configurations/qblox_mocked.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bfc6b7438dc5863018f1dd0959a18244ce94360c --- /dev/null +++ b/pulse_lib/tests/configurations/qblox_mocked.yaml @@ -0,0 +1,49 @@ +instruments: + + sig_gen1: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + sig_gen2: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + QCM1: + type: q1simulator.Q1Simulator + enable_forced_reconnect : True + init: + sim_type: QCM + + QCM2: + type: q1simulator.Q1Simulator + enable_forced_reconnect : True + init: + sim_type: QCM + + QCM3: + type: q1simulator.Q1Simulator + enable_forced_reconnect : True + init: + sim_type: QCM + + QRM1: + type: q1simulator.Q1Simulator + enable_forced_reconnect : True + init: + sim_type: QRM + + QRM2: + type: q1simulator.Q1Simulator + enable_forced_reconnect : True + init: + sim_type: QRM diff --git a/pulse_lib/tests/configurations/tektronix_mocked.yaml b/pulse_lib/tests/configurations/tektronix_mocked.yaml new file mode 100644 index 0000000000000000000000000000000000000000..77221faaf1073e62e2a3e8f66dcde97481a50687 --- /dev/null +++ b/pulse_lib/tests/configurations/tektronix_mocked.yaml @@ -0,0 +1,39 @@ +instruments: + + sig_gen1: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + sig_gen2: + type: qcodes.tests.instrument_mocks.DummyInstrument + enable_forced_reconnect: true + init: + gates: ['frequency','power'] + parameters: + frequency: + limits: [0,20e9] + + AWG1: + type: pulse_lib.tests.mock_tektronix5014.MockTektronix5014 + enable_forced_reconnect : True + + AWG2: + type: pulse_lib.tests.mock_tektronix5014.MockTektronix5014 + enable_forced_reconnect : True + + AWG3: + type: pulse_lib.tests.mock_tektronix5014.MockTektronix5014 + enable_forced_reconnect : True + + AWG4: + type: pulse_lib.tests.mock_tektronix5014.MockTektronix5014 + enable_forced_reconnect : True + + Dig1: + type: pulse_lib.tests.mock_m4i.MockM4i + enable_forced_reconnect: true diff --git a/pulse_lib/tests/configurations/test_configuration.py b/pulse_lib/tests/configurations/test_configuration.py new file mode 100644 index 0000000000000000000000000000000000000000..bd5df81ef566e19f3785875b29acbfe1fbc4ad43 --- /dev/null +++ b/pulse_lib/tests/configurations/test_configuration.py @@ -0,0 +1,305 @@ +import logging +import os +import math +from collections.abc import Sequence +import matplotlib.pyplot as pt +import numpy as np + +import qcodes as qc +import qcodes.logger as logger +from qcodes.logger import start_all_logging +from qcodes.data.data_set import DataSet +from qcodes.data.io import DiskIO + +from ruamel.yaml import YAML + +from pulse_lib.tests.utils.qc_run import qc_run +from pulse_lib.base_pulse import pulselib +from pulse_lib.virtual_channel_constructors import IQ_channel_constructor +from pulse_lib.tests.hw_schedule_mock import HardwareScheduleMock +from pulse_lib.schedule.tektronix_schedule import TektronixSchedule + +try: + import core_tools as ct + from core_tools.sweeps.sweeps import do0D + _ct_imported = True + _ct_configured = False +except: + _ct_imported = False + + +def init_logging(): + start_all_logging() + logger.get_console_handler().setLevel(logging.WARN) + logger.get_file_handler().setLevel(logging.DEBUG) + + +class Context: + def __init__(self): + self._dir = os.path.dirname(__file__) + self._load_configurations() + cfg = self.configurations + self.load_configuration(cfg['default']) + + def _load_configurations(self): + with open(self._dir + '/configurations.yaml') as fp: + yaml = YAML() + self.configurations = yaml.load(fp) + + def load_configuration(self, config_name): + self.configuration_name = config_name + self._configuration = self.configurations[config_name] + self._load_station(self._configuration['station']) + + def close_station(self): + if qc.Station.default is not None: + qc.Station.default.close_all_registered_instruments() + + def _load_station(self, config): + self.close_station() + config_file = os.path.join(self._dir, config) + station = qc.Station(default=True, config_file=config_file) + self.station = station + + station.load_all_instruments() + + awgs = [] + digs = [] + # map Qblox Cluster to AWG1 and digitizer + if 'Cluster' in station.components: + cluster = station.Cluster + for module in cluster.modules: + if module.present(): + rf = 'RF' if module.is_rf_type else '' + print(f' Add {module.name}: {module.module_type}{rf}') + setattr(station, module.name, module) + if module.is_qcm_type: + awgs.append(module) + else: + digs.append(module) + else: + for name,component in station.components.items(): + if name.startswith('AWG'): + awgs.append(component) + if name.startswith('Dig'): + digs.append(component) + + self.awgs = awgs + self.digitizers = digs + + def init_pulselib(self, n_gates=0, n_qubits=0, n_markers=0, + n_sensors=0, rf_sources=False, + virtual_gates=False, finish=True): + self.n_plots = 0 + cfg = self._configuration + station = self.station + backend = cfg['backend'] + if backend == 'Qblox': + from pulse_lib.qblox.pulsar_uploader import UploadAggregator + UploadAggregator.verbose = True + + pulse = pulselib(backend=backend) + self.pulse = pulse + + gate_map = {} + for awg_name,gates in cfg['awg_channels'].items(): + for i,gate in enumerate(gates): + if backend != 'Qblox': + i += 1 + gate_map[gate] = (awg_name,i) + + gates = [] + for i in range(n_gates): + gate = f'P{i+1}' + awg,channel = gate_map[gate] + if awg not in pulse.awg_devices: + pulse.add_awg(station.components[awg]) + pulse.define_channel(gate, awg, channel) + pulse.add_channel_compensation_limit(gate, (-100, 50)) +# pulse.add_channel_attenuation(name, 0.2) +# pulse.add_channel_delay(name, value) + + if virtual_gates: + n_gates = len(gates) + matrix = np.diag([0.9]*n_gates) + 0.1 + pulse.add_virtual_matrix( + name='virtual-gates', + real_gate_names=gates, + virtual_gate_names=['v'+gate for gate in gates], + matrix=matrix + ) + + for i in range(n_markers): + self._add_marker(f'M{i+1}') + + n_iq = math.ceil(n_qubits/2) + for i in range(n_iq): + I,Q = f'I{i+1}', f'Q{i+1}', + awg,channel_I = gate_map[I] + awg,channel_Q = gate_map[Q] + if awg not in pulse.awg_devices: + pulse.add_awg(station.components[awg]) + pulse.define_channel(I, awg, channel_I) + pulse.define_channel(Q, awg, channel_Q) + pulse.add_channel_delay(I, -40) + pulse.add_channel_delay(Q, -40) + sig_gen = station.components[f'sig_gen{i+1}'] + + IQ_pair = IQ_channel_constructor(pulse, f'IQ{i+1}') + IQ_pair.add_IQ_chan(I, 'I') + IQ_pair.add_IQ_chan(Q, 'Q') + IQ_pair.set_LO(sig_gen.frequency) + if i == 0: + self._add_marker('M_IQ', setup_ns=20, hold_ns=20) + pulse.add_channel_delay('M_IQ', -40) + IQ_pair.add_marker('M_IQ') + + sig_gen.frequency(2.400e9 + i*0.400e9) + # 2.400, 2.800 + # 2.450, 2.550, 2.650, 2.750 + # add qubits: q1 and q2 + for j in range(2): + qubit = 2*i+j+1 + if qubit < n_qubits+1: + idle_frequency = 2.350e9 + qubit*0.100e9 + IQ_pair.add_virtual_IQ_channel(f"q{qubit}", idle_frequency) + + if n_sensors > 0 and backend in ['Keysight']: + pulse.configure_digitizer = True + for i in range(n_sensors): + sensor = f'SD{i+1}' + digitizer,channel = cfg['sensors'][sensor] + if digitizer not in pulse.digitizers: + pulse.add_digitizer(station.components[digitizer]) + pulse.define_digitizer_channel(sensor, digitizer, channel) + + if n_sensors > 0 and backend == 'Tektronix_5014': + self._add_marker('M_M4i') + pulse.add_digitizer_marker('Dig1', 'M_M4i') + + if rf_sources: + for sensor,params in cfg['rf'].items(): + if sensor not in pulse.digitizer_channels: + continue + if backend == 'Qblox': + pulse.set_digitizer_frequency(sensor, params['frequency']) + pulse.set_digitizer_rf_source(sensor, + output=params['output'], + amplitude=params['amplitude'], + mode='pulsed', + startup_time_ns=params['startup_time']) + else: + pulse.set_digitizer_rf_source(sensor, + output=params['output'], + mode='pulsed', + startup_time_ns=params['startup_time']) + + if backend == 'Tektronix_5014': + # pulselib always wants a digitizer for Tektronix + if 'Dig1' not in pulse.digitizers: + pulse.add_digitizer(station.components['Dig1']) + + + if finish: + pulse.finish_init() + + return pulse + + def _add_marker(self, name, setup_ns=0, hold_ns=0): + cfg = self._configuration + pulse = self.pulse + awg,channel = cfg['markers'][name] + if isinstance(channel, Sequence): + channel = tuple(channel) + if awg not in pulse.awg_devices: + pulse.add_awg(self.station.components[awg]) + pulse.define_marker(name, awg, channel, setup_ns=setup_ns, hold_ns=hold_ns) + + def add_hw_schedule(self, sequence): + backend = self._configuration['backend'] + if backend in ['Keysight','Keysight_QS']: + sequence.set_hw_schedule(HardwareScheduleMock()) + elif backend == 'Tektronix_5014': + sequence.set_hw_schedule(TektronixSchedule(self.pulse)) + + def run(self, name, sequence, *params): + global _ct_configured + runner = self._configuration['runner'] + if runner == 'qcodes': + path = 'C:/measurements/test_pulselib' + DataSet.default_io = DiskIO(path) + return qc_run(name, sequence, *params) + + elif runner == 'core_tools': + if not _ct_imported: + raise Exception('core_tools import failed') + if not _ct_configured: + ct.configure(os.path.join(self._dir, 'ct_config.yaml')) + _ct_configured = True + ct.set_sample_info(sample=self.configuration_name) + return do0D(sequence, *params, name=name).run() + + else: + print(f'no implementation for {runner}') + + def plot_awgs(self, sequence, index=None, print_acquisitions=False, **kwargs): + job = sequence.upload(index) + sequence.play(index) + pulse = self.pulse + pt.ioff() + for awg in list(pulse.awg_devices.values()) + list(pulse.digitizers.values()): + if hasattr(awg, 'plot'): + pt.figure() + awg.plot() + pt.legend() + pt.grid() + pt.ylabel('amplitude [V]') + pt.xlabel('time [ns]') + pt.title(f'AWG upload {awg.name}') + for (method, arguments) in kwargs.items(): + getattr(pt, method)(*arguments) + self._savefig() + + if print_acquisitions: + backend = self._configuration['backend'] + if backend == 'Keysight': + print(sequence.hw_schedule.sequence_params) + elif backend == 'Keysight_QS': + print(sequence.hw_schedule.sequence_params) + for dig in pulse.digitizers.values(): + dig.describe() + elif backend == 'Qblox': + print('See .q1asm file for acquisition timing') + elif backend == 'Tektronix_5014': + print('triggers:', job.digitizer_triggers) + else: + print('No acquisition info for backend ' + backend) + + def plot_segments(self, segments, index=(0,), channels=None, awg_output=True): + pt.ioff() + for s in segments: + pt.figure() + pt.title(f'Segment index:{index}') + s.plot(index, channels=channels, render_full=awg_output) + self._savefig() + + + def _savefig(self): + backend = self._configuration['backend'] + self.n_plots += 1 + pt.savefig(f'figure_{self.n_plots}-{backend}.png') + pt.close() + + +init_logging() +context = Context() + + +#from core_tools.HVI2.hvi2_schedule_loader import Hvi2ScheduleLoader +# +#def cleanup_instruments(): +# try: +# oldLoader.close_all() +# except: pass +# oldLoader = Hvi2ScheduleLoader + diff --git a/pulse_lib/tests/looping/__init__.py b/pulse_lib/tests/looping/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/looping/test_1D_divide.py b/pulse_lib/tests/looping/test_1D_divide.py new file mode 100644 index 0000000000000000000000000000000000000000..7c7cd50e7b3248358ac672008e366dd5158b5eb5 --- /dev/null +++ b/pulse_lib/tests/looping/test_1D_divide.py @@ -0,0 +1,28 @@ + +from pulse_lib.tests.configurations.test_configuration import context +import pulse_lib.segments.utility.looping as lp + +def test(): + pulse = context.init_pulselib(n_gates=1) + + t_pulse = lp.linspace(20, 100, 5, name='t_pulse', axis=0) + amplitude = 1000.0 / t_pulse + + s = pulse.mk_segment() + + s.wait(100) + s.P1.add_block(0, t_pulse, amplitude) + + context.plot_segments([s]) + + sequence = pulse.mk_sequence([s]) + context.add_hw_schedule(sequence) + for t in sequence.t_pulse.values: + sequence.t_pulse(t) + context.plot_awgs(sequence, ylim=(-0.100,0.100)) + ds = context.run('test_1D_divide', sequence) + + return ds + +if __name__ == '__main__': + ds = test() diff --git a/pulse_lib/tests/looping/test_2D_divide.py b/pulse_lib/tests/looping/test_2D_divide.py new file mode 100644 index 0000000000000000000000000000000000000000..5278620eaea2e07aa4dbe559442437ea396b7eb4 --- /dev/null +++ b/pulse_lib/tests/looping/test_2D_divide.py @@ -0,0 +1,47 @@ + +from pulse_lib.tests.configurations.test_configuration import context +import pulse_lib.segments.utility.looping as lp + +def test(): + pulse = context.init_pulselib(n_gates=1, n_sensors=1) + + n_pulses = lp.array([1,2,5,10], name='n_pulses', axis=1) + t_all = lp.linspace(1000, 3000, 3, name='t_all', axis=0) + t_pulse = t_all / n_pulses + + s = pulse.mk_segment() + s.update_dim(n_pulses) + + # Add other axis before indexing. It cannot be added on the slice. + # TODO: This shouldn't be necessary... + s.update_dim(t_all) + + for i in range(len(n_pulses)): + s_i = s[i] + for j in range(int(n_pulses[i])): + s_i.P1.add_block(0, t_pulse[i], 50) + s_i.reset_time() + s_i.P1.add_block(0, t_pulse[i], -50) + s_i.reset_time() + + s.wait(100) + s.SD1.acquire(0, 100) + + context.plot_segments([s], index=(0,0)) + + sequence = pulse.mk_sequence([s]) + sequence.n_rep = 2 + context.add_hw_schedule(sequence) + m_param = sequence.get_measurement_param() + for t in sequence.t_all.values: + sequence.t_all(t) + for i in sequence.n_pulses.values: + sequence.n_pulses(i) + context.plot_awgs(sequence, ylim=(-0.100,0.100)) + + ds = context.run('test_2D_divide', sequence, m_param) + + return ds + +if __name__ == '__main__': + ds = test() diff --git a/pulse_lib/tests/mock_m4i.py b/pulse_lib/tests/mock_m4i.py new file mode 100644 index 0000000000000000000000000000000000000000..43903bf3821c8244d42989a1c6226bfb90a28855 --- /dev/null +++ b/pulse_lib/tests/mock_m4i.py @@ -0,0 +1,23 @@ + +from qcodes.instrument.base import Instrument + +class MockM4i(Instrument): + def __init__(self, name): + super().__init__(name) + self.timeout = Parameter(10000) + + def get_idn(self): + return dict(vendor='Pulselib', model=type(self).__name__, serial='', firmware='') + + def start_triggered(self): + pass + +class Parameter: + def __init__(self, value): + self.value = value + + def set(self, value): + self.value = value + + def cache(self): + return self.value \ No newline at end of file diff --git a/pulse_lib/tests/mock_tektronix5014.py b/pulse_lib/tests/mock_tektronix5014.py new file mode 100644 index 0000000000000000000000000000000000000000..c031e7c479d9e16fd333c706a82abb48fa6bd3e5 --- /dev/null +++ b/pulse_lib/tests/mock_tektronix5014.py @@ -0,0 +1,139 @@ + +import logging +from dataclasses import dataclass, field +from typing import Dict + +import numpy as np +import matplotlib.pyplot as pt + +from qcodes.instrument.base import Instrument + + +# mock for M3202A / SD_AWG_Async +class MockTektronix5014(Instrument): + + def __init__(self, name): + super().__init__(name) + self.visa_handle = VisaHandlerMock(self) + self.settings = {} + self.channel_settings = {ch:{} for ch in [1,2,3,4]} + self.waveforms = {} + self.waveforms_lengths = {} + self.sequence = [] + self.state = 'Stopped' + self.all_channels_off() + + def get_idn(self): + return dict(vendor='Pulselib', model=type(self).__name__, serial='', firmware='') + + def trigger_source(self, value): + self.settings['trigger_source'] = value + + def trigger_impedance(self, value): + self.settings['trigger_impedance'] = value + + def trigger_level(self, value): + self.settings['trigger_level'] = value + + def trigger_slope(self, value): + self.settings['trigger_slope'] = value + + def clock_freq(self, value): + self.settings['clock_freq'] = value + + def set(self, name, value): + if name.startswith('ch'): + channel = int(name[2]) + self.channel_settings[channel][name[4:]] = value + else: + self.settings[name] = value + + def delete_all_waveforms_from_list(self): + self.waveforms = {} + + def write(self, cmd): + if cmd.startswith('WLISt:WAVeform:DEL '): + name = cmd.split('"')[1] + if name in self.waveforms: + del self.waveforms[name] + elif cmd.startswith('WLISt:WAVeform:NEW '): + name = cmd.split('"')[1] + length = int(cmd.split(',')[1]) + self.waveforms_lengths[name] = length + + def sequence_length(self, length): + self.sequence = [SequenceElement() for _ in range(length)] + + def set_sqel_waveform(self, wave_name, channel, element_no): + self.sequence[element_no-1].wave_names[channel] = wave_name + + def set_sqel_goto_state(self, element_no, dest): + self.sequence[element_no-1].goto = dest + + def set_sqel_trigger_wait(self, element_no): + self.sequence[element_no-1].wait = True + + def set_sqel_loopcnt(self, n_repetitions, element_no): + self.sequence[element_no-1].loop_cnt = n_repetitions + + def set_sqel_loopcnt_to_inf(self, element_no): + self.sequence[element_no-1].loop_cnt = 10**6 + + def run_mode(self, mode): + self.settings['mode'] = mode + + def run(self): + self.state = 'Running' + + def stop(self): + self.state = 'Stopped' + + def force_trigger(self): + self.state = 'Running' + + def all_channels_off(self): + for ch in [1,2,3,4]: + settings = self.channel_settings[ch] + settings['state'] = 0 + + def plot(self): + for ch in [1,2,3,4]: + settings = self.channel_settings[ch] + print(self.name, ch, settings) + + if settings['state'] == 0: + continue + amp = settings.get('amp', 0.0) + offset = settings.get('offset', 0.0) + wave_raw = self.waveforms[self.sequence[0].wave_names[ch]] + wave_data = (wave_raw & 0x3FFF) # ((wave_raw & 0x3FFF) << 2).astype(np.int16) + wave = offset + amp * (wave_data/2**13 - 1) + pt.plot(wave, label=f'ch{ch}') + if settings.get('m1_high',False): + marker_1 = (wave_raw & 0x4000) >> 14 + pt.plot(marker_1, ':', label=f'M{ch}.1') + if settings.get('m2_high',False): + marker_2 = (wave_raw & 0x8000) >> 15 + pt.plot(marker_2, ':', label=f'M{ch}.2') + +class VisaHandlerMock: + def __init__(self, parent): + self.parent = parent + + def write_raw(self, msg): + cmd_end = msg.index(ord(',')) + cmd = str(msg[:cmd_end]) + name = cmd.split('"')[1] + data_length_len = int(chr(msg[cmd_end+2])) + data_start = cmd_end+3+data_length_len + # data_length = int(str(msg[cmd_end+3:data_start], encoding='utf-8')) + data = np.frombuffer(msg[data_start:], dtype='<u2') + self.parent.waveforms[name] = data + +@dataclass +class SequenceElement: + wave_names: Dict[int,str] = field(default_factory=dict) + goto: int = 0 + wait: bool = False + loop_cnt: int = 1 + diff --git a/pulse_lib/tests/rf_source/__init__.py b/pulse_lib/tests/rf_source/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/rf_source/test_rf_qblox_fast.py b/pulse_lib/tests/rf_source/test_rf_qblox_fast.py new file mode 100644 index 0000000000000000000000000000000000000000..c9c80763637957387c9157b723942ea913dd9054 --- /dev/null +++ b/pulse_lib/tests/rf_source/test_rf_qblox_fast.py @@ -0,0 +1,26 @@ + +from pulse_lib.tests.configurations.test_configuration import context +from pulse_lib.fast_scan.qblox_fast_scans import fast_scan1D_param, fast_scan2D_param + + +def test(): + pulse = context.init_pulselib(n_gates=2, n_sensors=2, rf_sources=True) + + param1 = fast_scan1D_param( + pulse, 'P1', 100.0, 10, 5000, + channels=['SD2']) + + context.plot_segments(param1.my_seq.sequence) + context.plot_awgs(param1.my_seq) + + param2 = fast_scan2D_param( + pulse, 'P1', 100.0, 10, 'P2', 80.0, 10, 2000, + channels=['SD2']) + + context.plot_segments(param2.my_seq.sequence) + context.plot_awgs(param2.my_seq) + + return None + +if __name__ == '__main__': + ds = test() diff --git a/pulse_lib/tests/test_iq/__init__.py b/pulse_lib/tests/test_iq/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/test_iq/test_phase.py b/pulse_lib/tests/test_iq/test_phase.py new file mode 100644 index 0000000000000000000000000000000000000000..3e79d08334f8088fefc871d557a2796d0ff89eb4 --- /dev/null +++ b/pulse_lib/tests/test_iq/test_phase.py @@ -0,0 +1,32 @@ + +from pulse_lib.tests.configurations.test_configuration import context + +from numpy import pi + +def test(): + pulse = context.init_pulselib(n_qubits=1) + + s = pulse.mk_segment() + + s.q1.add_MW_pulse(0, 20, 100, 2.450e9) + s.q1.add_phase_shift(20, pi/2) + s.q1.add_phase_shift(20, pi/2) + s.q1.add_MW_pulse(20, 40, 100, 2.450e9) + s.q1.add_phase_shift(40, pi) + s.reset_time() + s.q1.add_phase_shift(0, -pi/2) + s.q1.add_MW_pulse(0, 20, 100, 2.450e9) + s.q1.add_phase_shift(20, pi/2) + s.q1.add_MW_pulse(20, 40, 100, 2.450e9) + + context.plot_segments([s]) + + sequence = pulse.mk_sequence([s]) + sequence.n_rep = 1 + context.add_hw_schedule(sequence) + context.plot_awgs(sequence) + + return None + +if __name__ == '__main__': + ds = test() diff --git a/pulse_lib/tests/utils/__init__.py b/pulse_lib/tests/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/utils/qc_run.py b/pulse_lib/tests/utils/qc_run.py new file mode 100644 index 0000000000000000000000000000000000000000..89931658561d327204ddcd6f361aa5db431b605c --- /dev/null +++ b/pulse_lib/tests/utils/qc_run.py @@ -0,0 +1,60 @@ +from collections.abc import Sequence +import qcodes as qc +from qcodes.measure import Measure +from qcodes.loops import Loop +from qcodes.actions import Task + +from pulse_lib.sequencer import sequencer + +def upload_play(seq): + seq.upload() + seq.play() + +def qc_run(name, *args, quiet=False): + + seq = None + meas_params = [] + sweeps = [] + delays = {} + for arg in args: + if isinstance(arg, sequencer): + seq = arg + elif isinstance(arg, (qc.Parameter, qc.MultiParameter)): + meas_params.append(arg) + elif isinstance(arg, Sequence): + if len(arg) not in [4,5]: + raise ValueError(f'incorrect sweep {arg}') + param = arg[0] + if not isinstance(param, qc.Parameter): + raise TypeError(f'Expected Parameter, got {type(param)}') + sweeps.append(param[arg[1]:arg[2]:arg[3]]) + if len(arg) == 5: + delay = arg[4] + delays[len(sweeps)-1] = delay + + actions = [] + + if seq is not None: + for sp in seq.params: + sweep = sp[sp.values] + # np.random.shuffle(sweep._values) + sweeps.append(sweep) + play_task = Task(upload_play, seq) + actions.append(play_task) + + loop = None + for i,sweep in enumerate(sweeps): + delay = delays.get(i, 0) + if loop is None: + loop = Loop(sweep, delay) + else: + loop = loop.loop(sweep, delay) + + actions += meas_params + if loop is not None: + m = loop.each(*actions) + else: + m = Measure(*actions) + + ds = m.run(loc_record={'name':name}, quiet=quiet) + return ds