Skip to content

Commit

Permalink
variance shenanigans
Browse files Browse the repository at this point in the history
  • Loading branch information
wiedehopf committed Dec 5, 2020
1 parent 5802c61 commit 97bac3e
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 18 deletions.
38 changes: 27 additions & 11 deletions mlat/server/clocknorm.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import pygraph.classes.graph
import pygraph.algorithms.minmax
import time

from mlat import profile

Expand All @@ -37,7 +38,7 @@ def _identity_predict(x):
return x


def _make_predictors(clocktracker, station0, station1):
def _make_predictors(clocktracker, station0, station1, now):
"""Return a tuple of predictors (p_01, p_10) where:
p_01 will predict a station1 timestamp given a station0 timestamp
Expand All @@ -46,7 +47,6 @@ def _make_predictors(clocktracker, station0, station1):
Returns None if no suitable clock sync model is available for
this pair of stations.
"""

if station0 is station1:
return None

Expand All @@ -58,18 +58,32 @@ def _make_predictors(clocktracker, station0, station1):
predictor = _Predictor(_identity_predict, station0.clock.jitter ** 2 + station1.clock.jitter ** 2)
return (predictor, predictor)

pairing = None

if station0 < station1:
pairing = clocktracker.clock_pairs.get((station0, station1))
if pairing is None or not pairing.valid:
return None
return (_Predictor(pairing.predict_peer, pairing.variance),
_Predictor(pairing.predict_base, pairing.variance))
else:
pairing = clocktracker.clock_pairs.get((station1, station0))
if pairing is None or not pairing.valid:
return None
return (_Predictor(pairing.predict_base, pairing.variance),
_Predictor(pairing.predict_peer, pairing.variance))

if pairing is None or not pairing.valid:
return None

variance = pairing.variance
stale = now - pairing.updated

# increase variance for stale pairings
variance *= 1 + stale / 12

# increase variance for pairing with fewer sync points
if pairing.n < 10:
variance *= 1 + (10 - pairing.n) / 10

if station0 < station1:
return (_Predictor(pairing.predict_peer, variance),
_Predictor(pairing.predict_base, variance))
else:
return (_Predictor(pairing.predict_base, variance),
_Predictor(pairing.predict_peer, variance))


def _label_heights(g, node, heights):
Expand Down Expand Up @@ -175,11 +189,13 @@ def normalize(clocktracker, timestamp_map):
# also build a map of predictor objects corresponding to the
# edges for later use

now = time.monotonic()

predictor_map = {}
for si in timestamp_map.keys():
for sj in timestamp_map.keys():
if si < sj:
predictors = _make_predictors(clocktracker, si, sj)
predictors = _make_predictors(clocktracker, si, sj, now)
if predictors:
predictor_map[(si, sj)] = predictors[0]
predictor_map[(sj, si)] = predictors[1]
Expand Down
12 changes: 5 additions & 7 deletions mlat/server/clocksync.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,15 @@ def is_new(self, base_ts):
return bool(self.n == 0 or self.ts_base[-1] < base_ts)

def updateVars(self):
"""Variance of recent predictions of the sync point versus the actual sync point."""
if self.n == 0:
self.variance = None
self.error = None
else:
"""Variance of recent predictions of the sync point versus the actual sync point."""
self.variance = self.var_sum / self.n

"""Standard error of recent predictions."""
if self.n == 0:
self.error = None
else:
self.error = math.sqrt(self.var_sum / self.n)
"""Standard error of recent predictions."""
self.error = math.sqrt(self.variance)

def check_valid(self, now):
"""True if this pairing is usable for clock syncronization."""
Expand Down Expand Up @@ -142,7 +140,7 @@ def update(self, address, base_ts, peer_ts, base_interval, peer_interval, now):
prediction = self.predict_peer(base_ts)
prediction_error = (prediction - peer_ts) / self.peer_clock.freq

if abs(prediction_error) > self.outlier_threshold and abs(prediction_error) > self.error * 2.5 : # 2.5 sigma
if abs(prediction_error) > self.outlier_threshold and abs(prediction_error) > self.error * 3 : # 3 sigma
self.outliers += 1
if self.outliers < 5:
# don't accept this one
Expand Down

0 comments on commit 97bac3e

Please sign in to comment.