lockin module

Continuous-wave generation and measurement.

Detailed information is provided in the documentation for each class.

Lockin

Use the hardware in continuous-wave mode.

SymmetricLockin

Special-purpose version of Lockin with same frequencies on input and output ports (symmetric).

InputGroup

Settings of a lock-in input group.

OutputGroup

Settings of a lock-in output group.

SymmetricGroup

Settings of a symmetric lock-in group.

LockinReceiver

A receiver of lockin data running in the background.


Lockin class

class presto.lockin.Lockin(*, ext_ref_clk=False, force_reload=False, dry_run=False, address=None, port=None, adc_mode=AdcMode.Direct, adc_fsample=None, dac_mode=DacMode.Direct, dac_fsample=None, force_config=False)

Use the hardware in continuous-wave mode.

Warning

Create only one instance at a time. This class is designed to be instantiated with Python’s with statement, see Examples section.

Parameters:
  • ext_ref_clk (Union[None, bool, int, float]) – if None or False use internal reference clock; if True use external reference clock (10 MHz); if float or int use external reference clock at ext_ref_clk Hz

  • force_reload (bool) – if True re-configure clock and reload firmware even if there’s no change from the previous settings.

  • dry_run (bool) – if True don’t connect to hardware, for testing only.

  • address (Optional[str]) – IP address or hostname of the hardware. If None, use factory default "192.168.42.50".

  • port (Optional[int]) – port number of the server running on the hardware. If None, use factory default 7878.

  • adc_mode (AdcMode or list) – configure the inputs to sample in direct mode (default), or to use the digital mixers for downconversion. See Notes.

  • adc_fsample (AdcFSample or list) – configure the inputs sampling rate. If None (default), choose optimal rate automatically. See Notes.

  • dac_mode (DacMode or list) – configure the outputs to work in direct mode (default), or to use the digital mixers for upconversion. See Notes.

  • dac_fsample (DacFSample or list) – configure the outputs sampling rate. If None (default), choose optimal rate automatically. See Notes.

  • force_config (bool) – if True skip checks on DacModes not recommended for high DAC sampling rates.

Raises:

ValueError – if adc_mode or dac_mode are not valid Converter modes; if adc_fsample or dac_fsample are not valid Converter rates.

Notes

In all the Examples, it is assumed that the imports import numpy as np and from presto import lockin have been performed, and that this class has been instantiated in the form lck = lockin.Lockin(), or, much much better, using the with lockin.Lockin() as lck construct as below.

For an introduction to adc_mode and dac_mode, see Direct and Mixed mode. For valid values of adc_mode and dac_mode, see Converter modes. For valid values of adc_fsample and dac_fsample, see Converter rates. For advanced configuration, e.g. different converter rates on different ports, see Advanced tile configuration.

add_input_group(port, nr_freq)

Create and return a new input group

Parameters:
  • port (int) – which input port the group should sample data from

  • nr_freq (int) – how many frequencies the input group should demodulate

Return type:

InputGroup

add_output_group(ports, nr_freq)

Create and return a new output group

Parameters:
  • ports (int or array_like) – which output port(s) the group should output data to. If a list, the output will be replicated on all ports

  • nr_freq (int) – how many frequencies the output group should modulate

Return type:

OutputGroup

apply_required()

Check whether calling apply_settings() is required to sync outstanding changes.

Return type:

bool

apply_settings(*, auto_sync=True, only_if=False)

Apply the settings to the hardware.

Parameters:

auto_sync (bool) – if True (default), trigger signal generation internally. Set to False to synchronize to an external source, e.g. a Metronomo unit.

Note

Prior to a call to this function, any change of settings has no effect on the hardware.

close()

Gracely disconnect from the hardware.

Call this method if the class was instantiated without a with statement. This method is called automatically when exiting a with block and before the object is destructed.

get_Tm()

Get measurement time in seconds.

The inverse of the measurement bandwidth.

Return type:

float

See also

get_df()

get_clk_T()

Period of the programmable-logic clock in seconds.

Return type:

float

get_clk_f()

Frequency of the programmable-logic clock in Hz.

Return type:

float

get_df()

Get measurement bandwidth in Hz.

Return type:

float

See also

set_df() get_Tm()

get_fs(which)

Get sampling frequency for which converter in Hz.

Parameters:

which (str) – "adc" for input and "dac" for output.

Raises:

ValueError – if which is unknown.

Return type:

float

get_ns(which='adc')

Get number of samples per lock-in window.

The sampling rate divided by the measurement bandwidth.

Parameters:

which (str) – “adc” for input and “dac” for output.

Return type:

int

get_pixels(n, *, summed=False, fir_coeffs=None, nsum=250, quiet=False, auto_sync=True)

