reference: allow clock adjustments without updating reference
Add support for accumulating frequency and time offset without changing the reference parameters and calling the local parameter change handlers. This will allow an unsynchronized source to operate below other sources in order to stabilize the clock.
This commit is contained in:
parent
4c29f8888c
commit
af6ae9186b
4 changed files with 77 additions and 17 deletions
18
local.c
18
local.c
|
@ -628,6 +628,24 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset, double corr_rate)
|
||||||
|
{
|
||||||
|
ChangeListEntry *first_handler;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
first_handler = change_list.next;
|
||||||
|
change_list.next = &change_list;
|
||||||
|
|
||||||
|
r = LCL_AccumulateFrequencyAndOffset(dfreq, doffset, corr_rate);
|
||||||
|
|
||||||
|
change_list.next = first_handler;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
lcl_InvokeDispersionNotifyHandlers(double dispersion)
|
lcl_InvokeDispersionNotifyHandlers(double dispersion)
|
||||||
{
|
{
|
||||||
|
|
5
local.h
5
local.h
|
@ -173,6 +173,11 @@ extern void LCL_NotifyLeap(int leap);
|
||||||
a slew, in one easy step */
|
a slew, in one easy step */
|
||||||
extern int LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
extern int LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
||||||
|
|
||||||
|
/* Same as the routine above, except it does not call the registered
|
||||||
|
parameter change handlers */
|
||||||
|
extern int LCL_AccumulateFrequencyAndOffsetNoHandlers(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);
|
||||||
|
|
||||||
|
|
67
reference.c
67
reference.c
|
@ -150,6 +150,9 @@ static SCH_TimeoutID fb_drift_timeout_id;
|
||||||
static double last_ref_update;
|
static double last_ref_update;
|
||||||
static double last_ref_update_interval;
|
static double last_ref_update_interval;
|
||||||
|
|
||||||
|
static double last_ref_adjustment;
|
||||||
|
static int ref_adjustments;
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
|
static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
|
||||||
|
@ -286,6 +289,8 @@ REF_Initialise(void)
|
||||||
UTI_ZeroTimespec(&our_ref_time);
|
UTI_ZeroTimespec(&our_ref_time);
|
||||||
last_ref_update = 0.0;
|
last_ref_update = 0.0;
|
||||||
last_ref_update_interval = 0.0;
|
last_ref_update_interval = 0.0;
|
||||||
|
last_ref_adjustment = 0.0;
|
||||||
|
ref_adjustments = 0;
|
||||||
|
|
||||||
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
||||||
|
|
||||||
|
@ -960,6 +965,27 @@ fuzz_ref_time(struct timespec *ts)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
static double
|
||||||
|
get_correction_rate(double offset_sd, double update_interval)
|
||||||
|
{
|
||||||
|
/* 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 multiplied by the correction time ratio (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. */
|
||||||
|
|
||||||
|
return correction_time_ratio * 0.5 * offset_sd * update_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||||
uint32_t ref_id, IPAddr *ref_ip, struct timespec *ref_time,
|
uint32_t ref_id, IPAddr *ref_ip, struct timespec *ref_time,
|
||||||
|
@ -969,7 +995,7 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||||
{
|
{
|
||||||
double uncorrected_offset, accumulate_offset, step_offset;
|
double uncorrected_offset, accumulate_offset, step_offset;
|
||||||
double residual_frequency, local_abs_frequency;
|
double residual_frequency, local_abs_frequency;
|
||||||
double elapsed, mono_now, update_interval, correction_rate, orig_root_distance;
|
double elapsed, mono_now, update_interval, orig_root_distance;
|
||||||
struct timespec now, raw_now;
|
struct timespec now, raw_now;
|
||||||
int manual;
|
int manual;
|
||||||
|
|
||||||
|
@ -1024,21 +1050,6 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||||
last_ref_update_interval = update_interval;
|
last_ref_update_interval = update_interval;
|
||||||
last_offset = offset;
|
last_offset = offset;
|
||||||
|
|
||||||
/* 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 multiplied by the correction time ratio (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 = correction_time_ratio * 0.5 * offset_sd * update_interval;
|
|
||||||
|
|
||||||
/* Check if the clock should be stepped */
|
/* Check if the clock should be stepped */
|
||||||
if (is_step_limit_reached(offset, uncorrected_offset)) {
|
if (is_step_limit_reached(offset, uncorrected_offset)) {
|
||||||
/* Cancel the uncorrected offset and correct the total offset by step */
|
/* Cancel the uncorrected offset and correct the total offset by step */
|
||||||
|
@ -1050,7 +1061,8 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust the clock */
|
/* Adjust the clock */
|
||||||
LCL_AccumulateFrequencyAndOffset(frequency, accumulate_offset, correction_rate);
|
LCL_AccumulateFrequencyAndOffset(frequency, accumulate_offset,
|
||||||
|
get_correction_rate(offset_sd, update_interval));
|
||||||
|
|
||||||
maybe_log_offset(offset, raw_now.tv_sec);
|
maybe_log_offset(offset, raw_now.tv_sec);
|
||||||
|
|
||||||
|
@ -1095,6 +1107,27 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||||
avg2_moving = 1;
|
avg2_moving = 1;
|
||||||
avg2_offset = SQUARE(offset);
|
avg2_offset = SQUARE(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref_adjustments = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
REF_AdjustReference(double offset, double frequency)
|
||||||
|
{
|
||||||
|
double adj_corr_rate, ref_corr_rate, mono_now;
|
||||||
|
|
||||||
|
mono_now = SCH_GetLastEventMonoTime();
|
||||||
|
ref_adjustments++;
|
||||||
|
|
||||||
|
adj_corr_rate = get_correction_rate(fabs(offset), mono_now - last_ref_adjustment);
|
||||||
|
ref_corr_rate = get_correction_rate(our_offset_sd, last_ref_update_interval) /
|
||||||
|
ref_adjustments;
|
||||||
|
last_ref_adjustment = mono_now;
|
||||||
|
|
||||||
|
return LCL_AccumulateFrequencyAndOffsetNoHandlers(frequency, offset,
|
||||||
|
MAX(adj_corr_rate, ref_corr_rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
|
@ -162,6 +162,10 @@ extern void REF_SetManualReference
|
||||||
extern void
|
extern void
|
||||||
REF_SetUnsynchronised(void);
|
REF_SetUnsynchronised(void);
|
||||||
|
|
||||||
|
/* Make a small correction of the clock without updating the reference
|
||||||
|
parameters and calling the clock change handlers */
|
||||||
|
extern int REF_AdjustReference(double offset, double frequency);
|
||||||
|
|
||||||
/* Announce a leap second before the full reference update */
|
/* Announce a leap second before the full reference update */
|
||||||
extern void REF_UpdateLeapStatus(NTP_Leap leap);
|
extern void REF_UpdateLeapStatus(NTP_Leap leap);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue