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