Phase & frequency analyses

This section describes measurements that expect periodic signals, e.g., oscillator outputs.

FrequencyCounter

../../_images/FrequencyCounter.svg
class FrequencyCounter : public IteratorBase

This measurement calculates the frequency and the phase of a periodic signal at evenly spaced sampling times. If the ReferenceClock is active, the sampling times will automatically align with the ReferenceClockState::ideal_clock_channel. For details on using an external reference via the ReferenceClock see the In Depth Guide: Software-Defined Reference Clock .

Multiple channels can be analyzed in parallel to compare the phase evolution in time. Around every sampling time, the time tags within an adjustable fitting_window are used to fit the phase.

See all common methods

Public Functions

FrequencyCounter(TimeTaggerBase tagger, channel_t[] channels, timestamp_t sampling_interval, timestamp_t fitting_window, int n_values = 0)
Parameters:
  • tagger – Time Tagger object instance.

  • channels – List of channels to analyze.

  • sampling_interval – The sampling interval in picoseconds. If the ReferenceClock is active, it is recommended to set this value to an integer multiple of the ReferenceClockState::clock_period.

  • fitting_window – Time tags within this range around a sampling point are fitted for phase calculation.

  • n_values – Maximum number of sampling points to store.

FrequencyCounterData getDataObject(int event_divider = 1, bool remove = false, bool channels_last_dim = false)

Returns a FrequencyCounterData object containing a snapshot of the data accumulated in the FrequencyCounter at the time this method is called. The event_divider argument can be used to scale the results according to the current setting of TimeTagger::setEventDivider(). The remove argument allows you to control whether the data should be removed from the internal buffer or not.

Parameters:
  • event_divider – Compensate for the EventDivider (default: 1).

  • remove – Control if data is removed from the internal buffer (default: True).

  • channels_last_dim – Determines the memory layout of the output data (default: False).

    • If true, data is stored with channels as the last dimension (row-major order for channels).

    • If false, data is stored with channels as the first dimension (column-major order for channels).

Returns:

An object providing access to a snapshot data.

class FrequencyCounterData

Public Functions

timestamp_t[] getIndex()

Index of the samples. The reference sample would have index 0, counting starts with 1 at the first sampling point.

Returns:

The index of the samples.

timestamp_t[] getTime()

Array of timestamps of the sampling points.

Returns:

The timestamps of the sampling points.

timestamp_t[,] getPeriodsCount()

The integer part of the phase, i.e. full periods of the oscillation.

Returns:

Full cycles per channel and sampling point.

float[,] getPeriodsFraction()

The fraction of the current period at the sampling time.

Warning

Be careful with adding getPeriodsCount() and getPeriodsFraction() as the required precision can overflow a 64bit double precision within minutes. In doubt, please use getPhase() with the expected frequency instead.

Returns:

A fractional value in range [0, 1) per channel and sampling point.

float[,] getPhase(float reference_frequency = 0)

The relative phase with respect to a numerical reference signal, typically at the expected frequency. The returned phase is dimensionless and expressed in cycles, i.e. a value of 1.0 corresponds to one full period. The reference signal starts at phase 0 at index 0, so the return value of this method is identical to that of getPeriodsFraction() for index 0.

Parameters:

reference_frequency – The reference frequency in Hz to subtract (default: 0.0 Hz).

Returns:

Relative phase values per channel and sampling point.

float[,] getFrequency(timestamp_t time_scale = 1000000000000)

The average frequency between two consecutive sampling points. It is derived from the change in accumulated phase between consecutive sampling points. At index 0, there is no previous phase value to compare with, so the method returns an undefined value NaN.

Parameters:

time_scale – Scales the return value to this time interval. Default is 1 s, so the return value is in Hz. For negative values, the time scale is set to sampling_interval.

Returns:

A frequency value per channel and sampling point.

float[,] getFrequencyInstantaneous()

The instantaneous frequency obtained from the current fitting window. This value corresponds to the slope of the linear fit and therefore represents the local frequency at the sampling point.

Returns:

