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).
This commit is contained in:
parent
7fb0598b50
commit
fc1514db04
3 changed files with 50 additions and 17 deletions
|
@ -2287,9 +2287,11 @@ driver name and the number of the refclock are used as refid. Each
|
||||||
refclock has to use an unique refid.
|
refclock has to use an unique refid.
|
||||||
@item filter
|
@item filter
|
||||||
This option sets the length of the median filter which is used to
|
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
|
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
|
@item rate
|
||||||
PPS signal frequency (in Hz). This option only controls how the
|
PPS signal frequency (in Hz). This option only controls how the
|
||||||
received pulses are aligned. To actually receive more than one
|
received pulses are aligned. To actually receive more than one
|
||||||
|
|
2
conf.c
2
conf.c
|
@ -448,7 +448,7 @@ parse_refclock(const char *line)
|
||||||
|
|
||||||
poll = 4;
|
poll = 4;
|
||||||
dpoll = 0;
|
dpoll = 0;
|
||||||
filter_length = 15;
|
filter_length = 64;
|
||||||
pps_rate = 0;
|
pps_rate = 0;
|
||||||
offset = 0.0;
|
offset = 0.0;
|
||||||
delay = 1e-9;
|
delay = 1e-9;
|
||||||
|
|
59
refclock.c
59
refclock.c
|
@ -210,9 +210,6 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||||
inst->pps_rate = 0;
|
inst->pps_rate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst->driver_poll > inst->poll)
|
|
||||||
inst->driver_poll = inst->poll;
|
|
||||||
|
|
||||||
if (params->ref_id)
|
if (params->ref_id)
|
||||||
inst->ref_id = params->ref_id;
|
inst->ref_id = params->ref_id;
|
||||||
else {
|
else {
|
||||||
|
@ -222,6 +219,22 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||||
inst->ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
|
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)
|
||||||
if (!inst->driver->init(inst)) {
|
if (!inst->driver->init(inst)) {
|
||||||
LOG_FATAL(LOGF_Refclock, "refclock %s initialisation failed", params->driver_name);
|
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)
|
if (filter->used < 1)
|
||||||
return 0;
|
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;
|
selected = filter->selected;
|
||||||
|
|
||||||
for (i = 1, min_dispersion = filter->samples[0].dispersion; i < filter->used; i++) {
|
if (filter->used > 4) {
|
||||||
if (min_dispersion > filter->samples[i].dispersion)
|
/* select samples with dispersion better than 1.5 * minimum */
|
||||||
min_dispersion = filter->samples[i].dispersion;
|
|
||||||
|
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 */
|
if (j < 4) {
|
||||||
for (i = j = 0; i < filter->used; i++) {
|
/* select all samples */
|
||||||
if (filter->samples[i].dispersion <= 1.5 * min_dispersion)
|
|
||||||
selected[j++] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(j > 0);
|
for (j = 0; j < filter->used; j++)
|
||||||
|
selected[j] = j;
|
||||||
|
}
|
||||||
|
|
||||||
/* and sort their indices by offset */
|
/* and sort their indices by offset */
|
||||||
tmp_sorted_array = filter->samples;
|
tmp_sorted_array = filter->samples;
|
||||||
qsort(selected, j, sizeof (int), sample_compare);
|
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) {
|
if (j > 2) {
|
||||||
from = (j + 2) / 4;
|
from = j / 5;
|
||||||
|
if (from < 1)
|
||||||
|
from = 1;
|
||||||
to = j - from;
|
to = j - from;
|
||||||
} else {
|
} else {
|
||||||
from = 0;
|
from = 0;
|
||||||
|
|
Loading…
Reference in a new issue