Correctly calculate SAC rate in the presense of surface events

This assumes that you are not breathing your cylinders while at the
surface, which may or may not be correct, but is usually the right
thing.  Regardless, we're better off giving a conservative (higher) SAC
rate estimate for a diver that breathes his cylinder at the surface too
than giving an artificially low one because the diver ended up using his
snorkel and we didn't take that into account.

NOTE! This basically calculates a better duration and average depth than
the ones we end up showing in the dive list.  Maybe we should actually
show this "no-surface-time" duration and average depth instead of the
ones we do show?

That's a separate question, though.

Added a test-case for the surface case to the sac-test.xml dives.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Linus Torvalds 2013-02-24 10:50:18 -08:00 committed by Dirk Hohndel
parent f4bf16d5db
commit 6d548d2028
2 changed files with 65 additions and 19 deletions

View file

@ -719,38 +719,65 @@ static double calculate_airuse(struct dive *dive)
return airuse;
}
/*
* Calculate how long we were actually under water, and the average
* depth while under water.
*
* This ignores any surface time in the middle of the dive.
*/
static int calculate_duration(struct dive *dive, struct divecomputer *dc, int *meandepth)
{
int duration, i;
int lasttime, lastdepth, depthtime;
duration = 0;
lasttime = 0;
lastdepth = 0;
depthtime = 0;
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
int time = sample->time.seconds;
int depth = sample->depth.mm;
/* We ignore segments at the surface */
if (depth > SURFACE_THRESHOLD || lastdepth > SURFACE_THRESHOLD) {
duration += time - lasttime;
depthtime += (time - lasttime)*(depth+lastdepth)/2;
}
lastdepth = depth;
lasttime = time;
}
if (duration) {
if (meandepth)
*meandepth = depthtime / duration;
return duration;
}
/* No samples? */
if (meandepth)
*meandepth = dive->meandepth.mm;
return dive->duration.seconds;
}
/* this only uses the first divecomputer to calculate the SAC rate */
static int calculate_sac(struct dive *dive)
{
struct divecomputer *dc = &dive->dc;
double airuse, pressure, sac;
int duration, i;
int duration, meandepth;
airuse = calculate_airuse(dive);
if (!airuse)
return 0;
duration = dc->duration.seconds;
duration = calculate_duration(dive, dc, &meandepth);
/* find and eliminate long surface intervals */
if (!duration)
return 0;
/* find and eliminate long surface intervals */
for (i = 0; i < dc->samples; i++) {
if (dc->sample[i].depth.mm < 100) { /* less than 10cm */
int end = i + 1;
while (end < dc->samples && dc->sample[end].depth.mm < 100)
end++;
/* we only want the actual surface time during a dive */
if (end < dc->samples) {
end--;
duration -= dc->sample[end].time.seconds -
dc->sample[i].time.seconds;
i = end + 1;
}
}
}
/* Mean pressure in ATM (SAC calculations are in atm*l/min) */
pressure = (double) depth_to_mbar(dc->meandepth.mm, dive) / SURFACE_PRESSURE;
pressure = (double) depth_to_mbar(meandepth, dive) / SURFACE_PRESSURE;
sac = airuse / pressure * 60 / duration;
/* milliliters per minute.. */

View file

@ -46,5 +46,24 @@ We have exactly 100 ATM of gas in 15l of cylinder, average 20m for 25min</notes>
<sample time='25:00 min' depth='0.0 m' />
</divecomputer>
</dive>
<dive number='4' date='2013-02-24' time='12:26:04' duration='25:00 min'>
<location>SAC test dive 3</location>
<notes>SAC should be 20l/min (0.7063 cuft/min)
This adds a 5-minute surface time to the middle of the dive.
We have exactly 100 ATM of gas in 15l of cylinder, average 20m for 25min</notes>
<cylinder size='10 l' description='10l' start='202.6 bar' end='101.3 bar' />
<cylinder size='5 l' description='10l' start='202.6 bar' end='101.3 bar' />
<divecomputer>
<event time='22:00 min' name='gaschange' />
<depth max='20.0 m' mean='10.0 m' />
<sample time='0:00 min' depth='0.0 m' />
<sample time='5:00 min' depth='20.0 m' />
<sample time='10:00 min' depth='40.0 m' />
<sample time='15:00 min' depth='0.0 m' />
<sample time='20:00 min' depth='0.0 m' />
<sample time='25:00 min' depth='40.0 m' />
<sample time='30:00 min' depth='0.0 m' />
</divecomputer>
</dive>
</dives>
</divelog>