[PATCH v2] Add a simple table-based cns calculations

Dirk Hohndel dirk at hohndel.org
Tue Apr 9 20:44:34 PDT 2013


Anton Lundin <glance at acc.umu.se> writes:

> 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.
>
> Signed-off-by: Anton Lundin <glance at acc.umu.se>

Very nice.

I made a few small changes and am about to push this

> +static int calculate_cns(struct dive *dive)
> +{
> +	int i, j;
> +	double cns = 0.0;
> +	struct divecomputer *dc = &dive->dc;
> +
> +	/* shortcut */
> +	if (dive->cns)
> +		return dive->cns;
> +	/* or if we have a divecomputer that already tracked cns for us */
> +	if ((dc->sample + dc->samples - 1)->cns)
> +		return (dc->sample + dc->samples - 1)->cns;

This would be wrong (as it just checks the first divecomputer but there
could be several), but more importantly this is unnecessary as you only
call calculate_cns() if dive->maxcns == 0. And dive->maxcns is (as the
name implies) the maximum cns value found in the samples...

I simply removed those three lines (and added a comment before the
function that explains that this only gets called if dive->maxcns is 0).

> +	/*
> +	 * 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.
> +	 */
> +	if (dive->next && dive->when < (dive->next->when + 3600 * 12)) {
> +		cns = calculate_cns(dive->next);
> +		cns = cns * 1/pow(2, (dive->when - dive->next->when) / (90.0 * 60.0));
> +	}

This is the part that is problematic. dive->next is actually "the next
dive in the current trip". Some people don't use trips. Or a user may
have broken a trip in two. So instead we need to manually LOOK for the
previous dive.

I changed the code to do so.

Also, just from a logical point of view... we should use the END time of
the previous drive for the decay calculation.

> +	/* 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;
> +}

The formula looks right to me - I'm surprised by some of the CNS values
that I get - they are just higher than what I'd expect. But I need to
change the code so it calculates the CNS and compares it to what's in
the samples. I think that will give me a better idea if something is
completely off

/D


More information about the subsurface mailing list