utils module

Collection of functions that might be useful, or might not.

class presto.utils.ProgressBar(size, update_time=1.0)

Bases: object

Prints a progress bar to stderr, keeping track of remaining time.

Parameters:
  • size (int) – how many “units of work” will be done

  • update_time (float) – limit the update of the progress bar to update_time seconds

Example

>>> pb = ProgressBar(100)
>>> pb.start()
>>> for _ in range(100):
>>>     time.sleep(0.1)  # <-- do work here!
>>>     pb.increment()
>>> pb.done()
done()

Terminate the progress bar and print total time.

increment(inc=1)

Increment the progress bar.

Will not change the text on stderr if too little time has passed since last update.

Parameters:

inc (int) – how many “units of work” have been done since last call

start()

Start counting time.

class presto.utils.Spinner(msg, quiet=False)

Bases: object

Prints a spinner to stderr, while some work is being done.

Parameters:
  • msg (str) – the header message of the spinner

  • quiet (bool) – set to True to inhibit printing and thus disable the spinner

Example

Using a context manager (with block):

>>> with Spinner("Doing lots of work")
>>>     time.sleep(3.14)  # <-- do work here!

Will print sequentially (all in one line):

Doing lots of work... -
Doing lots of work... /
Doing lots of work... |
Doing lots of work... \
Doing lots of work... -
Doing lots of work... /
...
Doing lots of work: 3.2s
presto.utils.as_flat_list(x)

Return x as a flat unidimensional list.

Parameters:

x (object) – An arbitrarily nested list, tuple, np.ndarray, or a mixture thereof.

Return type:

list

Returns:

A flat, unidimensional list with all the objects of x.

presto.utils.format_precision(n, s)

Format a value and uncertainty to the correct number of significant digits.

Parameters:
  • n (float) – nominal value.

  • s (float) – uncertainty.

Return type:

str

Returns:

a formatted string with numbers rounded to significant digits.

Examples

>>> format_precision(36.91226461435421, 0.4060358649863922)
'36.9 ± 0.4'
presto.utils.format_sec(s)

Format a time interval in seconds into a more human-readable string.

Parameters:

s (float | timedelta) – time interval in seconds.

Return type:

str

Returns:

time interval in the form “Xh Ym Z.zs”.

Examples

>>> format_sec(np.pi * 1e+8)
'9y 348d 20h 27m 45.4s'
>>> format_sec(np.exp(-10))
'45.4us'
presto.utils.get_sourcecode(script_filename)

Open a file and return its content.

Parameters:

script_filename (str) – path to the file.

Return type:

list[str]

Returns:

the lines of the file at script_filename.

presto.utils.newman_phases(n)

Calculate phases for a frequency comb with low crest factor.

Parameters:

n (int) – the number of tones/components in the frequency comb

Return type:

ndarray[tuple[Any, ...], dtype[floating]]

Returns:

an array of phases in radians with length n

Notes

The individual tones/components of the comb are assumed to be equally spaced in frequency.

The returned phases are computed using the method by [Newman1965] as reported by [Boyd1986]: \(\phi_k = \pi k^2 / n\) for \(k = 0, ..., n-1\).

See also

newman_scale()

References

[Newman1965]

– D. J. Newman, “An L1 extremal problem for polynomials”, Proceedings of the American Mathematical Society 16(6), 1287-1290 (1965).

[Boyd1986]

– S. Boyd, “Multitone signals with low crest factor”, IEEE Transactions on Circuits and Systems 33(10), 1018-1022 (1986).

Examples

Set up a frequency comb with 100 tones starting at 100 MHz and separated by 10 kHz, using Newman phases and maximum (full-scale) amplitude.

Using lockin mode:

>>> import numpy as np
>>>
>>> from presto.lockin import Lockin
>>> from presto.utils import newman_phases, newman_scale
>>>
>>> N = 100  # number of tones in frequency comb
>>> AMP = 1.0  # full-scale amplitude
>>> OFFSET = 100e6  # starting frequency of comb
>>> DELTA = 10e3  # frequency separation inside comb
>>> OUT_PORT = 1
>>>
>>> with Lockin() as lck:
>>>     freqs = OFFSET + DELTA * np.arange(N)
>>>     amps = np.full(N, AMP / newman_scale(N))
>>>     phases = newman_phases(N)
>>>
>>>     lck.set_df(DELTA)
>>>     og = lck.add_output_group(OUT_PORT, N)
>>>     og.set_frequencies(freqs).set_phases(phases).set_amplitudes(amps)
>>>     lck.apply_settings()

Using spectral mode:

>>> import numpy as np
>>>
>>> from presto.spectral import Spectral
>>> from presto.utils import newman_phases, newman_scale
>>>
>>> N = 100  # number of tones in frequency comb
>>> AMP = 1.0  # full-scale amplitude
>>> OFFSET = 100e6  # starting frequency of comb
>>> DELTA = 10e3  # frequency separation inside comb
>>> OUT_PORT = 1
>>>
>>> with Spectral() as spec:
>>>     freqs = OFFSET + DELTA * np.arange(N)
>>>     amps = np.full(N, AMP / newman_scale(N))
>>>     phases = newman_phases(N)
>>>
>>>     period = 1.0 / DELTA
>>>     spec.output_multicos(OUT_PORT, period, freqs, amps, phases)
>>>     # ... measure here ...
presto.utils.newman_scale(n)

Global amplitude-scaling factor for a frequency comb using Newman phases.

Divide the maximum amplitude of the comb by this factor to ensure that the output is not clipped due to the crest factor.

Parameters:

n (int) – the number of tones/components in the frequency comb

See also

newman_phases()

Return type:

double

