Merged in janlmulder/ostc4/div-fixes-6 (pull request #23)
Cleanup VPM, NDL to 240 min, and more cleanup
line source
/* getrennte Gase f�r die verschiedenen Modi
um Gaswechsel Eintr�ge zu vereinfachen
das heisst:
oc == bailout in cc mode
*/
/* Konvention:
float extExample_variable_can_be_used_with_extern;
*/
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include "buehlmann.h"
#include "decom.h"
extern const float buehlmann_N2_a[];
extern const float buehlmann_N2_b[];
extern const float buehlmann_He_a[];
extern const float buehlmann_He_b[];
typedef struct
{
float depth;
int id;
} SStop;
#define DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS 59940 // 999 minuten; before: 18000 // 5(h) * 60(min) * 60 sec = 18000 sec
#define DECO_STOPS_MAX_TTS_FOR_EVERY_SECOND_CALC_IN_SECONDS 7200
#define NINETY_NINE_MINUTES_IN_SECONDS 59940
# define PRESSURE_TEN_METER 1.0f
# define PRESSURE_THREE_METER 0.333334f
# define PRESSURE_150_CM 0.15f
# define PRESSURE_HALF_METER 0.05f
static void buehlmann_backup_and_restore(_Bool backup_restore_otherwise);
static float tissue_tolerance(void);
static void ambient_bar_to_deco_stop_depth_bar(SDiveSettings *pDiveSettings, float ceiling);
static int ascend_with_all_gaschanges(SDiveSettings *pDiveSettings, float pressure_decrease);
static float next_stop_depth_input_is_actual_stop_id(SDiveSettings *pDiveSettings, int actual_id);
static float get_gf_at_pressure(SDiveSettings *pDiveSettings, float pressure);
static int buehlmann_calc_ndl(SDiveSettings *pDiveSettings);
static _Bool dive1_check_deco(SDiveSettings *pDiveSettings);
static float gSurface_pressure_bar;
static float gPressure;
static int gGas_id;
static float gTissue_nitrogen_bar[16];
static float gTissue_helium_bar[16];
static float gGF_value;
static float gCNS;
float gGF_low_depth_bar;
SStop gStop;
void buehlmann_init(void)
{
}
static void buehlmann_backup_and_restore(_Bool backup_restore_otherwise)
{
static float pressure;
static float gas_id;
static float tissue_nitrogen_bar[16];
static float tissue_helium_bar[16];
static float gf_value;
static float cns;
if(backup_restore_otherwise)
{
pressure = gPressure;
gas_id = gGas_id;
gf_value = gGF_value;
cns = gCNS;
memcpy(tissue_nitrogen_bar, gTissue_nitrogen_bar, (4*16));
memcpy(tissue_helium_bar, gTissue_helium_bar, (4*16));
}
else
{
gPressure = pressure;
gGas_id = gas_id;
gGF_value = gf_value;
gCNS = cns;
memcpy(gTissue_nitrogen_bar, tissue_nitrogen_bar, (4*16));
memcpy(gTissue_helium_bar, tissue_helium_bar, (4*16));
}
}
float buehlmann_get_gCNS(void)
{
return gCNS;
}
void buehlmann_calc_deco(SLifeData* pLifeData, SDiveSettings * pDiveSettings, SDecoinfo * pDecoInfo)
{
float ceiling;
int ascend_time;
int tts_seconds;
float pressure_delta;
float next_depth;
_Bool deco_reached = false;
unsigned short *stoplist;
int i;
gCNS = 0;
pDecoInfo->output_time_to_surface_seconds = 0;
pDecoInfo->output_ndl_seconds = 0;
for(int i=0;i<DECOINFO_STRUCT_MAX_STOPS;i++)
{
pDecoInfo->output_stop_length_seconds[i] = 0;
}
/* internal copying */
gSurface_pressure_bar = pLifeData->pressure_surface_bar;
gPressure = pLifeData->pressure_ambient_bar;
gGas_id = 0;
memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16));
memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16));
gGF_value = ((float)pDiveSettings->gf_low) / 100.0f;
stoplist = pDecoInfo->output_stop_length_seconds;
if(pLifeData->dive_time_seconds < 60)
return;
// clean stop list
for(i = 0; i < DECOINFO_STRUCT_MAX_STOPS; i++)
stoplist[i] = 0;
if(pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero >= (gPressure - PRESSURE_150_CM))
{
deco_reached = true;
}
gGF_value = ((float)pDiveSettings->gf_high) / 100.0f;
buehlmann_backup_and_restore(true);
if(!dive1_check_deco(pDiveSettings) )
{
buehlmann_backup_and_restore(false);
// no deco
pDecoInfo->output_time_to_surface_seconds = 0;
for(i = 0; i < DECOINFO_STRUCT_MAX_STOPS; i++)
pDecoInfo->output_stop_length_seconds[i] = 0;
// calc NDL
pDecoInfo->output_ndl_seconds = buehlmann_calc_ndl(pDiveSettings);;
return;
}
buehlmann_backup_and_restore(false);
pDecoInfo->output_ndl_seconds = 0;
gGF_value = get_gf_at_pressure(pDiveSettings, gPressure);
//current ceiling at actual position
ceiling = tissue_tolerance();
ambient_bar_to_deco_stop_depth_bar(pDiveSettings, ceiling);
// set the base for all upcoming parameters
ceiling = gStop.depth + gSurface_pressure_bar;
tts_seconds = 0;
// modify parameters if there is ascend or parameter fine adjustment
if(ceiling < (gPressure - PRESSURE_150_CM)) // more than 1.5 meter below ceiling
{
// ascend within 10 mtr to GF_low // speed 12 mtr/min -> 50 sec / 10 mtr; 15 sec / 3 mtr.
if(ceiling < (gPressure - PRESSURE_TEN_METER) )
{ do {
ascend_time = ascend_with_all_gaschanges(pDiveSettings, PRESSURE_TEN_METER);
tts_seconds += ascend_time;
ceiling = tissue_tolerance();
if(tts_seconds > DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS)
{
pDecoInfo->output_time_to_surface_seconds = NINETY_NINE_MINUTES_IN_SECONDS;
return;// NINETY_NINE_MINUTES_IN_SECONDS;
}
} while ((ascend_time > 0 ) && ((gPressure - PRESSURE_TEN_METER ) > gSurface_pressure_bar) && (ceiling < (gPressure - PRESSURE_TEN_METER)));
}
do {
buehlmann_backup_and_restore(true);
ascend_time = ascend_with_all_gaschanges(pDiveSettings, PRESSURE_THREE_METER);
tts_seconds += ascend_time;
ceiling = tissue_tolerance();
if(tts_seconds > DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS)
{
pDecoInfo->output_time_to_surface_seconds = NINETY_NINE_MINUTES_IN_SECONDS;
return;// NINETY_NINE_MINUTES_IN_SECONDS;
}
ambient_bar_to_deco_stop_depth_bar(pDiveSettings, ceiling);
} while ((ascend_time > 0 ) && ((gStop.depth + gSurface_pressure_bar) < gPressure));
if(gStop.depth + gSurface_pressure_bar > gPressure)
{
gPressure += PRESSURE_THREE_METER;
buehlmann_backup_and_restore(false);
tts_seconds -= ascend_time;
}
// calculate first stop based on tissue saturation within 10 meters of stop
//ambient_bar_to_deco_stop_depth_bar(ceiling);
}
else
{
// initial values, upper code might not be executed (is within 150 cm)
}
if (ceiling > gSurface_pressure_bar)
{
ceiling = gStop.depth + gSurface_pressure_bar;
// ascend the last meters to first stop (especially consider any gas changes around)
pressure_delta = gPressure - ceiling;
ascend_time = (int) ceil(pressure_delta * 50.0f);
tts_seconds += ascend_with_all_gaschanges(pDiveSettings, pressure_delta);
}
// NDL check
if(ceiling <= gSurface_pressure_bar)
{
// NDL with GF_low
pDecoInfo->output_time_to_surface_seconds = 0;
return;
}
if (ceiling > pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero)
pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = ceiling;
// calc gf loop
if(deco_reached)
gGF_low_depth_bar = pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero - gSurface_pressure_bar;
else
gGF_low_depth_bar = ceiling - gSurface_pressure_bar;
while(gStop.depth > 0)
{
do
{
next_depth = next_stop_depth_input_is_actual_stop_id(pDiveSettings, gStop.id);
gGF_value = get_gf_at_pressure(pDiveSettings, next_depth + gSurface_pressure_bar);
buehlmann_backup_and_restore(true);
ascend_time = ascend_with_all_gaschanges(pDiveSettings, gStop.depth - next_depth);
ceiling = tissue_tolerance();
/* pre check actual limit */
if(pDecoInfo->output_stop_length_seconds[gStop.id] >= 999*60)
{
tts_seconds -= 999*60 - pDecoInfo->output_stop_length_seconds[gStop.id];
pDecoInfo->output_stop_length_seconds[gStop.id] = 999*60;
}
else
/* more deco on the actual depth */
if(ceiling > next_depth + gSurface_pressure_bar)
{
next_depth = -1;
buehlmann_backup_and_restore(false);
decom_tissues_exposure2(10, &pDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar); // some seconds at least at each stop
decom_oxygen_calculate_cns_exposure(10, &pDiveSettings->decogaslist[gGas_id], gPressure, &gCNS);
pDecoInfo->output_stop_length_seconds[gStop.id] += 10;
tts_seconds += 10;
}
} while(next_depth == -1);
tts_seconds += ascend_time;
gStop.depth = next_depth;
for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
{
if(pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
break;
float pressureChange = ((float)pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero) / 10;
if(gStop.depth <= pressureChange + 0.00001f)
{
gGas_id = i;
}
else
{
break;
}
}
gStop.id--;
}
pDecoInfo->output_time_to_surface_seconds = tts_seconds;
}
static float tissue_tolerance(void)
{
float tissue_inertgas_saturation;
float inertgas_a;
float inertgas_b;
float ceiling;
float global_ceiling;
int ci;
global_ceiling = -1;
for (ci = 0; ci < 16; ci++)
{
if(gTissue_helium_bar[ci] == 0)
{
tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
//
inertgas_a = buehlmann_N2_a[ci];
inertgas_b = buehlmann_N2_b[ci];
}
else
{
tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
//
inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
}
//
ceiling = (inertgas_b * ( tissue_inertgas_saturation - gGF_value * inertgas_a ) ) / (gGF_value - (inertgas_b * gGF_value) + inertgas_b);
if(ceiling > global_ceiling)
global_ceiling = ceiling;
}
return global_ceiling;
}
void buehlmann_super_saturation_calculator(SLifeData* pLifeData, SDecoinfo * pDecoInfo)
{
float tissue_inertgas_saturation;
float inertgas_a;
float inertgas_b;
float ceiling;
float super_saturation;
float pres_respiration = pLifeData->pressure_ambient_bar;
int ci;
pDecoInfo->super_saturation = 0;
for (ci = 0; ci < 16; ci++)
{
if(gTissue_helium_bar[ci] == 0)
{
tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
inertgas_a = buehlmann_N2_a[ci];
inertgas_b = buehlmann_N2_b[ci];
}
else
{
tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
}
ceiling = pres_respiration / inertgas_b + inertgas_a;
if(tissue_inertgas_saturation > pres_respiration)
{
super_saturation =
(tissue_inertgas_saturation - pres_respiration) / (ceiling - pres_respiration);
if (super_saturation > pDecoInfo->super_saturation)
pDecoInfo->super_saturation = super_saturation;
}
}
}
static float buehlmann_tissue_test_tolerance(float depth_in_bar_absolute)
{
float tissue_inertgas_saturation;
float inertgas_a;
float inertgas_b;
float inertgas_tolerance;
float gf_minus_1;
gf_minus_1 = gGF_value - 1.0f;
for (int ci = 0; ci < 16; ci++)
{
if(gTissue_helium_bar[ci] == 0)
{
tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
inertgas_a = buehlmann_N2_a[ci];
inertgas_b = buehlmann_N2_b[ci];
}
else
{
tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
}
inertgas_tolerance = ( (gGF_value / inertgas_b - gf_minus_1) * depth_in_bar_absolute ) + ( gGF_value * inertgas_a );
if(inertgas_tolerance < tissue_inertgas_saturation)
return tissue_inertgas_saturation - inertgas_tolerance; // positive
}
return tissue_inertgas_saturation - inertgas_tolerance; // negative
}
static void ambient_bar_to_deco_stop_depth_bar(SDiveSettings *pDiveSettings, float ceiling)
{
int i;
ceiling -= gSurface_pressure_bar;
if(ceiling <= 0)
{
gStop.depth = pDiveSettings->last_stop_depth_bar;
gStop.id = 0;
return;
}
if((ceiling - pDiveSettings->last_stop_depth_bar) <= 0)
{
gStop.depth = pDiveSettings->last_stop_depth_bar;
gStop.id = 0;
return;
}
gStop.depth = pDiveSettings->input_second_to_last_stop_depth_bar;
gStop.id = 1;
ceiling -= pDiveSettings->input_second_to_last_stop_depth_bar;
if(ceiling <= 0)
return;
for(i = 1; i < (DECOINFO_STRUCT_MAX_STOPS - 2); i++)
{
ceiling -= pDiveSettings->input_next_stop_increment_depth_bar;
if(ceiling <= 0)
break;
}
gStop.depth += i * pDiveSettings->input_next_stop_increment_depth_bar;
gStop.id += i;
return;
}
static float next_stop_depth_input_is_actual_stop_id(SDiveSettings *pDiveSettings, int actual_id)
{
if(actual_id == 0)
return 0;
if(actual_id == 1)
return pDiveSettings->last_stop_depth_bar;
actual_id -= 2;
return pDiveSettings->input_second_to_last_stop_depth_bar + (actual_id * pDiveSettings->input_next_stop_increment_depth_bar);
}
static int ascend_with_all_gaschanges(SDiveSettings *pDiveSettings, float pressure_decrease)
{
float pressureTop, pressureTop_tmp, pressureBottom, pressureChange, ascendrate_in_seconds_for_one_bar, pressure_difference;
int time_for_ascend = 0;
int seconds;
int i;
ascendrate_in_seconds_for_one_bar = 60 * 10 / pDiveSettings->ascentRate_meterperminute;
if(fabsf(gPressure - gSurface_pressure_bar) < PRESSURE_HALF_METER)
{
gPressure = gSurface_pressure_bar;
return 0;
}
pressureTop = gPressure - pressure_decrease;
if( gSurface_pressure_bar > pressureTop)
pressureTop = gSurface_pressure_bar;
pressureBottom = gPressure;
seconds = 0;
do{
pressureTop_tmp = pressureTop;
for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
{
if(pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
break;
pressureChange = gSurface_pressure_bar + ((float)pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero) / 10;
if(pressureBottom <= pressureChange)
{
gGas_id = i;
}
else
{
break;
}
}
for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
{
if(pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
break;
pressureChange = gSurface_pressure_bar + ((float)pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero)/ 10;
if((pressureChange < pressureBottom) && (pressureChange > pressureTop))
{
pressureTop_tmp = pressureChange;
}
}
pressure_difference = pressureBottom - pressureTop_tmp;
if(pressure_difference > 0.0001f)
{
time_for_ascend = (int)ceilf(pressure_difference * ascendrate_in_seconds_for_one_bar);
decom_tissues_exposure_stage_schreiner(time_for_ascend, &pDiveSettings->decogaslist[gGas_id],
pressureBottom, pressureTop_tmp, gTissue_nitrogen_bar, gTissue_helium_bar);
decom_oxygen_calculate_cns_stage_SchreinerStyle(time_for_ascend,&pDiveSettings->decogaslist[gGas_id],
pressureBottom, pressureTop_tmp, &gCNS);
}
pressureBottom = pressureTop_tmp;
seconds += time_for_ascend;
}while(pressureTop_tmp > pressureTop);
gPressure = pressureTop;
return seconds;
}
static float get_gf_at_pressure(SDiveSettings *pDiveSettings, float pressure)
{
float gfSteigung = 0.0f;
if(gGF_low_depth_bar < 0)
gGF_low_depth_bar = PRESSURE_THREE_METER; // just to prevent erratic behaviour if variable is not set
gfSteigung = ((float)(pDiveSettings->gf_high - pDiveSettings->gf_low))/ gGF_low_depth_bar;
if((pressure - gSurface_pressure_bar) <= PRESSURE_HALF_METER)
return ((float)pDiveSettings->gf_high) / 100.0f;
if(pressure >= gSurface_pressure_bar + gGF_low_depth_bar)
return ((float)pDiveSettings->gf_low) / 100.0f;
return (pDiveSettings->gf_high - gfSteigung * (pressure - gSurface_pressure_bar) )/ 100.0f;
}
#define MAX_NDL 240
static int buehlmann_calc_ndl(SDiveSettings *pDiveSettings)
{
float local_tissue_nitrogen_bar[16];
float local_tissue_helium_bar[16];
int i;
int ndl = 0;
//Check ndl always use gHigh
gGF_value = ((float)pDiveSettings->gf_high) / 100.0f;
//10 minutes steps
while(ndl < (MAX_NDL * 60))
{
memcpy(local_tissue_nitrogen_bar, gTissue_nitrogen_bar, (4*16));
memcpy(local_tissue_helium_bar, gTissue_helium_bar, (4*16));
//
ndl += 600;
decom_tissues_exposure2(600, &pDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar);
decom_oxygen_calculate_cns_exposure(600,&pDiveSettings->decogaslist[gGas_id],gPressure,&gCNS);
buehlmann_backup_and_restore(true);
if(dive1_check_deco(pDiveSettings))
{
buehlmann_backup_and_restore(false);
break;
}
buehlmann_backup_and_restore(false);
}
if(ndl < (MAX_NDL * 60))
ndl -= 600;
if(ndl > (MAX_NDL/2 * 60))
return ndl;
// refine
memcpy(gTissue_nitrogen_bar, local_tissue_nitrogen_bar, (4*16));
memcpy(gTissue_helium_bar, local_tissue_helium_bar, (4*16));
//One minutes step
for(i = 0; i < 10; i++)
{
ndl += 60;
decom_tissues_exposure2(60, &pDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar);
decom_oxygen_calculate_cns_exposure(60,&pDiveSettings->decogaslist[gGas_id],gPressure,&gCNS);
buehlmann_backup_and_restore(true);
if(dive1_check_deco(pDiveSettings))
break;
buehlmann_backup_and_restore(false);
}
return ndl;
}
// ===============================================================================
// dive1_check_deco
/// @brief for NDL calculations
/// 160614 using ceilingOther and not ceiling
// ===============================================================================
static _Bool dive1_check_deco(SDiveSettings *pDiveSettings)
{
// gGF_value is set in call routine;
// internes Backup!
// calc like in deco
float ceiling;
float ceilingOther; // new hw 160614
ceiling = tissue_tolerance();
ambient_bar_to_deco_stop_depth_bar(pDiveSettings, ceiling); // this will set gStop.depth :-) (and gStop.id)
// set the base for all upcoming parameters
ceilingOther = gStop.depth + gSurface_pressure_bar;
// modify parameters if there is ascend or parameter fine adjustment
if(ceilingOther < (gPressure - PRESSURE_150_CM)) // more than 1.5 meter below ceiling
{
// ascend within 10 mtr to GF_low // speed 12 mtr/min -> 50 sec / 10 mtr; 15 sec / 3 mtr.
while(((gPressure - PRESSURE_TEN_METER ) > gSurface_pressure_bar) && (ceiling < (gPressure - PRESSURE_TEN_METER)))
{
ascend_with_all_gaschanges(pDiveSettings, PRESSURE_TEN_METER);
ceiling = tissue_tolerance();
}
while(((gPressure - PRESSURE_THREE_METER )> gSurface_pressure_bar) && (ceiling < gPressure))
{
ascend_with_all_gaschanges(pDiveSettings, PRESSURE_THREE_METER);
ceiling = tissue_tolerance();
}
}
return ceiling > gSurface_pressure_bar;
}
// compute ceiling recursively, with a resolution of 10cm. Notice
// that the initial call shall guarantee that the found ceiling
// is between low and high parameters.
static float compute_ceiling(float low, float high)
{
if ((high - low) < 0.01)
return low;
else {
float next_pressure_absolute = (low + high)/2;
float test_result = buehlmann_tissue_test_tolerance(next_pressure_absolute);
if (test_result < 0)
return compute_ceiling(low, next_pressure_absolute);
else
return compute_ceiling(next_pressure_absolute, high);
}
}
void buehlmann_ceiling_calculator(SLifeData *pLifeData, SDecoinfo *pDecoInfo)
{
float ceiling;
memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16));
memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16));
// this is just performance optimizing. The code below runs just fine
// without this. There is never a ceiling in NDL deco state
if (!pDecoInfo->output_time_to_surface_seconds) {
pDecoInfo->output_ceiling_meter = 0;
return;
}
ceiling = compute_ceiling(pLifeData->pressure_surface_bar, 1.0f + pLifeData->max_depth_meter/10.0f);
pDecoInfo->output_ceiling_meter = (ceiling - pLifeData->pressure_surface_bar) * 10.0f;
}