The nanokernel modifications require some changes in structure and behavior relative to RFC-1589  and the report on which it is based . However, the design provides backwards compatibility so that new and old NTP daemons can run in new and original kernels. Specific differences are described on this page.
Some variables, including the time, frequency and phase variables, are represented as 64-bit fixed point quantities, where the decimal point is between bit 31 and bit 32 (in either endian order). This format is used for time in nanoseconds and fraction and frequency in nanoseconds per second and fraction. In 64-bit machines, these variables are manipulated using native arithmetic and logical operations. In 32-bit machines, 64-bit operations are implemented using double precision arithmetic. The macro package defined in the l_fp.h header file hides the differences between the 32-bit and 64-bit versions.
The use of 64-bit arithmetic avoids two problems with the original kernel. One is the frequency calculation used when the tick interrupt frequency is not a power of two, which is the case for most architectures, including SPARC and Intel-based architectures. The calculation results in a frequency error of several percent, which is intolerable when frequencies must be computed with accuracies 1000 times better in the new kernel. The other problem is the leftover adjustment when the tick interrupt period does not evenly divide the number of microseconds or nanoseconds in one second, which is the case for the Digital Alpha and RISC architectures. In the original kernel the adjustment is performed once per second, in order to trim the frequency to the exact value. The jitter produced in this way is over 576 ms for the Alpha with 1024-Hz tick frequency. Obviously, this level of jitter is unacceptable in a nanosecond kernel. Both problems are solved using a 64-bit frequency variable, with which the frequency can be resolved to parts in 1019 nanoseconds per second.
The original kernel requires a different timex.h header file for each different tick interrupt frequency, which means that the tick frequency cannot be changed once the kernel is built. The new kernel uses the same header file for all tick frequencies and the frequency can be changed dynamically during operation. Considering that nanosecond resolution is preserved at all tick frequencies, the only reason to change the frequency might be to improve resolution for scheduled events, which is limited to the tick interval.
The original kernel can operate in either frequency-lock loop (FLL) or phase-lock loop (PLL) modes as selected by the ntp_adjtime() system call. The discipline time constant must be set by this system call to a value consistent with the poll interval used to update the clock. However, operation in FLL mode at poll intervals less than 256 s often results in instability, while operation in PLL mode at intervals greater than 1024 s results in poor frequency adaptation. The new kernel operates effectively in PLL mode if the update interval is less than 256 s and FLL mode if it is greater than 1024 s. Between these extremes, the STA_FLL bit in the status word can be used to select which mode to use. In any case, the particular mode in use can be determined by the STA_MODE status bit.
The original kernel has a limited range of time constants in PLL mode, the effect of which was to limit the poll interval to not less than 16 s. The new kernel extends this limit down to 1 s. Should a need for extremely rapid convergence arise, it is possible to use an initial poll interval of 1 s, in which case the time will converge in about a minute and the frequency in about an hour. Depending on the accuracy required, the poll interval can be increased to over one day, in order to reduce the network or operating system overhead. However, developers should note the new kernel requires a scale change in the time constant variable; in particular, the new time constant is 4 times larger than the old. Thus, a typical value of 2 in the original kernel corresponds to 6 in the new one. In addition, in the new kernel the time constant has meaning only in PLL mode. In FLL mode and PPS mode the time constant is fixed.
Most of the changes between the old and new kernels are in the PPS code. In most practical cases, the full capability of the new kernel is realizable only if a precision PPS signal is available. The changes include the use of 64-bit variables for time and frequency and for several intermediate and temporary variables. In addition, there are fundamental changes in the way some algorithms work.
The original kernel is vulnerable to input signals that are not at the nominal 1-PPS frequency or are excessively noisy. In the new kernel a frequency discriminator is used to suppress samples that are outside a tolerance range of ±500 PPM. As in the original kernel, a three-stage median filter is used to suppress outlyer time samples and second order time differences are used to suppress outlyer frequency samples. In the new kernel the outlyer thresholds have been changed to 500 ms for time (jitter) adjustments and between 500 PPM and about 2 PPM, depending on the calibration interval, for frequency adjustments.
While the new design allows for much larger tolerances and is much more resilient to noise and incorrect signal sources, there are specific limits due to the inherent ambiguity of the PPS signal itself when the pulse occurs approximately midway between two adjacent seconds. In order to prevent ambiguity errors, the sum of the maximum time offset and maximum frequency offset, expressed in microseconds over one second, must not exceed 500 ms. In practice with NTP, these limits cannot even be approached, due to the conservative design of the protocol daemon.
The original kernel modifications average the PPS time over a 64-s interval and average the PPS frequency over intervals that start at 8 s and eventually grow to 256 s. As determined by experiment and simulation, these intervals are too large for typical room temperature quartz oscillators. The design of the new kernel reflects the choice of Allan intercept, which depends on the intrinsic phase noise of the PPS signal and the intrinsic stability of the oscillator. As determined by simulation and experiment, an appropriate value for the Allan intercept is 128 s. The time offset is averaged each second with weight factor equal to the reciprocal of this value, while the frequency offset is measured over an interval equal to the same value.
Previous versions of the kernel modifications have been vulnerable to relatively infrequent but relatively large time offset samples due to PPS signal spikes or occasional interrupt latency excursions. The new modifications use a median filter and popcorn spike suppressor to detect and remove outlyer samples. Running averages of jitter and wander are maintained as performance indicators. Values exceeding nominal limits are flagged and counted. These values along with error indicator bits and counters can be obtained via the kernel API and used as a quality indicator.
The frequency discipline is computed in the same way as the original kernel, except that great care is taken to avoid roundoff errors and wander excursions in the various calculations. When available, the discipline uses the PCC in each processor to interpolate between tick interrupts, resulting in an attainable accuracy of one nanosecond in time and one nanosecond per second in frequency. A running average of frequency differences is used in the same way as the running average of time offset samples. The value of the running average, interpreted as a frequency stability estimate, can be obtained via the kernel API and used as a quality indicator.
In order to preserve backward compatibility with previous kernel and NTP daemon versions, the default behavior is to operate in microsecond mode, where the scaling is based on microseconds and PPM. In this mode the offset, precision and PPS jitter are represented in microseconds. In addition, the PLL time constant is interpreted as in the original kernel. The kernel can be switched to nanosecond mode by setting the MOD_NANO mode bit. If the kernel is capable of nanosecond mode, it sets the STA_NANO status bit. In this mode the offset, precision and PPS jitter are represented in nanoseconds. If necessary, the kernel can be switched back to microsecond mode by setting the MOD_MICRO mode bit. The NTP daemon can determine whether the old or new kernel is present by attempting to switch to nanosecond mode and then testing the STA_NANO bit. Note that the original kernel and older NTP daemon versions do not implement these bits, so will continue to operate as before.
There is a new feature to set the PPS averaging interval via the API, which can be used to optimize performance according to the wander characteristics of the individual clock oscillator. The default averaging interval is 128 s, which is a good compromise for systems with uncompensated quartz crystal oscillators. In systems where the clock oscillator is stabilized by a temperature compensated or oven compensated crystal oscillator, rubidium gas cell or cesium oscillator, the averaging interval can be increased to optimize performance.