CSS-WC Clients

Modules: dvbcss.protocol.client.wc | dvbcss.protocol.client.wc.algorithm

The WallClockClient class provides a complete Wall Clock Client implementation. It is used in conjunction with an algorithm for adjusting a clock object so that it mirrors the server’s Wall Clock.

Using a Wall Clock Client

Recommended simplest use is to instantiate a WallClockClient and provide it with an instance of the LowestDispersionCandidate algorithm to control how it updates a clock.

WallClockClient is used by providing it with an object implementing the clock synchronisation algorithm. The Wall Clock client handles the protocol interaction (sending the requests and parsing the responses) at the times specified by the algorithm and passes the results of each request-response measurement (known as a ‘candidate’) to the algorithm. The algorithm then adjusts the clock.

The type of Clock class that can be used for the wall clock will depend on the algorithm. Some algorithms require that the tick rate of the clock be 1 tick per nanosecond (tick rate = 1000000000). The WallClockClient class does not require this, but it is recommended to use this tick rate.

A simple example that connects to a wall clock server at 192.168.0.115 port 6677 and sends requests once per second:

from dvbcss.clock import SysClock as SysClock
from dvbcss.clock import TunableClock as TunableClock
from dvbcss.protocol.client.wc import WallClockClient
from dvbcss.protocol.client.wc.algorithm import LowestDispersionCandidate

sysClock=SysClock()
wallClock=TunableClock(sysClock,tickRate=1000000000)

algorithm = LowestDispersionCandidate(wallClock,repeatSecs=1,timeoutSecs=0.5)

bind = ("0.0.0.0", 6677)
server = ("192.168.0.115", 6677)

wc_client=WallClockClient(bind, server, wallClock, algorithm)
wc_client.start()

# wall clock client is now running in the background

After the start() method is called, the WallClockClient runs in a separate thread and execution continues.

Algorithms

The algorithm object determines when (and how often) a WallClockClient sends CSS-WC protocol requests and processes the results of requests and responses to adjust the clock object representing the wall clock.

Dispersion algorithm

The LowestDispersionCandidate algorithm is the recommended algorithm. It uses the candidate with the lowest dispersion.

Simple algorithm

The MostRecent algorithm is a simple naive algorithm that uses the most recent candidate irrespective of its quality (e.g. how long the round-trip time of the measurement was)

Writing new algorithms

An algorithm is an object that has the following method:

.algorithm(self)[source]

A python generator function that yields whenever it wants a Wall Clock protocol measurement to be taken:

candidateOrNone = yield timeoutSecs

The yield must pass a timeout in seconds. This is the maximum amount of time the Wall Clock client will wait for a response to its request before timing out.

The yield statement will return either None or a dict containing two Candidate object representing the result of the measurement in units of ticks and units of nanoseconds:

{
    "ticks" : candidate,    # in units of ticks
    "nanos" : candidate,    # same, but in units of nanoseconds
}

The algorithm can then use the Candidate object in its algorithm for estimating the wall clock (and in the case of most practical implementations: adjusting a dvbcss:Clock object).

Here is an example of a simple naive algorithm that adjusts a TunableClock object using the most recent measurement, irrespective of influencing factors such as previous measurements or network latency (round trip time). It makes requests at most once per second and has a timeout on waiting for responses of half a second:

class NaiveAlgorithm(object):

    def __init__(self,clock):
        self.clock = clock
    
    def algorithm(self):
        while True:
            candidate=(yield 0.5)
            if candidate is not None:
                candidate=candidate["ticks"]
                self.clock.adjustTicks(candidate.offset)
                time.sleep(1.0)

Composable Filter and prediction algorithm

There is also a simple modular framework for building up an algorithm out of two parts:

  • Filters - processes measurement candidates, determining whether to reject them.
  • A Predictor - takes the measurement candidates outputted from the filtering step and use them to adjust the clock.

Use the FilterAndPredict() function to compose zero, one or more Filters, and a Predictor into an algorithm that can be used with a WallClockClient.

