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.
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.protocol.client.wc import WallClockClient
from dvbcss.protocol.client.wc.algorithm import LowestDispersionCandidate
sysClock=SysClock()
wallClock=CorrelatedClock(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.
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
(a Candidate
) to the algorithm. The algorithm then
adjusts the clock.
Changed in version 0.4: The measurement process involves taking a reading from the local clock when
the request is about to be sent, and when the response is received. This measurement
is taken from the parent of the clock you provide. The candidate represents
a possible relationship between that (parent) clock and the Wall Clock of the
server given the results of the request-response measurement. The algorithm
processes this and makes a decision as to the Correlation
that is to be used.
Although the WallClockClient class does not require the tickrate of the Wall Clock to be 1 tick per nanosecond, it is recommended to set it as such. This is because the next step (using the CSS-TS protocol) assumes a Wall Clock ticking at this rate.
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.
Changed in version 0.4: The yield statement will return either
None
or aCandidate
object representing the result of the measurement.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
clock
object).
Here is an example of a simple naive algorithm that adjusts a CorrelatedClock
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 0.5 seconds:
class NaiveAlgorithm(object):
def __init__(self,clock):
self.clock = clock
def algorithm(self):
while True:
candidate=(yield 0.5)
if candidate is not None:
self.clock.correlation = candidate.calcCorrelationFor(self.clock)
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
.
Changed in version 0.4: When using this algorithm, you provide a CorrelatedClock
object to it, whose parent is the
clock given to the WallClockClient
.
This algorithm controls the CorrelatedClock
object by settings its
correlation
property to that returned 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 to
determine the best correlation for modelling the relationship between that
(parent) 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.clock import CorrelatedClock, SysClock
from dvbcss.protocol.client.wc.algorithm import FilterAndPredict, FilterRttThreshold, PredictSimple
from dvbcss.protocol.client.wc import WallClockClient
sysClock = SysClock(tickRate=1000000000)
wallClock = CorrelatedClock(parentClock=sysClock, tickRate=1000000000)
filters = [ FilterRttThreshold(thresholdMillis=10.0) ]
predictor = PredictSimple(wallClock)
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()
The Clock object given to the algorithm must be CorrelatedClock
whose parent is the clock object provided to the WallClockClient object.
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 directly transforms that into a dvbcss.clock.Correlation
.
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:
.
predictCorrelation
(self)[source]¶
Returns: A Correlation
The returned Correlation must represent the relationship between the clock and its parent, such that the clock becomes an estimate of the server’s Wall Clock. This must be in the correct units (tick rate) for the clock and its parent.
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.
The
Candidate
objects provided to the algorithm represent the relationship between the parent of the provided clock and the server’s Wall Clock.The algorithm is then expected to set the
dvbcss.clock.Correlation
of the clock object such that it becomes an estimate of the server’s Wall Clock.It is recommended to use the
LowestDispersionCandidate
algorithm.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. Measurements will be taken from its parent and candidates provided to the algorithm will represent the relationship between that (parent) clock and the server’s wall clock. - wcAlgorithm – (algorithm) The algorithm for the client to use to update the clock.
- (bindaddr,bindport) – (
Dispersion algorithm¶
-
class
dvbcss.protocol.client.wc.algorithm.
LowestDispersionCandidate
(clock, repeatSecs=1.0, timeoutSecs=0.2, localMaxFreqErrorPpm=None)[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:
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
Correlated
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 – Optional. Override using the
getRootMaxFreqError()
of the clock as the max freq error of the local clock, and instead use this value. It is the clock maximum frequency error in parts-per-million
-
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
CorrelatedClock
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)[source]¶ Simple filter that will reject a candidate unless its dispersion is lower than that currently being used by the clock.
Note that at initialisation, the clock’s dispersion is forced to +infinity.
Parameters: clock – A CorrelatedClock
object representing that will be adjusted to match the Wall Clock.
Predictors¶
-
class
dvbcss.protocol.client.wc.algorithm._filterpredict.
PredictSimple
(clock)[source]¶ Simple naive predictor that chooses the correlation represented by the most recent candidate
Parameters: clock – The CorrelatedClock
that is to be set.Note that this predictor does not actually set the clock. It just needs it in order to calculate the correct correlation for it.
Functions¶
Filter and Prediction algorithm creator¶
-
dvbcss.protocol.client.wc.algorithm.
FilterAndPredict
(clock, repeatSecs=1.0, timeoutSecs=0.2, filters=[], predictor=None)[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, or None to default to
PredictSimple
This algorithm controls the
CorrelatedClock
object by settings itscorrelation
property to that 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 theCorrelation
needed by the clock.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 correlation returned by the predictor replaces the previous correlation.
Note
The Clock object must be
CorrelatedClock
whose parent is the clock object that is measured when generating the candidates.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
Candidate quality calculator¶
This function is used internally by the WallClockClient
class.
-
dvbcss.protocol.client.wc.algorithm.
calcQuality
(reqMsg, respMsg)[source]¶ Generate measure of how good the response was. Quality < 0 means response corresponded to a different request.
Quality = 3 or 4 means it was a response for which no follow-up is expected or a follow-up response.
Quality = 2 means it was a response for which a follow-up is expected