Get lock-in packets (pixels) from the hardware.

Parameters:
  • n (int) – the number of lock-in packets to measure.

  • summed (bool) – when True, calculate on the hardware the mean and standard deviation of the acquired data in chunks of nsum lock-in packets.

  • fir_coeffs (array_like of float) – coefficients for FIR filter to be applied to measured data. 43 coefficients must be provided, or pass None (default) to disable the filter. Not available if summed=False. See also Notes and Examples sections.

  • nsum (int) – Only active when summed=True. How many lock-in packets (at rate get_df()) are included in a “chunk”. The resulting data rate is df / nsum. Ignored if summed=False.

  • quiet (bool) – if True, don’t check for inputs out of range

  • auto_sync (bool) – if True (default), trigger signal acquisition internally. Set to False to synchronize to an external source, e.g. a Metronomo unit.

Return type:

dict

Returns:

A dictionary with key port and value depending on the value of summed.

The key is always:

  • port (int): input port measured

When summed=False (default), the value is a tuple of:

  • freqs (ndarray, dtype=np.float64): frequencies at which the lockin measurement was done.

  • pixels (ndarray, dtype=np.complex64): measured lock-in data in ratio of full-scale input. shape is (n, len(freqs)). When using digital downconversion (adc_mode is AdcMode.Mixed), these are the pixels of the I port of the digital mixer.

  • pixels_q (ndarray, dtype=np.complex64): only present when using digital downconversion (adc_mode is AdcMode.Mixed), these are the pixels of the Q port of the digital mixer.

When summed=True, the value is a tuple of:

  • freqs (ndarray, dtype=np.float64): frequencies at which the lockin measurement was done.

  • mean_I (ndarray, dtype=np.complex64): calculated mean of nsum consecutive lock-in packets from the I port of the digital downconversion. shape is (n, len(freqs)).

  • std_I (ndarray, dtype=np.complex64): calculated standard deviation of nsum consecutive lock-in packets from the I port of the digital downconversion. shape is (n, len(freqs)). The standard deviation has a real and an imaginary part; abs(std) is the total standard deviation according to Complex random variable.

  • mean_Q (ndarray, dtype=np.complex64): same as mean_I, but from the Q port.

  • std_Q (ndarray, dtype=np.complex64): same as std_I, but from the Q port.

Raises:

RuntimeError – if apply_settings() was not called after changing some setting

Notes

This method locks execution until at least n measured packets are available.

summed=True is only implemented when using digital downconversion (adc_mode is AdcMode.Mixed).

Useful functions for computing the coefficients fir_coeffs for the FIR filter are remez() and firwin() in scipy.signal.

Examples

Measure 1k lock-in packets, and low-pass filter the measured data:

>>> from scipy.signal import firwin
>>> coeffs = firwin(43, 80e3, fs=lck.get_df())  # low-pass filter with 80 kHz cutoff
>>> data = lck.get_pixels(n=1000, fir_coeffs=coeffs)
>>> freqs, (pixels_I, pixels_Q) = data[input_port]
>>> freqs.shape
(32,)
>>> pixels_I.shape
(1000, 32)
>>> pixels_Q.shape
(1000, 32)

Measure 100k lock-in packets, and compute mean and standard deviation in chunks of 100 packets:

>>> data = lck.get_pixels(n=1000, summed=True, nsum=100)
>>> freqs, (mean_I, std_I, mean_Q, std_Q) = data[input_port]
>>> freqs.shape
(32,)
>>> mean_I.shape
(1000, 32)
>>> std_Q.shape
(1000, 32)
hardware: Hardware

interface to hardware features common to all modes of operation

set_df(df)

Set measurement bandwith.

The new setting is not applied until apply_settings() is called!

Parameters:

df (float) – Measurement bandwith in Hz.

Notes

Non-tuned measurement bandwidths can’t be set in hardware. When passing a non-tuned df, the closest tuned value will be set in hardware. To avoid confusion, it is recommended to explicitly tune df before calling this method.

set_dither(state, output_ports)

Add pseudorandom noise to the generated output.

Can improve harmonic and intermodulation distortion when working with small output amplitudes.

The change is active immediately

Parameters:
  • state (bool) – if True, add pseudorandom noise to the output

  • output_ports (int or array_like) – which output port(s) should be affected

set_phase_reset(reset_phase)

Reset the phase of the reference signals at the end of every lock-in window.

The new setting is not applied until apply_settings() is called!

Parameters:

reset_phase (bool) – if True the phase reset is enabled, set to False to disable.

Notes

This setting is enabled by default. See Notes in tune() for rationale.

set_trigger_out(states, delay=0.0, width=1e-07)

Output a trigger on the digital output ports at the start of every demodulation or summing window.

Times will be rounded to closest integer multiple of get_clk_T().

