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