silq.pulses package

Submodules

silq.pulses.pulse_modules module

class silq.pulses.pulse_modules.PulseRequirement(property, requirement)[source]

Bases: object

Pulse attribute requirement for a PulseImplementation

This class is used in Interfaces when registering a PulseImplementation, to impose additional constraints for implementing the pulse.

The class is never directly instantiated, but is instead created from a dict passed to the pulse_requirements kwarg of a PulseImplementation.

Example

For an AWG can apply sine pulses, but only up to its Nyquist limit max_frequency, the following implementation is used:

>>> SinePulseImplementation(
        pulse_requirements=[('frequency', {'max': max_frequency})])
Parameters
  • property (str) – Pulse attribute for which to place a constraint.

  • requirement (Union[list, Dict[str, Any]]) –

    Requirement that a property must satisfy.

    • If a dict, allowed keys are min and max, the value being the minimum/maximum value.

    • If a list, the property must be an element in the list.

satisfies(pulse)[source]

Checks if a given pulses satisfies this PulseRequirement.

Parameters

pulse – Pulse to be verified.

Return type

bool

Returns

True if pulse satisfies PulseRequirement.

Raises

Exception – Pulse requirement cannot be interpreted.

verify_requirement(requirement)[source]

Verifies that the requirement is valid.

A valid requirement is either a list, or a dict with keys min and/or max.

Raises

AssertionError – Requirement is not valid.

class silq.pulses.pulse_modules.PulseSequence(pulses=None, allow_untargeted_pulses=True, allow_targeted_pulses=True, allow_pulse_overlap=True, final_delay=None)[source]

Bases: qcodes.instrument.parameter_node.ParameterNode

Pulse container that can be targeted in the Layout.

It can be used to store untargeted or targeted pulses.

If multiple pulses with the same name are added, Pulse.id is set for the pulses sharing the same name, starting with 0 for the first pulse.

Retrieving pulses

To retrieve a pulse with name ‘read’:

>>> pulse_sequence['read']
>>> pulse_sequence.get_pulse(name='read')

Both methods work, but the latter is more versatile, as it also allows filtering of pulses by discriminants other than name.

If there are multiple pulses with the same name, the methods above will raise an error because there is no unique pulse with name read. Instead, the Pulse.id must also be passed to discriminate the pulses:

>>> pulse_sequence['read[0]']
>>> pulse_sequence.get_pulse(name='read', id=0)

Both methods return the first pulse added whose name is ‘read’.

Iterating over pulses

Pulses in a pulse sequence can be iterated over via:

>>> for pulse in pulse_sequence:
>>>     # perform actions

This will return the pulses sorted by Pulse.t_start. Pulses for which Pulse.enabled is False are ignored.

Checking if pulse sequence contains a pulse

Pulse sequences can be treated similar to a list, and so checking if a pulse exists in a list is done as such:

>>> pulse in pulse_sequence

Note that this does not compare object equality, but only checks if all attributes match.

Checking if a pulse sequence contains pulses

Checking if a pulse sequence contains pulses is similar to a list:

>>> if pulse_sequence:
>>>     # pulse_sequence contains pulses
Targeting a pulse sequence in the `Layout`

A pulse sequence can be targeted in the layout, which will distribute the pulses among it’s InstrumentInterface such that the pulse sequence is executed. Targeting of a pulse sequence is straightforward:

>>> layout.pulse_sequence = pulse_sequence

After this, the instruments can be configured via Layout.setup.

Parameters
  • pulses (List[Pulse]) – Pulse list to place in PulseSequence. Pulses can also be added later using PulseSequence.add.

  • allow_untargeted_pulses (bool) – Allow untargeted pulses (without corresponding Pulse.implementation) to be added to PulseSequence. InstrumentInterface.pulse_sequence should have this unchecked.

  • allow_targeted_pulses (bool) – Allow targeted pulses (with corresponding Pulse.implementation) to be added to PulseSequence. InstrumentInterface.pulse_sequence should have this checked.

  • allow_pulse_overlap (bool) – Allow pulses to overlap in time. If False, an error will be raised if a pulse is added that overlaps in time. If pulse has a Pulse.connection, an error is only raised if connections match as well.

  • duration (float) – Total duration of pulse sequence. Equal to Pulse.t_stop of last pulse, unless explicitly set. Can be reset to t_stop of last pulse by setting to None, and will automatically be reset every time a pulse is added/removed.

  • final_delay (Union[float, None]) – Optional final delay at the end of the pulse sequence. The interface of the primary instrument should incorporate any final delay. The default is .5 ms

  • enabled_pulses (List[Pulse]) – Pulse list with Pulse.enabled True. Updated when a pulse is added or Pulse.enabled is changed.

  • disabled_pulses (List[Pulse]) – Pulse list with Pulse.enabled False. Updated when a pulse is added or Pulse.enabled is changed.

  • t_start_list (List[float]) – Pulse.t_start list for all enabled pulses. Can contain duplicates if pulses share the same Pulse.t_start.

  • t_stop_list (List[float]) – Pulse.t_stop list for all enabled pulses. Can contain duplicates if pulses share the same Pulse.t_stop.

  • t_list (List[float]) – Combined list of Pulse.t_start and Pulse.t_stop for all enabled pulses. Does not contain duplicates.

Notes

  • If pulses are added without Pulse.t_start defined, the pulse is assumed to start after the last pulse finishes, and a connection is made with the attribute t_stop of the last pulse, such that if the last pulse t_stop changes, t_start is changed accordingly.

  • All pulses in the pulse sequence are listened to via Pulse.signal. Any time an attribute of a pulse changes, a signal will be emitted, which can then be interpreted by the pulse sequence.

add(*pulses, reset_duration=True)[source]

Adds pulse(s) to the PulseSequence.

Parameters
  • *pulses (Pulse) – Pulses to add

  • reset_duration (bool) – Reset duration of pulse sequence to t_stop of final pulse

Returns

Added pulses, which are copies of the original pulses.

Return type

List[Pulse]

Raises

Note