Parameters:
  • states (Union[int, List[int]]) –

    enable/disable the trigger on each of the digital output ports. Valid values are:

    • 0 no trigger output

    • 1 trigger for each new lock-in window

    • 2 trigger for each new sum window (mean and std)

  • delay (float) – delay trigger rising edge from start of lock-in window, in seconds

  • width (float) – trigger-high duration, in seconds

Raises:

ValueError – if delay and width are negative, or too large

Return type:

None

Examples

Output a 100ns trigger on port 1 every summing window and on port 2 every demodulation window:

>>> lck.set_trigger_out([2, 1])
stream_pixels(*, summed=False, fir_coeffs=None, nsum=250, quiet=False, auto_sync=True, rpu_params=None)

Receive lock-in packets (pixels) from the hardware in the background.

This method returns a LockinReceiver object that receives a stream of packets in a separate thread, without blocking the execution of the current thread.

Warning

This method is experimental and the exposed API might change in future releases.

Parameters:
  • summed (bool) – when True, calculate on the hardware the mean and standard deviation of the acquired data in chunks of nsum lock-in packets.

  • fir_coeffs (array_like of float) – coefficients for FIR filter to be applied to measured data. 43 coefficients must be provided, or pass None (default) to disable the filter. Not available if summed=False. See also Notes and Examples sections.

  • nsum (int) – Only active when summed=True. How many lock-in packets (at rate get_df()) are included in a “chunk”. The resulting data rate is df / nsum. Ignored if summed=False.

  • quiet (bool) – if True, don’t check for inputs out of range

  • auto_sync (bool) – if True (default), trigger signal acquisition internally. Set to False to synchronize to an external source, e.g. a Metronomo unit.

  • rpu_params (Optional[Tuple]) –

    set to None to not start the RPU. Otherwise, set to a tuple of:

    • RPU firmware filename (str)

    • quadrature select (list of int): a list of indexes for which lockin quadratures the RPU firmware should have access to. E.g. [0, 1] for I and Q quadratures of first frequency.

    • length of sliding window (int): the number of lockin pixels in the sliding sum/average performed by the RPU

Return type:

LockinReceiver

Returns:

An instance of LockinReceiver, to be used with Python’s with statement, see Examples section.

Raises:

RuntimeError – if apply_settings() was not called after changing some setting

Notes

summed=True is only implemented when using digital downconversion (adc_mode is AdcMode.Mixed).

Useful functions for computing the coefficients fir_coeffs for the FIR filter are remez() and firwin() in scipy.signal.

Examples

See LockinReceiver for examples.

tune(f, df)

Perform standard level of tuning.

This provides frequencies closer to the requested ones, with a level of Fourier leakage that is adequate to most experiments. See Notes.

Parameters:
  • f (float or array_like) – Target frequency/ies in Hz

  • df (float) – Target measurement bandwidth in Hz

Return type:

Tuple[Union[float, ndarray], float]

Returns:

a tuple of (f_tuned, df_tuned) where

  • f_tuned (float or array_like): Tuned frequencies in Hz. If f is a float, then f_tuned is also a float; if f is array-like, then f_tuned is a ndarray with dtype=np.float64

  • df_tuned (float): Tuned measurement bandwith in Hz

See also

tune_perfect(): perfect tuning set_phase_reset(): enable/disable phase reset every 1/df

Notes

First, this level of tuning forces the measurement bandwith df to be a divisor of the sampling frequency fs, i.e. there is an integer number of samples ns = fs/df_tuned in each lock-in measurement window. Second, the tuning forces each frequency f to be integer multiple of the measurement bandwith df_tuned, i.e. there is an integer number n = f_tuned/df_tuned of oscillations within each measurement window.

In theory, this level of tuning allows for measurement without Fourier leakage, or spectral leakage. In practice, however, not every value of f_tuned can be represented exactly in the hardware. With this level of tuning, the frequency that is actually set in hardware f_set is slightly different from the tuned frequency f_tuned. Therefore, the ratio f_set/df_tuned is not an integer, and some Fourier leakage occurs. To avoid long-term phase drift, the phase of the oscillation at frequency f_set is reset at the end of each lock-in window (every 1/df_tuned). See set_phase_reset() for a way to disable this behavior.

Nonetheless, the difference between f_set and f_tuned is actually really small: the worst-case error is get_fs("dac")/2/2**48, on the order of a single microhertz (1 μHz)! For most common applications, the resulting Fourier leakage and the phase-reset glitches are well below the noise level. If however, this is not acceptable, see tune_perfect().

tune_perfect(f, df)

Perform perfect level of tuning.

This provides frequencies that might be further from the requested ones, but with zero Fourier leakage. See Notes.