An instantaneous frequency value per channel and sampling point.

int[,] getOverflowMask()

If an overflow range overlaps with a fitting window, the values are invalid. This mask array indicates invalid elements and can be used to filter the results of the other getters.

Returns:

1 indicates that the sampling point was affected by an overflow range, 0 indicates valid data.

Public Members

int size

Number of sampling points represented by the object.

timestamp_t overflow_samples

Number of sampling points affected by an overflow range since the start of the measurement.

bool align_to_reference

Indicates if the sampling grid has been aligned to the ReferenceClock.

timestamp_t sampling_interval

The sampling interval in picoseconds.

timestamp_t sample_offset

Index offset of the first sampling point in the object.

bool channels_last_dim

The memory layout of the output data:

  • If True, the data is stored with channels as the last dimension (row-major order for channels).

  • If False, the data is stored with channels as the first dimension (column-major order for channels).

FrequencyStability

../../_images/FrequencyStability.svg
class FrequencyStability : public IteratorBase

Frequency Stability Analysis is used to characterize periodic signals and to identify sources of deviations from the perfect periodicity. It can be employed to evaluate the frequency stability of oscillators, for example. When the Time Tagger’s internal clock stability falls short of requirements, locking to a stable external reference is recommended. This can be achieved by calling TimeTaggerSource::setReferenceClock(). See the In Depth Guide: Software-Defined Reference Clock for details.

A set of established metrics provides insights into the oscillator characteristics on different time scales. The most prominent metric is the Allan Deviation (ADEV). FrequencyStability class executes the calculation of often used metrics in parallel and conforms to the IEEE 1139 standard. For more information, we recommend the Handbook of Frequency Stability Analysis.

The calculated deviations are the root-mean-square \sqrt{f_n \sum_i\left(E_i^{(n)}\right)^2} of a specific set of error samples E^{(n)} with a normalization factor f_n. The step size n together with the oscillator period T defines the time span \tau_n = n T that is investigated by the sample. The error samples E^{(n)} are calculated from the phase samples t that are generated by the FrequencyStability class by averaging over the timestamps of a configurable number of time-tags. To investigate the averaged phase samples directly, a trace of configurable length is stored to display the current evolution of frequency and phase errors.

Each of the available deviations has its specific sample E^{(n)}. For example, the Allan Deviation investigates the second derivative of the phase t using the sample E_i^{(n)} = t_i - 2 t_{i+n} + t_{i+2n}. The full formula of the Allan deviation for a set of N averaged timestamps is

\mathrm{ADEV}(\tau_n) = \sqrt{\frac{1}{2(N-2n)\tau_n^2}
  \sum_{i=1}^{N-2n}\left(t_i - 2 t_{i+n} + t_{i+2n}\right)^2}.

The deviations can be displayed in the Allan domain or in the time domain. For the time domain, the Allan domain data is multiplied by a factor proportional to \tau. This means that in a log-log plot, all slopes of the time domain curves are increased by +1 compared to the Allan ones. The factor \sqrt{3} for |ADEV|/|MDEV| and \sqrt{10/3} for |HDEV|, respectively, is used so that the scaled deviations of a white phase noise distortion correspond to the standard deviation of the averaged timestamps t. In some cases, there are different established names for the representations. The FrequencyStability class provides numerous metrics for both domains:

Allan domain

Time domain

Standard Deviation (STDD)

Allan Deviation (ADEV)

ADEVScaled = \frac{\tau}{\sqrt{3}} ADEV

Modified Allan Deviation (ADEV)

Time Deviation TDEV = \frac{\tau}{\sqrt{3}} MDEV

Hadamard Deviation (HDEV )

HDEVScaled = \frac{\tau}{\sqrt{10 / 3}} HDEV

See all common methods

Public Functions

FrequencyStability(TimeTaggerBase tagger, channel_t channel, int[] steps, timestamp_t average = 1000, int trace_len = 1000)

Note

Use average and TimeTagger::setEventDivider() with care: The event divider can be used to save USB bandwidth. If possible, transfer more data via USB and use average to improve your results.

