38
|
1 /* getrennte Gase für die verschiedenen Modi
|
|
2 um Gaswechsel Einträge zu vereinfachen
|
|
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 "arm_math.h"
|
|
13 #include <math.h>
|
|
14 #include <stdbool.h>
|
|
15 #include "buehlmann.h"
|
|
16 #include "decom.h"
|
|
17
|
|
18
|
|
19 extern const float helium_time_constant[16];
|
|
20 extern const float nitrogen_time_constant[16];
|
|
21
|
|
22 extern const float buehlmann_N2_a[];
|
|
23 extern const float buehlmann_N2_b[];
|
|
24 extern const float buehlmann_He_a[];
|
|
25 extern const float buehlmann_He_b[];
|
|
26
|
|
27
|
|
28 /*
|
|
29 typedef struct
|
|
30 {
|
|
31 float *pointer_array_tissue_nitrogen_bar;
|
|
32 float *pointer_array_tissue_helium_bar;
|
|
33 char gf_value;
|
|
34
|
|
35 float output_ceiling_ambient_bar_or_input;
|
|
36 _Bool output_ceiling_tolerated_if_ceiling_used_as_input;
|
|
37 } tissue_test_tolerance_struct;
|
|
38 */
|
|
39 typedef struct
|
|
40 {
|
|
41 float depth;
|
|
42 int id;
|
|
43 } SStop;
|
|
44
|
|
45 #define DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS 59940 // 999 minuten; before: 18000 // 5(h) * 60(min) * 60 sec = 18000 sec
|
|
46 #define DECO_STOPS_MAX_TTS_FOR_EVERY_SECOND_CALC_IN_SECONDS 7200
|
|
47 #define NINETY_NINE_MINUTES_IN_SECONDS 59940
|
|
48
|
|
49 # define PRESSURE_TEN_METER 1.0f
|
|
50 # define PRESSURE_THREE_METER 0.333334f
|
|
51 # define PRESSURE_150_CM 0.15f
|
|
52 # define PRESSURE_HALF_METER 0.05f
|
|
53 /*
|
|
54 # define PRESSURE_150_CM_MBAR 150
|
|
55 # define PRESSURE_TWO_M_MBAR 200
|
|
56 # define PRESSURE_FIVE_M_MBAR 500
|
|
57 # define PRESSURE_TEN_M_MBAR 1000
|
|
58 # define PRESSURE_120_METER 12.0
|
|
59 */
|
|
60 /*
|
|
61 _____________________________________________________________
|
|
62 */
|
|
63
|
|
64
|
|
65 void buehlmann_backup_and_restore(_Bool backup_restore_otherwise);
|
|
66 float tissue_tolerance(void);
|
|
67 void ambient_bar_to_deco_stop_depth_bar(float ceiling);
|
|
68 int ascend_with_all_gaschanges(float pressure_decrease);
|
|
69 float next_stop_depth_input_is_actual_stop_id(int actual_id);
|
|
70 float get_gf_at_pressure(float pressure);
|
|
71 void buehlmann_calc_ndl(void);
|
|
72 _Bool dive1_check_deco(void);
|
|
73 uint8_t buehlmann_tissue_test_tolerance(float depth_in_bar_absolute);
|
|
74
|
|
75 /*
|
|
76 _____________________________________________________________
|
|
77 */
|
|
78
|
|
79 SDecoinfo gDecotable;
|
|
80 float gSurface_pressure_bar;
|
|
81
|
|
82 float gPressure;
|
|
83 int gGas_id;
|
|
84 float gTTS;
|
|
85 float gTissue_nitrogen_bar[16];
|
|
86 float gTissue_helium_bar[16];
|
|
87 float gGF_value;
|
|
88 float gCNS;
|
|
89 //float gMax_ceiling_bar = 0;
|
|
90 int gNDL;
|
|
91
|
|
92
|
|
93 //SLifeData *pLifeData;
|
|
94 SDiveSettings *pBuDiveSettings;
|
|
95 SDecoinfo* pDecolistBuehlmann;
|
|
96 //signed char gGaschange_decreasing_depth_gas_id[BUEHLMANN_STRUCT_MAX_GASES];
|
|
97 float gGF_low_depth_bar;
|
|
98 SStop gStop;
|
|
99
|
|
100 void buehlmann_init(void)
|
|
101 {
|
|
102 //gMax_ceiling_bar = 0;
|
|
103 }
|
|
104
|
|
105 void buehlmann_backup_and_restore(_Bool backup_restore_otherwise)
|
|
106 {
|
|
107 static float pressure;
|
|
108 static float gas_id;
|
|
109 static float tts;
|
|
110 static float tissue_nitrogen_bar[16];
|
|
111 static float tissue_helium_bar[16];
|
|
112 static float gf_value;
|
|
113 static int ndl;
|
|
114 static float cns;
|
|
115
|
|
116 if(backup_restore_otherwise)
|
|
117 {
|
|
118 pressure = gPressure;
|
|
119 gas_id = gGas_id;
|
|
120 tts = gTTS;
|
|
121 gf_value = gGF_value;
|
|
122 ndl = gNDL;
|
|
123 cns = gCNS;
|
|
124 memcpy(tissue_nitrogen_bar, gTissue_nitrogen_bar, (4*16));
|
|
125 memcpy(tissue_helium_bar, gTissue_helium_bar, (4*16));
|
|
126 }
|
|
127 else
|
|
128 {
|
|
129 gPressure = pressure;
|
|
130 gGas_id = gas_id;
|
|
131 gTTS = tts;
|
|
132 gGF_value = gf_value;
|
|
133 gNDL = ndl;
|
|
134 gCNS = cns;
|
|
135 memcpy(gTissue_nitrogen_bar, tissue_nitrogen_bar, (4*16));
|
|
136 memcpy(gTissue_helium_bar, tissue_helium_bar, (4*16));
|
|
137 }
|
|
138
|
|
139 }
|
|
140 /*void buehlmann__test__saturate_tissues(SBuehlmann *pInput, int seconds)
|
|
141 {
|
|
142 pBuehlmann = pInput;
|
|
143 pInput->dive_time_seconds += seconds;
|
|
144 // internal copying
|
|
145 gSurface_pressure_bar = pBuehlmann->pressure_surface_bar;
|
|
146
|
|
147 gPressure = pBuehlmann->pressure_ambient_bar;
|
|
148 gGas_id = pBuehlmann->actual_gas_id;
|
|
149 memcpy(gTissue_nitrogen_bar, pBuehlmann->tissue_nitrogen_bar, (4*16));
|
|
150 memcpy(gTissue_helium_bar, pBuehlmann->tissue_helium_bar, (4*16));
|
|
151
|
|
152 tissues_exposure_at_gPressure_seconds(seconds);
|
|
153
|
|
154 memcpy(pBuehlmann->tissue_nitrogen_bar, gTissue_nitrogen_bar, (4*16));
|
|
155 memcpy(pBuehlmann->tissue_helium_bar, gTissue_helium_bar, (4*16));
|
|
156 }*/
|
|
157
|
|
158 float buehlmann_get_gCNS(void)
|
|
159 {
|
|
160 return gCNS;
|
|
161 }
|
|
162
|
|
163 void buehlmann_calc_deco(SLifeData* pLifeData, SDiveSettings * pDiveSettings, SDecoinfo * pDecoInfo)
|
|
164 {
|
|
165 float ceiling;
|
|
166 int ascend_time;
|
|
167 int tts_seconds;
|
|
168 float pressure_delta;
|
|
169 float next_depth;
|
|
170 _Bool deco_reached = false;
|
|
171 // tissue_test_tolerance_struct tolerance_data;
|
|
172 unsigned short *stoplist;
|
|
173 int i;
|
|
174
|
|
175 // decom_CreateGasChangeList(pDiveSettings, pLifeData);
|
|
176
|
|
177 gCNS = 0;
|
|
178 pDecoInfo->output_time_to_surface_seconds = 0;
|
|
179 pDecoInfo->output_ndl_seconds = 0;
|
|
180 for(int i=0;i<DECOINFO_STRUCT_MAX_STOPS;i++)
|
|
181 {
|
|
182 pDecoInfo->output_stop_length_seconds[i] = 0;
|
|
183 }
|
|
184 /* make input available global*/
|
|
185 pBuDiveSettings = pDiveSettings;
|
|
186
|
|
187 pDecolistBuehlmann = pDecoInfo;
|
|
188 /* internal copying */
|
|
189 gSurface_pressure_bar = pLifeData->pressure_surface_bar;
|
|
190
|
|
191 gPressure = pLifeData->pressure_ambient_bar;
|
|
192 gGas_id = 0;
|
|
193 memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16));
|
|
194 memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16));
|
|
195 gGF_value = ((float)pBuDiveSettings->gf_low) / 100.0f;
|
|
196
|
|
197 //
|
|
198 memcpy(&gDecotable, pDecolistBuehlmann, sizeof(SDecoinfo));
|
|
199 stoplist = gDecotable.output_stop_length_seconds;
|
|
200
|
|
201
|
|
202 if(pLifeData->dive_time_seconds < 60)
|
|
203 return;
|
|
204 /* coupling */
|
|
205
|
|
206 /* functions */
|
|
207
|
|
208 // clean stop list
|
|
209 for(i = 0; i < DECOINFO_STRUCT_MAX_STOPS; i++)
|
|
210 stoplist[i] = 0;
|
|
211 gTTS = 0;
|
|
212 gNDL = 0;
|
|
213
|
|
214 if(pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero >= (gPressure - PRESSURE_150_CM))
|
|
215 {
|
|
216 deco_reached = true;
|
|
217 }
|
|
218
|
|
219
|
|
220 //ascend_with_all_gaschanges(gPressure - gSurface_pressure_bar);
|
|
221 gGF_value = ((float)pBuDiveSettings->gf_high) / 100.0f;
|
|
222 //iling = tissue_tolerance();
|
|
223 // includes backup for gGF_value
|
|
224 // NDL
|
|
225 buehlmann_backup_and_restore(true); // includes backup for gGF_value
|
|
226 if(!dive1_check_deco() )
|
|
227 {
|
|
228 buehlmann_backup_and_restore(false);
|
|
229 // no deco
|
|
230 pDecolistBuehlmann->output_time_to_surface_seconds = 0;
|
|
231 for(i = 0; i < DECOINFO_STRUCT_MAX_STOPS; i++)
|
|
232 pDecolistBuehlmann->output_stop_length_seconds[i] = 0;
|
|
233 // calc NDL
|
|
234 buehlmann_calc_ndl();
|
|
235 pDecolistBuehlmann->output_ndl_seconds = gNDL;
|
|
236 return;
|
|
237 }
|
|
238 buehlmann_backup_and_restore(false);
|
|
239 pDecolistBuehlmann->output_ndl_seconds = 0;
|
|
240
|
|
241 gGF_value = get_gf_at_pressure(gPressure);
|
|
242 //current ceiling at actual position
|
|
243 ceiling = tissue_tolerance();
|
|
244 //if(ceiling < pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero)
|
|
245 //ambient_bar_to_deco_stop_depth_bar(pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero);
|
|
246 //else
|
|
247 ambient_bar_to_deco_stop_depth_bar(ceiling);
|
|
248
|
|
249 // set the base for all upcoming parameters
|
|
250 ceiling = gStop.depth + gSurface_pressure_bar;
|
|
251 tts_seconds = 0;
|
|
252
|
|
253 // modify parameters if there is ascend or parameter fine adjustment
|
|
254 if(ceiling < (gPressure - PRESSURE_150_CM)) // more than 1.5 meter below ceiling
|
|
255 {
|
|
256 // ascend within 10 mtr to GF_low // speed 12 mtr/min -> 50 sec / 10 mtr; 15 sec / 3 mtr.
|
|
257 if(ceiling < (gPressure - PRESSURE_TEN_METER) )
|
|
258 { do {
|
|
259 ascend_time = ascend_with_all_gaschanges(PRESSURE_TEN_METER);
|
|
260 tts_seconds += ascend_time;
|
|
261 ceiling = tissue_tolerance();
|
|
262 if(tts_seconds > DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS)
|
|
263 {
|
|
264 /* pInput == pBuehlmann */
|
|
265 pDecolistBuehlmann->output_time_to_surface_seconds = NINETY_NINE_MINUTES_IN_SECONDS;
|
|
266 return;// NINETY_NINE_MINUTES_IN_SECONDS;
|
|
267 }
|
|
268 } while ((ascend_time > 0 ) && ((gPressure - PRESSURE_TEN_METER ) > gSurface_pressure_bar) && (ceiling < (gPressure - PRESSURE_TEN_METER)));
|
|
269 }
|
|
270 do {
|
|
271 buehlmann_backup_and_restore(true);
|
|
272 ascend_time = ascend_with_all_gaschanges(PRESSURE_THREE_METER);
|
|
273 tts_seconds += ascend_time;
|
|
274 ceiling = tissue_tolerance();
|
|
275 if(tts_seconds > DECO_STOPS_MAX_TTS_CALCULATON_IN_SECONDS)
|
|
276 {
|
|
277 /* pInput == pBuehlmann */
|
|
278 pDecolistBuehlmann->output_time_to_surface_seconds = NINETY_NINE_MINUTES_IN_SECONDS;
|
|
279 return;// NINETY_NINE_MINUTES_IN_SECONDS;
|
|
280 }
|
|
281 ambient_bar_to_deco_stop_depth_bar(ceiling);
|
|
282 } while ((ascend_time > 0 ) && ((gStop.depth + gSurface_pressure_bar) < gPressure));
|
|
283
|
|
284 if(gStop.depth + gSurface_pressure_bar > gPressure)
|
|
285 {
|
|
286 gPressure += PRESSURE_THREE_METER;
|
|
287 buehlmann_backup_and_restore(false);
|
|
288 tts_seconds -= ascend_time;
|
|
289 }
|
|
290 // calculate first stop based on tissue saturation within 10 meters of stop
|
|
291 //ambient_bar_to_deco_stop_depth_bar(ceiling);
|
|
292 }
|
|
293 else
|
|
294 {
|
|
295 // initial values, upper code might not be executed (is within 150 cm)
|
|
296 }
|
|
297
|
|
298
|
|
299
|
|
300
|
|
301 if(ceiling > gSurface_pressure_bar)
|
|
302 {
|
|
303
|
|
304 ceiling = gStop.depth + gSurface_pressure_bar;
|
|
305 // ascend the last meters to first stop (especially consider any gas changes around)
|
|
306 pressure_delta = gPressure - ceiling;
|
|
307 ascend_time = (int)ceil(pressure_delta * 50.0f);
|
|
308 tts_seconds += ascend_with_all_gaschanges(pressure_delta);
|
|
309 }
|
|
310 // NDL check
|
|
311 if(ceiling <= gSurface_pressure_bar)
|
|
312 {
|
|
313 /* pInput == pBuehlmann same pointer*/
|
|
314 // NDL with GF_low
|
|
315 pDecolistBuehlmann->output_time_to_surface_seconds = 0;
|
|
316 return;
|
|
317 }
|
|
318 if(ceiling >pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero)
|
|
319 pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = ceiling;
|
|
320
|
|
321 // calc gf loop
|
|
322 if(deco_reached)
|
|
323 gGF_low_depth_bar = pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero - gSurface_pressure_bar;
|
|
324 else
|
|
325 gGF_low_depth_bar = ceiling - gSurface_pressure_bar;
|
|
326
|
|
327 while(gStop.depth > 0)
|
|
328 {
|
|
329 do
|
|
330 {
|
|
331 next_depth = next_stop_depth_input_is_actual_stop_id(gStop.id);
|
|
332 gGF_value = get_gf_at_pressure(next_depth + gSurface_pressure_bar);
|
|
333 buehlmann_backup_and_restore(true);
|
|
334 ascend_time = ascend_with_all_gaschanges(gStop.depth - next_depth);
|
|
335 ceiling = tissue_tolerance();
|
|
336 /* pre check actual limit */
|
|
337 if(gDecotable.output_stop_length_seconds[gStop.id] >= 999*60)
|
|
338 {
|
|
339 tts_seconds -= 999*60 - gDecotable.output_stop_length_seconds[gStop.id];
|
|
340 gDecotable.output_stop_length_seconds[gStop.id] = 999*60;
|
|
341 }
|
|
342 else
|
|
343 /* more deco on the actual depth */
|
|
344 if(ceiling > next_depth + gSurface_pressure_bar)
|
|
345 {
|
|
346 next_depth = -1;
|
|
347 buehlmann_backup_and_restore(false);
|
|
348 decom_tissues_exposure2(10, &pBuDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar); // some seconds at least at each stop
|
|
349 decom_oxygen_calculate_cns_exposure(10, &pBuDiveSettings->decogaslist[gGas_id], gPressure, &gCNS);
|
|
350 gDecotable.output_stop_length_seconds[gStop.id] += 10;
|
|
351 tts_seconds += 10;
|
|
352 }
|
|
353 } while(next_depth == -1);
|
|
354 tts_seconds += ascend_time;
|
|
355 gStop.depth = next_depth;
|
|
356 for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
|
|
357 {
|
|
358 if(pBuDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
|
|
359 break;
|
|
360 float pressureChange = ((float)pBuDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero) / 10;
|
|
361 if(gStop.depth <= pressureChange + 0.00001f)
|
|
362 {
|
|
363 gGas_id = i;
|
|
364 }
|
|
365 else
|
|
366 {
|
|
367 break;
|
|
368 }
|
|
369 }
|
|
370 gStop.id--;
|
|
371 }
|
|
372
|
|
373 gDecotable.output_time_to_surface_seconds = tts_seconds;
|
|
374 memcpy(pDecolistBuehlmann, &gDecotable, sizeof(SDecoinfo));
|
|
375 }
|
|
376
|
|
377
|
|
378 float tissue_tolerance(void)
|
|
379 {
|
|
380 float tissue_inertgas_saturation;
|
|
381 float inertgas_a;
|
|
382 float inertgas_b;
|
|
383 float ceiling;
|
|
384 float global_ceiling;
|
|
385 int ci;
|
|
386
|
|
387 global_ceiling = -1;
|
|
388
|
|
389 for (ci = 0; ci < 16; ci++)
|
|
390 {
|
|
391 if(gTissue_helium_bar[ci] == 0)
|
|
392 {
|
|
393 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
|
|
394 //
|
|
395 inertgas_a = buehlmann_N2_a[ci];
|
|
396 inertgas_b = buehlmann_N2_b[ci];
|
|
397 }
|
|
398 else
|
|
399 {
|
|
400 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
|
|
401 //
|
|
402 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
|
|
403 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
|
|
404 }
|
|
405 //
|
|
406 ceiling = (inertgas_b * ( tissue_inertgas_saturation - gGF_value * inertgas_a ) ) / (gGF_value - (inertgas_b * gGF_value) + inertgas_b);
|
|
407 if(ceiling > global_ceiling)
|
|
408 global_ceiling = ceiling;
|
|
409 }
|
|
410 return global_ceiling;
|
|
411 }
|
|
412
|
|
413 // hw 161121 for relative gradient
|
|
414 float tissue_tolerance_without_gf_correction(float *tissue_inertgas_saturation_output)
|
|
415 {
|
|
416 float tissue_inertgas_saturation;
|
|
417 float inertgas_a;
|
|
418 float inertgas_b;
|
|
419 float ceiling;
|
|
420 float global_ceiling;
|
|
421 int ci;
|
|
422
|
|
423 global_ceiling = -1;
|
|
424
|
|
425 for (ci = 0; ci < 16; ci++)
|
|
426 {
|
|
427 if(gTissue_helium_bar[ci] == 0)
|
|
428 {
|
|
429 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
|
|
430 //
|
|
431 inertgas_a = buehlmann_N2_a[ci];
|
|
432 inertgas_b = buehlmann_N2_b[ci];
|
|
433 }
|
|
434 else
|
|
435 {
|
|
436 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
|
|
437 //
|
|
438 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
|
|
439 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
|
|
440 }
|
|
441 //
|
|
442 ceiling = inertgas_b * ( tissue_inertgas_saturation - inertgas_a );
|
|
443 if(ceiling > global_ceiling)
|
|
444 {
|
|
445 global_ceiling = ceiling;
|
|
446 if(tissue_inertgas_saturation_output)
|
|
447 {
|
|
448 *tissue_inertgas_saturation_output = tissue_inertgas_saturation;
|
|
449 }
|
|
450 }
|
|
451 }
|
|
452 return global_ceiling;
|
|
453 }
|
|
454
|
|
455
|
|
456 uint8_t buehlmann_tissue_test_tolerance(float depth_in_bar_absolute)
|
|
457 {
|
|
458 float tissue_inertgas_saturation;
|
|
459 float inertgas_a;
|
|
460 float inertgas_b;
|
|
461 float inertgas_tolerance;
|
|
462 float gf_minus_1;
|
|
463
|
|
464 gf_minus_1 = gGF_value - 1.0f;
|
|
465
|
|
466 for (int ci = 0; ci < 16; ci++)
|
|
467 {
|
|
468 if(gTissue_helium_bar[ci] == 0)
|
|
469 {
|
|
470 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
|
|
471 //
|
|
472 inertgas_a = buehlmann_N2_a[ci];
|
|
473 inertgas_b = buehlmann_N2_b[ci];
|
|
474 }
|
|
475 else
|
|
476 {
|
|
477 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
|
|
478 //
|
|
479 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
|
|
480 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
|
|
481 }
|
|
482 //
|
|
483 inertgas_tolerance = ( (gGF_value / inertgas_b - gf_minus_1) * depth_in_bar_absolute ) + ( gGF_value * inertgas_a );
|
|
484 //
|
|
485 if(inertgas_tolerance < tissue_inertgas_saturation)
|
|
486 return 0;
|
|
487 }
|
|
488 return 1;
|
|
489 }
|
|
490
|
|
491
|
|
492 void ambient_bar_to_deco_stop_depth_bar(float ceiling)
|
|
493 {
|
|
494 int i;
|
|
495
|
|
496 ceiling -= gSurface_pressure_bar;
|
|
497
|
|
498 if(ceiling <= 0)
|
|
499 {
|
|
500 gStop.depth = pBuDiveSettings->last_stop_depth_bar;
|
|
501 gStop.id = 0;
|
|
502 return;
|
|
503 }
|
|
504
|
|
505
|
|
506 //for(int i = 1; i < 10; i++)
|
|
507
|
|
508 if((ceiling - pBuDiveSettings->last_stop_depth_bar) <= 0)
|
|
509 {
|
|
510 gStop.depth = pBuDiveSettings->last_stop_depth_bar;
|
|
511 gStop.id = 0;
|
|
512 return;
|
|
513 }
|
|
514
|
|
515 gStop.depth = pBuDiveSettings->input_second_to_last_stop_depth_bar;
|
|
516 gStop.id = 1;
|
|
517 ceiling -= pBuDiveSettings->input_second_to_last_stop_depth_bar;
|
|
518
|
|
519 if(ceiling <= 0)
|
|
520 return;
|
|
521
|
|
522 for(i = 1; i < (DECOINFO_STRUCT_MAX_STOPS - 2); i++)
|
|
523 {
|
|
524 ceiling -= pBuDiveSettings->input_next_stop_increment_depth_bar;
|
|
525 if(ceiling <= 0)
|
|
526 break;
|
|
527 }
|
|
528 gStop.depth += i * pBuDiveSettings->input_next_stop_increment_depth_bar;
|
|
529 gStop.id += i;
|
|
530 return;
|
|
531 }
|
|
532
|
|
533 float next_stop_depth_input_is_actual_stop_id(int actual_id)
|
|
534 {
|
|
535 if(actual_id == 0)
|
|
536 return 0;
|
|
537
|
|
538 if(actual_id == 1)
|
|
539 return pBuDiveSettings->last_stop_depth_bar;
|
|
540
|
|
541 actual_id -= 2;
|
|
542 return pBuDiveSettings->input_second_to_last_stop_depth_bar + (actual_id * pBuDiveSettings->input_next_stop_increment_depth_bar);
|
|
543 }
|
|
544
|
|
545 int ascend_with_all_gaschanges(float pressure_decrease)
|
|
546 {
|
|
547 float pressureTop, pressureTop_tmp, pressureBottom, pressureChange, ascendrate_in_seconds_for_one_bar, pressure_difference;
|
|
548 int time_for_ascend;
|
|
549 int seconds;
|
|
550 int i;
|
|
551
|
|
552 ascendrate_in_seconds_for_one_bar = 60 * 10 / pBuDiveSettings->ascentRate_meterperminute;
|
|
553
|
|
554 if(fabsf(gPressure - gSurface_pressure_bar) < PRESSURE_HALF_METER)
|
|
555 {
|
|
556 gPressure = gSurface_pressure_bar;
|
|
557 return 0;
|
|
558 }
|
|
559
|
|
560 pressureTop = gPressure - pressure_decrease;
|
|
561 if( gSurface_pressure_bar > pressureTop)
|
|
562 pressureTop = gSurface_pressure_bar;
|
|
563 pressureBottom = gPressure;
|
|
564 seconds = 0;
|
|
565 do{
|
|
566 pressureTop_tmp = pressureTop;
|
|
567 for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
|
|
568 {
|
|
569 if(pBuDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
|
|
570 break;
|
|
571 pressureChange = gSurface_pressure_bar + ((float)pBuDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero) / 10;
|
|
572 if(pressureBottom <= pressureChange)
|
|
573 {
|
|
574 gGas_id = i;
|
|
575 }
|
|
576 else
|
|
577 {
|
|
578 break;
|
|
579 }
|
|
580
|
|
581 }
|
|
582 for(i = gGas_id + 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++)
|
|
583 {
|
|
584 if(pBuDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
|
|
585 break;
|
|
586 pressureChange = gSurface_pressure_bar + ((float)pBuDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero)/ 10;
|
|
587 if((pressureChange < pressureBottom) && (pressureChange > pressureTop))
|
|
588 {
|
|
589 pressureTop_tmp = pressureChange;
|
|
590 }
|
|
591 }
|
|
592 pressure_difference = pressureBottom - pressureTop_tmp;
|
|
593 if(pressure_difference > 0.0001f)
|
|
594 {
|
|
595 time_for_ascend = (int)ceilf(pressure_difference * ascendrate_in_seconds_for_one_bar);
|
|
596 decom_tissues_exposure_stage_schreiner(time_for_ascend, &pBuDiveSettings->decogaslist[gGas_id],
|
|
597 pressureBottom, pressureTop_tmp, gTissue_nitrogen_bar, gTissue_helium_bar);
|
|
598 decom_oxygen_calculate_cns_stage_SchreinerStyle(time_for_ascend,&pBuDiveSettings->decogaslist[gGas_id],
|
|
599 pressureBottom, pressureTop_tmp, &gCNS);
|
|
600 }
|
|
601 pressureBottom = pressureTop_tmp;
|
|
602 seconds += time_for_ascend;
|
|
603 }while(pressureTop_tmp > pressureTop);
|
|
604 gPressure = pressureTop;
|
|
605 return seconds;
|
|
606 }
|
|
607
|
|
608
|
|
609 float get_gf_at_pressure(float pressure)
|
|
610 {
|
|
611 float gfSteigung = 0.0f;
|
|
612
|
|
613 if(gGF_low_depth_bar < 0)
|
|
614 gGF_low_depth_bar = PRESSURE_THREE_METER; // just to prevent erratic behaviour if variable is not set
|
|
615
|
|
616 gfSteigung = ((float)(pBuDiveSettings->gf_high - pBuDiveSettings->gf_low))/ gGF_low_depth_bar;
|
|
617
|
|
618
|
|
619 if((pressure - gSurface_pressure_bar) <= PRESSURE_HALF_METER)
|
|
620 return ((float)pBuDiveSettings->gf_high) / 100.0f;
|
|
621
|
|
622 if(pressure >= gSurface_pressure_bar + gGF_low_depth_bar)
|
|
623 return ((float)pBuDiveSettings->gf_low) / 100.0f;
|
|
624
|
|
625 return (pBuDiveSettings->gf_high - gfSteigung * (pressure - gSurface_pressure_bar) )/ 100.0f;
|
|
626 }
|
|
627
|
|
628
|
|
629 void buehlmann_calc_ndl(void)
|
|
630 {
|
|
631 float local_tissue_nitrogen_bar[16];
|
|
632 float local_tissue_helium_bar[16];
|
|
633 int i;
|
|
634
|
|
635 gNDL = 0;
|
|
636 //Check ndl always use gHigh
|
|
637 gGF_value = ((float)pBuDiveSettings->gf_high) / 100.0f;
|
|
638 //10 minutes steps
|
|
639 while(gNDL < (300 * 60))
|
|
640 {
|
|
641 memcpy(local_tissue_nitrogen_bar, gTissue_nitrogen_bar, (4*16));
|
|
642 memcpy(local_tissue_helium_bar, gTissue_helium_bar, (4*16));
|
|
643 //
|
|
644 gNDL += 600;
|
|
645 decom_tissues_exposure2(600, &pBuDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar);
|
|
646 decom_oxygen_calculate_cns_exposure(600,&pBuDiveSettings->decogaslist[gGas_id],gPressure,&gCNS);
|
|
647 //tissues_exposure_at_gPressure_seconds(600);
|
|
648 buehlmann_backup_and_restore(true);
|
|
649 if(dive1_check_deco() == true)
|
|
650 {
|
|
651 buehlmann_backup_and_restore(false);
|
|
652 break;
|
|
653 }
|
|
654 buehlmann_backup_and_restore(false);
|
|
655 }
|
|
656
|
|
657 if(gNDL < (300 * 60))
|
|
658 gNDL -= 600;
|
|
659
|
|
660 if(gNDL > (150 * 60))
|
|
661 return;
|
|
662
|
|
663 // refine
|
|
664 memcpy(gTissue_nitrogen_bar, local_tissue_nitrogen_bar, (4*16));
|
|
665 memcpy(gTissue_helium_bar, local_tissue_helium_bar, (4*16));
|
|
666
|
|
667 //One minutes step
|
|
668 for(i = 0; i < 20; i++)
|
|
669 {
|
|
670 gNDL += 60;
|
|
671 //tissues_exposure_at_gPressure_seconds(60);
|
|
672 decom_tissues_exposure2(60, &pBuDiveSettings->decogaslist[gGas_id], gPressure,gTissue_nitrogen_bar,gTissue_helium_bar);
|
|
673 decom_oxygen_calculate_cns_exposure(60,&pBuDiveSettings->decogaslist[gGas_id],gPressure,&gCNS);
|
|
674 buehlmann_backup_and_restore(true);
|
|
675 if(dive1_check_deco() == true)
|
|
676 break;
|
|
677 buehlmann_backup_and_restore(false);
|
|
678 }
|
|
679 //gNDL -= 60;
|
|
680 return;
|
|
681 }
|
|
682
|
|
683
|
|
684 // ===============================================================================
|
|
685 // dive1_check_deco
|
|
686 /// @brief for NDL calculations
|
|
687 /// 160614 using ceilingOther and not ceiling
|
|
688 // ===============================================================================
|
|
689 _Bool dive1_check_deco(void)
|
|
690 {
|
|
691 // gGF_value is set in call routine;
|
|
692 // internes Backup!
|
|
693
|
|
694 // calc like in deco
|
|
695 float ceiling;
|
|
696 float ceilingOther; // new hw 160614
|
|
697
|
|
698 ceiling = tissue_tolerance();
|
|
699 ambient_bar_to_deco_stop_depth_bar(ceiling); // this will set gStop.depth :-) (and gStop.id)
|
|
700
|
|
701 // set the base for all upcoming parameters
|
|
702 ceilingOther = gStop.depth + gSurface_pressure_bar;
|
|
703
|
|
704 // modify parameters if there is ascend or parameter fine adjustment
|
|
705 if(ceilingOther < (gPressure - PRESSURE_150_CM)) // more than 1.5 meter below ceiling
|
|
706 {
|
|
707 // ascend within 10 mtr to GF_low // speed 12 mtr/min -> 50 sec / 10 mtr; 15 sec / 3 mtr.
|
|
708 while(((gPressure - PRESSURE_TEN_METER ) > gSurface_pressure_bar) && (ceiling < (gPressure - PRESSURE_TEN_METER)))
|
|
709 {
|
|
710 ascend_with_all_gaschanges(PRESSURE_TEN_METER);
|
|
711 ceiling = tissue_tolerance();
|
|
712 }
|
|
713 while(((gPressure - PRESSURE_THREE_METER )> gSurface_pressure_bar) && (ceiling < gPressure))
|
|
714 {
|
|
715 ascend_with_all_gaschanges(PRESSURE_THREE_METER);
|
|
716 ceiling = tissue_tolerance();
|
|
717 }
|
|
718 }
|
|
719 if(ceiling <= gSurface_pressure_bar)
|
|
720 return false;
|
|
721 else
|
|
722 return true;
|
|
723 }
|
|
724
|
|
725
|
|
726 void buehlmann_ceiling_calculator(SLifeData* pLifeData, SDiveSettings * pDiveSettings, SDecoinfo * pDecoInfo)
|
|
727 {
|
|
728 float gf_low;
|
|
729 float gf_high;
|
|
730 float gf_delta;
|
|
731 int dv_gf_low_stop_meter;
|
|
732 _Bool test_result;
|
|
733 float next_gf_value;
|
|
734 float next_pressure_absolute;
|
|
735 int depth_in_meter;
|
|
736
|
|
737 gf_low = pDiveSettings->gf_low;
|
|
738 gf_high = pDiveSettings->gf_high;
|
|
739
|
|
740 //
|
|
741 dv_gf_low_stop_meter = (int)((pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero - pLifeData->pressure_surface_bar) * 10);
|
|
742 //
|
|
743 if(dv_gf_low_stop_meter < 1)
|
|
744 {
|
|
745 next_gf_value = gf_high; // fix hw 161024
|
|
746 gf_delta = 0;
|
|
747 }
|
|
748 else
|
|
749 {
|
|
750 next_gf_value = gf_high;
|
|
751 gf_delta = gf_high - gf_low;
|
|
752 gf_delta /= dv_gf_low_stop_meter; // gf_delta is delta for each meter now!!
|
|
753 }
|
|
754 //
|
|
755 depth_in_meter = 0;
|
|
756 next_pressure_absolute = pLifeData->pressure_surface_bar;
|
|
757
|
|
758 memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16));
|
|
759 memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16));
|
|
760 gGF_value = next_gf_value / 100.0f;
|
|
761 //
|
|
762 test_result = buehlmann_tissue_test_tolerance(next_pressure_absolute);
|
|
763 //
|
|
764 while(!test_result && depth_in_meter < 200)
|
|
765 {
|
|
766 depth_in_meter += 1;
|
|
767 next_gf_value = fmaxf(gf_low, next_gf_value - gf_delta);
|
|
768 gGF_value = next_gf_value / 100.0f;
|
|
769 next_pressure_absolute += 0.1f; // 1 meter down
|
|
770 test_result = buehlmann_tissue_test_tolerance(next_pressure_absolute);
|
|
771 }
|
|
772 //
|
|
773 if(test_result)
|
|
774 {
|
|
775 // old direct paste
|
|
776 pDecoInfo->output_ceiling_meter = depth_in_meter;
|
|
777 // new sub-meter hw 160331
|
|
778 if(depth_in_meter >= 1)
|
|
779 {
|
|
780 for(int i = 0; i < 10; i++)
|
|
781 {
|
|
782 next_gf_value += gf_delta/10.0f;
|
|
783 gGF_value = next_gf_value / 100.0f;
|
|
784 next_pressure_absolute -= 0.01f; // 0.1 meter up
|
|
785 if(!buehlmann_tissue_test_tolerance(next_pressure_absolute))
|
|
786 {
|
|
787 pDecoInfo->output_ceiling_meter -= ((float)i)/10.0f;
|
|
788 break;
|
|
789 }
|
|
790 }
|
|
791 }
|
|
792 }
|
|
793 else
|
|
794 {
|
|
795 pDecoInfo->output_ceiling_meter = 999;
|
|
796 }
|
|
797 }
|
|
798
|
|
799
|
|
800 void buehlmann_relative_gradient_calculator(SLifeData* pLifeData, SDiveSettings * pDiveSettings, SDecoinfo * pDecoInfo)
|
|
801 {
|
|
802 float gf_low;
|
|
803 float gf_high;
|
|
804 float gf_delta;
|
|
805 int dv_gf_low_stop_meter;
|
|
806
|
|
807 float rgf; // relative gradient factor by hwOS p2_deco.c
|
|
808 float temp_tissue;
|
|
809 float limit;
|
|
810 float pres_respiration;
|
|
811 float gf;
|
|
812
|
|
813 gf_low = pDiveSettings->gf_low;
|
|
814 gf_high = pDiveSettings->gf_high;
|
|
815
|
|
816 dv_gf_low_stop_meter = (int)((pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero - pLifeData->pressure_surface_bar) * 10);
|
|
817
|
|
818 if(dv_gf_low_stop_meter < 1)
|
|
819 {
|
|
820 gf_delta = 0;
|
|
821 }
|
|
822 else
|
|
823 {
|
|
824 gf_delta = gf_high - gf_low;
|
|
825 gf_delta /= dv_gf_low_stop_meter; // gf_delta is delta for each meter now!!
|
|
826 }
|
|
827
|
|
828
|
|
829 limit = tissue_tolerance_without_gf_correction(&temp_tissue);
|
|
830 pres_respiration = pLifeData->pressure_ambient_bar;
|
|
831
|
|
832 if( temp_tissue <= pres_respiration )
|
|
833 {
|
|
834 gf = 0.0;
|
|
835 }
|
|
836 else
|
|
837 {
|
|
838 gf = (temp_tissue - pres_respiration)
|
|
839 / (temp_tissue - limit)
|
|
840 * 100.0f;
|
|
841 }
|
|
842
|
|
843 if(dv_gf_low_stop_meter < 1)
|
|
844 {
|
|
845 rgf = gf_high;
|
|
846 }
|
|
847 else
|
|
848 {
|
|
849 float temp1 = dv_gf_low_stop_meter;
|
|
850 float temp2 = pLifeData->depth_meter;
|
|
851
|
|
852 if (temp2 <= 0)
|
|
853 rgf = gf_high;
|
|
854 else if (temp2 >= temp1)
|
|
855 rgf = gf_low;
|
|
856 else
|
|
857 rgf = gf_low + (temp1 - temp2)*gf_delta;
|
|
858 }
|
|
859
|
|
860 rgf = gf / rgf;
|
|
861
|
|
862 // avoid discussions about values > 100 below next deco stop
|
|
863 if((rgf > 1.0f) && (pLifeData->depth_meter >= pDecoInfo->output_ceiling_meter))
|
|
864 rgf = 1.0f;
|
|
865
|
|
866 pDecoInfo->output_relative_gradient = rgf;
|
|
867 }
|