Parameters:
  • f (float or array_like) – Target frequency/ies in Hz

  • df (float) – Target measurement bandwidth in Hz

Return type:

Tuple[Union[float, ndarray], float]

Returns:

a tuple of (f_tuned, df_tuned) where

  • f_tuned (float or array_like): Tuned frequencies in Hz. If f is a float, then f_tuned is also a float; if f is array-like, then f_tuned is a ndarray with dtype=np.float64

  • df_tuned (float): Tuned measurement bandwith in Hz

See also

tune(): standard tuning

Notes

First, this level of tuning forces the measurement bandwith df to divide the sampling frequency fs by a power of 2, i.e. the number of samples in each lock-in measurement window is a power of 2: ns = fs/df_tuned = 2**m. Second, the tuning forces each frequency f to be integer multiple of the measurement bandwith df_tuned, i.e. there is an integer number n = f_tuned/df_tuned of oscillations within each measurement window.

This level of tuning always allows for measurement without Fourier leakage, or spectral leakage, and guarantees that f_tuned can be represented exactly in the hardware.

SymmetricLockin class

class presto.lockin.SymmetricLockin(*, ext_ref_clk=False, force_reload=False, dry_run=False, address=None, port=None, adc_mode=AdcMode.Mixed, adc_fsample=None, dac_mode=DacMode.Mixed, dac_fsample=None, force_config=False)

Special-purpose version of Lockin with same frequencies on input and output ports (symmetric).

The symmetric lock-in only supports Mixed mode. The digital mixers are configured for single-sideband upconversion and downconversion, using the upper sideband. The frequency of the output tones will therefore be the sum of the IF frequency set with set_frequencies() and of the LO frequency set with hardware.configure_mixer.

Warning

Create only one instance at a time. This class is designed to be instantiated with Python’s with statement, see Examples section.

Parameters:
  • ext_ref_clk (Union[None, bool, int, float]) – if None or False use internal reference clock; if True use external reference clock (10 MHz); if float or int use external reference clock at ext_ref_clk Hz

  • force_reload (bool) – if True re-configure clock and reload firmware even if there’s no change from the previous settings.

  • dry_run (bool) – if True don’t connect to hardware, for testing only.

  • address (Optional[str]) – IP address or hostname of the hardware. If None, use factory default "192.168.42.50".

  • port (Optional[int]) – port number of the server running on the hardware. If None, use factory default 7878.

  • adc_mode (AdcMode or list) – configure the inputs to use the digital mixers for downconversion. Direct mode is not supported.

  • adc_fsample (AdcFSample or list) – configure the inputs sampling rate. If None (default), choose optimal rate automatically. See Notes.

  • dac_mode (DacMode or list) – configure the outputs to use the digital mixers for upconversion. Direct mode is not supported. See Notes.

  • dac_fsample (DacFSample or list) – configure the outputs sampling rate. If None (default), choose optimal rate automatically. See Notes.

  • force_config (bool) – if True skip checks on DacModes not recommended for high DAC sampling rates.

Raises:

ValueError – if adc_mode or dac_mode are not valid Converter modes; if adc_fsample or dac_fsample are not valid Converter rates.

Notes

In all the Examples, it is assumed that the imports import numpy as np and from presto import lockin have been performed, and that this class has been instantiated in the form lck = lockin.SymmetricLockin(), or, much much better, using the with lockin.SymmetricLockin() as lck construct as below.

For an introduction to adc_mode and dac_mode, see Direct and Mixed mode. For valid values of adc_mode and dac_mode, see Converter modes. For valid values of adc_fsample and dac_fsample, see Converter rates. For advanced configuration, e.g. different converter rates on different ports, see Advanced tile configuration.

add_symmetric_group(input_port, output_ports, nr_freq)

Create and return a new symmetric group.

Parameters:
  • input_port (int) – which input port the group should sample data from

  • output_ports (int or array_like) – which output port(s) the group should output data to. If a list, the output will be replicated on all ports

  • nr_freq (int) – how many frequencies the input group should modulate/demodulate

Return type:

SymmetricGroup

apply_required()

Check whether calling apply_settings() is required to sync outstanding changes.

Return type:

bool

apply_settings(*, auto_sync=True, only_if=False)

Apply the settings to the hardware.

Parameters:

auto_sync (bool) – if True (default), trigger signal generation internally. Set to False to synchronize to an external source, e.g. a Metronomo unit.

Note

Prior to a call to this function, any change of settings has no effect on the hardware.

close()

Gracely disconnect from the hardware.

Call this method if the class was instantiated without a with statement. This method is called automatically when exiting a with block and before the object is destructed.

get_Tm()

Get measurement time in seconds.

The inverse of the measurement bandwidth.

Return type:

float

See also

get_df()

