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