Mercurial > public > ostc4
annotate Discovery/Src/vpm.c @ 912:57fc479745b0 Evo_2_23
Ascent speed visualization:
Adapted limits for color changes to make sure that 10m/s (used for deco calculations) is still in the green area
author | Ideenmodellierer |
---|---|
date | Tue, 15 Oct 2024 21:07:07 +0200 |
parents | 46a21ff3f5ab |
children |
rev | line source |
---|---|
38 | 1 /////////////////////////////////////////////////////////////////////////////// |
2 /// -*- coding: UTF-8 -*- | |
3 /// | |
4 /// \file Discovery/Src/vpm.c | |
5 /// \brief critical_volume comment by hw | |
6 /// \author Heinrichs Weikamp, Erik C. Baker | |
7 /// \date 19-April-2014 | |
8 /// | |
9 /// \details | |
10 /// | |
11 /// $Id$ | |
12 /////////////////////////////////////////////////////////////////////////////// | |
13 /// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh | |
14 /// | |
15 /// This program is free software: you can redistribute it and/or modify | |
16 /// it under the terms of the GNU General Public License as published by | |
17 /// the Free Software Foundation, either version 3 of the License, or | |
18 /// (at your option) any later version. | |
19 /// | |
20 /// This program is distributed in the hope that it will be useful, | |
21 /// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 /// GNU General Public License for more details. | |
24 /// | |
25 /// You should have received a copy of the GNU General Public License | |
26 /// along with this program. If not, see <http://www.gnu.org/licenses/>. | |
27 ////////////////////////////////////////////////////////////////////////////// | |
28 /// \par Varying Permeability Model (VPM) Decompression Program in c (converted from FORTRAN) | |
29 /// | |
30 /// Author: Erik C. Baker | |
31 /// | |
32 /// "DISTRIBUTE FREELY - CREDIT THE AUTHORS" | |
33 /// | |
34 /// This program extends the 1986 VPM algorithm (Yount & Hoffman) to include | |
35 /// mixed gas, repetitive, and altitude diving. Developments to the algorithm | |
36 /// were made by David E. Yount, Eric B. Maiken, and Erik C. Baker over a | |
37 /// period from 1999 to 2001. This work is dedicated in remembrance of | |
38 /// Professor David E. Yount who passed away on April 27, 2000. | |
39 /// | |
40 /// Notes: | |
41 /// 1. This program uses the sixteen (16) half-time compartments of the | |
42 /// Buhlmann ZH-L16 model. The optional Compartment 1b is used here with | |
43 /// half-times of 1.88 minutes for helium and 5.0 minutes for nitrogen. | |
44 /// | |
45 /// 2. This program uses various DEC, IBM, and Microsoft extensions which | |
46 /// may not be supported by all FORTRAN compilers. Comments are made with | |
47 /// a capital "C" in the first column or an exclamation point "!" placed | |
48 /// in a line after code. An asterisk "*" in column 6 is a continuation | |
49 /// of the previous line. All code, except for line numbers, starts in | |
50 /// column 7. | |
51 /// | |
52 /// 3. Comments and suggestions for improvements are welcome. Please | |
53 /// respond by e-mail to: EBaker@se.aeieng.com | |
54 /// | |
55 /// Acknowledgment: Thanks to Kurt Spaugh for recommendations on how to clean | |
56 /// up the code. | |
57 /// =============================================================================== | |
58 /// Converted to vpmdeco.c using f2c; R.McGinnis (CABER Swe) 5/01 | |
59 /// =============================================================================== | |
60 /// | |
61 /// ************************ Heirichs Weipkamp ************************************** | |
62 /// | |
63 /// The original Yount & Baker code has been adjusted for real life calculation. | |
64 /// | |
65 /// 1) The original main function has been split in several functions | |
66 /// | |
67 /// 2) When the deco zone is reached (while ascending) the gradient factors are kept fix | |
68 /// and critical volume algorithm is switched of. maxfirststopdepth is kept fix | |
69 /// to make shure Boeyls Law algorithm works correctly | |
70 /// | |
71 /// 4) gas_loadings_ascent_descend heeds all gaschanges and CCR support has been added | |
72 /// | |
73 | |
74 #include <stdio.h> | |
75 #include <stdlib.h> | |
76 #include <string.h> | |
77 #include <math.h> | |
78 #include <time.h> | |
79 | |
80 #include "vpm.h" | |
81 #include "decom.h" | |
82 | |
83 #define GAS_N2 0 | |
84 #define GAS_HE 1 | |
85 | |
290 | 86 static const _Bool buehlmannSafety = true; |
38 | 87 /* Common Block Declarations */ |
88 | |
89 extern const float SURFACE_TENSION_GAMMA; //!Adj. Range: 0.015 to 0.065 N/m | |
90 extern const float SKIN_COMPRESSION_GAMMAC; //!Adj. Range: 0.160 to 0.290 N/m | |
91 extern const float UNITS_FACTOR; | |
92 extern const float WATER_VAPOR_PRESSURE; // (Schreiner value) based on respiratory quotien | |
93 extern const float CRIT_VOLUME_PARAMETER_LAMBDA; //!Adj. Range: 6500 to 8300 fsw-min | |
290 | 94 //extern const float GRADIENT_ONSET_OF_IMPERM_ATM; //!Adj. Range: 5.0 to 10.0 atm |
38 | 95 extern const float REGENERATION_TIME_CONSTANT; //!Adj. Range: 10080 to 51840 min |
290 | 96 //extern const float PRESSURE_OTHER_GASES_MMHG; //!Constant value for PO2 up to 2 atm |
38 | 97 extern const float CONSTANT_PRESSURE_OTHER_GASES; // PRESSURE_OTHER_GASES_MMHG / 760. * UNITS_FACTOR; |
98 | |
99 extern const float HELIUM_TIME_CONSTANT[]; | |
100 extern const float NITROGEN_TIME_CONSTANT[]; | |
101 | |
290 | 102 static float minimum_deco_stop_time; |
103 static float run_time, run_time_first_stop; | |
104 static float segment_time; | |
105 static short mix_number; | |
106 static float barometric_pressure; | |
107 static _Bool altitude_dive_algorithm_off; | |
108 static _Bool units_equal_fsw, units_equal_msw; | |
38 | 109 |
110 /* by hw 11.06.2015 to allow */ | |
290 | 111 static float gCNS_VPM; |
38 | 112 |
290 | 113 static float helium_pressure[16], nitrogen_pressure[16]; |
114 static float surface_phase_volume_time[16]; | |
115 static float regenerated_radius_he[16], regenerated_radius_n2[16]; | |
116 static float allowable_gradient_he[16], allowable_gradient_n2[16]; | |
38 | 117 |
118 //_Bool deco_zone_reached; | |
290 | 119 static _Bool critical_volume_algorithm_off; |
120 static float max_first_stop_depth; | |
121 static float max_deco_ceiling_depth; | |
38 | 122 //Boylslaw compensation |
290 | 123 static float deco_gradient_he[16]; |
124 static float deco_gradient_n2[16]; | |
125 static int vpm_calc_what; | |
126 static int count_critical_volume_iteration; | |
127 static short number_of_changes; | |
128 static float depth_change[11]; | |
129 static float step_size_change[11]; | |
130 static float rate_change[11]; | |
131 static short mix_change[11]; | |
38 | 132 |
290 | 133 static const _Bool vpm_b = true; |
38 | 134 |
907 | 135 static SvpmTableState vpmTableState = VPM_TABLE_INIT; |
902 | 136 static SDecoinfo vpmTable; |
137 | |
38 | 138 extern const float float_buehlmann_N2_factor_expositon_20_seconds[]; |
139 extern const float float_buehlmann_He_factor_expositon_20_seconds[]; | |
140 extern const float float_buehlmann_N2_factor_expositon_one_minute[]; | |
141 extern const float float_buehlmann_He_factor_expositon_one_minute[]; | |
142 extern const float float_buehlmann_N2_factor_expositon_five_minutes[]; | |
143 extern const float float_buehlmann_He_factor_expositon_five_minutes[]; | |
144 extern const float float_buehlmann_N2_factor_expositon_one_hour[]; | |
145 extern const float float_buehlmann_He_factor_expositon_one_hour[]; | |
146 | |
290 | 147 static float depth_start_of_deco_calc; |
148 static float depth_start_of_deco_zone; | |
149 static float first_stop_depth; | |
150 static float run_time_start_of_deco_zone; | |
38 | 151 |
290 | 152 static float r_nint(float *x); |
153 static float r_int(float *x); | |
154 static _Bool nullzeit_unter60; | |
155 static int vpm_calc_status; | |
156 static _Bool buehlmann_wait_exceeded = false; | |
38 | 157 |
290 | 158 static SLifeData* pInput = NULL; |
159 static SVpm* pVpm = NULL; | |
160 static SDecoinfo* pDecoInfo = NULL; | |
161 static SDiveSettings* pDiveSettings = NULL; | |
162 | |
163 static float r_nint(float *x) | |
38 | 164 { |
165 return( (*x)>=0 ? | |
166 floorf(*x + 0.5f) : -floorf(0.5f - *x) ); | |
167 } | |
168 | |
290 | 169 static float r_int(float *x) |
38 | 170 { |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
171 return( (*x>0.0) ? floorf(*x) : -floorf(- *x) ); |
38 | 172 } |
173 | |
174 /** private functions | |
175 */ | |
290 | 176 extern int radius_root_finder (float *a, float *b, float *c,float *low_bound, float *high_bound, float *ending_radius); |
38 | 177 |
290 | 178 static int nuclear_regeneration(float *dive_time);// clock_(); |
179 static int calc_deco_ceiling(float *deco_ceiling_depth,_Bool fallowablw); | |
180 static int critical_volume(float *deco_phase_volume_time); ; | |
181 static int calc_start_of_deco_zone(float *starting_depth, float *rate, float *depth_start_of_deco_zone); | |
182 static int calc_initial_allowable_gradient(void); | |
183 static void decompression_stop(float *deco_stop_depth, float *step_size, _Bool final_deco_calculation); | |
184 static int gas_loadings_ascent_descen(float* helium_pressure, float* nitrogen_pressure, float starting_depth,float ending_depth, float rate,_Bool check_gas_change); | |
185 static int calc_surface_phase_volume_time(void); | |
186 static int calc_max_actual_gradient(float *deco_stop_depth); | |
187 static int projected_ascent(float *starting_depth, float *rate, float *deco_stop_depth, float *step_size); | |
188 static void vpm_calc_deco(void); | |
189 static int vpm_calc_critcal_volume(_Bool begin,_Bool calc_nulltime); | |
190 static int vpm_check_converged(_Bool calc_nulltime); | |
191 static int vpm_calc_final_deco(_Bool begin); | |
192 static void BOYLES_LAW_COMPENSATION (float* First_Stop_Depth,float * Deco_Stop_Depth,float* Step_Size); | |
292 | 193 static int vpm_calc_ndl(void); |
290 | 194 static void vpm_init_1(void); |
195 static void vpm_calc_deco_ceiling(void); | |
38 | 196 |
907 | 197 uint8_t vpm_get_decozone(void); |
198 | |
290 | 199 static void vpm_init_1(void) |
38 | 200 { |
201 units_equal_msw = true; | |
202 units_equal_fsw = false; | |
203 altitude_dive_algorithm_off= true; //!Options: ON or OFF | |
204 minimum_deco_stop_time=1.0; //!Options: float positive number | |
205 critical_volume_algorithm_off= false; //!Options: ON or OFF | |
206 run_time = 0.; | |
207 //barometric_pressure = dive_data.surface * 10; | |
208 | |
209 //mix_number = dive_data.selected_gas + 1; | |
210 | |
211 max_first_stop_depth = 0; | |
212 max_deco_ceiling_depth = 0; | |
213 //deco_zone_reached = false; | |
214 depth_start_of_deco_calc = 0; | |
215 depth_start_of_deco_zone = 0; | |
216 first_stop_depth = 0; | |
217 run_time_start_of_deco_zone = 0; | |
218 | |
219 gCNS_VPM = 0; | |
220 } | |
221 | |
222 float vpm_get_CNS(void) | |
223 { | |
224 return gCNS_VPM; | |
225 } | |
226 | |
902 | 227 |
228 void vpm_maintainTable(SLifeData* pLifeData,SDecoinfo* pDecoInfo) | |
229 { | |
230 static uint32_t lastDiveSecond = 0; | |
231 uint8_t actual_deco_stop = 0; | |
232 int8_t index = 0; | |
233 uint8_t decreaseStopTime = 1; | |
234 | |
235 if(lastDiveSecond < pLifeData->dive_time_seconds) | |
236 { | |
237 lastDiveSecond = pLifeData->dive_time_seconds; | |
238 actual_deco_stop = decom_get_actual_deco_stop((SDiveState*)stateUsed); | |
239 | |
240 pDecoInfo->output_time_to_surface_seconds = 0; | |
241 for(index = DECOINFO_STRUCT_MAX_STOPS -1 ;index >= 0; index--) | |
242 { | |
243 if(pDecoInfo->output_stop_length_seconds[index] > 0) | |
244 { | |
245 if(decreaseStopTime) | |
246 { | |
907 | 247 if((pLifeData->depth_meter > (float)(actual_deco_stop - 1.5)) |
902 | 248 && (pLifeData->depth_meter < (float)actual_deco_stop + 1.5)) |
249 { | |
250 pDecoInfo->output_stop_length_seconds[index]--; | |
251 decreaseStopTime = 0; | |
252 } | |
907 | 253 else if (pLifeData->depth_meter < (float)(actual_deco_stop - 1.5)) /* missed deco stop */ |
254 { | |
255 vpmTableState = VPM_TABLE_MISSED; | |
256 pDecoInfo->output_stop_length_seconds[index] = 0; | |
257 decreaseStopTime = 0; | |
258 } | |
902 | 259 } |
260 pDecoInfo->output_time_to_surface_seconds += pDecoInfo->output_stop_length_seconds[index]; | |
261 } | |
262 } | |
263 pDecoInfo->output_time_to_surface_seconds += pLifeData->depth_meter / 10.0 * 60.0; | |
264 } | |
265 else if(lastDiveSecond > pLifeData->dive_time_seconds) | |
266 { | |
267 lastDiveSecond = pLifeData->dive_time_seconds; | |
268 } | |
269 } | |
270 | |
38 | 271 int vpm_calc(SLifeData* pINPUT, |
272 SDiveSettings* pSettings, | |
273 SVpm* pVPM, | |
274 SDecoinfo* | |
275 pDECOINFO, | |
276 int calc_what) | |
277 { | |
902 | 278 static uint8_t vpmTableActive = 0; |
279 | |
38 | 280 vpm_init_1(); |
281 //decom_CreateGasChangeList(pSettings, pINPUT); | |
282 vpm_calc_what = calc_what; | |
283 /**clear decoInfo*/ | |
902 | 284 |
285 if((vpmTableActive) && (vpm_calc_what == DECOSTOPS)) | |
286 { | |
287 memcpy(&vpmTable, pDECOINFO, sizeof(SDecoinfo)); /* save changes done by e.g. the simulator */ | |
288 } | |
38 | 289 pDECOINFO->output_time_to_surface_seconds = 0; |
290 pDECOINFO->output_ndl_seconds = 0; | |
291 pDECOINFO->output_ceiling_meter = 0; | |
247
3949781096d4
feature: Relative GF to Saturation renames
Jan Mulder <jlmulder@xs4all.nl>
parents:
149
diff
changeset
|
292 pDECOINFO->super_saturation = 0; |
38 | 293 uint8_t tmp_calc_status; |
294 for(int i=0;i<DECOINFO_STRUCT_MAX_STOPS;i++) | |
295 { | |
296 pDECOINFO->output_stop_length_seconds[i] = 0; | |
297 } | |
298 | |
305
305f251cc981
bugfix, consistency: show deco/NDL really after 1 minute divetime
Jan Mulder <jlmulder@xs4all.nl>
parents:
293
diff
changeset
|
299 if(pINPUT->dive_time_seconds_without_surface_time < 60) |
38 | 300 { |
292 | 301 vpm_calc_status = CALC_NDL; |
38 | 302 return vpm_calc_status; |
303 } | |
304 pVpm = pVPM; | |
305 pInput = pINPUT; | |
306 pDecoInfo = pDECOINFO; | |
307 pDiveSettings = pSettings; | |
308 | |
292 | 309 if(vpm_calc_status == CALC_NDL) |
38 | 310 { |
292 | 311 tmp_calc_status = vpm_calc_ndl(); |
38 | 312 } |
313 else | |
314 { | |
315 tmp_calc_status = CALC_BEGIN; | |
316 } | |
317 //Normal Deco calculation | |
292 | 318 if(tmp_calc_status != CALC_NDL) |
38 | 319 { |
320 max_first_stop_depth = pVpm->max_first_stop_depth_save; | |
321 run_time_start_of_deco_zone = pVpm->run_time_start_of_deco_zone_save; | |
322 depth_start_of_deco_zone = pVpm->depth_start_of_deco_zone_save; | |
323 for (int i = 0; i < 16; ++i) { | |
324 helium_pressure[i] = pInput->tissue_helium_bar[i] * 10; | |
325 nitrogen_pressure[i] = pInput->tissue_nitrogen_bar[i] * 10; | |
326 } | |
327 vpm_calc_deco(); | |
328 tmp_calc_status = vpm_calc_critcal_volume(true,false); | |
329 if(vpm_calc_what == DECOSTOPS) | |
330 { | |
331 pVpm->max_first_stop_depth_save = max_first_stop_depth; | |
332 pVpm->run_time_start_of_deco_zone_save = run_time_start_of_deco_zone; | |
333 pVpm->depth_start_of_deco_zone_save = depth_start_of_deco_zone; | |
334 } | |
335 } | |
336 | |
337 //Only Decostops not futute stops | |
338 if(vpm_calc_what == DECOSTOPS) | |
902 | 339 { |
38 | 340 vpm_calc_status = tmp_calc_status; |
902 | 341 if(pSettings->vpm_tableMode) /* store the most conservative deco plan and stick to it. */ |
342 { | |
343 if((int16_t)(pDECOINFO->output_time_to_surface_seconds - vpmTable.output_time_to_surface_seconds) > 60) | |
344 { | |
345 memcpy(&vpmTable, pDECOINFO, sizeof(SDecoinfo)); | |
346 vpmTableActive = 1; | |
907 | 347 if(pVpm->deco_zone_reached) /* table should not change after deco zone was entered */ |
348 { | |
349 if(vpmTableState != VPM_TABLE_MISSED) | |
350 { | |
351 vpmTableState = VPM_TABLE_WARNING; | |
352 } | |
353 } | |
902 | 354 } |
355 else | |
356 { | |
357 if(vpmTable.output_time_to_surface_seconds > 0) | |
358 { | |
359 vpm_maintainTable(pINPUT, &vpmTable); | |
360 vpmTable.output_ceiling_meter = pDECOINFO->output_ceiling_meter; | |
361 memcpy(pDECOINFO, &vpmTable, sizeof(SDecoinfo)); | |
362 } | |
363 } | |
364 } | |
365 } | |
38 | 366 return vpm_calc_status; |
367 } | |
368 | |
369 void vpm_saturation_after_ascent(SLifeData* input) | |
370 { | |
371 int i = 0; | |
372 for (i = 0; i < 16; ++i) { | |
373 pInput->tissue_helium_bar[i] = helium_pressure[i] / 10; | |
374 pInput->tissue_nitrogen_bar[i] = nitrogen_pressure[i] / 10; | |
375 } | |
376 pInput->pressure_ambient_bar = pInput->pressure_surface_bar; | |
377 } | |
378 /* =============================================================================== */ | |
379 /* NOTE ABOUT PRESSURE UNITS USED IN CALCULATIONS: */ | |
380 /* It is the convention in decompression calculations to compute all gas */ | |
381 /* loadings, absolute pressures, partial pressures, etc., in the units of */ | |
382 /* depth pressure that you are diving - either feet of seawater (fsw) or */ | |
383 /* meters of seawater (msw). This program follows that convention with the */ | |
384 /* the exception that all VPM calculations are performed in SI units (by */ | |
385 /* necessity). Accordingly, there are several conversions back and forth */ | |
386 /* between the diving pressure units and the SI units. */ | |
387 /* =============================================================================== */ | |
388 /* =============================================================================== */ | |
389 /* FUNCTION SUBPROGRAM FOR GAS LOADING CALCULATIONS - ASCENT AND DESCENT */ | |
390 /* =============================================================================== */ | |
391 | |
392 | |
393 | |
394 /* =============================================================================== */ | |
395 /* SUBROUTINE GAS_LOADINGS_ASCENT_DESCENT */ | |
396 /* Purpose: This subprogram applies the Schreiner equation to update the */ | |
397 /* gas loadings (partial pressures of helium and nitrogen) in the half-time */ | |
398 /* compartments due to a linear ascent or descent segment at a constant rate. */ | |
399 /* =============================================================================== */ | |
400 | |
290 | 401 static int gas_loadings_ascent_descen(float* helium_pressure, |
38 | 402 float* nitrogen_pressure, |
403 float starting_depth, | |
404 float ending_depth, | |
405 float rate,_Bool check_gas_change) | |
406 { | |
407 short i; | |
408 float initial_inspired_n2_pressure, | |
409 initial_inspired_he_pressure, nitrogen_rate, | |
410 last_run_time, | |
411 starting_ambient_pressure, | |
412 ending_ambient_pressure; | |
413 float initial_helium_pressure[16]; | |
414 float initial_nitrogen_pressure[16]; | |
415 float helium_rate; | |
416 float fraction_helium_begin; | |
417 float fraction_helium_end; | |
418 float fraction_nitrogen_begin; | |
419 float fraction_nitrogen_end; | |
420 float ending_depth_tmp = ending_depth; | |
421 float segment_time_tmp = 0; | |
422 /* loop */ | |
423 /* =============================================================================== */ | |
424 /* CALCULATIONS */ | |
425 /* =============================================================================== */ | |
426 segment_time = (ending_depth_tmp - starting_depth) / rate; | |
427 last_run_time = run_time; | |
428 run_time = last_run_time + segment_time; | |
429 do { | |
430 ending_depth_tmp = ending_depth; | |
431 if (starting_depth > ending_depth && check_gas_change && number_of_changes > 1) | |
432 { | |
433 for (i = 1; i < number_of_changes; ++i) | |
434 { | |
435 if (depth_change[i] < starting_depth && depth_change[i] > ending_depth) | |
436 { | |
437 ending_depth_tmp = depth_change[i]; | |
438 break; | |
439 } | |
440 } | |
441 for (i = 1; i < number_of_changes; ++i) | |
442 { | |
443 if (depth_change[i] >= starting_depth) | |
444 { | |
445 mix_number = mix_change[i]; | |
446 } | |
447 } | |
448 } | |
449 segment_time_tmp = (ending_depth_tmp - starting_depth) / rate; | |
450 ending_ambient_pressure = ending_depth_tmp + barometric_pressure; | |
451 starting_ambient_pressure = starting_depth + barometric_pressure; | |
452 decom_get_inert_gases( starting_ambient_pressure / 10, (&pDiveSettings->decogaslist[mix_number]), &fraction_nitrogen_begin, &fraction_helium_begin ); | |
453 decom_get_inert_gases( ending_ambient_pressure / 10, (&pDiveSettings->decogaslist[mix_number]), &fraction_nitrogen_end, &fraction_helium_end ); | |
454 | |
455 initial_inspired_he_pressure = (starting_ambient_pressure - WATER_VAPOR_PRESSURE) * fraction_helium_begin; | |
456 initial_inspired_n2_pressure = (starting_ambient_pressure - WATER_VAPOR_PRESSURE) * fraction_nitrogen_begin; | |
457 //helium_rate = *rate * fraction_helium[mix_number - 1]; | |
458 helium_rate = ((ending_ambient_pressure - WATER_VAPOR_PRESSURE)* fraction_helium_end - initial_inspired_he_pressure)/segment_time_tmp; | |
459 //nitrogen_rate2 = *rate * fraction_nitrogen[mix_number - 1]; | |
460 nitrogen_rate = ((ending_ambient_pressure - WATER_VAPOR_PRESSURE)* fraction_nitrogen_end - initial_inspired_n2_pressure)/segment_time_tmp; | |
461 | |
462 | |
463 decom_oxygen_calculate_cns_stage_SchreinerStyle(segment_time_tmp,&pDiveSettings->decogaslist[mix_number],starting_ambient_pressure/10,ending_ambient_pressure/10,&gCNS_VPM); | |
464 //if(fabs(nitrogen_rate - nitrogen_rate2) > 0.000001) | |
465 //return -2; | |
466 for (i = 1; i <= 16; ++i) | |
467 { | |
468 initial_helium_pressure[i - 1] = helium_pressure[i - 1]; | |
469 initial_nitrogen_pressure[i - 1] = nitrogen_pressure[i - 1]; | |
470 helium_pressure[i - 1] = | |
471 schreiner_equation__2(&initial_inspired_he_pressure, | |
472 &helium_rate, | |
473 &segment_time, | |
474 &HELIUM_TIME_CONSTANT[i - 1], | |
475 &initial_helium_pressure[i - 1]); | |
476 nitrogen_pressure[i - 1] = | |
477 schreiner_equation__2(&initial_inspired_n2_pressure, | |
478 &nitrogen_rate, | |
479 &segment_time, | |
480 &NITROGEN_TIME_CONSTANT[i - 1], | |
481 &initial_nitrogen_pressure[i - 1]); | |
482 | |
483 //nextround??? | |
484 | |
485 } | |
486 starting_depth = ending_depth_tmp; | |
487 } while(ending_depth_tmp > ending_depth); | |
488 | |
489 return 0; | |
490 } /* gas_loadings_ascent_descen */ | |
491 | |
290 | 492 static float last_phase_volume_time[16]; |
493 static float n2_pressure_start_of_deco_zone[16]; | |
494 static float he_pressure_start_of_deco_zone[16]; | |
495 static float phase_volume_time[16]; | |
496 static float n2_pressure_start_of_ascent[16]; | |
497 static float he_pressure_start_of_ascent[16]; | |
498 static float run_time_start_of_deco_calc; | |
499 static float starting_depth; | |
500 static float last_run_time; | |
501 static float deco_phase_volume_time; | |
502 static float run_time_start_of_ascent; | |
503 static float rate; | |
504 static float step_size; | |
505 static _Bool vpm_violates_buehlmann; | |
38 | 506 |
290 | 507 static void vpm_calc_deco(void) |
38 | 508 { |
509 /* System generated locals */ | |
510 | |
511 //float deepest_possible_stop_depth; | |
512 // altitude_of_dive, | |
513 short i; | |
514 int j = 0; | |
515 | |
516 // float rounding_operation; | |
517 | |
518 /* =============================================================================== */ | |
519 /* INPUT PARAMETERS TO BE USED FOR STAGED DECOMPRESSION AND SAVE IN ARRAYS. */ | |
520 /* ASSIGN INITAL PARAMETERS TO BE USED AT START OF ASCENT */ | |
521 /* The user has the ability to change mix, ascent rate, and step size in any */ | |
522 /* combination at any depth during the ascent. */ | |
523 /* =============================================================================== */ | |
524 | |
525 run_time = ((float)pInput->dive_time_seconds )/ 60; | |
526 count_critical_volume_iteration = 0; | |
527 number_of_changes = 1; | |
528 | |
529 barometric_pressure = pInput->pressure_surface_bar * 10; | |
530 depth_change[0] =(pInput->pressure_ambient_bar - pInput->pressure_surface_bar)* 10; | |
531 mix_change[0] = 0; | |
532 rate_change[0 ] = -10;// neu 160215 hw, zuvor: -12; | |
533 step_size_change[0] = 3; | |
534 vpm_violates_buehlmann = false; | |
535 | |
536 for (i = 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++) | |
537 { | |
538 depth_change[i] = 0; | |
539 mix_change[i] = 0; | |
540 } | |
541 j = 0; | |
542 | |
543 for (i = 1; i < BUEHLMANN_STRUCT_MAX_GASES; i++) | |
544 { | |
830
b7d93ff6b3b2
Added selection if an active gas shall be used for deco calculation or not:
Ideenmodellierer
parents:
305
diff
changeset
|
545 if((pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero >= depth_change[0] + 1) |
b7d93ff6b3b2
Added selection if an active gas shall be used for deco calculation or not:
Ideenmodellierer
parents:
305
diff
changeset
|
546 && (pDiveSettings->gas[pDiveSettings->decogaslist[i].GasIdInSettings].note.ub.decocalc)) |
38 | 547 continue; |
548 | |
830
b7d93ff6b3b2
Added selection if an active gas shall be used for deco calculation or not:
Ideenmodellierer
parents:
305
diff
changeset
|
549 if((pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero <= 0) |
b7d93ff6b3b2
Added selection if an active gas shall be used for deco calculation or not:
Ideenmodellierer
parents:
305
diff
changeset
|
550 || (pDiveSettings->gas[pDiveSettings->decogaslist[i].GasIdInSettings].note.ub.decocalc == 0)) |
38 | 551 break; |
552 | |
553 j++; | |
554 number_of_changes ++; | |
555 depth_change[j] = pDiveSettings->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero ; | |
556 mix_change[j] = i; | |
557 rate_change[j] = -10;// neu 160215 hw, zuvor: -12; | |
558 step_size_change[j] = 3; | |
559 } | |
560 | |
561 starting_depth = depth_change[0] ; | |
562 mix_number = mix_change[0] ; | |
563 rate = rate_change[0]; | |
564 step_size = step_size_change[0]; | |
565 | |
566 for (i = 0; i < 16; ++i) { | |
567 he_pressure_start_of_ascent[i ] = helium_pressure[i]; | |
568 n2_pressure_start_of_ascent[i] = nitrogen_pressure[i]; | |
569 } | |
570 run_time_start_of_ascent = run_time; | |
571 if(starting_depth <= depth_start_of_deco_zone && vpm_calc_what == DECOSTOPS) | |
572 { | |
573 pVpm->deco_zone_reached = true; | |
574 depth_start_of_deco_calc = starting_depth; | |
575 critical_volume_algorithm_off = true; | |
576 } | |
577 else | |
578 { | |
579 //if(deco_zone_reached) | |
580 //{ | |
581 pVpm->deco_zone_reached = false; | |
582 critical_volume_algorithm_off = false; | |
583 //max_first_stop_depth = 0; | |
584 //max_first_stop_depth_save = 0; | |
585 //} | |
586 /* =============================================================================== */ | |
587 /* BEGIN PROCESS OF ASCENT AND DECOMPRESSION */ | |
588 /* First, calculate the regeneration of critical radii that takes place over */ | |
589 /* the dive time. The regeneration time constant has a time scale of weeks */ | |
590 /* so this will have very little impact on dives of normal length, but will */ | |
591 /* have major impact for saturation dives. */ | |
592 /* =============================================================================== */ | |
593 | |
594 nuclear_regeneration(&run_time); | |
595 | |
596 /* =============================================================================== */ | |
597 /* CALCULATE INITIAL ALLOWABLE GRADIENTS FOR ASCENT */ | |
598 /* This is based on the maximum effective crushing pressure on critical radii */ | |
599 /* in each compartment achieved during the dive profile. */ | |
600 /* =============================================================================== */ | |
601 | |
602 calc_initial_allowable_gradient(); | |
603 | |
604 /* =============================================================================== */ | |
605 /* SAVE VARIABLES AT START OF ASCENT (END OF BOTTOM TIME) SINCE THESE WILL */ | |
606 /* BE USED LATER TO COMPUTE THE FINAL ASCENT PROFILE THAT IS WRITTEN TO THE */ | |
607 /* OUTPUT FILE. */ | |
608 /* The VPM uses an iterative process to compute decompression schedules so */ | |
609 /* there will be more than one pass through the decompression loop. */ | |
610 /* =============================================================================== */ | |
611 | |
612 /* =============================================================================== */ | |
613 /* CALCULATE THE DEPTH WHERE THE DECOMPRESSION ZONE BEGINS FOR THIS PROFILE */ | |
614 /* BASED ON THE INITIAL ASCENT PARAMETERS AND WRITE THE DEEPEST POSSIBLE */ | |
615 /* DECOMPRESSION STOP DEPTH TO THE OUTPUT FILE */ | |
616 /* Knowing where the decompression zone starts is very important. Below */ | |
617 /* that depth there is no possibility for bubble formation because there */ | |
618 /* will be no supersaturation gradients. Deco stops should never start */ | |
619 /* below the deco zone. The deepest possible stop deco stop depth is */ | |
620 /* defined as the next "standard" stop depth above the point where the */ | |
621 /* leading compartment enters the deco zone. Thus, the program will not */ | |
622 /* base this calculation on step sizes larger than 10 fsw or 3 msw. The */ | |
623 /* deepest possible stop depth is not used in the program, per se, rather */ | |
624 /* it is information to tell the diver where to start putting on the brakes */ | |
625 /* during ascent. This should be prominently displayed by any deco program. */ | |
626 /* =============================================================================== */ | |
627 | |
628 calc_start_of_deco_zone(&starting_depth, &rate, &depth_start_of_deco_zone); | |
629 /* =============================================================================== */ | |
630 /* TEMPORARILY ASCEND PROFILE TO THE START OF THE DECOMPRESSION ZONE, SAVE */ | |
631 /* VARIABLES AT THIS POINT, AND INITIALIZE VARIABLES FOR CRITICAL VOLUME LOOP */ | |
632 /* The iterative process of the VPM Critical Volume Algorithm will operate */ | |
633 /* only in the decompression zone since it deals with excess gas volume */ | |
634 /* released as a result of supersaturation gradients (not possible below the */ | |
635 /* decompression zone). */ | |
636 /* =============================================================================== */ | |
637 gas_loadings_ascent_descen(helium_pressure,nitrogen_pressure, starting_depth, depth_start_of_deco_zone, rate, true); | |
638 | |
639 run_time_start_of_deco_zone = run_time; | |
640 depth_start_of_deco_calc = depth_start_of_deco_zone; | |
641 | |
642 for (i = 0; i < 16; ++i) | |
643 { | |
644 pVpm->max_actual_gradient[i] = 0.; | |
645 } | |
646 } | |
647 | |
648 for (i = 0; i < 16; ++i) | |
649 { | |
650 surface_phase_volume_time[i] = 0.; | |
651 last_phase_volume_time[i] = 0.; | |
652 he_pressure_start_of_deco_zone[i] = helium_pressure[i]; | |
653 n2_pressure_start_of_deco_zone[i] = nitrogen_pressure[i]; | |
654 //pVpm->max_actual_gradient[i] = 0.; | |
655 } | |
656 run_time_start_of_deco_calc = run_time; | |
657 } | |
658 /* =============================================================================== */ | |
659 /* START OF CRITICAL VOLUME LOOP */ | |
660 /* This loop operates between Lines 50 and 100. If the Critical Volume */ | |
661 /* Algorithm is toggled "off" in the program settings, there will only be */ | |
662 /* one pass through this loop. Otherwise, there will be two or more passes */ | |
663 /* through this loop until the deco schedule is "converged" - that is when a */ | |
664 /* comparison between the phase volume time of the present iteration and the */ | |
665 /* last iteration is less than or equal to one minute. This implies that */ | |
666 /* the volume of released gas in the most recent iteration differs from the */ | |
667 /* "critical" volume limit by an acceptably small amount. The critical */ | |
668 /* volume limit is set by the Critical Volume Parameter Lambda in the program */ | |
669 /* settings (default setting is 7500 fsw-min with adjustability range from */ | |
670 /* from 6500 to 8300 fsw-min according to Bruce Wienke). */ | |
671 /* =============================================================================== */ | |
672 /* L50: */ | |
673 | |
290 | 674 static float deco_stop_depth; |
675 static int vpm_calc_critcal_volume(_Bool begin, | |
38 | 676 _Bool calc_nulltime) |
677 { /* loop will run continuous there is an exit stateme */ | |
678 | |
679 short i; | |
680 | |
681 float rounding_operation2; | |
682 //float ending_depth; | |
683 float deco_ceiling_depth; | |
684 | |
685 //float deco_time; | |
686 int count = 0; | |
687 _Bool first_stop; | |
688 int dp = 0; | |
689 float tissue_He_saturation[16]; | |
690 float tissue_N2_saturation[16]; | |
691 float vpm_buehlmann_safety_gradient = 1.0f - (((float)pDiveSettings->vpm_conservatism) / 40); | |
692 /* =============================================================================== */ | |
693 /* CALCULATE CURRENT DECO CEILING BASED ON ALLOWABLE SUPERSATURATION */ | |
694 /* GRADIENTS AND SET FIRST DECO STOP. CHECK TO MAKE SURE THAT SELECTED STEP */ | |
695 /* SIZE WILL NOT ROUND UP FIRST STOP TO A DEPTH THAT IS BELOW THE DECO ZONE. */ | |
696 /* =============================================================================== */ | |
697 if(begin) | |
698 { | |
699 if(depth_start_of_deco_calc < max_first_stop_depth ) | |
700 { | |
701 if(vpm_b) | |
702 { | |
703 BOYLES_LAW_COMPENSATION(&max_first_stop_depth, &depth_start_of_deco_calc, &step_size); | |
704 } | |
705 calc_deco_ceiling(&deco_ceiling_depth, false); | |
706 } | |
707 else | |
708 calc_deco_ceiling(&deco_ceiling_depth, true); | |
709 | |
710 | |
711 if (deco_ceiling_depth <= 0.0f) { | |
712 deco_stop_depth = 0.0f; | |
713 } else { | |
714 rounding_operation2 = deco_ceiling_depth / step_size + ( float)0.5f; | |
715 deco_stop_depth = r_nint(&rounding_operation2) * step_size; | |
716 } | |
717 | |
718 // buehlmann safety | |
719 if(buehlmannSafety) | |
720 { | |
721 for (i = 0; i < 16; i++) | |
722 { | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
723 tissue_He_saturation[i] = helium_pressure[i] / 10.0; |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
724 tissue_N2_saturation[i] = nitrogen_pressure[i] / 10.0; |
38 | 725 } |
726 | |
727 if(!decom_tissue_test_tolerance(tissue_N2_saturation, tissue_He_saturation, vpm_buehlmann_safety_gradient, (deco_stop_depth / 10.0f) + pInput->pressure_surface_bar)) | |
728 { | |
729 | |
730 vpm_violates_buehlmann = true; | |
731 do { | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
732 deco_stop_depth += 3.0; |
38 | 733 } while (!decom_tissue_test_tolerance(tissue_N2_saturation, tissue_He_saturation, vpm_buehlmann_safety_gradient, (deco_stop_depth / 10.0f) + pInput->pressure_surface_bar)); |
734 } | |
735 } | |
736 | |
737 /* =============================================================================== */ | |
738 /* PERFORM A SEPARATE "PROJECTED ASCENT" OUTSIDE OF THE MAIN PROGRAM TO MAKE */ | |
739 /* SURE THAT AN INCREASE IN GAS LOADINGS DURING ASCENT TO THE FIRST STOP WILL */ | |
740 /* NOT CAUSE A VIOLATION OF THE DECO CEILING. IF SO, ADJUST THE FIRST STOP */ | |
741 /* DEEPER BASED ON STEP SIZE UNTIL A SAFE ASCENT CAN BE MADE. */ | |
742 /* Note: this situation is a possibility when ascending from extremely deep */ | |
743 /* dives or due to an unusual gas mix selection. */ | |
744 /* CHECK AGAIN TO MAKE SURE THAT ADJUSTED FIRST STOP WILL NOT BE BELOW THE */ | |
745 /* DECO ZONE. */ | |
746 /* =============================================================================== */ | |
747 if (deco_stop_depth < depth_start_of_deco_calc) | |
748 { | |
749 projected_ascent(&depth_start_of_deco_calc, &rate, &deco_stop_depth, &step_size); | |
750 } | |
751 | |
752 /*if (deco_stop_depth > depth_start_of_deco_zone) { | |
753 printf("\t\n"); | |
754 printf(fmt_905); | |
755 printf(fmt_900); | |
756 printf("\nPROGRAM TERMINATED\n"); | |
757 exit(1); | |
758 }*/ | |
759 | |
760 /* =============================================================================== */ | |
761 /* HANDLE THE SPECIAL CASE WHEN NO DECO STOPS ARE REQUIRED - ASCENT CAN BE */ | |
762 /* MADE DIRECTLY TO THE SURFACE */ | |
763 /* Write ascent data to output file and exit the Critical Volume Loop. */ | |
764 /* =============================================================================== */ | |
765 | |
766 if (deco_stop_depth == 0.0f) | |
767 { | |
768 if(calc_nulltime) | |
769 { | |
770 return CALC_END; | |
771 } | |
772 if(pVpm->deco_zone_reached) | |
773 { | |
774 for(dp = 0;dp < DECOINFO_STRUCT_MAX_STOPS;dp++) | |
775 { | |
776 pDecoInfo->output_stop_length_seconds[dp] = 0; | |
777 } | |
778 pDecoInfo->output_ndl_seconds = 0; | |
779 } | |
780 | |
292 | 781 return CALC_NDL; |
38 | 782 /* exit the critical volume l */ |
783 } | |
784 | |
785 /* =============================================================================== */ | |
786 /* ASSIGN VARIABLES FOR ASCENT FROM START OF DECO ZONE TO FIRST STOP. SAVE */ | |
787 /* FIRST STOP DEPTH FOR LATER USE WHEN COMPUTING THE FINAL ASCENT PROFILE */ | |
788 /* =============================================================================== */ | |
877 | 789 deco_stop_depth = fmaxf(deco_stop_depth,(float)pDiveSettings->last_stop_depth_bar * 10); |
38 | 790 starting_depth = depth_start_of_deco_calc; |
791 first_stop_depth = deco_stop_depth; | |
792 first_stop = true; | |
793 } | |
794 /* =============================================================================== */ | |
795 /* DECO STOP LOOP BLOCK WITHIN CRITICAL VOLUME LOOP */ | |
796 /* This loop computes a decompression schedule to the surface during each */ | |
797 /* iteration of the critical volume loop. No output is written from this */ | |
798 /* loop, rather it computes a schedule from which the in-water portion of the */ | |
799 /* total phase volume time (Deco_Phase_Volume_Time) can be extracted. Also, */ | |
800 /* the gas loadings computed at the end of this loop are used the subroutine */ | |
801 /* which computes the out-of-water portion of the total phase volume time */ | |
802 /* (Surface_Phase_Volume_Time) for that schedule. */ | |
803 | |
804 /* Note that exit is made from the loop after last ascent is made to a deco */ | |
805 /* stop depth that is less than or equal to zero. A final deco stop less */ | |
806 /* than zero can happen when the user makes an odd step size change during */ | |
807 /* ascent - such as specifying a 5 msw step size change at the 3 msw stop! */ | |
808 /* =============================================================================== */ | |
809 | |
810 while(true) /* loop will run continuous there is an break statement */ | |
811 { | |
812 if(starting_depth > deco_stop_depth ) | |
813 gas_loadings_ascent_descen(helium_pressure, nitrogen_pressure, starting_depth, deco_stop_depth, rate,first_stop); | |
814 | |
815 first_stop = false; | |
816 if (deco_stop_depth <= 0.0f) | |
817 { | |
818 break; | |
819 } | |
820 if (number_of_changes > 1) | |
821 { | |
822 int i1 = number_of_changes; | |
823 for (i = 2; i <= i1; ++i) { | |
824 if (depth_change[i - 1] >= deco_stop_depth) | |
825 { | |
826 mix_number = mix_change[i - 1]; | |
827 rate = rate_change[i - 1]; | |
828 step_size = step_size_change[i - 1]; | |
829 } | |
830 } | |
831 } | |
832 if(vpm_b) | |
833 { | |
834 float fist_stop_depth2 = fmaxf(first_stop_depth,max_first_stop_depth); | |
835 BOYLES_LAW_COMPENSATION(&fist_stop_depth2, &deco_stop_depth, &step_size); | |
836 } | |
837 decompression_stop(&deco_stop_depth, &step_size, false); | |
838 starting_depth = deco_stop_depth; | |
839 | |
877 | 840 if(deco_stop_depth == (float)pDiveSettings->last_stop_depth_bar * 10) |
38 | 841 deco_stop_depth = 0; |
842 else | |
843 { | |
844 deco_stop_depth = deco_stop_depth - step_size; | |
877 | 845 deco_stop_depth = fmaxf(deco_stop_depth,(float)pDiveSettings->last_stop_depth_bar * 10); |
38 | 846 } |
847 | |
848 count++; | |
849 //if(count > 14) | |
850 //return CALC_CRITICAL2; | |
851 /* L60: */ | |
852 } | |
853 | |
854 return vpm_check_converged(calc_nulltime); | |
855 } | |
856 /* =============================================================================== */ | |
857 /* COMPUTE TOTAL PHASE VOLUME TIME AND MAKE CRITICAL VOLUME COMPARISON */ | |
858 /* The deco phase volume time is computed from the run time. The surface */ | |
859 /* phase volume time is computed in a subroutine based on the surfacing gas */ | |
860 /* loadings from previous deco loop block. Next the total phase volume time */ | |
861 /* (in-water + surface) for each compartment is compared against the previous */ | |
862 /* total phase volume time. The schedule is converged when the difference is */ | |
863 /* less than or equal to 1 minute in any one of the 16 compartments. */ | |
864 | |
865 /* Note: the "phase volume time" is somewhat of a mathematical concept. */ | |
866 /* It is the time divided out of a total integration of supersaturation */ | |
867 /* gradient x time (in-water and surface). This integration is multiplied */ | |
868 /* by the excess bubble number to represent the amount of free-gas released */ | |
869 /* as a result of allowing a certain number of excess bubbles to form. */ | |
870 /* =============================================================================== */ | |
871 /* end of deco stop loop */ | |
872 | |
290 | 873 static int vpm_check_converged(_Bool calc_nulltime) |
38 | 874 { |
875 | |
876 short i; | |
877 float critical_volume_comparison; | |
878 float r1; | |
879 _Bool schedule_converged = false; | |
880 | |
881 | |
882 deco_phase_volume_time = run_time - run_time_start_of_deco_zone; | |
883 calc_surface_phase_volume_time(); | |
884 | |
885 for (i = 1; i <= 16; ++i) | |
886 { | |
887 phase_volume_time[i - 1] = | |
888 deco_phase_volume_time + surface_phase_volume_time[i - 1]; | |
889 critical_volume_comparison = (r1 = phase_volume_time[i - 1] - last_phase_volume_time[i - 1], fabs(r1)); | |
890 | |
891 if (critical_volume_comparison <= 1.0f) | |
892 { | |
893 schedule_converged = true; | |
894 } | |
895 } | |
896 | |
897 /* =============================================================================== */ | |
898 /* CRITICAL VOLUME DECISION TREE BETWEEN LINES 70 AND 99 */ | |
899 /* There are two options here. If the Critical Volume Agorithm setting is */ | |
900 /* "on" and the schedule is converged, or the Critical Volume Algorithm */ | |
901 /* setting was "off" in the first place, the program will re-assign variables */ | |
902 /* to their values at the start of ascent (end of bottom time) and process */ | |
903 /* a complete decompression schedule once again using all the same ascent */ | |
904 /* parameters and first stop depth. This decompression schedule will match */ | |
905 /* the last iteration of the Critical Volume Loop and the program will write */ | |
906 /* the final deco schedule to the output file. */ | |
907 | |
908 /* Note: if the Critical Volume Agorithm setting was "off", the final deco */ | |
909 /* schedule will be based on "Initial Allowable Supersaturation Gradients." */ | |
910 /* If it was "on", the final schedule will be based on "Adjusted Allowable */ | |
911 /* Supersaturation Gradients" (gradients that are "relaxed" as a result of */ | |
912 /* the Critical Volume Algorithm). */ | |
913 | |
914 /* If the Critical Volume Agorithm setting is "on" and the schedule is not */ | |
915 /* converged, the program will re-assign variables to their values at the */ | |
916 /* start of the deco zone and process another trial decompression schedule. */ | |
917 /* =============================================================================== */ | |
918 /* L70: */ | |
919 //Not more than 4 iteration allowed | |
920 count_critical_volume_iteration++; | |
921 if(count_critical_volume_iteration > 4) | |
922 { | |
923 //return CALC_FINAL_DECO; | |
924 if(calc_nulltime) | |
925 return CALC_FINAL_DECO; | |
926 else | |
927 return vpm_calc_final_deco(true); | |
928 } | |
929 if (schedule_converged || critical_volume_algorithm_off) | |
930 { | |
931 | |
932 //return CALC_FINAL_DECO; | |
933 if(calc_nulltime) | |
934 return CALC_FINAL_DECO; | |
935 else | |
936 return vpm_calc_final_deco(true); | |
937 /* final deco schedule */ | |
938 /* exit critical volume l */ | |
939 | |
940 /* =============================================================================== */ | |
941 /* IF SCHEDULE NOT CONVERGED, COMPUTE RELAXED ALLOWABLE SUPERSATURATION */ | |
942 /* GRADIENTS WITH VPM CRITICAL VOLUME ALGORITHM AND PROCESS ANOTHER */ | |
943 /* ITERATION OF THE CRITICAL VOLUME LOOP */ | |
944 /* =============================================================================== */ | |
945 | |
946 } else { | |
947 critical_volume(&deco_phase_volume_time); | |
948 deco_phase_volume_time = 0.; | |
949 run_time = run_time_start_of_deco_calc; | |
950 starting_depth = depth_start_of_deco_calc; | |
951 mix_number = mix_change[0]; | |
952 rate = rate_change[0]; | |
953 step_size = step_size_change[0]; | |
954 for (i = 1; i <= 16; ++i) | |
955 { | |
956 last_phase_volume_time[i - 1] = phase_volume_time[i - 1]; | |
957 helium_pressure[i - 1] = he_pressure_start_of_deco_zone[i - 1]; | |
958 nitrogen_pressure[i - 1] = n2_pressure_start_of_deco_zone[i - 1]; | |
959 } | |
960 if(calc_nulltime) | |
961 return CALC_CRITICAL; | |
962 else | |
963 return vpm_calc_critcal_volume(true, false); | |
964 } | |
965 /* end of critical volume decision */ | |
966 /* L100: */ | |
967 // }/* end of critical vol loop */ | |
968 } | |
969 | |
290 | 970 static void vpm_calc_deco_ceiling(void) |
38 | 971 { |
972 | |
973 short i; | |
974 // hw 1601209 float r1; | |
975 // hw 1601209 float stop_time; | |
976 // hw 1601209 int count = 0; | |
977 //static int dp_max; | |
978 //static float surfacetime; | |
979 // _Bool first_stop = false; | |
980 float tissue_He_saturation[16]; | |
981 float tissue_N2_saturation[16]; | |
877 | 982 float vpm_buehlmann_safety_gradient = 1.0f - (((float)pDiveSettings->vpm_conservatism) / 40); |
38 | 983 //max_first_stop_depth = fmaxf(first_stop_depth,max_first_stop_depth); |
984 | |
985 /** CALC DECO Ceiling ******************************************************************/ | |
986 /** Not when Future stops */ | |
987 if(vpm_calc_what == DECOSTOPS) | |
988 { | |
989 | |
990 for (i = 1; i <= 16; ++i) | |
991 { | |
992 helium_pressure[i - 1] = he_pressure_start_of_deco_zone[i - 1]; | |
993 nitrogen_pressure[i - 1] = n2_pressure_start_of_deco_zone[i - 1]; | |
994 } | |
995 run_time = run_time_start_of_ascent;// run_time_start_of_ascent; | |
996 starting_depth = depth_change[0]; | |
997 mix_number = mix_change[0]; | |
998 rate = rate_change[0]; | |
999 //gas_loadings_ascent_descen(helium_pressure,nitrogen_pressure, starting_depth, depth_start_of_deco_calc, rate, true); | |
1000 | |
1001 float deco_ceiling_depth = 0.0f; | |
1002 if(depth_start_of_deco_calc > max_deco_ceiling_depth) | |
1003 { | |
1004 calc_deco_ceiling(&deco_ceiling_depth, true); | |
1005 } | |
1006 if(buehlmannSafety) | |
1007 { | |
1008 for (i = 0; i < 16; i++) | |
1009 { | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1010 tissue_He_saturation[i] = helium_pressure[i] / 10.0; |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1011 tissue_N2_saturation[i] = nitrogen_pressure[i] / 10.0; |
38 | 1012 } |
1013 | |
1014 if(!decom_tissue_test_tolerance(tissue_N2_saturation, tissue_He_saturation, vpm_buehlmann_safety_gradient, (deco_ceiling_depth / 10.0f) + pInput->pressure_surface_bar)) | |
1015 { | |
1016 vpm_violates_buehlmann = true; | |
1017 do { | |
1018 deco_ceiling_depth += 0.1f; | |
1019 } while (!decom_tissue_test_tolerance(tissue_N2_saturation, tissue_He_saturation, vpm_buehlmann_safety_gradient, (deco_ceiling_depth / 10.0f) + pInput->pressure_surface_bar)); | |
1020 } | |
1021 } | |
1022 | |
1023 if (deco_ceiling_depth < depth_start_of_deco_calc) | |
1024 { | |
1025 projected_ascent(&depth_start_of_deco_calc, &rate, &deco_ceiling_depth, &step_size); | |
1026 } | |
1027 | |
1028 max_deco_ceiling_depth = fmaxf(max_deco_ceiling_depth,deco_ceiling_depth); | |
1029 | |
1030 if(depth_start_of_deco_calc > deco_ceiling_depth) | |
1031 { | |
1032 gas_loadings_ascent_descen(helium_pressure,nitrogen_pressure, depth_start_of_deco_calc,deco_ceiling_depth, rate, true); | |
1033 //surfacetime += segment_time; | |
1034 } | |
1035 | |
1036 if(vpm_b) | |
1037 { | |
1038 BOYLES_LAW_COMPENSATION(&max_deco_ceiling_depth, &deco_ceiling_depth, &step_size); | |
1039 } | |
1040 calc_deco_ceiling(&deco_ceiling_depth, false); | |
1041 | |
1042 // buehlmann safety | |
1043 if(vpm_violates_buehlmann) | |
1044 { | |
1045 for (i = 0; i < 16; i++) | |
1046 { | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1047 tissue_He_saturation[i] = helium_pressure[i] / 10.0; |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1048 tissue_N2_saturation[i] = nitrogen_pressure[i] / 10.0; |
38 | 1049 } |
1050 | |
1051 if(!decom_tissue_test_tolerance(tissue_N2_saturation, tissue_He_saturation, vpm_buehlmann_safety_gradient, (deco_ceiling_depth / 10.0f) + pInput->pressure_surface_bar)) | |
1052 { | |
1053 vpm_violates_buehlmann = true; | |
1054 do { | |
1055 deco_ceiling_depth += 0.1f; | |
1056 } while (!decom_tissue_test_tolerance(tissue_N2_saturation, tissue_He_saturation, vpm_buehlmann_safety_gradient, (deco_ceiling_depth / 10.0f) + pInput->pressure_surface_bar)); | |
1057 } | |
1058 } | |
1059 // output_ceiling_meter | |
1060 if(deco_ceiling_depth > first_stop_depth) | |
1061 deco_ceiling_depth = first_stop_depth; | |
1062 pDecoInfo->output_ceiling_meter = deco_ceiling_depth ; | |
1063 } | |
1064 else | |
1065 { | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1066 pDecoInfo->output_ceiling_meter = 0.0; |
38 | 1067 } |
1068 | |
1069 // fix hw 160627 | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1070 if(pDecoInfo->output_ceiling_meter < 0.0) |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1071 pDecoInfo->output_ceiling_meter = 0.0; |
38 | 1072 |
1073 /*** End CALC ceiling ***************************************************/ | |
1074 } | |
1075 | |
1076 | |
1077 /* =============================================================================== */ | |
1078 /* DECO STOP LOOP BLOCK FOR FINAL DECOMPRESSION SCHEDULE */ | |
1079 /* =============================================================================== */ | |
1080 | |
290 | 1081 static int vpm_calc_final_deco(_Bool begin) |
38 | 1082 { |
1083 short i; | |
1084 float r1; | |
1085 float stop_time; | |
1086 int count = 0; | |
1087 static int dp_max; | |
1088 static float surfacetime; | |
1089 _Bool first_stop = false; | |
902 | 1090 float roundingValue = 0.0; |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1091 |
902 | 1092 uint16_t stop_time_seconds; |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1093 |
38 | 1094 max_first_stop_depth = fmaxf(first_stop_depth,max_first_stop_depth); |
1095 if(begin) | |
1096 { | |
1097 gCNS_VPM = 0; | |
1098 dp_max = 0; | |
1099 for (i = 1; i <= 16; ++i) | |
1100 { | |
1101 helium_pressure[i - 1] = | |
1102 he_pressure_start_of_ascent[i - 1]; | |
1103 nitrogen_pressure[i - 1] = | |
1104 n2_pressure_start_of_ascent[i - 1]; | |
1105 } | |
1106 run_time = run_time_start_of_ascent;// run_time_start_of_ascent; | |
1107 starting_depth = depth_change[0]; | |
1108 mix_number = mix_change[0]; | |
1109 rate = rate_change[0]; | |
1110 step_size = step_size_change[0]; | |
1111 deco_stop_depth = first_stop_depth; | |
1112 max_first_stop_depth = fmaxf(first_stop_depth,max_first_stop_depth); | |
1113 last_run_time = 0.; | |
1114 | |
1115 | |
1116 | |
1117 /* =============================================================================== */ | |
1118 /* DECO STOP LOOP BLOCK FOR FINAL DECOMPRESSION SCHEDULE */ | |
1119 /* =============================================================================== */ | |
1120 surfacetime = 0; | |
1121 first_stop = true; | |
1122 } | |
1123 | |
1124 while(true) /* loop will run continuous until there is an break statement */ | |
1125 { | |
1126 if(starting_depth > deco_stop_depth) | |
1127 { | |
1128 gas_loadings_ascent_descen(helium_pressure,nitrogen_pressure, starting_depth,deco_stop_depth, rate, first_stop); | |
1129 surfacetime += segment_time; | |
1130 } | |
1131 | |
1132 /* =============================================================================== */ | |
1133 /* DURING FINAL DECOMPRESSION SCHEDULE PROCESS, COMPUTE MAXIMUM ACTUAL */ | |
1134 /* SUPERSATURATION GRADIENT RESULTING IN EACH COMPARTMENT */ | |
1135 /* If there is a repetitive dive, this will be used later in the VPM */ | |
1136 /* Repetitive Algorithm to adjust the values for critical radii. */ | |
1137 /* =============================================================================== */ | |
1138 if(vpm_calc_what == DECOSTOPS) | |
1139 calc_max_actual_gradient(&deco_stop_depth); | |
1140 | |
1141 if (deco_stop_depth <= 0.0f) { | |
1142 break; | |
1143 } | |
1144 if (number_of_changes > 1) | |
1145 { | |
1146 int i1 = number_of_changes; | |
1147 for (i = 2; i <= i1; ++i) | |
1148 { | |
1149 if (depth_change[i - 1] >= deco_stop_depth) | |
1150 { | |
1151 mix_number = mix_change[i - 1]; | |
1152 rate = rate_change[i - 1]; | |
1153 step_size = step_size_change[i - 1]; | |
1154 } | |
1155 } | |
1156 } | |
1157 | |
1158 if(first_stop) | |
1159 { | |
1160 run_time_first_stop = run_time; | |
1161 first_stop = false; | |
1162 } | |
1163 if(vpm_b) | |
1164 { | |
1165 BOYLES_LAW_COMPENSATION(&max_first_stop_depth, &deco_stop_depth, &step_size); | |
1166 } | |
1167 decompression_stop(&deco_stop_depth, &step_size, true); | |
1168 | |
1169 /* =============================================================================== */ | |
1170 /* This next bit justs rounds up the stop time at the first stop to be in */ | |
1171 /* whole increments of the minimum stop time (to make for a nice deco table). */ | |
1172 /* =============================================================================== */ | |
1173 | |
1174 if (last_run_time == 0.0f) | |
1175 { | |
1176 r1 = segment_time / minimum_deco_stop_time + 0.5f; | |
1177 stop_time = r_int(&r1) * minimum_deco_stop_time; | |
1178 } else { | |
1179 stop_time = run_time - last_run_time; | |
1180 } | |
1181 stop_time = segment_time; | |
1182 surfacetime += stop_time; | |
1183 if((vpm_calc_what == DECOSTOPS) || (vpm_calc_what == BAILOUTSTOPS)) | |
1184 { | |
1185 int dp = 0; | |
1186 if(deco_stop_depth == (float)pDiveSettings->last_stop_depth_bar * 10) | |
1187 { | |
1188 dp = 0; | |
1189 } | |
1190 else | |
1191 { | |
902 | 1192 roundingValue = (deco_stop_depth - (pDiveSettings->input_second_to_last_stop_depth_bar * 10.0)) / step_size; |
1193 dp = 1 + r_nint(&roundingValue); | |
38 | 1194 } |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1195 |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1196 //dp_max = (int)fmaxf(dp_max,dp); |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1197 if(dp > dp_max) |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1198 { |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1199 dp_max = dp; |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1200 } |
38 | 1201 if(dp < DECOINFO_STRUCT_MAX_STOPS) |
1202 { | |
902 | 1203 stop_time_seconds = (uint16_t)(fminf((999.9 * 60.0), (stop_time *60.0))); |
38 | 1204 // |
1205 | |
1206 //if(vpm_calc_what == DECOSTOPS) | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1207 pDecoInfo->output_stop_length_seconds[dp] = stop_time_seconds; |
38 | 1208 //else |
1209 //decostop_bailout[dp] = (unsigned short)stop_time_seconds; | |
1210 } | |
1211 } | |
1212 | |
1213 | |
1214 /* =============================================================================== */ | |
1215 /* DURING FINAL DECOMPRESSION SCHEDULE, IF MINIMUM STOP TIME PARAMETER IS A */ | |
1216 /* WHOLE NUMBER (i.e. 1 minute) THEN WRITE DECO SCHEDULE USING short */ | |
1217 /* NUMBERS (looks nicer). OTHERWISE, USE DECIMAL NUMBERS. */ | |
1218 /* Note: per the request of a noted exploration diver(!), program now allows */ | |
1219 /* a minimum stop time of less than one minute so that total ascent time can */ | |
1220 /* be minimized on very long dives. In fact, with step size set at 1 fsw or */ | |
1221 /* 0.2 msw and minimum stop time set at 0.1 minute (6 seconds), a near */ | |
1222 /* continuous decompression schedule can be computed. */ | |
1223 /* =============================================================================== */ | |
1224 | |
1225 starting_depth = deco_stop_depth; | |
877 | 1226 if(deco_stop_depth == (float)pDiveSettings->last_stop_depth_bar * 10) |
1227 deco_stop_depth = 0; | |
38 | 1228 else |
1229 { | |
1230 deco_stop_depth = deco_stop_depth - step_size; | |
877 | 1231 deco_stop_depth = fmaxf(deco_stop_depth,(float)pDiveSettings->last_stop_depth_bar * 10); |
38 | 1232 } |
1233 | |
1234 last_run_time = run_time; | |
1235 count++; | |
1236 //if(count > 14) | |
1237 //return CALC_FINAL_DECO2; | |
1238 /* L80: */ | |
1239 } /* for final deco sche */ | |
1240 | |
1241 if( (vpm_calc_what == DECOSTOPS) || (vpm_calc_what == BAILOUTSTOPS)) | |
1242 { | |
1243 for(int dp = dp_max +1;dp < DECOINFO_STRUCT_MAX_STOPS;dp++) | |
1244 { | |
1245 //if(vpm_calc_what == DECOSTOPS) | |
1246 pDecoInfo->output_stop_length_seconds[dp] = 0; | |
1247 //else | |
1248 //decostop_bailout[dp] = 0; | |
1249 } | |
1250 } | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1251 pDecoInfo->output_time_to_surface_seconds = (int)(surfacetime * 60.0); |
38 | 1252 pDecoInfo->output_ndl_seconds = 0; |
1253 | |
1254 vpm_calc_deco_ceiling(); | |
1255 /* end of deco stop lo */ | |
1256 return CALC_END; | |
1257 } | |
1258 | |
1259 /* =============================================================================== */ | |
1260 /* SUBROUTINE NUCLEAR_REGENERATION */ | |
1261 /* Purpose: This subprogram calculates the regeneration of VPM critical */ | |
1262 /* radii that takes place over the dive time. The regeneration time constant */ | |
1263 /* has a time scale of weeks so this will have very little impact on dives of */ | |
1264 /* normal length, but will have a major impact for saturation dives. */ | |
1265 /* =============================================================================== */ | |
1266 | |
290 | 1267 static int nuclear_regeneration(float *dive_time) |
38 | 1268 { |
1269 /* Local variables */ | |
1270 float crush_pressure_adjust_ratio_he, | |
1271 ending_radius_n2, | |
1272 ending_radius_he; | |
1273 short i; | |
1274 float crushing_pressure_pascals_n2, | |
1275 crushing_pressure_pascals_he, | |
1276 adj_crush_pressure_n2_pascals, | |
1277 adj_crush_pressure_he_pascals, | |
1278 crush_pressure_adjust_ratio_n2; | |
1279 | |
1280 /* loop */ | |
1281 /* =============================================================================== */ | |
1282 /* CALCULATIONS */ | |
1283 /* First convert the maximum crushing pressure obtained for each compartment */ | |
1284 /* to Pascals. Next, compute the ending radius for helium and nitrogen */ | |
1285 /* critical nuclei in each compartment. */ | |
1286 /* =============================================================================== */ | |
1287 | |
1288 for (i = 1; i <= 16; ++i) | |
1289 { | |
1290 crushing_pressure_pascals_he = | |
1291 pVpm->max_crushing_pressure_he[i - 1] / UNITS_FACTOR * 101325.0f; | |
1292 crushing_pressure_pascals_n2 = | |
1293 pVpm->max_crushing_pressure_n2[i - 1] / UNITS_FACTOR * 101325.0f; | |
1294 ending_radius_he = | |
1295 1.0f / (crushing_pressure_pascals_he / | |
1296 ((SKIN_COMPRESSION_GAMMAC - SURFACE_TENSION_GAMMA) * 2.0f) + | |
1297 1.0f / pVpm->adjusted_critical_radius_he[i - 1]); | |
1298 ending_radius_n2 = | |
1299 1.0f / (crushing_pressure_pascals_n2 / | |
1300 ((SKIN_COMPRESSION_GAMMAC - SURFACE_TENSION_GAMMA) * 2.0f) + | |
1301 1.0f / pVpm->adjusted_critical_radius_n2[i - 1]); | |
1302 | |
1303 /* =============================================================================== */ | |
1304 /* A "regenerated" radius for each nucleus is now calculated based on the */ | |
1305 /* regeneration time constant. This means that after application of */ | |
1306 /* crushing pressure and reduction in radius, a nucleus will slowly grow */ | |
1307 /* back to its original initial radius over a period of time. This */ | |
1308 /* phenomenon is probabilistic in nature and depends on absolute temperature. */ | |
1309 /* It is independent of crushing pressure. */ | |
1310 /* =============================================================================== */ | |
1311 | |
1312 regenerated_radius_he[i - 1] = | |
1313 pVpm->adjusted_critical_radius_he[i - 1] + | |
1314 (ending_radius_he - pVpm->adjusted_critical_radius_he[i - 1]) * | |
1315 expf(-(*dive_time) / REGENERATION_TIME_CONSTANT); | |
1316 regenerated_radius_n2[i - 1] = | |
1317 pVpm->adjusted_critical_radius_n2[i - 1] + | |
1318 (ending_radius_n2 - pVpm->adjusted_critical_radius_n2[i - 1]) * | |
1319 expf(-(*dive_time) / REGENERATION_TIME_CONSTANT); | |
1320 | |
1321 /* =============================================================================== */ | |
1322 /* In order to preserve reference back to the initial critical radii after */ | |
1323 /* regeneration, an "adjusted crushing pressure" for the nuclei in each */ | |
1324 /* compartment must be computed. In other words, this is the value of */ | |
1325 /* crushing pressure that would have reduced the original nucleus to the */ | |
1326 /* to the present radius had regeneration not taken place. The ratio */ | |
1327 /* for adjusting crushing pressure is obtained from algebraic manipulation */ | |
1328 /* of the standard VPM equations. The adjusted crushing pressure, in lieu */ | |
1329 /* of the original crushing pressure, is then applied in the VPM Critical */ | |
1330 /* Volume Algorithm and the VPM Repetitive Algorithm. */ | |
1331 /* =============================================================================== */ | |
1332 | |
1333 crush_pressure_adjust_ratio_he = | |
1334 ending_radius_he * (pVpm->adjusted_critical_radius_he[i - 1] - | |
1335 regenerated_radius_he[i - 1]) / | |
1336 (regenerated_radius_he[i - 1] * | |
1337 (pVpm->adjusted_critical_radius_he[i - 1] - | |
1338 ending_radius_he)); | |
1339 crush_pressure_adjust_ratio_n2 = | |
1340 ending_radius_n2 * (pVpm->adjusted_critical_radius_n2[i - 1] - | |
1341 regenerated_radius_n2[i - 1]) / | |
1342 (regenerated_radius_n2[i - 1] * | |
1343 (pVpm->adjusted_critical_radius_n2[i - 1] - | |
1344 ending_radius_n2)); | |
1345 adj_crush_pressure_he_pascals = | |
1346 crushing_pressure_pascals_he * crush_pressure_adjust_ratio_he; | |
1347 adj_crush_pressure_n2_pascals = | |
1348 crushing_pressure_pascals_n2 * crush_pressure_adjust_ratio_n2; | |
1349 pVpm->adjusted_crushing_pressure_he[i - 1] = | |
1350 adj_crush_pressure_he_pascals / 101325.0f * UNITS_FACTOR; | |
1351 pVpm->adjusted_crushing_pressure_n2[i - 1] = | |
1352 adj_crush_pressure_n2_pascals / 101325.0f * UNITS_FACTOR; | |
1353 } | |
1354 return 0; | |
1355 } /* nuclear_regeneration */ | |
1356 | |
1357 /* =============================================================================== */ | |
1358 /* SUBROUTINE CALC_INITIAL_ALLOWABLE_GRADIENT */ | |
1359 /* Purpose: This subprogram calculates the initial allowable gradients for */ | |
1360 /* helium and nitrogren in each compartment. These are the gradients that */ | |
1361 /* will be used to set the deco ceiling on the first pass through the deco */ | |
1362 /* loop. If the Critical Volume Algorithm is set to "off", then these */ | |
1363 /* gradients will determine the final deco schedule. Otherwise, if the */ | |
1364 /* Critical Volume Algorithm is set to "on", these gradients will be further */ | |
1365 /* "relaxed" by the Critical Volume Algorithm subroutine. The initial */ | |
1366 /* allowable gradients are referred to as "PssMin" in the papers by Yount */ | |
1367 /* and colleauges, i.e., the minimum supersaturation pressure gradients */ | |
1368 /* that will probe bubble formation in the VPM nuclei that started with the */ | |
1369 /* designated minimum initial radius (critical radius). */ | |
1370 | |
1371 /* The initial allowable gradients are computed directly from the */ | |
1372 /* "regenerated" radii after the Nuclear Regeneration subroutine. These */ | |
1373 /* gradients are tracked separately for helium and nitrogen. */ | |
1374 /* =============================================================================== */ | |
1375 | |
290 | 1376 static int calc_initial_allowable_gradient() |
38 | 1377 { |
1378 float initial_allowable_grad_n2_pa, | |
1379 initial_allowable_grad_he_pa; | |
1380 short i; | |
1381 | |
1382 /* loop */ | |
1383 /* =============================================================================== */ | |
1384 /* CALCULATIONS */ | |
1385 /* The initial allowable gradients are computed in Pascals and then converted */ | |
1386 /* to the diving pressure units. Two different sets of arrays are used to */ | |
1387 /* save the calculations - Initial Allowable Gradients and Allowable */ | |
1388 /* Gradients. The Allowable Gradients are assigned the values from Initial */ | |
1389 /* Allowable Gradients however the Allowable Gradients can be changed later */ | |
1390 /* by the Critical Volume subroutine. The values for the Initial Allowable */ | |
1391 /* Gradients are saved in a global array for later use by both the Critical */ | |
1392 /* Volume subroutine and the VPM Repetitive Algorithm subroutine. */ | |
1393 /* =============================================================================== */ | |
1394 | |
1395 for (i = 1; i <= 16; ++i) | |
1396 { | |
1397 initial_allowable_grad_n2_pa = | |
1398 SURFACE_TENSION_GAMMA * 2.0f * | |
1399 (SKIN_COMPRESSION_GAMMAC - SURFACE_TENSION_GAMMA) / | |
1400 (regenerated_radius_n2[i - 1] * SKIN_COMPRESSION_GAMMAC); | |
1401 | |
1402 initial_allowable_grad_he_pa = | |
1403 SURFACE_TENSION_GAMMA * 2.0f * | |
1404 (SKIN_COMPRESSION_GAMMAC - SURFACE_TENSION_GAMMA) / | |
1405 (regenerated_radius_he[i - 1] * SKIN_COMPRESSION_GAMMAC); | |
1406 | |
1407 pVpm->initial_allowable_gradient_n2[i - 1] = | |
1408 initial_allowable_grad_n2_pa / 101325.0f * UNITS_FACTOR; | |
1409 | |
1410 pVpm->initial_allowable_gradient_he[i - 1] = | |
1411 initial_allowable_grad_he_pa / 101325.0f * UNITS_FACTOR; | |
1412 | |
1413 allowable_gradient_he[i - 1] = | |
1414 pVpm->initial_allowable_gradient_he[i - 1]; | |
1415 | |
1416 allowable_gradient_n2[i - 1] = | |
1417 pVpm->initial_allowable_gradient_n2[i - 1]; | |
1418 } | |
1419 return 0; | |
1420 } /* calc_initial_allowable_gradient */ | |
1421 | |
1422 /* =============================================================================== */ | |
1423 /* SUBROUTINE CALC_DECO_CEILING */ | |
1424 /* Purpose: This subprogram calculates the deco ceiling (the safe ascent */ | |
1425 /* depth) in each compartment, based on the allowable gradients, and then */ | |
1426 /* finds the deepest deco ceiling across all compartments. This deepest */ | |
1427 /* value (Deco Ceiling Depth) is then used by the Decompression Stop */ | |
1428 /* subroutine to determine the actual deco schedule. */ | |
1429 /* =============================================================================== */ | |
1430 | |
290 | 1431 static int calc_deco_ceiling(float *deco_ceiling_depth,_Bool fallowable) |
38 | 1432 { |
1433 /* System generated locals */ | |
1434 float r1, r2; | |
1435 /* Local variables */ | |
1436 float weighted_allowable_gradient; | |
1437 short i; | |
1438 float compartment_deco_ceiling[16], | |
1439 gas_loading, | |
1440 tolerated_ambient_pressure; | |
1441 float gradient_he, gradient_n2; | |
1442 | |
1443 if(!vpm_b) | |
1444 fallowable = true; | |
1445 /* loop */ | |
1446 /* =============================================================================== */ | |
1447 /* CALCULATIONS */ | |
1448 /* Since there are two sets of allowable gradients being tracked, one for */ | |
1449 /* helium and one for nitrogen, a "weighted allowable gradient" must be */ | |
1450 /* computed each time based on the proportions of helium and nitrogen in */ | |
1451 /* each compartment. This proportioning follows the methodology of */ | |
1452 /* Buhlmann/Keller. If there is no helium and nitrogen in the compartment, */ | |
1453 /* such as after extended periods of oxygen breathing, then the minimum value */ | |
1454 /* across both gases will be used. It is important to note that if a */ | |
1455 /* compartment is empty of helium and nitrogen, then the weighted allowable */ | |
1456 /* gradient formula cannot be used since it will result in division by zero. */ | |
1457 /* =============================================================================== */ | |
1458 | |
1459 for (i = 1; i <= 16; ++i) | |
1460 { | |
1461 | |
1462 // abfrage raus und pointer stattdessen | |
1463 if(fallowable){ | |
1464 gradient_he = allowable_gradient_he[i-1]; | |
1465 gradient_n2 = allowable_gradient_n2[i-1]; | |
1466 } | |
1467 else{ | |
1468 gradient_he = deco_gradient_he[i-1]; | |
1469 gradient_n2 = deco_gradient_n2[i-1]; | |
1470 } | |
1471 | |
1472 gas_loading = helium_pressure[i - 1] + nitrogen_pressure[i - 1]; | |
1473 | |
1474 if (gas_loading > 0) | |
1475 { | |
1476 weighted_allowable_gradient = | |
1477 (gradient_he * helium_pressure[i - 1] + | |
1478 gradient_n2 * nitrogen_pressure[i - 1]) / | |
1479 (helium_pressure[i - 1] + nitrogen_pressure[i - 1]); | |
1480 | |
1481 tolerated_ambient_pressure = | |
1482 gas_loading + | |
1483 CONSTANT_PRESSURE_OTHER_GASES - | |
1484 weighted_allowable_gradient; | |
1485 } | |
1486 else | |
1487 { | |
1488 /* Computing MIN */ | |
1489 r1 = gradient_he; | |
1490 r2 = gradient_n2; | |
1491 weighted_allowable_gradient = fminf(r1,r2); | |
1492 | |
1493 tolerated_ambient_pressure = | |
1494 CONSTANT_PRESSURE_OTHER_GASES - weighted_allowable_gradient; | |
1495 } | |
1496 | |
1497 /* =============================================================================== */ | |
1498 /* The tolerated ambient pressure cannot be less than zero absolute, i.e., */ | |
1499 /* the vacuum of outer space! */ | |
1500 /* =============================================================================== */ | |
1501 | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1502 if (tolerated_ambient_pressure < 0.0) { |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1503 tolerated_ambient_pressure = 0.0; |
38 | 1504 } |
1505 compartment_deco_ceiling[i - 1] = | |
1506 tolerated_ambient_pressure - barometric_pressure; | |
1507 } | |
1508 | |
1509 /* =============================================================================== */ | |
1510 /* The Deco Ceiling Depth is computed in a loop after all of the individual */ | |
1511 /* compartment deco ceilings have been calculated. It is important that the */ | |
1512 /* Deco Ceiling Depth (max deco ceiling across all compartments) only be */ | |
1513 /* extracted from the compartment values and not be compared against some */ | |
1514 /* initialization value. For example, if MAX(Deco_Ceiling_Depth . .) was */ | |
1515 /* compared against zero, this could cause a program lockup because sometimes */ | |
1516 /* the Deco Ceiling Depth needs to be negative (but not less than zero */ | |
1517 /* absolute ambient pressure) in order to decompress to the last stop at zero */ | |
1518 /* depth. */ | |
1519 /* =============================================================================== */ | |
1520 | |
1521 *deco_ceiling_depth = compartment_deco_ceiling[0]; | |
1522 for (i = 2; i <= 16; ++i) | |
1523 { | |
1524 /* Computing MAX */ | |
1525 r1 = *deco_ceiling_depth; | |
1526 r2 = compartment_deco_ceiling[i - 1]; | |
1527 *deco_ceiling_depth = fmaxf(r1,r2); | |
1528 } | |
1529 return 0; | |
1530 } /* calc_deco_ceiling */ | |
1531 | |
1532 | |
1533 | |
1534 /* =============================================================================== */ | |
1535 /* SUBROUTINE CALC_MAX_ACTUAL_GRADIENT */ | |
1536 /* Purpose: This subprogram calculates the actual supersaturation gradient */ | |
1537 /* obtained in each compartment as a result of the ascent profile during */ | |
1538 /* decompression. Similar to the concept with crushing pressure, the */ | |
1539 /* supersaturation gradients are not cumulative over a multi-level, staged */ | |
1540 /* ascent. Rather, it will be the maximum value obtained in any one discrete */ | |
1541 /* step of the overall ascent. Thus, the program must compute and store the */ | |
1542 /* maximum actual gradient for each compartment that was obtained across all */ | |
1543 /* steps of the ascent profile. This subroutine is invoked on the last pass */ | |
1544 /* through the deco stop loop block when the final deco schedule is being */ | |
1545 /* generated. */ | |
1546 /* */ | |
1547 /* The max actual gradients are later used by the VPM Repetitive Algorithm to */ | |
1548 /* determine if adjustments to the critical radii are required. If the max */ | |
1549 /* actual gradient did not exceed the initial alllowable gradient, then no */ | |
1550 /* adjustment will be made. However, if the max actual gradient did exceed */ | |
1551 /* the intitial allowable gradient, such as permitted by the Critical Volume */ | |
1552 /* Algorithm, then the critical radius will be adjusted (made larger) on the */ | |
1553 /* repetitive dive to compensate for the bubbling that was allowed on the */ | |
1554 /* previous dive. The use of the max actual gradients is intended to prevent */ | |
1555 /* the repetitive algorithm from being overly conservative. */ | |
1556 /* =============================================================================== */ | |
1557 | |
290 | 1558 static int calc_max_actual_gradient(float *deco_stop_depth) |
38 | 1559 { |
1560 /* System generated locals */ | |
1561 float r1; | |
1562 | |
1563 /* Local variables */ | |
1564 short i; | |
1565 float compartment_gradient; | |
1566 | |
1567 /* loop */ | |
1568 /* =============================================================================== */ | |
1569 /* CALCULATIONS */ | |
1570 /* Note: negative supersaturation gradients are meaningless for this */ | |
1571 /* application, so the values must be equal to or greater than zero. */ | |
1572 /* =============================================================================== */ | |
1573 | |
1574 for (i = 1; i <= 16; ++i) | |
1575 { | |
1576 compartment_gradient = | |
1577 helium_pressure[i - 1] + | |
1578 nitrogen_pressure[i - 1] + | |
1579 CONSTANT_PRESSURE_OTHER_GASES - | |
1580 (*deco_stop_depth + barometric_pressure); | |
1581 if (compartment_gradient <= 0.0f) { | |
1582 compartment_gradient = 0.0f; | |
1583 } | |
1584 /* Computing MAX */ | |
1585 r1 = pVpm->max_actual_gradient[i - 1]; | |
1586 pVpm->max_actual_gradient[i - 1] = fmaxf(r1, compartment_gradient); | |
1587 } | |
1588 return 0; | |
1589 } /* calc_max_actual_gradient */ | |
1590 | |
1591 /* =============================================================================== */ | |
1592 /* SUBROUTINE CALC_SURFACE_PHASE_VOLUME_TIME */ | |
1593 /* Purpose: This subprogram computes the surface portion of the total phase */ | |
1594 /* volume time. This is the time factored out of the integration of */ | |
1595 /* supersaturation gradient x time over the surface interval. The VPM */ | |
1596 /* considers the gradients that allow bubbles to form or to drive bubble */ | |
1597 /* growth both in the water and on the surface after the dive. */ | |
1598 | |
1599 /* This subroutine is a new development to the VPM algorithm in that it */ | |
1600 /* computes the time course of supersaturation gradients on the surface */ | |
1601 /* when both helium and nitrogen are present. Refer to separate write-up */ | |
1602 /* for a more detailed explanation of this algorithm. */ | |
1603 /* =============================================================================== */ | |
1604 | |
290 | 1605 static int calc_surface_phase_volume_time() |
38 | 1606 { |
1607 /* Local variables */ | |
1608 float decay_time_to_zero_gradient; | |
1609 short i; | |
1610 float integral_gradient_x_time, | |
1611 surface_inspired_n2_pressure; | |
1612 | |
1613 /* loop */ | |
1614 /* =============================================================================== */ | |
1615 /* CALCULATIONS */ | |
1616 /* =============================================================================== */ | |
1617 | |
1618 surface_inspired_n2_pressure = | |
1619 (barometric_pressure - WATER_VAPOR_PRESSURE) * 0.79f; | |
1620 for (i = 1; i <= 16; ++i) | |
1621 { | |
1622 if (nitrogen_pressure[i - 1] > surface_inspired_n2_pressure) | |
1623 { | |
1624 surface_phase_volume_time[i - 1] = | |
1625 (helium_pressure[i - 1] / HELIUM_TIME_CONSTANT[i - 1] + | |
1626 (nitrogen_pressure[i - 1] - surface_inspired_n2_pressure) / | |
1627 NITROGEN_TIME_CONSTANT[i - 1]) / | |
1628 (helium_pressure[i - 1] + nitrogen_pressure[i - 1] - | |
1629 surface_inspired_n2_pressure); | |
1630 } else if (nitrogen_pressure[i - 1] <= surface_inspired_n2_pressure && | |
1631 helium_pressure[i - 1] + nitrogen_pressure[i - 1] >= surface_inspired_n2_pressure) | |
1632 { | |
1633 decay_time_to_zero_gradient = | |
1634 1.0f / (NITROGEN_TIME_CONSTANT[i - 1] - HELIUM_TIME_CONSTANT[i - 1]) * | |
1635 log((surface_inspired_n2_pressure - nitrogen_pressure[i - 1]) / | |
1636 helium_pressure[i - 1]); | |
1637 integral_gradient_x_time = | |
1638 helium_pressure[i - 1] / | |
1639 HELIUM_TIME_CONSTANT[i - 1] * | |
1640 (1.0f - expf(-HELIUM_TIME_CONSTANT[i - 1] * | |
1641 decay_time_to_zero_gradient)) + | |
1642 (nitrogen_pressure[i - 1] - surface_inspired_n2_pressure) / | |
1643 NITROGEN_TIME_CONSTANT[i - 1] * | |
1644 (1.0f - expf(-NITROGEN_TIME_CONSTANT[i - 1] * | |
1645 decay_time_to_zero_gradient)); | |
1646 surface_phase_volume_time[i - 1] = | |
1647 integral_gradient_x_time / | |
1648 (helium_pressure[i - 1] + | |
1649 nitrogen_pressure[i - 1] - | |
1650 surface_inspired_n2_pressure); | |
1651 } else { | |
1652 surface_phase_volume_time[i - 1] = 0.0f; | |
1653 } | |
1654 } | |
1655 return 0; | |
1656 } /* calc_surface_phase_volume_time */ | |
1657 | |
1658 /* =============================================================================== */ | |
1659 /* SUBROUTINE CRITICAL_VOLUME */ | |
1660 /* Purpose: This subprogram applies the VPM Critical Volume Algorithm. This */ | |
1661 /* algorithm will compute "relaxed" gradients for helium and nitrogen based */ | |
1662 /* on the setting of the Critical Volume Parameter Lambda. */ | |
1663 /* =============================================================================== */ | |
1664 | |
290 | 1665 static int critical_volume(float *deco_phase_volume_time) |
38 | 1666 { |
1667 /* System generated locals */ | |
1668 float r1; | |
1669 | |
1670 /* Local variables */ | |
1671 float initial_allowable_grad_n2_pa, | |
1672 initial_allowable_grad_he_pa, | |
1673 parameter_lambda_pascals, b, | |
1674 c; | |
1675 short i; | |
1676 float new_allowable_grad_n2_pascals, | |
1677 phase_volume_time[16], | |
1678 new_allowable_grad_he_pascals, | |
1679 adj_crush_pressure_n2_pascals, | |
1680 adj_crush_pressure_he_pascals; | |
1681 | |
1682 /* loop */ | |
1683 /* =============================================================================== */ | |
1684 /* CALCULATIONS */ | |
1685 /* Note: Since the Critical Volume Parameter Lambda was defined in units of */ | |
1686 /* fsw-min in the original papers by Yount and colleauges, the same */ | |
1687 /* convention is retained here. Although Lambda is adjustable only in units */ | |
1688 /* of fsw-min in the program settings (range from 6500 to 8300 with default */ | |
1689 /* 7500), it will convert to the proper value in Pascals-min in this */ | |
1690 /* subroutine regardless of which diving pressure units are being used in */ | |
1691 /* the main program - feet of seawater (fsw) or meters of seawater (msw). */ | |
1692 /* The allowable gradient is computed using the quadratic formula (refer to */ | |
1693 /* separate write-up posted on the Deco List web site). */ | |
1694 /* =============================================================================== */ | |
1695 | |
1696 /** | |
1697 ****************************************************************************** | |
1698 * @brief critical_volume comment by hw | |
1699 * @version V0.0.1 | |
1700 * @date 19-April-2014 | |
1701 * @retval global: allowable_gradient_he[i], allowable_gradient_n2[i] | |
1702 ****************************************************************************** | |
1703 */ | |
1704 | |
1705 parameter_lambda_pascals = | |
1706 CRIT_VOLUME_PARAMETER_LAMBDA / 33.0f * 101325.0f; | |
1707 for (i = 1; i <= 16; ++i) | |
1708 { | |
1709 phase_volume_time[i - 1] = | |
1710 *deco_phase_volume_time + surface_phase_volume_time[i - 1]; | |
1711 } | |
1712 for (i = 1; i <= 16; ++i) | |
1713 { | |
1714 | |
1715 adj_crush_pressure_he_pascals = | |
1716 pVpm->adjusted_crushing_pressure_he[i - 1] / UNITS_FACTOR * 101325.0f; | |
1717 | |
1718 initial_allowable_grad_he_pa = | |
1719 pVpm->initial_allowable_gradient_he[i - 1] / UNITS_FACTOR * 101325.0f; | |
1720 | |
1721 b = initial_allowable_grad_he_pa + parameter_lambda_pascals * | |
1722 SURFACE_TENSION_GAMMA / ( | |
1723 SKIN_COMPRESSION_GAMMAC * phase_volume_time[i - 1]); | |
1724 | |
1725 c = SURFACE_TENSION_GAMMA * ( | |
1726 SURFACE_TENSION_GAMMA * ( | |
1727 parameter_lambda_pascals * adj_crush_pressure_he_pascals)) / | |
1728 (SKIN_COMPRESSION_GAMMAC * | |
1729 (SKIN_COMPRESSION_GAMMAC * phase_volume_time[i - 1])); | |
1730 /* Computing 2nd power */ | |
1731 | |
1732 r1 = b; | |
1733 | |
1734 new_allowable_grad_he_pascals = | |
1735 (b + sqrtf(r1 * r1 - c * 4.0f)) / 2.0f; | |
1736 | |
1737 /* modify global variable */ | |
1738 allowable_gradient_he[i - 1] = | |
1739 new_allowable_grad_he_pascals / 101325.0f * UNITS_FACTOR; | |
1740 } | |
1741 | |
1742 for (i = 1; i <= 16; ++i) | |
1743 { | |
1744 adj_crush_pressure_n2_pascals = | |
1745 pVpm->adjusted_crushing_pressure_n2[i - 1] / UNITS_FACTOR * 101325.0f; | |
1746 | |
1747 initial_allowable_grad_n2_pa = | |
1748 pVpm->initial_allowable_gradient_n2[i - 1] / UNITS_FACTOR * 101325.0f; | |
1749 | |
1750 b = initial_allowable_grad_n2_pa + parameter_lambda_pascals * | |
1751 SURFACE_TENSION_GAMMA / ( | |
1752 SKIN_COMPRESSION_GAMMAC * phase_volume_time[i - 1]); | |
1753 | |
1754 c = SURFACE_TENSION_GAMMA * | |
1755 (SURFACE_TENSION_GAMMA * | |
1756 (parameter_lambda_pascals * adj_crush_pressure_n2_pascals)) / | |
1757 (SKIN_COMPRESSION_GAMMAC * | |
1758 (SKIN_COMPRESSION_GAMMAC * phase_volume_time[i - 1])); | |
1759 /* Computing 2nd power */ | |
1760 | |
1761 r1 = b; | |
1762 | |
1763 new_allowable_grad_n2_pascals = | |
1764 (b + sqrtf(r1 * r1 - c * 4.0f)) / 2.0f; | |
1765 | |
1766 /* modify global variable */ | |
1767 allowable_gradient_n2[i - 1] = | |
1768 new_allowable_grad_n2_pascals / 101325.0f * UNITS_FACTOR; | |
1769 } | |
1770 return 0; | |
1771 } /* critical_volume */ | |
1772 | |
1773 /* =============================================================================== */ | |
1774 /* SUBROUTINE CALC_START_OF_DECO_ZONE */ | |
1775 /* Purpose: This subroutine uses the Bisection Method to find the depth at */ | |
1776 /* which the leading compartment just enters the decompression zone. */ | |
1777 /* Source: "Numerical Recipes in Fortran 77", Cambridge University Press, */ | |
1778 /* 1992. */ | |
1779 /* =============================================================================== */ | |
1780 | |
290 | 1781 static int calc_start_of_deco_zone(float *starting_depth, |
38 | 1782 float *rate, |
1783 float *depth_start_of_deco_zone) | |
1784 { | |
1785 /* Local variables */ | |
1786 float last_diff_change, | |
1787 initial_helium_pressure, | |
1788 mid_range_nitrogen_pressure; | |
1789 short i, j; | |
1790 float initial_inspired_n2_pressure, | |
1791 cpt_depth_start_of_deco_zone, | |
1792 low_bound, | |
1793 initial_inspired_he_pressure, | |
1794 high_bound_nitrogen_pressure, | |
1795 nitrogen_rate, | |
1796 function_at_mid_range, | |
1797 function_at_low_bound, | |
1798 high_bound, | |
1799 mid_range_helium_pressure, | |
1800 mid_range_time, | |
1801 starting_ambient_pressure, | |
1802 initial_nitrogen_pressure, | |
1803 function_at_high_bound; | |
1804 | |
1805 float time_to_start_of_deco_zone, | |
1806 high_bound_helium_pressure, | |
1807 helium_rate, | |
1808 differential_change; | |
1809 float fraction_helium_begin; | |
1810 float fraction_helium_end; | |
1811 float fraction_nitrogen_begin; | |
1812 float fraction_nitrogen_end; | |
1813 float ending_ambient_pressure; | |
1814 float time_test; | |
1815 | |
1816 | |
1817 /* loop */ | |
1818 /* =============================================================================== */ | |
1819 /* CALCULATIONS */ | |
1820 /* First initialize some variables */ | |
1821 /* =============================================================================== */ | |
1822 | |
1823 *depth_start_of_deco_zone = 0.0f; | |
1824 starting_ambient_pressure = *starting_depth + barometric_pressure; | |
1825 | |
1826 //>>>>>>>>>>>>>>>>>>>> | |
1827 //Test depth to calculate helium_rate and nitrogen_rate | |
1828 ending_ambient_pressure = starting_ambient_pressure/2; | |
1829 | |
1830 time_test = (ending_ambient_pressure - starting_ambient_pressure) / *rate; | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1831 decom_get_inert_gases(starting_ambient_pressure / 10.0, (&pDiveSettings->decogaslist[mix_number]), &fraction_nitrogen_begin, &fraction_helium_begin ); |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1832 decom_get_inert_gases(ending_ambient_pressure / 10.0, (&pDiveSettings->decogaslist[mix_number]), &fraction_nitrogen_end, &fraction_helium_end ); |
38 | 1833 initial_inspired_he_pressure = (starting_ambient_pressure - WATER_VAPOR_PRESSURE) * fraction_helium_begin; |
1834 initial_inspired_n2_pressure = (starting_ambient_pressure - WATER_VAPOR_PRESSURE) * fraction_nitrogen_begin; | |
1835 helium_rate = ((ending_ambient_pressure - WATER_VAPOR_PRESSURE)* fraction_helium_end - initial_inspired_he_pressure)/time_test; | |
1836 nitrogen_rate = ((ending_ambient_pressure - WATER_VAPOR_PRESSURE)* fraction_nitrogen_end - initial_inspired_n2_pressure)/time_test; | |
1837 //>>>>>>>>>>>>>>>>>>>>> | |
1838 /*initial_inspired_he_pressure = | |
1839 (starting_ambient_pressure - water_vapor_pressure) * | |
1840 fraction_helium[mix_number - 1]; | |
1841 initial_inspired_n2_pressure = | |
1842 (starting_ambient_pressure - water_vapor_pressure) * | |
1843 fraction_nitrogen[mix_number - 1]; | |
1844 helium_rate = *rate * fraction_helium[mix_number - 1]; | |
1845 nitrogen_rate = *rate * fraction_nitrogen[mix_number - 1];*/ | |
1846 | |
1847 /* =============================================================================== */ | |
1848 /* ESTABLISH THE BOUNDS FOR THE ROOT SEARCH USING THE BISECTION METHOD */ | |
1849 /* AND CHECK TO MAKE SURE THAT THE ROOT WILL BE WITHIN BOUNDS. PROCESS */ | |
1850 /* EACH COMPARTMENT INDIVIDUALLY AND FIND THE MAXIMUM DEPTH ACROSS ALL */ | |
1851 /* COMPARTMENTS (LEADING COMPARTMENT) */ | |
1852 /* In this case, we are solving for time - the time when the gas tension in */ | |
1853 /* the compartment will be equal to ambient pressure. The low bound for time */ | |
1854 /* is set at zero and the high bound is set at the time it would take to */ | |
1855 /* ascend to zero ambient pressure (absolute). Since the ascent rate is */ | |
1856 /* negative, a multiplier of -1.0 is used to make the time positive. The */ | |
1857 /* desired point when gas tension equals ambient pressure is found at a time */ | |
1858 /* somewhere between these endpoints. The algorithm checks to make sure that */ | |
1859 /* the solution lies in between these bounds by first computing the low bound */ | |
1860 /* and high bound function values. */ | |
1861 /* =============================================================================== */ | |
1862 | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
1863 low_bound = 0.0; |
38 | 1864 high_bound = starting_ambient_pressure / *rate * -1.0f; |
1865 for (i = 1; i <= 16; ++i) | |
1866 { | |
1867 initial_helium_pressure = helium_pressure[i - 1]; | |
1868 initial_nitrogen_pressure = nitrogen_pressure[i - 1]; | |
1869 function_at_low_bound = | |
1870 initial_helium_pressure + | |
1871 initial_nitrogen_pressure + | |
1872 CONSTANT_PRESSURE_OTHER_GASES - | |
1873 starting_ambient_pressure; | |
1874 high_bound_helium_pressure = | |
1875 schreiner_equation__2(&initial_inspired_he_pressure, | |
1876 &helium_rate, | |
1877 &high_bound, | |
1878 &HELIUM_TIME_CONSTANT[i - 1], | |
1879 &initial_helium_pressure); | |
1880 high_bound_nitrogen_pressure = | |
1881 schreiner_equation__2(&initial_inspired_n2_pressure, | |
1882 &nitrogen_rate, | |
1883 &high_bound, | |
1884 &NITROGEN_TIME_CONSTANT[i - 1], | |
1885 &initial_nitrogen_pressure); | |
1886 function_at_high_bound = high_bound_helium_pressure + | |
1887 high_bound_nitrogen_pressure + | |
1888 CONSTANT_PRESSURE_OTHER_GASES; | |
1889 if (function_at_high_bound * function_at_low_bound >= 0.0f) | |
1890 { | |
1891 printf("\nERROR! ROOT IS NOT WITHIN BRACKETS"); | |
1892 } | |
1893 | |
1894 /* =============================================================================== */ | |
1895 /* APPLY THE BISECTION METHOD IN SEVERAL ITERATIONS UNTIL A SOLUTION WITH */ | |
1896 /* THE DESIRED ACCURACY IS FOUND */ | |
1897 /* Note: the program allows for up to 100 iterations. Normally an exit will */ | |
1898 /* be made from the loop well before that number. If, for some reason, the */ | |
1899 /* program exceeds 100 iterations, there will be a pause to alert the user. */ | |
1900 /* =============================================================================== */ | |
1901 | |
1902 if (function_at_low_bound < 0.0f) | |
1903 { | |
1904 time_to_start_of_deco_zone = low_bound; | |
1905 differential_change = high_bound - low_bound; | |
1906 } else { | |
1907 time_to_start_of_deco_zone = high_bound; | |
1908 differential_change = low_bound - high_bound; | |
1909 } | |
1910 for (j = 1; j <= 100; ++j) | |
1911 { | |
1912 last_diff_change = differential_change; | |
1913 differential_change = last_diff_change * 0.5f; | |
1914 mid_range_time = | |
1915 time_to_start_of_deco_zone + | |
1916 differential_change; | |
1917 mid_range_helium_pressure = | |
1918 schreiner_equation__2(&initial_inspired_he_pressure, | |
1919 &helium_rate, | |
1920 &mid_range_time, | |
1921 &HELIUM_TIME_CONSTANT[i - 1], | |
1922 &initial_helium_pressure); | |
1923 mid_range_nitrogen_pressure = | |
1924 schreiner_equation__2(&initial_inspired_n2_pressure, | |
1925 &nitrogen_rate, | |
1926 &mid_range_time, | |
1927 &NITROGEN_TIME_CONSTANT[i - 1], | |
1928 &initial_nitrogen_pressure); | |
1929 function_at_mid_range = | |
1930 mid_range_helium_pressure + | |
1931 mid_range_nitrogen_pressure + | |
1932 CONSTANT_PRESSURE_OTHER_GASES - | |
1933 (starting_ambient_pressure + *rate * mid_range_time); | |
1934 if (function_at_mid_range <= 0.0f) { | |
1935 time_to_start_of_deco_zone = mid_range_time; | |
1936 } | |
1937 if( fabs(differential_change) < 0.001f | |
1938 || function_at_mid_range == 0.0f) | |
1939 { | |
1940 goto L170; | |
1941 } | |
1942 /* L150: */ | |
1943 } | |
1944 printf("\nERROR! ROOT SEARCH EXCEEDED MAXIMUM ITERATIONS"); | |
1945 //pause(); | |
1946 | |
1947 /* =============================================================================== */ | |
1948 /* When a solution with the desired accuracy is found, the program jumps out */ | |
1949 /* of the loop to Line 170 and assigns the solution value for the individual */ | |
1950 /* compartment. */ | |
1951 /* =============================================================================== */ | |
1952 | |
1953 L170: | |
1954 cpt_depth_start_of_deco_zone = | |
1955 starting_ambient_pressure + | |
1956 *rate * time_to_start_of_deco_zone - | |
1957 barometric_pressure; | |
1958 | |
1959 /* =============================================================================== */ | |
1960 /* The overall solution will be the compartment with the maximum depth where */ | |
1961 /* gas tension equals ambient pressure (leading compartment). */ | |
1962 /* =============================================================================== */ | |
1963 | |
1964 *depth_start_of_deco_zone = | |
1965 fmaxf(*depth_start_of_deco_zone, cpt_depth_start_of_deco_zone); | |
1966 /* L200: */ | |
1967 } | |
1968 return 0; | |
1969 } /* calc_start_of_deco_zone */ | |
1970 | |
1971 /* =============================================================================== */ | |
1972 /* SUBROUTINE PROJECTED_ASCENT */ | |
1973 /* Purpose: This subprogram performs a simulated ascent outside of the main */ | |
1974 /* program to ensure that a deco ceiling will not be violated due to unusual */ | |
1975 /* gas loading during ascent (on-gassing). If the deco ceiling is violated, */ | |
1976 /* the stop depth will be adjusted deeper by the step size until a safe */ | |
1977 /* ascent can be made. */ | |
1978 /* =============================================================================== */ | |
1979 | |
290 | 1980 static int projected_ascent(float *starting_depth, |
38 | 1981 float *rate, |
1982 float *deco_stop_depth, | |
1983 float *step_size) | |
1984 { | |
1985 /* Local variables */ | |
1986 float weighted_allowable_gradient, | |
1987 ending_ambient_pressure, | |
1988 temp_gas_loading[16]; | |
1989 int i; | |
1990 float allowable_gas_loading[16]; | |
1991 float temp_nitrogen_pressure[16]; | |
1992 float temp_helium_pressure[16]; | |
1993 float run_time_save = 0; | |
1994 | |
1995 /* loop */ | |
1996 /* =============================================================================== */ | |
1997 /* CALCULATIONS */ | |
1998 /* =============================================================================== */ | |
1999 | |
2000 | |
2001 L665: | |
2002 ending_ambient_pressure = *deco_stop_depth + barometric_pressure; | |
2003 for (i = 1; i <= 16; ++i) { | |
2004 temp_helium_pressure[i - 1] = helium_pressure[i - 1]; | |
2005 temp_nitrogen_pressure[i - 1] = nitrogen_pressure[i - 1]; | |
2006 } | |
2007 run_time_save = run_time; | |
2008 gas_loadings_ascent_descen(temp_helium_pressure, temp_nitrogen_pressure, *starting_depth,*deco_stop_depth,*rate,true); | |
2009 run_time = run_time_save; | |
2010 | |
2011 for (i = 1; i <= 16; ++i) | |
2012 { | |
2013 temp_gas_loading[i - 1] = | |
2014 temp_helium_pressure[i - 1] + | |
2015 temp_nitrogen_pressure[i - 1]; | |
2016 if (temp_gas_loading[i - 1] > 0.0f) | |
2017 { | |
2018 weighted_allowable_gradient = | |
2019 (allowable_gradient_he[i - 1] * | |
2020 temp_helium_pressure[i - 1] + | |
2021 allowable_gradient_n2[i - 1] * | |
2022 temp_nitrogen_pressure[i - 1]) / temp_gas_loading[i - 1]; | |
2023 } else { | |
2024 /* Computing MIN */ | |
2025 weighted_allowable_gradient = fminf(allowable_gradient_he[i - 1],allowable_gradient_n2[i - 1]); | |
2026 } | |
2027 allowable_gas_loading[i - 1] = | |
2028 ending_ambient_pressure + | |
2029 weighted_allowable_gradient - | |
2030 CONSTANT_PRESSURE_OTHER_GASES; | |
2031 /* L670: */ | |
2032 } | |
2033 for (i = 1; i <= 16; ++i) { | |
2034 if (temp_gas_loading[i - 1] > allowable_gas_loading[i - 1]) { | |
2035 *deco_stop_depth += *step_size; | |
2036 goto L665; | |
2037 } | |
2038 /* L671: */ | |
2039 } | |
2040 return 0; | |
2041 } /* projected_ascent */ | |
2042 | |
2043 /* =============================================================================== */ | |
2044 /* SUBROUTINE DECOMPRESSION_STOP */ | |
2045 /* Purpose: This subprogram calculates the required time at each */ | |
2046 /* decompression stop. */ | |
2047 /* =============================================================================== */ | |
2048 | |
290 | 2049 static void decompression_stop(float *deco_stop_depth, |
38 | 2050 float *step_size, |
2051 _Bool final_deco_calculation) | |
2052 { | |
2053 /* Local variables */ | |
2054 float inspired_nitrogen_pressure; | |
2055 // short last_segment_number; | |
2056 // float weighted_allowable_gradient; | |
2057 float initial_helium_pressure[16]; | |
2058 /* by hw */ | |
51
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
2059 float initial_CNS = gCNS_VPM; |
38 | 2060 |
2061 //static float time_counter; | |
2062 short i; | |
2063 float ambient_pressure; | |
2064 float inspired_helium_pressure, | |
2065 next_stop; | |
2066 //last_run_time, | |
2067 //temp_segment_time; | |
2068 | |
2069 float deco_ceiling_depth, | |
2070 initial_nitrogen_pressure[16]; | |
2071 //round_up_operation; | |
2072 float fraction_helium_begin; | |
2073 float fraction_nitrogen_begin; | |
2074 int count = 0; | |
2075 _Bool buehlmann_wait = false; | |
2076 float tissue_He_saturation[16]; | |
2077 float tissue_N2_saturation[16]; | |
877 | 2078 float vpm_buehlmann_safety_gradient = 1.0f - (((float)pDiveSettings->vpm_conservatism) / 40); |
38 | 2079 /* loop */ |
2080 /* =============================================================================== */ | |
2081 /* CALCULATIONS */ | |
2082 /* =============================================================================== */ | |
2083 | |
2084 segment_time = 0; | |
2085 // temp_segment_time = segment_time; | |
2086 ambient_pressure = *deco_stop_depth + barometric_pressure; | |
2087 //ending_ambient_pressure = ambient_pressure; | |
2088 decom_get_inert_gases(ambient_pressure / 10, (&pDiveSettings->decogaslist[mix_number]), &fraction_nitrogen_begin, &fraction_helium_begin ); | |
2089 | |
877 | 2090 if(*deco_stop_depth == (float)(pDiveSettings->last_stop_depth_bar * 10)) |
38 | 2091 next_stop = 0; |
2092 else | |
2093 { | |
2094 next_stop = *deco_stop_depth - *step_size; | |
877 | 2095 next_stop = fmaxf(next_stop,(float)pDiveSettings->last_stop_depth_bar * 10); |
38 | 2096 } |
2097 | |
2098 inspired_helium_pressure = | |
2099 (ambient_pressure - WATER_VAPOR_PRESSURE) * fraction_helium_begin; | |
2100 inspired_nitrogen_pressure = | |
2101 (ambient_pressure - WATER_VAPOR_PRESSURE) * fraction_nitrogen_begin; | |
2102 | |
2103 /* =============================================================================== */ | |
2104 /* Check to make sure that program won't lock up if unable to decompress */ | |
2105 /* to the next stop. If so, write error message and terminate program. */ | |
2106 /* =============================================================================== */ | |
2107 | |
2108 //deco_ceiling_depth = next_stop +1; //deco_ceiling_depth = next_stop + 1; | |
2109 if(!vpm_violates_buehlmann) | |
149 | 2110 { |
38 | 2111 calc_deco_ceiling(&deco_ceiling_depth, false); //weg, weil auf jeden Fall schleife für safety und so konservativer |
149 | 2112 } |
38 | 2113 else |
149 | 2114 { |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2115 deco_ceiling_depth = next_stop + 1.0; |
149 | 2116 } |
38 | 2117 if(deco_ceiling_depth > next_stop) |
2118 { | |
2119 while (deco_ceiling_depth > next_stop) | |
2120 { | |
2121 | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2122 segment_time += 60.0; |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2123 if(segment_time >= 999.0 ) |
38 | 2124 { |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2125 segment_time = 999.0 ; |
38 | 2126 run_time += segment_time; |
2127 return; | |
2128 } | |
2129 //goto L700; | |
2130 initial_CNS = gCNS_VPM; | |
2131 decom_oxygen_calculate_cns_exposure(60*60,&pDiveSettings->decogaslist[mix_number],ambient_pressure/10,&gCNS_VPM); | |
2132 for (i = 0; i < 16; i++) | |
2133 { | |
2134 initial_helium_pressure[i] = helium_pressure[i]; | |
2135 initial_nitrogen_pressure[i] = nitrogen_pressure[i]; | |
2136 helium_pressure[i] += (inspired_helium_pressure - helium_pressure[i]) * float_buehlmann_He_factor_expositon_one_hour[i]; | |
2137 nitrogen_pressure[i] += (inspired_nitrogen_pressure - nitrogen_pressure[i]) * float_buehlmann_N2_factor_expositon_one_hour[i]; | |
2138 } | |
2139 calc_deco_ceiling(&deco_ceiling_depth, false); | |
2140 } | |
2141 if(deco_ceiling_depth < next_stop) | |
2142 { | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2143 segment_time -= 60.0; |
38 | 2144 gCNS_VPM = initial_CNS; |
2145 for (i = 0; i < 16; i++) | |
2146 { | |
2147 helium_pressure[i] = initial_helium_pressure[i]; | |
2148 nitrogen_pressure[i] = initial_nitrogen_pressure[i]; | |
2149 } | |
2150 deco_ceiling_depth = next_stop +1; | |
2151 } | |
2152 count = 0; | |
2153 while (deco_ceiling_depth > next_stop && count < 13) | |
2154 { | |
2155 count++; | |
2156 segment_time += 5; | |
2157 //goto L700; | |
2158 initial_CNS = gCNS_VPM; | |
2159 decom_oxygen_calculate_cns_exposure(60*5,&pDiveSettings->decogaslist[mix_number],ambient_pressure/10,&gCNS_VPM); | |
2160 for (i = 0; i < 16; i++) | |
2161 { | |
2162 initial_helium_pressure[i] = helium_pressure[i]; | |
2163 initial_nitrogen_pressure[i] = nitrogen_pressure[i]; | |
2164 helium_pressure[i] += (inspired_helium_pressure - helium_pressure[i]) * float_buehlmann_He_factor_expositon_five_minutes[i]; | |
2165 nitrogen_pressure[i] += (inspired_nitrogen_pressure - nitrogen_pressure[i]) * float_buehlmann_N2_factor_expositon_five_minutes[i]; | |
2166 } | |
2167 calc_deco_ceiling(&deco_ceiling_depth, false); | |
2168 } | |
2169 if(deco_ceiling_depth < next_stop) | |
2170 { | |
2171 segment_time -= 5; | |
2172 gCNS_VPM = initial_CNS; | |
2173 for (i = 0; i < 16; i++) { | |
2174 helium_pressure[i] = initial_helium_pressure[i]; | |
2175 nitrogen_pressure[i] = initial_nitrogen_pressure[i]; | |
2176 } | |
2177 deco_ceiling_depth = next_stop +1; | |
2178 } | |
2179 buehlmann_wait = false; | |
2180 while (buehlmann_wait || (deco_ceiling_depth > next_stop)) | |
2181 { | |
2182 //time_counter = temp_segment_time; | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2183 segment_time += 1.0; |
38 | 2184 |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2185 if(segment_time >= 999.0 ) |
38 | 2186 { |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2187 segment_time = 999.0 ; |
38 | 2188 run_time += segment_time; |
2189 return; | |
2190 } | |
2191 //goto L700; | |
2192 initial_CNS = gCNS_VPM; | |
877 | 2193 decom_oxygen_calculate_cns_exposure(60*1,&pDiveSettings->decogaslist[mix_number],ambient_pressure/10,&gCNS_VPM); |
38 | 2194 for (i = 0; i < 16; i++) |
2195 { | |
2196 initial_helium_pressure[i] = helium_pressure[i]; | |
2197 initial_nitrogen_pressure[i] = nitrogen_pressure[i]; | |
2198 helium_pressure[i] += (inspired_helium_pressure - helium_pressure[i]) * float_buehlmann_He_factor_expositon_one_minute[i]; | |
2199 nitrogen_pressure[i] += (inspired_nitrogen_pressure - nitrogen_pressure[i]) * float_buehlmann_N2_factor_expositon_one_minute[i]; | |
2200 } | |
2201 if(!buehlmann_wait) | |
2202 calc_deco_ceiling(&deco_ceiling_depth, false); | |
2203 | |
2204 if(buehlmannSafety && final_deco_calculation && !(deco_ceiling_depth > next_stop)) | |
2205 { | |
2206 for (i = 0; i < 16; i++) | |
2207 { | |
2208 tissue_He_saturation[i] = helium_pressure[i] / 10; | |
2209 tissue_N2_saturation[i] = nitrogen_pressure[i] / 10; | |
2210 } | |
2211 if( (fabsf(nitrogen_pressure[15] - inspired_nitrogen_pressure) < 0.00001f) && (fabsf(helium_pressure[15] - inspired_helium_pressure) < 0.00001f) | |
2212 && (fabsf(nitrogen_pressure[0] - inspired_nitrogen_pressure) < 0.00001f) && (fabsf(helium_pressure[0] - inspired_helium_pressure) < 0.00001f)) | |
2213 { | |
2214 buehlmann_wait_exceeded = true; | |
2215 break; | |
2216 } | |
2217 | |
2218 if(decom_tissue_test_tolerance(tissue_N2_saturation, tissue_He_saturation, vpm_buehlmann_safety_gradient, (next_stop / 10.0f) + pInput->pressure_surface_bar)) | |
2219 break; | |
2220 | |
2221 buehlmann_wait = true; | |
2222 } | |
2223 } | |
2224 if(buehlmann_wait) | |
149 | 2225 { |
38 | 2226 vpm_violates_buehlmann = true; |
149 | 2227 } |
2228 if(!buehlmann_wait) | |
38 | 2229 { |
2230 if(deco_ceiling_depth < next_stop) | |
2231 { | |
2232 segment_time -= 1; | |
2233 gCNS_VPM = initial_CNS; | |
2234 for (i = 0; i < 16; i++) { | |
2235 helium_pressure[i] = initial_helium_pressure[i]; | |
2236 nitrogen_pressure[i] = initial_nitrogen_pressure[i]; | |
2237 } | |
2238 deco_ceiling_depth = next_stop +1; | |
2239 } | |
2240 while (deco_ceiling_depth > next_stop) | |
2241 { | |
2242 //time_counter = temp_segment_time; | |
2243 segment_time += (float) 1.0f / 3.0f; | |
2244 //goto L700; | |
2245 initial_CNS = gCNS_VPM; | |
2246 decom_oxygen_calculate_cns_exposure(20,&pDiveSettings->decogaslist[mix_number],ambient_pressure/10,&gCNS_VPM); | |
2247 for (i = 0; i < 16; i++) | |
2248 { | |
2249 helium_pressure[i] += (inspired_helium_pressure - helium_pressure[i]) * float_buehlmann_He_factor_expositon_20_seconds[i]; | |
2250 nitrogen_pressure[i] += (inspired_nitrogen_pressure - nitrogen_pressure[i]) * float_buehlmann_N2_factor_expositon_20_seconds[i]; | |
2251 } | |
2252 calc_deco_ceiling(&deco_ceiling_depth, false); | |
2253 } | |
2254 } | |
2255 } | |
2256 | |
2257 /*float pressure_save =dive_data.pressure; | |
2258 dive_data.pressure = ambient_pressure/10; | |
2259 tissues_exposure_stage(st_deco_test,(int)(segment_time * 60), &dive_data, &gaslist); | |
2260 dive_data.pressure = pressure_save;*/ | |
2261 run_time += segment_time; | |
2262 return; | |
2263 } /* decompression_stop */ | |
2264 | |
2265 /* =============================================================================== */ | |
2266 // SUROUTINE BOYLES_LAW_COMPENSATION | |
2267 // Purpose: This subprogram calculates the reduction in allowable gradients | |
2268 // with decreasing ambient pressure during the decompression profile based | |
2269 // on Boyle's Law considerations. | |
2270 //=============================================================================== | |
290 | 2271 static void BOYLES_LAW_COMPENSATION (float* First_Stop_Depth, |
38 | 2272 float* Deco_Stop_Depth, |
2273 float* Step_Size) | |
2274 { | |
2275 short i; | |
2276 | |
2277 float Next_Stop; | |
2278 float Ambient_Pressure_First_Stop, Ambient_Pressure_Next_Stop; | |
2279 float Amb_Press_First_Stop_Pascals, Amb_Press_Next_Stop_Pascals; | |
2280 float A, B, C, Low_Bound, High_Bound, Ending_Radius; | |
2281 float Deco_Gradient_Pascals; | |
2282 float Allow_Grad_First_Stop_He_Pa, Radius_First_Stop_He; | |
2283 float Allow_Grad_First_Stop_N2_Pa, Radius_First_Stop_N2; | |
2284 | |
2285 //=============================================================================== | |
2286 // LO//AL ARRAYS | |
2287 //=============================================================================== | |
2288 // float Radius1_He[16], Radius2_He[16]; | |
2289 // float Radius1_N2[16], Radius2_N2[16]; | |
2290 float root_factor; | |
2291 | |
2292 //=============================================================================== | |
2293 // CALCULATIONS | |
2294 //=============================================================================== | |
2295 Next_Stop = *Deco_Stop_Depth - *Step_Size; | |
2296 | |
2297 Ambient_Pressure_First_Stop = *First_Stop_Depth + | |
2298 barometric_pressure; | |
2299 | |
2300 Ambient_Pressure_Next_Stop = Next_Stop + barometric_pressure; | |
2301 | |
2302 Amb_Press_First_Stop_Pascals = (Ambient_Pressure_First_Stop/UNITS_FACTOR) * 101325.0f; | |
2303 | |
2304 Amb_Press_Next_Stop_Pascals = | |
2305 (Ambient_Pressure_Next_Stop/UNITS_FACTOR) * 101325.0f; | |
2306 root_factor = powf(Amb_Press_First_Stop_Pascals/Amb_Press_Next_Stop_Pascals,1.0f / 3.0f); | |
2307 | |
2308 for( i = 0; i < 16;i++) | |
2309 { | |
2310 Allow_Grad_First_Stop_He_Pa = | |
2311 (allowable_gradient_he[i]/UNITS_FACTOR) * 101325.0f; | |
2312 | |
2313 Radius_First_Stop_He = (2.0f * SURFACE_TENSION_GAMMA) / | |
2314 Allow_Grad_First_Stop_He_Pa; | |
2315 | |
2316 // Radius1_He[i] = Radius_First_Stop_He; | |
2317 A = Amb_Press_Next_Stop_Pascals; | |
2318 B = -2.0f * SURFACE_TENSION_GAMMA; | |
2319 C = (Amb_Press_First_Stop_Pascals + (2.0f * SURFACE_TENSION_GAMMA)/ | |
2320 Radius_First_Stop_He)* Radius_First_Stop_He* | |
2321 (Radius_First_Stop_He*(Radius_First_Stop_He)); | |
2322 Low_Bound = Radius_First_Stop_He; | |
2323 High_Bound = Radius_First_Stop_He * root_factor; | |
2324 //*pow(Amb_Press_First_Stop_Pascals/Amb_Press_Next_Stop_Pascals,1.0/3.0); | |
2325 //*(Amb_Press_First_Stop_Pascals/Amb_Press_Next_Stop_Pascals)**(1.0/3.0); | |
2326 | |
2327 radius_root_finder(&A,&B,&C, &Low_Bound, &High_Bound, | |
2328 &Ending_Radius); | |
2329 | |
2330 // Radius2_He[i] = Ending_Radius; | |
2331 Deco_Gradient_Pascals = (2.0f * SURFACE_TENSION_GAMMA) / | |
2332 Ending_Radius; | |
2333 | |
2334 deco_gradient_he[i] = (Deco_Gradient_Pascals / 101325.0f)* | |
2335 UNITS_FACTOR; | |
2336 | |
2337 } | |
2338 | |
2339 for( i = 0; i < 16;i++) | |
2340 { | |
2341 Allow_Grad_First_Stop_N2_Pa = | |
2342 (allowable_gradient_n2[i]/UNITS_FACTOR) * 101325.0f; | |
2343 | |
2344 Radius_First_Stop_N2 = (2.0f * SURFACE_TENSION_GAMMA) / | |
2345 Allow_Grad_First_Stop_N2_Pa; | |
2346 | |
2347 // Radius1_N2[i] = Radius_First_Stop_N2; | |
2348 A = Amb_Press_Next_Stop_Pascals; | |
2349 B = -2.0f * SURFACE_TENSION_GAMMA; | |
2350 C = (Amb_Press_First_Stop_Pascals + (2.0f * SURFACE_TENSION_GAMMA)/ | |
2351 Radius_First_Stop_N2)* Radius_First_Stop_N2* | |
2352 (Radius_First_Stop_N2*(Radius_First_Stop_N2)); | |
2353 Low_Bound = Radius_First_Stop_N2; | |
2354 High_Bound = Radius_First_Stop_N2* root_factor;//pow(Amb_Press_First_Stop_Pascals/Amb_Press_Next_Stop_Pascals,1.0/3.0); | |
2355 | |
2356 //High_Bound = Radius_First_Stop_N2*exp(log(Amb_Press_First_Stop_Pascals/Amb_Press_Next_Stop_Pascals)/3); | |
2357 radius_root_finder(&A,&B,&C, &Low_Bound, &High_Bound, | |
2358 &Ending_Radius); | |
2359 | |
2360 // Radius2_N2[i] = Ending_Radius; | |
2361 Deco_Gradient_Pascals = (2.0f * SURFACE_TENSION_GAMMA) / | |
2362 Ending_Radius; | |
2363 | |
2364 deco_gradient_n2[i] = (Deco_Gradient_Pascals / 101325.0f)* | |
2365 UNITS_FACTOR; | |
2366 } | |
2367 } | |
2368 | |
2369 /* =============================================================================== */ | |
292 | 2370 // vpm_calc_ndl |
2371 // Purpose: This function computes NDL (time where no decostops are needed) | |
38 | 2372 //=============================================================================== |
291
24ff72e627f4
Deco Models: limit NDL to 240 minutes
Jan Mulder <jlmulder@xs4all.nl>
parents:
290
diff
changeset
|
2373 #define MAX_NDL 240 |
24ff72e627f4
Deco Models: limit NDL to 240 minutes
Jan Mulder <jlmulder@xs4all.nl>
parents:
290
diff
changeset
|
2374 |
292 | 2375 static int vpm_calc_ndl(void) |
38 | 2376 { |
2377 static float future_helium_pressure[16]; | |
2378 static float future_nitrogen_pressure[16]; | |
2379 static int temp_segment_time; | |
2380 static int mix_number; | |
2381 static float inspired_helium_pressure; | |
2382 static float inspired_nitrogen_pressure; | |
2383 | |
2384 float previous_helium_pressure[16]; | |
2385 float previous_nitrogen_pressure[16]; | |
2386 float ambient_pressure; | |
2387 float fraction_helium_begin; | |
2388 float fraction_nitrogen_begin; | |
2389 int i = 0; | |
2390 int count = 0; | |
2391 int status = CALC_END; | |
291
24ff72e627f4
Deco Models: limit NDL to 240 minutes
Jan Mulder <jlmulder@xs4all.nl>
parents:
290
diff
changeset
|
2392 |
38 | 2393 for(i = 0; i < 16;i++) |
2394 { | |
863
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2395 future_helium_pressure[i] = pInput->tissue_helium_bar[i] * 10.0;//tissue_He_saturation[st_dive][i] * 10; |
0c89c6fa949c
Bugfix empty line in deco plan (VPM only):
Ideenmodellierer
parents:
830
diff
changeset
|
2396 future_nitrogen_pressure[i] = pInput->tissue_nitrogen_bar[i] * 10.0; |
38 | 2397 } |
2398 temp_segment_time = 0; | |
2399 | |
2400 mix_number = 0; | |
877 | 2401 ambient_pressure = pInput->pressure_ambient_bar * 10; |
2402 decom_get_inert_gases( ambient_pressure / 10, (&pDiveSettings->decogaslist[mix_number]) , &fraction_nitrogen_begin, &fraction_helium_begin ); | |
38 | 2403 inspired_helium_pressure =(ambient_pressure - WATER_VAPOR_PRESSURE) * fraction_helium_begin; |
2404 inspired_nitrogen_pressure =(ambient_pressure - WATER_VAPOR_PRESSURE) *fraction_nitrogen_begin; | |
2405 | |
2406 status = CALC_END; | |
2407 while (status == CALC_END) | |
2408 { | |
2409 count++; | |
2410 temp_segment_time += 60; | |
291
24ff72e627f4
Deco Models: limit NDL to 240 minutes
Jan Mulder <jlmulder@xs4all.nl>
parents:
290
diff
changeset
|
2411 if(temp_segment_time >= MAX_NDL) |
38 | 2412 { |
2413 pDecoInfo->output_ndl_seconds = temp_segment_time * 60; | |
292 | 2414 return CALC_NDL; |
38 | 2415 } |
2416 run_time += 60; | |
2417 //goto L700; | |
2418 for (i = 1; i <= 16; ++i) { | |
2419 previous_helium_pressure[i-1] = future_helium_pressure[i - 1]; | |
2420 previous_nitrogen_pressure[i - 1] = future_nitrogen_pressure[i - 1]; | |
2421 future_helium_pressure[i - 1] = future_helium_pressure[i - 1] + (inspired_helium_pressure - future_helium_pressure[i - 1]) * float_buehlmann_He_factor_expositon_one_hour[i-1]; | |
2422 future_nitrogen_pressure[i - 1] = future_nitrogen_pressure[i - 1] + (inspired_nitrogen_pressure - future_nitrogen_pressure[i - 1]) * float_buehlmann_N2_factor_expositon_one_hour[i-1]; | |
2423 helium_pressure[i - 1] = future_helium_pressure[i - 1]; | |
2424 nitrogen_pressure[i - 1] = future_nitrogen_pressure[i - 1]; | |
2425 } | |
2426 vpm_calc_deco(); | |
2427 while((status = vpm_calc_critcal_volume(true,true)) == CALC_CRITICAL); | |
2428 | |
2429 } | |
2430 | |
2431 temp_segment_time -= 60; | |
2432 run_time -= 60; | |
2433 for (i = 1; i <= 16; ++i) | |
2434 { | |
2435 future_helium_pressure[i - 1] = previous_helium_pressure[i-1]; | |
2436 future_nitrogen_pressure[i - 1] = previous_nitrogen_pressure[i - 1]; | |
2437 } | |
2438 | |
2439 status = CALC_END; | |
2440 if(temp_segment_time < 60) | |
2441 nullzeit_unter60 = true; | |
2442 | |
2443 while (status == CALC_END) | |
2444 { | |
2445 temp_segment_time += 5; | |
291
24ff72e627f4
Deco Models: limit NDL to 240 minutes
Jan Mulder <jlmulder@xs4all.nl>
parents:
290
diff
changeset
|
2446 if(temp_segment_time >= MAX_NDL) |
38 | 2447 { |
2448 pDecoInfo->output_ndl_seconds = temp_segment_time * 60; | |
292 | 2449 return CALC_NDL; |
38 | 2450 } |
2451 if(nullzeit_unter60 && temp_segment_time > 60) | |
2452 { | |
2453 nullzeit_unter60 = false; | |
292 | 2454 return CALC_NDL; |
38 | 2455 } |
2456 run_time += 5; | |
2457 //goto L700; | |
2458 for (i = 1; i <= 16; ++i) { | |
2459 previous_helium_pressure[i-1] = future_helium_pressure[i - 1]; | |
2460 previous_nitrogen_pressure[i - 1] = future_nitrogen_pressure[i - 1]; | |
2461 future_helium_pressure[i - 1] = future_helium_pressure[i - 1] + (inspired_helium_pressure - future_helium_pressure[i - 1]) * float_buehlmann_He_factor_expositon_five_minutes[i-1]; | |
2462 future_nitrogen_pressure[i - 1] = future_nitrogen_pressure[i - 1] + (inspired_nitrogen_pressure - future_nitrogen_pressure[i - 1]) * float_buehlmann_N2_factor_expositon_five_minutes[i-1]; | |
2463 helium_pressure[i - 1] = future_helium_pressure[i - 1]; | |
2464 nitrogen_pressure[i - 1] = future_nitrogen_pressure[i - 1]; | |
2465 } | |
2466 vpm_calc_deco(); | |
2467 while((status =vpm_calc_critcal_volume(true,true)) == CALC_CRITICAL); | |
2468 } | |
2469 temp_segment_time -= 5; | |
2470 run_time -= 5; | |
2471 for (i = 1; i <= 16; ++i) { | |
2472 future_helium_pressure[i - 1] = previous_helium_pressure[i-1]; | |
2473 future_nitrogen_pressure[i - 1] = previous_nitrogen_pressure[i - 1]; | |
2474 } | |
2475 status = CALC_END; | |
291
24ff72e627f4
Deco Models: limit NDL to 240 minutes
Jan Mulder <jlmulder@xs4all.nl>
parents:
290
diff
changeset
|
2476 |
38 | 2477 if(temp_segment_time <= 20) |
2478 { | |
2479 while (status == CALC_END) | |
2480 { | |
2481 temp_segment_time += minimum_deco_stop_time; | |
2482 run_time += minimum_deco_stop_time; | |
2483 //goto L700; | |
2484 for (i = 1; i <= 16; ++i) { | |
2485 future_helium_pressure[i - 1] = future_helium_pressure[i - 1] + (inspired_helium_pressure - future_helium_pressure[i - 1]) * float_buehlmann_He_factor_expositon_one_minute[i-1]; | |
2486 future_nitrogen_pressure[i - 1] = future_nitrogen_pressure[i - 1] + (inspired_nitrogen_pressure - future_nitrogen_pressure[i - 1]) * float_buehlmann_N2_factor_expositon_one_minute[i-1]; | |
2487 helium_pressure[i - 1] = future_helium_pressure[i - 1]; | |
2488 nitrogen_pressure[i - 1] =future_nitrogen_pressure[i - 1]; | |
2489 | |
2490 } | |
2491 vpm_calc_deco(); | |
2492 while((status =vpm_calc_critcal_volume(true,true)) == CALC_CRITICAL); | |
2493 | |
2494 } | |
2495 } | |
2496 else | |
2497 temp_segment_time += 5; | |
2498 pDecoInfo->output_ndl_seconds = temp_segment_time * 60; | |
2499 if(temp_segment_time > 1) | |
292 | 2500 return CALC_NDL; |
38 | 2501 else |
2502 return CALC_BEGIN; | |
2503 } | |
902 | 2504 |
2505 void vpm_table_init() | |
2506 { | |
2507 vpmTable.output_time_to_surface_seconds = 0; | |
907 | 2508 vpmTableState = VPM_TABLE_INIT; |
2509 } | |
2510 uint8_t vpm_get_decozone(void) | |
2511 { | |
2512 return((uint8_t)pVpm->depth_start_of_deco_zone_save); | |
2513 } | |
2514 SvpmTableState vpm_get_TableState(void) | |
2515 { | |
2516 return vpmTableState; | |
902 | 2517 } |
2518 |