Channels
The channels
subpackage encapsulates the concepts that specify the input and output
of instruments.
Represents an acquisition. |
|
Represents the address of a |
|
Represents an arbitrary envelope specified by linearly interpolating a list of amplitudes. |
|
A base class for classifiers. |
|
Represents the settings of a physical channel that has a local oscillator. |
|
A base class for waveforms. |
|
Represents the settings of a baseband AWG channel. |
|
Represents a map between |
|
Represents a physical channel's settings. |
|
A collection of channels to target. |
|
Classifies results based on the minimum distance to a reference point. |
|
Represents a constant envelope \(E(t) = 1\). |
|
A class for unmodulated waveforms. |
|
A class representing a data transaction. |
|
A |
|
Represents a derivative envelope, normalized by the maximum absolute value. |
|
Represents the settings of a digitizer channel. |
|
Represents the settings of a downconverter channel. |
|
An abstract base class for envelopes. |
|
A class representing an FDS Transaction through HVI. |
|
Represents a truncated Gaussian envelope shifted and rescaled to satisfy \(E(0) = E(1) = 0\) and \(E(0.5) = 1\). |
|
A base class for hardware operations. |
|
A |
|
An enum specifying the supported instrument types. |
|
Represents an integration filter for demodulating and integrating time-domain signals. |
|
Represents the part of an envelope between a specified start and end time. |
|
Classifies results based on the minimum distance to a reference point. |
|
A |
|
Represents a channel of an instrument. |
|
Represents the settings of an RF AWG channel. |
|
Represents a waveform with target frequency or frequencies. |
|
A class for a register with a fixed number of bits. |
|
Represents a sine envelope \(E(t) = \sin(\pi t)\). |
|
A class representing a list of DataTransaction between virtual channels. |
Acquisitions
- class keysight.qcs.channels.Acquisition(integration_filter: float | Variable[float] | HardwareOperation | Iterable[HardwareOperation] | IntegrationFilter, classifier: MinimumDistanceClassifier | Iterable[MinimumDistanceClassifier] | None = None, name: str | None = None)
Bases:
HardwareOperation
Represents an acquisition.
Note
As the M5200 Digitizer returns blocks of
16
samples, the duration of an acquisition with an integration filter should be chosen such that the number of samples is a multiple of16
.import keysight.qcs as qcs # initialize a 100ns acquisition qcs.Acquisition(100e-9) # initialize a constant 100ns integration filter with an amplitude of 1 waveform = qcs.DCWaveform(100e-9, qcs.ConstantEnvelope(), 1) integration_filter = qcs.IntegrationFilter(waveform) # specify a 100ns acquisition with a constant integration filter qcs.Acquisition(integration_filter)Acquisition(IntegrationFilter(DCWaveform(duration=Scalar(name=_implicit, value=1e-07, dtype=float, unit=s), envelope={ConstantEnvelope(): Scalar(name=_implicit, value=1.0, dtype=float, unit=none)})))
- Parameters:
integration_filter – The integration filter or a duration.
classifier – The classifiers used to classify integrated acquisitions.
name – An optional name for this.
- Raises:
ValueError – If classifiers are supplied without an integration filter.
ValueError – If the number of classifiers does not match the slice width of the integration filters.
- render(sample_rate: float, lo_frequency: float = 0.0, sample_offset: float = 0.5) np.ndarray | list[np.ndarray]
Computes the acquisition. The acquisition is rendered at a sideband frequency relative to
lo_frequency
.
- Parameters:
sample_rate – The rate at which to sample the acquisition in Hz.
lo_frequency – The frequency of the LO in Hz.
sample_offset – The offset of each sample in the sample window. The default value of
0.5
generates samples in the middle of the sample window.
- property classifier: Classifier | None
The classification to perform after the integration filter is applied.
- property integration_filter: IntegrationFilter | None
The integration filter used to integrate the raw results.
- property rf_frequencies: set[float]
The RF frequencies in the integration filters of this acquisition.
- class keysight.qcs.channels.BaseClassifier
A base class for classifiers.
- Parameters:
references – The map from reference points to the classified output.
- property references: Array[complex]
Returns the map from reference points to the classified output.
- classify(result: complex) int
Classify a result into distinct outcomes.
- Parameters:
result – Is the result to classify.
- class keysight.qcs.channels.Classifier(references: list[complex] | Array[complex], register: Register | None = None)
Classifies results based on the minimum distance to a reference point.
- Parameters:
references – The reference points.
register – The register to which the classified results are to be written. A register is required if the classified data is used in subsequent conditional operations.
- property slice_width: int | None
The number of classifiers in this, or
None
if there is a single classifier.
- class keysight.qcs.channels.MinimumDistanceClassifier(references: list[complex] | Array[complex])
Classifies results based on the minimum distance to a reference point.
- Parameters:
references – The reference points.
- class keysight.qcs.channels.IntegrationFilter(*waveforms: HardwareOperation)
Bases:
CsWrapper
Represents an integration filter for demodulating and integrating time-domain signals.
The signal provided to the
integrate()
is demodulated to a single complex number using the formula\[z = 2 * V^\dagger U / n\]where \(V\) is the rendered integration filter and n is the number of points of both \(U\) and \(V\).
import keysight.qcs as qcs import numpy as np # initialize a filter from a single waveform duration = 120e-9 waveform = qcs.DCWaveform(duration, qcs.ConstantEnvelope(), 1) integration_filter = qcs.IntegrationFilter(waveform) # initialize a set of data sample_rate = 4.8e9 n_samples = round(duration * sample_rate) data = np.ones(n_samples) # obtain the result by integrating result = integration_filter.integrate(data, sample_rate) assert (result == [2]).all() # specify a sliceable filter with a sliceable waveform frequencies = qcs.Array("frequencies", value=[0, 10e6, 20e6]) waveform = qcs.RFWaveform(duration, qcs.ConstantEnvelope(), 1, frequencies) filter_slc = qcs.IntegrationFilter(waveform) # integrate the data with each of the slices result_slc = filter_slc.integrate(data, sample_rate) assert np.allclose(result_slc, [2 + 0j, 0.25 - 0.18j, 0.08 - 0.23j], atol=2)
- Parameters:
waveforms – One or more
HardwareOperation
s used to perform demodulation.
- property rf_frequencies: set[float]
Returns all the RF frequencies in this filter.
- Raises:
ValueError – If any RF frequency has not been set.
- property slice_width: int | None
The dimension of the sliceable axis, or
None
if this filter does not contain sliceableHardwareOperation
s.
- property waveforms: tuple[keysight.qcs.channels.waveforms.HardwareOperation, ...]
Series of
HardwareOperation
s used to perform demodulation.
- broadcast(prefix: str, length: int) IntegrationFilter
Returns a new integration filter where any scalars have been broadcast to arrays.
- Parameters:
prefix – The prefix to use when broadcasting variables.
length – The length of the resulting arrays.
- integrate(signal: ndarray, sample_rate: float, downconversion_frequency: float = 0.0, sample_offset: float = 0.5, truncate: bool = False) ndarray
Returns the integrated time-domain data. If the filter is sliceable, the first axis is the slice axis.
- Parameters:
signal – The data to process. If multi-dimensional, the last axis is interpreted as time.
sample_rate – Sample rate of the signal.
downconversion_frequency – The frequency the filter is rendered with. See
render()
.sample_offset – The offset of each sample in the sample window. The default value of
0.5
generates samples in the middle of the sample window.truncate – Whether to truncate samples from either the signal or the filter before integrating.
- Raises:
ValueError – If the number of samples of
signal
and the rendered filter is different whentruncate
isFalse
.
- render(sample_rate: float, lo_frequency: float = 0.0, sample_offset: float = 0.5) np.ndarray | list[np.ndarray]
Computes the filter. The filter is rendered at a sideband frequency relative to
lo_frequency
.
- Parameters:
sample_rate – The rate at which to sample the filter in Hz.
lo_frequency – The frequency of the LO in Hz.
sample_offset – The offset of each sample in the sample window. The default value of
0.5
generates samples in the middle of the sample window.
Data Transactions
- class keysight.qcs.channels.DataTransaction(source: TargetedOperation)
A class representing a data transaction.
- Parameters:
source – The operation that will populate the register for this transaction.
- property destinations: list[keysight.qcs.operations.targeted_operation.TargetedOperation]
The destination for the data.
- property source: TargetedOperation
The source of the data.
- class keysight.qcs.channels.FdsTransaction(source: Address, destination: Address)
A class representing an FDS Transaction through HVI.
- Parameters:
source – The source module address.
destination – The destination module address.
- class keysight.qcs.channels.TransactionList
A class representing a list of DataTransaction between virtual channels.
- property unmapped_transactions: list[keysight.qcs.channels.data_transaction.DataTransaction]
A list of DataTransaction between virtual channels.
- property mapped_transactions: list[keysight.qcs.channels.data_transaction.DataTransaction]
A list of FdsTransactions between source addresses.
- class keysight.qcs.channels.Register(name: str, num_outcomes: int, dim: int | None = None)
A class for a register with a fixed number of bits.
- Parameters:
name – The name of this register.
num_outcomes – The number of outcomes to be stored in this register.
dim – The number of outcomes to be stored in each group of bits.
- property dim: int
The number of outcomes stored in each group of bits in this register.
- property name: str
The name of this register.
- property num_bits: int
The number of bits in this register.
- property num_outcomes: int
The number of outcomes in this register.
- binary_representations(num_ops: int) list[str]
Returns the binary representations of the bit strings needed to choose from a specified number of operations.
- Parameters:
num_ops – The number of operations to choose from.
- num_outcomes_per_decision(num_ops: int) int
Returns the number of outcomes needed to choose from a specified number of operations.
- Parameters:
num_ops – The number of operations to choose from.
- num_decisions(num_ops: int) int
Gets the number of independent decisions that can be made for a specified number of operations from this register.
- Parameters:
num_ops – The number of operations to choose from in each decision.
Instrument Channels
- class keysight.qcs.channels.Address(chassis: int, slot: int, channel: int, host_controller: int = 1)
Represents the address of a
PhysicalChannel
, defined by three integers that specify its chassis, slot and channel.
- Parameters:
chassis – An integer specifying a chassis number.
slot – An integer specifying a slot number.
channel – An integer specifying a channel number.
host_controller – An integer specifying a host controller ID.
- property chassis: int
The chassis number.
- property host_controller: int
The host controller index.
- property channel: int
The channel number.
- property slot: int
The slot number.
- class keysight.qcs.channels.Channels(labels: int | Iterable[int], name: str | None = None, absolute_phase: bool = False)
Bases:
Targets
A collection of channels to target.
Channels are destinations for channel-level operations. Channels that are grouped together can be used as a target for a common operation. Individual channels are identified by an integer label and the name of the collection.
import keysight.qcs as qcs # five channels each used for single-qubit xy control xy_channels = qcs.Channels(range(5), "xy_channels") # slice into a subset of the channels assert xy_channels[0:2] == qcs.Channels(range(2), "xy_channels")
- Parameters:
labels – An iterable of channel labels, or an integer representing a single label.
name – The name of this channel collection.
absolute_phase – Whether
RFWaveform
s played on the channels in this collection are rendered with a relative or an absolute phase.- Raises:
ValueError – If the name contains symbols other than letters, numbers and underscores.
- property absolute_phase: bool
Whether
RFWaveform
s played on the channels in this collection are rendered with a relative or an absolute phase.
- class keysight.qcs.channels.ChannelMapper(ip_address: str | None = None)
Bases:
CsWrapper
Represents a map between
Channels
andPhysicalChannel
s.import keysight.qcs as qcs # two channels each used for single-qubit xy control xy_channels = qcs.Channels(range(2), "xy_channels") # the associated physical channel addresses address1 = qcs.Address(1, 2, 3) address2 = qcs.Address(1, 2, 4) instrument_type = qcs.InstrumentEnum.M5300AWG # the channel mapper chan_map = qcs.ChannelMapper() # add the configurations chan_map.add_channel_mapping(xy_channels, [address1, address2], instrument_type) # get the physical channel associated with the first channel (phys_chan1,) = chan_map.get_physical_channels(xy_channels[0]) assert phys_chan1.address == address1 assert phys_chan1.instrument == instrument_type assert phys_chan1.settings.setting_names == ["delay", "lo_frequency"]
- Parameters:
ip_address – An IP address used for remote job submission.
- property channels: list[keysight.qcs.channels.channels.Channels]
The
Channels
in this channel mapper.
- property ip_address: str | None
The IP address of this channel mapper.
- property physical_channels: list[keysight.qcs.channels.physical_channels.PhysicalChannel]
The
PhysicalChannel
s in this channel mapper.
- add_channel_mapping(channels: Channels, addresses: Address | tuple[int, int, int] | list[Address | tuple[int, int, int]], instrument_types: InstrumentEnum | Iterable[InstrumentEnum]) None
Adds a channel configuration to map labels in
Channels
toAddress
s.
- Parameters:
channels – The channels to map from.
addresses – The physical channel addresses to map to.
instrument_types – The type of instrument present at
address
.- Raises:
ValueError – If the number of physical channels does not match the number of labels.
ValueError – If the attributes of
channels
does not match those specified in the channel map.
- add_downconverters(dig_addresses: Address | tuple[int, int, int] | list[Address | tuple[int, int, int]], downcon_addresses: Address | tuple[int, int, int] | list[Address | tuple[int, int, int]]) None
Maps digitizer channel addresses to upstream downconverter channel addresses.
import keysight.qcs as qcs ch_map = qcs.ChannelMapper() # link two digitizer channels in slot 3 with two downconverter channels in # slot 4. ch_map.add_downconverters( [qcs.Address(1, 3, 1), qcs.Address(1, 3, 2)], [qcs.Address(1, 4, 1), qcs.Address(1, 4, 2)], ) assert ch_map.get_downconverter( qcs.Address(1, 3, 1) ).address == qcs.Address(1, 4, 1)
- Parameters:
dig_addresses – The digitizer addresses to assign downconverters to.
downcon_addresses – The downconverter addresses to assign.
- Raises:
ValueError – If the number of digitizer and downconverter addresses do not match.
- get_downconverter(channel: PhysicalChannel | Address | tuple[int, int, int]) PhysicalChannel | None
Returns the upstream downconverter physical channel of a digitizer channel. Returns
None
if no downconverter is connected to the given channel.
- Parameters:
channel – The digitizer channel or address.
- get_physical_channel(address: Address | tuple[int, int, int]) PhysicalChannel
Returns the
PhysicalChannel
for an address.
- Raises:
ValueError – If the address is not defined in this channel mapper.
- get_physical_channels(channels: Channels) list[keysight.qcs.channels.physical_channels.PhysicalChannel]
Returns
PhysicalChannel
s for each label inchannels
.
- Parameters:
channels – The channels to get the physical channels of.
- get_virtual_channels(address: Address | tuple[int, int, int]) Iterable[Channels]
Returns the
Channels
s for the given address.
- Parameters:
address – The address to get the virtual channels of.
- constrain_lo_frequencies(addresses: Address | tuple[int, int, int] | list[Address | tuple[int, int, int]], min_freq: float, max_freq: float) float
Sets the LO frequency setting of a group of channels.
This method first constrains the LO frequency setting of the given channels. It then updates the setting values to a suitable LO frequency based on a given RF frequency range.
When a downconverter is not present in the list of addresses (i.e., only RF AWGs), this sets the LO frequency to the midpoint of the highest and lowest RF frequency provided. This uses both sidebands of the RF AWG.
When a downconverter is present in the list of addresses, this chooses the LO frequency such that the minimum IF frequency is above the minimum sideband frequency of 20 MHz. This is to account for the fact that the M5201A Downconverter has a high-pass filter on its IF output ports, and hence does not pass small IF frequencies. Additionally, this avoids the problem of spectral folding, wherein the upper and lower sidebands are indistinguishable after downconversion.
import keysight.qcs as qcs # initialize virtual channels xy_awg = qcs.Channels(range(1), "xy_awgs") readout_awg = qcs.Channels(range(1), "readout_awgs") digs = qcs.Channels(range(1), "digs") # map virtual channels to physical addresses mapper = qcs.ChannelMapper() mapper.add_channel_mapping(xy_awg, [(1, 1, 1)], qcs.InstrumentEnum.M5300AWG) mapper.add_channel_mapping( readout_awg, [(1, 2, 1)], qcs.InstrumentEnum.M5300AWG ) mapper.add_channel_mapping( digs, [(1, 4, 1)], qcs.InstrumentEnum.M5200Digitizer ) mapper.add_downconverters([(1, 4, 1)], [(1, 3, 1)]) # set the LO frequency for the awg in slot 1 xy_lo = mapper.constrain_lo_frequencies([(1, 1, 1)], 6e9, 6.6e9) assert xy_lo == 6.3e9 # set the LO frequency for the awg and downconverter used for readouts readout_lo = mapper.constrain_lo_frequencies( [(1, 2, 1), (1, 3, 1)], 6.4e9, 6.9e9 ) assert readout_lo == 6.38e9
- Parameters:
addresses – The physical channel addresses to set to the same LO frequency.
min_freq – The minimum RF frequency played through a channel.
max_freq – The maximum RF frequency played through a channel.
- Raises:
ValueError – If a specified channel does not have an LO frequency setting.
ValueError – If the range of frequencies is larger than the bandwidth of the M5300 AWG and M5201 downconverter.
- set_delays(addresses: Address | tuple[int, int, int] | list[Address | tuple[int, int, int]], delays: float | list[float] | Scalar[float] | list[Scalar[float]]) None
Sets the delay setting of a group of channels.
- Parameters:
addresses – The physical channel addresses to set.
delays – The delays to set these channels to. All addresses are set to the same delay if provided with only a single delay.
- Raises:
ValueError – If the number of delays given does not match the number of addresses when provided with more than one delay.
- set_lo_frequencies(addresses: Address | tuple[int, int, int] | list[Address | tuple[int, int, int]], lo_frequency: float) None
Sets the LO frequency setting of a group of channels to a given value.
- Parameters:
addresses – The physical channel addresses to set to the given LO frequency.
lo_frequency – The LO frequency to set these channels to.
- Raises:
ValueError – If a specified channel does not have an LO frequency setting.
- class keysight.qcs.channels.PhysicalChannel(address: Address | tuple[int, int, int], instrument: InstrumentEnum | str)
Bases:
CsWrapper
Represents a channel of an instrument.
Note
This class should not be constructed directly, and should instead be constructed through
ChannelMapper
.
- Parameters:
address – The address of this channel.
instrument – The instrument type of this channel.
- property bandwidth: float
The bandwidth of the channel in Hz.
- property instrument: InstrumentEnum
The instrument type of this channel.
- property sample_rate: float | None
The sample rate of the channel in Hz, or
None
for analog channels.
- property settings: ChannelSettings
The settings of this channel.
Instrument Channel Settings
- class keysight.qcs.channels.ChannelSettings
Bases:
CsWrapper
Represents a physical channel’s settings.
- Parameters:
name – The name of this collection of settings.
- property delay: Scalar[float]
The physical channel delay.
The units are in seconds and the default value is
0.0
.
- property name: str
The name of this collection of settings.
- abstract property setting_names: list[str]
The setting names.
- constrain(setting_name: str, source: Scalar[float]) None
Constrains the value of a channel setting to that of another
Scalar
.import keysight.qcs as qcs settings = qcs.BasebandAWGChannelSettings("1x2x1") source = qcs.Scalar("other_scalar", value=0.1, dtype=float) settings.constrain("offset", source) assert settings.offset == source assert settings.offset.value == 0.1 source.value = 0.2 assert settings.offset.value == 0.2This can also be used to tie settings together between channels:
settings_downconverter = qcs.DownconverterChannelSettings("1x2x1") settings_awg = qcs.RFAWGChannelSettings("1x3x1") settings_awg.constrain("lo_frequency", settings_downconverter.lo_frequency) settings_downconverter.lo_frequency.value = 8e9 assert settings_awg.lo_frequency.value == 8e9
- Parameters:
setting_name – The name of the setting to constrain in snake_case.
source – The unique name of this settings collection.
- Raises:
ValueError – If
setting_name
is not a valid setting name.
- get_default_value(setting_name: str) float | None
Returns the default value of a setting.
import keysight.qcs as qcs settings = qcs.BasebandAWGChannelSettings("1x2x1") assert settings.get_default_value("offset") == 0.0
- Parameters:
setting_name – The name of the setting.
- Raises:
ValueError – If
setting_name
is not a valid setting name.
- reset(setting_name: str)
Restores a channel setting to its default state.
import keysight.qcs as qcs settings = qcs.BasebandAWGChannelSettings("1x2x1") settings.offset.value = 0.4 settings.reset("offset") assert settings.offset.value == settings.get_default_value("offset")This method can be used to remove settings constraints.
import keysight.qcs as qcs settings = qcs.BasebandAWGChannelSettings("1x2x1") source = qcs.Scalar("other_scalar", value=0.1, dtype=float) settings.constrain("offset", source) assert settings.offset.value == 0.1 settings.reset("offset") assert settings.offset.value == settings.get_default_value("offset")
- Parameters:
setting_name – The name of the setting to reset in snake_case.
- Raises:
ValueError – If
setting_name
is not a valid setting name.
- class keysight.qcs.channels.BasebandAWGChannelSettings(name)
Bases:
ChannelSettings
Represents the settings of a baseband AWG channel.
import keysight.qcs as qcs settings = qcs.BasebandAWGChannelSettings("1x2x1") assert settings.offset.value == 0.0
- Parameters:
name – The unique name of this settings collection.
- property offset: Scalar[float]
The DC offset voltage as a fraction of the max output voltage.
The default value is
0
and the limits are[-1, 1]
.
- property setting_names: list[str]
The setting names.
- class keysight.qcs.channels.BaseLOChannelSettings
Bases:
ChannelSettings
Represents the settings of a physical channel that has a local oscillator.
- Parameters:
name – The unique name of this settings collection.
- property lo_frequency: Scalar[float]
The local oscillator frequency.
The setting units are Hz and the limits are
[0, 18e9]
. The setting defaults to a value ofNone
, meaning that it must be set before executing. Seeconstrain_lo_frequencies()
for an automated way of setting this value.
- property setting_names: list[str]
The setting names.
- class keysight.qcs.channels.DigitizerChannelSettings(name)
Bases:
ChannelSettings
Represents the settings of a digitizer channel.
import keysight.qcs as qcs settings = qcs.DigitizerChannelSettings("1x3x1") assert settings.range.value == 0.9
- Parameters:
name – The unique name of this settings collection.
- property range: Scalar[float]
The range of this digitizer channel.
The units are in Volts. This defaults to a value of
0.9
and its limits are[0.045, 1.7]
.
- property setting_names: list[str]
The setting names.
- class keysight.qcs.channels.DownconverterChannelSettings(name: str)
Bases:
BaseLOChannelSettings
Represents the settings of a downconverter channel.
import keysight.qcs as qcs settings = qcs.DownconverterChannelSettings("1x4x1") assert settings.lo_frequency.value is None
- Parameters:
name – The unique name of this settings collection.
- class keysight.qcs.channels.RFAWGChannelSettings(name: str)
Bases:
BaseLOChannelSettings
Represents the settings of an RF AWG channel.
import keysight.qcs as qcs setings = qcs.RFAWGChannelSettings("1x5x1") assert settings.lo_frequency.value is None
- Parameters:
name – The unique name of this settings collection.
Supported Instruments
Constants
- qcs.SAMPLE_RATES = {<InstrumentEnum.M3202AWG: 0>: 1000000000.0, <InstrumentEnum.M5300AWG: 1>: 2400000000.0, <InstrumentEnum.M5301AWG: 2>: 2400000000.0, <InstrumentEnum.M5200Digitizer: 3>: 4800000000.0}
- class keysight.qcs.channels.InstrumentEnum
An enum specifying the supported instrument types.
The names (values) are: M3202AWG (0) M5300AWG (1) M5301AWG (2) M5200Digitizer (3) M5201Downconverter (4)
- from_string() str
Construct a <class ‘Keysight.Qcs.SharedTypes.Channels.InstrumentEnum’> from a string.
Waveforms
- class keysight.qcs.channels.ArbitraryEnvelope(times: Iterable[float], amplitudes: Iterable[complex])
Bases:
Envelope
Represents an arbitrary envelope specified by linearly interpolating a list of amplitudes.
Upon construction, the times are renormalized to the unit interval
[0, 1]
and the sampled values are normalized to the unit disc.import keysight.qcs as qcs import numpy as np # initialize an ArbitraryEnvelope pulse = qcs.ArbitraryEnvelope(np.linspace(0, 1, 5), np.linspace(0, 1, 5))
- Parameters:
times – The time (in seconds) corresponding to each of the amplitudes.
amplitudes – The amplitudes of the envelope.
- Raises:
ValueError – If any sampled time is negative or there is no positive sampled time.
- property sampled_amplitudes: ndarray
The normalized sampled amplitudes.
- property sampled_times: ndarray
The normalized times at which the amplitudes were sampled.
- static sample(fn: Callable[[float], complex], n_samples: int) ArbitraryEnvelope
Returns an instance of this class with amplitudes sampled
n_samples
times fromfn
on the interval[0, duration]
.
- Parameters:
fn – The function to sample from.
n_samples – The number of samples.
- class keysight.qcs.channels.BaseWaveform
Bases:
HardwareOperation
A base class for waveforms.
- Parameters:
duration – The duration of the waveform in seconds.
- property envelopes: dict[Envelope, Variable[float]]
The dictionary from envelopes to corresponding amplitudes.
For envelopes \(E_i(t)\) with amplitudes \(\alpha_i\), the envelope of the waveform is given by the linear combination
\[E(t) = \sum_i \alpha_i E_i(t).\]
- render(sample_rate: float, lo_frequency: float = 0.0, sample_offset: float = 0.5) np.ndarray | list[np.ndarray]
Render the waveform as it would appear at the input of a specified channel before mixing with a local oscillator (LO) at a specific frequency.
- Parameters:
sample_rate – The rate at which to sample the envelope in Hz.
lo_frequency – The frequency of the LO in Hz.
sample_offset – The offset of each sample in the sample window. The default value of
0.5
generates samples in the middle of the sample window.
- to_flattop(hold_duration: float | Iterable[float] | Variable[float], fraction: float = 0.5) list[HardwareOperation]
Returns a sequence of three operations where a sample at a specified fraction is held for a specified time.
- Parameters:
hold_duration – How long to hold the sample for.
fraction – The fraction of the duration specifying the sample to hold.
- Raises:
ValueError – If
fraction
is not in[0.0, 1.0]
.
- class keysight.qcs.channels.ConstantEnvelope
Bases:
Envelope
Represents a constant envelope \(E(t) = 1\).
import keysight.qcs as qcs # initialize a ConstantEnvelope pulse = qcs.ConstantEnvelope()
- class keysight.qcs.channels.DCWaveform(duration: float | Iterable[float] | Variable[float], envelope: Envelope, amplitude: float | Variable[float], name: str | None = None)
Bases:
BaseWaveform
A class for unmodulated waveforms.
- Parameters:
duration – The duration of the waveform.
envelope – The shape of the waveform.
amplitude – The amplitude of the waveform relative to the range of the signal generator.
name – An optional name for this.
- class keysight.qcs.channels.Delay(duration: float | Iterable[float] | Variable[float], name: str | None = None)
Bases:
HardwareOperation
A
HardwareOperation
representing a delay.When a delay is present in a series of waveforms, the next RF waveform is modulated by the phase accumulated during the delay, which depends on the frequency of the next RF waveform. This ensures that channels can track phase evolution.
The value of the phase is
exp(1j * sampled_delay * int_freq)
wheresampled_delay
is the exact duration of the delay accounting for finite sampling effects (that is, the output ofdelay.sampled_duration(sample_rate)
) andint_freq
is the output ofwaveform.intermediate_frequency(lo_frequency)
.
- Parameters:
duration – The duration of the delay in seconds.
name – An optional name for this.
- render(sample_rate: float, lo_frequency: float = 0.0, start: float = 0.0) ndarray
Renders the delay as it would appear at the input of a specified channel before mixing with a local oscillator (LO) at a specific frequency.
- Parameters:
sample_rate – The rate at which to sample the operation in Hz.
lo_frequency – The frequency of the LO in Hz.
start – The start time in seconds.
- class keysight.qcs.channels.DerivativeEnvelope(base_envelope: Envelope)
Bases:
Envelope
Represents a derivative envelope, normalized by the maximum absolute value.
The derivative is evaluated using a central finite difference with a step size of 1% of the sample period, unless the sample offset is too close to an edge, in which case it falls back to the appropriate forward or backward finite difference.
import keysight.qcs as qcs # initialize a single derivative envelope base_env = qcs.SineEnvelope() pulse = qcs.DerivativeEnvelope(base_env)
- Parameters:
base_envelope – The base envelope.
- class keysight.qcs.channels.Envelope
Bases:
CsWrapper
An abstract base class for envelopes.
- render(n_samples: int = 64, sample_offset: float = 0.5) ndarray
Render the envelope.
By default, envelopes are normalized to the unit interval and this method will return \(64\) samples.
import keysight.qcs as qcs envelope = qcs.GaussianEnvelope(4) envelope.render()array([9.44711312e-05+0.j, 3.62458897e-04+0.j, 7.79880111e-04+0.j, 1.41928233e-03+0.j, 2.38240131e-03+0.j, 3.80884406e-03+0.j, 5.88593499e-03+0.j, 8.85922081e-03+0.j, 1.30427741e-02+0.j, 1.88280253e-02+0.j, 2.66894332e-02+0.j, 3.71849332e-02+0.j, 5.09488792e-02+0.j, 6.86752013e-02+0.j, 9.10888496e-02+0.j, 1.18904354e-01+0.j, 1.52771524e-01+0.j, 1.93209934e-01+0.j, 2.40535702e-01+0.j, 2.94786083e-01+0.j, 3.55649096e-01+0.j, 4.22406682e-01+0.j, 4.93900196e-01+0.j, 5.68526310e-01+0.j, 6.44269391e-01+0.j, 7.18773229e-01+0.j, 7.89450938e-01+0.j, 8.53627259e-01+0.j, 9.08703130e-01+0.j, 9.52328808e-01+0.j, 9.82569622e-01+0.j, 9.98048126e-01+0.j, 9.98048126e-01+0.j, 9.82569622e-01+0.j, 9.52328808e-01+0.j, 9.08703130e-01+0.j, 8.53627259e-01+0.j, 7.89450938e-01+0.j, 7.18773229e-01+0.j, 6.44269391e-01+0.j, 5.68526310e-01+0.j, 4.93900196e-01+0.j, 4.22406682e-01+0.j, 3.55649096e-01+0.j, 2.94786083e-01+0.j, 2.40535702e-01+0.j, 1.93209934e-01+0.j, 1.52771524e-01+0.j, 1.18904354e-01+0.j, 9.10888496e-02+0.j, 6.86752013e-02+0.j, 5.09488792e-02+0.j, 3.71849332e-02+0.j, 2.66894332e-02+0.j, 1.88280253e-02+0.j, 1.30427741e-02+0.j, 8.85922081e-03+0.j, 5.88593499e-03+0.j, 3.80884406e-03+0.j, 2.38240131e-03+0.j, 1.41928233e-03+0.j, 7.79880111e-04+0.j, 3.62458897e-04+0.j, 9.44711312e-05+0.j])With a given
duration
andsample_rate
, the envelope is rendered as it appears on an instrument.import keysight.qcs as qcs duration = qcs.Scalar("duration", value=30e-9, dtype=float) sample_rate = 1e9 qcs.GaussianEnvelope(4).render(n_samples=duration.value * sample_rate)array([2.31385801e-04+0.j, 1.19875019e-03+0.j, 3.53164225e-03+0.j, 8.74255799e-03+0.j, 1.95121777e-02+0.j, 4.00794614e-02+0.j, 7.63107690e-02+0.j, 1.35045123e-01+0.j, 2.22374001e-01+0.j, 3.40887090e-01+0.j, 4.86580023e-01+0.j, 6.46786686e-01+0.j, 8.00670535e-01+0.j, 9.23090546e-01+0.j, 9.91147531e-01+0.j, 9.91147531e-01+0.j, 9.23090546e-01+0.j, 8.00670535e-01+0.j, 6.46786686e-01+0.j, 4.86580023e-01+0.j, 3.40887090e-01+0.j, 2.22374001e-01+0.j, 1.35045123e-01+0.j, 7.63107690e-02+0.j, 4.00794614e-02+0.j, 1.95121777e-02+0.j, 8.74255799e-03+0.j, 3.53164225e-03+0.j, 1.19875019e-03+0.j, 2.31385801e-04+0.j])
- Parameters:
n_samples – The number of samples to render.
sample_offset – The offset of each sample in the sample window. The default value of
0.5
generates samples in the middle of the sample window.
- class keysight.qcs.channels.GaussianEnvelope(num_sigma: float = 2)
Bases:
Envelope
Represents a truncated Gaussian envelope shifted and rescaled to satisfy \(E(0) = E(1) = 0\) and \(E(0.5) = 1\).
The envelope \(E(t)\) at time \(t\) is
\[E(t) = (1 + \alpha)\exp\left(-(2 * t - 1)^2 n_\sigma^2 / 2 \right) - \alpha\:,\]where \(n_\sigma\) is the number of standard deviations included in the envelope and \(\alpha\) is the scale factor.
import keysight.qcs as qcs # initialize a GaussianEnvelope with three standard deviations pulse = qcs.GaussianEnvelope(3)
- Parameters:
num_sigma – The number of standard deviations to include in the envelope.
- Raises:
ValueError – If
num_sigma
is less than 2.
- property alpha: float
The scale factor used to ensure that \(E(0) = E(1) = 0\) and \(E(0.5) = 1\).
Specifically, \(\alpha = 1 / (\exp\left(n_\sigma^2 / 2\right) - 1)\).
- property num_sigma: float
The number of standard deviations included in the envelope.
- class keysight.qcs.channels.HardwareOperation
Bases:
BaseOperation
A base class for hardware operations.
- Parameters:
duration – The duration of the operation in seconds.
- n_samples(sample_rate: float) int
The number of samples in this operation when sampled at a specific rate.
- Parameters:
sample_rate – The sample rate in Hz.
- sampled_duration(sample_rate: float) float
The duration of the operation in seconds when sampled at a specified rate.
- Parameters:
sample_rate – The rate at which to sample the operation in Hz.
- class keysight.qcs.channels.Hold(duration: float | Iterable[float] | Variable[float], name: str | None = None)
Bases:
HardwareOperation
A
HardwareOperation
representing a hold.When a hold is present in a series of waveforms, the value of the last sample will be held as a constant waveform and modulated based on the previous waveform.
- Parameters:
duration – The duration of the hold in seconds.
name – An optional name for this.
- make_waveform(amplitude: complex, frequency: float | None) BaseWaveform
Makes a waveform equivalent to this based on the last sample value and the frequency of the last waveform.
- Parameters:
value – The value of the sample immediately before this.
frequency – The frequency of the previous waveform.
- class keysight.qcs.channels.MaskEnvelope(base_envelope: Envelope, start: float, end: float)
Bases:
Envelope
Represents the part of an envelope between a specified start and end time.
import keysight.qcs as qcs # initialize a single Mask envelope for the first half of a sine envelope base_env = qcs.SineEnvelope() pulse = qcs.MaskEnvelope(base_env, 0, 0.5)
- Parameters:
base_envelope – The base envelope.
start – The start of the mask as a fraction of the unit interval.
end – The end of the mask as a fraction of the unit interval.
- Raises:
ValueError – If
start
orend
is outside[0.0, 1.0]
.ValueError – If
end
is less thanstart
.
- property end: float
The end of the mask as a fraction of the unit interval.
- property start: float
The start of the mask as a fraction of the unit interval.
- class keysight.qcs.channels.PhaseIncrement(phase: float | Variable[float], name: str | None = None)
Bases:
HardwareOperation
A
HardwareOperation
representing a phase increment. This operation always has duration \(0\).When a phase increment is present in a series of waveforms, the phase of the next
RFWaveform
will be incremented.
- Parameters:
phase – The phase to increment the next RF waveform by in radians.
name – An optional name for this.
- class keysight.qcs.channels.RFWaveform(duration: float | Iterable[float] | Scalar[float], envelope: Envelope, amplitude: float | Variable[float], rf_frequency: float | Variable[float], instantaneous_phase: float | Variable[float] = 0.0, post_phase: float | Variable[float] = 0.0, name: str | None = None)
Bases:
BaseWaveform
Represents a waveform with target frequency or frequencies.
The signal \(V(t)\) at time \(t\) after modulating an envelope \(E(t)\) by a frequency \(f\) and a phase \(\phi\) is
\[V(t) = E(t) \exp(2 \pi j f t + \phi).\]import keysight.qcs as qcs # initialize a 100ns base envelope base = qcs.ConstantEnvelope() # initialize an RFWaveform with an amplitude of 0.3 and a frequency of 5 GHz pulse1 = qcs.RFWaveform(100e-9, base, 0.3, 5e9) # initialize a sliceable RFWaveform with different frequencies rf = qcs.Array("rf", value=[5e9, 6e9]) pulse2 = qcs.RFWaveform(100e-9, base, 0.3, rf)Note
If
rf_frequency
andinstantaneous_phase
are given asfloat
s, they are converted to a scalar. Otherwise, if they are given as scalar or array, they are stored as provided.
- Parameters:
duration – The duration of the waveform.
envelope – The envelope of the waveform before modulation.
amplitude – The amplitude of the waveform relative to the range of the signal generator.
rf_frequency – The RF frequency of the output pulse in Hz.
instantaneous_phase – The amount (in radians) by which the phase of this waveform is shifted, relative to the rotating frame set by
rf_frequency
.post_phase – The amount (in radians) by which the phase of all subsequent RF waveforms are shifted relative to the rotating frame.
name – An optional name for this.
- Raises:
ValueError – If
rf_frequency`, ``instantaneous_phase
, andpost_phase
have invalid (not one-dimensional) or inconsistent shapes.
- property instantaneous_phase: dict[Envelope, Variable[float]]
The amount (in radians) by which the phase of each envelope is shifted.
- property post_phase: Variable[float]
The amount (in radians) by which the phases of all subsequent RF waveforms are shifted.
- drag(coeff: float | Iterable[float] | Variable[float]) RFWaveform
Returns a new waveform with a Derivative Removal by Adiabatic Gate (DRAG) envelope that uses the envelope of this as the base.
For a base envelope \(E(t)\) and a DRAG coefficient \(b\), the corresponding DRAG envelope is given by
\[DRAG(E(t), b) = E(t) + ibE'(t),\]where \(E'(t)\) is the derivative of \(E(t)\) with respect to time.
- Parameters:
coeff – The coefficient \(b\) of the imaginary part.
- intermediate_frequency(lo_frequency: float) float
The intermediate frequency in radians per second for a specified LO frequency.
- Parameters:
lo_frequency – The LO frequency in Hz.
- Raises:
ValueError – If the RF frequency has not been set.
- phase_update(sample_rate: float, lo_frequency: float = 0.0) complex
The complex phasor by which subsequent RF waveforms should be multiplied due to phase accumulation during this Waveform and the specified
post_phase()
.
- Parameters:
sample_rate – The rate at which to sample the envelope in Hz.
lo_frequency – The LO frequency in Hz.
- phase_per_fractional_sample(sample_rate: float, lo_frequency: float = 0.0, fraction: float = 1) complex
The complex phasor specifying the phase accumulated during a fraction of a sample period.
- Parameters:
sample_rate – The rate at which to sample the envelope in Hz.
lo_frequency – The LO frequency in Hz.
fraction – The fraction of a sample period to compute the phase accumulation for.