[PATCH 2/2] Add initial rudimentary no-fly time calculation

Linus Torvalds torvalds at linux-foundation.org
Fri Feb 8 00:44:03 PST 2013


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Fri, 8 Feb 2013 17:49:51 +1100
Subject: [PATCH 2/2] Add initial rudimentary no-fly time calculation

NOTE NOTE NOTE! The numbers are interesting, and the math uses the exact
same Bühlmann algorithm that we use for diving, and that has been tested
at altitude - it's what people use for diving in mountain lakes after
all. So we can explain where these numbers come from.

But at the same time, this fixes the constants involved:

 - We assume the minimum pressurization level is 12000 ft.

   This is very conservative, since airlines generally pressurize their
   cabins to about 8000 ft, and sometimes as low as 5000.  But small
   planes can have lower cabin pressure, and obviously really small
   planes may be entirely unpressurized.

   We could easily make this configurable, this already calculates the
   flight pressure from the given altitude, we just happen to fix that
   altitude to 12000 ft.

 - We fix the gradient factors to 30/75 (which is also the default for
   diving).  We can't just let the user specify this willy-nilly,
   because that can cause the decompression calculations to never reach
   the required pressure tolerance.

Anyway, if you trust Bühlmann enough to dive with it, you should believe
that these no-fly times make some sense.  But maybe there's something
wrong with the calculations, so you should trust your dive computer
(which will almost certainly give *much* longer times - it's clear that
they add just tons of unexplained padding to this whole thing, and the
PADI 24-hour rule seems to be totally made up, probably more to do with
lawsuits than with any actual deco calculations).

People, please double-check my calculations.

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

Robert, Jan, could you please give this a look from the theoretical 
standpoint.. The code is pretty straightforward, and it actually all makes 
sense, and even the numbers make sense.

But the numbers - while making sense - are *so* totally not what the dive 
computers report. Some dive computers will give 24-hour no-fly times after 
every single dive, but using actual Buhlmann calculations makes most 
common recreational dives have no no-fly time at all, or very short times.

Sure, I can trigger 12-hour no-fly times with this: repeated dives will 
certainly do it. But even then it's much less than my Suunto will give me, 
for example. Now, Suunto's are known to be crazy about things like this, 
but I'd still like some deco people to take a second and third look. Ok?

 display.h |  1 +
 gtk-gui.c |  4 ----
 planner.c |  1 -
 prefs.c   |  1 -
 profile.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/display.h b/display.h
index 83f8ada8f62c..1dbfc04ec310 100644
--- a/display.h
+++ b/display.h
@@ -18,6 +18,7 @@ struct plot_info {
 	int meandepth, maxdepth;
 	int minpressure, maxpressure;
 	int mintemp, maxtemp;
+	int nofly;
 	double endtempcoord;
 	double maxpp;
 	gboolean has_ndl;
diff --git a/gtk-gui.c b/gtk-gui.c
index 20a2da824f31..dd515d37378a 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -522,7 +522,6 @@ static gboolean gflow_edit(GtkWidget *w, GdkEvent *event, gpointer _data)
 		buf = gtk_entry_get_text(GTK_ENTRY(w));
 		sscanf(buf, "%lf", &gflow);
 		prefs.gflow = gflow / 100.0;
-		set_gf(prefs.gflow, -1.0);
 		update_screen();
 	}
 	return FALSE;
@@ -536,7 +535,6 @@ static gboolean gfhigh_edit(GtkWidget *w, GdkEvent *event, gpointer _data)
 		buf = gtk_entry_get_text(GTK_ENTRY(w));
 		sscanf(buf, "%lf", &gfhigh);
 		prefs.gfhigh = gfhigh / 100.0;
-		set_gf(-1.0, prefs.gfhigh);
 		update_screen();
 	}
 	return FALSE;
@@ -885,7 +883,6 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
 		sscanf(gfhigh_text, "%lf", &prefs.gfhigh);
 		prefs.gflow /= 100.0;
 		prefs.gfhigh /= 100.0;
-		set_gf(prefs.gflow, prefs.gfhigh);
 
 		update_screen();
 
@@ -907,7 +904,6 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
 		save_preferences();
 	} else if (result == GTK_RESPONSE_CANCEL) {
 		prefs = oldprefs;
-		set_gf(prefs.gflow, prefs.gfhigh);
 		update_screen();
 	}
 	gtk_widget_destroy(dialog);
diff --git a/planner.c b/planner.c
index c972b0da01ec..e52db46763ea 100644
--- a/planner.c
+++ b/planner.c
@@ -1273,5 +1273,4 @@ void input_plan()
 		}
 	}
 	gtk_widget_destroy(planner);
-	set_gf(prefs.gflow, prefs.gfhigh);
 }
