comparison code_part1/OSTC_code_c_part2/p2_deco.c @ 241:f44274d8440a

Model cleanups. + Fix look for current gas. + Minor optimize. + Fix needs to remember last switch gas depth, too. + Always take deepest gas. + Optimize by limiting search to 10m/min ascent. + FIX ascending 10m is 0.9985 bar. + FIX typos 9995 --> 9985
author JeanDo
date Mon, 21 Mar 2011 20:50:52 +0100
parents d995e220ddac
children ce869aad7440
comparison
equal deleted inserted replaced
240:d995e220ddac 241:f44274d8440a
126 static void calc_hauptroutine_data_input(void); 126 static void calc_hauptroutine_data_input(void);
127 static void calc_hauptroutine_update_tissues(void); 127 static void calc_hauptroutine_update_tissues(void);
128 static void calc_hauptroutine_calc_deco(void); 128 static void calc_hauptroutine_calc_deco(void);
129 static void sim_ascent_to_first_stop(void); 129 static void sim_ascent_to_first_stop(void);
130 130
131 static void deepest_gas_switch(void); 131 static unsigned char gas_switch_deepest(void);
132 static void best_gas_switch(void); 132 static void gas_switch_set(void);
133 static void set_gas(void); 133
134 134 static unsigned char calc_nextdecodepth(void);
135 static void calc_nextdecodepth(void);
136 135
137 //---- Bank 4 parameters ----------------------------------------------------- 136 //---- Bank 4 parameters -----------------------------------------------------
138 #pragma udata bank4=0x400 137 #pragma udata bank4=0x400
139 138
140 static float temp_limit; 139 static float temp_limit;
181 static float pres_diluent; // new in v.101 180 static float pres_diluent; // new in v.101
182 static float const_ppO2; // new in v.101 181 static float const_ppO2; // new in v.101
183 static float deco_ppO2_change; // new in v.101 182 static float deco_ppO2_change; // new in v.101
184 static float deco_ppO2; // new in v.101 183 static float deco_ppO2; // new in v.101
185 184
186 static unsigned char sim_gas_last_used; // Last used gas, to detected a gas switch. 185 static unsigned char sim_gas_last_depth; // Depth of last used gas, to detected a gas switch.
186 static unsigned char sim_gas_last_used; // Number of last used gas, to detected a gas switch.
187 static unsigned short sim_gas_delay; // Time of gas-switch-stop ends [min on dive]. 187 static unsigned short sim_gas_delay; // Time of gas-switch-stop ends [min on dive].
188 static unsigned short sim_dive_mins; // Simulated dive time. 188 static unsigned short sim_dive_mins; // Simulated dive time.
189 static float calc_N2_ratio; // Simulated (switched) nitrogen ratio. 189 static float calc_N2_ratio; // Simulated (switched) nitrogen ratio.
190 static float calc_He_ratio; // Simulated (switched) helium ratio. 190 static float calc_He_ratio; // Simulated (switched) helium ratio.
191 static float CNS_fraction; // new in v.101 191 static float CNS_fraction; // new in v.101
632 // GF_high 632 // GF_high
633 // GF_low 633 // GF_low
634 // char_I_depth_last_deco 634 // char_I_depth_last_deco
635 // float_deco_distance 635 // float_deco_distance
636 // 636 //
637 // RETURN TRUE iff a stop is needed.
638 //
637 // OUTPUT 639 // OUTPUT
638 // locked_GF_step 640 // locked_GF_step
639 // temp_depth_limt 641 // temp_depth_limt
640 // low_depth 642 // low_depth
641 // 643 //
642 static void calc_nextdecodepth(void) 644 static unsigned char calc_nextdecodepth(void)
643 { 645 {
646 //--- Max ascent speed ---------------------------------------------------
647 // Recompute leading gas limit, at current depth:
648 overlay float depth = (temp_deco - pres_surface) / 0.09985;
649
650 // At most, ascent 1 minute, at 10m/min == 10.0 m.
651 overlay float min_depth = depth - 10.0;
652
653 // Do we need to stop at current depth ?
654 overlay unsigned char need_stop = 0;
655
656 assert( depth >= -0.2 ); // Allow for 200mbar of weather change.
657 assert( low_depth < 255 );
658
644 //---- ZH-L16 + GRADIENT FACTOR model ------------------------------------ 659 //---- ZH-L16 + GRADIENT FACTOR model ------------------------------------
645 if (char_I_deco_model == 1) 660 if (char_I_deco_model == 1)
646 { 661 {
647 // Recompute leading gas limit, at current depth: 662 if( depth >= low_depth )
648 overlay float depth = (temp_deco - pres_surface) / 0.09995;
649 assert( depth >= -0.2 ); // Allow for 200mbar of weather change.
650 assert( low_depth < 255 );
651
652 if( depth > low_depth )
653 sim_limit( GF_low ); 663 sim_limit( GF_low );
654 else 664 else
655 sim_limit( GF_high - depth * locked_GF_step ); 665 sim_limit( GF_high - depth * locked_GF_step );
656 666
657 // Stops are needed ? 667 // Stops are needed ?
658 if( sim_lead_tissue_limit > pres_surface ) 668 if( sim_lead_tissue_limit > pres_surface )
659 { 669 {
660 // Deepest stop, in meter. 670 // Deepest stop, in meter (rounded up with a margin of 0.5m)
661 overlay unsigned char first_stop = 3 * (short)(0.99 + (sim_lead_tissue_limit - pres_surface) / 0.29985); 671 overlay unsigned char first_stop = 3 * (short)(0.83 + (sim_lead_tissue_limit - pres_surface) / 0.29955);
662 assert( first_stop < 128 ); 672 assert( first_stop < 128 );
663 673
664 // Apply correction for the shallowest stop. 674 // Apply correction for the shallowest stop.
665 if( first_stop == 3 ) // new in v104 675 if( first_stop == 3 ) // new in v104
666 first_stop = char_I_depth_last_deco; // Use last 3m..6m instead. 676 first_stop = char_I_depth_last_deco; // Use last 3m..6m instead.
668 // Check all stops until one is higher than tolerated presure 678 // Check all stops until one is higher than tolerated presure
669 while(first_stop > 0) 679 while(first_stop > 0)
670 { 680 {
671 overlay unsigned char next_stop; // Next index (0..30) 681 overlay unsigned char next_stop; // Next index (0..30)
672 overlay float pres_stop; // Next depth (0m..90m) 682 overlay float pres_stop; // Next depth (0m..90m)
683
684 // Check max speed, or reaching surface.
685 if( first_stop <= min_depth )
686 break;
687
688 // So, there is indeed a stop needed:
689 need_stop = 1;
673 690
674 if( first_stop <= char_I_depth_last_deco ) // new in v104 691 if( first_stop <= char_I_depth_last_deco ) // new in v104
675 next_stop = 0; 692 next_stop = 0;
676 else if( first_stop == 6 ) 693 else if( first_stop == 6 )
677 next_stop = char_I_depth_last_deco; 694 next_stop = char_I_depth_last_deco;
678 else 695 else
679 next_stop = first_stop - 3; // Index of next (upper) stop. 696 next_stop = first_stop - 3; // Index of next (upper) stop.
680 697
681 pres_stop = next_stop * 0.09995 // Meters to bar 698 pres_stop = next_stop * 0.09985 // Meters to bar
682 + pres_surface; 699 + pres_surface;
683 700
684 // Keep GF_low until a first stop depth is found: 701 // Keep GF_low until a first stop depth is found:
685 if( next_stop >= low_depth ) 702 if( next_stop >= low_depth )
686 sim_limit( GF_low ); 703 sim_limit( GF_low );
697 first_stop = next_stop; 714 first_stop = next_stop;
698 } 715 }
699 716
700 // Is it a new deepest first stop ? If yes this is the reference for 717 // Is it a new deepest first stop ? If yes this is the reference for
701 // the varying gradient factor. So reset that: 718 // the varying gradient factor. So reset that:
702 if( first_stop > low_depth ) 719 if( first_stop > min_depth && first_stop > low_depth )
703 { 720 {
704 // Store the deepest stop depth, as reference for GF_low. 721 // Store the deepest stop depth, as reference for GF_low.
705 low_depth = first_stop; 722 low_depth = first_stop;
706 locked_GF_step = GF_delta / low_depth; 723 locked_GF_step = GF_delta / low_depth;
707 } 724 }
724 sim_limit(1.0); 741 sim_limit(1.0);
725 742
726 pres_gradient = sim_lead_tissue_limit - pres_surface; 743 pres_gradient = sim_lead_tissue_limit - pres_surface;
727 if (pres_gradient >= 0) 744 if (pres_gradient >= 0)
728 { 745 {
729 pres_gradient /= 0.29985; // Bar --> stop number; 746 pres_gradient /= 0.29955; // Bar --> stop number;
730 temp_depth_limit = 3 * (short) (pres_gradient + 0.99); // --> meter : depth for deco 747 temp_depth_limit = 3 * (short) (pres_gradient + 0.99); // --> meter : depth for deco
731 if (temp_depth_limit != 0) // At surface ? 748 need_stop = 1; // Hit.
732 { 749
733 if (temp_depth_limit < char_I_depth_last_deco) // Implement last stop at 4m/5m/6m... 750 // Implement last stop at 4m/5m/6m...
734 temp_depth_limit = char_I_depth_last_deco; 751 if( temp_depth_limit == 3 )
735 } 752 temp_depth_limit = char_I_depth_last_deco;
736 } 753 }
737 else 754 else
738 temp_depth_limit = 0; // stop depth, in meter. 755 temp_depth_limit = 0;
739 } 756 }
740 757
741 //---- Check gas change -------------------------------------------------- 758 //---- Check gas change --------------------------------------------------
742 best_gas_switch(); // Update temp_depth_limit if there is a change, 759 need_stop |= gas_switch_deepest(); // Update temp_depth_limit if there is a change,
743 // Calculate N2_ratio and He_ratio too. 760
761 return need_stop;
744 } 762 }
745 763
746 ////////////////////////////////////////////////////////////////////////////// 764 //////////////////////////////////////////////////////////////////////////////
747 // copy_deco_table 765 // copy_deco_table
748 // 766 //
862 void deco_debug(void) 880 void deco_debug(void)
863 { 881 {
864 RESET_C_STACK 882 RESET_C_STACK
865 } 883 }
866 884
885
886 //////////////////////////////////////////////////////////////////////////////
887 // Find current gas in the list (if any).
888 //
889 // Input: char_I_deco_N2_ratio[] and He, to detect breathed gas.
890 //
891 // Output: sim_gas_depth_used
892 //
893 static void gas_switch_find_current(void)
894 {
895 if( sim_gas_last_used == 0 )
896 {
897 overlay unsigned char j;
898 overlay unsigned char N2 = (unsigned char)(N2_ratio * 100 + 0.5);
899 overlay unsigned char He = (unsigned char)(He_ratio * 100 + 0.5);
900 for(j=0; j<5; ++j)
901 {
902 // Make sure to detect if we are already breathing some gas in
903 // the current list (happends when first gas do have a depth).
904 if( N2 == char_I_deco_N2_ratio[j]
905 && He == char_I_deco_He_ratio[j] )
906 {
907 sim_gas_last_depth = char_I_deco_gas_change[j];
908 sim_gas_last_used = j+1;
909 break;
910 }
911 }
912 }
913 }
914
867 ////////////////////////////////////////////////////////////////////////////// 915 //////////////////////////////////////////////////////////////////////////////
868 // Find deepest available gas. 916 // Find deepest available gas.
869 // 917 //
870 // Input: deco_gas_change[] 918 // Input: temp_depth_limit,
871 // sim_gas_delay, sim_gas_last_used, sim_dive_mins. 919 // deco_gas_change[]
872 // 920 // sim_gas_delay, sim_gas_depth_used, sim_dive_mins.
873 // Output: temp_depth_limit, sim_gas_delay, sim_gas_last_used IFF the is a switch. 921 //
874 // 922 // RETURNS TRUE if a stop is needed for gas switch.
875 static void deepest_gas_switch(void) 923 //
876 { 924 // Output: temp_depth_limit, sim_gas_delay, sim_gas_depth_used IFF the is a switch.
877 overlay unsigned char temp_gas_switch = 0; 925 //
878 overlay unsigned char switch_deco = 0; 926 // NOTE: might be called from bottom (when sim_gas_delay and sim_gas_depth_used
927 // are null), or during the ascent to make sure we are not passing a
928 // stop (in which case both can be already set).
929 //
930 static unsigned char gas_switch_deepest(void)
931 {
932 overlay unsigned char switch_deco = 0, switch_last = 0;
879 933
880 if (char_I_const_ppO2 == 0) 934 if (char_I_const_ppO2 == 0)
881 { 935 {
882 overlay unsigned char j; 936 overlay unsigned char j;
883 937
884 // Loop over all enabled gas, to find the deepest enabled one above us. 938 // Loop over all enabled gas, to find the deepest one,
885 for(temp_gas_switch=j=0; j<5; ++j) 939 // above las gas, but below temp_depth_limit.
886 { 940 for(j=0; j<5; ++j)
887 if( temp_depth_limit <= deco_gas_change[j] ) 941 {
888 if( (temp_gas_switch == 0) || (switch_deco < deco_gas_change[j]) ) 942 // Gas not (yet) allowed ? Skip !
889 { 943 if( temp_depth_limit > deco_gas_change[j] )
890 temp_gas_switch = j+1; 944 continue;
891 switch_deco = deco_gas_change[j]; 945
892 } 946 // Gas deeper than the current/previous one ? Skip !
947 if( sim_gas_last_depth && deco_gas_change[j] >= sim_gas_last_depth )
948 continue;
949
950 // First, or deeper ?
951 if( (switch_last == 0) || (switch_deco < deco_gas_change[j]) )
952 {
953 switch_deco = deco_gas_change[j];
954 switch_last = j+1;
955 }
893 } 956 }
894 } 957 }
895 958
896 // If there is a better gas available 959 // If there is a better gas available
897 if( temp_gas_switch ) 960 if( switch_deco )
898 { 961 {
962 assert( !sim_gas_last_depth || sim_gas_last_depth > switch_deco );
963
899 // Should restart gas-switch delay only when gas do changes... 964 // Should restart gas-switch delay only when gas do changes...
900 // sim_gas_last_used: used to detect just once in each ascent simu. 965 assert( sim_gas_delay <= sim_dive_mins );
901 // N2_ratio : used to detect when already breathing that gas. 966
902 if( temp_depth_limit != switch_deco 967 sim_gas_last_depth = switch_deco;
903 && sim_gas_last_used != temp_gas_switch 968 sim_gas_last_used = switch_last;
904 && sim_gas_delay <= sim_dive_mins ) 969 sim_gas_delay = read_custom_function(55);
905 { 970
906 sim_gas_last_used = temp_gas_switch; 971 // Apply depth correction ONLY if CF#55 is not null:
907 sim_gas_delay = read_custom_function(55); 972 if( sim_gas_delay > 0 )
908 973 {
909 // Apply depth correction ONLY if CF#55 is not null: 974 sim_gas_delay += sim_dive_mins;
910 if( sim_gas_delay > 0 ) 975 temp_depth_limit = switch_deco;
911 { 976 return 1;
912 sim_gas_delay += sim_dive_mins; 977 }
913 temp_depth_limit = switch_deco; 978
914 } 979 return 0;
915 }
916 } 980 }
917 else 981
918 sim_gas_delay = 0; 982 sim_gas_delay = 0;
919 } 983 return 0;
920
921 //////////////////////////////////////////////////////////////////////////////
922 // Find best (shallowest) available gas.
923 //
924 // Input: deco_gas_change*
925 // sim_gas_delay, sim_gas_last_used, sim_dive_mins.
926 //
927 // Output: temp_depth_limit, sim_gas_delay, sim_gas_last_used IFF the is a switch.
928 //
929 static void best_gas_switch(void)
930 {
931 overlay unsigned char temp_gas_switch = 0;
932 overlay unsigned char switch_deco = 0;
933
934 if (char_I_const_ppO2 == 0)
935 {
936 overlay unsigned char j;
937
938 // Loop over all enabled gas, to find the shallowest enabled one above us.
939 for(temp_gas_switch=j=0; j<5; ++j)
940 {
941 if( temp_depth_limit <= deco_gas_change[j] )
942 if( (temp_gas_switch == 0) || (switch_deco > deco_gas_change[j]) )
943 {
944 temp_gas_switch = j+1;
945 switch_deco = deco_gas_change[j];
946 }
947 }
948 }
949
950 // If there is a better gas available
951 if( temp_gas_switch )
952 {
953 // Should restart gas-switch delay only when gas do changes...
954 // sim_gas_last_used: used to detect just once in each ascent simu.
955 // N2_ratio : used to detect when already breathing that gas.
956 if( sim_gas_last_used != temp_gas_switch
957 && sim_gas_delay <= sim_dive_mins )
958 {
959 sim_gas_last_used = temp_gas_switch;
960 sim_gas_delay = read_custom_function(55);
961
962 // Apply depth correction ONLY if CF#55 is not null:
963 if( sim_gas_delay > 0 )
964 {
965 sim_gas_delay += sim_dive_mins;
966 temp_depth_limit = switch_deco;
967 }
968 }
969 }
970 else
971 sim_gas_delay = 0;
972 } 984 }
973 985
974 ////////////////////////////////////////////////////////////////////////////// 986 //////////////////////////////////////////////////////////////////////////////
975 // Calculate gas switches 987 // Calculate gas switches
976 // 988 //
978 // Input: N2_ratio, He_ratio. 990 // Input: N2_ratio, He_ratio.
979 // sim_gas_last_used 991 // sim_gas_last_used
980 // 992 //
981 // Output: calc_N2_ratio, calc_He_ratio 993 // Output: calc_N2_ratio, calc_He_ratio
982 // 994 //
983 static void set_gas(void) 995 static void gas_switch_set(void)
984 { 996 {
985 assert( 0 <= sim_gas_last_used && sim_gas_last_used <= 5 ); 997 assert( 0 <= sim_gas_last_used && sim_gas_last_used <= 5 );
986 998
987 if( sim_gas_last_used == 0 ) 999 if( sim_gas_last_used == 0 )
988 { 1000 {
1106 // | +------< not finished 1118 // | +------< not finished
1107 // +--------< finish 1119 // +--------< finish
1108 // 1120 //
1109 static void calc_hauptroutine(void) 1121 static void calc_hauptroutine(void)
1110 { 1122 {
1111 static unsigned char backup_gas_used = 0; 1123 static unsigned char backup_gas_used = 0;
1124 static unsigned char backup_gas_depth = 0;
1112 static unsigned char backup_gas_delay = 0; 1125 static unsigned char backup_gas_delay = 0;
1113 1126
1114 calc_hauptroutine_data_input(); 1127 calc_hauptroutine_data_input();
1115 1128
1116 if(!flag_in_divemode) 1129 if(!flag_in_divemode)
1140 // This is used to record the lowest stop for the whole dive, 1153 // This is used to record the lowest stop for the whole dive,
1141 // Including ACCROSS all simulated ascent. 1154 // Including ACCROSS all simulated ascent.
1142 low_depth = 0; 1155 low_depth = 0;
1143 1156
1144 // Reset gas switch history. 1157 // Reset gas switch history.
1145 backup_gas_used = sim_gas_last_used = 0; 1158 backup_gas_used = sim_gas_last_used = 0;
1159 backup_gas_depth = sim_gas_last_depth = 0;
1146 backup_gas_delay = sim_gas_delay = 0; 1160 backup_gas_delay = sim_gas_delay = 0;
1147 sim_dive_mins = 0; 1161 sim_dive_mins = 0;
1148 break; 1162 break;
1149 1163
1150 case 0: //---- bottom time ----------------------------------------------- 1164 case 0: //---- bottom time -----------------------------------------------
1153 char_O_deco_status = 2; // calc ascent next time. 1167 char_O_deco_status = 2; // calc ascent next time.
1154 break; 1168 break;
1155 1169
1156 case 2: //---- Simulate ascent to first stop ----------------------------- 1170 case 2: //---- Simulate ascent to first stop -----------------------------
1157 // Check proposed gas at begin of ascent simulation 1171 // Check proposed gas at begin of ascent simulation
1172 gas_switch_find_current();
1173 gas_switch_set();
1174
1158 sim_dive_mins = int_I_divemins; // and time. 1175 sim_dive_mins = int_I_divemins; // and time.
1159 temp_depth_limit = (int)(0.95 + (pres_respiration - pres_surface) / 0.09985) ; // Starts from current real depth. 1176 backup_gas_used = sim_gas_last_used; // And save for later simu steps.
1160 best_gas_switch(); 1177 backup_gas_depth = sim_gas_last_depth;// And save for later simu steps.
1161 set_gas();
1162
1163 backup_gas_used = sim_gas_last_used;// And save for later simu steps.
1164 backup_gas_delay = sim_gas_delay; 1178 backup_gas_delay = sim_gas_delay;
1165 1179
1166 sim_ascent_to_first_stop(); 1180 sim_ascent_to_first_stop();
1167 1181
1168 char_O_deco_status = 1; // Calc stops next time (deco or gas switch). 1182 char_O_deco_status = 1; // Calc stops next time (deco or gas switch).
1173 1187
1174 // If simulation is finished, restore the GF low reference, so that 1188 // If simulation is finished, restore the GF low reference, so that
1175 // next ascent simulation is done from the current depth: 1189 // next ascent simulation is done from the current depth:
1176 if( char_O_deco_status == 0 ) 1190 if( char_O_deco_status == 0 )
1177 { 1191 {
1178 sim_gas_last_used = backup_gas_used; 1192 sim_gas_last_used = backup_gas_used;
1193 sim_gas_last_depth = backup_gas_depth;
1179 sim_gas_delay = backup_gas_delay; 1194 sim_gas_delay = backup_gas_delay;
1180 } 1195 }
1181 break; 1196 break;
1182 } 1197 }
1183 1198
1315 { 1330 {
1316 overlay unsigned char loop; 1331 overlay unsigned char loop;
1317 1332
1318 for(loop = 0; loop < 16; ++loop) 1333 for(loop = 0; loop < 16; ++loop)
1319 { 1334 {
1320 overlay float new_presure; 1335 // Do not ascent while doing a gas switch ?
1321 overlay unsigned char backup_gas_last_used;
1322
1323 // Do not ascent while doing a gas switch.
1324 if( sim_gas_delay <= sim_dive_mins ) 1336 if( sim_gas_delay <= sim_dive_mins )
1325 { 1337 {
1326 backup_gas_last_used = sim_gas_last_used; 1338 if( calc_nextdecodepth() )
1327 calc_nextdecodepth(); 1339 {
1328 1340 if( temp_depth_limit == 0 )
1329 //---- Finish computations once surface is reached --------------- 1341 goto Surface;
1330 if( temp_depth_limit == 0 ) 1342
1331 { 1343 //---- We hit a stop at temp_depth_limit ---------------------
1332 copy_deco_table(); 1344 temp_deco = temp_depth_limit * 0.09985 // Convert to relative bar,
1333 calc_ascenttime(); 1345 + pres_surface; // To absolute.
1334 char_O_deco_status = 0; // calc nullzeit next time. 1346 update_deco_table(); // Adds a one minute stops.
1335 return; 1347 }
1336 } 1348 else
1337 } 1349 {
1338 1350 //---- No stop -----------------------------------------------
1339 //---- Can we ascent to that stop at once, or is it just ascenting ? 1351 temp_deco -= 0.9985; // Ascend 10m, no wait.
1340 new_presure = temp_depth_limit * 0.09985 // Convert to relative bar, 1352
1341 + pres_surface; // To absolute, 1353 //---- Finish computations once surface is reached -----------
1342 1354 if( temp_deco <= pres_surface )
1343 if( (temp_deco - new_presure) > 1.0 ) // More than 10m/mn ? 1355 {
1344 { 1356 Surface:
1345 temp_deco -= 1.0; // Just keep ascending. 1357 copy_deco_table();
1346 sim_gas_delay = 0; // Reset gas delay, 1358 calc_ascenttime();
1347 sim_gas_last_used = backup_gas_last_used; // and usage history. 1359 char_O_deco_status = 0; // calc nullzeit next time.
1360 return;
1361 }
1362 }
1363
1348 } 1364 }
1349 else 1365 else
1350 { 1366 update_deco_table(); // Just pass one minute.
1351 temp_deco = new_presure; 1367
1352 update_deco_table(); // This is a one minute stops. 1368 //---- Then update tissue --------------------------------------------
1353 }
1354
1355 //---- Then update tissue and decoplan -------------------------------
1356 sim_dive_mins++; // Advance simulated time by 1 minute. 1369 sim_dive_mins++; // Advance simulated time by 1 minute.
1357 set_gas(); // Apply any simulated gas change, once validated. 1370 gas_switch_set(); // Apply any simulated gas change, once validated.
1358 sim_alveolar_presures(); // Updates ppN2 and ppHe. 1371 sim_alveolar_presures(); // Updates ppN2 and ppHe.
1359 sim_tissue(1); // Simulate compartiments for 1 minute. 1372 sim_tissue(1); // Simulate compartiments for 1 minute.
1360 } 1373 }
1361 1374
1362 // Surface not reached, need more stops... 1375 // Surface not reached, need more stops...
1379 1392
1380 // Do we have a gas switch going on ? 1393 // Do we have a gas switch going on ?
1381 if( sim_gas_delay > sim_dive_mins ) 1394 if( sim_gas_delay > sim_dive_mins )
1382 return; 1395 return;
1383 1396
1384 // Loop until first stop, gas switch, or surface is reached. 1397 //---- Loop until first stop, gas switch, or surface is reached ----------
1385 for(;;) 1398 for(;;)
1386 { 1399 {
1387 // No: try ascending 1 full minute. 1400 // Try ascending 1 full minute.
1388 temp_deco -= 1.0; // Ascent 1 min, at 10m/min. == 1bar/min. 1401 temp_deco -= 0.9985; // 1 min, at 10m/min. ~ 1bar.
1389 1402
1390 // Compute sim_lead_tissue_limit at GF_low (deepest stop). 1403 // Compute sim_lead_tissue_limit at GF_low (deepest stop).
1391 sim_limit(GF_low); 1404 sim_limit(GF_low);
1392 1405
1393 // Did we reach deepest remaining stop ? 1406 // Did we reach deepest remaining stop ?
1394 if( temp_deco <= sim_lead_tissue_limit ) 1407 if( temp_deco < sim_lead_tissue_limit )
1395 { 1408 {
1396 temp_deco += 1.0; // Restore last correct depth. 1409 temp_deco += 0.9985; // Restore last correct depth,
1397 break; // Return stop found ! 1410 break; // End fast ascent.
1398 } 1411 }
1399 1412
1400 // Did we reach surface ? 1413 // Did we reach surface ?
1401 if( temp_deco <= pres_surface ) 1414 if( temp_deco <= pres_surface )
1402 { 1415 {
1403 temp_deco = pres_surface; // Yes: finished ! 1416 temp_deco = pres_surface; // Yes: finished !
1404 break; 1417 break;
1405 } 1418 }
1406 1419
1407 // Check gas change 5 meter below new depth. 1420 // Check for gas change below new depth ?
1408 temp_depth_limit = (temp_deco + 0.5 - pres_surface) / 0.09985; 1421 temp_depth_limit = (temp_deco - pres_surface) / 0.09985;
1409 deepest_gas_switch(); 1422
1410 if( sim_gas_delay > sim_dive_mins ) 1423 if( gas_switch_deepest() )
1424 {
1425 temp_deco = temp_depth_limit * 0.09985 + pres_surface;
1411 break; 1426 break;
1427 }
1412 1428
1413 sim_dive_mins++; // Advance simulated time by 1 minute. 1429 sim_dive_mins++; // Advance simulated time by 1 minute.
1414 sim_alveolar_presures(); // Still uses temp_deco. 1430 sim_alveolar_presures(); // temp_deco --> ppN2/ppHe
1415 sim_tissue(1); // and update tissues for 1 min. 1431 sim_tissue(1); // and update tissues for 1 min.
1416 } 1432 }
1417 } 1433 }
1418 1434
1419 ////////////////////////////////////////////////////////////////////////////// 1435 //////////////////////////////////////////////////////////////////////////////
1586 // Start ascent simulation with current tissue partial pressures. 1602 // Start ascent simulation with current tissue partial pressures.
1587 for (x = 0;x<16;x++) 1603 for (x = 0;x<16;x++)
1588 { 1604 {
1589 sim_pres_tissue[x] = pres_tissue[x]; 1605 sim_pres_tissue[x] = pres_tissue[x];
1590 (sim_pres_tissue+16)[x] = (pres_tissue+16)[x]; 1606 (sim_pres_tissue+16)[x] = (pres_tissue+16)[x];
1591 sim_pres_tissue_limit[x] = pres_tissue_limit[x];
1592 } 1607 }
1593 1608
1594 // No leading tissue (yet) for this ascent simulation. 1609 // No leading tissue (yet) for this ascent simulation.
1595 sim_lead_tissue_limit = 0.0; 1610 sim_lead_tissue_limit = 0.0;
1596 sim_lead_tissue_no = 255; 1611 sim_lead_tissue_no = 255;
1640 sim_lead_tissue_limit = 0.0; 1655 sim_lead_tissue_limit = 0.0;
1641 sim_lead_tissue_no = 0; // If no one is critic, keep first tissue. 1656 sim_lead_tissue_no = 0; // If no one is critic, keep first tissue.
1642 1657
1643 for(ci=0; ci<16; ci++) 1658 for(ci=0; ci<16; ci++)
1644 { 1659 {
1645 overlay float p = sim_pres_tissue[ci] + (sim_pres_tissue+16)[ci]; 1660 overlay float N2 = sim_pres_tissue[ci];
1661 overlay float He = (sim_pres_tissue+16)[ci];
1662 overlay float p = N2 + He;
1646 1663
1647 read_buhlmann_coefficients(-1); 1664 read_buhlmann_coefficients(-1);
1648 var_N2_a = (var_N2_a * sim_pres_tissue[ci] + var_He_a * (sim_pres_tissue+16)[ci]) / p; 1665 var_N2_a = (var_N2_a * N2 + var_He_a * He) / p;
1649 var_N2_b = (var_N2_b * sim_pres_tissue[ci] + var_He_b * (sim_pres_tissue+16)[ci]) / p; 1666 var_N2_b = (var_N2_b * N2 + var_He_b * He) / p;
1650 1667
1651 // Apply the Eric Baker's varying gradient factor correction. 1668 // Apply the Eric Baker's varying gradient factor correction.
1652 // Note: the correction factor depends both on GF and b, 1669 // Note: the correction factor depends both on GF and b,
1653 // Actual values are in the 1.5 .. 1.0 range (for a GF=30%), 1670 // Actual values are in the 1.5 .. 1.0 range (for a GF=30%),
1654 // so that can change who is the leading gas... 1671 // so that can change who is the leading gas...
1658 / (GF_current + var_N2_b * (1.0 - GF_current)); 1675 / (GF_current + var_N2_b * (1.0 - GF_current));
1659 else 1676 else
1660 p = (p - var_N2_a) * var_N2_b; 1677 p = (p - var_N2_a) * var_N2_b;
1661 if( p < 0.0 ) p = 0.0; 1678 if( p < 0.0 ) p = 0.0;
1662 1679
1680 assert( 0.0 <= p && p <= 14.0 );
1681
1663 sim_pres_tissue_limit[ci] = p; 1682 sim_pres_tissue_limit[ci] = p;
1664 if( p > sim_lead_tissue_limit ) 1683 if( p > sim_lead_tissue_limit )
1665 { 1684 {
1666 sim_lead_tissue_no = ci; 1685 sim_lead_tissue_no = ci;
1667 sim_lead_tissue_limit = p; 1686 sim_lead_tissue_limit = p;
1769 1788
1770 if( low_depth == 0 ) 1789 if( low_depth == 0 )
1771 rgf = GF_high; 1790 rgf = GF_high;
1772 else 1791 else
1773 { 1792 {
1774 overlay float temp1 = low_depth * 0.09995; 1793 overlay float temp1 = low_depth * 0.09985;
1775 overlay float temp2 = pres_respiration - pres_surface; 1794 overlay float temp2 = pres_respiration - pres_surface;
1776 1795
1777 if (temp2 <= 0) 1796 if (temp2 <= 0)
1778 rgf = GF_high; 1797 rgf = GF_high;
1779 else if (temp2 >= temp1) 1798 else if (temp2 >= temp1)
2168 void deco_gas_volumes(void) 2187 void deco_gas_volumes(void)
2169 { 2188 {
2170 overlay float volumes[5]; 2189 overlay float volumes[5];
2171 overlay float ascent_usage; 2190 overlay float ascent_usage;
2172 overlay unsigned char i, deepest_first; 2191 overlay unsigned char i, deepest_first;
2192 overlay unsigned char gas;
2173 RESET_C_STACK 2193 RESET_C_STACK
2174 2194
2175 //---- initialize with bottom consumption -------------------------------- 2195 //---- initialize with bottom consumption --------------------------------
2176 for(i=0; i<5; ++i) // Nothing yet... 2196 for(i=0; i<5; ++i) // Nothing yet...
2177 volumes[i] = 0.0; 2197 volumes[i] = 0.0;
2178 2198
2179 assert( 1 <= char_I_first_gas && char_I_first_gas <= 5); 2199 assert(1 <= char_I_first_gas && char_I_first_gas <= 5);
2180 volumes[char_I_first_gas - 1] 2200 gas = char_I_first_gas - 1;
2201
2202 volumes[gas]
2181 = (char_I_bottom_depth*0.1 + 1.0) // Use Psurface = 1.0 bar. 2203 = (char_I_bottom_depth*0.1 + 1.0) // Use Psurface = 1.0 bar.
2182 * char_I_bottom_time // in minutes. 2204 * char_I_bottom_time // in minutes.
2183 * read_custom_function(56) // In deci-liter/minutes. 2205 * read_custom_function(56) // In deci-liter/minutes.
2184 * 0.1; // deci-liters --> liters. 2206 * 0.1; // deci-liters --> liters.
2185 2207
2191 // Usage up to the first stop: 2213 // Usage up to the first stop:
2192 // - computed at MAX depth (easier, safer), 2214 // - computed at MAX depth (easier, safer),
2193 // - with an ascent speed of 10m/min. 2215 // - with an ascent speed of 10m/min.
2194 // - with ascent litter / minutes. 2216 // - with ascent litter / minutes.
2195 // - still using bottom gas: 2217 // - still using bottom gas:
2196 volumes[char_I_first_gas - 1] 2218 volumes[gas]
2197 += (char_I_bottom_depth*0.1 + 1.0) // Depth -> bar 2219 += (char_I_bottom_depth*0.1 + 1.0) // Depth -> bar
2198 * (char_I_bottom_depth - char_O_first_deco_depth) * 0.1 // ascent time (min) 2220 * (char_I_bottom_depth - char_O_first_deco_depth) * 0.1 // ascent time (min)
2199 * ascent_usage; // Consumption ( xxx / min @ 1 bar) 2221 * ascent_usage; // Consumption ( xxx / min @ 1 bar)
2200 2222
2201 for(i=0; i<32; ++i) 2223 for(i=0; i<32; ++i)
2202 { 2224 {
2203 overlay unsigned char j, gas; 2225 overlay unsigned char j;
2204 overlay unsigned char depth, time, ascent; 2226 overlay unsigned char depth, time, ascent;
2205 2227
2206 // Manage stops in reverse order (CF#54) 2228 // Manage stops in reverse order (CF#54)
2207 if( deepest_first ) 2229 if( deepest_first )
2208 { 2230 {
2209 time = char_O_deco_time[i]; 2231 time = char_O_deco_time[i];
2210 if( time == 0 ) break; // End of table: done. 2232 if( time == 0 ) break; // End of table: done.
2211 2233
2212 ascent = depth = char_O_deco_depth[i]; 2234 ascent = depth = char_O_deco_depth[i];
2213 if( i < 31 ) 2235 if( i < 31 )
2214 ascent -= char_O_deco_depth[i+1]; 2236 ascent -= char_O_deco_depth[i+1];
2222 if( i < 31 ) 2244 if( i < 31 )
2223 ascent -= char_O_deco_depth[30-i]; 2245 ascent -= char_O_deco_depth[30-i];
2224 } 2246 }
2225 2247
2226 // Gas switch depth ? 2248 // Gas switch depth ?
2227 for(gas=j=0; j<5; ++j) 2249 for(j=0; j<5; ++j)
2228 { 2250 {
2229 if( depth <= char_I_deco_gas_change[j] ) 2251 if( depth <= char_I_deco_gas_change[j] )
2230 if( (gas == 0) || (char_I_deco_gas_change[gas] > char_I_deco_gas_change[j]) ) 2252 if( !char_I_deco_gas_change[gas] || (char_I_deco_gas_change[gas] > char_I_deco_gas_change[j]) )
2231 gas = j; 2253 gas = j;
2232 } 2254 }
2233 2255
2234 // usage during stop: 2256 // usage during stop:
2235 // Note: because first gas is not in there, increment gas+1 2257 // Note: because first gas is not in there, increment gas+1