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 |
