From: Linus Torvalds <[email protected]> Date: Sun, 25 Oct 2015 12:02:08 +0900 Subject: [PATCH] Interpolate depth for samples that have no depth
When downloading from libdivecomputer, we used to initialize the depth of a sample to the previous depth. However, at least for the Suunto EON Steel, you can get sample times without any actual depth reading - the time might be associated with some ranbdom event rather than a new depth sample. Rather than initialize these samples to have the same depth as the previous one (and then perhaps getting a very sudden jump when the *real* depth event comes in a second later), initialize the depth samples to -1, and if that sample doesn't get a real depth, we'll create an interpolated depth. It is possible that we should just carry the sample around as not actually having a depth, and instead just interpolate in the plot_info generation, but at least right now we have a ton of code that "knows" that every sample has a depth. Not the least of which is our own save format. So generating an interpolated depth seems the path of least resistance, and at least makes the graph look correct - no odd staircase effect from other events that happen in between depth samples. Signed-off-by: Linus Torvalds <[email protected]> --- This fixes my profile from the EON Steel, where I before had the occasional red "steep ascent" warning segments because we would generate what looked like a staircase profile when an event happened in between two depth events, and rather than interpolate it would take the previous sample depth, and then the next sample would look like a very sudden jump. Using a negative depth to indicate "this sample has no depth" is a new situation for us, but it gets fixed up very early in the dive parsing stage, so no other code should hopefully ever see it. So the upside of interpolating the depth early is that this change is fairly localized. The negative depth only exists during the download, and as we fix up the dive we get rid of it and replace it with the interpolated depth and nobody else will ever see a depth of "-1 mm". The downside is that we save that fake depth and use it as a real depth, even though it's "fake". Of course, we used to do that before too - it's just that it was another - and far worse - fake value. But arguably we *could* carry the "this sample has no depth" around for much longer, and only interpolate when actually displaying it. That would more accurately reflect the real download, but it would also break a lot of existing code that just knows that all samples have a depth. The upside of carrying the "we have no depth value" around in the samples seems to be very questionable, and the downside would be that we'd have to find every single place we use a sample depth and either not use it at all, or interpolate it. So I think this patch is the right approach. But if somebody wants to do a more full conversion, go right ahead.. And even though this patch does the interpolation pretty early, having another set of eyes verify that there really is nothing else that sees the negative depth might be a good idea. dive.c | 22 ++++++++++++++++++++++ libdivecomputer.c | 11 +++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/dive.c b/dive.c index dfd5b495c1ee..2ae84ca1e56c 100644 --- a/dive.c +++ b/dive.c @@ -1243,6 +1243,23 @@ static void fixup_dc_events(struct divecomputer *dc) } } +static int interpolate_depth(struct divecomputer *dc, int idx, int lastdepth, int lasttime, int now) +{ + int i; + int nextdepth = lastdepth; + int nexttime = now; + + for (i = idx+1; i < dc->samples; i++) { + struct sample *sample = dc->sample + i; + if (sample->depth.mm < 0) + continue; + nextdepth = sample->depth.mm; + nexttime = sample->time.seconds; + break; + } + return interpolate(lastdepth, nextdepth, now-lasttime, nexttime-lasttime); +} + static void fixup_dive_dc(struct dive *dive, struct divecomputer *dc) { int i, j; @@ -1276,6 +1293,11 @@ static void fixup_dive_dc(struct dive *dive, struct divecomputer *dc) int o2_pressure = sample->o2cylinderpressure.mbar; int index; + if (depth < 0) { + depth = interpolate_depth(dc, i, lastdepth, lasttime, time); + sample->depth.mm = depth; + } + /* if we have an explicit first cylinder */ if (sample->sensor == 0 && first_cylinder != 0) sample->sensor = first_cylinder; diff --git a/libdivecomputer.c b/libdivecomputer.c index a9d90d837979..b5f90cb35acd 100644 --- a/libdivecomputer.c +++ b/libdivecomputer.c @@ -231,7 +231,6 @@ static void handle_event(struct divecomputer *dc, struct sample *sample, dc_samp void sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata) { - unsigned int mm; static unsigned int nsensor = 0; struct divecomputer *dc = userdata; struct sample *sample; @@ -252,7 +251,10 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata) switch (type) { case DC_SAMPLE_TIME: nsensor = 0; - mm = 0; + + // The previous sample gets some sticky values + // that may have been around from before, even + // if there was no new data if (sample) { sample->in_deco = in_deco; sample->ndl.seconds = ndl; @@ -260,11 +262,12 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata) sample->stopdepth.mm = stopdepth; sample->setpoint.mbar = po2; sample->cns = cns; - mm = sample->depth.mm; } + // Create a new sample. + // Mark depth as negative sample = prepare_sample(dc); sample->time.seconds = value.time; - sample->depth.mm = mm; + sample->depth.mm = -1; finish_sample(dc); break; case DC_SAMPLE_DEPTH: -- 2.6.0 _______________________________________________ subsurface mailing list [email protected] http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface
