aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2017-07-28 11:25:42 -0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2017-07-28 21:50:23 -0700
commitdf1bd0015a2f69429116c29d6e7818a33a9070b0 (patch)
tree892769b3c77da70a32332dda9c5820515ce1533e /core
parentdefa71256fe16de32f69e78657c807828b7488bd (diff)
downloadsubsurface-df1bd0015a2f69429116c29d6e7818a33a9070b0.tar.gz
Calculate momentary SAC rates with the right gases
The momentary SAC rate got broken by the multiple ressure handling too, and always used just the first cylinder. This uses the new "get_gasmix()" helper to see what you're breathing, and will do the SAC rate over all the cylinders that contain that gas. So it should now DTRT even for sidemount diving (assuming you had the same gas in the sidemount cylinders). NOTE! We could just do the SAC rate over *all* the gases you have pressures for, and maybe that's the right thing to do. The ones you are not breating from shouldn't have their pressure change. But maybe some people add their drysuit argon gas to the gas list? So this may need more work, but it's a step in the right direction. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'core')
-rw-r--r--core/dive.c2
-rw-r--r--core/dive.h3
-rw-r--r--core/profile.c107
3 files changed, 83 insertions, 29 deletions
diff --git a/core/dive.c b/core/dive.c
index d07a9d2aa..7f89e5063 100644
--- a/core/dive.c
+++ b/core/dive.c
@@ -2071,7 +2071,7 @@ static void cylinder_renumber(struct dive *dive, int mapping[])
dc_cylinder_renumber(dive, dc, mapping);
}
-static int same_gasmix(struct gasmix *a, struct gasmix *b)
+int same_gasmix(struct gasmix *a, struct gasmix *b)
{
if (gasmix_is_air(a) && gasmix_is_air(b))
return 1;
diff --git a/core/dive.h b/core/dive.h
index d19ccca4d..350331d95 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -140,8 +140,7 @@ extern int gas_volume(cylinder_t *cyl, pressure_t p);
extern double gas_compressibility_factor(struct gasmix *gas, double bar);
extern double isothermal_pressure(struct gasmix *gas, double p1, int volume1, int volume2);
extern double gas_density(struct gasmix *gas, int pressure);
-
-
+extern int same_gasmix(struct gasmix *a, struct gasmix *b);
static inline int get_o2(const struct gasmix *mix)
{
diff --git a/core/profile.c b/core/profile.c
index 6e62ac499..cb11251cf 100644
--- a/core/profile.c
+++ b/core/profile.c
@@ -637,26 +637,34 @@ struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer *
/*
* Calculate the sac rate between the two plot entries 'first' and 'last'.
*
- * Everything in between has a cylinder pressure, and it's all the same
- * cylinder.
+ * Everything in between has a cylinder pressure for at least some of the cylinders.
*/
-static int sac_between(struct dive *dive, struct plot_data *first, struct plot_data *last)
+static int sac_between(struct dive *dive, struct plot_data *first, struct plot_data *last, unsigned int gases)
{
- int sensor = 0;
- int airuse;
+ int i, airuse;
double pressuretime;
- pressure_t a, b;
- cylinder_t *cyl;
if (first == last)
return 0;
- /* Calculate air use - trivial */
- a.mbar = GET_PRESSURE(first, sensor);
- b.mbar = GET_PRESSURE(last, sensor);
- cyl = dive->cylinder + sensor;
- airuse = gas_volume(cyl, a) - gas_volume(cyl, b);
- if (airuse <= 0)
+ /* Get airuse for the set of cylinders over the range */
+ airuse = 0;
+ for (i = 0; i < MAX_CYLINDERS; i++) {
+ pressure_t a, b;
+ cylinder_t *cyl;
+ int cyluse;
+
+ if (!(gases & (1u << i)))
+ continue;
+
+ a.mbar = GET_PRESSURE(first, i);
+ b.mbar = GET_PRESSURE(last, i);
+ cyl = dive->cylinder + i;
+ cyluse = gas_volume(cyl, a) - gas_volume(cyl, b);
+ if (cyluse > 0)
+ airuse += cyluse;
+ }
+ if (!airuse)
return 0;
/* Calculate depthpressure integrated over time */
@@ -676,26 +684,45 @@ static int sac_between(struct dive *dive, struct plot_data *first, struct plot_d
return lrint(airuse / pressuretime);
}
+/* Which of the set of gases have pressure data */
+static unsigned int have_pressures(struct plot_data *entry, unsigned int gases)
+{
+ int i;
+
+ for (i = 0; i < MAX_CYLINDERS; i++) {
+ unsigned int mask = 1 << i;
+ if (gases & mask) {
+ if (!GET_PRESSURE(entry, i))
+ gases &= ~mask;
+ }
+ }
+ return gases;
+}
+
/*
* Try to do the momentary sac rate for this entry, averaging over one
* minute.
*/
-static void fill_sac(struct dive *dive, struct plot_info *pi, int idx)
+static void fill_sac(struct dive *dive, struct plot_info *pi, int idx, unsigned int gases)
{
struct plot_data *entry = pi->entry + idx;
struct plot_data *first, *last;
- int sensor = 0;
int time;
if (entry->sac)
return;
- if (!GET_PRESSURE(entry, 0))
+ /*
+ * We may not have pressure data for all the cylinders,
+ * but we'll calculate the SAC for the ones we do have.
+ */
+ gases = have_pressures(entry, gases);
+ if (!gases)
return;
/*
* Try to go back 30 seconds to get 'first'.
- * Stop if the sensor changed, or if we went back too far.
+ * Stop if the cylinder pressure data set changes.
*/
first = entry;
time = entry->sec - 30;
@@ -706,7 +733,7 @@ static void fill_sac(struct dive *dive, struct plot_info *pi, int idx)
break;
if (prev->sec < time)
break;
- if (!GET_PRESSURE(prev, sensor))
+ if (have_pressures(prev, gases) != gases)
break;
idx--;
first = prev;
@@ -721,19 +748,47 @@ static void fill_sac(struct dive *dive, struct plot_info *pi, int idx)
break;
if (next->sec > time)
break;
- if (!GET_PRESSURE(next, sensor))
+ if (have_pressures(next, gases) != gases)
break;
last = next;
}
/* Ok, now calculate the SAC between 'first' and 'last' */
- entry->sac = sac_between(dive, first, last);
+ entry->sac = sac_between(dive, first, last, gases);
}
-static void calculate_sac(struct dive *dive, struct plot_info *pi)
+/*
+ * Create a bitmap of cylinders that match our current gasmix
+ */
+static unsigned int matching_gases(struct dive *dive, struct gasmix *gasmix)
+{
+ int i;
+ unsigned int gases = 0;
+
+ for (i = 0; i < MAX_CYLINDERS; i++) {
+ cylinder_t *cyl = dive->cylinder + i;
+ if (same_gasmix(gasmix, &cyl->gasmix))
+ gases |= 1 << i;
+ }
+ return gases;
+}
+
+static void calculate_sac(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
{
- for (int i = 0; i < pi->nr; i++)
- fill_sac(dive, pi, i);
+ struct gasmix *gasmix = NULL;
+ struct event *ev = NULL;
+ unsigned int gases = 0;
+
+ for (int i = 0; i < pi->nr; i++) {
+ struct plot_data *entry = pi->entry + i;
+ struct gasmix *newmix = get_gasmix(dive, dc, entry->sec, &ev, gasmix);
+ if (newmix != gasmix) {
+ gasmix = newmix;
+ gases = matching_gases(dive, newmix);
+ }
+
+ fill_sac(dive, pi, i, gases);
+ }
}
static void populate_secondary_sensor_data(struct divecomputer *dc, struct plot_info *pi)
@@ -1125,7 +1180,7 @@ static void calculate_gas_information_new(struct dive *dive, struct divecomputer
}
}
-void fill_o2_values(struct divecomputer *dc, struct plot_info *pi, struct dive *dive)
+void fill_o2_values(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
/* In the samples from each dive computer, there may be uninitialised oxygen
* sensor or setpoint values, e.g. when events were inserted into the dive log
* or if the dive computer does not report o2 values with every sample. But
@@ -1222,8 +1277,8 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo
for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++)
populate_pressure_information(dive, dc, pi, cyl);
}
- fill_o2_values(dc, pi, dive); /* .. and insert the O2 sensor data having 0 values. */
- calculate_sac(dive, pi); /* Calculate sac */
+ fill_o2_values(dive, dc, pi); /* .. and insert the O2 sensor data having 0 values. */
+ calculate_sac(dive, dc, pi); /* Calculate sac */
#ifndef SUBSURFACE_MOBILE
calculate_deco_information(dive, dc, pi, false); /* and ceiling information, using gradient factor values in Preferences) */
#endif