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