When a pulse is added, it is first copied, to ensure that the original pulse remains unmodified. For an speed-optimized version, see PulseSequence.quick_add

clear()[source]

Clear all pulses from pulse sequence.

connection_conditions = None
default_final_delay = 0.0005
finish_quick_add()[source]

Finish adding pulses via PulseSequence.quick_add

Steps performed:

  • Sorting of pulses

  • Checking that pulses do not overlap

  • Adding unique id’s to pulses in case a name is shared by pulses

get_connection(**conditions)[source]

Get unique connections from any pulse satisfying conditions.

Parameters

**conditions – Connection and pulse conditions.

Returns

Unique Connection satisfying conditions

Return type

Connection

See also

Pulse.satisfies_conditions, Connection.satisfies_conditions.

Raises

AssertionError – No unique connection satisfying conditions.

get_pulse(**conditions)[source]

Get unique pulse in pulse sequence satisfying conditions.

Parameters

**conditions – Connection and pulse conditions.

Returns

Unique pulse satisfying conditions

Return type

Pulse

See also

Pulse.satisfies_conditions, Connection.satisfies_conditions.

Raises

RuntimeError – No unique pulse satisfying conditions

get_pulses(enabled=True, connection=None, connection_label=None, **conditions)[source]

Get list of pulses in pulse sequence satisfying conditions

Parameters
  • enabled – Pulse must be enabled

  • connection – pulse must have connection

  • **conditions – Additional connection and pulse conditions.

Returns

Pulses satisfying conditions

Return type

List[Pulse]

See also

Pulse.satisfies_conditions, Connection.satisfies_conditions.

get_trace_shapes(sample_rate, samples)[source]

Get dictionary of trace shapes for given sample rate and samples

Parameters
  • sample_rate (int) – Acquisition sample rate

  • samples (int) – acquisition samples.

Returns

{Pulse.full_name: trace_shape}

Return type

Dict[str, tuple]

Note

trace shape depends on Pulse.average

get_transition_voltages(pulse=None, connection=None, t=None)[source]

Finds the voltages at the transition between two pulses.

Note

This method can potentially cause issues, and should be avoided until it’s better thought through

Parameters
  • pulse (Pulse) – Pulse starting at transition voltage. If not provided, connection and t must both be provided.

  • connection (Connection) – connection along which the voltage transition occurs

  • t (float) – Time at which the voltage transition occurs.

Return type

Tuple[float, float]

Returns

(Voltage before transition, voltage after transition)

plot(t_range=None, points=2001, subplots=False, scale_ylim=True, figsize=None, legend=True, **connection_kwargs)[source]
pulse_conditions = None
static pulses_overlap(pulse1, pulse2)[source]

Tests if pulse1 and pulse2 overlap in time and connection.

Parameters
  • pulse1 (Pulse) – First pulse

  • pulse2 (Pulse) – Second pulse

Return type

bool

Returns

True if pulses overlap

Note

If either of the pulses does not have a connection, this is not tested.

quick_add(*pulses, copy=True, connect=True, reset_duration=True)[source]

“Quickly add pulses to a sequence skipping steps and checks.

This method is used in the during the Layout targeting of a pulse sequence, and should generally only be used if speed is a crucial factor.

Note

When using this method, make sure to finish adding pulses with PulseSequence.finish_quick_add.

The following steps are skipped and are performed in PulseSequence.finish_quick_add:

  • Assigning a unique pulse id if multiple pulses share the same name

  • Sorting pulses

  • Ensuring no pulses overlapped

Parameters
  • *pulses – List of pulses to be added. Note that these won’t be copied if copy is False, and so the t_start may be set

  • copy (bool) – Whether to copy the pulse before applying operations

  • reset_duration (bool) – Reset duration of pulse sequence to t_stop of final pulse

Returns

Added pulses. If copy is False, the original pulses are returned.

Note

If copy is False, the id of original pulses may be set when calling PulseSequence.quick_add.

remove(*pulses)[source]

Removes Pulse or pulses from pulse sequence

Parameters

pulses – Pulse(s) to remove from PulseSequence

Raises

AssertionError – No unique pulse found

snapshot_base(update=False, params_to_skip_update=[])[source]

State of the pulse sequence as a JSON-compatible dict.

Parameters
  • update (bool) – If True, update the state by querying the instrument. If False, just use the latest values in memory.

  • params_to_skip_update (Sequence[str]) – List of parameter names that will be skipped in update even if update is True. This is useful if you have parameters that are slow to update but can be updated in a different way (as in the qdac)

Returns

base snapshot

Return type

dict

sort()[source]

Sort pulses by Pulse.t_start

up_to_date()[source]

Checks if a pulse sequence is up to date or needs to be generated.

Used by PulseSequenceGenerator.

Return type

bool

Returns

True by default, can be overridden in subclass.

class silq.pulses.pulse_modules.PulseImplementation(pulse_requirements=[])[source]

Bases: object

InstrumentInterface implementation for a Pulse.

Each InstrumentInterface should have corresponding pulse implementations for the pulses it can output. These should be subclasses of the PulseImplementation.

When a PulseSequence is targeted in the Layout, each Pulse is directed to the relevant InstrumentInterface, which will call target the pulse using the corresponding PulseImplementation. During Pulse targeting, a copy of the pulse is made, and the PulseImplementation is added to Pulse.implementation.

Creating a PulseImplementation

A PulseImplementation is specific for a certain Pulse, which should be defined in PulseImplementation.pulse_class.

A PulseImplementation subclass may override the following methods:

Parameters

pulse_requirements – Requirements that pulses must satisfy to allow implementation.

add_pulse_requirement(property, requirement)[source]

Add requirement that any pulse must satisfy to be targeted

get_additional_pulses(interface)[source]

Provide any additional pulses needed such as triggering pulses

The additional pulses can be requested should usually have Pulse.connection_conditions specified to ensure that the pulse is sent to the right connection.

Parameters

interface (InstrumentInterface) – Interface to which this PulseImplementation belongs

Returns

List of additional pulses needed.

Return type

List[Pulse]

implement(*args, **kwargs)[source]