presto.utils.plot_sequence(pls, period=None, repeat_count=1, num_averages=1)

Plots pulse sequence for interactive inspection.

See Plot pulse sequences for more documentation.

Parameters:
  • pls (pulsed.Pulsed) – Pulsed object that contains the pulse sequence to be plotted.

  • period (float | None) – Measurement time in seconds for one repetition. Must be a multiple of get_clk_T()

  • repeat_count (int | tuple) – Number of times to repeat the experiment and stack the acquired data (no averaging). For multi-dimensional parameter sweeps, repeat_count is a tuple where each element specifies the number of repetitions along that axis.

  • num_averages (int) – Number of times to repeat the whole sequence (including the repetitions due to repeat_count) and average the acquired data.

Returns:

The matplotlib Figure instance.

Return type:

matplotlib.figure.Figure

Examples

>>> from presto import pulsed
>>> from presto.utils import plot_sequence, sin2
>>>
>>> with pulsed.Pulsed(dry_run=True) as pls:
>>>     # define the pulse and set parameters
>>>     pulse = pls.setup_template(1, 0, 0.5 * sin2(100))
>>>     pls.setup_scale_lut(1, 0, 0.707)
>>>     pls.set_store_ports(1)
>>>     pls.set_store_duration(100e-9)
>>>
>>>     # define the pulse sequence
>>>     pls.store(0.0)
>>>     pls.output_pulse(26e-9, pulse)
>>>
>>>     # plot the pulse sequence
>>>     plot_sequence(pls)
Raises:

ImportError – if matplotlib is not installed.

presto.utils.recommended_dac_config(freq, *, print_all=False, plot=False)

Recommended DAC configuration.

Parameters:
  • freq (float) – signal frequency in Hz

  • print_all (bool) – set to True to print all valid DAC configurations for freq, together with frequency of spurious tones and suggested reconstruction filters

  • plot (bool) – set to True to show a matplotlib figure with DAC zones and frequencies of signal and spurious tones

Returns:

A tuple of (dac_mode, dac_fsample) where

represent the most recommended DAC configuration.

Raises:

ValueError – if freq is negative or above 9.6 GHz.

Examples

Print detailed information:

>>> recommended_dac_config(5.2e9, print_all=True)
Valid DAC configurations for signal at 5200.0 MHz:
  * Mixed42-G8 (score 1680):
      - low-frequency spur: 2800.0 MHz
      - high-frequency spur: 10800.0 MHz
      - compatible band-pass filters: ['VBFZ-5500-S+', 'ZBSS-6G-S+', 'ZVBP-5G-S+']
  * Mixed02-G6 (score 1173):
      - low-frequency spur: 800.0 MHz
      - high-frequency spur: 6800.0 MHz
      - compatible band-pass filters: ['ZVBP-5G-S+']

Use suggested configuration directly:

>>> dac_mode, dac_fsample = recommended_dac_config(5.2e9)
>>> print(f"Best DacMode is {dac_mode.name}, DacFSample is {dac_fsample.name}")
DacMode is Mixed42, DacFSample is G8
>>> from presto import lockin, pulsed
>>> lck = lockin.Lockin(dac_mode=dac_mode, dac_fsample=dac_fsample)
>>> pls = pulsed.Pulsed(dac_mode=dac_mode, dac_fsample=dac_fsample)
presto.utils.rotate_opt(data, return_x=False)

Rotates data so that all the signal is in the I quadrature (real part).

Parameters:
Return type:

ndarray[tuple[Any, ...], dtype[cdouble]] | tuple[ndarray, float]

Returns:

data * np.exp(1j * x), with x such that np.std(ret.imag) is minimum. dtype=complex128.

If return_x=True, also return the angle x.

presto.utils.si_prefix_scale(data)

Calculare the appropriate SI prefix for data.

Parameters:

data – an integer, a float, a list or array of those, …

Return type:

tuple[str, float]

Returns:

a tuple (prefix, scale)

Examples

>>> si_prefix_scale(3.1415e-5)
('μ', 1000000)
>>> value = 2.718e-7
>>> (unit, scale) = si_prefix_scale(value)
>>> print(f"The length is {scale * value} {unit}m")
The length is 271.8 nm
presto.utils.sin2(nr_samples, drag=0.0)

Create a \(\sin^2\) envelope/template.

Parameters:
  • nr_samples (int)

  • drag (float) – if nonzero, use DRAG with \(\lambda / \alpha\) equal to drag

Return type:

ndarray

Returns:

NumPy array for desired pulse with dtype=float64 if drag=0.0, or dtype=complex128 otherwise.

presto.utils.sinP(P, nr_samples)

Create a \(\sin^P\) envelope/template.

Parameters:
Return type:

ndarray

Returns:

NumPy array for desired pulse with dtype=float64.

presto.utils.ssh_reboot(address)

Deprecated since version 2.17.0: Use ssh.reboot() instead.

presto.utils.ssh_restart(address)

Deprecated since version 2.17.0: Use ssh.restart() instead.

presto.utils.to_pm_pi(phase)

Converts a phase in radians into the [-π, +π) interval.

Parameters:

phase (float)

Return type:

float

presto.utils.triangle(nr_samples)

Create a triangular envelope/template.

Parameters:

nr_samples (int)

Return type:

ndarray

Returns:

NumPy array for desired pulse with dtype=float64.

presto.utils.untwist_downconversion(I_port, Q_port)

Convert a measured IQ pair into a low/high sideband pair.

Parameters:
Return type:

tuple[ndarray[tuple[Any, ...], dtype[complexfloating]], ndarray[tuple[Any, ...], dtype[complexfloating]]]

Returns:

a tuple (L_sideband, H_sideband) of NumPy arrays with dtype=complex128.