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 6b38fe39..250dca28 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 0baf86da..7810fefd 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 12fecf43..b300cc6d 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 40c08536..eea70722 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 a473d16f..ce92f1c7 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 6181002d..c2c316e0 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 2b66f6ab..2d6de9f2 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 3ee8b66f..aa172e14 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 6ebd6204..bfe7e3c2 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 ffc917ed..c0512bdb 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 863f572c..c9a29b33 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 db40091e..54d2bde8 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 5178c5aa..3ac67a07 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; -- 2.47.2