Implements a targeted pulse for an InstrumentInterface.

This method is called during InstrumentInterface.setup.

Implementation of a targeted pulse is very dependent on the interface. For an AWG, this method may return a list of waveform points. For a triggering source, this method may return the triggering time. In very simple cases, this method may not even be necessary.

Parameters
  • *args – Interface-specific args to use

  • **kwargs – Interface-specific kwargs to use

Return type

Any

Returns

Instrument-specific return values.

See also

Other interface source codes may serve as a guide for this method.

pulse_class = None
pulse_config = None
satisfies_requirements(pulse, match_class=True)[source]

Checks if a pulse satisfies pulse requirements

Parameters
target_pulse(pulse, interface, connections, **kwargs)[source]

Tailors a PulseImplementation to a specific pulse.

Targeting happens in three stages:

  1. Both the pulse and pulse implementation are copied.

  2. PulseImplementation of the copied pulse is set to the copied pulse implementation, and PulseImplementation.pulse is set to the copied pulse. This way, they can both reference each other.

  3. The targeted pulse is returned

Parameters
  • pulse (Pulse) – Pulse to be targeted.

  • interface (InstrumentInterface) – PulseImplementation belongs.

  • connections (List[Connection]) – All connections in Layout.

  • **kwargs – Additional unused kwargs

Raises

TypeError – Pulse class does not match PulseImplementation.pulse_class

silq.pulses.pulse_sequences module

class silq.pulses.pulse_sequences.ESRPulseSequence(**kwargs)[source]

Bases: silq.pulses.pulse_sequences.PulseSequenceGenerator

PulseSequenceGenerator for electron spin resonance (ESR).

This pulse sequence can handle many of the basic pulse sequences involving ESR. The pulse sequence is generated from its pulse settings attributes.

In general the pulse sequence is as follows:

  1. Perform any pre_pulses defined in ESRPulseSequence.pre_pulses.

  2. Perform stage pulse ESRPulseSequence.ESR['stage_pulse']. By default, this is the plunge pulse.

  3. Perform ESR pulse within plunge pulse, the delay from start of plunge pulse is defined in ESRPulseSequence.ESR['pulse_delay'].

  4. Perform read pulse ESRPulseSequence.ESR['read_pulse'].

  5. Repeat steps 2 and 3 for each ESR pulse in ESRPulseSequence.ESR['ESR_pulses'], which by default contains single pulse ESRPulseSequence.ESR['ESR_pulse'].

  6. Perform empty-plunge-read sequence (EPR), but only if ESRPulseSequence.EPR['enabled'] is True. EPR pulses are defined in ESRPulseSequence.EPR['pulses'].

  7. Perform any post_pulses defined in ESRPulseSequence.post_pulses.

