Source code for qibolab.channels

from dataclasses import dataclass, field
from typing import Dict, Optional

from qibo.config import raise_error

from qibolab.instruments.oscillator import LocalOscillator
from qibolab.instruments.port import Port


[docs]def check_max_offset(offset, max_offset): """Checks if a given offset value exceeds the maximum supported offset. This is to avoid sending high currents that could damage lab equipment such as amplifiers. """ if max_offset is not None and abs(offset) > max_offset: raise_error( ValueError, f"{offset} exceeds the maximum allowed offset {max_offset}." )
[docs]@dataclass class Channel: """Representation of physical wire connection (channel).""" name: str """Name of the channel from the lab schematics.""" port: Optional[Port] = None """Instrument port that is connected to this channel.""" local_oscillator: Optional[LocalOscillator] = None """Instrument object controlling the local oscillator connected to this channel. Not applicable for setups that do not use external local oscillators because the controller can send sufficiently high frequencies or contains internal local oscillators. """ max_offset: Optional[float] = None """Maximum DC voltage that we can safely send through this channel. Sending high voltages for prolonged times may damage amplifiers or other lab equipment. If the user attempts to send a higher value an error will be raised to prevent execution in real instruments. """ @property def offset(self): """DC offset that is applied to this port.""" return self.port.offset @offset.setter def offset(self, value): check_max_offset(value, self.max_offset) self.port.offset = value @property def lo_frequency(self): if self.local_oscillator is not None: return self.local_oscillator.frequency return self.port.lo_frequency @lo_frequency.setter def lo_frequency(self, value): if self.local_oscillator is not None: self.local_oscillator.frequency = value else: self.port.lo_frequency = value @property def lo_power(self): if self.local_oscillator is not None: return self.local_oscillator.power return self.port.lo_power @lo_power.setter def lo_power(self, value): if self.local_oscillator is not None: self.local_oscillator.power = value else: self.port.lo_power = value # TODO: gain, attenuation and power range can be unified to a single property @property def gain(self): return self.port.gain @gain.setter def gain(self, value): self.port.gain = value @property def attenuation(self): return self.port.attenuation @attenuation.setter def attenuation(self, value): self.port.attenuation = value @property def power_range(self): return self.port.power_range @power_range.setter def power_range(self, value): self.port.power_range = value @property def filter(self): return self.port.filter @filter.setter def filter(self, value): self.port.filter = value
[docs]@dataclass class ChannelMap: """Collection of :class:`qibolab.designs.channel.Channel` objects identified by name. Essentially, it allows creating a mapping of names to channels just specifying the names. """ _channels: Dict[str, Channel] = field(default_factory=dict)
[docs] def add(self, *items): """Add multiple items to the channel map. If :class: `qibolab.channels.Channel` objects are given they are dded to the channel map. If a different type is given, a :class: `qibolab.channels.Channel` with the corresponding name is created and added to the channel map. """ for item in items: if isinstance(item, Channel): self[item.name] = item else: self[item] = Channel(item) return self
def __getitem__(self, name): return self._channels[name] def __setitem__(self, name, channel): if not isinstance(channel, Channel): raise_error( TypeError, f"Cannot add channel of type {type(channel)} to ChannelMap." ) self._channels[name] = channel def __contains__(self, name): return name in self._channels def __or__(self, channel_map): channels = self._channels.copy() channels.update(channel_map._channels) return self.__class__(channels) def __ior__(self, items): if not isinstance(items, type(self)): try: if isinstance(items, str): raise TypeError items = type(self)().add(*items) except TypeError: items = type(self)().add(items) self._channels.update(items._channels) return self