Skip to main content

Clock Drift

When people think about clocks, they might know about how old analog clocks functioned and also suffered from the problem of clock drift. But even with the advent of digital clocks, we also find the same problem once more. Physicists might think about this problem in the context of time dilation. And cryptographers might seek to use the clock drift to generate random numbers. But it can appear a counter-intuitive problem, even to folks who might work in technology.

Before computers, time keeping was especially troublesome due to watches being vulnerable to harsh environmental factors. For example, clocks were frequently used on ships, but being at sea, analog clocks would fail to accurately measure time due to clock drift, as traditional clocks used pendulums and designs that were otherwise unreliable in the face of constant motion, temperature, and humidity, thereby challenging and threatening the safety of sailors and travelers as they tried to navigate and determine their coordinates. The problem is nicely described on geographyfieldwork.com:

Measuring latitude, how far you are north or south of the equator, was not a problem in 1675. Longitude, the position east or west, was still not accurate but was theoretically possible to measure in terms of time.

We knew in the 17th century that the earth turns 360° every day, or 15° every hour. So if you travelled 15° eastward, the local time moves one hour ahead and similarly, travelling West, the local time moves back one hour. The imaginary lines drawn on a globe representing each 15° are called the meridian lines.

Therefore, using the meridian lines you could see how far you have travelled east or west.

For example, if it was noon where you were and you knew it to be 9am in Greenwich (0°) you would have sailed west for 3 hours and you would be at longitude 45°.

You know from using a compass if you have travelled east or west but knowing the exact time back in Greenwich was the problem.

How do you know if you have travelled 2 hours 59 minutes or 3 hours 02 minutes?

Getting a clock to work accurately at sea was very difficult - just a few seconds too fast or too slow could result in the ship ending up miles off course. The difficulty was producing a clock which could maintain accurate time in widely-varying temperature, pressure and humidity.

In 1714, the British government assigned a prize for a better method of determining longitude at sea. And John Harrison, a carpenter, began inventing watches in an attempt to solve the problem. His first three iterations of clock design were all too inaccurate. But upon a fourth iteration of the design, he achieved success in producing a watch that was resistant and accurate enough in rugged conditions that it could be safely used at sea.

John Harrison's clock schematics
A page from 'The Principles of Mr. Harrison's time-keeper' via Library of Congress

John Harrison's H4 watch utilized an intricate design that included several plates and a spring escapement system which resisted both centrifugal force and factors like pressure and temperature:

His design used a fast-beating balance wheel controlled by a temperature-compensated spiral spring. These features remained in use until stable electronic oscillators allowed very accurate portable timepieces to be made at affordable cost.

Fast forward to the digital age, and even today, we find time-keeping can be a problematic task. The problem crops up in GPS systems and in software ecosystems. For example, before a mobile app uses an internet protocol to send a message over the internet, it may first need to agree on a time keeping strategy with a remote server on the internet in order to reduce the likelihood of errors. But there are various ways to keep time. And some of them are more precise than others. Some might involve a centralized network time server. Others might rely on other methods. Some might rely on hardware items, like CMOS batteries. As hardware or battery health degrades, software precision might degrade, too.

While we find somewhat more complex versions of this problem in various software ecosystems, it can be demonstrated simply here. Per some sparse Apple documentation and a few posts on the internet, we can see there are a few different ways to calculate the time on an iPhone or Apple device. And a similar approach can be used on varying Unix devices. But we'll use the system clock, as well as mach_absolute_time, to demonstrate two varying methods to return the time of a simple 1 second counter.

In our main function, we'll first grab two start times—one utilizing time() which uses the system clock, and stash our starting time there. Then we'll define a larger uint64_t variable to get a precise time via mach_absolute_time.

Lastly, we'll use printf to display the two times to their respective floats, as well as a third statement to print the resulting subtraction, to display the difference between them:

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <mach/mach_time.h>

uint64_t getTimestamp() {
    static mach_timebase_info_data_t timebase = {0};
    
    if (timebase.denom == 0) {
        if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
            fprintf(stderr, "Failed to get mach_timebase_info\n");
            return 0;
        }
    }

    uint64_t ticks = mach_absolute_time();
    return (ticks * timebase.numer) / timebase.denom;  // get nanoseconds
}

int main() {
    time_t start_time = time(NULL);
    uint64_t precise_start_time = getTimestamp();

    int run_duration = 180; // test for three minutes
    while (difftime(time(NULL), start_time) < run_duration) {
        time_t current_time = time(NULL);
        double elapsed_time = difftime(current_time, start_time);

        uint64_t precise_current_time = getTimestamp();
        double precise_elapsed_time = (precise_current_time - precise_start_time) / 1e9;

        printf("Elapsed time: %.2lf seconds\n", elapsed_time);
        printf("Precision time: %.9lf seconds\n", precise_elapsed_time);
        printf("Difference: %.9lf seconds\n\n", precise_elapsed_time - elapsed_time);

        // nano sleep for more accuracy
  
        struct timespec ts;
        ts.tv_sec = 1;  // Sleep for 1 second
        ts.tv_nsec = 0; // And 0 nanoseconds
        nanosleep(&ts, NULL);
    }

    printf("Test completed after %d seconds.\n", run_duration);
    return 0;
}

After compiling with gcc, we can run and visualize a small scale digital clock drift. For every second on the regular, less accurate clock, we see from our precise clock, that, in fact, slightly more time has elapsed. And the difference compounds quite fast.

By the 170 second mark, our clock is now off and inaccurate by half a second. One can imagine the potential cumalative and second-order effects of clock drift in both digital and analog systems.

$ gcc -o time time.c
...
Elapsed time: 170.00 seconds
Precision time: 170.519596970 seconds
Difference: 0.519596970 seconds

Comments

Popular posts from this blog

yt-dlp Archiving, Improved

One annoying thing about YouTube is that, by default, some videos are now served in .webm format or use VP9 encoding. However, I prefer storing media in more widely supported codecs and formats, like .mp4, which has broader support and runs on more devices than .webm files. And sometimes I prefer AVC1 MP4 encoding because it just works out of the box on OSX with QuickTime, as QuickTime doesn't natively support VP9/VPO9. AVC1-encoded MP4s are still the most portable video format. AVC1 ... is by far the most commonly used format for the recording, compression, and distribution of video content, used by 91% of video industry developers as of September 2019. [ 1 ] yt-dlp , the command-line audio/video downloader for YouTube videos, is a great project. But between YouTube supporting various codecs and compatibility issues with various video players, this can make getting what you want out of yt-dlp a bit more challenging: $ yt-dlp -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best...