51
+ − 1 /* getrennte Gase f�r die verschiedenen Modi
+ − 2 um Gaswechsel Eintr�ge zu vereinfachen
38
+ − 3 das heisst:
+ − 4 oc == bailout in cc mode
+ − 5 */
+ − 6
+ − 7 /* Konvention:
+ − 8 float extExample_variable_can_be_used_with_extern;
+ − 9 */
+ − 10
+ − 11 #include <string.h>
+ − 12 #include <math.h>
+ − 13 #include <stdbool.h>
+ − 14 #include "buehlmann.h"
+ − 15 #include "decom.h"
+ − 16
+ − 17 extern const float buehlmann_N2_a[];
+ − 18 extern const float buehlmann_N2_b[];
+ − 19 extern const float buehlmann_He_a[];
+ − 20 extern const float buehlmann_He_b[];
+ − 21
+ − 22 typedef struct
+ − 23 {
+ − 24 float depth;
+ − 25 int id;
+ − 26 } SStop;
+ − 27
+ − 28 #define DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS 59940 // 999 minuten; before: 18000 // 5(h) * 60(min) * 60 sec = 18000 sec
+ − 29 #define DECO_STOPS_MAX_TTS_FOR_EVERY_SECOND_CALC_IN_SECONDS 7200
+ − 30 #define NINETY_NINE_MINUTES_IN_SECONDS 59940
+ − 31
+ − 32 # define PRESSURE_TEN_METER 1.0f
+ − 33 # define PRESSURE_THREE_METER 0.333334f
+ − 34 # define PRESSURE_150_CM 0.15f
+ − 35 # define PRESSURE_HALF_METER 0.05f
+ − 36
253
+ − 37 static void buehlmann_backup_and_restore(_Bool backup_restore_otherwise);
+ − 38 static float tissue_tolerance(void);
255
+ − 39 static void ambient_bar_to_deco_stop_depth_bar(SDiveSettings *pDiveSettings, float ceiling);
+ − 40 static int ascend_with_all_gaschanges(SDiveSettings *pDiveSettings, float pressure_decrease);
+ − 41 static float next_stop_depth_input_is_actual_stop_id(SDiveSettings *pDiveSettings, int actual_id);
+ − 42 static float get_gf_at_pressure(SDiveSettings *pDiveSettings, float pressure);
257
+ − 43 static int buehlmann_calc_ndl(SDiveSettings *pDiveSettings);
255
+ − 44 static _Bool dive1_check_deco(SDiveSettings *pDiveSettings);
38
+ − 45
253
+ − 46 static float gSurface_pressure_bar;
+ − 47 static float gPressure;
+ − 48 static int gGas_id;
+ − 49 static float gTissue_nitrogen_bar[16];
+ − 50 static float gTissue_helium_bar[16];
+ − 51 static float gGF_value;
+ − 52 static float gCNS;
38
+ − 53
+ − 54 float gGF_low_depth_bar;
+ − 55 SStop gStop;
+ − 56
+ − 57 void buehlmann_init(void)
+ − 58 {
+ − 59 }
+ − 60
253
+ − 61 static void buehlmann_backup_and_restore(_Bool backup_restore_otherwise)
38
+ − 62 {
+ − 63 static float pressure;
+ − 64 static float gas_id;
+ − 65 static float tissue_nitrogen_bar[16];
+ − 66 static float tissue_helium_bar[16];
+ − 67 static float gf_value;
+ − 68 static float cns;
+ − 69
+ − 70 if(backup_restore_otherwise)
+ − 71 {
+ − 72 pressure = gPressure;
+ − 73 gas_id = gGas_id;
+ − 74 gf_value = gGF_value;
+ − 75 cns = gCNS;
+ − 76 memcpy(tissue_nitrogen_bar, gTissue_nitrogen_bar, (4*16));
+ − 77 memcpy(tissue_helium_bar, gTissue_helium_bar, (4*16));
+ − 78 }
+ − 79 else
+ − 80 {
+ − 81 gPressure = pressure;
+ − 82 gGas_id = gas_id;
+ − 83 gGF_value = gf_value;
+ − 84 gCNS = cns;
+ − 85 memcpy(gTissue_nitrogen_bar, tissue_nitrogen_bar, (4*16));
+ − 86 memcpy(gTissue_helium_bar, tissue_helium_bar, (4*16));
+ − 87 }
+ − 88
+ − 89 }
+ − 90
+ − 91 float buehlmann_get_gCNS(void)
+ − 92 {
+ − 93 return gCNS;
+ − 94 }
+ − 95
+ − 96 void buehlmann_calc_deco(SLifeData* pLifeData, SDiveSettings * pDiveSettings, SDecoinfo * pDecoInfo)
+ − 97 {
+ − 98 float ceiling;
+ − 99 int ascend_time;
+ − 100 int tts_seconds;
+ − 101 float pressure_delta;
+ − 102 float next_depth;
+ − 103 _Bool deco_reached = false;
+ − 104 unsigned short *stoplist;
+ − 105 int i;
+ − 106
+ − 107 gCNS = 0;
253
+ − 108 pDecoInfo->output_time_to_surface_seconds = 0;
38
+ − 109 pDecoInfo->output_ndl_seconds = 0;
+ − 110 for(int i=0;i<DECOINFO_STRUCT_MAX_STOPS;i++)
+ − 111 {
+ − 112 pDecoInfo->output_stop_length_seconds[i] = 0;
+ − 113 }
+ − 114
+ − 115 /* internal copying */
+ − 116 gSurface_pressure_bar = pLifeData->pressure_surface_bar;
+ − 117
+ − 118 gPressure = pLifeData->pressure_ambient_bar;
+ − 119 gGas_id = 0;
+ − 120 memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16));
+ − 121 memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16));
255
+ − 122 gGF_value = ((float)pDiveSettings->gf_low) / 100.0f;
38
+ − 123
258
+ − 124 stoplist = pDecoInfo->output_stop_length_seconds;
38
+ − 125
305
305f251cc981
bugfix, consistency: show deco/NDL really after 1 minute divetime
Jan Mulder <jlmulder@xs4all.nl>
diff
changeset
+ − 126 if(pLifeData->dive_time_seconds_without_surface_time < 60)
253
+ − 127 return;
38
+ − 128
+ − 129 // clean stop list
+ − 130 for(i = 0; i < DECOINFO_STRUCT_MAX_STOPS; i++)
+ − 131 stoplist[i] = 0;
+ − 132
253
+ − 133 if(pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero >= (gPressure - PRESSURE_150_CM))
+ − 134 {
+ − 135 deco_reached = true;
+ − 136 }
38
+ − 137
255
+ − 138 gGF_value = ((float)pDiveSettings->gf_high) / 100.0f;
257
+ − 139 buehlmann_backup_and_restore(true);
255
+ − 140 if(!dive1_check_deco(pDiveSettings) )
38
+ − 141 {
257
+ − 142 buehlmann_backup_and_restore(false);
38
+ − 143 // no deco
257
+ − 144 pDecoInfo->output_time_to_surface_seconds = 0;
38
+ − 145 for(i = 0; i < DECOINFO_STRUCT_MAX_STOPS; i++)
254
+ − 146 pDecoInfo->output_stop_length_seconds[i] = 0;
38
+ − 147 // calc NDL
257
+ − 148 pDecoInfo->output_ndl_seconds = buehlmann_calc_ndl(pDiveSettings);;
38
+ − 149 return;
+ − 150 }
+ − 151 buehlmann_backup_and_restore(false);
254
+ − 152 pDecoInfo->output_ndl_seconds = 0;
38
+ − 153
255
+ − 154 gGF_value = get_gf_at_pressure(pDiveSettings, gPressure);
38
+ − 155 //current ceiling at actual position
+ − 156 ceiling = tissue_tolerance();
255
+ − 157 ambient_bar_to_deco_stop_depth_bar(pDiveSettings, ceiling);
38
+ − 158
+ − 159 // set the base for all upcoming parameters
+ − 160 ceiling = gStop.depth + gSurface_pressure_bar;
+ − 161 tts_seconds = 0;
+ − 162
+ − 163 // modify parameters if there is ascend or parameter fine adjustment
+ − 164 if(ceiling < (gPressure - PRESSURE_150_CM)) // more than 1.5 meter below ceiling
+ − 165 {
+ − 166 // ascend within 10 mtr to GF_low // speed 12 mtr/min -> 50 sec / 10 mtr; 15 sec / 3 mtr.
+ − 167 if(ceiling < (gPressure - PRESSURE_TEN_METER) )
+ − 168 { do {
255
+ − 169 ascend_time = ascend_with_all_gaschanges(pDiveSettings, PRESSURE_TEN_METER);
38
+ − 170 tts_seconds += ascend_time;
+ − 171 ceiling = tissue_tolerance();
+ − 172 if(tts_seconds > DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS)
+ − 173 {
254
+ − 174 pDecoInfo->output_time_to_surface_seconds = NINETY_NINE_MINUTES_IN_SECONDS;
38
+ − 175 return;// NINETY_NINE_MINUTES_IN_SECONDS;
+ − 176 }
+ − 177 } while ((ascend_time > 0 ) && ((gPressure - PRESSURE_TEN_METER ) > gSurface_pressure_bar) && (ceiling < (gPressure - PRESSURE_TEN_METER)));
+ − 178 }
+ − 179 do {
+ − 180 buehlmann_backup_and_restore(true);
255
+ − 181 ascend_time = ascend_with_all_gaschanges(pDiveSettings, PRESSURE_THREE_METER);
38
+ − 182 tts_seconds += ascend_time;
+ − 183 ceiling = tissue_tolerance();
+ − 184 if(tts_seconds > DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS)
+ − 185 {
254
+ − 186 pDecoInfo->output_time_to_surface_seconds = NINETY_NINE_MINUTES_IN_SECONDS;
38
+ − 187 return;// NINETY_NINE_MINUTES_IN_SECONDS;
+ − 188 }
255
+ − 189 ambient_bar_to_deco_stop_depth_bar(pDiveSettings, ceiling);
38
+ − 190 } while ((ascend_time > 0 ) && ((gStop.depth + gSurface_pressure_bar) < gPressure));
+ − 191
+ − 192 if(gStop.depth + gSurface_pressure_bar > gPressure)
+ − 193 {
+ − 194 gPressure += PRESSURE_THREE_METER;
+ − 195 buehlmann_backup_and_restore(false);
+ − 196 tts_seconds -= ascend_time;
+ − 197 }
+ − 198 // calculate first stop based on tissue saturation within 10 meters of stop
+ − 199 //ambient_bar_to_deco_stop_depth_bar(ceiling);
+ − 200 }
+ − 201 else
+ − 202 {
+ − 203 // initial values, upper code might not be executed (is within 150 cm)
+ − 204 }
+ − 205
253
+ − 206 if (ceiling > gSurface_pressure_bar)
+ − 207 {
+ − 208 ceiling = gStop.depth + gSurface_pressure_bar;
+ − 209 // ascend the last meters to first stop (especially consider any gas changes around)
+ − 210 pressure_delta = gPressure - ceiling;
+ − 211 ascend_time = (int) ceil(pressure_delta * 50.0f);
255
+ − 212 tts_seconds += ascend_with_all_gaschanges(pDiveSettings, pressure_delta);
253
+ − 213 }
38
+ − 214 // NDL check
+ − 215 if(ceiling <= gSurface_pressure_bar)
+ − 216 {
+ − 217 // NDL with GF_low
254
+ − 218 pDecoInfo->output_time_to_surface_seconds = 0;
38
+ − 219 return;
+ − 220 }
253
+ − 221 if (ceiling > pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero)
+ − 222 pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = ceiling;
38
+ − 223
+ − 224 // calc gf loop
+ − 225 if(deco_reached)
+ − 226 gGF_low_depth_bar = pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero - gSurface_pressure_bar;
+ − 227 else
+ − 228 gGF_low_depth_bar = ceiling - gSurface_pressure_bar;
+ − 229
+ − 230 while(gStop.depth > 0)
+ − 231 {
+ − 232 do
+ − 233 {
255
+ − 234 next_depth = next_stop_depth_input_is_actual_stop_id(pDiveSettings, gStop.id);
+ − 235 gGF_value = get_gf_at_pressure(pDiveSettings, next_depth + gSurface_pressure_bar);
38
+ − 236 buehlmann_backup_and_restore(true);
255
+ − 237 ascend_time = ascend_with_all_gaschanges(pDiveSettings, gStop.depth - next_depth);
38
+ − 238 ceiling = tissue_tolerance();
+ − 239 /* pre check actual limit */
258
+ − 240 if(pDecoInfo->output_stop_length_seconds[gStop.id] >= 999*60)
38
+ − 241 {
258
+ − 242 tts_seconds -= 999*60 - pDecoInfo->output_stop_length_seconds[gStop.id];
+ − 243 pDecoInfo->output_stop_length_seconds[gStop.id] = 999*60;
38
+ − 244 }
+ − 245 else
+ − 246 /* more deco on the actual depth */
+ − 247 if(ceiling > next_depth + gSurface_pressure_bar)
+ − 248 {
+ − 249 next_depth = -1;
+ − 250 buehlmann_backup_and_restore(false);
255
+ − 251 decom_tissues_exposure2(10, &pDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar); // some seconds at least at each stop
+ − 252 decom_oxygen_calculate_cns_exposure(10, &pDiveSettings->decogaslist[gGas_id], gPressure, &gCNS);
258
+ − 253 pDecoInfo->output_stop_length_seconds[gStop.id] += 10;
38
+ − 254 tts_seconds += 10;
+ − 255 }
+ − 256 } while(next_depth == -1);
253
+ − 257 tts_seconds += ascend_time;
38
+ − 258 gStop.depth = next_depth;
+ − 259 for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
+ − 260 {
862
+ − 261 if((pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
+ − 262 || (pDiveSettings->gas[pDiveSettings->decogaslist[i].GasIdInSettings].note.ub.decocalc == 0))
+ − 263 {
38
+ − 264 break;
862
+ − 265 }
255
+ − 266 float pressureChange = ((float)pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero) / 10;
38
+ − 267 if(gStop.depth <= pressureChange + 0.00001f)
+ − 268 {
+ − 269 gGas_id = i;
+ − 270 }
+ − 271 else
+ − 272 {
+ − 273 break;
+ − 274 }
+ − 275 }
+ − 276 gStop.id--;
+ − 277 }
+ − 278
258
+ − 279 pDecoInfo->output_time_to_surface_seconds = tts_seconds;
38
+ − 280 }
+ − 281
+ − 282
253
+ − 283 static float tissue_tolerance(void)
38
+ − 284 {
+ − 285 float tissue_inertgas_saturation;
+ − 286 float inertgas_a;
+ − 287 float inertgas_b;
+ − 288 float ceiling;
+ − 289 float global_ceiling;
+ − 290 int ci;
+ − 291
+ − 292 global_ceiling = -1;
+ − 293
+ − 294 for (ci = 0; ci < 16; ci++)
+ − 295 {
+ − 296 if(gTissue_helium_bar[ci] == 0)
+ − 297 {
+ − 298 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
+ − 299 //
+ − 300 inertgas_a = buehlmann_N2_a[ci];
+ − 301 inertgas_b = buehlmann_N2_b[ci];
+ − 302 }
+ − 303 else
+ − 304 {
+ − 305 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
+ − 306 //
+ − 307 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
+ − 308 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
+ − 309 }
+ − 310 //
+ − 311 ceiling = (inertgas_b * ( tissue_inertgas_saturation - gGF_value * inertgas_a ) ) / (gGF_value - (inertgas_b * gGF_value) + inertgas_b);
+ − 312 if(ceiling > global_ceiling)
+ − 313 global_ceiling = ceiling;
+ − 314 }
+ − 315 return global_ceiling;
+ − 316 }
+ − 317
246
+ − 318 void buehlmann_super_saturation_calculator(SLifeData* pLifeData, SDecoinfo * pDecoInfo)
38
+ − 319 {
+ − 320 float tissue_inertgas_saturation;
+ − 321 float inertgas_a;
+ − 322 float inertgas_b;
+ − 323 float ceiling;
246
+ − 324 float super_saturation;
+ − 325 float pres_respiration = pLifeData->pressure_ambient_bar;
38
+ − 326 int ci;
+ − 327
246
+ − 328 pDecoInfo->super_saturation = 0;
38
+ − 329
+ − 330 for (ci = 0; ci < 16; ci++)
+ − 331 {
+ − 332 if(gTissue_helium_bar[ci] == 0)
+ − 333 {
+ − 334 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
+ − 335 inertgas_a = buehlmann_N2_a[ci];
+ − 336 inertgas_b = buehlmann_N2_b[ci];
+ − 337 }
+ − 338 else
+ − 339 {
+ − 340 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
+ − 341 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
+ − 342 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
+ − 343 }
246
+ − 344
+ − 345 ceiling = pres_respiration / inertgas_b + inertgas_a;
+ − 346 if(tissue_inertgas_saturation > pres_respiration)
38
+ − 347 {
246
+ − 348 super_saturation =
+ − 349 (tissue_inertgas_saturation - pres_respiration) / (ceiling - pres_respiration);
+ − 350
+ − 351 if (super_saturation > pDecoInfo->super_saturation)
+ − 352 pDecoInfo->super_saturation = super_saturation;
38
+ − 353 }
+ − 354 }
+ − 355 }
+ − 356
+ − 357
253
+ − 358 static float buehlmann_tissue_test_tolerance(float depth_in_bar_absolute)
38
+ − 359 {
+ − 360 float tissue_inertgas_saturation;
+ − 361 float inertgas_a;
+ − 362 float inertgas_b;
+ − 363 float inertgas_tolerance;
+ − 364 float gf_minus_1;
+ − 365
+ − 366 gf_minus_1 = gGF_value - 1.0f;
+ − 367
+ − 368 for (int ci = 0; ci < 16; ci++)
+ − 369 {
+ − 370 if(gTissue_helium_bar[ci] == 0)
+ − 371 {
+ − 372 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
+ − 373 inertgas_a = buehlmann_N2_a[ci];
+ − 374 inertgas_b = buehlmann_N2_b[ci];
+ − 375 }
+ − 376 else
+ − 377 {
+ − 378 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
+ − 379 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
+ − 380 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
+ − 381 }
+ − 382 inertgas_tolerance = ( (gGF_value / inertgas_b - gf_minus_1) * depth_in_bar_absolute ) + ( gGF_value * inertgas_a );
+ − 383 if(inertgas_tolerance < tissue_inertgas_saturation)
250
+ − 384 return tissue_inertgas_saturation - inertgas_tolerance; // positive
38
+ − 385 }
250
+ − 386 return tissue_inertgas_saturation - inertgas_tolerance; // negative
38
+ − 387 }
+ − 388
+ − 389
255
+ − 390 static void ambient_bar_to_deco_stop_depth_bar(SDiveSettings *pDiveSettings, float ceiling)
38
+ − 391 {
+ − 392 int i;
+ − 393
+ − 394 ceiling -= gSurface_pressure_bar;
+ − 395
+ − 396 if(ceiling <= 0)
+ − 397 {
255
+ − 398 gStop.depth = pDiveSettings->last_stop_depth_bar;
38
+ − 399 gStop.id = 0;
+ − 400 return;
+ − 401 }
+ − 402
255
+ − 403 if((ceiling - pDiveSettings->last_stop_depth_bar) <= 0)
38
+ − 404 {
255
+ − 405 gStop.depth = pDiveSettings->last_stop_depth_bar;
38
+ − 406 gStop.id = 0;
+ − 407 return;
+ − 408 }
+ − 409
255
+ − 410 gStop.depth = pDiveSettings->input_second_to_last_stop_depth_bar;
38
+ − 411 gStop.id = 1;
255
+ − 412 ceiling -= pDiveSettings->input_second_to_last_stop_depth_bar;
38
+ − 413
+ − 414 if(ceiling <= 0)
+ − 415 return;
+ − 416
+ − 417 for(i = 1; i < (DECOINFO_STRUCT_MAX_STOPS - 2); i++)
+ − 418 {
255
+ − 419 ceiling -= pDiveSettings->input_next_stop_increment_depth_bar;
38
+ − 420 if(ceiling <= 0)
+ − 421 break;
+ − 422 }
255
+ − 423 gStop.depth += i * pDiveSettings->input_next_stop_increment_depth_bar;
38
+ − 424 gStop.id += i;
+ − 425 return;
+ − 426 }
+ − 427
255
+ − 428 static float next_stop_depth_input_is_actual_stop_id(SDiveSettings *pDiveSettings, int actual_id)
38
+ − 429 {
+ − 430 if(actual_id == 0)
+ − 431 return 0;
+ − 432
+ − 433 if(actual_id == 1)
255
+ − 434 return pDiveSettings->last_stop_depth_bar;
38
+ − 435
+ − 436 actual_id -= 2;
255
+ − 437 return pDiveSettings->input_second_to_last_stop_depth_bar + (actual_id * pDiveSettings->input_next_stop_increment_depth_bar);
38
+ − 438 }
+ − 439
255
+ − 440 static int ascend_with_all_gaschanges(SDiveSettings *pDiveSettings, float pressure_decrease)
38
+ − 441 {
+ − 442 float pressureTop, pressureTop_tmp, pressureBottom, pressureChange, ascendrate_in_seconds_for_one_bar, pressure_difference;
51
+ − 443 int time_for_ascend = 0;
38
+ − 444 int seconds;
+ − 445 int i;
+ − 446
255
+ − 447 ascendrate_in_seconds_for_one_bar = 60 * 10 / pDiveSettings->ascentRate_meterperminute;
38
+ − 448
+ − 449 if(fabsf(gPressure - gSurface_pressure_bar) < PRESSURE_HALF_METER)
+ − 450 {
+ − 451 gPressure = gSurface_pressure_bar;
+ − 452 return 0;
+ − 453 }
+ − 454
+ − 455 pressureTop = gPressure - pressure_decrease;
+ − 456 if( gSurface_pressure_bar > pressureTop)
+ − 457 pressureTop = gSurface_pressure_bar;
+ − 458 pressureBottom = gPressure;
+ − 459 seconds = 0;
+ − 460 do{
+ − 461 pressureTop_tmp = pressureTop;
+ − 462 for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
+ − 463 {
862
+ − 464 if((pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
+ − 465 || (pDiveSettings->gas[pDiveSettings->decogaslist[i].GasIdInSettings].note.ub.decocalc == 0))
+ − 466 {
38
+ − 467 break;
862
+ − 468 }
255
+ − 469 pressureChange = gSurface_pressure_bar + ((float)pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero) / 10;
38
+ − 470 if(pressureBottom <= pressureChange)
+ − 471 {
+ − 472 gGas_id = i;
+ − 473 }
+ − 474 else
+ − 475 {
+ − 476 break;
+ − 477 }
+ − 478
+ − 479 }
+ − 480 for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
+ − 481 {
862
+ − 482 if((pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
+ − 483 || (pDiveSettings->gas[pDiveSettings->decogaslist[i].GasIdInSettings].note.ub.decocalc == 0))
+ − 484 {
38
+ − 485 break;
862
+ − 486 }
+ − 487
255
+ − 488 pressureChange = gSurface_pressure_bar + ((float)pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero)/ 10;
38
+ − 489 if((pressureChange < pressureBottom) && (pressureChange > pressureTop))
+ − 490 {
+ − 491 pressureTop_tmp = pressureChange;
+ − 492 }
+ − 493 }
+ − 494 pressure_difference = pressureBottom - pressureTop_tmp;
+ − 495 if(pressure_difference > 0.0001f)
+ − 496 {
+ − 497 time_for_ascend = (int)ceilf(pressure_difference * ascendrate_in_seconds_for_one_bar);
255
+ − 498 decom_tissues_exposure_stage_schreiner(time_for_ascend, &pDiveSettings->decogaslist[gGas_id],
38
+ − 499 pressureBottom, pressureTop_tmp, gTissue_nitrogen_bar, gTissue_helium_bar);
255
+ − 500 decom_oxygen_calculate_cns_stage_SchreinerStyle(time_for_ascend,&pDiveSettings->decogaslist[gGas_id],
38
+ − 501 pressureBottom, pressureTop_tmp, &gCNS);
+ − 502 }
+ − 503 pressureBottom = pressureTop_tmp;
+ − 504 seconds += time_for_ascend;
+ − 505 }while(pressureTop_tmp > pressureTop);
+ − 506 gPressure = pressureTop;
+ − 507 return seconds;
+ − 508 }
+ − 509
+ − 510
255
+ − 511 static float get_gf_at_pressure(SDiveSettings *pDiveSettings, float pressure)
38
+ − 512 {
+ − 513 float gfSteigung = 0.0f;
+ − 514
+ − 515 if(gGF_low_depth_bar < 0)
+ − 516 gGF_low_depth_bar = PRESSURE_THREE_METER; // just to prevent erratic behaviour if variable is not set
+ − 517
255
+ − 518 gfSteigung = ((float)(pDiveSettings->gf_high - pDiveSettings->gf_low))/ gGF_low_depth_bar;
38
+ − 519
+ − 520
+ − 521 if((pressure - gSurface_pressure_bar) <= PRESSURE_HALF_METER)
255
+ − 522 return ((float)pDiveSettings->gf_high) / 100.0f;
38
+ − 523
+ − 524 if(pressure >= gSurface_pressure_bar + gGF_low_depth_bar)
255
+ − 525 return ((float)pDiveSettings->gf_low) / 100.0f;
38
+ − 526
255
+ − 527 return (pDiveSettings->gf_high - gfSteigung * (pressure - gSurface_pressure_bar) )/ 100.0f;
38
+ − 528 }
+ − 529
291
+ − 530 #define MAX_NDL 240
257
+ − 531 static int buehlmann_calc_ndl(SDiveSettings *pDiveSettings)
38
+ − 532 {
+ − 533 float local_tissue_nitrogen_bar[16];
+ − 534 float local_tissue_helium_bar[16];
+ − 535 int i;
257
+ − 536 int ndl = 0;
38
+ − 537
+ − 538 //Check ndl always use gHigh
255
+ − 539 gGF_value = ((float)pDiveSettings->gf_high) / 100.0f;
38
+ − 540 //10 minutes steps
291
+ − 541 while(ndl < (MAX_NDL * 60))
38
+ − 542 {
+ − 543 memcpy(local_tissue_nitrogen_bar, gTissue_nitrogen_bar, (4*16));
+ − 544 memcpy(local_tissue_helium_bar, gTissue_helium_bar, (4*16));
+ − 545 //
257
+ − 546 ndl += 600;
255
+ − 547 decom_tissues_exposure2(600, &pDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar);
+ − 548 decom_oxygen_calculate_cns_exposure(600,&pDiveSettings->decogaslist[gGas_id],gPressure,&gCNS);
38
+ − 549 buehlmann_backup_and_restore(true);
255
+ − 550 if(dive1_check_deco(pDiveSettings))
38
+ − 551 {
+ − 552 buehlmann_backup_and_restore(false);
+ − 553 break;
+ − 554 }
+ − 555 buehlmann_backup_and_restore(false);
+ − 556 }
+ − 557
291
+ − 558 if(ndl < (MAX_NDL * 60))
257
+ − 559 ndl -= 600;
38
+ − 560
291
+ − 561 if(ndl > (MAX_NDL/2 * 60))
257
+ − 562 return ndl;
38
+ − 563
+ − 564 // refine
+ − 565 memcpy(gTissue_nitrogen_bar, local_tissue_nitrogen_bar, (4*16));
+ − 566 memcpy(gTissue_helium_bar, local_tissue_helium_bar, (4*16));
+ − 567
+ − 568 //One minutes step
256
+ − 569 for(i = 0; i < 10; i++)
38
+ − 570 {
257
+ − 571 ndl += 60;
255
+ − 572 decom_tissues_exposure2(60, &pDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar);
+ − 573 decom_oxygen_calculate_cns_exposure(60,&pDiveSettings->decogaslist[gGas_id],gPressure,&gCNS);
38
+ − 574 buehlmann_backup_and_restore(true);
255
+ − 575 if(dive1_check_deco(pDiveSettings))
38
+ − 576 break;
+ − 577 buehlmann_backup_and_restore(false);
+ − 578 }
257
+ − 579 return ndl;
38
+ − 580 }
+ − 581
+ − 582
+ − 583 // ===============================================================================
+ − 584 // dive1_check_deco
+ − 585 /// @brief for NDL calculations
+ − 586 /// 160614 using ceilingOther and not ceiling
+ − 587 // ===============================================================================
255
+ − 588 static _Bool dive1_check_deco(SDiveSettings *pDiveSettings)
38
+ − 589 {
+ − 590 // gGF_value is set in call routine;
+ − 591 // internes Backup!
+ − 592
+ − 593 // calc like in deco
+ − 594 float ceiling;
+ − 595 float ceilingOther; // new hw 160614
+ − 596
+ − 597 ceiling = tissue_tolerance();
255
+ − 598 ambient_bar_to_deco_stop_depth_bar(pDiveSettings, ceiling); // this will set gStop.depth :-) (and gStop.id)
38
+ − 599
+ − 600 // set the base for all upcoming parameters
+ − 601 ceilingOther = gStop.depth + gSurface_pressure_bar;
+ − 602
+ − 603 // modify parameters if there is ascend or parameter fine adjustment
+ − 604 if(ceilingOther < (gPressure - PRESSURE_150_CM)) // more than 1.5 meter below ceiling
+ − 605 {
+ − 606 // ascend within 10 mtr to GF_low // speed 12 mtr/min -> 50 sec / 10 mtr; 15 sec / 3 mtr.
+ − 607 while(((gPressure - PRESSURE_TEN_METER ) > gSurface_pressure_bar) && (ceiling < (gPressure - PRESSURE_TEN_METER)))
+ − 608 {
255
+ − 609 ascend_with_all_gaschanges(pDiveSettings, PRESSURE_TEN_METER);
38
+ − 610 ceiling = tissue_tolerance();
+ − 611 }
+ − 612 while(((gPressure - PRESSURE_THREE_METER )> gSurface_pressure_bar) && (ceiling < gPressure))
+ − 613 {
255
+ − 614 ascend_with_all_gaschanges(pDiveSettings, PRESSURE_THREE_METER);
38
+ − 615 ceiling = tissue_tolerance();
+ − 616 }
+ − 617 }
255
+ − 618 return ceiling > gSurface_pressure_bar;
38
+ − 619 }
+ − 620
250
+ − 621 // compute ceiling recursively, with a resolution of 10cm. Notice
+ − 622 // that the initial call shall guarantee that the found ceiling
+ − 623 // is between low and high parameters.
+ − 624 static float compute_ceiling(float low, float high)
38
+ − 625 {
250
+ − 626 if ((high - low) < 0.01)
+ − 627 return low;
+ − 628 else {
+ − 629 float next_pressure_absolute = (low + high)/2;
+ − 630 float test_result = buehlmann_tissue_test_tolerance(next_pressure_absolute);
+ − 631 if (test_result < 0)
+ − 632 return compute_ceiling(low, next_pressure_absolute);
+ − 633 else
+ − 634 return compute_ceiling(next_pressure_absolute, high);
+ − 635 }
+ − 636 }
38
+ − 637
250
+ − 638 void buehlmann_ceiling_calculator(SLifeData *pLifeData, SDecoinfo *pDecoInfo)
+ − 639 {
+ − 640 float ceiling;
224
+ − 641
261
+ − 642 memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16));
+ − 643 memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16));
+ − 644
250
+ − 645 // this is just performance optimizing. The code below runs just fine
+ − 646 // without this. There is never a ceiling in NDL deco state
+ − 647 if (!pDecoInfo->output_time_to_surface_seconds) {
+ − 648 pDecoInfo->output_ceiling_meter = 0;
+ − 649 return;
38
+ − 650 }
+ − 651
250
+ − 652 ceiling = compute_ceiling(pLifeData->pressure_surface_bar, 1.0f + pLifeData->max_depth_meter/10.0f);
+ − 653 pDecoInfo->output_ceiling_meter = (ceiling - pLifeData->pressure_surface_bar) * 10.0f;
38
+ − 654 }