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 adict
containing twoCandidate
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:
Writing your own Predictor¶
You can write your own Predictor by creating a class with the following methods defined:
.
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 itscorrelation
property to (0,offset) where offset is provided by the predictor. The parent of this clock is the clock used by theWallClockClient
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.
- clock – A
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.- (bindaddr,bindport) – (
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).
- clock – A
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).
- clock – A
General helper classes¶
Candidate quality calculator¶
This function is used internally by the WallClockClient
class.
.. autofunction:: dvbcss.protocol.client.wc.algorithm.calcQuality