Tuesday, July 4, 2023

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 obscure and 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, in a world immersed by electronic devices, we find time-keeping can be a problematic task still. For example, before a phone can use an internet protocol to send a message over the internet, it ideally first needs to agree on a time keeping strategy with a remote server on the internet, in order to reduce the likelihood of errors. But in the world of software, there are various ways to keep time. And some of them are more precise than others.

While we find somewhat more complex versions of this problem in various software ecosystems, this post will present a simple example to demonstrate the problem of clock drift to a wider audience. 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_t which uses the system clock, and stash our starting time there. Then we'll define a larger uint64_t variable to get a start time via mach_absolute_time, which is more precise. Lastly, we'll use printf to display the two times to their respective floats, as well as a third statement to print the result of a simple subtraction, displaying the difference between them:

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


uint64_t getTimestamp() {
        return mach_absolute_time();
}

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

    while (1) {
        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 (Drifting clock): %.2lf seconds\n", elapsed_time);
        printf("Elapsed time (Precise clock): %.9lf seconds\n", precise_elapsed_time);
        printf("Difference: %.9lf seconds\n\n", precise_elapsed_time - elapsed_time);
        
        sleep(1);
    }

    return 0;
}

After compiling with gcc, we can run and visualize digital clock drift. For every second on the drifting clock, despite the program claiming a single unitary second has passed, we find from our precise clock, that, in fact, much more time has elapsed. And the difference compounds quite fast:

hexagr@am ~ % ./clock2 
Elapsed time (Drifting clock): 0.00 seconds
Elapsed time (Precise clock): 0.000000418 seconds
Difference: 0.000000418 seconds

Elapsed time (Drifting clock): 1.00 seconds
Elapsed time (Precise clock): 1.004206989 seconds
Difference: 0.004206989 seconds

Elapsed time (Drifting clock): 2.00 seconds
Elapsed time (Precise clock): 2.008466130 seconds
Difference: 0.008466130 seconds

Elapsed time (Drifting clock): 3.00 seconds
Elapsed time (Precise clock): 3.012706402 seconds
Difference: 0.012706402 seconds

No comments:

Post a Comment