From c7d0232bb113c6ca86cd24f9e694c70bfc946ab2 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Mon, 5 Sep 2011 15:45:32 +0200 Subject: [PATCH] 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. --- acquire.c | 2 +- cmdmon.c | 2 +- local.c | 10 +++++----- local.h | 7 ++++--- localp.h | 5 +++-- reference.c | 22 +++++++++++++++++++--- reference.h | 1 + rtc_linux.c | 2 +- sources.c | 1 + sys_linux.c | 2 +- sys_netbsd.c | 2 +- sys_solaris.c | 2 +- sys_sunos.c | 2 +- 13 files changed, 40 insertions(+), 20 deletions(-) diff --git a/acquire.c b/acquire.c index 6b38fe3..250dca2 100644 --- a/acquire.c +++ b/acquire.c @@ -708,7 +708,7 @@ process_measurements(void) LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)", fabs(estimated_offset), (estimated_offset >= 0) ? "fast" : "slow"); - LCL_AccumulateOffset(estimated_offset); + LCL_AccumulateOffset(estimated_offset, 0.0); } } else { diff --git a/cmdmon.c b/cmdmon.c index 0baf86d..7810fef 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -1354,7 +1354,7 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message) usec = (long)(ntohl(rx_message->data.doffset.usec)); doffset = (double) sec + 1.0e-6 * (double) usec; 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); } diff --git a/local.c b/local.c index 12fecf4..b300cc6 100644 --- a/local.c +++ b/local.c @@ -443,7 +443,7 @@ LCL_AccumulateDeltaFrequency(double dfreq) /* ================================================== */ void -LCL_AccumulateOffset(double offset) +LCL_AccumulateOffset(double offset, double corr_rate) { ChangeListEntry *ptr; struct timeval raw, cooked; @@ -454,7 +454,7 @@ LCL_AccumulateOffset(double offset) LCL_ReadRawTime(&raw); LCL_CookTime(&raw, &cooked, NULL); - (*drv_accrue_offset)(offset); + (*drv_accrue_offset)(offset, corr_rate); /* Dispatch to all handlers */ for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) { @@ -505,7 +505,7 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked, /* ================================================== */ void -LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset) +LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate) { ChangeListEntry *ptr; struct timeval raw, cooked; @@ -532,7 +532,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset) current_freq_ppm = (*drv_set_freq)(current_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 */ for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) { @@ -598,7 +598,7 @@ LCL_MakeStep(double threshold) return 0; /* Cancel remaining slew and make the step */ - LCL_AccumulateOffset(correction); + LCL_AccumulateOffset(correction, 0.0); LCL_ApplyStepOffset(-correction); LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction); diff --git a/local.h b/local.h index 40c0853..eea7072 100644 --- a/local.h +++ b/local.h @@ -138,9 +138,10 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq); /* Routine to apply an offset (in seconds) to the local clock. 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 - 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 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 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. */ extern int LCL_GetSysPrecisionAsLog(void); diff --git a/localp.h b/localp.h index a473d16..ce92f1c 100644 --- a/localp.h +++ b/localp.h @@ -41,8 +41,9 @@ typedef double (*lcl_ReadFrequencyDriver)(void); typedef double (*lcl_SetFrequencyDriver)(double freq_ppm); /* System driver to accrue an offset. A positive argument means slew - the clock forwards. */ -typedef void (*lcl_AccrueOffsetDriver)(double offset); + the clock forwards. The suggested correction rate of time to correct the + 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 the clock forwards. */ diff --git a/reference.c b/reference.c index 6181002..c2c316e 100644 --- a/reference.c +++ b/reference.c @@ -541,6 +541,7 @@ REF_SetReference(int stratum, IPAddr *ref_ip, struct timeval *ref_time, double offset, + double offset_sd, double frequency, double skew, double root_delay, @@ -556,6 +557,7 @@ REF_SetReference(int stratum, double abs_freq_ppm; double update_interval; double elapsed; + double correction_rate; struct timeval now; assert(initialised); @@ -611,6 +613,20 @@ REF_SetReference(int stratum, } 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 information */ @@ -645,7 +661,7 @@ REF_SetReference(int stratum, our_residual_freq = new_freq - our_frequency; maybe_log_offset(our_offset); - LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset); + LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset, correction_rate); } 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); #endif maybe_log_offset(our_offset); - LCL_AccumulateOffset(our_offset); + LCL_AccumulateOffset(our_offset, correction_rate); our_residual_freq = frequency; } @@ -714,7 +730,7 @@ REF_SetManualReference our_residual_freq = 0.0; maybe_log_offset(offset); - LCL_AccumulateFrequencyAndOffset(frequency, offset); + LCL_AccumulateFrequencyAndOffset(frequency, offset, 0.0); maybe_make_step(); abs_freq_ppm = LCL_ReadAbsoluteFrequency(); diff --git a/reference.h b/reference.h index 2b66f6a..2d6de9f 100644 --- a/reference.h +++ b/reference.h @@ -109,6 +109,7 @@ extern void REF_SetReference IPAddr *ref_ip, struct timeval *ref_time, double offset, + double offset_sd, double frequency, double skew, double root_delay, diff --git a/rtc_linux.c b/rtc_linux.c index 3ee8b66..aa172e1 100644 --- a/rtc_linux.c +++ b/rtc_linux.c @@ -664,7 +664,7 @@ handle_initial_trim(void) sys_error_now = rtc_error_now - coef_seconds_fast; 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 { LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time"); } diff --git a/sources.c b/sources.c index 6ebd620..bfe7e3c 100644 --- a/sources.c +++ b/sources.c @@ -857,6 +857,7 @@ SRC_SelectSource(uint32_t match_refid) sources[selected_source_index]->ip_addr, &ref_time, src_offset, + src_offset_sd, src_frequency, src_skew, src_root_delay, diff --git a/sys_linux.c b/sys_linux.c index ffc917e..c0512bd 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -592,7 +592,7 @@ abort_slew(void) time) */ static void -accrue_offset(double offset) +accrue_offset(double offset, double corr_rate) { /* Add the new offset to the register */ offset_register += offset; diff --git a/sys_netbsd.c b/sys_netbsd.c index 863f572..c9a29b3 100644 --- a/sys_netbsd.c +++ b/sys_netbsd.c @@ -199,7 +199,7 @@ stop_adjust(void) slew backwards */ static void -accrue_offset(double offset) +accrue_offset(double offset, double corr_rate) { stop_adjust(); offset_register += offset; diff --git a/sys_solaris.c b/sys_solaris.c index db40091..54d2bde 100644 --- a/sys_solaris.c +++ b/sys_solaris.c @@ -212,7 +212,7 @@ stop_adjust(void) slew backwards */ static void -accrue_offset(double offset) +accrue_offset(double offset, double corr_rate) { stop_adjust(); offset_register += offset; diff --git a/sys_sunos.c b/sys_sunos.c index 5178c5a..3ac67a0 100644 --- a/sys_sunos.c +++ b/sys_sunos.c @@ -216,7 +216,7 @@ stop_adjust(void) slew backwards */ static void -accrue_offset(double offset) +accrue_offset(double offset, double corr_rate) { stop_adjust(); offset_register += offset;