Introduce offset correction rate
We want to correct the offset quickly, but we also want to keep the frequency error caused by the correction itself low. Define correction rate as the area of the region bounded by the graph of offset corrected in time. Set the rate so that the time needed to correct an offset equal to the current sourcestats stddev will be equal to the update interval (assuming linear adjustment). The offset and the time needed to make the correction are inversely proportional. This is only a suggestion and it's up to the system driver how the adjustment will be executed.
This commit is contained in:
parent
79e5f2be13
commit
c7d0232bb1
13 changed files with 40 additions and 20 deletions
|
@ -708,7 +708,7 @@ process_measurements(void)
|
||||||
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)",
|
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)",
|
||||||
fabs(estimated_offset),
|
fabs(estimated_offset),
|
||||||
(estimated_offset >= 0) ? "fast" : "slow");
|
(estimated_offset >= 0) ? "fast" : "slow");
|
||||||
LCL_AccumulateOffset(estimated_offset);
|
LCL_AccumulateOffset(estimated_offset, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
2
cmdmon.c
2
cmdmon.c
|
@ -1354,7 +1354,7 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||||
usec = (long)(ntohl(rx_message->data.doffset.usec));
|
usec = (long)(ntohl(rx_message->data.doffset.usec));
|
||||||
doffset = (double) sec + 1.0e-6 * (double) usec;
|
doffset = (double) sec + 1.0e-6 * (double) usec;
|
||||||
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
|
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
|
||||||
LCL_AccumulateOffset(doffset);
|
LCL_AccumulateOffset(doffset, 0.0);
|
||||||
tx_message->status = htons(STT_SUCCESS);
|
tx_message->status = htons(STT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
local.c
10
local.c
|
@ -443,7 +443,7 @@ LCL_AccumulateDeltaFrequency(double dfreq)
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
LCL_AccumulateOffset(double offset)
|
LCL_AccumulateOffset(double offset, double corr_rate)
|
||||||
{
|
{
|
||||||
ChangeListEntry *ptr;
|
ChangeListEntry *ptr;
|
||||||
struct timeval raw, cooked;
|
struct timeval raw, cooked;
|
||||||
|
@ -454,7 +454,7 @@ LCL_AccumulateOffset(double offset)
|
||||||
LCL_ReadRawTime(&raw);
|
LCL_ReadRawTime(&raw);
|
||||||
LCL_CookTime(&raw, &cooked, NULL);
|
LCL_CookTime(&raw, &cooked, NULL);
|
||||||
|
|
||||||
(*drv_accrue_offset)(offset);
|
(*drv_accrue_offset)(offset, corr_rate);
|
||||||
|
|
||||||
/* Dispatch to all handlers */
|
/* Dispatch to all handlers */
|
||||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||||
|
@ -505,7 +505,7 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
|
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||||
{
|
{
|
||||||
ChangeListEntry *ptr;
|
ChangeListEntry *ptr;
|
||||||
struct timeval raw, cooked;
|
struct timeval raw, cooked;
|
||||||
|
@ -532,7 +532,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
|
||||||
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
|
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
|
||||||
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 + old_freq_ppm);
|
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 + old_freq_ppm);
|
||||||
|
|
||||||
(*drv_accrue_offset)(doffset);
|
(*drv_accrue_offset)(doffset, corr_rate);
|
||||||
|
|
||||||
/* Dispatch to all handlers */
|
/* Dispatch to all handlers */
|
||||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||||
|
@ -598,7 +598,7 @@ LCL_MakeStep(double threshold)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Cancel remaining slew and make the step */
|
/* Cancel remaining slew and make the step */
|
||||||
LCL_AccumulateOffset(correction);
|
LCL_AccumulateOffset(correction, 0.0);
|
||||||
LCL_ApplyStepOffset(-correction);
|
LCL_ApplyStepOffset(-correction);
|
||||||
|
|
||||||
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction);
|
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction);
|
||||||
|
|
7
local.h
7
local.h
|
@ -138,9 +138,10 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
|
||||||
/* Routine to apply an offset (in seconds) to the local clock. The
|
/* Routine to apply an offset (in seconds) to the local clock. The
|
||||||
argument should be positive to move the clock backwards (i.e. the
|
argument should be positive to move the clock backwards (i.e. the
|
||||||
local clock is currently fast of true time), or negative to move it
|
local clock is currently fast of true time), or negative to move it
|
||||||
forwards (i.e. it is currently slow of true time). */
|
forwards (i.e. it is currently slow of true time). Provided is also
|
||||||
|
a suggested correction rate (correction time * offset). */
|
||||||
|
|
||||||
extern void LCL_AccumulateOffset(double offset);
|
extern void LCL_AccumulateOffset(double offset, double corr_rate);
|
||||||
|
|
||||||
/* Routine to apply an immediate offset by doing a sudden step if
|
/* Routine to apply an immediate offset by doing a sudden step if
|
||||||
possible. (Intended for use after an initial estimate of offset has
|
possible. (Intended for use after an initial estimate of offset has
|
||||||
|
@ -158,7 +159,7 @@ extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cook
|
||||||
|
|
||||||
/* Perform the combination of modifying the frequency and applying
|
/* Perform the combination of modifying the frequency and applying
|
||||||
a slew, in one easy step */
|
a slew, in one easy step */
|
||||||
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset);
|
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
||||||
|
|
||||||
/* Routine to read the system precision as a log to base 2 value. */
|
/* Routine to read the system precision as a log to base 2 value. */
|
||||||
extern int LCL_GetSysPrecisionAsLog(void);
|
extern int LCL_GetSysPrecisionAsLog(void);
|
||||||
|
|
5
localp.h
5
localp.h
|
@ -41,8 +41,9 @@ typedef double (*lcl_ReadFrequencyDriver)(void);
|
||||||
typedef double (*lcl_SetFrequencyDriver)(double freq_ppm);
|
typedef double (*lcl_SetFrequencyDriver)(double freq_ppm);
|
||||||
|
|
||||||
/* System driver to accrue an offset. A positive argument means slew
|
/* System driver to accrue an offset. A positive argument means slew
|
||||||
the clock forwards. */
|
the clock forwards. The suggested correction rate of time to correct the
|
||||||
typedef void (*lcl_AccrueOffsetDriver)(double offset);
|
offset is given in 'corr_rate'. */
|
||||||
|
typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
|
||||||
|
|
||||||
/* System driver to apply a step offset. A positive argument means step
|
/* System driver to apply a step offset. A positive argument means step
|
||||||
the clock forwards. */
|
the clock forwards. */
|
||||||
|
|
22
reference.c
22
reference.c
|
@ -541,6 +541,7 @@ REF_SetReference(int stratum,
|
||||||
IPAddr *ref_ip,
|
IPAddr *ref_ip,
|
||||||
struct timeval *ref_time,
|
struct timeval *ref_time,
|
||||||
double offset,
|
double offset,
|
||||||
|
double offset_sd,
|
||||||
double frequency,
|
double frequency,
|
||||||
double skew,
|
double skew,
|
||||||
double root_delay,
|
double root_delay,
|
||||||
|
@ -556,6 +557,7 @@ REF_SetReference(int stratum,
|
||||||
double abs_freq_ppm;
|
double abs_freq_ppm;
|
||||||
double update_interval;
|
double update_interval;
|
||||||
double elapsed;
|
double elapsed;
|
||||||
|
double correction_rate;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
|
||||||
assert(initialised);
|
assert(initialised);
|
||||||
|
@ -611,6 +613,20 @@ REF_SetReference(int stratum,
|
||||||
}
|
}
|
||||||
last_ref_update = now;
|
last_ref_update = now;
|
||||||
|
|
||||||
|
/* We want to correct the offset quickly, but we also want to keep the
|
||||||
|
frequency error caused by the correction itself low.
|
||||||
|
|
||||||
|
Define correction rate as the area of the region bounded by the graph of
|
||||||
|
offset corrected in time. Set the rate so that the time needed to correct
|
||||||
|
an offset equal to the current sourcestats stddev will be equal to the
|
||||||
|
update interval (assuming linear adjustment). The offset and the
|
||||||
|
time needed to make the correction are inversely proportional.
|
||||||
|
|
||||||
|
This is only a suggestion and it's up to the system driver how the
|
||||||
|
adjustment will be executed. */
|
||||||
|
|
||||||
|
correction_rate = 0.5 * offset_sd * update_interval;
|
||||||
|
|
||||||
/* Eliminate updates that are based on totally unreliable frequency
|
/* Eliminate updates that are based on totally unreliable frequency
|
||||||
information */
|
information */
|
||||||
|
|
||||||
|
@ -645,7 +661,7 @@ REF_SetReference(int stratum,
|
||||||
our_residual_freq = new_freq - our_frequency;
|
our_residual_freq = new_freq - our_frequency;
|
||||||
|
|
||||||
maybe_log_offset(our_offset);
|
maybe_log_offset(our_offset);
|
||||||
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset);
|
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset, correction_rate);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -653,7 +669,7 @@ REF_SetReference(int stratum,
|
||||||
LOG(LOGS_INFO, LOGF_Reference, "Skew %f too large to track, offset=%f", skew, our_offset);
|
LOG(LOGS_INFO, LOGF_Reference, "Skew %f too large to track, offset=%f", skew, our_offset);
|
||||||
#endif
|
#endif
|
||||||
maybe_log_offset(our_offset);
|
maybe_log_offset(our_offset);
|
||||||
LCL_AccumulateOffset(our_offset);
|
LCL_AccumulateOffset(our_offset, correction_rate);
|
||||||
|
|
||||||
our_residual_freq = frequency;
|
our_residual_freq = frequency;
|
||||||
}
|
}
|
||||||
|
@ -714,7 +730,7 @@ REF_SetManualReference
|
||||||
our_residual_freq = 0.0;
|
our_residual_freq = 0.0;
|
||||||
|
|
||||||
maybe_log_offset(offset);
|
maybe_log_offset(offset);
|
||||||
LCL_AccumulateFrequencyAndOffset(frequency, offset);
|
LCL_AccumulateFrequencyAndOffset(frequency, offset, 0.0);
|
||||||
maybe_make_step();
|
maybe_make_step();
|
||||||
|
|
||||||
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||||
|
|
|
@ -109,6 +109,7 @@ extern void REF_SetReference
|
||||||
IPAddr *ref_ip,
|
IPAddr *ref_ip,
|
||||||
struct timeval *ref_time,
|
struct timeval *ref_time,
|
||||||
double offset,
|
double offset,
|
||||||
|
double offset_sd,
|
||||||
double frequency,
|
double frequency,
|
||||||
double skew,
|
double skew,
|
||||||
double root_delay,
|
double root_delay,
|
||||||
|
|
|
@ -664,7 +664,7 @@ handle_initial_trim(void)
|
||||||
sys_error_now = rtc_error_now - coef_seconds_fast;
|
sys_error_now = rtc_error_now - coef_seconds_fast;
|
||||||
|
|
||||||
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
|
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
|
||||||
LCL_AccumulateOffset(sys_error_now);
|
LCL_AccumulateOffset(sys_error_now, 0.0);
|
||||||
} else {
|
} else {
|
||||||
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
|
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
|
||||||
}
|
}
|
||||||
|
|
|
@ -857,6 +857,7 @@ SRC_SelectSource(uint32_t match_refid)
|
||||||
sources[selected_source_index]->ip_addr,
|
sources[selected_source_index]->ip_addr,
|
||||||
&ref_time,
|
&ref_time,
|
||||||
src_offset,
|
src_offset,
|
||||||
|
src_offset_sd,
|
||||||
src_frequency,
|
src_frequency,
|
||||||
src_skew,
|
src_skew,
|
||||||
src_root_delay,
|
src_root_delay,
|
||||||
|
|
|
@ -592,7 +592,7 @@ abort_slew(void)
|
||||||
time) */
|
time) */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
accrue_offset(double offset)
|
accrue_offset(double offset, double corr_rate)
|
||||||
{
|
{
|
||||||
/* Add the new offset to the register */
|
/* Add the new offset to the register */
|
||||||
offset_register += offset;
|
offset_register += offset;
|
||||||
|
|
|
@ -199,7 +199,7 @@ stop_adjust(void)
|
||||||
slew backwards */
|
slew backwards */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
accrue_offset(double offset)
|
accrue_offset(double offset, double corr_rate)
|
||||||
{
|
{
|
||||||
stop_adjust();
|
stop_adjust();
|
||||||
offset_register += offset;
|
offset_register += offset;
|
||||||
|
|
|
@ -212,7 +212,7 @@ stop_adjust(void)
|
||||||
slew backwards */
|
slew backwards */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
accrue_offset(double offset)
|
accrue_offset(double offset, double corr_rate)
|
||||||
{
|
{
|
||||||
stop_adjust();
|
stop_adjust();
|
||||||
offset_register += offset;
|
offset_register += offset;
|
||||||
|
|
|
@ -216,7 +216,7 @@ stop_adjust(void)
|
||||||
slew backwards */
|
slew backwards */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
accrue_offset(double offset)
|
accrue_offset(double offset, double corr_rate)
|
||||||
{
|
{
|
||||||
stop_adjust();
|
stop_adjust();
|
||||||
offset_register += offset;
|
offset_register += offset;
|
||||||
|
|
Loading…
Reference in a new issue