NTP Temperature Compensation

The network time protocol (NTP) provides a mechanism to improve the system clock's accuracy. Used with a suitable PPS reference exhibiting sub-microsecond accuracy, NTP makes it possible to put together an extremely accurate clock system. However, no matter how good the accuracy of the PPS source, the NTP clock is also limited by the thermal response of the quartz oscillator crystal that is used to generate the electronic reference signal for the clock.

A typical uncompensated crystal oscillator on the motherboard of a bog-standard pc can exhibit a frequency variation of the order of 1 ppm/°C. Left uncompensated, this can lead to significant drift over time in the clock offset parameter. In a typical machine room, the temperature varies periodically with a period of the order of 30 minutes and an amplitude of 1°C. If the frequency of the clock is left uncompensated and allowed to vary by this same amount, an offset error of about 500 μS may be expected. The NTP loop filter will attempt to compensate for this variation, but the 30 minute period of the air conditioning in a standard machine room is much faster than the response time of the loop filter. Thus, a significant fraction of the thermal variation in offset will be left uncompensated.

There are at least two methods of compensation that may be used to solve this problem. Hardware temperature compensation involves replacing the uncompensated quartz crystal oscillator originally shipped with the motherboard with a more expensive temperature-compensated crystal oscillator (TCXO). The TCXO is designed so that its output frequency exhibits little dependence on temperature. Using hardware temperature compensation it is possible to achieve NTP operation much closer to the ultimate accuracy of the PPS source being used as a reference clock. The problem with this approach is that TCXOs are difficult to find and install, as well as having a high cost.

A second method for temperature compensation is software compensation. With this method, NTP is periodically updated with temperature data from the uncompensated crystal oscillator source, permitting NTP to use this data in disciplining the system clock. There have been two primary approachs people have taken in implementing software temperature compensation. The first of these involved patching the NTP program to add temperature compensation data to the frequency drift data that NTP normally uses to compensate for quasi-static nonidealities in the system's quartz oscillator. This approach was successful, demonstrating a 3.5-fold reduction in the standard deviation of the offset parameter compared to the same system in an uncompensated state. However, development using this approach stopped in 2001. A second approach using the ntptime utility has also been successfully demonstrated. In this case, the authors did not use a PPS refclock, so it is not possible to compare the improvement using the method with the native NTP approach referenced above. However, they did note improvement in the temperature performance characteristics of a system using networked reference clocks.

Here I describe a new variation on the Martinec approach to software temperature compensation in NTP. I have modified the NTP source code to pass temperature data to the kernel using the ntp_adjtime() system call. This approach works with kernels that conform to Dave Mills' kernel model for precision timekeeping specification. The patch works with the most recent development release of NTP (4.2.5p158). In particular, this patch works with the FreeBSD 7.0 production release, and may work with other systems. Please let me know if you get it working and I will put together a list of systems for which this patch is functional.

My patch for ntp-dev-4.2.5p158 is available here. To use this patch, gunzip and untar a fresh copy of the ntp-dev-4.2.5p158 distribution. Change into the top level directory (usually called ntp-dev-4.2.5p158) and configure as appropriate. Apply the patch with the command:

patch -p0 < k0rx_temp-0.6.patch
Then run
make; make install
to build the installation. At that point you should have a patched version of ntpd ready to run on your system.

In order to use this new version of NTP, you will need to provide some mechanism for reading the temperature of the crystal oscillator and computing a frequency correction from the temperature value. The patched ntpd looks for the file /etc/ntp.drift.temp. In this file should be a single line with the temperature correction to the frequency drift in units of ppm (parts per million). The patched ntpd will read this data and apply the correction to the kernel once every 2^sys_poll seconds. The loopstats output file format has been modified by the patch to reflect the temperature correction data as well. Column four of the loopstats file contains the sum of the original NTP drift compensation frequency and the new temperature compensation frequency offset, and the new column eight contains only the temperature compensation frequency offset value.

There are a variety of ways to implement the temperature sensing and frequency correction calculation process. For the implementation described here, I am using a DS18B20 temperature sensor with 12 bit resolution. Digitemp is used to read and log the sensor data (a FreeBSD port is available here). A bash script then reads the temperature log file, calculates the frequency correction, and writes it to the /etc/ntp.drift.temp file. The entire process repeats with a period of 16 S.

This page is a work in progress. I am working on collecting data to demonstrate the performance of this software temperature compensation approach. However, for now I leave you with some preliminary numbers.

Using a GPS18-LVC gps, I am able to compensate accurately for cyclic temperature
changes of ~ 1°C and have achieved a standard deviation of the offset parameter
of 2.1 μS. Thus far, with this system, I haven't included a second order
(T - T0)^2 compensation parameter, but it is clear that doing so will be helpful.
A histogram of the temporal evolution over a 3 1/2 hour time period is shown here (horizontal axis in μS, vertical axis in counts, N = 838 samples, average offset = 0.5 μS for the red fitted curve):

During this time the temperature was oscillating approximately periodically with an amplitude of 0.5°C and a period of 24 minutes.


I would like to acknowledge helpful discussions about temperature compensation with Mark Martinec, the author of the first NTP temperature compensation code.


  1. http://www.ijs.si/time/temp-compensation/
  2. http://lx.ujf.cas.cz/ntp-lx/temp/www/
  3. http://www.cis.udel.edu/~mills/ntp/html/index.html
  4. http://support.ntp.org/bin/view/Support/WebHome