Parameters
  • ESR (dict) –

    Pulse settings for the ESR part of the pulse sequence. Contains the following items:

    • stage_pulse (Pulse): Stage pulse in which to perform ESR (e.g. plunge). Default is ‘plunge DCPulse.

    • ESR_pulse (Pulse): Default ESR pulse to use. Default is ‘ESR’ SinePulse.

    • ESR_pulses (List[Union[str, Pulse]]): List of ESR pulses to use. Can be strings, in which case the string should be an item in ESR whose value is a Pulse.

    • pulse_delay (float): ESR pulse delay after beginning of stage pulse. Default is 5 ms.

    • read_pulse (Pulse): Pulse after stage pulse for readout and initialization of electron. Default is ‘read_initialize` DCPulse.

  • EPR (dict) –

    Pulse settings for the empty-plunge-read (EPR) part of the pulse sequence. This part is optional, and is used for non-ESR contast, and to measure dark counts and hence ESR contrast. Contains the following items:

    • enabled (bool): Enable EPR sequence.

    • pulses (List[Pulse]): List of pulses for EPR sequence. Default is empty, plunge, read_long DCPulse.

  • pre_pulses (List[Pulse]) – Pulses before main pulse sequence. Empty by default.

  • post_pulses (List[Pulse]) – Pulses after main pulse sequence. Empty by default.

  • pulse_settings (dict) – Dict containing all pulse settings.

  • **kwargs – Additional kwargs to PulseSequence.

Examples

The following code measures two ESR frequencies and performs an EPR from which the contrast can be determined for each ESR frequency:

>>> ESR_pulse_sequence = ESRPulseSequence()
>>> ESR_pulse_sequence.ESR['pulse_delay'] = 5e-3
>>> ESR_pulse_sequence.ESR['stage_pulse'] = DCPulse['plunge']
>>> ESR_pulse_sequence.ESR['ESR_pulse'] = FrequencyRampPulse('ESR_adiabatic')
>>> ESR_pulse_sequence.ESR_frequencies = [39e9, 39.1e9]
>>> ESR_pulse_sequence.EPR['enabled'] = True
>>> ESR_pulse_sequence.pulse_sequence.generate()

The total pulse sequence is plunge-read-plunge-read-empty-plunge-read with an ESR pulse in the first two plunge pulses, 5 ms after the start of the plunge pulse. The ESR pulses have different frequencies.

Notes

For given pulse settings, ESRPulseSequence.generate will recreate the pulse sequence from settings.

property ESR_frequencies
add_ESR_pulses(ESR_frequencies=None)[source]

Add ESR pulses to the pulse sequence

Parameters

ESR_frequencies – List of ESR frequencies. If provided, the pulses in ESR[‘ESR_pulses’] will be reset to copies of ESR[‘ESR_pulse’] with the provided frequencies

Note

Each element in ESR_frequencies can also be a list of multiple frequencies, in which case multiple pulses with the provided subfrequencies will be used.

generate(ESR_frequencies=None)[source]
class silq.pulses.pulse_sequences.ESRRamseyDetuningPulseSequence(**kwargs)[source]

Bases: silq.pulses.pulse_sequences.ESRPulseSequence

” Created to implement an arbitrary number of DC pulses in a Ramsey sequence during the wait time. Please Refer to ESRPulseSequence for the ESR pulses.

Highlights:

  • DC pulses can be stored in [‘ESR’][‘detuning_pulses’] and will become the new ‘stage_pulse’

  • t_start_detuning is the time at which the DC detuning pulses start. In the case the detuning starts right after the ESR pi/2 , then this time should

be equal to [‘pre_delay’] +ESR[‘piHalf’].duration

  • If the time for the detuning pulses is shorter that the total stage duration, the final part of the pulse (called post_stage) will the standard stage pulse

add_ESR_pulses(ESR_frequencies=None)[source]

Add ESR pulses to the pulse sequence

Parameters

ESR_frequencies – List of ESR frequencies. If provided, the pulses in ESR[‘ESR_pulses’] will be reset to copies of ESR[‘ESR_pulse’] with the provided frequencies

Note

Each element in ESR_frequencies can also be a list of multiple frequencies, in which case multiple pulses with the provided subfrequencies will be used.

class silq.pulses.pulse_sequences.FlipFlopPulseSequence(**kwargs)[source]

Bases: silq.pulses.pulse_sequences.PulseSequenceGenerator

PulseSequenceGenerator for hitting the flip-flop transition

The flip-flop transition is the one where both the electron and nucleus flip in opposite direction, thus keeping the total spin constant.

This pulse sequence is mainly used to flip the nucleus to a certain state without having to perform NMR or even having to measure the electron.

The flip-flop transitions between a nuclear spin state S1 and (S1+1) is:

f_ESR(S1) + A/2 + gamma_n * B_0,

where f_ESR(S1) is the ESR frequency for nuclear state S1, A is the hyperfine, gamma_n is the nuclear Zeeman, and B_0 is the static magnetic field. The transition will flip (electron down, nucleus S+1) to (electron up, nucleus S) and vice versa.

Parameters
  • ESR (dict) –

    Pulse settings for the ESR part of the pulse sequence. Contains the following items:

    • frequency (float): ESR frequency below the flip-flop transition (Hz).

    • hyperfine (float): Hyperfine interaction (Hz).

    • nuclear_zeeman (float): Nuclear zeeman strength (gamma_n*B_0)

    • stage_pulse (Pulse): Stage pulse in which to perform ESR (e.g. plunge). Default is `DCPulse`(‘plunge’).

    • pre_flip_ESR_pulse (Pulse): ESR pulse to use before the flip-flop pulse to pre-flip the electron to spin-up, which allows the nucleus to be flipped to a higher state. Default is `SinePulse`(‘ESR’).

    • flip_flop_pulse (Pulse): Flip-flop ESR pulse, whose frequency will be set to A/2 + gamma_n*B_0 higher than the frequency setting. Default pulse is `SinePulse`(‘ESR’)

    • pre_flip (bool): Whether to pre-flip the electron, to transition to a higher nuclear state. Default is False.

    • pre_delay (float): Delay between start of stage pulse and first pulse (pre_flip_ESR_pulse or flip_flop_pulse).

    • inter_delay (float): Delay between pre_flip_ESR_pulse and flip_flop_pulse. Ignored if pre_flip is False

    • post_delay (float): Delay after last frequency pulse and end of stage pulse.

  • pre_pulses (List[Pulse]) – Pulses before main pulse sequence. Empty by default.

  • post_pulses (List[Pulse]) – Pulses after main pulse sequence. Empty by default.

  • pulse_settings (dict) – Dict containing all pulse settings.

  • **kwargs – Additional kwargs to PulseSequence.

add_ESR_pulses()[source]
generate()[source]

Updates the pulse sequence

class silq.pulses.pulse_sequences.NMRCPMGPulseSequence(pulses=[], **kwargs)[source]

Bases: silq.pulses.pulse_sequences.NMRPulseSequence

PulseSequenceGenerator for nuclear magnetic resonance (NMR).

This pulse sequence can handle many of the basic pulse sequences involving NMR. The pulse sequence is generated from its pulse settings attributes.

In general, the pulse sequence is as follows:

  1. Perform any pre_pulses defined in NMRPulseSequence.pre_pulses.

  2. Perform NMR sequence

    1. Perform stage pulse NMRPulseSequence.NMR['stage_pulse']. Default is ‘empty’ DCPulse.

    2. Perform NMR pulses within the stage pulse. The NMR pulses defined in NMRPulseSequence.NMR['NMR_pulses'] are applied successively. The delay after start of the stage pulse is NMRPulseSequence.NMR['pre_delay'], delays between NMR pulses is NMRPulseSequence.NMR['inter_delay'], and the delay after the final NMR pulse is NMRPulseSequence.NMR['post_delay'].

  3. Perform ESR sequence

    1. Perform stage pulse NMRPulseSequence.ESR['stage_pulse']. Default is ‘plunge’ DCPulse.

    2. Perform ESR pulse within stage pulse for first pulse in NMRPulseSequence.ESR['ESR_pulses'].

    3. Perform NMRPulseSequence.ESR['read_pulse'], and acquire trace.

    4. Repeat steps 1 - 3 for each ESR pulse. The different ESR pulses usually correspond to different ESR frequencies (see NMRPulseSequence.ESR_frequencies).

    5. Repeat steps 1 - 4 for NMRPulseSequence.ESR['shots_per_frequency'] This effectively interleaves the ESR pulses, which counters effects of the nucleus flipping within an acquisition.

By measuring the average up proportion for each ESR frequency, a switching between high and low up proportion indicates a flipping of the nucleus

Parameters
  • NMR (dict) –

    Pulse settings for the NMR part of the pulse sequence. Contains the following items:

    • stage_pulse (Pulse): Stage pulse in which to perform NMR (e.g. plunge). Default is ‘empty’ DCPulse. Duration of stage pulse is adapted to NMR pulses and delays.

    • NMR_pulse (Pulse): Default NMR pulse to use. By default ‘NMR’ SinePulse.

    • NMR_pulses (List[Union[str, Pulse]]): List of NMR pulses to successively apply. Can be strings, in which case the string should be an item in NMR whose value is a Pulse. Default is single element NMRPulseSequence.NMR['NMR_pulse'].

    • pre_delay (float): Delay after start of stage pulse, until first NMR pulse.

    • inter_delay (float): Delay between successive NMR pulses.

    • post_delay (float): Delay after final NMR pulse until stage pulse end.

  • ESR (dict) –

    Pulse settings for the ESR part of the pulse sequence. Contains the following items:

    • stage_pulse (Pulse): Stage pulse in which to perform ESR (e.g. plunge). Default is ‘plunge DCPulse.

    • ESR_pulse (Pulse): Default ESR pulse to use. Default is ‘ESR’ SinePulse.

    • ESR_pulses (List[Union[str, Pulse]]): List of ESR pulses to use. Can be strings, in which case the string should be an item in ESR whose value is a Pulse.

    • pulse_delay (float): ESR pulse delay after beginning of stage pulse. Default is 5 ms.

    • read_pulse (Pulse): Pulse after stage pulse for readout and initialization of electron. Default is ‘read_initialize` DCPulse.

  • EPR (dict) –

    Pulse settings for the empty-plunge-read (EPR) part of the pulse sequence. This part is optional, and is used for non-ESR contast, and to measure dark counts and hence ESR contrast. Contains the following items:

    • enabled (bool): Enable EPR sequence.

    • pulses (List[Pulse]): List of pulses for EPR sequence. Default is empty, plunge, read_long DCPulse.

  • pre_pulses (List[Pulse]) – Pulses before main pulse sequence. Empty by default.

  • pre_ESR_pulses (List[Pulse]) – Pulses before ESR readout pulse sequence. Empty by default.

  • post_pulses (List[Pulse]) – Pulses after main pulse sequence. Empty by default.

  • pulse_settings (dict) – Dict containing all pulse settings.

  • **kwargs – Additional kwargs to PulseSequence.

