sourcestats: correct offsets with asymmetric network jitter
Estimate asymmetry of network jitter on the path to the source as a slope of offset against network delay in multiple linear regression. If the asymmetry is significant and its sign doesn't change frequently, the measured offsets (which are used later to estimate the offset and frequency of the clock) are corrected to correspond to the minimum network delay. This can significantly improve the accuracy and stability of the estimated offset and frequency.
This commit is contained in:
parent
9d9d6c30cf
commit
39f34eb674
1 changed files with 77 additions and 2 deletions
|
@ -50,6 +50,19 @@
|
|||
/* The minimum allowed skew */
|
||||
#define MIN_SKEW 1.0e-12
|
||||
|
||||
/* The asymmetry of network jitter when all jitter is in one direction */
|
||||
#define MAX_ASYMMETRY 0.5
|
||||
|
||||
/* The minimum estimated asymmetry that can activate the offset correction */
|
||||
#define MIN_ASYMMETRY 0.45
|
||||
|
||||
/* The minimum number of consecutive asymmetries with the same sign needed
|
||||
to activate the offset correction */
|
||||
#define MIN_ASYMMETRY_RUN 10
|
||||
|
||||
/* The maximum value of the counter */
|
||||
#define MAX_ASYMMETRY_RUN 1000
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static LOG_FileID logfileid;
|
||||
|
@ -97,6 +110,13 @@ struct SST_Stats_Record {
|
|||
/* Number of runs of the same sign amongst the residuals */
|
||||
int nruns;
|
||||
|
||||
/* Number of consecutive estimated asymmetries with the same sign.
|
||||
The sign of the number encodes the sign of the asymmetry. */
|
||||
int asymmetry_run;
|
||||
|
||||
/* This is the latest estimated asymmetry of network jitter */
|
||||
double asymmetry;
|
||||
|
||||
/* This value contains the estimated frequency. This is the number
|
||||
of seconds that the local clock gains relative to the reference
|
||||
source per unit local time. (Positive => local clock fast,
|
||||
|
@ -218,6 +238,8 @@ SST_ResetInstance(SST_Stats inst)
|
|||
inst->offset_time.tv_usec = 0;
|
||||
inst->variance = 16.0;
|
||||
inst->nruns = 0;
|
||||
inst->asymmetry_run = 0;
|
||||
inst->asymmetry = 0.0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -385,6 +407,56 @@ find_min_delay_sample(SST_Stats inst)
|
|||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function estimates asymmetry of network jitter on the path to the
|
||||
source as a slope of offset against network delay in multiple linear
|
||||
regression. If the asymmetry is significant and its sign doesn't change
|
||||
frequently, the measured offsets (which are used later to estimate the
|
||||
offset and frequency of the clock) are corrected to correspond to the
|
||||
minimum network delay. This can significantly improve the accuracy and
|
||||
stability of the estimated offset and frequency. */
|
||||
|
||||
static void
|
||||
correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
|
||||
{
|
||||
double asymmetry, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
|
||||
int i, n;
|
||||
|
||||
/* Don't try to estimate the asymmetry with reference clocks */
|
||||
if (!inst->ip_addr)
|
||||
return;
|
||||
|
||||
n = inst->runs_samples + inst->n_samples;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] -
|
||||
inst->peer_delays[inst->min_delay_sample];
|
||||
|
||||
/* Reset the counter when the regression fails or the sign changes */
|
||||
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &asymmetry) ||
|
||||
asymmetry * inst->asymmetry_run < 0.0) {
|
||||
inst->asymmetry_run = 0;
|
||||
inst->asymmetry = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
asymmetry = CLAMP(-MAX_ASYMMETRY, asymmetry, MAX_ASYMMETRY);
|
||||
|
||||
if (asymmetry <= -MIN_ASYMMETRY && inst->asymmetry_run > -MAX_ASYMMETRY_RUN)
|
||||
inst->asymmetry_run--;
|
||||
else if (asymmetry >= MIN_ASYMMETRY && inst->asymmetry_run < MAX_ASYMMETRY_RUN)
|
||||
inst->asymmetry_run++;
|
||||
|
||||
if (abs(inst->asymmetry_run) < MIN_ASYMMETRY_RUN)
|
||||
return;
|
||||
|
||||
/* Correct the offsets */
|
||||
for (i = 0; i < n; i++)
|
||||
offsets[i] -= asymmetry * delays[i];
|
||||
|
||||
inst->asymmetry = asymmetry;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This defines the assumed ratio between the standard deviation of
|
||||
|
@ -446,6 +518,8 @@ SST_DoNewRegression(SST_Stats inst)
|
|||
}
|
||||
}
|
||||
|
||||
correct_asymmetry(inst, times_back, offsets);
|
||||
|
||||
inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples,
|
||||
offsets + inst->runs_samples, weights,
|
||||
inst->n_samples, inst->runs_samples,
|
||||
|
@ -472,9 +546,10 @@ SST_DoNewRegression(SST_Stats inst)
|
|||
|
||||
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "off=%e freq=%e skew=%e n=%d bs=%d runs=%d",
|
||||
DEBUG_LOG(LOGF_SourceStats, "off=%e freq=%e skew=%e n=%d bs=%d runs=%d asym=%f arun=%d",
|
||||
inst->estimated_offset, inst->estimated_frequency, inst->skew,
|
||||
inst->n_samples, best_start, inst->nruns);
|
||||
inst->n_samples, best_start, inst->nruns,
|
||||
inst->asymmetry, inst->asymmetry_run);
|
||||
|
||||
if (logfileid != -1) {
|
||||
LOG_FileWrite(logfileid, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d",
|
||||
|
|
Loading…
Reference in a new issue