[PATCH] Split up helper functions for interpolating gas pressure

Linus Torvalds torvalds at linux-foundation.org
Sun Jan 6 18:40:44 PST 2013


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Sun, 6 Jan 2013 18:20:12 -0800
Subject: [PATCH] Split up helper functions for interpolating gas pressure

This splits up the function to create the estimated pressures for
missing tank pressure information.

The code now has a separate pass to create the beginning and ending
pressures for segments that lack them, and fill them in to match the
overall SAC-rate for that cylinder.

In the process, it also fixes the calculation of the interpolated gas
pressure: you can see this in test-dive 13, where we switch back to the
first tank at the end of the dive.  It used to be that the latter
segment of that cylinder showed in a different color from the first
segment, showing that we had a different SAC-rate.  But that makes no
sense, since our interpolation is supposed to use a constant SAC-rate
for each cylinder.

The bug was that the "magic" calculation (which is just the pressure
change rate over pressure-time) was incorrect, and used the current
cylinder pressure for start-pressure calculation.  But that's wrong,
since we update the current cylinder pressure as we go along, but we
didn't update the total pressure_time.

With the separate phase to calculate the segment beginning/ending
pressures, the code got simplified and the bug stood out more.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

Once more, this adds more lines than it removes, but I think the lines are 
simpler, and splitting the function made the different parts easier to 
understand (and showed a bug too). And many of the new lines are actually 
comments.

NOTE! The bug that test-dive #13 shows *used* to be invisible, because we 
used to have all this special case code for the end conditions, that got 
removed in the previous gas handling cleanups. 

So in a sense the bug was introduced by the other cleanups, but I am 
actually reasonably sure that it always existed before - it's just that it 
was hidden by the special cases. I think the special cases is why we also 
used to show the wrong pressures.

To give that dive13 as another example: if you go back to subsurface a day 
or two ago (without any of my plot-entry changes or the split up of the 
gas handling functions), you'll see the SAC-coding of the first and last 
segmetns agreeing like they should.

However, at the same time, the actual *values* it prints out are simply 
wrong. The cylinder start/end pressures for all the cylinders is supposed 
to be 2901/1450 psi: look at the equipment page. But that's not what the 
plot showed, because of all the special casing. So I think we had two bugs 
that basically were written to cancel each other out.

With this, the code actually makes sense, the SAC-rate coloring matches, 
and we get the right beginning ending values shown in the plot.

 profile.c | 177 ++++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 114 insertions(+), 63 deletions(-)

diff --git a/profile.c b/profile.c
index 6643e34cf185..51f8cc1e467f 100644
--- a/profile.c
+++ b/profile.c
@@ -1323,11 +1323,89 @@ static void dump_pr_track(pr_track_t **track_pr)
 	}
 }
 
