comparison code_part1/OSTC_code_c_part2/p2_deco.c @ 511:2a6293641d51

NEW NDL NDL faster/more precise simu (but no closed formula for trimix).
author JeanDo
date Fri, 25 Nov 2011 01:56:17 +0100
parents 103051b4d9c1
children e7893664bd29
comparison
equal deleted inserted replaced
510:6c0bf50610f7 511:2a6293641d51
76 // 2011/04/15: [jDG] Store low_depth in 32bits (w/o rounding), for a better stability. 76 // 2011/04/15: [jDG] Store low_depth in 32bits (w/o rounding), for a better stability.
77 // 2011/04/25: [jDG] Added 1mn mode for CNS calculation, to allow it for decoplanning. 77 // 2011/04/25: [jDG] Added 1mn mode for CNS calculation, to allow it for decoplanning.
78 // 2011/04/27: [jDG] Fixed char_O_gradient_factor calculation when model uses gradient-factor. 78 // 2011/04/27: [jDG] Fixed char_O_gradient_factor calculation when model uses gradient-factor.
79 // 2011/05/02: [jDG] Added "Future TTS" function (CF58). 79 // 2011/05/02: [jDG] Added "Future TTS" function (CF58).
80 // 2011/05/17: [jDG] Various cleanups. 80 // 2011/05/17: [jDG] Various cleanups.
81 // 2011/08/08: [jDG] Computes CNS during deco planning ascent.
82 // 2011/11/24: [jDG] Slightly faster and better NDL computation.
81 // 83 //
82 // TODO: 84 // TODO:
83 // + Allow to abort MD2 calculation (have to restart next time). 85 // + Allow to abort MD2 calculation (have to restart next time).
84 // 86 //
85 // Literature: 87 // Literature:
1191 // preload tissues with standard pressure for the given ambient pressure. 1193 // preload tissues with standard pressure for the given ambient pressure.
1192 // Note: fixed N2_ratio for standard air. 1194 // Note: fixed N2_ratio for standard air.
1193 // 1195 //
1194 static void clear_tissue(void) 1196 static void clear_tissue(void)
1195 { 1197 {
1198 overlay float p;
1196 flag_in_divemode = 0; 1199 flag_in_divemode = 0;
1197 int_O_DBS_bitfield = 0; 1200 int_O_DBS_bitfield = 0;
1198 int_O_DBS2_bitfield = 0; 1201 int_O_DBS2_bitfield = 0;
1199 int_O_DBG_pre_bitfield = 0; 1202 int_O_DBG_pre_bitfield = 0;
1200 int_O_DBG_post_bitfield = 0; 1203 int_O_DBG_post_bitfield = 0;
1202 1205
1203 // Kludge: the 0.0002 of 0.7902 are missing with standard air. 1206 // Kludge: the 0.0002 of 0.7902 are missing with standard air.
1204 N2_ratio = 0.7902; 1207 N2_ratio = 0.7902;
1205 pres_respiration = int_I_pres_respiration * 0.001; 1208 pres_respiration = int_I_pres_respiration * 0.001;
1206 1209
1210 p = N2_ratio * (pres_respiration - ppWater);
1207 for(ci=0; ci<NUM_COMP; ci++) 1211 for(ci=0; ci<NUM_COMP; ci++)
1208 { 1212 {
1209 // cycle through the 16 Bühlmann tissues 1213 // cycle through the 16 Bühlmann N2 tissues
1210 overlay float p = N2_ratio * (pres_respiration - ppWater);
1211 pres_tissue_N2[ci] = p; 1214 pres_tissue_N2[ci] = p;
1212 1215
1213 // cycle through the 16 Bühlmann tissues for Helium 1216 // cycle through the 16 Bühlmann tissues for Helium
1214 pres_tissue_He[ci] = 0.0; 1217 pres_tissue_He[ci] = 0.0;
1215 } // for 0 to 15 1218 }
1216 1219
1217 clear_deco_table(); 1220 clear_deco_table();
1218 char_O_deco_status = 0; 1221 char_O_deco_status = 0;
1219 char_O_nullzeit = 0; 1222 char_O_nullzeit = 0;
1220 int_O_ascenttime = 0; 1223 int_O_ascenttime = 0;
1340 // Detect gas change condition. 1343 // Detect gas change condition.
1341 // 1344 //
1342 void calc_hauptroutine_data_input(void) 1345 void calc_hauptroutine_data_input(void)
1343 { 1346 {
1344 overlay short int_temp; 1347 overlay short int_temp;
1348 overlay unsigned char g;
1345 1349
1346 pres_respiration = int_I_pres_respiration * 0.001; 1350 pres_respiration = int_I_pres_respiration * 0.001;
1347 pres_surface = int_I_pres_surface * 0.001; 1351 pres_surface = int_I_pres_surface * 0.001;
1348 N2_ratio = char_I_N2_ratio * 0.01; 1352 N2_ratio = char_I_N2_ratio * 0.01;
1349 He_ratio = char_I_He_ratio * 0.01; 1353 He_ratio = char_I_He_ratio * 0.01;
1356 1360
1357 // Keep a margin of 150mbar = 1.50m 1361 // Keep a margin of 150mbar = 1.50m
1358 int_temp = (int_I_pres_respiration - int_I_pres_surface) 1362 int_temp = (int_I_pres_respiration - int_I_pres_surface)
1359 + MBAR_REACH_GASCHANGE_AUTO_CHANGE_OFF; 1363 + MBAR_REACH_GASCHANGE_AUTO_CHANGE_OFF;
1360 1364
1361 deco_gas_change[0] = 0;
1362 deco_gas_change[1] = 0;
1363 deco_gas_change[2] = 0;
1364 deco_gas_change[3] = 0;
1365 deco_gas_change[4] = 0;
1366
1367 // Gas are selectable if we did not pass the change depth by more than 1.50m: 1365 // Gas are selectable if we did not pass the change depth by more than 1.50m:
1368 if(char_I_deco_gas_change[0]) 1366 for(g=0; g < NUM_GAS; ++g)
1369 { 1367 {
1370 if( int_temp > 100 *(short)char_I_deco_gas_change[0] ) 1368 deco_gas_change[g] = 0;
1371 deco_gas_change[0] = char_I_deco_gas_change[0]; 1369 if(char_I_deco_gas_change[g])
1372 } 1370 if( int_temp > 100 *(short)char_I_deco_gas_change[g] )
1373 if(char_I_deco_gas_change[1]) 1371 deco_gas_change[g] = char_I_deco_gas_change[g];
1374 {
1375 if( int_temp > 100 *(short)char_I_deco_gas_change[1] )
1376 deco_gas_change[1] = char_I_deco_gas_change[1];
1377 }
1378 if(char_I_deco_gas_change[2])
1379 {
1380 if( int_temp > 100 *(short)char_I_deco_gas_change[2] )
1381 deco_gas_change[2] = char_I_deco_gas_change[2];
1382 }
1383 if(char_I_deco_gas_change[3])
1384 {
1385 if( int_temp > 100 *(short)char_I_deco_gas_change[3] )
1386 deco_gas_change[3] = char_I_deco_gas_change[3];
1387 }
1388 if(char_I_deco_gas_change[4])
1389 {
1390 if( int_temp > 100 *(short)char_I_deco_gas_change[4] )
1391 deco_gas_change[4] = char_I_deco_gas_change[4];
1392 } 1372 }
1393 1373
1394 const_ppO2 = char_I_const_ppO2 * 0.01; 1374 const_ppO2 = char_I_const_ppO2 * 0.01;
1395 float_desaturation_multiplier = char_I_desaturation_multiplier * 0.01; 1375 float_desaturation_multiplier = char_I_desaturation_multiplier * 0.01;
1396 float_saturation_multiplier = char_I_saturation_multiplier * 0.01; 1376 float_saturation_multiplier = char_I_saturation_multiplier * 0.01;
1715 ////////////////////////////////////////////////////////////////////////////// 1695 //////////////////////////////////////////////////////////////////////////////
1716 // calc_nullzeit 1696 // calc_nullzeit
1717 // 1697 //
1718 // calculates the remaining bottom time 1698 // calculates the remaining bottom time
1719 // 1699 //
1720 // 2011-11-20 jDG: Changed (beta 2.06) to use Eric Baker's direct NDL formula. 1700 // NOTE: Erik Baker's closed formula works for Nitroxes. Trimix adds a second
1701 // exponential term to the M-value equation, making it impossible to
1702 // invert... So we have to make a fast-simu until we find a better way.
1721 // 1703 //
1722 // Input: pres_respiration 1704 // Input: pres_respiration
1723 // Output: char_O_nullzeit 1705 // Output: char_O_nullzeit
1724 // 1706 //
1725 static void calc_nullzeit(void) 1707 static void calc_nullzeit(void)
1726 { 1708 {
1727 overlay float Pin; 1709 //---- Compute ppN2 and ppHe ---------------------------------------------
1728
1729 temp_deco = pres_respiration; 1710 temp_deco = pres_respiration;
1730 sim_alveolar_presures(); 1711 sim_alveolar_presures();
1731 Pin = ppN2 + ppHe;
1732 1712
1733 char_O_nullzeit = 240; 1713 char_O_nullzeit = 240;
1734 for(ci=0; ci<NUM_COMP; ci++) 1714 for(ci=0; ci<NUM_COMP; ci++)
1735 { 1715 {
1736 //---- Compute composite A/B values and half times for the mix ------- 1716 //---- Read A/B values and loading factor for N2 and He --------------
1737 overlay float N2 = pres_tissue_N2[ci]; 1717 overlay float tN2 = pres_tissue_N2[ci];
1738 overlay float He = pres_tissue_He[ci]; 1718 overlay float tHe = pres_tissue_He[ci];
1739 overlay float p = N2 + He; 1719 overlay float t = tN2 + tHe;
1740 1720 overlay unsigned char ndl;
1741 read_buhlmann_ht(); 1721 overlay unsigned char period = 10;
1742 var_N2_ht = (var_N2_ht * N2 + var_He_ht * He) / p;
1743 1722
1744 read_buhlmann_coefficients(); 1723 read_buhlmann_coefficients();
1745 var_N2_a = (var_N2_a * N2 + var_He_a * He) / p; 1724 read_buhlmann_times(2); // Starts with a 10min period.
1746 var_N2_b = (var_N2_b * N2 + var_He_b * He) / p;
1747 1725
1748 //---- Calc time for that tissue ------------------------------------- 1726 //---- Simulate for that tissue --------------------------------------
1749 // Erik Baker's formula: 1727 // NOTE: No need to simulate for longuer than the already found NDL.
1750 // M0 (M-value at surface) = var_N2_a + pres_surface/var_N2_b 1728 for(ndl=0; ndl<char_O_nullzeit;)
1751 // Pin = respirated pressure ppN2 + ppHe 1729 {
1752 // p = pressure inside tissue 1730 //---- Compute updated mix M-value at surface
1753 // 0.6931 = log(2) 1731 overlay float a = (var_N2_a * tN2 + var_He_a * tHe) / t;
1754 // NDL(ci) = log((Pin - p)/(Pin - M0))/log(2) * ht 1732 overlay float b = (var_N2_b * tN2 + var_He_b * tHe) / t;
1755 // 1733 overlay float M0 = (a + pres_surface/b);
1756 if( Pin > p ) // Only when on-gasing 1734
1757 { 1735 //---- Add 10min/1min to N2/He tissues
1758 overlay float M0 = (var_N2_a + pres_surface/var_N2_b); 1736 overlay float dTN2 = (ppN2 - tN2) * var_N2_e;
1759 1737 overlay float dTHe = (ppHe - tHe) * var_He_e;
1760 // Apply security margin when using the GF model 1738
1761 if( char_I_deco_model != 0 ) 1739 //---- Apply security margin when using the non-GF model
1740 if( char_I_deco_model == 0 )
1741 {
1742 dTN2 *= float_saturation_multiplier;
1743 dTHe *= float_saturation_multiplier;
1744 }
1745 else // Or GF-based model
1762 M0 = GF_high * (M0 - pres_surface) + pres_surface; 1746 M0 = GF_high * (M0 - pres_surface) + pres_surface;
1763 1747
1764 if( Pin > M0 ) 1748 //---- Simulate off-gasing while going to surface
1749 // TODO !
1750 // dTN2 -= exp( ... ascent time ... ppN2...)
1751 // dTHe -= exp( ... ascent time ... ppHe...)
1752
1753 //---- Still ok to surface after 1 or 10 minutes ?
1754 if( t + dTN2 + dTHe <= M0 )
1765 { 1755 {
1766 overlay unsigned char indl; 1756 tN2 += dTN2; // YES: apply gas loadings,
1767 1757 tHe += dTHe;
1768 overlay float ndl = log((Pin - p)/(Pin - M0)) * var_N2_ht/0.6931; 1758 t = tN2 + tHe;
1769 1759 ndl += period; // increment NDL,
1770 // Apply non-GF model security margins: 1760 continue; // and loop.
1771 // Saturation factor will be applied to gas loading, accelerating
1772 // loading, hence we should decrease NDL accordingly.
1773 if( char_I_deco_model == 0)
1774 ndl /= float_saturation_multiplier;
1775
1776 if( ndl < 0.0f ) ndl = 0.0f;
1777 if( ndl > 254.5f ) ndl = 255.0f;
1778 indl = (unsigned char)(ndl + 0.5f);
1779 if( indl < char_O_nullzeit )
1780 char_O_nullzeit = indl;
1781 } 1761 }
1782 } 1762
1763 //---- Should we retry with smaller steps ?
1764 if( period == 10 )
1765 {
1766 read_buhlmann_times(1); // 1min coefs.
1767 period = 1;
1768 continue;
1769 }
1770
1771 //---- ELSE make a linear approx for the last minute
1772 // Usefull to have a meneaingfull rounding of NDL
1773 ndl += (unsigned char)(0.5f + (M0-t)/(dTN2+dTHe));
1774 break;
1775 }
1776
1777 // Keep the shortest NDL found
1778 if( ndl < char_O_nullzeit )
1779 char_O_nullzeit = ndl;
1783 } 1780 }
1784 } 1781 }
1785 1782
1786 ////////////////////////////////////////////////////////////////////////////// 1783 //////////////////////////////////////////////////////////////////////////////
1787 // calc_ascenttime 1784 // calc_ascenttime
2207 // Should be protected by deco_push_tissues_to_vault(), 2204 // Should be protected by deco_push_tissues_to_vault(),
2208 // deco_pull_tissues_from_vault() 2205 // deco_pull_tissues_from_vault()
2209 // 2206 //
2210 // desaturation slowed down to 70,42%. 2207 // desaturation slowed down to 70,42%.
2211 // 2208 //
2212 static void calc_dive_interval() 2209 static void calc_dive_interval(void)
2213 { 2210 {
2214 overlay unsigned char t; 2211 overlay unsigned char t;
2215 overlay unsigned char backup_model; 2212 overlay unsigned char backup_model;
2216 2213
2217 //---- Initialize simulation parameters ---------------------------------- 2214 //---- Initialize simulation parameters ----------------------------------
2225 // Make sure SURFACE_DESAT_FACTOR is applyed: 2222 // Make sure SURFACE_DESAT_FACTOR is applyed:
2226 backup_model = char_I_deco_model; 2223 backup_model = char_I_deco_model;
2227 char_I_deco_model = 0; 2224 char_I_deco_model = 0;
2228 2225
2229 //---- Perform simulation ------------------------------------------------ 2226 //---- Perform simulation ------------------------------------------------
2230
2231 for(t=0; t<char_I_dive_interval; ++t) 2227 for(t=0; t<char_I_dive_interval; ++t)
2232 { 2228 {
2233 calc_tissue(2); // period = 10min. 2229 calc_tissue(2); // period = 10min.
2234 CNS_fraction = 0.92587471 * CNS_fraction; // Half-time = 90min: (1/2)^(1/9) 2230 CNS_fraction = 0.92587471 * CNS_fraction; // Half-time = 90min: (1/2)^(1/9)
2235 } 2231 }
2410 } 2406 }
2411 2407
2412 ////////////////////////////////////////////////////////////////////////////// 2408 //////////////////////////////////////////////////////////////////////////////
2413 // deco_calc_CNS_planning 2409 // deco_calc_CNS_planning
2414 // 2410 //
2415 // Compute CNS during predicetd ascent. 2411 // Compute CNS during predicted ascent.
2416 // 2412 //
2417 // Note: Needs a call to deco_push_tissues_to_vault(), 2413 // Note: Needs a call to deco_push_tissues_to_vault(),
2418 // deco_pull_tissues_from_vault() to avoid trashing everything... 2414 // deco_pull_tissues_from_vault() to avoid trashing everything...
2419 // 2415 //
2420 // Input: CNS_fraction, char_O_deco_time[], char_O_deco_depth[] 2416 // Input: CNS_fraction, char_O_deco_time[], char_O_deco_depth[]
2598 volumes[gas] = 65535.0; 2594 volumes[gas] = 65535.0;
2599 2595
2600 //---- Ascent usage ------------------------------------------------------ 2596 //---- Ascent usage ------------------------------------------------------
2601 2597
2602 deepest_first = read_custom_function(54) == 0; 2598 deepest_first = read_custom_function(54) == 0;
2603 deco_usage = (float) read_custom_function(57); // In liter/minutes. 2599 deco_usage = (float) read_custom_function(57); // In liter/minutes.
2604 2600
2605 // Usage up to the first stop: 2601 // Usage up to the first stop:
2606 // - computed at MAX depth (easier, safer), 2602 // - computed at MAX depth (easier, safer),
2607 // - with an ascent speed of 10m/min. 2603 // - with an ascent speed of 10m/min.
2608 // - with ascent litter / minutes. 2604 // - with ascent litter / minutes.