diff --git a/chrony.texi.in b/chrony.texi.in index 6503ca8..47c6079 100644 --- a/chrony.texi.in +++ b/chrony.texi.in @@ -2599,6 +2599,10 @@ sources. The default is 1e-9 (1 nanosecond). @item precision Refclock precision (in seconds). The default is 1e-6 (1 microsecond) for SHM refclock, and 1e-9 (1 nanosecond) for SOCK, PPS and PHC refclocks. +@item maxdispersion +Maximum allowed dispersion for filtered samples (in seconds). Samples +with larger estimated dispersion are ignored. By default, this limit +is disabled. @item prefer Prefer this source over sources without prefer option. @item noselect diff --git a/conf.c b/conf.c index 50ed760..03666eb 100644 --- a/conf.c +++ b/conf.c @@ -593,7 +593,7 @@ parse_refclock(char *line) { int i, n, poll, dpoll, filter_length, pps_rate; uint32_t ref_id, lock_ref_id; - double offset, delay, precision; + double offset, delay, precision, max_dispersion; char *p, *cmd, *name, *param; unsigned char ref[5]; SRC_SelectOption sel_option; @@ -609,6 +609,7 @@ parse_refclock(char *line) offset = 0.0; delay = 1e-9; precision = 0.0; + max_dispersion = 0.0; ref_id = 0; lock_ref_id = 0; sel_option = SRC_SelectNormal; @@ -667,6 +668,9 @@ parse_refclock(char *line) } else if (!strcasecmp(cmd, "precision")) { if (sscanf(line, "%lf%n", &precision, &n) != 1) break; + } else if (!strcasecmp(cmd, "maxdispersion")) { + if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1) + break; } else if (!strcasecmp(cmd, "noselect")) { n = 0; sel_option = SRC_SelectNoselect; @@ -693,6 +697,7 @@ parse_refclock(char *line) refclock_sources[i].offset = offset; refclock_sources[i].delay = delay; refclock_sources[i].precision = precision; + refclock_sources[i].max_dispersion = max_dispersion; refclock_sources[i].sel_option = sel_option; refclock_sources[i].ref_id = ref_id; refclock_sources[i].lock_ref_id = lock_ref_id; diff --git a/refclock.c b/refclock.c index dfd2b69..0cd4754 100644 --- a/refclock.c +++ b/refclock.c @@ -57,6 +57,7 @@ struct MedianFilter { int last; int avg_var_n; double avg_var; + double max_var; struct FilterSample *samples; int *selected; double *x_data; @@ -100,7 +101,7 @@ static void slew_samples(struct timeval *raw, struct timeval *cooked, double dfr static void add_dispersion(double dispersion, void *anything); static void log_sample(RCL_Instance instance, struct timeval *sample_time, int filtered, int pulse, double raw_offset, double cooked_offset, double dispersion); -static void filter_init(struct MedianFilter *filter, int length); +static void filter_init(struct MedianFilter *filter, int length, double max_dispersion); static void filter_fini(struct MedianFilter *filter); static void filter_reset(struct MedianFilter *filter); static double filter_get_avg_sample_dispersion(struct MedianFilter *filter); @@ -245,7 +246,7 @@ RCL_AddRefclock(RefclockParameters *params) return 0; } - filter_init(&inst->filter, params->filter_length); + filter_init(&inst->filter, params->filter_length, params->max_dispersion); inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL); @@ -622,7 +623,7 @@ log_sample(RCL_Instance instance, struct timeval *sample_time, int filtered, int } static void -filter_init(struct MedianFilter *filter, int length) +filter_init(struct MedianFilter *filter, int length, double max_dispersion) { if (length < 1) length = 1; @@ -634,6 +635,7 @@ filter_init(struct MedianFilter *filter, int length) /* set first estimate to system precision */ filter->avg_var_n = 0; filter->avg_var = LCL_GetSysPrecisionAsQuantum() * LCL_GetSysPrecisionAsQuantum(); + filter->max_var = max_dispersion * max_dispersion; filter->samples = MallocArray(struct FilterSample, filter->length); filter->selected = MallocArray(int, filter->length); filter->x_data = MallocArray(double, filter->length); @@ -861,6 +863,13 @@ filter_get_sample(struct MedianFilter *filter, struct timeval *sample_time, doub d = sqrt(var); } + /* drop the sample if variance is larger than allowed maximum */ + if (filter->max_var > 0.0 && var > filter->max_var) { + DEBUG_LOG(LOGF_Refclock, "filter dispersion too large disp=%.9f max=%.9f", + sqrt(var), sqrt(filter->max_var)); + return 0; + } + prev_avg_var = filter->avg_var; /* update exponential moving average of the variance */ diff --git a/refclock.h b/refclock.h index 5854139..b2122d3 100644 --- a/refclock.h +++ b/refclock.h @@ -43,6 +43,7 @@ typedef struct { double offset; double delay; double precision; + double max_dispersion; SRC_SelectOption sel_option; } RefclockParameters;