From b5abdd46f0dfedacc248c1d96737f96e65bb9ed1 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 19 Nov 2011 07:09:14 -0500 Subject: [PATCH 1/4] Remove redundant linear sample tank pressure data I've seen at least DivingLog do this. If you manually enter beginning and end pressure for a tank it will either linearize the samples in between or offer to simulate a dive (with constant SAC rate). At least the first case is reasonably easy to detect. We throw out those samples and ensure that we still have valid beginning and end pressure for that dive. Signed-off-by: Dirk Hohndel --- dive.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/dive.c b/dive.c index cd797d276..31be3291d 100644 --- a/dive.c +++ b/dive.c @@ -236,7 +236,7 @@ static int same_rounded_pressure(pressure_t a, pressure_t b) struct dive *fixup_dive(struct dive *dive) { - int i; + int i,j; double depthtime = 0; int lasttime = 0; int lastindex = -1; @@ -244,6 +244,7 @@ struct dive *fixup_dive(struct dive *dive) int maxdepth = 0, mintemp = 0; int lastdepth = 0; int lasttemp = 0, lastpressure = 0; + int pressure_delta[MAX_CYLINDERS] = {INT_MAX, }; for (i = 0; i < dive->samples; i++) { struct sample *sample = dive->sample + i; @@ -253,10 +254,25 @@ struct dive *fixup_dive(struct dive *dive) int pressure = sample->cylinderpressure.mbar; int index = sample->cylinderindex; - /* Remove duplicate redundant pressure information */ - if (pressure == lastpressure && index == lastindex) - sample->cylinderpressure.mbar = 0; - + if (index == lastindex) { + /* Remove duplicate redundant pressure information */ + if (pressure == lastpressure) + sample->cylinderpressure.mbar = 0; + /* check for simply linear data in the samples + +INT_MAX means uninitialized, -INT_MAX means not linear */ + if (pressure_delta[index] != -INT_MAX && lastpressure) { + if (pressure_delta[index] == INT_MAX) { + pressure_delta[index] = abs(pressure - lastpressure); + } else { + int cur_delta = abs(pressure - lastpressure); + if (cur_delta && abs(cur_delta - pressure_delta[index]) > 150) { + /* ok the samples aren't just a linearisation + * between start and end */ + pressure_delta[index] = -INT_MAX; + } + } + } + } lastindex = index; lastpressure = pressure; @@ -290,6 +306,33 @@ struct dive *fixup_dive(struct dive *dive) lastdepth = depth; lasttime = time; } + /* if all the samples for a cylinder have pressure data that + * is basically equidistant throw out the sample cylinder pressure + * information but make sure we still have a valid start and end + * pressure + * this happens when DivingLog decides to linearalize the + * pressure between beginning and end and for strange reasons + * decides to put that in the sample data as if it came from + * the dive computer; we don't want that (we'll visualize with + * constant SAC rate instead) + * WARNING WARNING - I have only seen this in single tank dives + * --- maybe I should try to create a multi tank dive and see what + * --- divinglog does there - but the code right now is only tested + * --- for the single tank case */ + for (j = 0; j < MAX_CYLINDERS; j++) { + if (abs(pressure_delta[j]) != INT_MAX) { + cylinder_t *cyl = dive->cylinder + j; + for (i = 0; i < dive->samples; i++) + if (dive->sample[i].cylinderindex == j) + dive->sample[i].cylinderpressure.mbar = 0; + if (! cyl->start.mbar) + cyl->start.mbar = cyl->sample_start.mbar; + if (! cyl->end.mbar) + cyl->end.mbar = cyl->sample_end.mbar; + cyl->sample_start.mbar = 0; + cyl->sample_end.mbar = 0; + } + } if (end < 0) return dive; From 4e876b3082b46913d71e0f9bb6ff084aca4a2184 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 19 Nov 2011 10:17:19 -0500 Subject: [PATCH 2/4] Be more consistent in our handling of rgb value tables Use rgb_t for the sac colors, create a new set_source_rgb_struct function and use that for the velocity values (in the depth plot) as well. Signed-off-by: Dirk Hohndel --- profile.c | 57 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/profile.c b/profile.c index 1b1546c0f..9f8fa75b3 100644 --- a/profile.c +++ b/profile.c @@ -48,7 +48,7 @@ struct plot_info { /* convert velocity to colors */ typedef struct { double r, g, b; } rgb_t; -static const rgb_t rgb[] = { +static const rgb_t velocity_color[] = { [STABLE] = {0.0, 0.4, 0.0}, [SLOW] = {0.4, 0.8, 0.0}, [MODERATE] = {0.8, 0.8, 0.0}, @@ -89,6 +89,11 @@ static void set_source_rgba(struct graphics_context *gc, double r, double g, dou cairo_set_source_rgba(gc->cr, r, g, b, a); } +static void set_source_rgb_struct(struct graphics_context *gc, const rgb_t *rgb) +{ + set_source_rgba(gc, rgb->r, rgb->g, rgb->b, 1); +} + void set_source_rgb(struct graphics_context *gc, double r, double g, double b) { set_source_rgba(gc, r, g, b, 1); @@ -476,9 +481,8 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi /* we want to draw the segments in different colors * representing the vertical velocity, so we need to * chop this into short segments */ - rgb_t color = rgb[entry->velocity]; depth = entry->depth; - set_source_rgb(gc, color.r, color.g, color.b); + set_source_rgb_struct(gc, &velocity_color[entry->velocity]); move_to(gc, entry[-1].sec, entry[-1].depth); line_to(gc, sec, depth); cairo_stroke(cr); @@ -595,29 +599,36 @@ static int get_cylinder_pressure_range(struct graphics_context *gc, struct plot_ return pi->maxpressure != 0; } +#define SAC_COLORS 9 +static const rgb_t sac_color[SAC_COLORS] = { + { 0.0, 0.4, 0.2}, + { 0.2, 0.6, 0.2}, + { 0.4, 0.8, 0.2}, + { 0.6, 0.8, 0.2}, + { 0.8, 0.8, 0.2}, + { 0.8, 0.6, 0.2}, + { 0.8, 0.4, 0.2}, + { 0.9, 0.3, 0.2}, + { 1.0, 0.2, 0.2}, +}; + /* set the color for the pressure plot according to temporary sac rate - * as compared to avg_sac */ + * as compared to avg_sac; the calculation simply maps the delta between + * sac and avg_sac to indexes 0 .. (SAC_COLORS - 1) with everything + * more than 6000 ml/min below avg_sac mapped to 0 */ + static void set_sac_color(struct graphics_context *gc, int sac, int avg_sac) { - int delta = sac - avg_sac; - if (delta < -6000) - set_source_rgb(gc, 0.0, 0.4, 0.2); - else if (delta < -4000) - set_source_rgb(gc, 0.2, 0.6, 0.2); - else if (delta < -2000) - set_source_rgb(gc, 0.4, 0.8, 0.2); - else if (delta < 0) - set_source_rgb(gc, 0.6, 0.8, 0.2); - else if (delta < 2000) - set_source_rgb(gc, 0.8, 0.8, 0.2); - else if (delta < 4000) - set_source_rgb(gc, 0.8, 0.6, 0.2); - else if (delta < 6000) - set_source_rgb(gc, 0.8, 0.4, 0.2); - else if (delta < 8000) - set_source_rgb(gc, 0.9, 0.3, 0.2); - else - set_source_rgb(gc, 1.0, 0.2, 0.2); + int sac_index = 0; + int delta = sac - avg_sac + 6000; + + sac_index = delta / 2000; + if (sac_index < 0) + sac_index = 0; + if (sac_index > SAC_COLORS - 1) + sac_index = SAC_COLORS - 1; + + set_source_rgb_struct(gc, &sac_color[sac_index]); } /* calculate the current SAC in ml/min and convert to int */ From e1019cafa87058562d9f5844619841546029a57c Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 19 Nov 2011 14:39:35 -0500 Subject: [PATCH 3/4] Improve tank pressure sac coloring This changes the algorithm that picks the sac color to consider +/- 1 l/min to be the same color (before the color changed every time you crossed above or below the average which looked silly with our synthetic "constant sac" values as those are discrete and oscilate around the average. This also changes the order in which things are drawn so so that the pressure plot goes over the depth profile plot (so the red shading of the dive no longer changes the color of the tank pressure plot). Signed-off-by: Dirk Hohndel --- profile.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/profile.c b/profile.c index 9f8fa75b3..3b69f1839 100644 --- a/profile.c +++ b/profile.c @@ -620,14 +620,13 @@ static const rgb_t sac_color[SAC_COLORS] = { static void set_sac_color(struct graphics_context *gc, int sac, int avg_sac) { int sac_index = 0; - int delta = sac - avg_sac + 6000; + int delta = sac - avg_sac + 7000; sac_index = delta / 2000; if (sac_index < 0) sac_index = 0; if (sac_index > SAC_COLORS - 1) sac_index = SAC_COLORS - 1; - set_source_rgb_struct(gc, &sac_color[sac_index]); } @@ -1312,13 +1311,13 @@ void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, stru /* Temperature profile */ plot_temperature_profile(gc, pi); - /* Cylinder pressure plot */ - plot_cylinder_pressure(gc, pi, dive); - /* Depth profile */ plot_depth_profile(gc, pi); plot_events(gc, pi, dive); + /* Cylinder pressure plot */ + plot_cylinder_pressure(gc, pi, dive); + /* Text on top of all graphs.. */ plot_temperature_text(gc, pi); plot_depth_text(gc, pi); From e7491d3bf50ad31bbee38abc9da823c9cbdb9cd1 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 19 Nov 2011 14:43:37 -0500 Subject: [PATCH 4/4] Make pressure plot shading by sac rate consistent Some parts of the existing code used the depth at the time of the sample to calculate the sac rate - it makes much more sense to use the average depth. But that requires us to loop over the entries and average the individual sac rates per segment instead of just using the beginning and end depth of the multi-segment interval we use for smoothing purposes. This may seem like a subtle detail, but it does in fact matter when we plot the synthetic tank pressure values that we create when we have no tank pressure data in the samples. Another detail we change here is to not artificially start with a forward looking segment of the full SAC_WINDOW but instead just start with the first two data points and then simply let the time window grow until it hits SAC_WINDOW - at which point it becomes a sliding window. Signed-off-by: Dirk Hohndel --- profile.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/profile.c b/profile.c index 3b69f1839..9fab8b2e8 100644 --- a/profile.c +++ b/profile.c @@ -670,19 +670,19 @@ static void plot_cylinder_pressure(struct graphics_context *gc, struct plot_info last = i; last_entry = entry; if (first_plot) { - /* don't start with a sac of 0 */ - int fe = i + 1; - struct plot_data *future_entry = pi->entry + fe; - while (fe < pi->nr && future_entry->sec - entry->sec < SAC_WINDOW) { - fe++; - future_entry = pi->entry + fe; - } - sac = GET_LOCAL_SAC(entry, future_entry, dive); + /* don't start with a sac of 0, so just calculate the first one */ + sac = GET_LOCAL_SAC(entry, pi->entry + i + 1, dive); + } + } else { + int j; + sac = 0; + for (j = last; j < i; j++) + sac += GET_LOCAL_SAC(pi->entry + j, pi->entry + j + 1, dive); + sac /= (i - last); + if (entry->sec - last_entry->sec >= SAC_WINDOW) { + last++; + last_entry = pi->entry + last; } - } else if (entry->sec - last_entry->sec >= SAC_WINDOW) { - sac = GET_LOCAL_SAC(last_entry, entry, dive); - last++; - last_entry = pi->entry + last; } set_sac_color(gc, sac, dive->sac); if (lift_pen) { @@ -998,10 +998,11 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, list = NULL; continue; } - magic = (nlist->end - cur_pr[entry->cylinderindex]) / pt; } + magic = (nlist->end - cur_pr[entry->cylinderindex]) / pt; + } if (pt != 0.0) { double cur_pt = (entry->sec - (entry-1)->sec) * - (1 + entry->depth / 10000.0); + (1 + (entry->depth + (entry-1)->depth) / 20000.0); INTERPOLATED_PRESSURE(entry) = cur_pr[entry->cylinderindex] + cur_pt * magic; cur_pr[entry->cylinderindex] = INTERPOLATED_PRESSURE(entry); @@ -1217,7 +1218,7 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str } /* finally, do the discrete integration to get the SAC rate equivalent */ current->pressure_time += (entry->sec - (entry-1)->sec) * - (1 + entry->depth / 10000.0); + (1 + (entry->depth + (entry-1)->depth) / 20000.0); missing_pr |= !SENSOR_PRESSURE(entry); }