get_clk_T()

Period of the programmable-logic clock in seconds.

Return type:

float

get_clk_f()

Frequency of the programmable-logic clock in Hz.

Return type:

float

get_df()

Get measurement bandwidth in Hz.

Return type:

float

See also

set_df() get_Tm()

get_fs(which)

Get sampling frequency for which converter in Hz.

Parameters:

which (str) – "adc" for input and "dac" for output.

Raises:

ValueError – if which is unknown.

Return type:

float

get_ns(which='adc')

Get number of samples per lock-in window.

The sampling rate divided by the measurement bandwidth.

Parameters:

which (str) – “adc” for input and “dac” for output.

Return type:

int

get_pixels(n, *, summed=False, fir_coeffs=None, nsum=250, quiet=False, auto_sync=True)

Get lock-in packets (pixels) from the hardware.

Parameters:
  • n (int) – the number of lock-in packets to measure. When summed=True, n is the number of means and standard deviation acquired: the number of lock-in packets measured will be n*nsum.

  • summed (bool) – when True, calculate on the hardware the mean and standard deviation of the acquired data in chunks of nsum lock-in packets.

  • fir_coeffs (array_like of float) – coefficients for FIR filter to be applied to measured data. 43 coefficients must be provided, or pass None (default) to disable the filter. Not available if summed=False. See also Notes and Examples sections.

  • nsum (int) – Ignored if summed=False. How many lock-in packets (at rate get_df()) The resulting data rate will be df / nsum.

  • quiet (bool) – if True, don’t check for inputs out of range

  • auto_sync (bool) – if True (default), trigger signal acquisition internally. Set to False to synchronize to an external source, e.g. a Metronomo unit.

Return type:

dict

Returns:

a dictionary with key port (int) and value depending on the argument summed.

The key is always:

  • port (int): input port measured

When summed=False (default), the value is a tuple of:

  • freqs (ndarray, dtype=np.float64): frequencies at which the lockin measurement was done.

  • pixels (ndarray, dtype=np.complex64): measured lock-in data in ratio of full-scale input. shape is (n, len(freqs)).

When summed=True, the value is a tuple of:

  • freqs (ndarray, dtype=np.float64): frequencies at which the lockin measurement was done.

  • mean (ndarray, dtype=np.complex64): calculated mean of nsum consecutive lock-in packets. shape is (n, len(freqs)).

  • std (ndarray, dtype=np.complex64): calculated standard deviation of nsum consecutive lock-in packets. shape is (n, len(freqs)). The standard deviation has a real and an imaginary part; abs(std) is the total standard deviation according to Complex random variable.

Raises:

RuntimeError – if apply_settings() was not called after changing some setting

Notes

This method locks execution until at least n measured packets are available.

Useful functions for computing the coefficients fir_coeffs for the FIR filter are remez() and firwin() in the scipy.signal module.

Examples

Measure 1k lock-in packets, and low-pass filter the measured data:

>>> from scipy.signal import firwin
>>> coeffs = firwin(43, 80e3, fs=lck.get_df())  # low-pass filter with 80 kHz cutoff
>>> data = lck.get_pixels(n=1000, fir_coeffs=coeffs)
>>> freqs, pixels = data[input_port]
>>> freqs.shape
(32,)
>>> pixels.shape
(1000, 32)

Measure 100k lock-in packets, and compute mean and standard deviation in chunks of 100 packets:

>>> data = lck.get_pixels(n=1000, summed=True, nsum=100)
>>> freqs, mean, std = data[input_port]
>>> freqs.shape
(32,)
>>> mean.shape
(1000, 32)
>>> std.shape
(1000, 32)
hardware: Hardware

interface to hardware features common to all modes of operation

set_df(df)

Set measurement bandwith.

The new setting is not applied until apply_settings() is called!

Parameters:

df (float) – Measurement bandwith in Hz.

Notes

Non-tuned measurement bandwidths can’t be set in hardware. When passing a non-tuned df, the closest tuned value will be set in hardware. To avoid confusion, it is recommended to explicitly tune df before calling this method.

set_dither(state, output_ports)

Add pseudorandom noise to the generated output.

Can improve harmonic and intermodulation distortion when working with small output amplitudes.

The change is active immediately

Parameters:
  • state (bool) – if True, add pseudorandom noise to the output

  • output_ports (int or array_like) – which output port(s) should be affected

set_phase_reset(reset_phase)

Reset the phase of the reference signals at the end of every lock-in window.

The new setting is not applied until apply_settings() is called!

Parameters:

reset_phase (bool) – if True the phase reset is enabled, set to False to disable.

Notes

This setting is enabled by default. See Notes in tune() for rationale.

set_trigger_out(states, delay=0.0, width=1e-07)

Output a trigger on the digital output ports at the start of every demodulation or summing window.

Times will be rounded to closest integer multiple of get_clk_T().

Parameters:
  • states (Union[int, List[int]]) –

    enable/disable the trigger on each of the digital output ports. Valid values are:

    • 0 no trigger output

    • 1 trigger for each new lock-in window

    • 2 trigger for each new sum window (mean and std)

  • delay (float) – delay trigger rising edge from start of lock-in window, in seconds

  • width (float) – trigger-high duration, in seconds

Raises:

ValueError – if delay and width are negative, or too large

Return type:

None

Examples

Output a 100ns trigger on port 1 every summing window and on port 2 every demodulation window:

>>> lck.set_trigger_out([2, 1])
stream_pixels(*, summed=False, fir_coeffs=None, nsum=250, quiet=False, auto_sync=True, rpu_params=None)

Receive lock-in packets (pixels) from the hardware in the background.

This method returns a LockinReceiver object that receives a stream of packets in a separate thread, without blocking the execution of the current thread.

Warning

This method is experimental and the exposed API might change in future releases.

Parameters:
  • summed (bool) – when True, calculate on the hardware the mean and standard deviation of the acquired data in chunks of nsum lock-in packets.

  • fir_coeffs (array_like of float) – coefficients for FIR filter to be applied to measured data. 43 coefficients must be provided, or pass None (default) to disable the filter. Not available if summed=False. See also Notes and Examples sections.

  • nsum (int) – Only active when summed=True. How many lock-in packets (at rate get_df()) are included in a “chunk”. The resulting data rate is df / nsum. Ignored if summed=False.

  • quiet (bool) – if True, don’t check for inputs out of range

  • auto_sync (bool) – if True (default), trigger signal acquisition internally. Set to False to synchronize to an external source, e.g. a Metronomo unit.

  • rpu_params (Optional[Tuple]) –

    set to None to not start the RPU. Otherwise, set to a tuple of:

    • RPU firmware filename (str)

    • quadrature select (list of int): a list of indexes for which lockin quadratures the RPU firmware should have access to. E.g. [0, 1] for I and Q quadratures of first frequency.

    • length of sliding window (int): the number of lockin pixels in the sliding sum/average performed by the RPU

Return type:

LockinReceiver

Returns:

An instance of LockinReceiver, to be used with Python’s with statement, see Examples section.

Raises:

RuntimeError – if apply_settings() was not called after changing some setting

Notes

summed=True is only implemented when using digital downconversion (adc_mode is AdcMode.Mixed).

Useful functions for computing the coefficients fir_coeffs for the FIR filter are remez() and firwin() in scipy.signal.

Examples

See LockinReceiver for examples.

tune(f, df)

Perform standard level of tuning.

This provides frequencies closer to the requested ones, with a level of Fourier leakage that is adequate to most experiments. See Notes.

Parameters:
  • f (float or array_like) – Target frequency/ies in Hz

  • df (float) – Target measurement bandwidth in Hz

Return type:

Tuple[Union[float, ndarray], float]

Returns:

a tuple of (f_tuned, df_tuned) where

  • f_tuned (float or array_like): Tuned frequencies in Hz. If f is a float, then f_tuned is also a float; if f is array-like, then f_tuned is a ndarray with dtype=np.float64

  • df_tuned (float): Tuned measurement bandwith in Hz

See also

tune_perfect(): perfect tuning set_phase_reset(): enable/disable phase reset every 1/df

Notes

First, this level of tuning forces the measurement bandwith df to be a divisor of the sampling frequency fs, i.e. there is an integer number of samples ns = fs/df_tuned in each lock-in measurement window. Second, the tuning forces each frequency f to be integer multiple of the measurement bandwith df_tuned, i.e. there is an integer number n = f_tuned/df_tuned of oscillations within each measurement window.

In theory, this level of tuning allows for measurement without Fourier leakage, or spectral leakage. In practice, however, not every value of f_tuned can be represented exactly in the hardware. With this level of tuning, the frequency that is actually set in hardware f_set is slightly different from the tuned frequency f_tuned. Therefore, the ratio f_set/df_tuned is not an integer, and some Fourier leakage occurs. To avoid long-term phase drift, the phase of the oscillation at frequency f_set is reset at the end of each lock-in window (every 1/df_tuned). See set_phase_reset() for a way to disable this behavior.

Nonetheless, the difference between f_set and f_tuned is actually really small: the worst-case error is get_fs("dac")/2/2**48, on the order of a single microhertz (1 μHz)! For most common applications, the resulting Fourier leakage and the phase-reset glitches are well below the noise level. If however, this is not acceptable, see tune_perfect().

tune_perfect(f, df)

Perform perfect level of tuning.

