================================
Software-Defined Reference Clock
================================

Overview of synchronization concepts
------------------------------------

Like many other instruments, the Time Tagger can be locked to an external clock.
Unlike conventional implementations, however, it supports two different synchronization concepts.

Traditional hardware reference clock
************************************

Among the inputs of the Time Tagger, you will find one labeled CLK or CLK IN.
This input can be used to provide an external frequency reference.
If the device's hardware |PLL| accepts the applied frequency,
the Time Tagger switches to the external reference which takes over the clock role from the internal oscillator.
As a result, the |FPGA| of the Time Tagger that performs the |TDC| is driven directly by the external clock.
However, this concept has three major drawbacks:

#. The CLK IN accepts only specific frequencies within a narrow tolerance range.
   For example, a |ttu-name| or |ttx-name| accepts only 10 MHz or 500 MHz;
   a frequency of 9.5 MHz would already be rejected.
   As a result, it is often not possible to lock the Time Tagger directly to a laser system,
   even though using the laser as the master clock of an experiment may be desirable.
#. For signals that are strongly correlated with the external reference, the self-calibration
   of the Time Tagger does no longer operate correctly. This self-calibration relies on the assumption
   that incoming events are randomly distributed with respect to the |TDC|.
   This condition is always fulfilled when the internal oscillator is used,
   but it may be violated when the |FPGA| clock is defined by an external reference.
#. The loop filter is fixed in hardware. Therefore, the cutoff frequency between the external clock
   and the built-in reference cannot be configured.
   For drifting references, a high cutoff frequency allows faster tracking, whereas for very stable references,
   a low cutoff frequency provides better suppression of white noise.

There are still use cases that make use of the hardware clock (see :doc:`/synchronizer/index`).

Software-defined reference clock
********************************

The alternative and recommended concept is the software-defined reference clock.
It has been introduced in software version 2.10 under the label *Software Clock* and has been extended in version 2.18 to the *Reference Clock*.
In contrast to the traditional hardware synchronization, the TDC is always performed with respect to the internal oscillator of the Time Tagger.
The external reference is applied to one of the standard signal inputs.
This means, on the hardware level, it is handled like any other signal.
On the software level, however, it is evaluated immediately by a software PLL.
Based on the new time base provided by the PLL, the entire time-tag stream is rescaled.
This means that the behavior of all virtual channel and measurement objects will feel to the user just like the external clock has been applied to the instrument itself.


Setting up the software-defined reference clock
-----------------------------------------------

After connecting a clock signal to one of the inputs of the Time Tagger, you can declare the respective input as the system clock by the :cpp:func:`~TimeTaggerSource::setReferenceClock` method:

.. code:: python

    from Swabian import TimeTagger
    tagger = TimeTagger.createTimeTagger()
    tagger.setEventDivider(channel=1,
                           divider=2)
    tagger.setReferenceClock(clock_channel=1,           # channel number
                             clock_frequency=10E6,      # frequency in Hz
                             time_constant=1E-3,        # time constant in seconds
                             wait_until_locked=True)
    
    # This command would be ignored because channel #1 is restricted by the Reference Clock.
    # The user receives a warning.
    tagger.setEventDivider(channel=1
                           divider=100)

In this example, a 10 MHz clock is connected to channel #1.
One important aspect is that the `clock_frequency` takes the actual frequency of the physical signal at the input.
While the *Reference Clock* is active, an *Event Divider* cannot be set by :cpp:func:`~TimeTaggerSource::setEventDivider`.
This means that the *Reference Clock* is aware of the original frequency before division and is able to inject events at the place of dismissed events.

The locking behavior of the *Reference Clock* depends strongly on the `time_constant` parameter.
It determines the time until the clock settles upon frequency changes.
A small `time_constant` allows the frequency to be tracked more quickly, but with less averaging.
On the other hand, larger values improve averaging, but the lock may be lost if the frequency changes too rapidly.
In addition, stronger averaging increases the influence of phase noise on the measurement.
The optimal value depends on the characteristics of the reference.
If the *Reference Clock* loses the lock, the Time Tagger will switch to the overflow mode and timing information is lost.

The following figure illustrates the effect of the *Reference Clock* for two signals with an average frequency of 10 MHz.
For clarity, the frequency fluctuations and measurement jitter are exaggerated.
In practice, the *Reference Clock* would not be able to lock to signals of such poor quality.

.. plot:: figures_engine/ReferenceClock_BasicConcept.py
    :align: center

In the upper panel, the input signal on channel #1 oscillates more slowly in the first half,
resulting in larger separations between events, and more quickly in the second half,
resulting in smaller separations. For the signal on channel #5, the behavior is reversed.
In addition, both signals include measurement jitter, which causes the spacing between neighboring events to vary randomly.

The middle panel shows the effect of declaring channel #1 as the *Reference Clock*.
Compared to the upper panel, the signal on channel #1 now appears much more uniform,
while the frequency variation on channel #5 becomes more pronounced.
This is because the *Reference Clock*, and therefore the software-defined time base,
follows the frequency changes of channel #1. Note that the original measurement jitter is still present on both channels.

The bottom panel shows the :cpp:member:`ReferenceClockState::ideal_clock_channel`.
While the *Reference Clock* computes the adjusted time base, it can also determine the expected timestamps of all events,
including those that were filtered out, and, therefore, not transmitted. These "ideal" time tags are separated by numerically exact intervals.
Since :cpp:member:`ReferenceClockState::ideal_clock_channel` is based on channel #1,
it largely removes the effect of measurement jitter and can therefore serve as an improved replacement signal.

Technical limitations
---------------------

Before setting up the *Reference Clock*, you should consider a few limitations.
In particular, it is important to understand which signals can be used as clock signals and what accuracy can theoretically be achieved.

