refclock: add option to filter wrong pulse edges

Add width option to the refclock directive to set expected width of
pulses in a PPS signal. The width adds a limit for the maximum offset
and root distance in order to reject PPS samples from wrong events, e.g.
PHCs which cannot be configured to timestamp only rising of falling
edges.
This commit is contained in:
Miroslav Lichvar 2017-05-19 18:51:03 +02:00
parent eceb8d9937
commit 1ca099473f
3 changed files with 36 additions and 1 deletions

7
conf.c
View file

@ -676,7 +676,7 @@ parse_refclock(char *line)
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options; int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
int max_lock_age, pps_forced; int max_lock_age, pps_forced;
uint32_t ref_id, lock_ref_id; uint32_t ref_id, lock_ref_id;
double offset, delay, precision, max_dispersion; double offset, delay, precision, max_dispersion, pulse_width;
char *p, *cmd, *name, *param; char *p, *cmd, *name, *param;
unsigned char ref[5]; unsigned char ref[5];
RefclockParameters *refclock; RefclockParameters *refclock;
@ -693,6 +693,7 @@ parse_refclock(char *line)
delay = 1e-9; delay = 1e-9;
precision = 0.0; precision = 0.0;
max_dispersion = 0.0; max_dispersion = 0.0;
pulse_width = 0.0;
ref_id = 0; ref_id = 0;
max_lock_age = 2; max_lock_age = 2;
lock_ref_id = 0; lock_ref_id = 0;
@ -766,6 +767,9 @@ parse_refclock(char *line)
} else if (!strcasecmp(cmd, "maxdispersion")) { } else if (!strcasecmp(cmd, "maxdispersion")) {
if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1) if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1)
break; break;
} else if (!strcasecmp(cmd, "width")) {
if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
break;
} else if (!strcasecmp(cmd, "noselect")) { } else if (!strcasecmp(cmd, "noselect")) {
n = 0; n = 0;
sel_options |= SRC_SELECT_NOSELECT; sel_options |= SRC_SELECT_NOSELECT;
@ -804,6 +808,7 @@ parse_refclock(char *line)
refclock->delay = delay; refclock->delay = delay;
refclock->precision = precision; refclock->precision = precision;
refclock->max_dispersion = max_dispersion; refclock->max_dispersion = max_dispersion;
refclock->pulse_width = pulse_width;
refclock->ref_id = ref_id; refclock->ref_id = ref_id;
refclock->max_lock_age = max_lock_age; refclock->max_lock_age = max_lock_age;
refclock->lock_ref_id = lock_ref_id; refclock->lock_ref_id = lock_ref_id;

View file

@ -85,6 +85,7 @@ struct RCL_Instance_Record {
double offset; double offset;
double delay; double delay;
double precision; double precision;
double pulse_width;
SCH_TimeoutID timeout_id; SCH_TimeoutID timeout_id;
SRC_Instance source; SRC_Instance source;
}; };
@ -208,6 +209,7 @@ RCL_AddRefclock(RefclockParameters *params)
inst->delay = params->delay; inst->delay = params->delay;
if (params->precision > 0.0) if (params->precision > 0.0)
inst->precision = params->precision; inst->precision = params->precision;
inst->pulse_width = params->pulse_width;
inst->timeout_id = -1; inst->timeout_id = -1;
inst->source = NULL; inst->source = NULL;
@ -415,6 +417,27 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
return RCL_AddCookedPulse(instance, &cooked_time, second, dispersion, correction); return RCL_AddCookedPulse(instance, &cooked_time, second, dispersion, correction);
} }
static int
check_pulse_edge(RCL_Instance instance, double offset, double distance)
{
double max_error;
if (instance->pulse_width <= 0.0)
return 1;
max_error = 1.0 / instance->pps_rate - instance->pulse_width;
max_error = MIN(instance->pulse_width, max_error);
max_error *= 0.5;
if (fabs(offset) > max_error || distance > max_error) {
DEBUG_LOG("refclock pulse ignored offset=%.9f distance=%.9f max_error=%.9f",
offset, distance, max_error);
return 0;
}
return 1;
}
int int
RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time, RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
double second, double dispersion, double raw_correction) double second, double dispersion, double raw_correction)
@ -476,6 +499,9 @@ RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
return 0; return 0;
} }
if (!check_pulse_edge(instance, ref_offset - offset, 0.0))
return 0;
leap = lock_refclock->leap_status; leap = lock_refclock->leap_status;
DEBUG_LOG("refclock pulse offset=%.9f offdiff=%.9f samplediff=%.9f", DEBUG_LOG("refclock pulse offset=%.9f offdiff=%.9f samplediff=%.9f",
@ -500,6 +526,9 @@ RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
filter_reset(&instance->filter); filter_reset(&instance->filter);
return 0; return 0;
} }
if (!check_pulse_edge(instance, offset, distance))
return 0;
} }
filter_add_sample(&instance->filter, cooked_time, offset, dispersion); filter_add_sample(&instance->filter, cooked_time, offset, dispersion);

View file

@ -49,6 +49,7 @@ typedef struct {
double delay; double delay;
double precision; double precision;
double max_dispersion; double max_dispersion;
double pulse_width;
} RefclockParameters; } RefclockParameters;
typedef struct RCL_Instance_Record *RCL_Instance; typedef struct RCL_Instance_Record *RCL_Instance;