Parameters:
  • tagger – Time tagger object.

  • channel – The input channel number.

  • steps – The step sizes to consider in the calculation. The length of the list determines the maximum number of data points. Because the oscillator frequency is unknown, it is not possible to define \tau directly.

  • average – The number of time-tags to average internally. This downsampling allows for a reduction of noise and memory requirements (default: 1000).

  • trace_len – Number of data points in the phase and frequency error traces, calculated from averaged data. The trace always contains the latest data (default: 1000).

FrequencyStabilityData getDataObject()
Returns:

An object that allows access to the current metrics.

class FrequencyStabilityData

Public Functions

float[] getTau()

The \tau axis for all deviations. This is the product of the steps parameter of the FrequencyStability measurement and the measured average period of the signal.

Returns:

The \tau values.

float[] getADEV()

The overlapping Allan deviation, the most common analysis framework. In a log-log plot, the slope allows one to identify the type of noise:

  • -1: white or flicker phase noise like discretization or analog noisy delay

  • -0.5: white period noise

  • 0: flicker period noise like electric noisy oscillator

  • 0.5: integrated white period noise (random walk period)

  • 1: frequency drift, e.g., induced thermally.

Sample:

E_i^{(n)} = t_i - 2 t_{i+n} + t_{i+2n}.

Domain:

Allan domain.

Returns:

The overlapping Allan Deviation.

float[] getMDEV()

Modified overlapping Allan deviation. It averages the second derivate before calculating the RMS. This splits the slope of white and flicker phase noise:

  • -1.5: white phase noise, like discretization

  • -1.0: flicker phase noise, like an electric noisy delay.

The metric is more commonly used in the time domain, see getTDEV():

Sample:

E_i^{(n)} = \frac{1}{n} \sum_{j=0}^{n-1} \left(t_{i+j} - 2 t_{i+j+n} + t_{i+j+2n}\right).

Domain:

Allan domain.

Returns:

The overlapping MDEV.

float[] getHDEV()

The overlapping Hadamard deviation uses the third derivate of the phase. This cancels the effect of a constant phase drift and converges for more divergent noise sources at higher slopes:

  • 1: integrated flicker period noise (flicker walk period)

  • 1.5: double integrated white period noise (random run period).

It is scaled to match the ADEV for white period noise.

Sample:

E_i^{(n)} = t_i - 3 t_{i+n} + 3 t_{i+2n} - t_{i+3n}.

Domain:

Allan domain.

Returns:

The overlapping HDEV.

float[] getSTDD()

Standard deviation of the periods.

Warning

The standard deviation is not recommended as a measure of frequency stability because it is non-convergent for some types of noise commonly found in frequency sources, most noticeable the frequency drift.

Sample:

E_i^{(n)} = t_i - t_{i+n} - \mathrm{mean}_k(t_k - t_{k+n}).

Domain:

Time domain.

Returns:

The standard deviation.

float[] getADEVScaled()

Domain:

Time domain.

Returns:

The scaled version of the overlapping Allan Deviation, equivalent to getADEV() * getTau() / \sqrt{3}.

float[] getTDEV()

The Time Deviation (TDEV) is the common representation of the Modified overlapping Allan deviation getMDEV(). Taking the log-log slope +1 and the splitting of the slope of white and flicker phase noise into account, it allows an easy identification of the two contributions:

  • -0.5: white phase noise, like discretization

  • 0: flicker phase noise, like an electric noisy delay.

Domain:

Time domain.

Returns:

The overlapping Time Deviation, equivalent to getMDEV()* getTau() / \sqrt{3}.

float[] getHDEVScaled()

Warning

While HDEV is scaled to match ADEV for white period noise, this function is scaled to match the TDEV for white phase noise. The difference of period vs phase matching is roughly 5% and easy to overlook.

Domain:

Time domain.

Returns:

The scaled version of the overlapping Hadamard Deviation, equivalent to getHDEV() * getTau() / \sqrt{10 / 3}.

float[] getTraceIndex()

The time axis for getTracePhase() and getTraceFrequency().

