summaryrefslogtreecommitdiffstats
path: root/divelist.c
diff options
context:
space:
mode:
authorGravatar Anton Lundin <glance@acc.umu.se>2013-04-09 19:25:21 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2013-04-23 20:43:34 -0700
commitee0025f69687af08347de738dcd2d2dc9ebc6365 (patch)
treef9c50e4b7b5cbbf2c3a0bda3cc2de690638dbcee /divelist.c
parent8cdb8364008487753d9e8f31f9165048f827f2d1 (diff)
downloadsubsurface-ee0025f69687af08347de738dcd2d2dc9ebc6365.tar.gz
Add a simple table-based cns calculations
For dives where divecomputers haven't provided us with a cns, we calculate our cns accumulated during that dive based on a simple table. We also check if we did a dive in the prior 12 ours and grab the cns from it and calculate how much of that still affects us. [Dirk Hohndel: a couple of small changes: remove unnecessary check of cns values in the samples of the first dive computer, changed the way we determine the 'previous dive' and used the end time of that previous dive for the decay calculation] Signed-off-by: Anton Lundin <glance@acc.umu.se> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'divelist.c')
-rw-r--r--divelist.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/divelist.c b/divelist.c
index 42fb272b0..577750399 100644
--- a/divelist.c
+++ b/divelist.c
@@ -273,7 +273,7 @@ static int active_o2(struct dive *dive, struct divecomputer *dc, duration_t time
return o2permille;
}
-/* calculate OTU for a dive - this only takes the first diveomputer into account */
+/* calculate OTU for a dive - this only takes the first divecomputer into account */
static int calculate_otu(struct dive *dive)
{
int i;
@@ -297,6 +297,74 @@ static int calculate_otu(struct dive *dive)
}
return otu + 0.5;
}
+/* calculate CNS for a dive - this only takes the first divecomputer into account */
+int const cns_table[][3] = {
+/* po2, Maximum Single Exposure, Maximum 24 hour Exposure */
+ {1600, 45 * 60, 150 * 60},
+ {1500, 120 * 60, 180 * 60},
+ {1400, 150 * 60, 180 * 60},
+ {1300, 180 * 60, 210 * 60},
+ {1200, 210 * 60, 240 * 60},
+ {1100, 240 * 60, 270 * 60},
+ {1000, 300 * 60, 300 * 60},
+ { 900, 360 * 60, 360 * 60},
+ { 800, 450 * 60, 450 * 60},
+ { 700, 570 * 60, 570 * 60},
+ { 600, 720 * 60, 720 * 60}
+};
+
+/* this only gets called if dive->maxcns == 0 which means we know that
+ * none of the divecomputers has tracked any CNS for us
+ * so we calculated it "by hand" */
+static int calculate_cns(struct dive *dive)
+{
+ int i, j, divenr;
+ double cns = 0.0;
+ struct divecomputer *dc = &dive->dc;
+ struct dive *prev_dive;
+ timestamp_t endtime;
+
+ /* shortcut */
+ if (dive->cns)
+ return dive->cns;
+ /*
+ * Do we start with a cns loading from a privious dive?
+ * Check if we did a dive 12 hours prior, and what cns we had from that.
+ * Then apply ha 90min halftime to see whats left.
+ */
+ divenr = get_divenr(dive);
+ if (divenr) {
+ prev_dive = get_dive(divenr -1 );
+ endtime = prev_dive->when + prev_dive->duration.seconds;
+ if (prev_dive && dive->when < (endtime + 3600 * 12)) {
+ cns = calculate_cns(prev_dive);
+ cns = cns * 1/pow(2, (dive->when - endtime) / (90.0 * 60.0));
+ }
+ }
+ /* Caclulate the cns for each sample in this dive and sum them */
+ for (i = 1; i < dc->samples; i++) {
+ int t;
+ int po2;
+ struct sample *sample = dc->sample + i;
+ struct sample *psample = sample - 1;
+ t = sample->time.seconds - psample->time.seconds;
+ if (sample->po2) {
+ po2 = sample->po2;
+ } else {
+ int o2 = active_o2(dive, dc, sample->time);
+ po2 = o2 / 1000.0 * depth_to_mbar(sample->depth.mm, dive);
+ }
+ /* Find what table-row we should calculate % for */
+ for (j = 1; j < sizeof(cns_table)/(sizeof(int) * 3); j++)
+ if (po2 > cns_table[j][0])
+ break;
+ j--;
+ cns += ((double)t)/((double)cns_table[j][1]) * 100;
+ }
+ /* save calculated cns in dive struct */
+ dive->cns = cns;
+ return dive->cns;
+}
/*
* Return air usage (in liters).
*/
@@ -456,6 +524,8 @@ void update_cylinder_related_info(struct dive *dive)
if (dive != NULL) {
dive->sac = calculate_sac(dive);
dive->otu = calculate_otu(dive);
+ if (dive->maxcns == 0)
+ dive->maxcns = calculate_cns(dive);
}
}