]> git.tdb.fi Git - ext/subsurface.git/commitdiff
Color pressure plot according to current SAC rate
authorDirk Hohndel <dirk@hohndel.org>
Thu, 17 Nov 2011 02:34:50 +0000 (00:34 -0200)
committerDirk Hohndel <dirk@hohndel.org>
Thu, 17 Nov 2011 20:13:10 +0000 (18:13 -0200)
Similar to color indicating vertical speed in the profile plot we now use
color in the tank pressure plot to indicate current SAC rate.

We use a 45 sec sliding window to make sure we cover at least two breaths
for each current SAC sample to avoid artificial oscillation based on
breathing rhythm for corputers with high sample resolution.

Not sure about the color coding that I'm using right now - it's green-ish
for SAC rates under 15l/min ~= .55cuft/min and turns yellow and red as you
go higher. That seems to work well for me, but for other divers this may
be way off (or at least not as useful). Maybe this should be configurable?
This is a lot more diver specific than the vertical velocity where there
are clear recommendations based on safety considerations on what is good
and bad.

As a side effect, this removes the color coding that showed you whether
you were looking at pressure data from samples (green) vs. interpolated
pressure data (yellow). Not sure if people really want to see that. We
might be able to indicate this differently (I am thinking different line
width or transparency or something along those line)

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
profile.c

index f0ae0c9311c5eba3c3bc24130c01d8b02c36eb59..88e86941b40a0082788f74a1562b6b3449f7503f 100644 (file)
--- a/profile.c
+++ b/profile.c
@@ -44,6 +44,7 @@ struct plot_info {
 #define INTERPOLATED_PR 1
 #define SENSOR_PRESSURE(_entry) (_entry)->pressure[SENSOR_PR]
 #define INTERPOLATED_PRESSURE(_entry) (_entry)->pressure[INTERPOLATED_PR]
+#define GET_PRESSURE(_entry) (SENSOR_PRESSURE(_entry) ? : INTERPOLATED_PRESSURE(_entry))
 
 /* convert velocity to colors */
 typedef struct { double r, g, b; } rgb_t;
@@ -594,55 +595,103 @@ static int get_cylinder_pressure_range(struct graphics_context *gc, struct plot_
        return pi->maxpressure != 0;
 }
 
-static void plot_pressure_helper(struct graphics_context *gc, struct plot_info *pi, int type)
+/* set the color for the pressure plot according to temporary sac rate */
+static void set_sac_color(struct graphics_context *gc, double sac)
+{
+       if (sac < 9)
+               set_source_rgba(gc, 0.0, 0.4, 0.2, 0.80);
+       else if (sac < 11)
+               set_source_rgba(gc, 0.2, 0.6, 0.2, 0.80);
+       else if (sac < 13)
+               set_source_rgba(gc, 0.4, 0.8, 0.2, 0.80);
+       else if (sac < 15)
+               set_source_rgba(gc, 0.6, 0.8, 0.2, 0.80);
+       else if (sac < 17)
+               set_source_rgba(gc, 0.8, 0.8, 0.2, 0.80);
+       else if (sac < 19)
+               set_source_rgba(gc, 0.8, 0.6, 0.2, 0.80);
+       else if (sac < 21)
+               set_source_rgba(gc, 0.8, 0.4, 0.2, 0.80);
+       else if (sac < 23)
+               set_source_rgba(gc, 0.9, 0.3, 0.2, 0.80);
+       else
+               set_source_rgba(gc, 1.0, 0.2, 0.2, 0.80);
+}
+
+/* calculate the current SAC in l/min */
+#define GET_LOCAL_SAC(_entry1, _entry2, _dive)                                 \
+       ((GET_PRESSURE((_entry1)) - GET_PRESSURE((_entry2))) *                  \
+               (_dive)->cylinder[(_entry1)->cylinderindex].type.size.mliter /  \
+               (((_entry2)->sec - (_entry1)->sec) / 60.0) /                    \
+               (1 + ((_entry1)->depth + (_entry2)->depth) / 20000.0) /         \
+               1000000.0)
+
+#define SAC_WINDOW 45  /* sliding window in seconds for current SAC calculation */
+
+static void plot_cylinder_pressure(struct graphics_context *gc, struct plot_info *pi,
+                               struct dive *dive)
 {
        int i;
+       int last = -1;
        int lift_pen = FALSE;
+       int first_plot = TRUE;
+       double sac = 0.0;
+       struct plot_data *last_entry = NULL;
+
+       if (!get_cylinder_pressure_range(gc, pi))
+               return;
 
        for (i = 0; i < pi->nr; i++) {
                int mbar;
                struct plot_data *entry = pi->entry + i;
 
-               mbar = entry->pressure[type];
-               if (!entry->same_cylinder)
+               mbar = GET_PRESSURE(entry);
+               if (!entry->same_cylinder) {
                        lift_pen = TRUE;
+                       last_entry = NULL;
+               }
                if (!mbar) {
                        lift_pen = TRUE;
                        continue;
                }
+               if (!last_entry) {
+                       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);
+                       }
+               } 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);
                if (lift_pen) {
-                       if (i > 0 && entry->same_cylinder) {
+                       if (!first_plot && entry->same_cylinder) {
                                /* if we have a previous event from the same tank,
-                                * draw at least a short line .
-                                * This uses the implementation detail that the
-                                * type is either 0 or 1 */
+                                * draw at least a short line */
                                int prev_pr;
-                               prev_pr = (entry-1)->pressure[type] ? : (entry-1)->pressure[1 - type];
+                               prev_pr = GET_PRESSURE(entry - 1);
                                move_to(gc, (entry-1)->sec, prev_pr);
                                line_to(gc, entry->sec, mbar);
-                       } else
+                       } else {
+                               first_plot = FALSE;
                                move_to(gc, entry->sec, mbar);
+                       }
                        lift_pen = FALSE;
-               }
-               else
+               } else {
                        line_to(gc, entry->sec, mbar);
+               }
+               cairo_stroke(gc->cr);
+               move_to(gc, entry->sec, mbar);
        }
-       cairo_stroke(gc->cr);
-
-}
-
-static void plot_cylinder_pressure(struct graphics_context *gc, struct plot_info *pi)
-{
-       if (!get_cylinder_pressure_range(gc, pi))
-               return;
-
-       /* first plot the pressure readings we have from the dive computer */
-       set_source_rgba(gc, 0.2, 1.0, 0.2, 0.80);
-       plot_pressure_helper(gc, pi, SENSOR_PR);
-
-       /* then, in a different color, the interpolated values */
-       set_source_rgba(gc, 1.0, 1.0, 0.2, 0.80);
-       plot_pressure_helper(gc, pi, INTERPOLATED_PR);
 }
 
 static void plot_pressure_value(struct graphics_context *gc, int mbar, int sec,
@@ -656,8 +705,6 @@ static void plot_pressure_value(struct graphics_context *gc, int mbar, int sec,
        plot_text(gc, &tro, sec, mbar, "%d %s", pressure, unit);
 }
 
-#define GET_PRESSURE(_entry) (SENSOR_PRESSURE(_entry) ? : INTERPOLATED_PRESSURE(_entry))
-
 static void plot_cylinder_pressure_text(struct graphics_context *gc, struct plot_info *pi)
 {
        int i;
@@ -1253,7 +1300,7 @@ void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, stru
        plot_temperature_profile(gc, pi);
 
        /* Cylinder pressure plot */
-       plot_cylinder_pressure(gc, pi);
+       plot_cylinder_pressure(gc, pi, dive);
 
        /* Depth profile */
        plot_depth_profile(gc, pi);