When using this algorithm, you provide a CorrelatedClock object to it, whose parent is the clock given to the :class:`~dvbcss.protocol.client.wc.WallClockClient.

This algorithm controls the CorrelatedClock object by settings its correlation property to (0,offset) where offset is provided by the predictor. The parent of this clock is the clock used by the WallClockClient in generating the measurement candidates. So the job of the predictor is always to estimate the current absolute offset between that clock and the wall clock of the server.

Here is a simple example that uses a simple predictor and a round-trip-time threshold filter:

from dvbcss.protocol.wc.algorithm import FilterAndPredict, FilterRttThreshold, PredictSimple

sysClock = SysClock(tickRate=1000000000)
wallClock = CorrelatedClock(parentClock=sysClock, tickRate=1000000000, correlation=(0,0))

filters = [ FilterRttTreshold(thresholdMillis=10.0) ]
predictor = PredictSimple()

algorithm = FilterAndPredict(wallClock, repeatSecs, timeoutSecs, filters, predictor)

bind = ("0.0.0.0", 6677)
server = ("192.168.0.115", 6677)

wc_client=WallClockClient(bind, server, wallClock, algorithm)
wc_client.start()

Note

The Clock object given to the algorithm must be CorrelatedClock whose parent is the clock object provided to the WallClockClient object.

Both clocks must have the same tick rate.

Round-trip time threshold Filter

The FilterRttThreshold class implements a filter that eliminates any candidate where the round-trip time exceeds a threshold.

Lowest dispersion candidate filter

The FilterLowestDispersionCandidate class implements a filter that eliminates any candidate if it does not have a lower dispersion that any candidate that came before it.

Simple Predictor

The PredictSimple class is a simple predictor that uses the candidate most recently provided to it and uses the offset calculated by that candidate as the prediction.

Writing your own Filter

You can write your own Filter by creating a class with the following method defined:

.checkCandidate(self, candidate)[source]
Parameters:candidate – A (dict) containing two Candidate objects representing the result of the measurement in units of ticks (dict key “ticks”) and units of nanoseconds (dict key “nanos”):

Writing your own Predictor

You can write your own Predictor by creating a class with the following methods defined:

.addCandidate(self, candidate)[source]
param candidate:
 A (dict) containing two Candidate objects representing the result of the measurement in units of ticks (dict key “ticks”) and units of nanoseconds (dict key “nanos”):

This method is called whenever a measurement candidate resulting from a request-response measurement survives the filtering process.

.predictOffset(self)[source]

This method must return the difference between the clock used and the server wall clock. The clock used by the client is a fixed clock. The difference therefore represents the difference between that clock and the Wall Clock on the server.

Returns:The offset (in ticks) between the client clock and the wall clock

Functions

Filter and Prediction algorithm creator

dvbcss.protocol.client.wc.algorithm.FilterAndPredict(clock, repeatSecs=1.0, timeoutSecs=0.2, filters=[], predictor=<dvbcss.protocol.client.wc.algorithm._filterpredict.PredictSimple object>)[source]

Combines zero, one or more Filters and a Predictor and returns an algorithm for a WallClockClient.

Parameters:
  • clock – A CorrelatedClock object that will be adjusted to match the Wall Clock.
  • repeatSecs – (float) The rate at which Wall Clock protocol requests are to be sent (in seconds).
  • timeoutSecs – (float) The timeout on waiting for responses to requests (in seconds).
  • filters – (list of Filters) A list of zero, one or more Filters
  • predictor – (Predictor) The Predictor to use.
Returns:

An algorithm object embodying the filtering and prediction process, that is suitable to be passed to a WallClockClient.

This algorithm controls the CorrelatedClock object by settings its correlation property to (0,offset) where offset is provided by the predictor. The parent of this clock is the clock used by the WallClockClient in generating the measurement candidates. So the job of the predictor is always to estimate the current absolute offset between that clock and the wall clock of the server.

Requests are made at the repetition rate specified. If a response is received within the timeout period it is then it is transformed into a measurement candidate and passed to the filters. Filters are applied in the order you list them. If a candidate survives filtering, then it is passed to the predictor. Every time a candidate is provided to the predictor, the offset returned by the predictor replaces the previous offset.

Note

The Clock object must be CorrelatedClock whose parent is the clock object provided to the WallClockClient object with which this algorithm is used.

It must not be the same clock object. However both must have the same tick rate. If the same clock object is used or different tick rates are used then the Wall Clock will not synchronise correctly..

The tick rate of the Clock can be any tick rate (it does not have to be one tick per nanosecond), but too low a tick rate will limit clock synchronisation precision.

Classes

WallClockClient

class dvbcss.protocol.client.wc.WallClockClient((bindaddr, bindport), (dstaddr, dstport), wallClock, wcAlgorithm)[source]

Simple object implementing the client side of the CSS-TS protocol.

Use by initialising and supplying with an algorithm object and Clock object.

Initialisation takes the following parameters:

Parameters:
  • (bindaddr,bindport) – (str, int) A tuple containing the IP address (as a string) and port (as an int) to bind to to listen for incoming packets
  • (dstaddr,dstport) – (str, int) A tuple containing the IP address (as a string) and port (as an int) of the Wall Clock server
  • wallClock – (clock) The local clock that will be controlled to be a Wall Clock
  • wcAlgorithm – (algorithm) The algorithm for the client to use to update the clock.

It is recommended to use the LowestDispersionCandidate algorithm.

algorithm = None[source]

(read only) The algorithm object being used with this WallClockClient

start()[source]

Call this method to start the client running. This function call returns immediately and the client proceeds to run in a thread in the background.

Does nothing if the client is already running.

stop()[source]

Call this method to stop the client running. Returns once the client has stopped.

If the client is not running then nothing happens and this call returns immediately.

Dispersion algorithm

class dvbcss.protocol.client.wc.algorithm.LowestDispersionCandidate(clock, repeatSecs=1.0, timeoutSecs=0.2, localMaxFreqErrorPpm=500)[source]

Algorithm that selects the candidate (request-response measurement result) with the lowest dispersion.

Dispersion is a formal measure of the error bounds of the Wall Clock estimate. This value is the sum of possible error due to:

  • measurement precision limitations (at both client and server)
  • round-trip time
  • maximum potential for oscillator frequency error at the client and at the server server This grows as the candidate (that was used to most recently adjust the clock) ages.

Note

The Clock object must be the same one that is provided to the WallClockClient, otherwise this algorithm will not synchronise correctly.

The tick rate of the Clock can be any tick rate (it does not have to be one tick per nanosecond), but too low a tick rate will limit clock synchronisation precision.

There is a stub callback function provided that you can override (e.g. by subclassing) that will be called whenever the clock is adjusted:

  • onClockAdjusted()

The arguments to this method provide details of when the adjustment took place and what adjustment was made. It also reports the dispersion before and after the adjustment and gives information needed to extrapolate future dispersions. You can use this, for example, to record the clock dispersion over time.

Initialisation takes the following parameters:

Parameters:
  • clock – A TunableClock object representing that will be adjusted to match the Wall Clock.
  • repeatSecs – (float) The rate at which Wall Clock protocol requests are to be sent (in seconds).
  • timeoutSecs – (float) The timeout on waiting for responses to requests (in seconds).
  • localMaxFreqErrorPpm – (float) The maximum frequency error of the local oscillator that underpins the clock object provided (in ppm).
getCurrentDispersion()[source]
Returns:Current dispersion at this moment in time in units of nanoseconds.
getWorstDispersion()[source]

Returns the worst (greatest) dispersion encountered since the previous time this method was called.

The first time it is called, the value reported will be very large, reflecting the fact that initially dispersion is high because the client is not yet synchronised.

Returns:dispersion
onClockAdjusted(timeAfterAdjustment, adjustment, oldDispersionNanos, newDispersionNanos, dispersionGrowthRate)[source]

This method is called immediately after a clock adjustment has been made, and gives details on how the clock was changed and the effect on the dispersion.

Parameters:
  • timeAfterAdjustment – The wall clock time (in ticks) immedaitely after the adjustment took place
  • adjustment – The amount by which the wall clock instaneously changed (in ticks)
  • oldDispersionNanos – The dispersion (in nanoseconds) just prior to adjustment
  • newDispersionNanos – The dispersion (in nanoseconds) immediately after adjustment
  • dispersionGrowthRate – The rate at which dispersion will continue to grow.
To calculate a future dispersion at time T:
futureDispersion = newDispersionNanos + (t-timeOfAdjustment) * dispersionGrowthRate

This is a stub for this method. Sub-classes should implement it.

Most recent measurement algorithm

class dvbcss.protocol.client.wc.algorithm.MostRecent(clock, repeatSecs=1.0, timeoutSecs=0.2)[source]

Simple (naive) Wall Clock client algorithm.

Crash locks the supplied clock based on the offset observed in the result of every successful request/response.

Note

The Clock object must be the same one that is provided to the WallClockClient, otherwise this algorithm will not synchronise correctly.

The tick rate of the Clock can be any tick rate (it does not have to be one tick per nanosecond), but too low a tick rate will limit clock synchronisation precision.

Initialisation takes the following parameters:

Parameters:
  • clock – A TunableClock object representing that will be adjusted to match the Wall Clock.
  • repeatSecs – (float) The rate at which Wall Clock protocol requests are to be sent (in seconds).
  • timeoutSecs – (float) The timeout on waiting for responses to requests (in seconds).
getCurrentDispersion()[source]

Calling this method will always result in ValueError being raised.

Raises:ValueError – This algorithm does not model clock synchronisation accuracy.

Filter and Prediction composable algorithms

Filters

class dvbcss.protocol.client.wc.algorithm._filterpredict.FilterRttThreshold(thresholdMillis=1.0)[source]

Simple filter that rejects all candidates where round trip time exceeds a specified threshold.

Parameters:thresholdMillis – (float) The threshold to use (in milliseconds)
class dvbcss.protocol.client.wc.algorithm._filterpredict.FilterLowestDispersionCandidate(clock, precisionSecs, maxFreqErrorPpm)[source]

Simple filter that will reject a candidate unless its dispersion is lower than any candidate seen previously.

Parameters:
  • clock – A TunableClock object representing that will be adjusted to match the Wall Clock.
  • precisionSecs – (float) The measurement precision of the local clock (in units of seconds).
  • maxFreqErrorPpm – (float) The maximum frequency error of the local oscillator that underpins the clock object provided (in ppm).

Predictors

class dvbcss.protocol.client.wc.algorithm._filterpredict.PredictSimple[source]

Simple naive predictor that uses the offset calculated by the most recent candidate.

General helper classes

Dispersion calculator

class dvbcss.protocol.client.wc.algorithm.DispersionCalculator(clock, localPrecisionSecs, localMaxFreqErrorPpm)[source]

Candidate quality calculator

This function is used internally by the WallClockClient class. .. autofunction:: dvbcss.protocol.client.wc.algorithm.calcQuality