Synthesised clocks (dvbcss.clock)¶
Module: dvbcss.clock
The dvbcss.clock module provides software synthesised clock objects that can be chained together into dependent hierarchies.
Use in conjunction with dvbcss.task
to sleep and run code at set times on these clocks.
Introduction¶
The classes in this module implement software synthesised clocks
from which you can query a current time value.
A clock counts in whole numbers of ticks (unlike the standard library time.time()
function which
counts in seconds and fractions of a second) and has a tick rate (expresed in ticks per second).
To use clocks as timers or to schedule code to run later, you must use them with the functions of the dvbcss.task
module.
To use clocks begin with a root clock that is based on a underlying timing source. The following root clocks are provided:
SysClock
is an root clock based on thedvbcss.monotonic_time.time()
function as the underlying time source
Other dependent clocks can then be created that have the underlying clock as their parent. and further dependent clocks can be created with those dependents as their parents, creating chains of clocks, each based on their parent and leading back to an underlying clock. The following dependent clocks are provided:
CorrelatedClock
is a fixed tick rate clock where you define the point of correlation between it and its parent.TunableClock
is a clock that can have its tick count tweaked and its frequency slewed on the fly.RangleCorrelatedClock
is a clock where the relationship to the parent is determined from two points of correlation.
Dependent clocks can have a different tick rate to their parent and count their ticks from a different starting point.
Dependent clocks allow their relationship to its parent clock to be changed dynamically - e.g. the absolute value, or the rate at which the clock ticks. If your code needs to be notified of such a change, it can bind itself as a dependent to that clock.
The base ClockBase
class defines the set of methods common to
all clocks (both underlying and dependent)
Limitations on tick resolution (precision)¶
The Clock objects here do not run a thread that counts individual ticks. Instead, to determine the current tick value they query the parent clock for its current tick value and then calculate what the tick value should be.
A clock is therefore limited in the precision and resolution of its tick value by its parents. SysClock
,
for example, is limited by the resolution of the underlying time source provided to it by dvbcss.monotonic_time
module’s dvbcss.monotonic_time.time()
function. And this will be operating system dependent. SysClock also outputs
ticks as integer values.
If a parent of a clock only reports whole number (integer) tick values then that also limits the resolution of any clocks that depend on it. For example, a clock that counts in integer ticks only at 25 ticks per second will cause a clock descended from it, with a tick rate of 100 ticks per second, to report tick values that increment 4 ticks at a time ... or worse if a parent of both has an even lower tick rate.
With the clocks provided by this module, only SysClock
limits itself to integer numbers of ticks.
CorrelatedClock
and TunableClock
are capable of fractional numbers of ticks provided that the
parameters provided to them (e.g. the tickRate) are passed as floating point values (this will force python to
do the maths in floating point instead of integer maths).
Timers and Sleep functions¶
Use the functions of the dvbcss.task
in conjunction with Clock objects
to create code that sleeps, or which triggers callbacks, based on time as
measured by these clocks.
Usage examples¶
Simple hierarchies of clocks¶
Here is a simple example where a clock represents a timeline and another represents a timeline related to the first by a correlation:
from dvbcss.clock import SysClock
from dvbcss.clock import CorrelatedClock
# create a clock based on dvbcss.monotonic_time.time() that ticks in milliseconds
sysClock = SysClock(tickRate=1000)
# create a clock to represent a timeline
baseTimeline = CorrelatedClock(parentClock=sysClock, tickRate=25, correlation=(0,0))
# create a clock representing another timeline, where time zero corresponds to time 100
# on the parent timeline
subTimeline = CorrelatedClock(parentClock=baseTimeline, tickRate=25, correlation=(100,0)
At some point later in time during the program, we query the values of all the clocks, confirming that the sub timeline is always 100 ticks ahead of the base timeline.
def printTimes():
sys = sysClock.ticks()
base = baseTimeline.ticks()
sub = subTimeline.ticks()
print "SysClock ticks = %d", sys
print "Base timeline ticks = %d", base
print "Sub timeline ticks = %d", sub
>>> printTimes()
SysClock ticks = 20000
Base timeline ticks = 500
Sub timeline ticks = 600
Note that in these examples, for clarity, the tick count on the sysClock is artificially low. It would likely be a much larger value.
We then change the correlation for the base timeline, declaring tick 25 on its baseline to correspond to tick 0 on its parent timeline, and both the base timeline and the sub timeline reflect this:
>>> baseTimeline.correlation = (0,25)
>>> printTimes()
SysClock ticks = 30000
Base timeline ticks = 775
Sub timeline ticks = 875
Clock speed adjustment¶
All clocks have a speed
property. Normally this is 1.0. Some clock classes support changing this value. This scales the rate at which
the clock ticks relative to its parent. For example, 0.5 corresponds to half speed; 2.0 = double speed, 0 = frozen and -1.0 = reverse.
Clocks will take speed into account when returning their current tick position or converting it to or from the tick value of a parent clock. However it does not alter the tickRate property. A child clock will similarly ignore the speed property of a parent clock. In this way, the speed property can be used to tweak the speed of time, or to emulate speed control (fast forward, rewind, pause) for a media timeline.
Here is an example where we create 3 clocks in a chain and all tick initially at 100 ticks per second:
>>> import time
>>> baseClock = Sysclock(tickRate=100)
>>> clock1 = TunableClock(parent=baseClock, tickRate=100)
>>> clock2 = TunableClock(parent=clock1, tickRate=100)
We confirm that both clock1 and its child - clock2 - tick at 100 ticks per second:
>>> print clock1.ticks; time.sleep(1.0); print clock1.ticks
5023
5123
>>> print clock2.ticks; time.sleep(1.0); print clock2.ticks
2150
2250
If we change the tick rate of clock1 this affects clock1, but its child - clock2 - continues to tick at 100 ticks every second:
>>> clock1.tickRate = 200
>>> print clock1.ticks; time.sleep(1.0); print clock1.ticks
5440
5640
>>> print clock2.ticks; time.sleep(1.0); print clock2.ticks
4103
4203
But if we instead change the speed multiplier of clock1 then this not only affects the ticking rate of clock1 but also of its child - clock2:
>>> clock1.tickRate = 100
>>> clock1.speed = 2.0
>>> print clock1.ticks; time.sleep(1.0); print clock1.ticks
5740
5940
>>> print clock2.ticks; time.sleep(1.0); print clock2.ticks
4603
4803
Translating tick values between clocks¶
The clock classes provide mechanisms to translate a tick value from one clock to a tick value of another clock such that it still represents the same moment in time. So long as both clocks share a common ancestor clock, the conversion will be possible.
toParentTicks()
and fromParentTicks()
converts tick values for a clock to/from its parent clock.
toOtherClockTicks()
will convert a tick value for this clock to the corresponding tick value for any other clock
with a common ancestor to this one.
from dvbcss.clock import SysClock
from dvbcss.clock import CorrelatedClock
# create a clock based on dvbcss.monotonic_time.time() that ticks in milliseconds
sysClock = SysClock(tickRate=1000)
# +------------+
# .-- | mediaClock |
# +----------+ +-----------+ <--' +------------+
# | sysClock | <-- | wallClock |
# +----------+ +-----------+ <--. +-----------------+
# '-- | otherMediaClock |
# +-----------------+
wallClock = CorrelatedClock(parentClock=sysClock, tickRate=1000000000, correlation=(0,0))
mediaClock = CorrelatedClock(parentClock=wallClock, tickRate=25, correlation=(500021256, 0))
otherMediaClock = CorrelatedClock(parentClock=wallClock, tickRate=30, correlation=(21093757, 0))
# calculate wall clock time 'w' corresponding to a mediaClock time 1582:
t = 1582
w = mediaClock.toParentTicks(t)
print "When MediaClock ticks =", t, " wall clock ticks =", w
# calculate mediaClock time 'm' corresponding to wall clock time 1920395
w = 1920395
m = mediaClock.fromParentTicks(w)
print "When wall clock ticks =", w, " media clock ticks =", m
# calculate other media clock time corresponding to media clock time 2248
t = 2248
o = mediaClock.toOtherClockTicks(otherMediaClock, t)
print "When MediaClock ticks =", t, " other media clock ticks =", o
Implementing new clocks¶
Implement a new clock class by subclassing ClockBase
and implementing the stub methods.
For example, here is a clock that is the same as its parent (same tick rate) except that its current tick value differs by a fixed offset.
from dvbcss.clock import ClockBase
class FixedTicksOffsetClock(ClockBase):
def __init__(self, parent, offset):
super(FixedTicksOffsetClock,self).__init__()
self._parent = parent
self._offset = offset
def calcWhen(self, ticksWhen):
return self._parent.calcWhen(ticksWhen - self._offset)
def fromParentTicks(self, ticks):
return ticks + self._offset
def getParent(self):
return self._parent
@property
def tickRate(self):
return self._parent.tickRate
@property
def ticks(self)
return self._parent.ticks + self._offset
def toParentTicks(self, ticks):
return ticks - self._offset
In use:
>>> f = FixedTicksOffsetClock(parentClock, 100)
>>> print parentClock.ticks, f.ticks
216 316
When doing this, you must decide whether to allow the speed to be adjusted. If you do, then it must be taken into account in the calculations for the methods:
calcWhen()
, fromParentTicks()
and toParentTicks()
.
Functions¶
measurePrecision - estimate measurement precision of a clock¶
-
dvbcss.clock.
measurePrecision
(clock, sampleSize=10000)[source]¶ Do a very rough experiment to work out the precision of the provided clock.
Works by empirically looking for the smallest observable difference in the tick count.
Parameters: - clock – (:class:dvbcss.clock.ClockBase) Clock to measure
- sampleSize – (int) Number of iterations (sample size) to estimate the precision over
Returns: (float) estimate of clock measurement precision (in seconds)
Classes¶
ClockBase - base class for clocks¶
-
class
dvbcss.clock.
ClockBase
(**kwargs)[source]¶ Base class for all clock classes.
By default, adjusting tickRate and speed are not permitted unless a subclass overrides and implements a property setter.
-
bind
(dependent)[source]¶ Bind for notification if this clock changes.
Parameters: dependent – When this clock changes, the notify()
method of this dependent will be called, passing a single argument that is this clock.
-
calcWhen
(ticksWhen)[source]¶ Return: “when” in terms of the underlying clock behind the root clock implementation (e.g. monotonic_time.time()
in the case ofSysClock
)This is a stub for this method. Sub-classes should implement it.
-
fromParentTicks
(ticks)[source]¶ This is a stub for this method. Sub-classes should implement it.
Method to convert from a tick value for this clock’s parent to the equivalent tick value (representing the same point in time) for this clock.
Implementations should use the parent clock’s
tickRate
andspeed
properties when performing the conversion.Returns: The specified tick value for the parent clock converted to the timescale of this clock. Throws StopIteration: if this clock has no parent
-
getEffectiveSpeed
()[source]¶ Returns the ‘effective speed’ of this clock.
This is equal to multiplying together the speed properties of this clock and all of the parents up to the root clock.
-
getParent
()[source]¶ This is a stub for this method. Sub-classes should implement it.
Returns: ClockBase
representing the immediate parent of this clock, or None if it is a root clock.
-
nanos
[source]¶ (read only) The tick count of this clock, but converted to units of nanoseconds, based on the current tick rate (but ignoring the speed property).
-
nanosToTicks
(nanos)[source]¶ Convert the supplied nanosecond to number of ticks given the current tick rate of this clock (but ignoring the speed property).
Parameters: nanos – nanoseconds value Returns: number of ticks equivalent to the supplied nanosecond value
-
notify
(cause)[source]¶ Call to notify this clock that the clock on which it is based (its parent) has changed relative to the underlying timing source.
Parameters: cause – The clock that is calling this method. Will notify all dependents of this clock (entities that have registered themselves by calling
bind()
).
-
speed
[source]¶ (read/write
float
) The speed at which the clock is running. Does not change the reported tickRate value, but will affect how ticks are calculated from parent clock ticks. Default = 1.0 = normal tick rate.
-
tickRate
[source]¶ (read only)The tick rate (in ticks per second) of this clock.
This is a stub for this method. Sub-classes should implement it.
-
ticks
[source]¶ (read only) The tick count for this clock.
This is a stub for this method. Sub-classes should implement it.
-
toOtherClockTicks
(otherClock, ticks)[source]¶ Converts a tick value for this clock into a tick value corresponding to the timescale of another clock.
Parameters: - otherClock – A
clock
object representing another clock. - ticks – A time (tick value) for this clock
Returns: The tick value of the otherClock that represents the same moment in time.
Throws NoCommonClock: if there is no common ancestor clock (meaning it is not possible to convert
- otherClock – A
-
toParentTicks
(ticks)[source]¶ This is a stub for this method. Sub-classes should implement it.
Method to convert from a tick value for this clock to the equivalent tick value (representing the same point in time) for the parent clock.
Implementations should use the parent clock’s
tickRate
andspeed
properties when performing the conversion.Returns: The specified tick value of this clock converted to the timescale of the parent clock. Throws StopIteration: if this clock has no parent
-
SysClock - Clock based on time module¶
-
class
dvbcss.clock.
SysClock
(tickRate=1000000, **kwargs)[source]¶ A clock based directly on the standard library timer function
monotonic_time.time()
. Returns integer ticks when itsticks
property is queried.The default tick rate is 1 million ticks per second, but a different tick rate can be chosen during initialisation.
It is not permitted to change the
tickRate
orspeed
property of this clock because it directly represents a system clock.Parameters: tickRate – (int) tick rate for this clock (in ticks per second) -
bind
(dependent)[source]¶ Bind for notification if this clock changes.
Parameters: dependent – When this clock changes, the notify()
method of this dependent will be called, passing a single argument that is this clock.
-
calcWhen
(ticksWhen)[source]¶ Return: “when” in terms of the underlying clock behind the root clock implementation (e.g. monotonic_time.time()
in the case ofSysClock
)(Documentation inherited from
ClockBase
)
-
fromParentTicks
(ticks)[source]¶ Method to convert from a tick value for this clock’s parent to the equivalent tick value (representing the same point in time) for this clock.
Implementations should use the parent clock’s
tickRate
andspeed
properties when performing the conversion.returns: The specified tick value for the parent clock converted to the timescale of this clock. throws StopIteration: if this clock has no parent (Documentation inherited from
ClockBase
)
-
getEffectiveSpeed
()[source]¶ Returns the ‘effective speed’ of this clock.
This is equal to multiplying together the speed properties of this clock and all of the parents up to the root clock.
-
getParent
()[source]¶ returns: ClockBase
representing the immediate parent of this clock, or None if it is a root clock.(Documentation inherited from
ClockBase
)
-
nanos
[source]¶ (read only) The tick count of this clock, but converted to units of nanoseconds, based on the current tick rate (but ignoring the speed property).
-
nanosToTicks
(nanos)[source]¶ Convert the supplied nanosecond to number of ticks given the current tick rate of this clock (but ignoring the speed property).
Parameters: nanos – nanoseconds value Returns: number of ticks equivalent to the supplied nanosecond value
-
notify
(cause)[source]¶ Call to notify this clock that the clock on which it is based (its parent) has changed relative to the underlying timing source.
Parameters: cause – The clock that is calling this method. Will notify all dependents of this clock (entities that have registered themselves by calling
bind()
).
-
speed
[source]¶ (read/write
float
) The speed at which the clock is running. Does not change the reported tickRate value, but will affect how ticks are calculated from parent clock ticks. Default = 1.0 = normal tick rate.
-
tickRate
[source]¶ (read only)The tick rate (in ticks per second) of this clock.
(Documentation inherited from
ClockBase
)
-
toOtherClockTicks
(otherClock, ticks)[source]¶ Converts a tick value for this clock into a tick value corresponding to the timescale of another clock.
Parameters: - otherClock – A
clock
object representing another clock. - ticks – A time (tick value) for this clock
Returns: The tick value of the otherClock that represents the same moment in time.
Throws NoCommonClock: if there is no common ancestor clock (meaning it is not possible to convert
- otherClock – A
-
toParentTicks
(ticks)[source]¶ Method to convert from a tick value for this clock to the equivalent tick value (representing the same point in time) for the parent clock.
Implementations should use the parent clock’s
tickRate
andspeed
properties when performing the conversion.returns: The specified tick value of this clock converted to the timescale of the parent clock. throws StopIteration: if this clock has no parent (Documentation inherited from
ClockBase
)
-
TunableClock - Clock with dynamically adjustable frequency and tick offset¶
-
class
dvbcss.clock.
TunableClock
(parentClock, tickRate, ticks=0, **kwargs)[source]¶ A clock whose tick offset and speed can be adjusted on the fly. Must be based on another clock.
Advancement of time of this clock is based on the tick count and rates reported by the supplied parent clock.
If you adjust the tickRate or speed, then the change is applied going forward from the moment it is made. E.g. if you are observing the rate of increase of the ticks property, then doubling the speed wil cause the ticks property to start increasing faster but will not cause it to suddenly jump value.
Note
The maths to calculate and convert tick values will be performed, by default, as integer maths unless the parameters controlling the clock (tickRate etc) are floating point, or the ticks property of the parent clock supplies floating point values.
Parameters: - parentClock – The parent clock for this clock.
- tickRate – The tick rate (ticks per second) for this clock.
- ticks – The starting tick value for this clock.
The specified starting tick value applies from the moment this object is initialised.
-
bind
(dependent)[source]¶ Bind for notification if this clock changes.
Parameters: dependent – When this clock changes, the notify()
method of this dependent will be called, passing a single argument that is this clock.
-
calcWhen
(ticksWhen)[source]¶ Return: “when” in terms of the underlying clock behind the root clock implementation (e.g. monotonic_time.time()
in the case ofSysClock
)(Documentation inherited from
ClockBase
)
-
fromParentTicks
(ticks)[source]¶ Method to convert from a tick value for this clock’s parent to the equivalent tick value (representing the same point in time) for this clock.
Implementations should use the parent clock’s
tickRate
andspeed
properties when performing the conversion.returns: The specified tick value for the parent clock converted to the timescale of this clock. throws StopIteration: if this clock has no parent (Documentation inherited from
ClockBase
)
-
getEffectiveSpeed
()[source]¶ Returns the ‘effective speed’ of this clock.
This is equal to multiplying together the speed properties of this clock and all of the parents up to the root clock.
-
getParent
()[source]¶ returns: ClockBase
representing the immediate parent of this clock, or None if it is a root clock.(Documentation inherited from
ClockBase
)
-
nanos
[source]¶ (read only) The tick count of this clock, but converted to units of nanoseconds, based on the current tick rate (but ignoring the speed property).
-
nanosToTicks
(nanos)[source]¶ Convert the supplied nanosecond to number of ticks given the current tick rate of this clock (but ignoring the speed property).
Parameters: nanos – nanoseconds value Returns: number of ticks equivalent to the supplied nanosecond value
-
notify
(cause)[source]¶ Call to notify this clock that the clock on which it is based (its parent) has changed relative to the underlying timing source.
Parameters: cause – The clock that is calling this method. Will notify all dependents of this clock (entities that have registered themselves by calling
bind()
).
-
slew
[source]¶ This is an alternative method of querying or adjusting the speed property.
The slew (in ticks per second) currently applied to this clock.
Setting this property will set the speed property to correspond to the specified slew.
For example: for a clock with tickRate of 100, then a slew of -25 corresponds to a speed of 0.75
-
speed
[source]¶ - (read/write
float
) The speed at which the clock is running. - Does not change the reported tickRate value, but will affect how ticks are calculated from parent clock ticks. Default = 1.0 = normal tick rate.
(Documentation inherited from
ClockBase
)- (read/write
-
tickRate
[source]¶ Read or change the tick rate (in ticks per second) of this clock. The value read is not affected by the value of the
speed
property.
-
toOtherClockTicks
(otherClock, ticks)[source]¶ Converts a tick value for this clock into a tick value corresponding to the timescale of another clock.
Parameters: - otherClock – A
clock
object representing another clock. - ticks – A time (tick value) for this clock
Returns: The tick value of the otherClock that represents the same moment in time.
Throws NoCommonClock: if there is no common ancestor clock (meaning it is not possible to convert
- otherClock – A
-
toParentTicks
(ticks)[source]¶ Method to convert from a tick value for this clock to the equivalent tick value (representing the same point in time) for the parent clock.
Implementations should use the parent clock’s
tickRate
andspeed
properties when performing the conversion.returns: The specified tick value of this clock converted to the timescale of the parent clock. throws StopIteration: if this clock has no parent (Documentation inherited from
ClockBase
)