diff --git a/prefs.c b/prefs.c
index 7c833116f0f4..1e51d3556d4f 100644
--- a/prefs.c
+++ b/prefs.c
@@ -179,7 +179,6 @@ void load_preferences(void)
 		prefs.gfhigh /= 100.0;
 		free((void *)conf_value);
 	}
-	set_gf(prefs.gflow, prefs.gfhigh);
 
 	conf_value = subsurface_get_conf("divelist_font");
 	if (conf_value)
diff --git a/profile.c b/profile.c
index 86f7537aff43..e9fe3a4c93e8 100644
--- a/profile.c
+++ b/profile.c
@@ -1135,6 +1135,7 @@ static void plot_cylinder_pressure_text(struct graphics_context *gc, struct plot
 
 static void plot_deco_text(struct graphics_context *gc, struct plot_info *pi)
 {
+	int nofly = pi->nofly;
 	if (prefs.profile_calc_ceiling) {
 		float x = gc->leftx + (gc->rightx - gc->leftx) / 2;
 		float y = gc->topy = 1.0;
@@ -1142,6 +1143,17 @@ static void plot_deco_text(struct graphics_context *gc, struct plot_info *pi)
 		gc->bottomy = 0.0;
 		plot_text(gc, &tro, x, y, "GF %.0f/%.0f", prefs.gflow * 100, prefs.gfhigh * 100);
 	}
+	/*
+	 * If you can get into the air in less than half an hour after diving, you're doing
+	 * something odd. So we don't bother showing no-fly times of 15 minutes or less.
+	 */
+	if (nofly > 15) {
+		float x = gc->rightx;
+		float y = gc->topy = 1.0;
+		text_render_options_t tro = {10, PRESSURE_TEXT, RIGHT, -0.2};
+		gc->bottomy = 0.0;
+		plot_text(gc, &tro, x, y, "NoFly %d:%02d", nofly / 60, nofly % 60);
+	}
 }
 
 static void analyze_plot_info_minmax_minute(struct plot_data *entry, struct plot_data *first, struct plot_data *last, int index)
@@ -1810,12 +1822,27 @@ static void populate_pressure_information(struct dive *dive, struct divecomputer
 		list_free(track_pr[i]);
 }
 
-static void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
+/* Don't sue me: flight altitudes are done in feet. Deal with it */
+static double air_pressure(int feet)
+{
+	double h = feet_to_mm(feet) / 1000.0;
+	double p0 = SURFACE_PRESSURE / 1000.0;
+	double g = 9.80665;	/* Standard acceleration */
+	double M = 0.0289644;	/* mass of dry air */
+	double R = 8.31447;	/* gas constant */
+	double T0 = 288.15;	/* Standard temperature in kelvin */
+
+	return p0 * exp(-g*M*h/(R*T0));
+}
+
+static int calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
 {
 	int i;
 	double amb_pressure;
 	double surface_pressure = (dive->dc.surface_pressure.mbar ? dive->dc.surface_pressure.mbar : SURFACE_PRESSURE) / 1000.0;
+	double flight_pressure;
 
+	set_gf(prefs.gflow, prefs.gfhigh);
 	for (i = 1; i < pi->nr; i++) {
 		int fo2, fhe, j, t0, t1;
 		double tissue_tolerance;
@@ -1889,6 +1916,28 @@ static void calculate_deco_information(struct dive *dive, struct divecomputer *d
 #if DECO_CALC_DEBUG & 1
 	dump_tissues();
 #endif
+
+	/* The nofly gradient factors are fixed - otherwise you can get infinite nofly's */
+#define NOFLY_GFLOW	0.30
+#define NOFLY_GFHIGH	0.75
+
+	set_gf(NOFLY_GFLOW, NOFLY_GFHIGH);
+
+	/* Airlines generally pressurize to 8000 or 8500 ft, but let's add some slack */
+	flight_pressure = air_pressure(12000);
+
+	/* Do things in 5-minute increments */
+	for (i = 1; ;i++) {
+		static const struct gasmix air = { .o2 = { O2_IN_AIR } };
+		double pressure = SURFACE_PRESSURE / 1000.0;
+		double tolerance = add_segment(pressure, &air, 5*60, 0, dive);
+
+		if (tolerance < flight_pressure)
+			break;
+	}
+
+	/* We return no-fly time in minutes */
+	return i*5;
 }
 
 /*
@@ -1923,7 +1972,7 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
 	populate_pressure_information(dive, dc, pi);
 
 	/* Then, calculate partial pressures and deco information */
-	calculate_deco_information(dive, dc, pi);
+	pi->nofly = calculate_deco_information(dive, dc, pi);
 	pi->meandepth = dive->dc.meandepth.mm;
 
 	if (0) /* awesome for debugging - not useful otherwise */
-- 
1.8.1.3.535.ga923c31



More information about the subsurface mailing list