comparison src/p2_deco.c @ 521:06e9370c6d75

CHANGE: Apply safety margin parameters to both models (GF and non-GF) Put B?hlmann constants in code for readability Fix unused gas warning (Do not warn)
author heinrichsweikamp
date Fri, 04 Aug 2017 16:01:28 +0200
parents ff1e6adf55ad
children 4d70a93b18cb
comparison
equal deleted inserted replaced
520:1d74d6221084 521:06e9370c6d75
87 // 2013/05/08: [jDG] A. Salm remark: NOAA tables for CNS are in ATA, not bar. 87 // 2013/05/08: [jDG] A. Salm remark: NOAA tables for CNS are in ATA, not bar.
88 // 2013/12/21: [jDG] Fix CNS calculation in decoplan w/o marked gas switch 88 // 2013/12/21: [jDG] Fix CNS calculation in decoplan w/o marked gas switch
89 // 2014/06/16: [jDG] Fix Helium diluant. Fix volumes with many travel mix. 89 // 2014/06/16: [jDG] Fix Helium diluant. Fix volumes with many travel mix.
90 // 2014/06/29: [mH] Compute int_O_ceiling 90 // 2014/06/29: [mH] Compute int_O_ceiling
91 // 2015/06/12: [jDG] Fix NDL prediction while desaturating with the Buhlmann model. 91 // 2015/06/12: [jDG] Fix NDL prediction while desaturating with the Buhlmann model.
92 // 2017/08/04: [mH] Switch to absolute GF everywhere and apply safety margin parameters to both models (GF and non-GF), fixes from Ralph Lembcke
92 // 93 //
93 // TODO: 94 // TODO:
94 // 95 //
95 // Literature: 96 // Literature:
96 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002]; 97 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002];
256 // 257 //
257 #ifndef UNIX 258 #ifndef UNIX
258 # pragma romdata buhlmann_tables = 0x1DD00 // Needs to be in UPPER bank. 259 # pragma romdata buhlmann_tables = 0x1DD00 // Needs to be in UPPER bank.
259 #endif 260 #endif
260 261
261 #include "p2_tables.romdata" // new table for deco_main_v.101 (var_N2_a modified) 262 rom const float buhlmann_ab[4*16] = {
263 // Data ZH-L16C, from Bühlmann Tauchmedizin 2002, option 1a (4mn)
264 // a for N2 b for N2 a of He b for He
265 1.2599, 0.5050, 1.7424, 0.4245,
266 1.0000, 0.6514, 1.3830, 0.5747,
267 0.8618, 0.7222, 1.1919, 0.6527,
268 0.7562, 0.7825, 1.0458, 0.7223,
269 0.6200, 0.8126, 0.9220, 0.7582,
270 0.5043, 0.8434, 0.8205, 0.7957,
271 0.4410, 0.8693, 0.7305, 0.8279,
272 0.4000, 0.8910, 0.6502, 0.8553,
273 0.3750, 0.9092, 0.5950, 0.8757,
274 0.3500, 0.9222, 0.5545, 0.8903,
275 0.3295, 0.9319, 0.5333, 0.8997,
276 0.3065, 0.9403, 0.5189, 0.9073,
277 0.2835, 0.9477, 0.5181, 0.9122,
278 0.2610, 0.9544, 0.5176, 0.9171,
279 0.2480, 0.9602, 0.5172, 0.9217,
280 0.2327, 0.9653, 0.5119, 0.9267
281 };
282
283 rom const float buhlmann_ht[2*16] = {
284 // Compartiment half-life, in minute
285 //-- N2 ---- He ---------------------------------------------------------------------
286 4.0, 1.51,
287 8.0, 3.02,
288 12.5, 4.72,
289 18.5, 6.99,
290 27.0, 10.21,
291 38.3, 14.48,
292 54.3, 20.53,
293 77.0, 29.11,
294 109.0, 41.20,
295 146.0, 55.19,
296 187.0, 70.69,
297 239.0, 90.34,
298 305.0, 115.29,
299 390.0, 147.42,
300 498.0, 188.24,
301 635.0, 240.03
302 };
303
304 rom const float e2secs[2*16] = {
305 // result of 1 - 2^(-1/(30sec*HT))
306 //---- N2 ------------- He ------------
307 5.75958E-03, 1.51848E-02,
308 2.88395E-03, 7.62144E-03,
309 1.84669E-03, 4.88315E-03,
310 1.24813E-03, 3.29997E-03,
311 8.55371E-04, 2.26041E-03,
312 6.03079E-04, 1.59437E-03,
313 4.25414E-04, 1.12479E-03,
314 3.00019E-04, 7.93395E-04,
315 2.11949E-04, 5.60641E-04,
316 1.58240E-04, 4.18555E-04,
317 1.23548E-04, 3.26795E-04,
318 9.66686E-05, 2.55722E-04,
319 7.57509E-05, 2.00387E-04,
320 5.92416E-05, 1.56716E-04,
321 4.63943E-05, 1.22734E-04,
322 3.63850E-05, 9.62538E-05
323 //-------------------------------------
324 };
325
326 rom const float e1min[2*16] = {
327 // Integration constant for 1 minute,
328 // Ie. 1- 2^(-1/HT)
329 //----- N2 --------- e 1min He --------
330 1.59104E-01, 3.68109E-01,
331 8.29960E-02, 2.05084E-01,
332 5.39424E-02, 1.36579E-01,
333 3.67742E-02, 9.44046E-02,
334 2.53454E-02, 6.56359E-02,
335 1.79351E-02, 4.67416E-02,
336 1.26840E-02, 3.31991E-02,
337 8.96152E-03, 2.35301E-02,
338 6.33897E-03, 1.66832E-02,
339 4.73633E-03, 1.24808E-02,
340 3.69981E-03, 9.75753E-03,
341 2.89600E-03, 7.64329E-03,
342 2.27003E-03, 5.99417E-03,
343 1.77572E-03, 4.69082E-03,
344 1.39089E-03, 3.67548E-03,
345 1.09097E-03, 2.88359E-03
346 //-------------------------------------
347 };
348
349 rom const float e10min[2*16] = {
350 // The 10 min Value in float notation:
351 // result of 1 - 2^(-10/ht)
352 //---- N2 -------------- He -----------
353 8.23223E-01, 9.89851E-01,
354 5.79552E-01, 8.99258E-01,
355 4.25651E-01, 7.69737E-01,
356 3.12487E-01, 6.29027E-01,
357 2.26416E-01, 4.92821E-01,
358 1.65547E-01, 3.80407E-01,
359 1.19840E-01, 2.86538E-01,
360 8.60863E-02, 2.11886E-01,
361 6.16117E-02, 1.54849E-01,
362 4.63665E-02, 1.18026E-01,
363 3.63881E-02, 9.34005E-02,
364 2.85855E-02, 7.38569E-02,
365 2.24698E-02, 5.83504E-02,
366 1.76160E-02, 4.59303E-02,
367 1.38222E-02, 3.61528E-02,
368 1.08563E-02, 2.84646E-02
369 //-------------------------------------
370 };
262 371
263 ////////////////////////////////////////////////////////////////////////////// 372 //////////////////////////////////////////////////////////////////////////////
264 ////////////////////////////////////////////////////////////////////////////// 373 //////////////////////////////////////////////////////////////////////////////
265 ////////////////////////////// THE SUBROUTINES /////////////////////////////// 374 ////////////////////////////// THE SUBROUTINES ///////////////////////////////
266 ////////////////////////////////////////////////////////////////////////////// 375 //////////////////////////////////////////////////////////////////////////////
642 ////////////////////////////////////////////////////////////////////////////// 751 //////////////////////////////////////////////////////////////////////////////
643 // temp_tissue_safety // 752 // temp_tissue_safety //
644 // 753 //
645 // outsourced in v.102 754 // outsourced in v.102
646 // 755 //
647 // Apply safety factors for brand ZH-L16 model. 756 // Apply safety factors for both ZH-L16 models.
648 // 757 //
649 static void temp_tissue_safety(void) 758 static void temp_tissue_safety(void)
650 { 759 {
651 assert( 0.0 < float_desaturation_multiplier && float_desaturation_multiplier <= 1.0 ); 760 assert( 0.0 < float_desaturation_multiplier && float_desaturation_multiplier <= 1.0 );
652 assert( 1.0 <= float_saturation_multiplier && float_saturation_multiplier <= 2.0 ); 761 assert( 1.0 <= float_saturation_multiplier && float_saturation_multiplier <= 2.0 );
653 762
654 if( char_I_deco_model == 0 )
655 {
656 if( temp_tissue < 0.0 ) 763 if( temp_tissue < 0.0 )
657 temp_tissue *= float_desaturation_multiplier; 764 temp_tissue *= float_desaturation_multiplier;
658 else 765 else
659 temp_tissue *= float_saturation_multiplier; 766 temp_tissue *= float_saturation_multiplier;
660 }
661 } 767 }
662 768
663 ////////////////////////////////////////////////////////////////////////////// 769 //////////////////////////////////////////////////////////////////////////////
664 ////////////////////////////////////////////////////////////////////////////// 770 //////////////////////////////////////////////////////////////////////////////
665 // ** THE JUMP-IN CODE ** 771 // ** THE JUMP-IN CODE **
794 { 900 {
795 assert( !sim_gas_last_depth || sim_gas_last_depth > switch_deco ); 901 assert( !sim_gas_last_depth || sim_gas_last_depth > switch_deco );
796 902
797 sim_gas_last_depth = switch_deco; 903 sim_gas_last_depth = switch_deco;
798 sim_gas_last_used = switch_last; 904 sim_gas_last_used = switch_last;
799 return 0;
800 } 905 }
801 return 0; 906 return 0;
802 } 907 }
803 908
804 ////////////////////////////////////////////////////////////////////////////// 909 //////////////////////////////////////////////////////////////////////////////
905 clear_deco_table(); 1010 clear_deco_table();
906 char_O_deco_status = 0; 1011 char_O_deco_status = 0;
907 char_O_nullzeit = 0; 1012 char_O_nullzeit = 0;
908 int_O_ascenttime = 0; 1013 int_O_ascenttime = 0;
909 char_O_gradient_factor = 0; 1014 char_O_gradient_factor = 0;
910 char_O_relative_gradient_GF = 0;
911 1015
912 calc_lead_tissue_limit = 0.0; 1016 calc_lead_tissue_limit = 0.0;
913 char_O_gtissue_no = 0; 1017 char_O_gtissue_no = 0;
914 } 1018 }
915 1019
1412 1516
1413 //---- Add 10min/1min to N2/He tissues 1517 //---- Add 10min/1min to N2/He tissues
1414 overlay float dTN2 = (ppN2 - tN2) * var_N2_e; 1518 overlay float dTN2 = (ppN2 - tN2) * var_N2_e;
1415 overlay float dTHe = (ppHe - tHe) * var_He_e; 1519 overlay float dTHe = (ppHe - tHe) * var_He_e;
1416 1520
1417 //---- Apply security margin when using the non-GF model 1521 //---- Apply security margin for both models
1418 if( char_I_deco_model == 0 )
1419 {
1420 // NDL can be computed while ascending... SO we have 1522 // NDL can be computed while ascending... SO we have
1421 // to check wether we are saturating or desaturating. 1523 // to check wether we are saturating or desaturating.
1422 if( dTN2 > 0.0 ) dTN2 *= float_saturation_multiplier; 1524 if( dTN2 > 0.0 ) dTN2 *= float_saturation_multiplier;
1423 else dTN2 *= float_desaturation_multiplier; 1525 else dTN2 *= float_desaturation_multiplier;
1424 1526
1425 if( dTHe > 0.0 ) dTHe *= float_saturation_multiplier; 1527 if( dTHe > 0.0 ) dTHe *= float_saturation_multiplier;
1426 else dTHe *= float_saturation_multiplier; 1528 else dTHe *= float_saturation_multiplier;
1427 } 1529
1428 else // Or GF-based model 1530 if (char_I_deco_model != 0 )
1429 M0 = GF_high * (M0 - pres_surface) + pres_surface; 1531 M0 = GF_high * (M0 - pres_surface) + pres_surface;
1430 1532
1431 //---- Simulate off-gasing while going to surface 1533 //---- Simulate off-gasing while going to surface
1432 // TODO ! 1534 // TODO !
1433 // dTN2 -= exp( ... ascent time ... ppN2...) 1535 // dTN2 -= exp( ... ascent time ... ppN2...)
1698 if( gf > 254.5 ) gf = 255.0; 1800 if( gf > 254.5 ) gf = 255.0;
1699 if( gf < 0.0 ) gf = 0.0; 1801 if( gf < 0.0 ) gf = 0.0;
1700 } 1802 }
1701 char_O_gradient_factor = (unsigned char)(gf+0.5f); 1803 char_O_gradient_factor = (unsigned char)(gf+0.5f);
1702 1804
1703 if( char_I_deco_model != 0 ) // calculate relative gradient factor
1704 {
1705 overlay float rgf;
1706
1707 if( low_depth < 3 )
1708 rgf = GF_high;
1709 else
1710 {
1711 overlay float temp1 = low_depth * METER_TO_BAR;
1712 overlay float temp2 = pres_respiration - pres_surface;
1713
1714 if (temp2 <= 0)
1715 rgf = GF_high;
1716 else if (temp2 >= temp1)
1717 rgf = GF_low;
1718 else
1719 rgf = GF_low + (temp1 - temp2)/temp1*GF_delta;
1720 }
1721
1722 rgf = gf / rgf; // gf is already in percent
1723 if( rgf < 0.0 ) rgf = 0.0;
1724 if( rgf > 254.5 ) rgf = 255.0;
1725 char_O_relative_gradient_GF = (unsigned char)(rgf+0.5f);
1726 }
1727 else
1728 {
1729 // calc relative gradient factor
1730 char_O_relative_gradient_GF = char_O_gradient_factor;
1731 }
1732 } 1805 }
1733 1806
1734 ////////////////////////////////////////////////////////////////////////////// 1807 //////////////////////////////////////////////////////////////////////////////
1735 // deco_calc_desaturation_time 1808 // deco_calc_desaturation_time
1736 // 1809 //
1881 // desaturation slowed down to 70,42%. 1954 // desaturation slowed down to 70,42%.
1882 // 1955 //
1883 static void calc_dive_interval(void) 1956 static void calc_dive_interval(void)
1884 { 1957 {
1885 overlay unsigned char t; 1958 overlay unsigned char t;
1886 overlay unsigned char backup_model; 1959
1887
1888 //---- Initialize simulation parameters ---------------------------------- 1960 //---- Initialize simulation parameters ----------------------------------
1889 N2_ratio = 0.7902; // FIXED, sum lt. buehlmann 1961 N2_ratio = 0.7902; // FIXED, sum lt. buehlmann
1890 pres_respiration = pres_surface = int_I_pres_surface * 0.001; 1962 pres_respiration = pres_surface = int_I_pres_surface * 0.001;
1891 ppN2 = N2_ratio * (pres_respiration - ppWater); 1963 ppN2 = N2_ratio * (pres_respiration - ppWater);
1892 ppHe = 0.0; 1964 ppHe = 0.0;
1893 float_desaturation_multiplier = char_I_desaturation_multiplier * (0.01 * SURFACE_DESAT_FACTOR); 1965 float_desaturation_multiplier = char_I_desaturation_multiplier * (0.01 * SURFACE_DESAT_FACTOR);
1894 float_saturation_multiplier = char_I_saturation_multiplier * 0.01; 1966 float_saturation_multiplier = char_I_saturation_multiplier * 0.01;
1895 1967
1896 // Make sure SURFACE_DESAT_FACTOR is applied:
1897 backup_model = char_I_deco_model;
1898 char_I_deco_model = 0;
1899
1900 //---- Perform simulation ------------------------------------------------ 1968 //---- Perform simulation ------------------------------------------------
1901 for(t=0; t<char_I_dive_interval; ++t) 1969 for(t=0; t<char_I_dive_interval; ++t)
1902 { 1970 {
1903 calc_tissue(2); // period = 10min. 1971 calc_tissue(2); // period = 10min.
1904 CNS_fraction = 0.92587471 * CNS_fraction; // Half-time = 90min: (1/2)^(1/9) 1972 CNS_fraction = 0.92587471 * CNS_fraction; // Half-time = 90min: (1/2)^(1/9)
1905 } 1973 }
1906 assert( 0.0 <= CNS_fraction && CNS_fraction <= 9.99 ); // 999 % 1974 assert( 0.0 <= CNS_fraction && CNS_fraction <= 9.99 ); // 999 %
1907 int_O_CNS_fraction = (unsigned short)(CNS_fraction * 100.0 + 0.5); 1975 int_O_CNS_fraction = (unsigned short)(CNS_fraction * 100.0 + 0.5);
1908 1976
1909 //---- Restore model -----------------------------------------------------
1910 char_I_deco_model = backup_model;
1911 } 1977 }
1912 1978
1913 ////////////////////////////////////////////////////////////////////////////// 1979 //////////////////////////////////////////////////////////////////////////////
1914 // deco_clear_CNS_fraction 1980 // deco_clear_CNS_fraction
1915 // 1981 //