Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qblox setting #676

Merged
merged 10 commits into from
Dec 1, 2023
10 changes: 5 additions & 5 deletions src/qibolab/instruments/qblox/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,15 @@ def connect(self):
raise InstrumentException(self, f"Unable to connect to {self.name}")

# apply stored settings
self._setup()
# self._setup()

def _setup(self):
if self.is_connected:
self.device.set("reference_source", self.settings.reference_clock_source.value)
# def _setup(self):
# if self.is_connected:
# self.device.set("reference_source", self.settings.reference_clock_source.value)

def setup(self):
"""Configures the instrument with the stored settings."""
self._setup()
# self._setup()

def start(self):
"""Empty method to comply with Instrument interface."""
Expand Down
52 changes: 26 additions & 26 deletions src/qibolab/instruments/qblox/cluster_qcm_bb.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,26 +110,28 @@ class ClusterQCM_BB(Instrument):
)

def __init__(self, name: str, address: str, cluster: Cluster = None):
"""Initialises the instance.
"""
Initialize a Qblox QCM baseband module.

All class attributes are defined and initialised.
Parameters:
- name: An arbitrary name to identify the module.
- address: The network address of the instrument, specified as "cluster_IP:module_slot_idx".
- cluster: The Cluster object to which the QCM baseband module is connected.

Args:
name(str): A unique name given to the instrument.
address: IP_address:module_number (the IP address of the cluster and module number)
cluster: the cluster to which the instrument belongs.
Example:
To create a ClusterQCM_BB instance named 'qcm_bb' connected to slot 2 of a Cluster at address '192.168.0.100':
>>> cluster_instance = Cluster("cluster","192.168.1.100", settings)
>>> qcm_module = ClusterQCM_BB(name="qcm_bb", address="192.168.1.100:2", cluster=cluster_instance)
"""
super().__init__(name, address)
self.ports: dict = {}
self.settings: dict = {}
self.device = None
self.channels: list = []

self._debug_folder: str = ""
self._cluster: Cluster = cluster
self._sequencers: dict[Sequencer] = {}
self._port_channel_map: dict = {}
self._channel_port_map: dict = {}
self.channel_map: dict = {}
self._device_parameters = {}
self._device_num_output_ports = 2
self._device_num_sequencers: int
Expand Down Expand Up @@ -227,7 +229,6 @@ def connect(self):
for port in self.settings:
self._sequencers[port] = []
self.ports[port].offset = self.settings[port]["offset"]
self.ports[port].qubit = self.settings[port]["qubit"]
self.ports[port].hardware_mod_en = True
self.ports[port].nco_freq = 0
self.ports[port].nco_phase_offs = 0
Expand Down Expand Up @@ -275,11 +276,13 @@ def setup(self, **settings):
At the moment this param is not loaded but is always set to True.
"""
for port_num, port in enumerate(settings):
self.ports[port] = QbloxOutputPort(self, self.DEFAULT_SEQUENCERS[port], port_number=port_num)
self.ports[port] = QbloxOutputPort(
self, self.DEFAULT_SEQUENCERS[port], port_number=port_num, port_name=port
)

self.settings = settings if settings else self.settings

def _get_next_sequencer(self, port, frequency, qubits: dict, qubit: None):
def _get_next_sequencer(self, port, frequency, qubits: dict):
"""Retrieves and configures the next avaliable sequencer.

The parameters of the new sequencer are copied from those of the default sequencer, except for the
Expand All @@ -291,6 +294,10 @@ def _get_next_sequencer(self, port, frequency, qubits: dict, qubit: None):
Raises:
Exception = If attempting to set a parameter without a connection to the instrument.
"""
# select the qubit relative to specific port
for _qubit in qubits.values():
if _qubit.flux.port.name == port and _qubit.flux.port.module.name == self.name:
qubit = _qubit
# select a new sequencer and configure it as required
next_sequencer_number = self._free_sequencers_numbers.pop(0)
if next_sequencer_number != self.DEFAULT_SEQUENCERS[port]:
Expand Down Expand Up @@ -321,11 +328,11 @@ def _get_next_sequencer(self, port, frequency, qubits: dict, qubit: None):
# value=qubits[qubit].sweetspot,
# )

self.ports[port].offset = qubits[qubit].sweetspot
self.ports[port].offset = qubit.sweetspot

# create sequencer wrapper
sequencer = Sequencer(next_sequencer_number)
sequencer.qubit = qubit
sequencer.qubit = qubit.name
return sequencer