This provides frequencies that might be further from the requested ones, but with zero Fourier leakage. See Notes.

Parameters:
  • f (float or array_like) – Target frequency/ies in Hz

  • df (float) – Target measurement bandwidth in Hz

Return type:

Tuple[Union[float, ndarray], float]

Returns:

a tuple of (f_tuned, df_tuned) where

  • f_tuned (float or array_like): Tuned frequencies in Hz. If f is a float, then f_tuned is also a float; if f is array-like, then f_tuned is a ndarray with dtype=np.float64

  • df_tuned (float): Tuned measurement bandwith in Hz

See also

tune(): standard tuning

Notes

First, this level of tuning forces the measurement bandwith df to divide the sampling frequency fs by a power of 2, i.e. the number of samples in each lock-in measurement window is a power of 2: ns = fs/df_tuned = 2**m. Second, the tuning forces each frequency f to be integer multiple of the measurement bandwith df_tuned, i.e. there is an integer number n = f_tuned/df_tuned of oscillations within each measurement window.

This level of tuning always allows for measurement without Fourier leakage, or spectral leakage, and guarantees that f_tuned can be represented exactly in the hardware.


Input and output groups

class presto.lockin.InputGroup(port, nr_freq, lockin)

Settings of a lock-in input group.

Used as return type by Lockin.add_input_group(). Contains access functions for changing the settings of this input group.

The lock-in input is divided into 16 groups. Each group is capable of demodulating 12 different quadratures, for a total of 192 demodulations (96 I/Q pairs). Each demodulator has a configurable frequency and phase. Each group can acquire data from a single (configurable) input port.

Warning

Do not instantiate this class directly! Call Lockin.add_input_group() to obtain a valid instance.

get_frequencies()

Get the lock-in input frequencies.

Return type:

ndarray

Returns:

ndarray of frequencies in Hz. dtype=np.float64

get_phases(*, deg=False)

Get the lock-in input phases.

Parameters:

deg (bool) – if True, get the phases in degrees in [-180.0, +180.0]; if False (default) radians in [-π, +π].

Return type:

ndarray

Returns:

ndarray of phases in rad/deg for each frequency. dtype=np.float64.

set_frequencies(freqs)

Set the lock-in input frequencies.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:

freqs (float or array_like) – frequency/ies in Hz. If less than available number of frequencies, the rest is set to zero.

Return type:

InputGroup

Notes

This function performs no tuning, make sure freqs are tuned to the user needs before calling this function.

set_phases(phases, *, deg=False)

Set the lock-in input phases.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:
  • phases (float or array_like) – phases in rad/deg. If less than available number of frequencies, set the rest to zero. When using the digital mixers (adc_mode is AdcMode.Mixed), sets the phase of both the I and the Q port of the downconversion mixer.

  • deg (bool) – if True, set the phases in degrees; if False (default) radians.

Return type:

InputGroup

class presto.lockin.OutputGroup(ports, nr_freq, lockin)

Settings of a lock-in output group.

Used as return type by Lockin.add_output_group(). Contains access functions for changing the settings of this output group.

The lock-in output is divided into 16 groups. Each group is capable of driving tones at 12 different frequencies, for a total of 192 frequencies. Each tone has a configurable frequency, phase and amplitude. Each group can be output on one or more output ports.

Warning

Do not instantiate this class directly! Call Lockin.add_output_group() to obtain a valid instance.

get_amplitudes()

Get the lock-in output amplitudes.

Return type:

ndarray

Returns:

ndarray of amplitudes for each frequency with +/- 1.0 being full scale. dtype=np.float64.

get_frequencies()

Get the lock-in output frequencies.

Return type:

ndarray

Returns:

ndarray of frequencies in Hz. dtype=np.float64

get_phases(*, deg=False)

Get the lock-in output phases.

Parameters:

deg (bool) – if True, get the phases in degrees in [-180.0, +180.0]; if False (default) radians in [-π, +π].

Returns:

ndarray of phases in rad/deg for each frequency. dtype=np.float64.

set_amplitudes(amps)

Set the lock-in output amplitudes.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:

amps (float or array_like) – amplitudes with +/- 1.0 being full scale. If less than available number of frequencies, set the rest to zero.

Return type:

OutputGroup

set_frequencies(freqs)

Set the lock-in output frequencies.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:

freqs (float or array_like) – frequency/ies in Hz. If less than available number of frequencies, the rest is set to zero.

Return type:

OutputGroup

Notes

This function performs no tuning, make sure freqs are tuned to the user needs before calling this function.

set_phases(phases, phases_q=None, *, deg=False)

