spectral module¶
FFT-based measurements of spectral content.
Detailed information is provided in the documentation for each class.
Use the hardware in spectral mode. |
|
Specify the spectral measurement mode. |
|
Container for measurement results in spectral mode. |
|
A receiver of spectral data running in the background. |
Spectral class¶
- class presto.spectral.Spectral(*, nr_inputs=1, 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)¶
Use the hardware in spectral 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:
nr_inputs (
int) – number of input ports that are active simultaneously. The spectral content (FFT or PSD) will be measured in parallel from this many ports.ext_ref_clk (
Union[None,bool,int,float]) – ifNoneorFalseuse internal reference clock; ifTrueuse external reference clock (10 MHz); iffloatorintuse external reference clock atext_ref_clkHzforce_reload (
bool) – ifTruere-configure clock and reload firmware even if there’s no change from the previous settings.dry_run (
bool) – ifTruedon’t connect to hardware, for testing only.address (
Optional[str]) – IP address or hostname of the hardware. IfNone, use factory default"192.168.42.50".port (
Optional[int]) – port number of the server running on the hardware. IfNone, use factory default7878.adc_mode (AdcMode or list) – must be
AdcMode.Mixed(default), using the digital mixers for downconversion.Directmode is not supported in spectral mode.adc_fsample (AdcFSample or list) – configure the inputs sampling rate. If
None(default), choose optimal rate automatically. See Notes.dac_mode (DacMode or list) – must be
DacMode.Mixed(default) or another of the mixed variants, using the digital mixers for upconversion.Directmode is not supported in spectral mode. See Notes.dac_fsample (DacFSample or list) – configure the outputs sampling rate. If
None(default), choose optimal rate automatically. See Notes.force_config (
bool) – ifTrueskip checks onDacModes not recommended for high DAC sampling rates.
- Raises:
ValueError – if
adc_modeordac_modeare not valid Converter modes; ifadc_fsampleordac_fsampleare not valid Converter rates.
Notes
In all the Examples, it is assumed that the imports
import numpy as npandfrom presto.spectral import Spectral, SpecModehave been performed, and that this class has been instantiated in the formspec = Spectral(), or, much much better, using thewith Spectral() as specconstruct as below.For an introduction to
adc_modeanddac_mode, see Direct and Mixed mode. For valid values ofadc_modeanddac_mode, see Converter modes. For valid values ofadc_fsampleanddac_fsample, see Converter rates. For advanced configuration, e.g. different converter rates on different ports, see Advanced tile configuration.Examples
Drive two continuous-wave signals from output port 1 and 2, and measure averaged FFT from input port 1. Plot the results.
>>> import matplotlib.pyplot as plt >>> import numpy as np >>> >>> IN_PORT = 1 >>> OUT_PORT_1 = 1 >>> OUT_PORT_2 = 2 >>> >>> with Spectral(address="192.168.20.10") as spec: >>> # configure 1.5 GHz carrier for up- and down-conversion >>> spec.hardware.configure_mixer( >>> freq=1.5e9, >>> in_ports=IN_PORT, >>> out_ports=[OUT_PORT_1, OUT_PORT_2], >>> ) >>> >>> # 1 MHz resolution in FFT >>> period = spec.tune_period(1.0e-6) >>> >>> # on the first output port, >>> # drive two tones at 110 and 112 MHz from the carrier >>> # with same phase but different amplitude >>> # one below the carrier (lower sideband) and one above (upper sideband) >>> f1 = [-110.0e6, +120.0e6] >>> a1 = [0.1, 0.2] >>> p1 = [0.0, 0.0] >>> spec.output_multicos(OUT_PORT_1, period, f1, a1, p1) >>> >>> # on the second output port, >>> # drive one tone on port 2 at the carrier frequency >>> f2 = 0.0 >>> a2 = 0.5 >>> p2 = 0.0 >>> spec.output_multicos(OUT_PORT_2, period, f2, a2, p2) >>> >>> # measure FFT data, averaged 1000 times >>> res = spec.measure(SpecMode.FftAvg, IN_PORT, 1000, period) >>> >>> # plot data >>> >>> # frequencies in MHz >>> x = np.fft.fftshift(res.freqs) / 1.0e6 >>> # data in dBFS >>> y = np.fft.fftshift(res.to_db()[0]) >>> >>> fig, ax = plt.subplots() >>> ax.plot(x, y) >>> ax.set_xlabel("Offset frequency [MHz]") >>> ax.set_ylabel("Amplitude [dBFS]") >>> ax.set_title("Center frequency 1.5 GHz") >>> ax.grid() >>> plt.show()
Drive two random signals from output ports 1 and 2 into input ports 1 and 2, one delayed 100 ns from the other, and measure the correlation of the two.
>>> import matplotlib.pyplot as plt >>> import numpy as np >>> >>> IN_PORTS = [1, 2] >>> OUT_PORTS = [1, 2] >>> >>> with Spectral( >>> nr_inputs=len(IN_PORTS), >>> address="192.168.20.10", >>> ) as spec: >>> # configure 1.5 GHz carrier for up- and down-conversion >>> spec.hardware.configure_mixer(1.5e9, in_ports=IN_PORTS, out_ports=OUT_PORTS) >>> >>> # 1 MHz resolution in FFT >>> period = spec.tune_period(1.0e-6) >>> >>> # generate random data and output from first port >>> def random_complex(ns): >>> rng = np.random.default_rng() >>> real = 2.0 * rng.random(ns) - 1.0 >>> imag = 2.0 * rng.random(ns) - 1.0 >>> return real + 1j * imag >>> >>> duration = 10 * period >>> nr_samples = int(round(duration * spec.get_fs("dac"))) >>> data1 = 0.1 * random_complex(nr_samples) >>> spec.output_waveform(OUT_PORTS[0], data1) >>> >>> # output same data on second port, >>> # but delayed by 100 samples (100 ns) >>> data2 = np.roll(data1, 100) >>> spec.output_waveform(OUT_PORTS[1], data2) >>> >>> # measure cross power spectral density (CPSD) data >>> # averaged 10 times >>> res = spec.measure(SpecMode.Cpsd, IN_PORTS, 10, period) >>> >>> # calculate correlation from measured CPSD >>> # and plot results >>> >>> x, y = res.to_correlation() >>> fig, ax = plt.subplots() >>> ax.plot(1e9 * x, np.real(y[0])) >>> ax.plot(1e9 * x, np.imag(y[0])) >>> ax.set_xlabel("Time lag [ns]") >>> ax.set_ylabel("Correlation [arb. units]") >>> ax.set_title("Center frequency 1.5 GHz") >>> ax.grid() >>> plt.show()
- clear_outputs()¶
Clear the waveforms set up on all output ports.
- 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
withblock and before the object is destructed.
- fftfreq(period)¶
Return the fast Fourier transform sample frequencies.
The returned array contains the frequency bin centers in hertz (cycles second), with zero at the start. This methos is similar to
numpy.fft.fftfreq(), but with different arguments.- Parameters:
period (
float) – the FFT measurement period, or window length, in seconds.- Return type:
Note
The period is assumed to be tuned. See
tune_period()for details.
- get_fs(which)¶
Get sampling frequency for
whichconverter in Hz.Note
This is the sampling rate in the intermediate-frequency (IF) domain, and not the (higher) sampling rate in the radio-frequency (RF) domain.
- Parameters:
which (
str) –"adc"for input and"dac"for output.- Raises:
ValueError – if
whichis unknown.- Return type:
- measure(mode, input_ports, nr_meas, period, auto_sync=True, quiet=False)¶
Measure the spectral content of the signal at
input_ports.Depending on
mode, measure the averaged fast Fourier transform (FFT), multiple FFT windows, the power spectral density (PSD), or the cross PSD (CPSD).- Parameters:
mode (
SpecMode) – select measurement mode, seeSpecModefor detailsinput_ports (int or list) – input port, can be a list of up to 4 ports
nr_meas (
int) – number of individual FFT/PSD windows to measure or to average, depending onmodeperiod (
float) – requested measurement period (integration time) for the FFT/PSD, corresponding to the inverse of the frequency resolution. See Notes section below for detailsauto_sync (
bool) – ifTrue(default), trigger signal generation and acquisition internally. Set toFalseto synchronize to an external source, e.g. a Metronomo unit.quiet (
bool) – set toTrueto inhibit printing timing information
- Return type:
- Returns:
res- a container for the measurement results, seeSpecResultfor documentation
Notes
The period is assumed to be tuned, see
tune_period()for details. If period is not tuned, the backend will choose the available period that is closest to the user-requested value.The shape and data type of the returned
res.datadepends on the measurementmode, seeSpecResult.datafor documentation.- Raises:
ValueError – if
input_portsis not in [1,get_nr_ports()]ValueError – if
len(input_ports)is not 1, 2 or 4RuntimeError – if any setup error is detected while setting up the measurement
Examples
See documentation for the
Spectralclass for examples.
- property nr_inputs¶
The current number of interleaved input ports.
This value is read only. To change it, create a new instance of the
Spectralclass and pass the desired number of input ports as the nr_inputs parameter.
- output_multicos(output_ports, period, frequencies, amplitudes, phases=None)¶
Set up a multi-tone waveform on one or more output ports.
- Parameters:
output_ports (int or list) – output port, can be a list of up to 4 ports
period (
float) – the repetition period of the output waveform, in secondsfrequencies (list of float) – frequencies of the individual tones that comprise the waveform, in hertz
amplitudes (list of float) – amplitudes of the individual tones that comprise the waveform, in full-scale units between -1.0 and +1.0 FS
phases (list of float, optional) – phases of the individual tones that comprise the waveform, in radians. If
None(default), all tones have zero phase
Notes
Positive frequencies are up-coverted to the upper sideband (USB) by the digital up-conversion mixer, and negative frequencies are up-coverted to the lower sideband (LSB).
If
sum(abs(amplitudes))> 1.0, it is possible for the tones in the waveform to interfere constructively and cause an overflow (clipping), resulting in a heavily-distorted output waveform. To prevent this effect, ensure thatsum(abs(amplitudes))<= 1.0, or adjust thephasesof the tones to prevent isolated peaks in the resulting waveform.- Raises:
ValueError – if
output_portsis not in [1,get_nr_ports()]ValueError – if
len(amplitudes) != len(frequencies)ValueError – if
len(phases) != len(frequencies)ValueError – if any of
abs(frequencies)>= Nyquist frequency, i.e. half ofget_fs("dac")ValueError – if any of
abs(amplitudes) > 1.0RuntimeError – if there are no more output slots available
See also
- output_waveform(output_ports, data)¶
Set up an arbitrary waveform on one or more output ports.
- Parameters:
Notes
The real part of
datais fed to the I port of the digital up-conversion mixer, while the imaginary part ofdatais fed to the Q port.- Raises:
ValueError – if
output_portsis not in [1,get_nr_ports()]ValueError – if
datais out of range: both real and imaginary parts must be in [-1.0, +1.0]RuntimeError – if there are no more output slots available
See also
- setup_delay(*, pre_delay=0.0, start_delay=0.0, end_delay=0.0)¶
Configure FFT measurement delays.
- Parameters:
Notes
pre_delayadds a delay at the very beginning of the measurement sequence, between the start of the output waveform (DAC) and the first input window (ADC).start_delayandend_delayadd some “dead time” within each input window. Data measured during this dead time is discarded and not included in the FFT calculation:
- stream(input_ports, period, indexes=None, freqs=None, auto_sync=True, quiet=False)¶
Measure continuously the spectral content of the signal at
input_ports.This will measure the fast Fourier transform (FFT) of the signal.
- Parameters:
input_ports (int or list) – input port, can be a list of up to 4 ports
period (
float) – requested measurement period (integration time) for the FFT, corresponding to the inverse of the frequency resolution. See Notes section below for detailsindexes (list of int, optional) – which FFT frequency components (bin indexes) should be measured. If
None(default), all of themfreqs (list of float, optional) – which FFT frequency components (bin indexes) should be measured. If
None(default), all of themauto_sync (
bool) – ifTrue(default), trigger signal generation and acquisition internally. Set toFalseto synchronize to an external source, e.g. a Metronomo unit.quiet (
bool) – set toTrueto inhibit printing timing information
- Return type:
- Returns:
recv- a handle to the spectral receiver, seeSpecReceiverfor documentation
Notes
The period is assumed to be tuned, see
tune_period()for details. If period is not tuned, the backend will choose the available period that is closest to the user-requested value.By default, all measured FFT frequencies will be streamed, see
fftfreq(). Optional arguments indexes and freqs can be used to stream only a subset of all the measured frequencies and therefore save bandwidth and memory.Use freqs to select components based on their value in hertz (Hz). If the requested value is not a valid FFT frequency, the closest valid value will be selected. Use indexes to select components based on their index in the array returned by
fftfreq(). It is an error to specify both freqs and indexes.Specifying frequency components with indexes or freqs will ensure that at least those components are streamed. The backend might stream more components than requested, see
recv.freqsfor a list of all the frequencies that are being streamed.- Raises:
ValueError – if
input_portsis not in [1,get_nr_ports()]ValueError – if
len(input_ports)is not 1, 2 or 4ValueError – if both indexes and freqs are not None
RuntimeError – if any setup error is detected while setting up the measurement
Examples
See documentation for the
SpecReceiverclass for examples.
- tune_period(period, *, strategy=None)¶
Tune the provided measurement period to a value supported by the hardware.
Only a limited number of measurement periods are supported by the hardware. The default
tuning strategywill choose the available period that is closest to the user-requested value.- Parameters:
period (
float) – the desired FFT measurement period is seconds, equal to the inverse of the desired frequency resolution in hertzstrategy (
Optional[TuningStrategy]) – optional tuning strategy
- Return type:
- Returns:
the tuned
period
SpecMode class¶
- class presto.spectral.SpecMode(*values)¶
Specify the spectral measurement mode.
Used as parameter to
Spectral.measure().- Cpsd¶
Measure the cross power spectral density (CPSD).
- FftAvg¶
Measure the averaged fast Fourier transform (FFT).
- FftStream¶
Measure multiple (stacked) fast Fourier transform (FFT) windows.
- Psd¶
Measure the averaged power spectral density (PSD).
SpecResult class¶
- class presto.spectral.SpecResult(*, mode, freqs, data, input_ports)¶
Container for measurement results in spectral mode.
Used as return type by
Spectral.measure().Warning
Do not instantiate this class directly! Call
Spectral.measure()to obtain a valid instance.-
data:
ndarray[tuple[Any,...],dtype[TypeVar(SR_T, bound=Union[float64,complex64,complex128])]]¶ Array of measured spectral data (the y axis).
The shape and data type depend on the parameters
mode,input_portsandnr_meastoSpectral.measure():Mode
Shape
Type
SpecMode.FftStream(nr_meas, nr_ports, nr_freqs)SpecMode.FftAvg(nr_ports, nr_freqs)SpecMode.Psd(nr_ports, nr_freqs)SpecMode.Cpsd(nr_ports // 2, nr_freqs)where
nr_measis the number of independent measurements,nr_ports = len(input_ports)is the number of measured input ports, andnr_freqs = len(freqs)is the number of measured frequency components.
- to_correlation()¶
Convenience function to convert measured PSD/CPSD
datato auto/cross correlation.- Return type:
Tuple[ndarray[tuple[Any,...],dtype[float64]],ndarray[tuple[Any,...],dtype[complex128]]]- Returns:
- a tuple of
(lags, corr)where lags: array of time lags of lengthdata.shape[-1]corr: array of auto/cross correlation with same shape asdata
- a tuple of
- Raises:
TypeError – if the measurement
modeis notSpecMode.PsdorSpecMode.Cpsd.
-
data:
SpecReceiver class¶
- class presto.spectral.SpecReceiver(*, sock, freqs, input_ports, nr_inputs, bytes_per_meas, map, buf_size=1073741824)¶
A receiver of spectral data running in the background.
Used as return type by
Spectral.stream().Warning
Do not instantiate this class directly! Call
Spectral.stream()to obtain a valid instance.Examples
>>> with Spectral( >>> address=PRESTOs_IP_ADDRESS, >>> ) as spec: >>> # configure 1.5 GHz carrier for up- and down-conversion >>> spec.hardware.configure_mixer( >>> freq=1.5e9, >>> in_ports=1, >>> out_ports=1, >>> ) >>> >>> # 1 MHz resolution in FFT >>> period = spec.tune_period(1.0e-6) >>> >>> # drive two tones at 110 and 112 MHz >>> # with same phase but different amplitude >>> # on output port 1 >>> freq = [110.0e6, 112.0e6] >>> amp = [0.1, 0.2] >>> phase = [0.0, 0.0] >>> spec.output_multicos(1, period, freq, amp, phase) >>> >>> # continuously receive FFT measurements >>> # on input port 1 >>> # in chunks of 100 measurements >>> with spec.stream(1, period) as recv: >>> data = recv.get_last(100)
- close()¶
Gracely terminate the stream receiver.
Call this method if the class was instantiated without a with statement. This method is called automatically when exiting a
withblock and before the object is destructed.
- freqs¶
Array of measured frequencies (the x axis)
- get(n)¶
Return
nmeasurements received since the last call to this method.This method might block the current thread until
nnew measurements are available.- Return type:
TypeVar(SR_T)
Notes
This method keeps track of what measurements have already been returned, and always returns contiguous measurements (without gaps). If the requested measurements are available in the local buffer, they are returned immediately. Otherwise, the thread will block until all the requested measurements have been received.
That means that calling
get(n)twice results in the same data as callingget(2 * n)once. It also means that the data returned might have been already buffered locally and not be the latest received from the hardware.See See also section below for getter methods with different semantics.
See also
get_new(): always receive new data from the hardwareget_last(): return latest data from local buffer
- get_last(n)¶
Return the last
nmeasurements available in the local buffer.This method might block the current thread, if fewer than
nmeasurements are available in the local buffer.- Return type:
TypeVar(SR_T)
Notes
This method returns the most up-to-date data available in the local buffer, regardless of whether this data has already been returned to the user.
That means that calling
get_last(n)twice is not equivalent to callingget_last(2 * n)once: in the former case, the two data sets might overlap.See See also section below for getter methods with different semantics.
- get_new(n)¶
Receive
nnew measurements.This method blocks the current thread until
nnew measurements are received.- Return type:
TypeVar(SR_T)
Notes
This method always waits for
nnew measurements to be received from the hardware, without regard for what measurements have already been received in the background but not yet returned to the user.That means that calling
get_new(n)twice is not equivalent to callingget_new(2 * n)once: in the former case an arbitrary time gap might be present between the two data sets. Nevertheless, the two data sets will be distinct and non overlapping.See See also section below for getter methods with different semantics.
See also
get(): keep track of previously returned dataget_last(): return latest data from local buffer
- property nr_inputs¶
The number of interleaved input ports.
Other¶
- class presto.spectral.TuningStrategy(*values)¶
Specify an optional tuning strategy for the FFT period.
Used as parameter to
Spectral.tune_period().- AtLeast¶
Choose the period supported by the hardware that is greater than or equal to the user-requested value. If the requested value is greater than the maximum-supported period, choose the latter.
- AtMost¶
Choose the period supported by the hardware that is less than or equal to the user-requested value. If the requested value is smaller than the minimum-supported period, choose the latter.
- Closest¶
DEFAULT – Choose the period supported by the hardware that is closest to the user-requested value. This is the default strategy.