Mercurial > public > mk2
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. |