Set the lock-in output phases.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:
  • phases (float or array_like) – phases in rad/deg. If less than available number of frequencies, set the rest to zero. When using the digital mixers (dac_mode is one of DacMode.Mixedxx), sets the phase of the I port of the upconversion mixer.

  • phases_q (float or array_like, optional) – when using the digital mixers, sets the phase of the Q port of the upconversion mixer. In direct mode (dac_mode is DacMode.Direct), setting phases_q throws a ValueError exception.

  • deg (bool) – if True, set the phases in degrees; if False (default) radians.

Raises:

ValueError – if phases_q is not None in direct mode

Return type:

OutputGroup

class presto.lockin.SymmetricGroup(input_port, output_ports, nr_freq, lockin)

Settings of a symmetric lock-in group.

Used as return type by SymmetricLockin.add_symmetric_group(). Contains access functions for changing the settings of this input-output group.

The lock-in output is divided into 16 groups. Each group is capable of driving tones at 12 different frequencies, for a total of 192 frequencies. Each tone has a configurable frequency, phase and amplitude. Each group can be output on one or more output ports, and acquire data from a single (configurable) input port.

Warning

Do not instantiate this class directly! Call SymmetricLockin.add_symmetric_group() to obtain a valid instance.

get_amplitudes()

Get the lock-in output amplitudes.

Return type:

ndarray

Returns:

ndarray of amplitudes for each frequency with +/- 1.0 being full scale. dtype=np.float64.

get_frequencies()

Get the lock-in frequencies.

Return type:

ndarray

Returns:

ndarray of frequencies in Hz. dtype=np.float64

get_phases(*, deg=False)

Get the lock-in output phases.

Parameters:

deg (bool) – if True, get the phases in degrees in [-180.0, +180.0]; if False (default) radians in [-π, +π].

Return type:

ndarray

Returns:

ndarray of phases in rad/deg for each frequency. dtype=np.float64.

set_amplitudes(amps)

Set the lock-in output amplitudes.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:

amps (float or array_like) – amplitudes with +/- 1.0 being full scale. If less than available number of frequencies, set the rest to zero.

Return type:

SymmetricGroup

set_frequencies(freqs)

Set the lock-in frequencies.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:

freqs (float or array_like) – frequency/ies in Hz. If less than available number of frequencies, the rest is set to zero.

Return type:

SymmetricGroup

Notes

This function performs no tuning, make sure freqs are tuned to the user needs before calling this function.

set_phases(phases, *, deg=False)

Set the lock-in output phases.

The new setting is not applied until Lockin.apply_settings() is called!

Parameters:
  • phases (float or array_like) – phases in rad/deg. If less than available number of frequencies, set the rest to zero.

  • deg (bool) – if True, set the phases in degrees; if False (default) radians.

Return type:

SymmetricGroup


Other

class presto.lockin.LockinReceiver(*, lck, sock, summed, bytes_per_pixel, extra_bytes, buf_size=1073741824)

A receiver of lockin data running in the background.

Used as return type by Lockin.stream_pixels().

Warning

This class is experimental and the exposed API might change in future releases.

Warning

Do not instantiate this class directly! Call Lockin.stream_pixels() to obtain a valid instance.

Examples

>>> with lockin.Lockin(
>>>     address=PRESTOs_IP_ADDRESS,
>>> ) as lck:
>>>     lck.set_df(1e3)
>>>
>>>     og = lck.add_output_group(OUTPUT_PORT, 1)
>>>     og.set_frequencies(240e6).set_amplitudes(0.7).set_phases(0.0)
>>>
>>>     ig = lck.add_input_group(INPUT_PORT, 1)
>>>     ig.set_frequencies(240e6)
>>>
>>>     lck.apply_settings()
>>>
>>>     # receive pixels with get_pixels
>>>     _, data0 = lck.get_pixels(1_000)[INPUT_PORT]
>>>
>>>     # receive pixels with a LockinReceiver
>>>     with lck.stream_pixels() as recv:
>>>         _, data1 = recv.get_last(1_000)[INPUT_PORT]
close()

Gracely terminate the lockin receiver.

Call this method if the class was instantiated without a with statement. This method is called automatically when exiting a with block and before the object is destructed.

get_last(n)

Return the last n lockin pixels.

If fewer than n lockin packets are available in the internal buffer, this method will block the current thread until enough pixels are received.

See Lockin.get_pixels() for the format of the returned data. :rtype: dict

Warning

This method is experimental and the exposed API might change in future releases.

get_new(n)

Receive n new lockin pixels.

This method will block the current thread until n new lockin packets are received.

See Lockin.get_pixels() for the format of the returned data. :rtype: dict

Warning

This method is experimental and the exposed API might change in future releases.

nr_pixels_received()

The number of lockin packets received so far.

Note that not all the received pixels might be available in the internal buffer. :rtype: int

Warning

This method is experimental and the exposed API might change in future releases.