From fc1514db04e6d69dbf019ca15af9e2a908562293 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Wed, 24 Feb 2010 12:02:53 +0100 Subject: [PATCH] Adjust refclock filter parameters Drop only about 40 percent of samples, change default length to 64, require at least 4 samples between polls (or full filter for lengths below 4). --- chrony.texi | 6 ++++-- conf.c | 2 +- refclock.c | 59 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/chrony.texi b/chrony.texi index 60f2924..be6b946 100644 --- a/chrony.texi +++ b/chrony.texi @@ -2287,9 +2287,11 @@ driver name and the number of the refclock are used as refid. Each refclock has to use an unique refid. @item filter This option sets the length of the median filter which is used to -reduce noise. With each poll about half of the stored samples are +reduce noise. With each poll about 40 percent of the stored samples is discarded and one final sample is calculated as average of the -remaining samples. The default is 15. +remaining samples. If the length is 4 or above, at least 4 samples +have to be collected between polls. For lengths below 4, the filter +has to be full. The default is 64. @item rate PPS signal frequency (in Hz). This option only controls how the received pulses are aligned. To actually receive more than one diff --git a/conf.c b/conf.c index 88a6525..359c108 100644 --- a/conf.c +++ b/conf.c @@ -448,7 +448,7 @@ parse_refclock(const char *line) poll = 4; dpoll = 0; - filter_length = 15; + filter_length = 64; pps_rate = 0; offset = 0.0; delay = 1e-9; diff --git a/refclock.c b/refclock.c index 54e72ba..ad7cde9 100644 --- a/refclock.c +++ b/refclock.c @@ -210,9 +210,6 @@ RCL_AddRefclock(RefclockParameters *params) inst->pps_rate = 0; } - if (inst->driver_poll > inst->poll) - inst->driver_poll = inst->poll; - if (params->ref_id) inst->ref_id = params->ref_id; else { @@ -222,6 +219,22 @@ RCL_AddRefclock(RefclockParameters *params) inst->ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3]; } + if (inst->driver->poll) { + int max_samples; + + if (inst->driver_poll > inst->poll) + inst->driver_poll = inst->poll; + + max_samples = 1 << (inst->poll - inst->driver_poll); + if (max_samples < params->filter_length) { + if (max_samples < 4) { + LOG(LOGS_WARN, LOGF_Refclock, "Setting filter length for %s to %d", + UTI_RefidToString(inst->ref_id), max_samples); + } + params->filter_length = max_samples; + } + } + if (inst->driver->init) if (!inst->driver->init(inst)) { LOG_FATAL(LOGF_Refclock, "refclock %s initialisation failed", params->driver_name); @@ -691,28 +704,46 @@ filter_select_samples(struct MedianFilter *filter) if (filter->used < 1) return 0; + /* for lengths below 4 require full filter, + for 4 and above require at least 4 samples */ + if ((filter->length < 4 && filter->used != filter->length) || + (filter->length >= 4 && filter->used < 4)) + return 0; + selected = filter->selected; - for (i = 1, min_dispersion = filter->samples[0].dispersion; i < filter->used; i++) { - if (min_dispersion > filter->samples[i].dispersion) - min_dispersion = filter->samples[i].dispersion; + if (filter->used > 4) { + /* select samples with dispersion better than 1.5 * minimum */ + + for (i = 1, min_dispersion = filter->samples[0].dispersion; i < filter->used; i++) { + if (min_dispersion > filter->samples[i].dispersion) + min_dispersion = filter->samples[i].dispersion; + } + + for (i = j = 0; i < filter->used; i++) { + if (filter->samples[i].dispersion <= 1.5 * min_dispersion) + selected[j++] = i; + } + } else { + j = 0; } - /* select samples with dispersion better than 1.5 * minimum */ - for (i = j = 0; i < filter->used; i++) { - if (filter->samples[i].dispersion <= 1.5 * min_dispersion) - selected[j++] = i; - } + if (j < 4) { + /* select all samples */ - assert(j > 0); + for (j = 0; j < filter->used; j++) + selected[j] = j; + } /* and sort their indices by offset */ tmp_sorted_array = filter->samples; qsort(selected, j, sizeof (int), sample_compare); - /* select half of the samples closest to the median */ + /* select 60 percent of the samples closest to the median */ if (j > 2) { - from = (j + 2) / 4; + from = j / 5; + if (from < 1) + from = 1; to = j - from; } else { from = 0;