Returns:

The time index in seconds of the phase and frequency error trace.

float[] getTracePhase()

Provides the time offset of the averaged timestamps from a linear fit over the last trace_len averaged timestamps.

Returns:

A trace of the last trace_len phase samples in seconds.

float[] getTraceFrequency()

Provides the relative frequency offset from the average frequency during the last trace_len + 1 averaged timestamps.

Returns:

A trace of the last trace_len normalized frequency error data points in pp1.

float[] getTraceFrequencyAbsolute(float input_frequency = 0.0)

Provides the absolute frequency offset from a given input_frequency during the last trace_len + 1 averaged timestamps.

Parameters:

input_frequency – Nominal frequency of the periodic signal (default: 0 Hz).

Returns:

A trace of the last trace_len frequency data points in Hz.

PhaseNoise

../../_images/PhaseNoise.svg
class PhaseNoise : public IteratorBase

This measurement provides a phase noise estimator with spectral samples distributed quasi-logarithmically over frequency offset. When the Time Tagger’s internal clock stability falls short of requirements, locking to a stable external reference is recommended. This can be achieved by calling TimeTaggerSource::setReferenceClock(). See the In Depth Guide: Software-Defined Reference Clock for details.

Welch’s method is employed to estimate the power spectral density (PSD) from the time tag stream:

  • The time tag stream is divided into overlapping sequences of NFFT = 4 * samples_per_octave samples.

  • The linear regression is applied to each sequence to remove constant phase and frequency offsets, yielding demodulated phase samples.

  • A Hann window is applied to each sequence to suppress spectral leakage and mitigate edge effects in the Fast Fourier Transform (FFT). These windowing operations are visualized in the sketch as the colored envelope curves (red, orange, brown) spanning overlapping time tags sequences.

  • The squared magnitude of each FFT result is computed and averaged over time to reduce variance.

  • Sequences are processed with 50% overlap to improve spectral stability and compensate for the window’s reduced sensitivity at the edges.

Welch’s method provides a spectrum with linearly spaced spectral samples. To achieve a quasi-logarithmic distribution, only the upper half of each FFT output is retained. The lower-frequency half is reconstructed by recursively averaging adjacent timestamp pairs and reapplying Welch’s method at each level of decimation, as shown in the sketch. This recursive refinement yields samples_per_octave spectral samples per octave.

See all common methods

Public Functions

PhaseNoise(TimeTaggerBase tagger, channel_t channel, int samples_per_octave = 32)
Parameters:
  • tagger – Time Tagger object instance.

  • channel – The channel to analyze.

  • samples_per_octave – The number of phase noise samples per octave (default: 32). For optimal FFT performance, this should be set to a power of two.

PhaseNoiseData getDataObject()

Returns a PhaseNoiseData object containing a snapshot of the data accumulated in the PhaseNoise at the time this method is called.

Returns:

An object providing access to a snapshot data.

class PhaseNoiseData

Public Functions

float[] getPhaseNoise()

Array of phase noise measurement results.

Returns:

The phase noise measurement results in dBc/Hz.

float getIntegratedJitter(float lower_bound = 12000.0, float upper_bound = -1.0)

Integrates the phase noise and calculate the estimated RMS jitter.

Note

The integration starting from 0 Hz will diverge for any noise source with a spectral power density law starting from 1/f. This includes Flicker phase noise, any frequency noise and any frequency drifts.

Parameters:
  • lower_bound – The lower frequency offset boundary for the integration in Hz (default: 12e3).

  • upper_bound – The upper frequency offset boundary for the integration in Hz (default: -1). Negative values are interpreted as the Nyquist frequency.

Returns:

The integrated phase noise as estimated RMS jitter in seconds.

float[] getOffset()

Array of frequency offsets for all spectral samples.

Returns:

The frequency offset for each spectral sample in Hz.

int[] getAveragedSequences()

Array of the number of averaged sequences for all spectral samples.

Returns:

The number of averaged sequences for each spectral samples.

float getFrequency()

Average carrier frequency of the PhaseNoise measurement.

