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