See also

NMRParameter

Notes

For given pulse settings, NMRPulseSequence.generate will recreate the pulse sequence from settings.

add_ESR_pulses(pulse_sequence=None, previous_pulse=None)[source]
add_NMR_pulses(pulse_sequence=None)[source]
generate()[source]

Updates the pulse sequence

class silq.pulses.pulse_sequences.NMRPulseSequence(pulses=[], **kwargs)[source]

Bases: silq.pulses.pulse_sequences.PulseSequenceGenerator

PulseSequenceGenerator for nuclear magnetic resonance (NMR).

This pulse sequence can handle many of the basic pulse sequences involving NMR. The pulse sequence is generated from its pulse settings attributes.

In general, the pulse sequence is as follows:

  1. Perform any pre_pulses defined in NMRPulseSequence.pre_pulses.

  2. Perform NMR sequence

    1. Perform stage pulse NMRPulseSequence.NMR['stage_pulse']. Default is ‘empty’ DCPulse.

    2. Perform NMR pulses within the stage pulse. The NMR pulses defined in NMRPulseSequence.NMR['NMR_pulses'] are applied successively. The delay after start of the stage pulse is NMRPulseSequence.NMR['pre_delay'], delays between NMR pulses is NMRPulseSequence.NMR['inter_delay'], and the delay after the final NMR pulse is NMRPulseSequence.NMR['post_delay'].

  3. Perform ESR sequence

    1. Perform stage pulse NMRPulseSequence.ESR['stage_pulse']. Default is ‘plunge’ DCPulse.

    2. Perform ESR pulse within stage pulse for first pulse in NMRPulseSequence.ESR['ESR_pulses'].

    3. Perform NMRPulseSequence.ESR['read_pulse'], and acquire trace.

    4. Repeat steps 1 - 3 for each ESR pulse. The different ESR pulses usually correspond to different ESR frequencies (see NMRPulseSequence.ESR_frequencies).

    5. Repeat steps 1 - 4 for NMRPulseSequence.ESR['shots_per_frequency'] This effectively interleaves the ESR pulses, which counters effects of the nucleus flipping within an acquisition.

By measuring the average up proportion for each ESR frequency, a switching between high and low up proportion indicates a flipping of the nucleus

