comparison code_part1/OSTC_code_c_part2/p2_deco.c @ 212:275befc5f39d

Debug GF model (bug #11 & #12). + ASSERT stops should be computed in order (bug#11). + BUGFIX: Mark GF_low reference at actual first stop, not predicted one. + BUGFIX: sim_to_first_stop() stops BEFORE first stop, not after (bug#11). + BUGFIX: check that calc_nextdecodepth() don't ascent faster than 10m/mn (bug#11). + BUGFIX: calc_nextdecodepth() should check gas switch, too (bug#11). + let gas switch detection in depth/meter (not ambientPresure/mbar). + BUGFIX OCR mode: bad diluent value in sim_alveolar_pressure() (bug#11). + BUGFIX: add deco distance (offset) only to compartiment integration, not to B?hlmann or GF criterion. + BUGFIX: add margin one meter above gas switch depth (bug#12) + BUGFIX: When ascenting too fast, cancel gas switch delay and history (bug#11).
author JeanDo
date Mon, 21 Feb 2011 22:36:48 +0100
parents 2d9af08ed0ac
children c7e32ff65636
comparison
equal deleted inserted replaced
211:d0903d4ab588 212:275befc5f39d
125 static void calc_hauptroutine_data_input(void); 125 static void calc_hauptroutine_data_input(void);
126 static void calc_hauptroutine_update_tissues(void); 126 static void calc_hauptroutine_update_tissues(void);
127 static void calc_hauptroutine_calc_deco(void); 127 static void calc_hauptroutine_calc_deco(void);
128 static void sim_ascent_to_first_stop(void); 128 static void sim_ascent_to_first_stop(void);
129 129
130 static void check_gas_switch(void);
130 static void calc_nextdecodepth(void); 131 static void calc_nextdecodepth(void);
131 132
132 //---- Bank 4 parameters ----------------------------------------------------- 133 //---- Bank 4 parameters -----------------------------------------------------
133 #pragma udata bank4=0x400 134 #pragma udata bank4=0x400
134 135
172 static float var_He_b; // Bühlmann b, for current He tissue. 173 static float var_He_b; // Bühlmann b, for current He tissue.
173 static float var_N2_e; // Exposition, for current N2 tissue. 174 static float var_N2_e; // Exposition, for current N2 tissue.
174 static float var_He_e; // Exposition, for current He tissue. 175 static float var_He_e; // Exposition, for current He tissue.
175 176
176 static float pres_diluent; // new in v.101 177 static float pres_diluent; // new in v.101
177 static float deco_diluent; // new in v.101
178 static float const_ppO2; // new in v.101 178 static float const_ppO2; // new in v.101
179 static float deco_ppO2_change; // new in v.101 179 static float deco_ppO2_change; // new in v.101
180 static float deco_ppO2; // new in v.101 180 static float deco_ppO2; // new in v.101
181 181
182 static unsigned char sim_gas_last_used; // Last used gas, to detected a gas switch. 182 static unsigned char sim_gas_last_used; // Last used gas, to detected a gas switch.
188 static float float_saturation_multiplier; // new in v.101 188 static float float_saturation_multiplier; // new in v.101
189 static float float_desaturation_multiplier; // new in v.101 189 static float float_desaturation_multiplier; // new in v.101
190 static float float_deco_distance; // new in v.101 190 static float float_deco_distance; // new in v.101
191 static char flag_in_divemode; // new in v.108 191 static char flag_in_divemode; // new in v.108
192 192
193 static float deco_gas_change1; // new in v.101 193 static unsigned char deco_gas_change1; // new in v.101
194 static float deco_gas_change2; // new in v.109 194 static unsigned char deco_gas_change2; // new in v.109
195 static float deco_gas_change3; // new in v.109 195 static unsigned char deco_gas_change3; // new in v.109
196 static float deco_gas_change4; // new in v.109 196 static unsigned char deco_gas_change4; // new in v.109
197 static float deco_gas_change5; // new in v.109 197 static unsigned char deco_gas_change5; // new in v.109
198 198
199 static float deco_N2_ratio1; // new in v.101 199 static float deco_N2_ratio1; // new in v.101
200 static float deco_He_ratio1; // new in v.101 200 static float deco_He_ratio1; // new in v.101
201 201
202 202
225 static char md_state[48]; // DONT MOVE !! // has to be at the beginning of bank 9 for the asm code!!! 225 static char md_state[48]; // DONT MOVE !! // has to be at the beginning of bank 9 for the asm code!!!
226 226
227 // internal, dbg: 227 // internal, dbg:
228 static unsigned char DBG_char_I_deco_model; // new in v.108. 228 static unsigned char DBG_char_I_deco_model; // new in v.108.
229 static unsigned char DBG_char_I_depth_last_deco; // new in v.108 229 static unsigned char DBG_char_I_depth_last_deco; // new in v.108
230 static unsigned char DBG_deco_gas_change; // new in v.108
230 static float DBG_pres_surface; // new in v.108 231 static float DBG_pres_surface; // new in v.108
231 static float DBG_GF_low; // new in v.108 232 static float DBG_GF_low; // new in v.108
232 static float DBG_GF_high; // new in v.108 233 static float DBG_GF_high; // new in v.108
233 static float DBG_const_ppO2; // new in v.108 234 static float DBG_const_ppO2; // new in v.108
234 static float DBG_deco_ppO2_change; // new in v.108 235 static float DBG_deco_ppO2_change; // new in v.108
235 static float DBG_deco_ppO2; // new in v.108 236 static float DBG_deco_ppO2; // new in v.108
236 static float DBG_deco_N2_ratio; // new in v.108 237 static float DBG_deco_N2_ratio; // new in v.108
237 static float DBG_deco_He_ratio; // new in v.108 238 static float DBG_deco_He_ratio; // new in v.108
238 static float DBG_deco_gas_change; // new in v.108
239 static float DBG_float_saturation_multiplier; // new in v.108 239 static float DBG_float_saturation_multiplier; // new in v.108
240 static float DBG_float_desaturation_multiplier; // new in v.108 240 static float DBG_float_desaturation_multiplier; // new in v.108
241 static float DBG_float_deco_distance; // new in v.108 241 static float DBG_float_deco_distance; // new in v.108
242 static float DBG_deco_N2_ratio; // new in v.108 242 static float DBG_deco_N2_ratio; // new in v.108
243 static float DBG_deco_He_ratio; // new in v.108 243 static float DBG_deco_He_ratio; // new in v.108
596 // char_I_depth_last_deco 596 // char_I_depth_last_deco
597 // float_deco_distance 597 // float_deco_distance
598 // 598 //
599 // OUTPUT 599 // OUTPUT
600 // locked_GF_step 600 // locked_GF_step
601 // temp_deco
602 // temp_depth_limt 601 // temp_depth_limt
603 // low_depth 602 // low_depth
604 // 603 //
605 static void calc_nextdecodepth(void) 604 static void calc_nextdecodepth(void)
606 { 605 {
607 //---- ZH-L16 + GRADIENT FACTOR model ------------------------------------ 606 //---- ZH-L16 + GRADIENT FACTOR model ------------------------------------
608 if (char_I_deco_model == 1) 607 if (char_I_deco_model == 1)
609 { 608 {
610 // Recompute leading gas limit, at current depth: 609 // Recompute leading gas limit, at current depth:
611 overlay float depth = (temp_deco - pres_surface) / 0.09995; 610 overlay float depth = (temp_deco - pres_surface) / 0.09995;
612 assert( depth >= 0.0 ); 611 assert( depth >= 0.0 );
622 { 621 {
623 // Deepest stop, in meter. 622 // Deepest stop, in meter.
624 overlay unsigned char first_stop = 3 * (short)(0.99 + (sim_lead_tissue_limit - pres_surface) / 0.29985); 623 overlay unsigned char first_stop = 3 * (short)(0.99 + (sim_lead_tissue_limit - pres_surface) / 0.29985);
625 assert( first_stop < 128 ); 624 assert( first_stop < 128 );
626 625
627 // Apply correction for the first stop. 626 // Apply correction for the shallowest stop.
628 if( first_stop == 3 ) // new in v104 627 if( first_stop == 3 ) // new in v104
629 first_stop = char_I_depth_last_deco; // Use last 3m..6m instead. 628 first_stop = char_I_depth_last_deco; // Use last 3m..6m instead.
629
630 // Check all stops until one is higher than tolerated presure
631 while(first_stop > 0)
632 {
633 overlay unsigned char next_stop; // Next index (0..30)
634 overlay float pres_stop; // Next depth (0m..90m)
635
636 if( first_stop <= char_I_depth_last_deco ) // new in v104
637 next_stop = 0;
638 else
639 next_stop = first_stop - 3; // Index of next (upper) stop.
640 if( first_stop == 3 )
641 first_stop = char_I_depth_last_deco;
642
643 pres_stop = next_stop * 0.09995 // Meters to bar
644 + pres_surface;
645
646 // Keep GF_low until a first stop depth is found:
647 if( next_stop >= low_depth )
648 sim_limit( GF_low );
649 else
650 // current GF is GF_high - alpha (GF_high - GF_low)
651 // With alpha = currentDepth / maxDepth, hence in [0..1]
652 sim_limit( GF_high - next_stop * locked_GF_step );
653
654 // upper limit (lowest pressure tolerated):
655 if( sim_lead_tissue_limit >= pres_stop ) // check if ascent to next deco stop is ok
656 break;
657
658 // Else, validate that stop and loop...
659 first_stop = next_stop;
660 }
630 661
631 // Is it a new deepest first stop ? If yes this is the reference for 662 // Is it a new deepest first stop ? If yes this is the reference for
632 // the varying gradient factor. So reset that: 663 // the varying gradient factor. So reset that:
633 if( first_stop > low_depth ) 664 if( first_stop > low_depth )
634 { 665 {
635 // Store the deepest stop depth, as reference for GF_low. 666 // Store the deepest stop depth, as reference for GF_low.
636 low_depth = first_stop; 667 low_depth = first_stop;
637 locked_GF_step = GF_delta / low_depth; 668 locked_GF_step = GF_delta / low_depth;
638 } 669 }
639 670
640 // Check all stops until one is higher than tolerated presure 671 // next stop is the last validated depth found, aka first_stop
641 while(first_stop > 0)
642 {
643 overlay unsigned char next_stop; // Next index (0..30)
644 overlay float pres_stop; // Next depth (0m..90m)
645
646 if( first_stop <= char_I_depth_last_deco ) // new in v104
647 next_stop = 0;
648 else
649 next_stop = first_stop - 3; // Index of next (upper) stop.
650 if( first_stop == 3 )
651 first_stop = char_I_depth_last_deco;
652
653 pres_stop = next_stop * 0.09995 // Meters to bar
654 + pres_surface;
655
656 // current GF is GF_high - alpha (GF_high - GF_low)
657 // With alpha = currentDepth / maxDepth, hence in [0..1]
658 sim_limit( GF_high - next_stop * locked_GF_step );
659
660 // upper limit (lowest pressure tolerated):
661 if( sim_lead_tissue_limit >= pres_stop ) // check if ascent to next deco stop is ok
662 break;
663
664 // Else, validate that stop and loop...
665 first_stop = next_stop;
666 }
667
668 // first_stop is the last validated depth found:
669 temp_depth_limit = first_stop; // Stop depth, in meter. 672 temp_depth_limit = first_stop; // Stop depth, in meter.
670 temp_deco = first_stop * 0.09995 // Convert to bars, too.
671 + pres_surface;
672 if (first_stop > 0)
673 temp_deco += float_deco_distance; // Add security distance (bars too)
674 } 673 }
675 else 674 else
676 {
677 temp_deco = pres_surface; // surface ambient presure
678 temp_depth_limit = 0; // stop depth, in meter. 675 temp_depth_limit = 0; // stop depth, in meter.
679 }
680 } 676 }
681 else //---- ZH-L16 model ------------------------------------------------- 677 else //---- ZH-L16 model -------------------------------------------------
682 { 678 {
683 overlay float pres_gradient; 679 overlay float pres_gradient;
684 680
692 pres_gradient = sim_lead_tissue_limit - pres_surface; 688 pres_gradient = sim_lead_tissue_limit - pres_surface;
693 if (pres_gradient >= 0) 689 if (pres_gradient >= 0)
694 { 690 {
695 pres_gradient /= 0.29985; // Bar --> stop number; 691 pres_gradient /= 0.29985; // Bar --> stop number;
696 temp_depth_limit = 3 * (short) (pres_gradient + 0.99); // --> meter : depth for deco 692 temp_depth_limit = 3 * (short) (pres_gradient + 0.99); // --> meter : depth for deco
697 if (temp_depth_limit == 0) // At surface ? 693 if (temp_depth_limit != 0) // At surface ?
698 temp_deco = pres_surface;
699 else
700 { 694 {
701 if (temp_depth_limit < char_I_depth_last_deco) // Implement last stop at 4m/5m/6m... 695 if (temp_depth_limit < char_I_depth_last_deco) // Implement last stop at 4m/5m/6m...
702 temp_depth_limit = char_I_depth_last_deco; 696 temp_depth_limit = char_I_depth_last_deco;
703 temp_deco = (temp_depth_limit * 0.09995) // depth for deco [bar] = depth
704 + float_deco_distance // + security margin
705 + pres_surface; // + surface ambient presure
706 } 697 }
707 } 698 }
708 else 699 else
709 {
710 temp_deco = pres_surface; // surface ambient presure
711 temp_depth_limit = 0; // stop depth, in meter. 700 temp_depth_limit = 0; // stop depth, in meter.
712 }
713 } 701 }
702
703 //---- Check gas change --------------------------------------------------
704 check_gas_switch(); // Update temp_depth_limit if there is a change,
705 // Calculate N2_ratio and He_ratio too.
714 } 706 }
715 707
716 ////////////////////////////////////////////////////////////////////////////// 708 //////////////////////////////////////////////////////////////////////////////
717 // copy_deco_table 709 // copy_deco_table
718 // 710 //
870 862
871 ////////////////////////////////////////////////////////////////////////////// 863 //////////////////////////////////////////////////////////////////////////////
872 // Calculate gas switches 864 // Calculate gas switches
873 // 865 //
874 // 866 //
875 void check_gas_switch(void) 867 // Input: N2_ratio, He_ratio.
868 // deco_gas_change*
869 // sim_gas_delay, sim_gas_last_used, sim_dive_mins.
870 //
871 // Output: calc_N2_ratio, calc_He_ratio
872 // temp_depth_limit, sim_gas_delay, sim_gas_last_used IFF the is a switch.
873 //
874 static void check_gas_switch(void)
876 { 875 {
877 overlay unsigned char temp_gas_switch = 0; 876 overlay unsigned char temp_gas_switch = 0;
878 overlay float switch_deco; 877 overlay unsigned char switch_deco = 0;
879 878
880 calc_N2_ratio = N2_ratio; 879 calc_N2_ratio = N2_ratio;
881 calc_He_ratio = He_ratio; 880 calc_He_ratio = He_ratio;
882 881
883 if (char_I_const_ppO2 == 0) 882 if (char_I_const_ppO2 == 0)
884 { 883 {
885 deco_diluent = temp_deco;
886
887 // Keep selecting the best gas during the ascent simulation. 884 // Keep selecting the best gas during the ascent simulation.
888 if( deco_gas_change1 && (temp_deco < deco_gas_change1)) 885 // Add a one meter margin in depth comparaison.
886 if( deco_gas_change1 && ((temp_depth_limit-1) <= deco_gas_change1))
889 { 887 {
890 calc_N2_ratio = deco_N2_ratio1; 888 calc_N2_ratio = deco_N2_ratio1;
891 calc_He_ratio = deco_He_ratio1; 889 calc_He_ratio = deco_He_ratio1;
892 temp_gas_switch = 1; 890 temp_gas_switch = 1;
893 switch_deco = deco_gas_change1; 891 switch_deco = deco_gas_change1;
894 } 892 }
895 if(deco_gas_change2 && (temp_deco < deco_gas_change2)) 893 if(deco_gas_change2 && ((temp_depth_limit-1) <= deco_gas_change2))
896 { 894 {
897 calc_N2_ratio = char_I_deco_N2_ratio2 * 0.01; 895 calc_N2_ratio = char_I_deco_N2_ratio2 * 0.01;
898 calc_He_ratio = char_I_deco_He_ratio2 * 0.01; 896 calc_He_ratio = char_I_deco_He_ratio2 * 0.01;
899 temp_gas_switch = 2; 897 temp_gas_switch = 2;
900 switch_deco = deco_gas_change2; 898 switch_deco = deco_gas_change2;
901 } 899 }
902 if(deco_gas_change3 && (temp_deco < deco_gas_change3)) 900 if(deco_gas_change3 && ((temp_depth_limit-1) <= deco_gas_change3))
903 { 901 {
904 calc_N2_ratio = char_I_deco_N2_ratio3 * 0.01; 902 calc_N2_ratio = char_I_deco_N2_ratio3 * 0.01;
905 calc_He_ratio = char_I_deco_He_ratio3 * 0.01; 903 calc_He_ratio = char_I_deco_He_ratio3 * 0.01;
906 temp_gas_switch = 3; 904 temp_gas_switch = 3;
907 switch_deco = deco_gas_change3; 905 switch_deco = deco_gas_change3;
908 } 906 }
909 if(deco_gas_change4 && (temp_deco < deco_gas_change4)) 907 if(deco_gas_change4 && ((temp_depth_limit-1) <= deco_gas_change4))
910 { 908 {
911 calc_N2_ratio = char_I_deco_N2_ratio4 * 0.01; 909 calc_N2_ratio = char_I_deco_N2_ratio4 * 0.01;
912 calc_He_ratio = char_I_deco_He_ratio4 * 0.01; 910 calc_He_ratio = char_I_deco_He_ratio4 * 0.01;
913 temp_gas_switch = 4; 911 temp_gas_switch = 4;
914 switch_deco = deco_gas_change4; 912 switch_deco = deco_gas_change4;
915 } 913 }
916 if(deco_gas_change5 && (temp_deco < deco_gas_change5)) 914 if(deco_gas_change5 && ((temp_depth_limit-1) <= deco_gas_change5))
917 { 915 {
918 calc_N2_ratio = char_I_deco_N2_ratio5 * 0.01; 916 calc_N2_ratio = char_I_deco_N2_ratio5 * 0.01;
919 calc_He_ratio = char_I_deco_He_ratio5 * 0.01; 917 calc_He_ratio = char_I_deco_He_ratio5 * 0.01;
920 temp_gas_switch = 5; 918 temp_gas_switch = 5;
921 switch_deco = deco_gas_change5; 919 switch_deco = deco_gas_change5;
923 } 921 }
924 922
925 // If there is a better gas available 923 // If there is a better gas available
926 if( temp_gas_switch ) 924 if( temp_gas_switch )
927 { 925 {
928 // Should detect gas switch only when gas do changes... 926 // Should restart gas-switch delay only when gas do changes...
929 // sim_gas_last_used: used to detect just once in each ascent simu. 927 // sim_gas_last_used: used to detect just once in each ascent simu.
930 // N2_ratio : used to detect when already breathing that gas. 928 // N2_ratio : used to detect when already breathing that gas.
931 if( sim_gas_last_used < temp_gas_switch 929 if( sim_gas_last_used < temp_gas_switch
932 && sim_gas_delay <= sim_dive_mins 930 && sim_gas_delay <= sim_dive_mins
933 && (calc_N2_ratio != N2_ratio || calc_He_ratio != He_ratio)) 931 && (calc_N2_ratio != N2_ratio || calc_He_ratio != He_ratio))
937 935
938 // Apply depth correction ONLY if CF#55 is not null: 936 // Apply depth correction ONLY if CF#55 is not null:
939 if( sim_gas_delay > 0 ) 937 if( sim_gas_delay > 0 )
940 { 938 {
941 sim_gas_delay += sim_dive_mins; 939 sim_gas_delay += sim_dive_mins;
942 temp_deco = switch_deco - float_deco_distance; 940 temp_depth_limit = switch_deco;
943 temp_depth_limit = (temp_deco - pres_surface) / 0.09985;
944 } 941 }
945 } 942 }
946 } 943 }
947 else 944 else
948 sim_gas_delay = 0; 945 sim_gas_delay = 0;
952 assert( (calc_N2_ratio + calc_He_ratio) <= 1.00 ); 949 assert( (calc_N2_ratio + calc_He_ratio) <= 1.00 );
953 } 950 }
954 951
955 ////////////////////////////////////////////////////////////////////////////// 952 //////////////////////////////////////////////////////////////////////////////
956 // 953 //
957 static void alveolar_presures(void) 954 // Input: calc_N2_ratio, calc_He_ratio : simulated gas mix.
958 { 955 // temp_deco : simulated respiration pressure + security offset (deco_distance)
956 // Water-vapor pressure inside lumbs (ppWVapour).
957 //
958 // Output: ppO2, ppHe.
959 //
960 static void sim_alveolar_presures(void)
961 {
962 overlay float deco_diluent = temp_deco; // new in v.101
963
964 //---- CCR mode : deco gas switch ? --------------------------------------
959 if (char_I_const_ppO2 != 0) 965 if (char_I_const_ppO2 != 0)
960 { 966 {
961 if (temp_deco > deco_ppO2_change) 967 // In CCR mode, calc_XX_ratio == XX_ratio.
962 { 968 if( temp_deco > deco_ppO2_change )
963 deco_diluent = ((temp_deco - const_ppO2)/(N2_ratio + He_ratio)); 969 deco_diluent = ((temp_deco - const_ppO2)/(calc_N2_ratio + calc_He_ratio));
964 }
965 else 970 else
966 { 971 deco_diluent = ((temp_deco - deco_ppO2)/(calc_N2_ratio + calc_He_ratio));
967 deco_diluent = ((temp_deco - deco_ppO2)/(N2_ratio + He_ratio)); 972
968 } 973 if (deco_diluent > temp_deco)
974 deco_diluent = temp_deco;
969 } 975 }
970 976
971 if (deco_diluent > temp_deco) 977 // Take deco offset into account, but not at surface.
972 deco_diluent = temp_deco; 978 if( deco_diluent > pres_surface )
973 if (deco_diluent > ppWVapour) 979 deco_diluent += float_deco_distance;
980
981 if( deco_diluent > ppWVapour )
974 { 982 {
975 ppO2 = calc_N2_ratio * (deco_diluent - ppWVapour); 983 ppO2 = calc_N2_ratio * (deco_diluent - ppWVapour);
976 ppHe = calc_He_ratio * (deco_diluent - ppWVapour); 984 ppHe = calc_He_ratio * (deco_diluent - ppWVapour);
977 } 985 }
978 else 986 else
1001 int_O_DBG_post_bitfield = 0; 1009 int_O_DBG_post_bitfield = 0;
1002 char_O_NDL_at_20mtr = 255; 1010 char_O_NDL_at_20mtr = 255;
1003 1011
1004 // Kludge: the 0.0002 of 0.7902 are missing with standard air. 1012 // Kludge: the 0.0002 of 0.7902 are missing with standard air.
1005 N2_ratio = 0.7902; 1013 N2_ratio = 0.7902;
1006 pres_respiration = (float)int_I_pres_respiration / 1000.0; 1014 pres_respiration = int_I_pres_respiration * 0.001;
1007 1015
1008 for(ci=0; ci<16; ci++) 1016 for(ci=0; ci<16; ci++)
1009 { 1017 {
1010 // cycle through the 16 Bühlmann tissues 1018 // cycle through the 16 Bühlmann tissues
1011 overlay float p = N2_ratio * (pres_respiration - ppWVapour); 1019 overlay float p = N2_ratio * (pres_respiration - ppWVapour);
1100 // dive data. 1108 // dive data.
1101 backup_GF_step = locked_GF_step; 1109 backup_GF_step = locked_GF_step;
1102 backup_low_depth = low_depth; 1110 backup_low_depth = low_depth;
1103 1111
1104 // Check proposed gas at begin of ascent simulation 1112 // Check proposed gas at begin of ascent simulation
1105 temp_deco = pres_respiration; // Starts from current real depth.
1106 sim_dive_mins = int_I_divemins; // and time. 1113 sim_dive_mins = int_I_divemins; // and time.
1114 temp_depth_limit = (int)(0.95 + (pres_respiration - pres_surface) / 0.09985) ; // Starts from current real depth.
1107 check_gas_switch(); 1115 check_gas_switch();
1108 1116
1109 backup_gas_used = sim_gas_last_used;// And save for later simu steps. 1117 backup_gas_used = sim_gas_last_used;// And save for later simu steps.
1110 backup_gas_delay = sim_gas_delay; 1118 backup_gas_delay = sim_gas_delay;
1111 1119
1155 // ____________________________________________________ 1163 // ____________________________________________________
1156 // 1164 //
1157 // _____________ G A S _ C H A N G E S ________________ 1165 // _____________ G A S _ C H A N G E S ________________
1158 // ____________________________________________________ 1166 // ____________________________________________________
1159 1167
1160 // Keep a marhin of 150mbar = 1.50m 1168 // Keep a margin of 150mbar = 1.50m
1161 int_temp = (int_I_pres_respiration - int_I_pres_surface) + MBAR_REACH_GASCHANGE_AUTO_CHANGE_OFF; 1169 int_temp = (int_I_pres_respiration - int_I_pres_surface)
1170 + MBAR_REACH_GASCHANGE_AUTO_CHANGE_OFF;
1162 1171
1163 deco_gas_change1 = 0.0; 1172 deco_gas_change1 = 0;
1164 deco_gas_change2 = 0.0; 1173 deco_gas_change2 = 0;
1165 deco_gas_change3 = 0.0; 1174 deco_gas_change3 = 0;
1166 deco_gas_change4 = 0.0; 1175 deco_gas_change4 = 0;
1167 deco_gas_change5 = 0.0; 1176 deco_gas_change5 = 0;
1168 1177
1169 // Gas are selectable if we did not pass the change depth by more than 1.50m: 1178 // Gas are selectable if we did not pass the change depth by more than 1.50m:
1170 if(char_I_deco_gas_change1) 1179 if(char_I_deco_gas_change1)
1171 { 1180 {
1172 if( int_temp > 100 *(short)char_I_deco_gas_change1 ) 1181 if( int_temp > 100 *(short)char_I_deco_gas_change1 )
1173 deco_gas_change1 = char_I_deco_gas_change1 / 9.995 1182 deco_gas_change1 = char_I_deco_gas_change1;
1174 + pres_surface
1175 + float_deco_distance;
1176 } 1183 }
1177 if(char_I_deco_gas_change2) 1184 if(char_I_deco_gas_change2)
1178 { 1185 {
1179 if( int_temp > 100 *(short)char_I_deco_gas_change2 ) 1186 if( int_temp > 100 *(short)char_I_deco_gas_change2 )
1180 deco_gas_change2 = char_I_deco_gas_change2 / 9.995 1187 deco_gas_change2 = char_I_deco_gas_change2;
1181 + pres_surface
1182 + float_deco_distance;
1183 } 1188 }
1184 if(char_I_deco_gas_change3) 1189 if(char_I_deco_gas_change3)
1185 { 1190 {
1186 if( int_temp > 100 *(short)char_I_deco_gas_change3 ) 1191 if( int_temp > 100 *(short)char_I_deco_gas_change3 )
1187 deco_gas_change3 = char_I_deco_gas_change3 / 9.995 1192 deco_gas_change3 = char_I_deco_gas_change3;
1188 + pres_surface
1189 + float_deco_distance;
1190 } 1193 }
1191 if(char_I_deco_gas_change4) 1194 if(char_I_deco_gas_change4)
1192 { 1195 {
1193 if( int_temp > 100 *(short)char_I_deco_gas_change4 ) 1196 if( int_temp > 100 *(short)char_I_deco_gas_change4 )
1194 deco_gas_change4 = char_I_deco_gas_change4 / 9.995 1197 deco_gas_change4 = char_I_deco_gas_change4;
1195 + pres_surface
1196 + float_deco_distance;
1197 } 1198 }
1198 if(char_I_deco_gas_change5) 1199 if(char_I_deco_gas_change5)
1199 { 1200 {
1200 if( int_temp > 100 *(short)char_I_deco_gas_change5 ) 1201 if( int_temp > 100 *(short)char_I_deco_gas_change5 )
1201 deco_gas_change5 = char_I_deco_gas_change5 / 9.995 1202 deco_gas_change5 = char_I_deco_gas_change5;
1202 + pres_surface
1203 + float_deco_distance;
1204 } 1203 }
1205 1204
1206 const_ppO2 = char_I_const_ppO2 * 0.01; 1205 const_ppO2 = char_I_const_ppO2 * 0.01;
1207 deco_ppO2_change = char_I_deco_ppO2_change / 99.95 1206 deco_ppO2_change = char_I_deco_ppO2_change / 99.95
1208 + pres_surface 1207 + pres_surface
1275 { 1274 {
1276 overlay unsigned char loop; 1275 overlay unsigned char loop;
1277 1276
1278 for(loop = 0; loop < 16; ++loop) 1277 for(loop = 0; loop < 16; ++loop)
1279 { 1278 {
1279 overlay float new_presure;
1280 overlay unsigned char backup_gas_last_used;
1281
1280 // Do not ascent while doing a gas switch. 1282 // Do not ascent while doing a gas switch.
1281 if( sim_gas_delay <= sim_dive_mins ) 1283 if( sim_gas_delay <= sim_dive_mins )
1282 { 1284 {
1285 backup_gas_last_used = sim_gas_last_used;
1283 calc_nextdecodepth(); 1286 calc_nextdecodepth();
1284 1287
1285 //---- Finish computations once surface is reached --------------- 1288 //---- Finish computations once surface is reached ---------------
1286 if( temp_depth_limit == 0 ) 1289 if( temp_depth_limit == 0 )
1287 { 1290 {
1288 copy_deco_table(); 1291 copy_deco_table();
1289 calc_ascenttime(); 1292 calc_ascenttime();
1290 char_O_deco_status = 0; // calc nullzeit next time. 1293 char_O_deco_status = 0; // calc nullzeit next time.
1291 return; 1294 return;
1292 } 1295 }
1293 1296 }
1294 //---- Else, continue simulating the stops ----------------------- 1297
1295 check_gas_switch(); // Calculate N2_ratio and He_ratio. 1298 //---- Can we ascent to that stop at once, or is it just ascenting ?
1299 new_presure = temp_depth_limit * 0.09985 // Convert to relative bar,
1300 + pres_surface; // To absolute,
1301
1302 if( (temp_deco - new_presure) > 1.0 ) // More than 10m/mn ?
1303 {
1304 temp_deco -= 1.0; // Just keep ascending.
1305 sim_gas_delay = 0; // Reset gas delay,
1306 sim_gas_last_used = backup_gas_last_used; // and usage history.
1307 }
1308 else
1309 {
1310 temp_deco = new_presure;
1311 update_deco_table(); // This is a one minute stops.
1296 } 1312 }
1297 1313
1298 //---- Then update tissue and decoplan ------------------------------- 1314 //---- Then update tissue and decoplan -------------------------------
1299 sim_dive_mins++; // Advance simulated time by 1 minute. 1315 sim_dive_mins++; // Advance simulated time by 1 minute.
1300 alveolar_presures(); // Updates ppN2 and ppHe. 1316 sim_alveolar_presures(); // Updates ppN2 and ppHe.
1301 sim_tissue(1); // Simulate compartiments for 1 minute. 1317 sim_tissue(1); // Simulate compartiments for 1 minute.
1302 update_deco_table(); // Add one minute stops.
1303 } 1318 }
1304 1319
1305 // Surface not reached, need more stops... 1320 // Surface not reached, need more stops...
1306 char_O_deco_status = 1; // calc more stops next time. 1321 char_O_deco_status = 1; // calc more stops next time.
1307 } 1322 }
1318 update_startvalues(); 1333 update_startvalues();
1319 clear_deco_table(); 1334 clear_deco_table();
1320 1335
1321 temp_deco = pres_respiration; // Starts from current real depth. 1336 temp_deco = pres_respiration; // Starts from current real depth.
1322 1337
1338 // Do we have a gas switch going on ?
1339 if( sim_gas_delay > sim_dive_mins )
1340 return;
1341
1323 // Loop until first stop, gas switch, or surface is reached. 1342 // Loop until first stop, gas switch, or surface is reached.
1324 for(;;) 1343 for(;;)
1325 { 1344 {
1326 // Do we have a gas switch going on ?
1327 if( sim_gas_delay > sim_dive_mins )
1328 break;
1329
1330 // No: try ascending 1 full minute. 1345 // No: try ascending 1 full minute.
1331 temp_deco -= 1.0; // Ascent 1 min, at 10m/min. == 1bar/min. 1346 temp_deco -= 1.0; // Ascent 1 min, at 10m/min. == 1bar/min.
1347
1348 // Compute sim_lead_tissue_limit at GF_low (deepest stop).
1349 sim_limit(GF_low);
1350
1351 // Did we reach deepest remaining stop ?
1352 if( temp_deco <= sim_lead_tissue_limit )
1353 {
1354 temp_deco += 1.0; // Restore last correct depth.
1355 break; // Return stop found !
1356 }
1332 1357
1333 // Did we reach surface ? 1358 // Did we reach surface ?
1334 if( temp_deco <= pres_surface ) 1359 if( temp_deco <= pres_surface )
1335 { 1360 {
1336 temp_deco = pres_surface; // Yes: finished ! 1361 temp_deco = pres_surface; // Yes: finished !
1337 break; 1362 break;
1338 } 1363 }
1339 1364
1340 // Compute sim_lead_tissue_limit at GF_low (deepest stop). 1365 // Check gas change 5 meter below new depth.
1341 sim_limit(GF_low); 1366 temp_depth_limit = (temp_deco + 0.5 - pres_surface) / 0.09985;
1342 1367 check_gas_switch();
1343 // Did we reach deepest remaining stop ? 1368 if( sim_gas_delay > sim_dive_mins )
1344 if( temp_deco <= sim_lead_tissue_limit ) 1369 break;
1345 {
1346 temp_deco = sim_lead_tissue_limit;
1347 break; // Return stop found !
1348 }
1349
1350 temp_deco += 0.5; // Check gas change 5 meter below new depth.
1351 check_gas_switch();
1352 temp_deco -= 0.5; // Back to new depth.
1353 1370
1354 sim_dive_mins++; // Advance simulated time by 1 minute. 1371 sim_dive_mins++; // Advance simulated time by 1 minute.
1355 alveolar_presures(); // Calculate ppO2/ppHe at new depth. 1372 sim_alveolar_presures(); // Still uses temp_deco.
1356 sim_tissue(1); // and update tissues for 1 min. 1373 sim_tissue(1); // and update tissues for 1 min.
1357 } 1374 }
1358
1359 // Always updates depth in meter, too:
1360 temp_depth_limit = (temp_deco - pres_surface) / 0.09985;
1361 } 1375 }
1362 1376
1363 ////////////////////////////////////////////////////////////////////////////// 1377 //////////////////////////////////////////////////////////////////////////////
1364 // calc_tissue 1378 // calc_tissue
1365 // 1379 //
1571 // Function separated from sim_tissue() to allow recomputing limit on 1585 // Function separated from sim_tissue() to allow recomputing limit on
1572 // different depth, because it depends on current gradient factor. 1586 // different depth, because it depends on current gradient factor.
1573 // 1587 //
1574 static void sim_limit(PARAMETER float GF_current) 1588 static void sim_limit(PARAMETER float GF_current)
1575 { 1589 {
1590 assert( 0.0 < GF_current && GF_current <= 1.0f);
1591
1576 sim_lead_tissue_limit = 0.0; 1592 sim_lead_tissue_limit = 0.0;
1577 sim_lead_tissue_no = 255; 1593 sim_lead_tissue_no = 0; // If no one is critic, keep first tissue.
1578 1594
1579 for(ci=0; ci<16; ci++) 1595 for(ci=0; ci<16; ci++)
1580 { 1596 {
1581 overlay float p = sim_pres_tissue[ci] + (sim_pres_tissue+16)[ci]; 1597 overlay float p = sim_pres_tissue[ci] + (sim_pres_tissue+16)[ci];
1582 1598
1643 overlay unsigned char x; 1659 overlay unsigned char x;
1644 assert( temp_depth_limit < 128 ); // Can't be negativ (overflown). 1660 assert( temp_depth_limit < 128 ); // Can't be negativ (overflown).
1645 1661
1646 for(x=0; x<32; ++x) 1662 for(x=0; x<32; ++x)
1647 { 1663 {
1664 // Make sure deco-stops are recorded in order:
1665 assert( !internal_deco_depth[x] || temp_depth_limit <= internal_deco_depth[x] );
1666
1648 if( internal_deco_depth[x] == temp_depth_limit ) 1667 if( internal_deco_depth[x] == temp_depth_limit )
1649 { 1668 {
1650 // Do not overflow (max 255') 1669 // Do not overflow (max 255')
1651 if( internal_deco_time[x] < 255 ) 1670 if( internal_deco_time[x] < 255 )
1652 { 1671 {
1846 flag_in_divemode = 0; 1865 flag_in_divemode = 0;
1847 set_dbg_end_of_dive(); 1866 set_dbg_end_of_dive();
1848 } 1867 }
1849 1868
1850 N2_ratio = 0.7902; // FIXED, sum lt. buehlmann 1869 N2_ratio = 0.7902; // FIXED, sum lt. buehlmann
1851 pres_respiration = (float)int_I_pres_respiration / 1000.0; // assembler code uses different digit system 1870 pres_respiration = int_I_pres_respiration * 0.001; // assembler code uses different digit system
1852 pres_surface = (float)int_I_pres_surface / 1000.0; // the b"uhlmann formula using pres_surface does not use the N2_ratio 1871 pres_surface = int_I_pres_surface * 0.001; // the b"uhlmann formula using pres_surface does not use the N2_ratio
1853 ppO2 = N2_ratio * (pres_respiration - ppWVapour); // ppWVapour is the extra pressure in the body 1872 ppO2 = N2_ratio * (pres_respiration - ppWVapour); // ppWVapour is the extra pressure in the body
1854 ppHe = 0.0; 1873 ppHe = 0.0;
1855 float_desaturation_multiplier = char_I_desaturation_multiplier / 142.0; // new in v.101 (70,42%/100.=142) 1874 float_desaturation_multiplier = char_I_desaturation_multiplier / 142.0; // new in v.101 (70,42%/100.=142)
1856 float_saturation_multiplier = char_I_saturation_multiplier * 0.01; 1875 float_saturation_multiplier = char_I_saturation_multiplier * 0.01;
1857 1876