aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Robert C. Helling <helling@atdotde.de>2021-08-18 23:38:15 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2021-08-19 10:58:08 -0700
commitc634a07e38a4196bc64d05e5d58b183d32e84092 (patch)
tree3d18d36a1beb6842aeffec8fd34cfab887c9d673
parentedce24314739290c06d717cbe73e3864f7ff1269 (diff)
downloadsubsurface-c634a07e38a4196bc64d05e5d58b183d32e84092.tar.gz
Planner: Correctly compute CNS and OTU for bailout segments
For dives with mixed divemode, one needs to check sample.setpoint to figure out if the segment is an OC segment and the po2 needs to be computed from the gasmix and ambient pressure. This fixes #3310 Signed-off-by: Robert C. Helling <helling@atdotde.de>
-rw-r--r--CHANGELOG.md1
-rw-r--r--core/divelist.c74
-rw-r--r--core/planner.c2
3 files changed, 44 insertions, 33 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc2e06a04..97309fe64 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
- mobile: add ability to edit tags
+- Correct OTU and CNS calculations for planned bailout
- replace dive computer management with a new implementation, this fixes rare cases where
Subsurface unnecessarily download already downloaded dives, but also means
that some older style dive computer can no longer have nicknames
diff --git a/core/divelist.c b/core/divelist.c
index 9beea4d7c..1d856118c 100644
--- a/core/divelist.c
+++ b/core/divelist.c
@@ -85,6 +85,35 @@ static int active_o2(const struct dive *dive, const struct divecomputer *dc, dur
return get_o2(gas);
}
+// Do not call on first sample as it acccesses the previous sample
+static int get_sample_o2(const struct dive *dive, const struct divecomputer *dc, const struct sample *sample)
+{
+ int po2i, po2f, po2;
+ const struct sample *psample = sample - 1;
+ // Use sensor[0] if available
+ if ((dc->divemode == CCR || dc->divemode == PSCR) && sample->o2sensor[0].mbar) {
+ po2i = psample->o2sensor[0].mbar;
+ po2f = sample->o2sensor[0].mbar; // then use data from the first o2 sensor
+ po2 = (po2f + po2i) / 2;
+ } else if (sample->setpoint.mbar > 0) {
+ po2 = MIN((int) sample->setpoint.mbar,
+ depth_to_mbar(sample->depth.mm, dive));
+ } else {
+ double amb_presure = depth_to_bar(sample->depth.mm, dive);
+ double pamb_pressure = depth_to_bar(psample->depth.mm , dive);
+ if (dc->divemode == PSCR) {
+ po2i = pscr_o2(pamb_pressure, get_gasmix_at_time(dive, dc, psample->time));
+ po2f = pscr_o2(amb_presure, get_gasmix_at_time(dive, dc, sample->time));
+ } else {
+ int o2 = active_o2(dive, dc, psample->time); // ... calculate po2 from depth and FiO2.
+ po2i = lrint(o2 * pamb_pressure); // (initial) po2 at start of segment
+ po2f = lrint(o2 * amb_presure); // (final) po2 at end of segment
+ }
+ po2 = (po2i + po2f) / 2;
+ }
+ return po2;
+}
+
/* Calculate OTU for a dive - this only takes the first divecomputer into account.
Implement the protocol in Erik Baker's document "Oxygen Toxicity Calculations". This code
implements a third-order continuous approximation of Baker's Eq. 2 and enables OTU
@@ -104,15 +133,19 @@ static int calculate_otu(const struct dive *dive)
struct sample *sample = dc->sample + i;
struct sample *psample = sample - 1;
t = sample->time.seconds - psample->time.seconds;
- if ((dc->divemode == CCR || dc->divemode == PSCR) && sample->o2sensor[0].mbar) { // if dive computer has o2 sensor(s) (CCR & PSCR) ..
+ // if there is sensor data use sensor[0]
+ if ((dc->divemode == CCR || dc->divemode == PSCR) && sample->o2sensor[0].mbar) {
po2i = psample->o2sensor[0].mbar;
po2f = sample->o2sensor[0].mbar; // ... use data from the first o2 sensor
} else {
- if (dc->divemode == CCR) {
- po2i = MIN((int) psample->setpoint.mbar,
- depth_to_mbar(psample->depth.mm, dive)); // if CCR has no o2 sensors then use setpoint
+ if (sample->setpoint.mbar > 0) {
po2f = MIN((int) sample->setpoint.mbar,
depth_to_mbar(sample->depth.mm, dive));
+ if (psample->setpoint.mbar > 0)
+ po2i = MIN((int) psample->setpoint.mbar,
+ depth_to_mbar(psample->depth.mm, dive));
+ else
+ po2i = po2f;
} else { // For OC and rebreather without o2 sensor/setpoint
double amb_presure = depth_to_bar(sample->depth.mm, dive);
double pamb_pressure = depth_to_bar(psample->depth.mm , dive);
@@ -162,42 +195,17 @@ static double calculate_cns_dive(const struct dive *dive)
/* Calculate the CNS for each sample in this dive and sum them */
for (n = 1; n < dc->samples; n++) {
int t;
- int po2i, po2f;
- bool trueo2 = false;
+ int po2;
struct sample *sample = dc->sample + n;
struct sample *psample = sample - 1;
t = sample->time.seconds - psample->time.seconds;
- if ((dc->divemode == CCR || dc->divemode == PSCR) && sample->o2sensor[0].mbar) { // if dive computer has o2 sensor(s) (CCR & PSCR)
- po2i = psample->o2sensor[0].mbar;
- po2f = sample->o2sensor[0].mbar; // then use data from the first o2 sensor
- trueo2 = true;
- }
- if ((dc->divemode == CCR) && (!trueo2)) {
- po2i = MIN((int) psample->setpoint.mbar,
- depth_to_mbar(psample->depth.mm, dive)); // if CCR has no o2 sensors then use setpoint
- po2f = MIN((int) sample->setpoint.mbar,
- depth_to_mbar(sample->depth.mm, dive));
- trueo2 = true;
- }
- if (!trueo2) {
- double amb_presure = depth_to_bar(sample->depth.mm, dive);
- double pamb_pressure = depth_to_bar(psample->depth.mm , dive);
- if (dc->divemode == PSCR) {
- po2i = pscr_o2(pamb_pressure, get_gasmix_at_time(dive, dc, psample->time));
- po2f = pscr_o2(amb_presure, get_gasmix_at_time(dive, dc, sample->time));
- } else {
- int o2 = active_o2(dive, dc, psample->time); // ... calculate po2 from depth and FiO2.
- po2i = lrint(o2 * pamb_pressure); // (initial) po2 at start of segment
- po2f = lrint(o2 * amb_presure); // (final) po2 at end of segment
- }
- }
- int po2avg = (po2i + po2f) / 2; // po2i now holds the mean po2 of initial and final po2 values of segment.
+ po2 = get_sample_o2(dive, dc, sample);
/* Don't increase CNS when po2 below 500 matm */
- if (po2avg <= 500)
+ if (po2 <= 500)
continue;
// This formula is the result of fitting two lines to the Log of the NOAA CNS table
- rate = po2i <= 1500 ? exp(-11.7853 + 0.00193873 * po2avg) : exp(-23.6349 + 0.00980829 * po2avg);
+ rate = po2 <= 1500 ? exp(-11.7853 + 0.00193873 * po2) : exp(-23.6349 + 0.00980829 * po2);
cns += (double) t * rate * 100.0;
}
return cns;
diff --git a/core/planner.c b/core/planner.c
index 98c75df1e..598e568bf 100644
--- a/core/planner.c
+++ b/core/planner.c
@@ -284,6 +284,8 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
}
sample = prepare_sample(dc);
sample[-1].setpoint.mbar = po2;
+ if (po2)
+ sample[-1].o2sensor[0].mbar = po2;
sample->time.seconds = lasttime + 1;
sample->depth = lastdepth;
sample->manually_entered = dp->entered;