Alternative Implementations

The decompression calculations in DecoTengu are divided into various parts

  • descent

  • bottom time

  • finding first stop

  • free ascent to first stop (or surface)

  • decompression ascent to surface when decompression required

  • tissues saturation calculations

Each part can be replaced with an alternative, independent implementation. The decotengu.alt module provides some of such alternatives

  • tabular calculator - calculate tissues saturation using precomputed values of exponential function (useful when exponential function is too expensive on a given hardware)

  • deco stop stepper - naive algorithm to find length of decompression stop using 1 minute intervals

  • decompression calculations using fixed point arithmetic

  • first decompression stop binary search algorithm

Tabular Calculations

To calculate saturation of inert gas in tissue compartments, the decompression model uses Schreiner equation, which calls exponential function. Such call can be too costly or even impossible on some of the hardware architectures, i.e. microcontrollers lacking FPU. To make decompression software available on such hardware architectures, the exponential function values can be precomputed and stored in a table. DecoTengu library allows to experiment with dive decompression calculations using such technique, which we call tabular calculation.

The tabular calculation uses group homomorphism of exponential function

\[e^{x + y} = e^x * e^y\]

Part of Schreiner equation (see Schreiner Equation) is calculation of inert gas exposure with exponential function

\[e^{-k * t}\]

We can precompute the values for above function for 1 minute and for 6 seconds intervals and store them in a table for each gas decay constant \(k\). Then, exponential function results can be calculated with formula

\[e^{-k * t} = (e_{1min}) ^ {n_{1min}} * (e_{6s}) ^ {n_{6s}}\]

where

\(e_{1min}\)

Exponential function value \(e^{-k * 1}\).

\(e_{6s}\)

Exponential function value \(e^{-k * 0.1}\) (\(0.1\) is 6 seconds).

\(n_{1min}\)

Number of one minute time intervals \(t\ div\ 1\) in time \(t\).

\(n_{6s}\)

Number of 6 second time intervals \((t\ mod\ 1) * 10\) in time \(t\ mod\ 1\).

The precalculated values of exponential function imply configuration constraints, which are discussed in the following section.

Configuration Constraints

The main configuration constraint for DecoTengu tabular calculation is the number of precomputed values of exponential function. This is driven by limited amount of computer memory.

To keep the number of precomputed values of exponential function constant, we need to make ascent and descent rates constant. Therefore, first configuration constraint sets ascent and descent rates to 10m/min.

The second configuration constraint is the smallest depth change for which tissue saturation can be calculated. By default it is 1m (or 6s at 10m/min), which forces us to round up current depth value, i.e. from 31.2m to 32m.

Implementation

The values of exponential function are precomputed and stored by tabular calculator class decotengu.alt.tab.TabExp.

The decotengu.alt.tab.TabExp class divides time into one minute segments and 6 seconds segments and caclulates exponential function value using formula specified at the begining of this section.

The helper function decotengu.alt.tab.tab_engine() takes decompression engine object as an argument and overrides engine configuration and methods, so decompression calculations can be performed with tabular calculator.

Example

To calculate dive decompression information using tabular calculator override decompression engine object with decotengu.alt.tab.tab_engine() function.

Create the decompression engine first

>>> import decotengu
>>> from decotengu.alt.tab import tab_engine
>>> engine = decotengu.create()
>>> engine.add_gas(0, 21)

Override the engine

>>> tab_engine(engine)
>>> print(engine.model._exp) 
<decotengu.alt.tab.TabExp object at ...>

Perform calculations

>>> profile = list(engine.calculate(35, 40))
>>> for stop in engine.deco_table:
...     print(stop)
DecoStop(depth=18.0, time=1.0)
DecoStop(depth=15.0, time=1.0)
DecoStop(depth=12.0, time=4.0)
DecoStop(depth=9.0, time=6.0)
DecoStop(depth=6.0, time=9.0)
DecoStop(depth=3.0, time=22.0)

Decimal Calculations

DecoTengu allows to experiment with accuracy of decompression calculations by providing context manager for overriding float data type with a decimal data type.

By default, float type is used for decompression calculations. The contex manager implemented in decotengu.alt.decimal module enables programmer to change the default and experiment with fixed point arithmetics.

NOTE 1: The implementation uses local context manager provided by Python’s decimal module. In the future, it should be probably allowed to use custom decimal types without decimal module dependency.

NOTE 2: At the moment, only tabular tissue calculator can be used with decimal type override.

Example

As an example, we will compare a dive to 90 meters for 20 minutes when using float type and decimal type with precision 9.

Let’s calculate dive profile using float type

>>> from decotengu import create
>>> from decotengu.alt.tab import tab_engine
>>> engine = create()
>>> deco_table = engine.deco_table
>>> tab_engine(engine)
>>> engine.model.gf_low = 0.2
>>> engine.model.gf_high = 0.75
>>> engine.add_gas(0, 13, 50)
>>> engine.add_gas(33, 36)
>>> engine.add_gas(21, 50)
>>> engine.add_gas(9, 80)
>>> profile = tuple(engine.calculate(90, 20, descent=False))
>>> last = profile[-1]

and dive profile using decimal type with precision 9

>>> from decotengu.alt.decimal import DecimalContext
>>> from decimal import Decimal
>>> with DecimalContext(prec=9) as ctx:
...     engine = create()
...     deco_table_dec = engine.deco_table
...     tab_engine(engine)
...     engine.model.gf_low = Decimal(0.2)
...     engine.model.gf_high = Decimal(0.75)
...     engine.add_gas(Decimal(0), Decimal(13), Decimal(50))
...     engine.add_gas(Decimal(33), Decimal(36), Decimal(0))
...     engine.add_gas(Decimal(21), Decimal(50), Decimal(0))
...     engine.add_gas(Decimal(9), Decimal(80), Decimal(0))
...     profile_dec = tuple(engine.calculate(Decimal(90), Decimal(20), descent=False))
>>> last_dec = profile_dec[-1]

Check the total time of dive decompression phase

>>> deco_table.total
103.0
>>> deco_table_dec.total
Decimal('103.00000')

Calculate maximum absolute error of saturation of inert gas in a tissue at the surface

>>> max_error = max(abs(v1[0] - float(v2[0]) + v1[1] - float(v2[1])) for v1, v2 in zip(last.data.tissues, last_dec.data.tissues))
>>> round(max_error, 10)
1.06134e-05

Naive Algorithms

There are various algorithms, which can be used for decompression calculations. The decotengu.alt.naive module implements some of them, i.e. calculation of decompression stop length using 1 minute intervals.

The algorithms are quite inefficient, usually \(O(n)\) while algorithm of complexity \(O(log(n))\) could be used. They are implemented in DecoTengu for comparison purposes only.

Decompression Stop Stepper

The decompression stop stepper is simple algorithm to calculate length of a decompression stop.

Decompression stop length is calculated by increasing length of the stop by one minute until it is possible to ascend to next stop or to the surface.

The algorithm is implemented by decotengu.alt.naive.DecoStopStepper class.

The complexity of the algorithm is \(O(n)\), where \(n\) is length of decompression stop in minutes.