def get_if(self, pulse):
Expand Down Expand Up @@ -392,7 +399,8 @@ def process_pulse_sequence(
# process the pulses for every port
for port in self.ports:
# split the collection of instruments pulses by ports
port_pulses: PulseSequence = instrument_pulses.get_channel_pulses(self._port_channel_map[port])
port_channel = [chan.name for chan in self.channel_map.values() if chan.port.name == port]
port_pulses: PulseSequence = instrument_pulses.get_channel_pulses(*port_channel)

# initialise the list of sequencers required by the port
self._sequencers[port] = []
Expand All @@ -414,10 +422,7 @@ def process_pulse_sequence(
)
# get next sequencer
sequencer = self._get_next_sequencer(
port=port,
frequency=self.get_if(non_overlapping_pulses[0]),
qubits=qubits,
qubit=non_overlapping_pulses[0].qubit,
port=port, frequency=self.get_if(non_overlapping_pulses[0]), qubits=qubits
)
# add the sequencer to the list of sequencers required by the port
self._sequencers[port].append(sequencer)
Expand All @@ -444,17 +449,12 @@ def process_pulse_sequence(
)
# get next sequencer
sequencer = self._get_next_sequencer(
port=port,
frequency=self.get_if(non_overlapping_pulses[0]),
qubits=qubits,
qubit=non_overlapping_pulses[0].qubit,
port=port, frequency=self.get_if(non_overlapping_pulses[0]), qubits=qubits
)
# add the sequencer to the list of sequencers required by the port
self._sequencers[port].append(sequencer)
else:
sequencer = self._get_next_sequencer(
port=port, frequency=0, qubits=qubits, qubit=self.ports[port].qubit
)
sequencer = self._get_next_sequencer(port=port, frequency=0, qubits=qubits)
# add the sequencer to the list of sequencers required by the port
self._sequencers[port].append(sequencer)

Expand Down
26 changes: 18 additions & 8 deletions src/qibolab/instruments/qblox/cluster_qcm_rf.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,18 @@ class ClusterQCM_RF(Instrument):
"""

def __init__(self, name: str, address: str, cluster: Cluster):
"""Initialises the instance.
"""
Initialize a Qblox QCM-RF module.

Parameters:
- name: An arbitrary name to identify the module.
- address: The network address of the instrument, specified as "cluster_IP:module_slot_idx".
- cluster: The Cluster object to which the QCM-RF module is connected.

All class attributes are defined and initialised.
Example:
To create a ClusterQCM_RF instance named 'qcm_rf' connected to slot 2 of a Cluster at address '192.168.0.100':
>>> cluster_instance = Cluster("cluster","192.168.1.100", settings)
>>> qcm_module = ClusterQCM_RF(name="qcm_rf", address="192.168.1.100:2", cluster=cluster_instance)
"""
super().__init__(name, address)
self.device: QbloxQrmQcm = None
Expand All @@ -147,9 +156,7 @@ def __init__(self, name: str, address: str, cluster: Cluster):
self._debug_folder: str = ""
self._cluster: Cluster = cluster
self._sequencers: dict[Sequencer] = {}
self.channels: list = []
self._port_channel_map: dict = {}
self._channel_port_map: dict = {}
self.channel_map: dict = {}
self._device_parameters = {}
self._device_num_output_ports = 2
self._device_num_sequencers: int
Expand Down Expand Up @@ -296,7 +303,9 @@ def setup(self, **settings):
At the moment this param is not loaded but is always set to True.
"""
for port_num, port in enumerate(settings):
self.ports[port] = QbloxOutputPort(self, self.DEFAULT_SEQUENCERS[port], port_number=port_num)
self.ports[port] = QbloxOutputPort(
self, self.DEFAULT_SEQUENCERS[port], port_number=port_num, port_name=port
)
self._sequencers[port] = []
self.settings = settings if settings else self.settings

Expand Down Expand Up @@ -344,7 +353,7 @@ def get_if(self, pulse):
"""Returns the intermediate frequency needed to synthesise a pulse based on the port lo frequency."""

_rf = pulse.frequency
_lo = self.ports[self._channel_port_map[pulse.channel]].lo_frequency
_lo = self.channel_map[pulse.channel].lo_frequency
_if = _rf - _lo
if abs(_if) > self.FREQUENCY_LIMIT:
raise Exception(
Expand Down Expand Up @@ -406,7 +415,8 @@ def process_pulse_sequence(
# process the pulses for every port
for port in self.ports:
# split the collection of instruments pulses by ports
port_pulses: PulseSequence = instrument_pulses.get_channel_pulses(self._port_channel_map[port])
port_channel = [chan.name for chan in self.channel_map.values() if chan.port.name == port]
port_pulses: PulseSequence = instrument_pulses.get_channel_pulses(*port_channel)

# initialise the list of sequencers required by the port
self._sequencers[port] = []
Expand Down
33 changes: 24 additions & 9 deletions src/qibolab/instruments/qblox/cluster_qrm_rf.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,18 @@ class ClusterQRM_RF(Instrument):
"""

def __init__(self, name: str, address: str, cluster: Cluster):
"""Initialises the instance.
"""
Initialize a Qblox QRM-RF module.

Parameters:
- name: An arbitrary name to identify the module.
- address: The network address of the instrument, specified as "cluster_IP:module_slot_idx".
- cluster: The Cluster object to which the QRM-RF module is connected.

All class attributes are defined and initialised.
Example:
To create a ClusterQRM_RF instance named 'qrm_rf' connected to slot 2 of a Cluster at address '192.168.0.100':
>>> cluster_instance = Cluster("cluster","192.168.1.100", settings)
>>> qrm_module = ClusterQRM_RF(name="qrm_rf", address="192.168.1.100:2", cluster=cluster_instance)
"""

super().__init__(name, address)
Expand All @@ -162,9 +171,7 @@ def __init__(self, name: str, address: str, cluster: Cluster):
self._input_ports_keys = ["i1"]
self._output_ports_keys = ["o1"]
self._sequencers: dict[Sequencer] = {"o1": []}
self.channels: list = []
self._port_channel_map: dict = {}
self._channel_port_map: dict = {}
self.channel_map: dict = {}
self._device_parameters = {}
self._device_num_output_ports = 1
self._device_num_sequencers: int
Expand Down Expand Up @@ -234,6 +241,11 @@ def connect(self):
self.device.sequencers[sequencer],
"connect_out0",
value="off",
)
self._set_device_parameter(
self.device.sequencers[sequencer],
"connect_acq",
value="off",
) # Default after reboot = True
try:
if "o1" in self.settings:
Expand Down Expand Up @@ -312,14 +324,15 @@ def setup(self, **settings):
"""
if "o1" in settings:
self.ports["o1"] = QbloxOutputPort(
module=self, sequencer_number=self.DEFAULT_SEQUENCERS["o1"], port_number=0
module=self, sequencer_number=self.DEFAULT_SEQUENCERS["o1"], port_number=0, port_name="o1"
)
if "i1" in settings:
self.ports["i1"] = QbloxInputPort(
module=self,
output_sequencer_number=self.DEFAULT_SEQUENCERS["o1"],
input_sequencer_number=self.DEFAULT_SEQUENCERS["i1"],
port_number=0,
port_name="i1",
)

self.settings = settings if settings else self.settings
Expand Down Expand Up @@ -384,7 +397,7 @@ def get_if(self, pulse: Pulse):
"""Returns the intermediate frequency needed to synthesise a pulse based on the port lo frequency."""

_rf = pulse.frequency
_lo = self.ports[self._channel_port_map[pulse.channel]].lo_frequency
_lo = self.channel_map[pulse.channel].lo_frequency
_if = _rf - _lo
if abs(_if) > self.FREQUENCY_LIMIT:
raise Exception(
Expand Down Expand Up @@ -444,7 +457,6 @@ def process_pulse_sequence(
sweepers = []
sequencer: Sequencer
sweeper: Sweeper

# calculate the number of bins
num_bins = nshots
for sweeper in sweepers:
Expand All @@ -458,7 +470,10 @@ def process_pulse_sequence(
self._free_sequencers_numbers = [self.DEFAULT_SEQUENCERS[port]] + [1, 2, 3, 4, 5]

# split the collection of instruments pulses by ports
port_pulses: PulseSequence = instrument_pulses.get_channel_pulses(self._port_channel_map[port])
# ro_channel = None
# feed_channel = None
port_channel = [chan.name for chan in self.channel_map.values() if chan.port.name == port]
port_pulses: PulseSequence = instrument_pulses.get_channel_pulses(*port_channel)

# initialise the list of sequencers required by the port
self._sequencers[port] = []
Expand Down
Loading