Returns:

The average carrier frequency in Hz.

PulsePerSecondMonitor

../../_images/PulsePerSecondMonitor.svg
class PulsePerSecondMonitor : public IteratorBase

This measurement allows the user to monitor the synchronicity of different sources of 1 pulse per second (PPS) signals with respect to a reference source. For each signal from the reference PPS source, comparative offsets are calculated for the other signal channels. Upon processing, a UTC timestamp from the system time is associated with each reference pulse.

The monitoring starts on the first signal from the reference source and will run uninterrupted until the measurement is stopped. If a signal from a channel is not detected within one and a half periods, its respective offset will not be calculated but the measurement will continue nonetheless.

By specifying an output file name, the monitoring data can be continuously written to a comma-separated value file (.csv).

See all common methods

Note

If you need to monitor reference drift over many PPS epochs, using PulsePerSecondData::getReferenceOffsets(), or you need traceability to a lab standard, it is advisable to feed a stable external reference (e.g., 10 MHz) into a regular input of the Time Tagger and enable the ReferenceClock via TimeTaggerSource::setReferenceClock(). See the In Depth Guide: Software-Defined Reference Clock for details. On the other hand, the internal clock is sufficient to monitor time offsets of multiple PPS channels relative to one reference PPS, provided the edges refer to the same nominal second.

Public Functions

PulsePerSecondMonitor(TimeTaggerBase tagger, channel_t reference_channel, channel_t[] signal_channels, str filename = "", timestamp_t period = 1E12)
Parameters:
  • tagger – Time Tagger object instance.

  • reference_channel – The channel number corresponding to the PPS reference source.

  • signal_channels – A list of channel numbers with PPS signals to be compared to the reference.

  • filename – The name of the .csv file to store measurement data. By default, no data is written to file (default: “”).

  • period – The assumed period of the reference source, typically one second, in picoseconds (default: 1e12).

PulsePerSecondData getDataObject(bool remove = false)

Returns a PulsePerSecondData object containing a snapshot of the data accumulated in the PulsePerSecondMonitor at the time this method is called. To remove the data from the internal memory after each call, set remove to True.

Parameters:

remove – Controls if the returned data shall be removed from the internal buffer.

Returns:

An object providing access to a snapshot data.

class PulsePerSecondData

Public Functions

int[] getIndices()

The indices of each reference pulse in the PulsePerSecondData object. The first reference pulse will have index 0, each subsequent pulse from the reference source increments the index by one. In case of overflows in the reference channel, this index will be incremented by the number of missed pulses.

Returns:

A list of indices for each pulse from the reference source.

float[] getReferenceOffsets()

A list of offsets of each reference pulse with respective to its predecessor, with the period subtracted. For a perfect PPS source, this offset would always be zero. The offset of the first pulse is always defined to be zero. If a reference signal is missing, its offset is defined to be NaN.

Returns:

A list of the offsets of each reference with respect to the previous.

float[,] getSignalOffsets()

For each reference contained in the PulsePerSecondData object a list of offsets for each signal channel is given, in the channel order given by signal_channels. If any signal is missing, its offset is defined to be NaN.

Returns:

A list of lists of offsets for each signal_channel for given reference pulses.

float[] getUtcSeconds()

The number of elapsed seconds from the beginning of the Unix epoch (1st of January 1970) to the time at which each reference pulse is processed, as a floating point number.

Returns:

A list of the number of seconds since the Unix epoch to the time of processing, for each reference pulse.

str[] getUtcDates()

The UTC timestamps for the system time at which each reference pulse is processed, as a string with ISO 8601 formatting (YYYY-MM-DD hh:mm:ss.ssssss).

Returns:

A list of the UTC timestamp at processing time, for each reference pulse.

bool[] getStatus()

A list of booleans values describing whether all signals, including from the reference source, were detected. True corresponds to a complete collection of signals, False otherwise.

Returns:

A list of bools describing the signal integrity for each reference pulse.

Public Members

int size

Number of reference pulses contained in the PulsePerSecondData object.