Parameters
  • NMR (dict) –

    Pulse settings for the NMR part of the pulse sequence. Contains the following items:

    • stage_pulse (Pulse): Stage pulse in which to perform NMR (e.g. plunge). Default is ‘empty’ DCPulse. Duration of stage pulse is adapted to NMR pulses and delays.

    • NMR_pulse (Pulse): Default NMR pulse to use. By default ‘NMR’ SinePulse.

    • NMR_pulses (List[Union[str, Pulse]]): List of NMR pulses to successively apply. Can be strings, in which case the string should be an item in NMR whose value is a Pulse. Default is single element NMRPulseSequence.NMR['NMR_pulse'].

    • pre_delay (float): Delay after start of stage pulse, until first NMR pulse.

    • inter_delay (float): Delay between successive NMR pulses.

    • post_delay (float): Delay after final NMR pulse until stage pulse end.

  • ESR (dict) –

    Pulse settings for the ESR part of the pulse sequence. Contains the following items:

    • stage_pulse (Pulse): Stage pulse in which to perform ESR (e.g. plunge). Default is ‘plunge DCPulse.

    • ESR_pulse (Pulse): Default ESR pulse to use. Default is ‘ESR’ SinePulse.

    • ESR_pulses (List[Union[str, Pulse]]): List of ESR pulses to use. Can be strings, in which case the string should be an item in ESR whose value is a Pulse.

    • pulse_delay (float): ESR pulse delay after beginning of stage pulse. Default is 5 ms.

    • read_pulse (Pulse): Pulse after stage pulse for readout and initialization of electron. Default is ‘read_initialize` DCPulse.

  • EPR (dict) –

    Pulse settings for the empty-plunge-read (EPR) part of the pulse sequence. This part is optional, and is used for non-ESR contast, and to measure dark counts and hence ESR contrast. Contains the following items:

    • enabled (bool): Enable EPR sequence.

    • pulses (List[Pulse]): List of pulses for EPR sequence. Default is empty, plunge, read_long DCPulse.

  • pre_pulses (List[Pulse]) – Pulses before main pulse sequence. Empty by default.

  • pre_ESR_pulses (List[Pulse]) – Pulses before ESR readout pulse sequence. Empty by default.

  • post_pulses (List[Pulse]) – Pulses after main pulse sequence. Empty by default.

  • pulse_settings (dict) – Dict containing all pulse settings.

  • **kwargs – Additional kwargs to PulseSequence.

See also

NMRParameter

Notes

For given pulse settings, NMRPulseSequence.generate will recreate the pulse sequence from settings.

add_ESR_pulses(pulse_sequence=None, previous_pulse=None)[source]
add_NMR_pulses(pulse_sequence=None)[source]
generate()[source]

Updates the pulse sequence

class silq.pulses.pulse_sequences.PulseSequenceGenerator(pulses=[], **kwargs)[source]

Bases: silq.pulses.pulse_modules.PulseSequence

Base class for a PulseSequence that is generated from settings.

generate()[source]
up_to_date()[source]

Checks if a pulse sequence is up to date or needs to be generated.

Used by PulseSequenceGenerator.

Returns

True by default, can be overridden in subclass.

class silq.pulses.pulse_sequences.T2ElectronPulseSequence(**kwargs)[source]

Bases: silq.pulses.pulse_sequences.PulseSequenceGenerator

PulseSequenceGenerator for electron coherence (T2) measurements.

This pulse sequence can handle measurements on the electron coherence time, including adding refocusing pulses

In general the pulse sequence is as follows:

  1. Perform any pre_pulses defined in T2ElectronPulseSequence.pre_pulses.

  2. Perform stage pulse T2ElectronPulseSequence.ESR['stage_pulse']. By default, this is the plunge pulse.

  3. Perform initial ESR pulse T2ElectronPulseSequence.ESR['ESR_initial_pulse'] within plunge pulse, the delay until start of the ESR pulse is defined in T2ElectronPulseSequence.ESR['pre_delay'].

  4. For T2ElectronPulseSequence.ESR['num_refocusing_pulses'] times, wait for T2ElectronPulseSequence.ESR['inter_delay']` and apply ``T2ElectronPulseSequence.ESR['ESR_refocusing_pulse].

  5. Wait T2ElectronPulseSequence.ESR['ESR_refocusing_pulse'] and apply T2ElectronPulseSequence.ESR['ESR_final_pulse'].

  6. Wait T2ElectronPulseSequence.ESR['post_delay'], then stop stage pulse and Perform read pulse T2ElectronPulseSequence.ESR['read_pulse'].

  7. Perform empty-plunge-read sequence (EPR), but only if T2ElectronPulseSequence.EPR['enabled'] is True. EPR pulses are defined in T2ElectronPulseSequence.EPR['pulses'].

  8. Perform any post_pulses defined in ESRPulseSequence.post_pulses.

Parameters
  • ESR (dict) –

    Pulse settings for the ESR part of the pulse sequence. Contains the following items:

    stage_pulse (Pulse)

    Stage pulse in which to perform ESR (e.g. plunge). Default is ‘plunge DCPulse.

    ESR_initial_pulse (Pulse)

    Initial ESR pulse to apply within stage pulse. Default is ESR_piHalf SinePulse. Ignored if set to None

    ESR_refocusing_pulse (Pulse)

    Refocusing ESR pulses between initial and final ESR pulse. Zero refocusing pulses measures T2star, one refocusing pulse measures T2Echo. Default is ESR_pi SinePulse.

    ESR_final_pulse (Pulse)

    Final ESR pulse within stage pulse. Default is ESR_piHalf SinePulse. Ignored if set to None.

    num_refocusing_pulses (int)

    Number of refocusing pulses T2ElectronPulseSequence.ESR['ESR_refocusing_pulse'] to apply.

    pre_delay (float)

    Delay after stage pulse before first ESR pulse.

    inter_delay (float)

    Delay between successive ESR pulses.

    post_delay (float)

    Delay after final ESR pulse.

    read_pulse (Pulse)

    Pulse after stage pulse for readout and initialization of electron. Default is ‘read_initialize` DCPulse.

  • EPR (dict) –

    Pulse settings for the empty-plunge-read (EPR) part of the pulse sequence. This part is optional, and is used for non-ESR contast, and to measure dark counts and hence ESR contrast. Contains the following items:

    enabled

    (bool): Enable EPR sequence.

    pulses

    (List[Pulse]): List of pulses for EPR sequence. Default is empty, plunge, read_long DCPulse.

  • pre_pulses (List[Pulse]) – Pulses before main pulse sequence. Empty by default.

  • post_pulses (List[Pulse]) – Pulses after main pulse sequence. Empty by default.

  • pulse_settings (dict) – Dict containing all pulse settings.

  • **kwargs – Additional kwargs to PulseSequence.

Notes

For given pulse settings, T2ElectronPulseSequence.generate will recreate the pulse sequence from settings.

add_ESR_pulses()[source]
generate()[source]

Updates the pulse sequence

silq.pulses.pulse_types module

class silq.pulses.pulse_types.Pulse(name=None, id=None, t_start=None, t_stop=None, duration=None, acquire=False, initialize=False, connection=None, enabled=True, average='none', connection_label=None, connection_requirements={}, connect_to_config=True)[source]

Bases: qcodes.instrument.parameter_node.ParameterNode

Representation of physical pulse, component in a PulseSequence.

A Pulse is a representation of a physical pulse, usually one that is outputted by an instrument. All pulses have specific timings, defined by t_start, t_stop, and duration. Additional attributes specify ancillary properties, such as if the acquisition instrument should acquire the pulse. Specific pulse types (subclasses of Pulse) have additional properties, such as a frequency.

Pulses can be added to a PulseSequence, which can in turn be targeted by the Layout. Here, each Pulse is targeted to a Connection, which can modify the pulse (e.g. applying an amplitude scale). Next the pulse is targeted by the output and input InstrumentInterface of the connection, which provide an instrument-specific implementation of the pulse.

Pulses usually have a name, which is used to retrieve any default properties from the config. If the pulse name is an entry in silq.config.{environment}.pulses, the properties in that entry are used by default. These default values can be overridden by either passing them explicitly during the pulse initialization, or afterwards.

Example

If silq.config.{environment}.pulses contains:

>>> {'read': {'amplitude': 0.5, 'duration': 100e-3}}

Then creating the following pulse will partially use these properties:

>>> DCPulse('read', duration=200e-3)
DCPulse('read', amplitude=0.5, duration=200e-3)

Here the default amplitude value is used, but the duration is overridden during initialization.

Parameters
  • name (Optional[str]) – Pulse name. If corresponding name is registered in pulse config, its properties will be copied to the pulse.

  • id (Optional[int]) – Unique pulse identifier, assigned when added to PulseSequence if it already has another pulse with same name. Pre-existing pulse will be assigned id 0, and will increase for each successive pulse added.

  • full_name – Pulse name, including id if not None. If id is not None, full_name is ‘{name}[{id}]’

  • environment – Config environment to use for pulse config. If not set, default environment (silq.config.properties.default_environment) is used.

  • t_start (Optional[float]) – Pulse start time. If undefined and added to PulseSequence, it will be set to Pulse.t_stop of last pulse. If no pulses are present, it will be set to zero.

  • t_stop (Optional[float]) – Pulse stop time. Is updated whenever t_start or duration is changed. Changing this modifies duration but not t_start.

  • duration (Optional[float]) – Pulse duration.

  • acquire (bool) – Flag to acquire pulse. If True, pulse will be passed on to the acquisition InstrumentInterface by the Layout during targeting.

  • initialize (bool) – Pulse is used for initialization. This signals that the pulse can exist before the pulse sequence starts. In this case, pulse duration should be zero.

  • connection (Connection) – Connection that pulse is targeted to. Is only set for targeted pulse.

  • enabled (bool) – Pulse is enabled. If False, it still exists in a PulseSequence, but is not included in targeting.

  • average (str) –

    Pulse acquisition average mode. Allowed modes are:

    • ’none’: No averaging (return samples x points_per_trace).

    • ’trace’: Average over time (return points_per_trace).

    • ’point’: Average over time and sample (return single point).

    • ’point_segment:{N}’ Segment trace into N segment, average each segment into a point.

  • connection_label (Optional[str]) – Connection label that Pulse should be targeted to. These are defined in silq.config.{environment}.connections. If unspecified, pulse can only be targeted if connection_requirements uniquely determine connection.

  • connection_requirements (dict) – Requirements that a connection must satisfy for targeting. If connection_label is defined, these are ignored.

  • pulse_config – Pulse config whose attributes to match. If it exists, equal to silq.config.{environment}.pulses.{pulse.name}, otherwise equal to zero.

  • properties_config – General properties config whose attributes to match. If it exists, equal to silq.config.{environment}.properties, otherwise None. Only Pulse.properties_attrs are matched.

  • properties_attrs (List[str]) – Attributes in properties config to match. Should be defined in __init__ before calling Pulse.__init__.

  • implementation (PulseImplementation) – Pulse implementation for targeted pulse, see PulseImplementation.

  • connect_to_config (bool) – Connect parameters to the config (default True)

get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

multiple_senders = False
satisfies_conditions(pulse_class=None, name=None, **kwargs)[source]

Checks if pulse satisfies certain conditions.

Each kwarg is a condition, and can be a value (equality testing) or it can be a tuple (relation, value), in which case the relation is tested. Possible relations: ‘>’, ‘<’, ‘>=’, ‘<=’, ‘==’

Parameters
  • pulse_class – Pulse must have specific class.

  • name (Optional[str]) – Pulse must have name, which may include id.

  • **kwargs – Additional pulse attributes to be satisfied. Examples are t_start, connection, etc. Time t can also be passed, in which case the condition is satisfied if t is between Pulse.t_start and Pulse.t_stop (including limits).

Return type

bool

Returns

True if all conditions are satisfied.

snapshot_base(update=False, params_to_skip_update=None)[source]

State of the instrument as a JSON-compatible dict.

Parameters
  • update (bool) – If True, update the state by querying the instrument. If False, just use the latest values in memory.

  • params_to_skip_update (Optional[Sequence[str]]) – List of parameter names that will be skipped in update even if update is True. This is useful if you have parameters that are slow to update but can be updated in a different way (as in the qdac)

Returns

base snapshot

Return type

dict

class silq.pulses.pulse_types.SteeredInitialization(name=None, t_no_blip=None, t_max_wait=None, t_buffer=None, readout_threshold_voltage=None, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Initialization pulse to ensure a spin-down electron is loaded.

This is performed by continuously measuring at the read stage until no blip has been measured for t_no_blip, or until t_max_wait has elapsed.

Parameters
  • name (Optional[str]) – Pulse name

  • t_no_blip (Optional[float]) – Min duration without measuring blips. If condition is met, an event should be fired to the primary instrument to start the pulse sequence.

  • t_max_wait (Optional[float]) – Maximum wait time for the no-blip condition. If t_max_wait has elapsed, an event should be fired to the primary instrument to start the pulse seqeuence.

  • t_buffer (Optional[float]) – Duration of a single acquisition buffer. Shorter buffers mean that one can more closely approach t_no_blip, but too short buffers may cause lagging.

  • readout_threshold_voltage (Optional[float]) – Threshold voltage for a blip.

  • **kwargs – Additional parameters of Pulse.

class silq.pulses.pulse_types.SinePulse(name=None, frequency=None, phase=None, amplitude=None, power=None, offset=None, frequency_sideband=None, sideband_mode=None, phase_reference=None, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Sinusoidal pulse

Parameters
  • name (Optional[str]) – Pulse name

  • frequency (Optional[float]) – Pulse frequency

  • phase (Optional[float]) – Pulse phase

  • amplitude (Optional[float]) – Pulse amplitude. If not set, power must be set.

  • power (Optional[float]) – Pulse power. If not set, amplitude must be set.

  • offset (Optional[float]) – amplitude offset, zero by default

  • frequency_sideband (Optional[float]) – Mixer sideband frequency (off by default).

  • sideband_mode (Optional[float]) – Sideband frequency to apply. This feature must be existent in interface. Not used if not set.

  • phase_reference (Optional[str]) –

    What point in the the phase is with respect to. Can be two modes:

    • ’absolute’: phase is with respect to Pulse.t_start.

    • ’relative’: phase is with respect to t=0 (phase-coherent).

  • **kwargs – Additional parameters of Pulse.

Notes

Either amplitude or power must be set, depending on the instrument that should output the pulse.

get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

class silq.pulses.pulse_types.FrequencyRampPulse(name=None, frequency_start=None, frequency_stop=None, frequency=None, frequency_deviation=None, amplitude=None, power=None, offset=None, phase=None, frequency_sideband=None, sideband_mode=None, phase_reference=None, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Linearly increasing/decreasing frequency Pulse.

Parameters
  • name (Optional[str]) – Pulse name

  • frequency_start (Optional[float]) – Start frequency

  • frequency_stop (Optional[float]) – Stop frequency.

  • frequency (Optional[float]) – Center frequency, only used if frequency_start and frequency_stop not used.

  • frequency_deviation (Optional[float]) – Frequency deviation, only used if frequency_start and frequency_stop not used.

  • frequency_final – Can be either start or stop indicating the frequency when reaching frequency_stop should go back to the initial frequency or stay at current frequency. Useful if the pulse doesn’t immediately stop at the end (this depends on how the corresponding instrument/interface is programmed).

  • amplitude (Optional[float]) – Pulse amplitude. If not set, power must be set.

  • power (Optional[float]) – Pulse power. If not set, amplitude must be set.

  • offset (Optional[float]) – amplitude offset, zero by default

  • frequency_sideband (Optional[float]) – Sideband frequency to apply. This feature must be existent in interface. Not used if not set.

  • sideband_mode – Type of mixer sideband (‘IQ’ by default)

  • **kwargs – Additional parameters of Pulse.

Notes

Either amplitude or power must be set, depending on the instrument that should output the pulse.

get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

class silq.pulses.pulse_types.DCPulse(name=None, amplitude=None, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

DC (fixed-voltage) Pulse.

Parameters
  • name (Optional[str]) – Pulse name

  • amplitue – Pulse amplitude

  • **kwargs – Additional parameters of Pulse.

get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

class silq.pulses.pulse_types.DCRampPulse(name=None, amplitude_start=None, amplitude_stop=None, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Linearly ramping voltage Pulse.

Parameters
get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

class silq.pulses.pulse_types.TriggerPulse(name='trigger', duration=1e-07, amplitude=1.0, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Triggering pulse.

Parameters
  • name (str) – Pulse name.

  • duration (float) – Pulse duration (default 100 ns).

  • amplitude (float) – Pulse amplitude (default 1V).

  • **kwargs – Additional parameters of Pulse.

default_amplitude = 1.0
default_duration = 1e-07
get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

class silq.pulses.pulse_types.MarkerPulse(name=None, amplitude=1.0, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Marker pulse

Parameters
  • name (Optional[str]) – Pulse name.

  • amplitude (float) – Pulse amplitude (default 1V).

  • **kwargs – Additional parameters of Pulse.

default_amplitude = 1.0
get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

class silq.pulses.pulse_types.TriggerWaitPulse(name=None, t_start=None, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Pulse that wait until condition is met and then applies trigger

Parameters

Note

Duration is fixed at 0s.

class silq.pulses.pulse_types.MeasurementPulse(name=None, acquire=True, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Pulse that is only used to signify an acquiition

This pulse is not directed to any interface other than the acquisition interface.

Parameters
  • name – Pulse name.

  • acquire – Acquire pulse (default True)

  • **kwargs – Additional parameters of Pulse.

get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

class silq.pulses.pulse_types.CombinationPulse(name=None, pulse1=None, pulse2=None, relation=None, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Pulse that is a combination of multiple pulse types.

Like any other pulse, a CombinationPulse has a name, t_start and t_stop. t_start and t_stop are calculated and updated from the pulses that make up the combination.

A CombinationPulse is itself a child of the Pulse class, therefore a CombinationPulse can also be used in consecutive combinations like:

>>> CombinationPulse1 = SinePulse1 + DCPulse
>>>CombinationPulse2 = SinePulse2 + CombinationPulse1

Examples

>>> CombinationPulse = SinePulse + DCPulse
>>> CombinationPulse = DCPulse * SinePulse
Parameters
  • name (Optional[str]) – The name for this CombinationPulse.

  • pulse1 (Optional[Pulse]) – The first pulse this combination is made up from.

  • pulse2 (Optional[Pulse]) – The second pulse this combination is made up from.

  • relation (Optional[str]) –

    The relation between pulse1 and pulse2. This must be one of the following:

    • ’+’ : pulse1 + pulse2

    • ’-‘ : pulse1 - pulse2

    • ’*’ : pulse1 * pulse2

  • **kwargs – Additional kwargs of Pulse.

property combination_string
get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

property pulse_details
t_start
t_stop
class silq.pulses.pulse_types.AWGPulse(name=None, fun=None, wf_array=None, interpolate=True, **kwargs)[source]

Bases: silq.pulses.pulse_types.Pulse

Arbitrary waveform pulses that can be implemented by AWGs.

This class allows the user to create a truly arbitrary pulse by either:
  • providing a function that converts time-stamps to waveform points

  • an array of waveform points

The resulting AWGPulse can be sampled at different sample rates, interpolating between waveform points if necessary.

Parameters
  • name (Optional[str]) – Pulse name.

  • fun (Optional[Callable]) – The function used for calculating waveform points based on time-stamps.

  • wf_array (Optional[ndarray]) – Numpy array of (float) with time-stamps and waveform points.

  • interpolate (bool) – Use interpolation of the wf_array.

classmethod from_array(array, **kwargs)[source]
classmethod from_function(function, **kwargs)[source]
get_voltage(t)[source]

Get voltage(s) at time(s) t.

Raises

AssertionError – not all t between Pulse.t_start and Pulse.t_stop

Return type

Union[float, ndarray]

Module contents