-static void fill_missing_tank_pressures(struct plot_info *pi, pr_track_t **track_pr)
+/*
+ * This looks at the pressures for one cylinder, and
+ * calculates any missing beginning/end pressures for
+ * each segment by taking the over-all SAC-rate into
+ * account for that cylinder.
+ *
+ * NOTE! Many segments have full pressure information
+ * (both beginning and ending pressure). But if we have
+ * switched away from a cylinder, we will have the
+ * beginning pressure for the first segment with a
+ * missing end pressure. We may then have one or more
+ * segments without beginning or end pressures, until
+ * we finally have a segment with an end pressure.
+ *
+ * We want to spread out the pressure over these missing
+ * segments according to how big of a time_pressure area
+ * they have.
+ */
+static void fill_missing_segment_pressures(pr_track_t *list)
+{
+	while (list) {
+		int start = list->start, end;
+		pr_track_t *tmp = list;
+		double pt_sum = 0.0, pt = 0.0;
+
+		for (;;) {
+			pt_sum += tmp->pressure_time;
+			end = tmp->end;
+			if (end)
+				break;
+			end = start;
+			if (!tmp->next)
+				break;
+			tmp = tmp->next;
+		}
+
+		if (!start)
+			start = end;
+
+		/*
+		 * Now 'start' and 'end' contain the pressure values
+		 * for the set of segments described by 'list'..'tmp'.
+		 * pt_sum is the sum of all the pressure-times of the
+		 * segments.
+		 *
+		 * Now dole out the pressures relative to pressure-time.
+		 */
+		list->start = start;
+		tmp->end = end;
+		for (;;) {
+			int pressure;
+			pt += list->pressure_time;
+			pressure = start;
+			if (pt_sum)
+				pressure -= (start-end)*pt/pt_sum;
+			list->end = pressure;
+			if (list == tmp)
+				break;
+			list = list->next;
+			list->start = pressure;
+		}
+
+		/* Ok, we've done that set of segments */
+		list = list->next;
+	}
+}
+
+/*
+ * What's the pressure-time between two plot data entries?
+ * We're calculating the integral of pressure over time by
+ * adding these up.
+ */
+static inline double pressure_time(struct dive *dive, struct plot_data *a, struct plot_data *b)
+{
+	int time = b->sec - a->sec;
+	int depth = (a->depth + b->depth)/2;
+	int mbar = depth_to_mbar(depth, dive);
+
+	return bar_to_atm(mbar / 1000.0) * time;
+}
+
+static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr)
 {
-	pr_track_t *list = NULL;
-	pr_track_t *nlist = NULL;
-	double pt, magic;
 	int cyl, i;
 	struct plot_data *entry;
 	int cur_pr[MAX_CYLINDERS];
@@ -1337,57 +1415,44 @@ static void fill_missing_tank_pressures(struct plot_info *pi, pr_track_t **track
 		dump_pr_track(track_pr);
 	}
 	for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
+		fill_missing_segment_pressures(track_pr[cyl]);
 		cur_pr[cyl] = track_pr[cyl]->start;
 	}
 
 	/* The first two are "fillers", but in case we don't have a sample
 	 * at time 0 we need to process the second of them here */
 	for (i = 1; i < pi->nr; i++) {
+		double magic, cur_pt;
+		pr_track_t *segment;
+		int pressure;
+
 		entry = pi->entry + i;
+		cyl = entry->cylinderindex;
+
 		if (SENSOR_PRESSURE(entry)) {
-			cur_pr[entry->cylinderindex] = SENSOR_PRESSURE(entry);
-		} else {
-			if(!list || list->t_end < entry->sec) {
-				nlist = track_pr[entry->cylinderindex];
-				list = NULL;
-				while (nlist && nlist->t_start <= entry->sec) {
-					list = nlist;
-					nlist = list->next;
-				}
-				/* there may be multiple segments - so
-				 * let's assemble the length */
-				nlist = list;
-				if (list) {
-					pt = list->pressure_time;
-					while (!nlist->end) {
-						nlist = nlist->next;
-						if (!nlist) {
-							/* oops - we have no end pressure,
-							 * so this means this is a tank without
-							 * gas consumption information */
-							break;
-						}
-						pt += nlist->pressure_time;
-					}
-				}
-				if (!nlist) {
-					/* just continue without calculating
-					 * interpolated values */
-					INTERPOLATED_PRESSURE(entry) = cur_pr[entry->cylinderindex];
-					list = NULL;
-					continue;
-				}
-				magic = (nlist->end - cur_pr[entry->cylinderindex]) / pt;
-			}
-			if (pt != 0.0) {
-				double cur_pt = (entry->sec - (entry-1)->sec) *
-					(1 + (entry->depth + (entry-1)->depth) / 20000.0);
-				INTERPOLATED_PRESSURE(entry) =
-					cur_pr[entry->cylinderindex] + cur_pt * magic + 0.5;
-				cur_pr[entry->cylinderindex] = INTERPOLATED_PRESSURE(entry);
-			} else
-				INTERPOLATED_PRESSURE(entry) = cur_pr[entry->cylinderindex];
+			cur_pr[cyl] = SENSOR_PRESSURE(entry);
+			continue;
 		}
+
+		/* Find the right pressure segment for this entry.. */
+		segment = track_pr[cyl];
+		while (segment && segment->t_end < entry->sec)
+			segment = segment->next;
+
+		/* No (or empty) segment? Just use our current pressure */
+		if (!segment || !segment->pressure_time) {
+			SENSOR_PRESSURE(entry) = cur_pr[cyl];
+			continue;
+		}
+
+		/* Overall pressure change over total pressure-time for this segment*/
+		magic = (segment->end - segment->start) / segment->pressure_time;
+
+		/* Use that overall pressure change to update the current pressure */
+		cur_pt = pressure_time(dive, entry-1, entry);
+		pressure = cur_pr[cyl] + cur_pt * magic + 0.5;
+		INTERPOLATED_PRESSURE(entry) = pressure;
+		cur_pr[cyl] = pressure;
 	}
 }
 
@@ -1546,12 +1611,12 @@ static struct plot_data *populate_plot_entries(struct dive *dive, struct divecom
 		maxtime = dive->end;
 
 	/*
-	 * We want to have a plot_info event at least every 10s (so "maxtime/10"),
+	 * We want to have a plot_info event at least every 10s (so "maxtime/10+1"),
 	 * but samples could be more dense than that (so add in dc->samples), and
 	 * additionally we want two surface events around the whole thing (thus the
 	 * additional 4).
 	 */
-	nr = dc->samples + 4 + maxtime / 10;
+	nr = dc->samples + 5 + maxtime / 10;
 	plot_data = calloc(nr, sizeof(struct plot_data));
 	pi->entry = plot_data;
 	if (!plot_data)
@@ -1685,20 +1750,6 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc
 	} while ((secondary = secondary->next) != NULL);
 }
 
-/*
- * What's the pressure-time between two plot data entries?
- * We're calculating the integral of pressure over time by
- * adding these up.
- */
-static inline double pressure_time(struct dive *dive, struct plot_data *a, struct plot_data *b)
-{
-	int time = b->sec - a->sec;
-	int depth = (a->depth + b->depth)/2;
-	int mbar = depth_to_mbar(depth, dive);
-
-	return bar_to_atm(mbar / 1000.0) * time;
-}
-
 static void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
 {
 	int i, cylinderindex;
@@ -1759,7 +1810,7 @@ static void populate_pressure_information(struct dive *dive, struct divecomputer
 	}
 
 	if (missing_pr) {
-		fill_missing_tank_pressures(pi, track_pr);
+		fill_missing_tank_pressures(dive, pi, track_pr);
 	}
 	for (i = 0; i < MAX_CYLINDERS; i++)
 		list_free(track_pr[i]);
-- 
1.8.1.rc2.6.g18499ba



More information about the subsurface mailing list