Skip to content

Instantly share code, notes, and snippets.

@hfiennes
Last active January 25, 2019 03:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hfiennes/07d5f8f53ed4e11d44b02071e9963c48 to your computer and use it in GitHub Desktop.
Save hfiennes/07d5f8f53ed4e11d44b02071e9963c48 to your computer and use it in GitHub Desktop.
A time experiment
// Latency history
const SAMPLES = 10
rtt_history <- [];
// Send a timestamp packet to the imp, which it will loop back
// Comapring the times when we get the return tells us the RTT
function link_latency() {
local d = date();
device.send("latency", { "s":d.time, "us":d.usec });
}
// Process the returned time packet
device.on("latency", function(v) {
// Get the agent's view of the current time
local d = date();
// Work out the RTT, and push it into the history array
local rtt = 1000000*(d.time - v.s) + (d.usec - v.us);
rtt_history.push(rtt);
// Did we get enough of them?
if (rtt_history.len() == SAMPLES) {
// Calculate mean
local total = rtt_history.reduce(function(p,c) { return p+c; });
local mean = 1.0*total / rtt_history.len();
// Calculate squared differences from mean, sum them, then take square root to get stddev
local sqdiff = rtt_history.map(function(d) { return (d-mean)*(d-mean); });
local sqdiff_total = sqdiff.reduce(function(p,c) { return p+c; });
local sqdiff_mean = sqdiff_total / sqdiff.len();
local stddev = math.sqrt(sqdiff_mean);
//server.log("mean="+mean+"us, stddev="+stddev+"us");
// Does this look okish, using a totally arbitrary bar?
if (stddev > (mean*0.1)) {
// Looks a bit high, so we'll start another cycle
//server.log("deviation too high, trying again");
measure_rtt();
} else {
// Looks ok, let's use this. We halve it as we are just interested in
// time time it takes for the packet to arrive at the client
send_corrected_time(mean / 2);
}
} else {
// Send another packet
link_latency();
}
});
// Kick of RTT measurement cycle
function measure_rtt() {
rtt_history = [];
link_latency();
}
// Now we have an RTT offset, send it to the device
// Note! offset_us must be an integer, otherwise you get float promotion and
// things are strangely bad
function send_corrected_time(offset_us) {
// Get agent time
local d = date();
// By the time this arrives with the client, it'll be on average offset_us old,
// so add this to the time we're sending
d.usec += offset_us.tointeger();
d.time += (d.usec / 1000000);
d.usec = d.usec % 1000000;
device.send("time", { "s":d.time, "us":d.usec });
}
// Send corrections every 10s
function repeat() {
measure_rtt();
imp.wakeup(10, repeat);
}
// Wait for device to be ready after a build & run
imp.wakeup(1, function() { repeat(); });
// Respond to an RTT request by returning the packet
agent.on("latency", function(v) { agent.send("latency", v); });
// In order to be able to return a "more accurate" time, we need to store the
// accurate time and when we received it from the server
reference_time <- { "s":0, "us":0 };
reference_received <- 0;
// Deal with a corrected time sent from the agent
agent.on("time", function(v) {
// Set these as references
local now = hardware.millis();
// For this demo, save what our local concept of "accurate time" is
local pre_sync = get_time();
// Now, update the reference
reference_time = v;
reference_received = now;
// Now get our *new* concept of "accurate time"
local post_sync = get_time();
// ...and get diff & log it
local diff = 1000000*(post_sync.s - pre_sync.s) + (post_sync.us - pre_sync.us);
server.log(format("pre %d.%06d -> post %d.%06d, diff %dus",
pre_sync.s, pre_sync.us,
post_sync.s, post_sync.us,
diff));
});
// Return the "accurised" time ;)
function get_time() {
// Work out time since last server fix
local since = hardware.millis() - reference_received;
// Add to reference & normalize
local r = { "s": reference_time.s, "us": reference_time.us };
r.us += (since * 1000);
r.s += r.us / 1000000;
r.us = r.us % 1000000;
return r;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment