SAC and Gas Consumed Calculation

Linus Torvalds torvalds at linux-foundation.org
Tue Feb 11 13:08:29 UTC 2014


On Tue, Feb 11, 2014 at 12:46 PM, Linus Torvalds
<torvalds at linux-foundation.org> wrote:
>
>> Note that the SAC is reported differently in the info panel, as opposed to
>> the dive live (when that column is added), which appears to out by the 1.013
>> factor.
>
> Ok, so it sounds like we have a real bug. Let me check that.

Ok, spot the bug..

So the SAC text in the dive info view does this (for each cylinder):

    sac.mliter = gases[i].mliter * 1000.0 / (depth_to_mbar(mean[i], d)
* duration[i] / 60);

but "calculate_sac()" in divelist.c does:

    pressure = (double) depth_to_mbar(meandepth, dive) / SURFACE_PRESSURE;
    sac = airuse / pressure * 60 / duration;

and the divelist is correct. SAC is calculated in relationship to
surface pressure, not "1 bar". Embarrassing.

I also realize that we have a few other cases where we do the same
mistake: the partial pressure calculations do things like

    po2 = o2 / 1000.0 * depth_to_mbar(sample->depth.mm, dive);

which is wrong as well - the partial pressure is also relative to
standard atmospheric pressures.

The attached patch should fix it. Dirk, feel free to add my sign-off
and some commit message ("Fix ATM-vs-bar confusion")

                  Linus
-------------- next part --------------
 dive.h            | 10 ++++++++++
 divelist.c        |  6 +++---
 profile.c         |  2 +-
 qt-ui/maintab.cpp |  4 ++--
 4 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/dive.h b/dive.h
index 625ea4351973..5a7338fff270 100644
--- a/dive.h
+++ b/dive.h
@@ -223,6 +223,11 @@ static inline double bar_to_atm(double bar)
 	return bar / SURFACE_PRESSURE * 1000;
 }
 
+static inline double mbar_to_atm(int mbar)
+{
+	return (double) mbar / SURFACE_PRESSURE;
+}
+
 /* Volume in mliter of a cylinder at pressure 'p' */
 extern int gas_volume(cylinder_t *cyl, pressure_t p);
 extern int wet_volume(double cuft, pressure_t p);
@@ -450,6 +455,11 @@ static inline int depth_to_mbar(int depth, struct dive *dive)
 	return calculate_depth_to_mbar(depth, dive->surface_pressure, dive->salinity);
 }
 
+static inline double depth_to_atm(int depth, struct dive *dive)
+{
+	return mbar_to_atm(depth_to_mbar(depth, dive));
+}
+
 /* for the inverse calculation we use just the relative pressure
  * (that's the one that some dive computers like the Uemis Zurich
  * provide - for the other models that do this libdivecomputer has to
diff --git a/divelist.c b/divelist.c
index b16c9e513f3e..a9a2b451c057 100644
--- a/divelist.c
+++ b/divelist.c
@@ -221,7 +221,7 @@ static int calculate_otu(struct dive *dive)
 			po2 = sample->po2;
 		} else {
 			int o2 = active_o2(dive, dc, sample->time);
-			po2 = o2 / 1000.0 * depth_to_mbar(sample->depth.mm, dive);
+			po2 = o2 * depth_to_atm(sample->depth.mm, dive);
 		}
 		if (po2 >= 500)
 			otu += pow((po2 - 500) / 1000.0, 0.83) * t / 30.0;
@@ -285,7 +285,7 @@ static int calculate_cns(struct dive *dive)
 			po2 = sample->po2;
 		} else {
 			int o2 = active_o2(dive, dc, sample->time);
-			po2 = o2 / 1000.0 * depth_to_mbar(sample->depth.mm, dive);
+			po2 = o2 / depth_to_atm(sample->depth.mm, dive);
 		}
 		/* Find what table-row we should calculate % for */
 		for (j = 1; j < sizeof(cns_table)/(sizeof(int) * 3); j++)
@@ -338,7 +338,7 @@ static int calculate_sac(struct dive *dive)
 		return 0;
 
 	/* Mean pressure in ATM (SAC calculations are in atm*l/min) */
-	pressure = (double) depth_to_mbar(meandepth, dive) / SURFACE_PRESSURE;
+	pressure = depth_to_atm(meandepth, dive);
 	sac = airuse / pressure * 60 / duration;
 
 	/* milliliters per minute.. */
diff --git a/profile.c b/profile.c
index 14b76f70e239..07328580f982 100644
--- a/profile.c
+++ b/profile.c
@@ -226,7 +226,7 @@ static int get_local_sac(struct plot_data *entry1, struct plot_data *entry2, str
 
 	/* Mean pressure in ATM */
 	depth = (entry1->depth + entry2->depth) / 2;
-	atm = (double) depth_to_mbar(depth, dive) / SURFACE_PRESSURE;
+	atm = depth_to_atm(depth, dive);
 
 	cyl = dive->cylinder + index;
 
diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp
index 0aa683dcb487..8543597d94cd 100644
--- a/qt-ui/maintab.cpp
+++ b/qt-ui/maintab.cpp
@@ -475,7 +475,7 @@ void MainTab::updateDiveInfo(int dive)
 		volume_t sac;
 		QString SACs;
 		if (mean[0] && duration[0]) {
-			sac.mliter = gases[0].mliter * 1000.0 / (depth_to_mbar(mean[0], d) * duration[0] / 60.0);
+			sac.mliter = gases[0].mliter / (depth_to_atm(mean[0], d) * duration[0] / 60.0);
 			SACs = get_volume_string(sac, true).append(tr("/min"));
 		} else {
 			SACs = QString(tr("unknown"));
@@ -483,7 +483,7 @@ void MainTab::updateDiveInfo(int dive)
 		for(int i=1; i < MAX_CYLINDERS && gases[i].mliter != 0; i++) {
 			volumes.append("\n" + get_volume_string(gases[i], true));
 			if (duration[i]) {
-				sac.mliter = gases[i].mliter * 1000.0 / (depth_to_mbar(mean[i], d) * duration[i] / 60);
+				sac.mliter = gases[i].mliter / (depth_to_atm(mean[i], d) * duration[i] / 60);
 				SACs.append("\n" + get_volume_string(sac, true).append(tr("/min")));
 			} else {
 				SACs.append("\n");


More information about the subsurface mailing list