Input signal limitations
************************

In comparison to a traditional hardware clock,  which on a |ttu-name| and |ttx-name| only accepts 10 MHz or 500 MHz,
the software-defined *Reference Clock* is much more flexible and can operate with arbitrary input frequencies.
For |ttu-name| and |ttx-name|, we recommend using reference clock frequencies between 100 kHz and |ttu-max-frequency| or |ttx-max-frequency|, respectively.
Tracking and evaluating periodic signals requires a sufficient internal oscillator, which the |tt20-name| is lacking, unfortunately.
For this reason, the |tt20-name| will not achieve the performance discussed in this article.
When configuring the *Reference Clock* on a |tt20-name|, a warning is displayed indicating that the resulting phase error may be large.
Whether this is acceptable depends on the experiment, but we will not consider the |tt20-name| further in this guide.


Resolution limitations
**********************

.. plot:: figures/ReferenceClock_TDEV/referenceclock_TDEV.py
    :align: center

The figure above shows the |TDEV| of a 1 MHz signal on two inputs.
It can be interpreted as the resolution limit for the various Time Tagger models using the *Reference Clock*.
The |TDEV| is a metric that can be measured using the :cpp:class:`FrequencyStability` measurement class.
It estimates the timing error of signal events separated by a given `tau` while taking into account averaging over all available data points.
The measurement is performed using a power splitter to route the 1 MHz signal to two inputs, #1 and #5.
Although the split signal is phase-locked at all times, the measurement jitter on the two inputs is independent.
The relevant question is therefore how strongly the individual measurement error can be reduced by averaging.

In this experiment, channel #1 is used as the `clock_channel` in :cpp:func:`~TimeTaggerSource::setReferenceClock`,
while channel #5 is analyzed with :cpp:class:`FrequencyStability`.
On the left, the `tau` axis starts at 1 µs, corresponding to the 1 MHz signal.
The data point at 1 µs represents the shortest possible interval between consecutive events and therefore does not allow for averaging.
Accordingly, the curves start at the specified timing resolution of the respective model.
At larger timescales, averaging over more events improves the timing resolution.
The |TDEV| settles between 100 and 200 femtoseconds for both, the |ttu-name| and the |ttx-name|.
This means, that for both models, there is a more or less common non-white noise floor.
While white noise can be eliminated at a rate of :math:`\frac{1}{\sqrt{n}}`
by averaging over :math:`n` events, this is not the case, e.g., for :math:`\frac{1}{f}`-noise.


Advanced features
-----------------

Emulating the Conditional Filter
********************************

In most cases it is neither necessary nor desirable to transmit the full clock signal to the PC.
For periodic signals such as a clock, the straightforward way to reduce the data rate is to use the *EventDivider*.
For a typical 10 MHz clock, an event divider of 100 can easily be applied without reducing performance.

Consider a fluorescence lifetime experiment:
A femtosecond-laser, which can be regarded as a clock, excites a sample and, from time to time, a photon is emitted a few nanoseconds later.
In this case, one of the signals is aperiodic, and the traditional filtering solution would be the *ConditionalFilter*:
Each photon allows exactly one laser event to pass to the PC.
This results in pairs of events, typically one photon event and one laser event.
Their time differences can be easily evaluated by measurements such as :cpp:class:`Histogram`.

However, this approach has two drawbacks in comparison to the *EventDivider* approach:

1. You have to use 50% of the available bandwidth for laser events, instead of reducing the bandwidth by a factor of 100 with the *EventDivider*.

2. You cannot benefit from the improved temporal resolution of the *ReferenceClock* on the periodic channel, because the transmitted signal is no longer periodic.

For this scenario, the *ReferenceClock* includes a feature that emulates the behavior of the *ConditionalFilter* while internally using the *EventDivider*.
The following code shows how to set up this emulation:

.. code:: python

    tagger.setEventDivider(channel=1,
                           divider=100)
    reference_clock_state = tagger.getReferenceClockState()
    tagger.setConditionalFilter(trigger=[2],
                                filtered=[reference_clock_state.ideal_clock_channel])
    tagger.setReferenceClock(clock_channel=1,
                             clock_frequency=80E6)

As you can see, the emulator is configured in the same way as *ConditionalFilter*, using :cpp:func:`~TimeTaggerSource::setConditionalFilter`.
It works as a modification of the way events are injected in the :cpp:member:`ReferenceClockState::ideal_clock_channel`.
The dismissed events are recreated during the rescaling process and immediately filtered by trigger events.
The effect is shown in the following sketch:

.. plot:: figures_engine/ReferenceClock_ConditionalFilter.py
    :align: center

Note that the jitter of the measured laser events is widely eliminated in the ideal clock and that comparatively few events need to be transferred.

Averaging of rising and falling edges
*************************************

On the |ttu-name| and |ttx-name|, there is an experimental feature that typically allows to improve the noise characteristics of periodic signals:
By using the :cpp:func:`TimeTagger::xtra_setAvgRisingFalling()` method, you can configure the Time Tagger such that it transmits the average of a close-by rising and falling edge.
This eliminates anti-correlated noise.
Low-frequency noise (e.g. flicker :math:`1/f``) on the analog input voltage shifts the trigger level transitions in the opposite direction on rising and falling edges (for similar rise vs fall times).
For the white noise part (which is per definition uncorrelated), it yields :math:`\sqrt(2)`.
It is not yet fully clear which effects contribute to this improvement but the graph below clearly shows that this makes it possible to push the |TDEV| below 100 fs.

.. plot:: figures/ReferenceClock_TDEV/referenceclock_TDEV_with_averaging.py
    :align: center