hwclock: don't drop valid samples in HCL_ProcessReadings()

Modify the HCL_ProcessReadings() function to try to always provide
a valid sample. Instead of dropping a sample outside of the expected
delay, provide its assumed quality level as a small integer (relative to
already accumulated samples), and let the caller decide what quality is
acceptable.
This commit is contained in:
Miroslav Lichvar
2025-08-11 16:00:38 +02:00
parent f78e4681ef
commit 5535384878
5 changed files with 38 additions and 20 deletions

View File

@@ -163,7 +163,8 @@ HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
int
HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
struct timespec *hw_ts, struct timespec *local_ts, double *err)
struct timespec *hw_ts, struct timespec *local_ts, double *err,
int *quality)
{
double delay, raw_delay, min_delay, low_delay, high_delay, e, pred_err;
double delay_sum, hw_sum, local_sum, local_prec, freq;
@@ -228,11 +229,13 @@ HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3]
UTI_AddDoubleToTimespec(&tss[0][1], hw_sum / combined, hw_ts);
UTI_AddDoubleToTimespec(&tss[0][0], local_sum / combined, local_ts);
*err = MAX(delay_sum / combined / 2.0, clock->precision);
*quality = 2;
return 1;
}
/* Accept the reading with minimum delay if its interval does not contain
the current offset predicted from previous samples */
/* Indicate acceptable quality of the reading with minimum delay if its
interval does not contain the current offset predicted from previous
samples, or a new sample is needed to get the tracking working */
*hw_ts = tss[min_reading][1];
UTI_AddDoubleToTimespec(&tss[min_reading][0], min_delay / freq / 2.0, local_ts);
@@ -242,11 +245,14 @@ HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3]
LCL_CookTime(local_ts, &ts1, NULL);
if (!HCL_CookTime(clock, hw_ts, &ts2, &e) ||
((pred_err = UTI_DiffTimespecsToDouble(&ts1, &ts2)) > *err)) {
DEBUG_LOG("Accepted reading err=%e prerr=%e", *err, pred_err);
return 1;
*quality = 1;
} else {
*quality = 0;
}
return 0;
DEBUG_LOG("Min-delay reading err=%e prerr=%e ql=%d", *err, pred_err, *quality);
return 1;
}
/* ================================================== */

View File

@@ -38,10 +38,14 @@ extern void HCL_DestroyInstance(HCL_Instance clock);
/* Check if a new sample should be accumulated at this time */
extern int HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now);
/* Process new readings of the HW clock in form of (sys, hw, sys) triplets and
produce a sample which can be accumulated */
/* Process new readings of the HW clock in the form of (sys, hw, sys) triplets
and produce a sample which can be accumulated by HCL_AccumulateSample().
Indicate the quality of the sample relative to already processed samples as
a value of 0, 1, or 2, where a sample of quality 0 should normally be
dropped. */
extern int HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
struct timespec *hw_ts, struct timespec *local_ts, double *err);
struct timespec *hw_ts, struct timespec *local_ts, double *err,
int *quality);
/* Accumulate a new sample */
extern void HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,

View File

@@ -519,7 +519,7 @@ poll_phc(struct Interface *iface, struct timespec *now)
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts;
struct timespec phc_readings[PHC_READINGS][3];
double phc_err, local_err, interval;
int n_readings;
int n_readings, quality;
if (!HCL_NeedsNewSample(iface->clock, now))
return;
@@ -543,7 +543,8 @@ poll_phc(struct Interface *iface, struct timespec *now)
return;
if (!HCL_ProcessReadings(iface->clock, n_readings, phc_readings,
&sample_phc_ts, &sample_sys_ts, &phc_err))
&sample_phc_ts, &sample_sys_ts, &phc_err, &quality) ||
quality <= 0)
return;
LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);

View File

@@ -198,7 +198,7 @@ static int phc_poll(RCL_Instance instance)
struct timespec phc_ts, sys_ts, local_ts, readings[PHC_READINGS][3];
struct phc_instance *phc;
double phc_err, local_err;
int n_readings;
int n_readings, quality;
phc = (struct phc_instance *)RCL_GetDriverData(instance);
@@ -210,15 +210,20 @@ static int phc_poll(RCL_Instance instance)
if (!phc->extpps)
RCL_UpdateReachability(instance);
if (!HCL_ProcessReadings(phc->clock, n_readings, readings, &phc_ts, &sys_ts, &phc_err))
if (!HCL_ProcessReadings(phc->clock, n_readings, readings,
&phc_ts, &sys_ts, &phc_err, &quality))
return 0;
LCL_CookTime(&sys_ts, &local_ts, &local_err);
HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);
if (quality > 0)
HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);
if (phc->extpps)
return 0;
if (quality <= 0)
return 0;
DEBUG_LOG("PHC offset: %+.9f err: %.9f",
UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts), phc_err);

View File

@@ -32,9 +32,9 @@ test_unit(void)
{
struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
struct timespec readings[MAX_READINGS][3];
int i, j, k, l, new_sample, n_readings, count, quality;
HCL_Instance clock;
double freq, jitter, interval, dj, err, sum;
int i, j, k, l, new_sample, n_readings, count;
LCL_Initialise();
TST_RegisterDummyDrivers();
@@ -84,11 +84,13 @@ test_unit(void)
UTI_ZeroTimespec(&hw_ts);
UTI_ZeroTimespec(&local_ts);
if (HCL_ProcessReadings(clock, n_readings, readings, &hw_ts, &local_ts, &err)) {
HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
new_sample = 1;
} else {
new_sample = 0;
new_sample = 0;
if (HCL_ProcessReadings(clock, n_readings, readings, &hw_ts, &local_ts, &err, &quality)) {
TEST_CHECK(quality >= 0 && quality <= 2);
if (quality > 0) {
HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
new_sample = 1;
}
}
}