Mercurial > public > mk2
comparison code_part1/OSTC_code_c_part2/p2_deco.c @ 569:ef667587b2b9
BUGFIX Don't forget missed stops
MINOR cleanups for MacOSX compiler.
author | JeanDo |
---|---|
date | Wed, 04 Apr 2012 00:24:32 +0200 |
parents | a4586e115ded |
children | fff1d38625f0 |
comparison
equal
deleted
inserted
replaced
566:ebf6133207d4 | 569:ef667587b2b9 |
---|---|
78 // 2011/04/27: [jDG] Fixed char_O_gradient_factor calculation when model uses gradient-factor. | 78 // 2011/04/27: [jDG] Fixed char_O_gradient_factor calculation when model uses gradient-factor. |
79 // 2011/05/02: [jDG] Added "Future TTS" function (CF58). | 79 // 2011/05/02: [jDG] Added "Future TTS" function (CF58). |
80 // 2011/05/17: [jDG] Various cleanups. | 80 // 2011/05/17: [jDG] Various cleanups. |
81 // 2011/08/08: [jDG] Computes CNS during deco planning ascent. | 81 // 2011/08/08: [jDG] Computes CNS during deco planning ascent. |
82 // 2011/11/24: [jDG] Slightly faster and better NDL computation. | 82 // 2011/11/24: [jDG] Slightly faster and better NDL computation. |
83 // 2011/12/17: [mH] Remove of the useless debug stuff | 83 // 2011/12/17: [mH] Remove of the useless debug stuff |
84 // 2012/02/24: [jDG] Remove missed stop bug. | |
85 // 2012/02/25: [jDG] Looking for a more stable LOW grad factor reference. | |
84 // | 86 // |
85 // TODO: | 87 // TODO: |
86 // + Allow to abort MD2 calculation (have to restart next time). | 88 // + Allow to abort MD2 calculation (have to restart next time). |
87 // | 89 // |
88 // Literature: | 90 // Literature: |
151 static unsigned char calc_nextdecodepth(void); | 153 static unsigned char calc_nextdecodepth(void); |
152 | 154 |
153 //---- Bank 4 parameters ----------------------------------------------------- | 155 //---- Bank 4 parameters ----------------------------------------------------- |
154 #pragma udata bank4=0x400 | 156 #pragma udata bank4=0x400 |
155 | 157 |
156 static float temp_limit; | |
157 static float GF_low; | 158 static float GF_low; |
158 static float GF_high; | 159 static float GF_high; |
159 static float GF_delta; | 160 static float GF_delta; |
160 static float low_depth; // Depth of deepest stop | |
161 static float locked_GF_step; // GF_delta / low_depth | 161 static float locked_GF_step; // GF_delta / low_depth |
162 | 162 |
163 static unsigned char temp_depth_limit; | 163 static unsigned char temp_depth_limit; |
164 static unsigned char low_depth; // Depth of deepest stop | |
164 | 165 |
165 // Simulation context: used to predict ascent. | 166 // Simulation context: used to predict ascent. |
166 static unsigned char sim_lead_tissue_no; // Leading compatiment number. | 167 static unsigned char sim_lead_tissue_no; // Leading compatiment number. |
167 static float sim_lead_tissue_limit; // Buhlmann tolerated pressure. | 168 static float sim_lead_tissue_limit; // Buhlmann tolerated pressure. |
168 | 169 |
341 #endif | 342 #endif |
342 | 343 |
343 static short read_custom_function(PARAMETER unsigned char cf) | 344 static short read_custom_function(PARAMETER unsigned char cf) |
344 { | 345 { |
345 #ifdef CROSS_COMPILE | 346 #ifdef CROSS_COMPILE |
346 return (cf & 32) ? eeprom.bank1_CF[cf-32].value | 347 return (cf & 32) ? eeprom.bank1_CF[cf-32].value.lo |
347 : eeprom.bank0_CF[cf ].value; | 348 : eeprom.bank0_CF[cf ].value.lo; |
348 #else | 349 #else |
349 extern unsigned char hi, lo; | 350 extern unsigned char hi, lo; |
350 extern void getcustom15(); | 351 extern void getcustom15(); |
351 _asm | 352 _asm |
352 movff cf,WREG | 353 movff cf,WREG |
386 movlw 1 | 387 movlw 1 |
387 movwf TBLPTRU,0 | 388 movwf TBLPTRU,0 |
388 _endasm | 389 _endasm |
389 #endif | 390 #endif |
390 | 391 |
391 assert( 0 <= ci && ci < NUM_COMP ); | 392 assert( ci < NUM_COMP ); |
392 | 393 |
393 // Use an interleaved array (AoS) to access coefficients with a | 394 // Use an interleaved array (AoS) to access coefficients with a |
394 // single addressing. | 395 // single addressing. |
395 { | 396 { |
396 overlay rom const float* ptr = &buhlmann_ab[4*ci]; | 397 overlay rom const float* ptr = &buhlmann_ab[4*ci]; |
417 movlw 1 | 418 movlw 1 |
418 movwf TBLPTRU,0 | 419 movwf TBLPTRU,0 |
419 _endasm | 420 _endasm |
420 #endif | 421 #endif |
421 | 422 |
422 assert( 0 <= ci && ci < NUM_COMP ); | 423 assert( ci < NUM_COMP ); |
423 | 424 |
424 // Integration intervals. | 425 // Integration intervals. |
425 switch(period) | 426 switch(period) |
426 { | 427 { |
427 case 0: //---- 2 sec ----------------------------------------------------- | 428 case 0: //---- 2 sec ----------------------------------------------------- |
468 movlw 1 | 469 movlw 1 |
469 movwf TBLPTRU,0 | 470 movwf TBLPTRU,0 |
470 _endasm | 471 _endasm |
471 #endif | 472 #endif |
472 | 473 |
473 assert( 0 <= ci && ci < NUM_COMP ); | 474 assert( ci < NUM_COMP ); |
474 { | 475 { |
475 overlay rom const float* ptr = &buhlmann_ht[2*ci]; | 476 overlay rom const float* ptr = &buhlmann_ht[2*ci]; |
476 var_N2_ht = *ptr++; | 477 var_N2_ht = *ptr++; |
477 var_He_ht = *ptr++; | 478 var_He_ht = *ptr++; |
478 } | 479 } |
520 assert( depth >= -0.2 ); // Allow for 200mbar of weather change. | 521 assert( depth >= -0.2 ); // Allow for 200mbar of weather change. |
521 | 522 |
522 //---- ZH-L16 + GRADIENT FACTOR model ------------------------------------ | 523 //---- ZH-L16 + GRADIENT FACTOR model ------------------------------------ |
523 if( char_I_deco_model != 0 ) | 524 if( char_I_deco_model != 0 ) |
524 { | 525 { |
525 if( depth >= low_depth ) | 526 overlay unsigned char first_stop = 0; |
526 sim_limit( GF_low ); | 527 overlay float p; |
527 else | 528 |
528 sim_limit( GF_high - depth * locked_GF_step ); | 529 sim_limit( GF_low ); |
529 | 530 p = sim_lead_tissue_limit - pres_surface; |
530 // Stops are needed ? | 531 if( p <= 0.0f ) |
531 if( sim_lead_tissue_limit > pres_surface ) | 532 goto no_deco_stop; // We can surface directly... |
532 { | 533 |
533 // Compute tolerated depth, for the leading tissue [metre]: | 534 p *= BAR_TO_METER; |
534 overlay float depth_tol = (sim_lead_tissue_limit - pres_surface) * BAR_TO_METER; | 535 if( p < min_depth ) |
535 overlay unsigned char first_stop; | 536 goto no_deco_stop; // First stop is higher than 1' ascent. |
536 | 537 |
537 // If ascent is VERY fast, this can be lower than the actual depth... Because | 538 first_stop = 3 * (short)(0.99999 + p*0.333333); |
538 // this happends only in simulation, just forget about it: | 539 assert( first_stop < 128 ); |
539 if( depth_tol > depth ) | 540 |
540 depth_tol = depth; | 541 // Apply correction for the shallowest stop. |
541 | 542 if( first_stop == 3 ) // new in v104 |
542 // Deepest stop, in multiples of 3 metres. | 543 first_stop = char_I_depth_last_deco; // Use last 3m..6m instead. |
543 first_stop = 3 * (short)(0.99999 + depth_tol * 0.33333 ); | 544 |
544 assert( first_stop < 128 ); | 545 // Store the deepest point needing a deco stop as the LOW reference for GF. |
545 | 546 // NOTE: following stops will be validated using this LOW-HIGH gf scale, |
546 // Is it a new deepest needed stop ? If yes this is the reference for | 547 // so if we want to keep coherency, we should not validate this stop |
547 // the varying gradient factor. So reset that: | 548 // yet, but apply the search to it, as for all the following stops afterward. |
548 if( depth_tol > min_depth && depth_tol > low_depth ) | 549 if( first_stop > low_depth ) |
549 { | 550 { |
550 // Store the deepest stop depth, as reference for GF_low. | 551 low_depth = first_stop; |
551 low_depth = depth_tol; | 552 locked_GF_step = GF_delta / first_stop; |
552 locked_GF_step = GF_delta / low_depth; | 553 } |
553 } | 554 |
554 | 555 // We have a stop candidate. |
555 #if defined(__DEBUG) || defined(CROSS_COMPILE) | 556 // But maybe ascending to the next stop will diminish the constraint, |
556 { | 557 // because the GF might decrease more than the preassure gradient... |
557 // Extra testing code to make sure the first_stop formula | 558 while(first_stop > 0) |
558 // and rounding provides correct depth: | 559 { |
559 overlay float pres_stop = first_stop * METER_TO_BAR | 560 overlay unsigned char next_stop; // Next depth (0..90m) |
560 + pres_surface; | 561 overlay float pres_stop; // Next pressure (bar) |
561 | 562 |
562 // Keep GF_low until a first stop depth is found: | 563 // Check max speed, or reaching surface. |
563 if( first_stop >= low_depth ) | 564 if( first_stop <= min_depth ) |
564 sim_limit( GF_low ); | 565 goto no_deco_stop; |
565 else | 566 |
566 // current GF is GF_high - alpha (GF_high - GF_low) | 567 if( first_stop <= char_I_depth_last_deco ) // new in v104 |
567 // With alpha = currentDepth / maxDepth, hence in [0..1] | 568 next_stop = 0; |
568 sim_limit( GF_high - first_stop * locked_GF_step ); | 569 else if( first_stop == 6 ) |
569 | 570 next_stop = char_I_depth_last_deco; |
570 // upper limit (lowest pressure tolerated), + 1mbar for rounding...: | 571 else |
571 assert( sim_lead_tissue_limit < (pres_stop + 0.001) ); | 572 next_stop = first_stop - 3; // Index of next (upper) stop. |
572 } | 573 |
573 #endif | 574 // Just a check we are indeed above LOW ref. |
574 | 575 assert( next_stop < low_depth ); |
575 // Apply correction for the shallowest stop. | 576 |
576 if( first_stop == 3 ) // new in v104 | 577 // Total preassure at the new stop candidate: |
577 first_stop = char_I_depth_last_deco; // Use last 3m..6m instead. | 578 pres_stop = next_stop * METER_TO_BAR |
578 | 579 + pres_surface; |
579 // Because gradient factor at first_stop might be bigger than at | 580 |
580 // current depth, we might ascent a bit more. | 581 // Keep GF_low until a first stop depth is found: |
581 // Hence, check all stops until one is indeed higher than tolerated presure: | 582 sim_limit( GF_high - next_stop * locked_GF_step ); |
582 while(first_stop > 0) | 583 |
583 { | 584 // Check upper limit (lowest pressure tolerated): |
584 overlay unsigned char next_stop; // Next index (0..30) | 585 if( sim_lead_tissue_limit >= pres_stop ) // check if ascent to next deco stop is ok |
585 overlay float pres_stop; // Next depth (0m..90m) | 586 goto deco_stop_found; |
586 | 587 |
587 // Check max speed, or reaching surface. | 588 // Else, validate that stop and loop... |
588 if( first_stop <= min_depth ) | 589 first_stop = next_stop; |
589 break; | 590 } |
590 | 591 assert( first_stop == 0 ); |
591 // So, there is indeed a stop needed: | 592 |
592 need_stop = 1; | 593 no_deco_stop: |
593 | 594 temp_depth_limit = 0; |
594 if( first_stop <= char_I_depth_last_deco ) // new in v104 | 595 goto done; |
595 next_stop = 0; | 596 |
596 else if( first_stop == 6 ) | 597 // next stop is the last validated depth found, aka first_stop |
597 next_stop = char_I_depth_last_deco; | 598 deco_stop_found: |
598 else | 599 need_stop = 1; // Hit. |
599 next_stop = first_stop - 3; // Index of next (upper) stop. | 600 temp_depth_limit = first_stop; // Stop depth, in meter. |
600 | 601 |
601 pres_stop = next_stop * METER_TO_BAR | 602 done: |
602 + pres_surface; | 603 ; |
603 | |
604 // Keep GF_low until a first stop depth is found: | |
605 if( next_stop >= low_depth ) | |
606 sim_limit( GF_low ); | |
607 else | |
608 // current GF is GF_high - alpha (GF_high - GF_low) | |
609 // With alpha = currentDepth / maxDepth, hence in [0..1] | |
610 sim_limit( GF_high - next_stop * locked_GF_step ); | |
611 | |
612 // upper limit (lowest pressure tolerated): | |
613 if( sim_lead_tissue_limit >= pres_stop ) // check if ascent to next deco stop is ok | |
614 break; | |
615 | |
616 // Else, validate that stop and loop... | |
617 first_stop = next_stop; | |
618 } | |
619 | |
620 // next stop is the last validated depth found, aka first_stop | |
621 temp_depth_limit = first_stop; // Stop depth, in metre. | |
622 } | |
623 else | |
624 temp_depth_limit = 0; // stop depth, in metre. | |
625 } | 604 } |
626 else //---- ZH-L16 model ------------------------------------------------- | 605 else //---- ZH-L16 model ------------------------------------------------- |
627 { | 606 { |
628 overlay float pres_gradient; | 607 overlay float pres_gradient; |
629 | 608 |
785 { | 764 { |
786 RESET_C_STACK | 765 RESET_C_STACK |
787 calc_dive_interval(); | 766 calc_dive_interval(); |
788 } | 767 } |
789 | 768 |
790 | |
791 ////////////////////////////////////////////////////////////////////////////// | 769 ////////////////////////////////////////////////////////////////////////////// |
792 // Find current gas in the list (if any). | 770 // Find current gas in the list (if any). |
793 // | 771 // |
794 // Input: char_I_current_gas = 1..6 | 772 // Input: char_I_current_gas = 1..6 |
795 // | 773 // |
893 // | 871 // |
894 // Output: calc_N2_ratio, calc_He_ratio | 872 // Output: calc_N2_ratio, calc_He_ratio |
895 // | 873 // |
896 static void gas_switch_set(void) | 874 static void gas_switch_set(void) |
897 { | 875 { |
898 assert( 0 <= sim_gas_last_used && sim_gas_last_used <= NUM_GAS ); | 876 assert( sim_gas_last_used <= NUM_GAS ); |
899 | 877 |
900 if( sim_gas_last_used == 0 ) // Gas6 = manualy set gas. | 878 if( sim_gas_last_used == 0 ) // Gas6 = manualy set gas. |
901 { | 879 { |
902 calc_N2_ratio = N2_ratio; | 880 calc_N2_ratio = N2_ratio; |
903 calc_He_ratio = He_ratio; | 881 calc_He_ratio = He_ratio; |
1042 char_O_deco_status = 0; // Calc bottom-time/nullzeit next iteration. | 1020 char_O_deco_status = 0; // Calc bottom-time/nullzeit next iteration. |
1043 | 1021 |
1044 // Values that should be reset just once for the full real dive. | 1022 // Values that should be reset just once for the full real dive. |
1045 // This is used to record the lowest stop for the whole dive, | 1023 // This is used to record the lowest stop for the whole dive, |
1046 // Including ACCROSS all simulated ascent. | 1024 // Including ACCROSS all simulated ascent. |
1047 low_depth = 0.0; | 1025 low_depth = 0; |
1026 locked_GF_step = 0.0; | |
1048 | 1027 |
1049 // Reset gas switch history. | 1028 // Reset gas switch history. |
1050 backup_gas_used = sim_gas_last_used = 0; | 1029 backup_gas_used = sim_gas_last_used = 0; |
1051 backup_gas_depth = sim_gas_last_depth = 0; | 1030 backup_gas_depth = sim_gas_last_depth = 0; |
1052 backup_gas_delay = sim_gas_delay = 0; | 1031 backup_gas_delay = sim_gas_delay = 0; |
1782 | 1761 |
1783 if( char_I_deco_model != 0 ) // calculate relative gradient factor | 1762 if( char_I_deco_model != 0 ) // calculate relative gradient factor |
1784 { | 1763 { |
1785 overlay float rgf; | 1764 overlay float rgf; |
1786 | 1765 |
1787 if( low_depth < 1.5 ) | 1766 if( low_depth < 3 ) |
1788 rgf = GF_high; | 1767 rgf = GF_high; |
1789 else | 1768 else |
1790 { | 1769 { |
1791 overlay float temp1 = low_depth * METER_TO_BAR; | 1770 overlay float temp1 = low_depth * METER_TO_BAR; |
1792 overlay float temp2 = pres_respiration - pres_surface; | 1771 overlay float temp2 = pres_respiration - pres_surface; |
1975 ppN2 = N2_ratio * (pres_respiration - ppWater); | 1954 ppN2 = N2_ratio * (pres_respiration - ppWater); |
1976 ppHe = 0.0; | 1955 ppHe = 0.0; |
1977 float_desaturation_multiplier = char_I_desaturation_multiplier * (0.01 * SURFACE_DESAT_FACTOR); | 1956 float_desaturation_multiplier = char_I_desaturation_multiplier * (0.01 * SURFACE_DESAT_FACTOR); |
1978 float_saturation_multiplier = char_I_saturation_multiplier * 0.01; | 1957 float_saturation_multiplier = char_I_saturation_multiplier * 0.01; |
1979 | 1958 |
1980 // Make sure SURFACE_DESAT_FACTOR is applyed: | 1959 // Make sure SURFACE_DESAT_FACTOR is applied: |
1981 backup_model = char_I_deco_model; | 1960 backup_model = char_I_deco_model; |
1982 char_I_deco_model = 0; | 1961 char_I_deco_model = 0; |
1983 | 1962 |
1984 //---- Perform simulation ------------------------------------------------ | 1963 //---- Perform simulation ------------------------------------------------ |
1985 for(t=0; t<char_I_dive_interval; ++t) | 1964 for(t=0; t<char_I_dive_interval; ++t) |
2211 else //---- OC mode : have to follow all gas switches... ----------------- | 2190 else //---- OC mode : have to follow all gas switches... ----------------- |
2212 { | 2191 { |
2213 overlay unsigned char i = 0; // Decostop loop counter | 2192 overlay unsigned char i = 0; // Decostop loop counter |
2214 overlay float actual_ppO2; | 2193 overlay float actual_ppO2; |
2215 overlay unsigned char time, t; | 2194 overlay unsigned char time, t; |
2195 overlay unsigned char deepest_first = (read_custom_function(54) == 0); | |
2216 | 2196 |
2217 //---- Ascent to surface delay | 2197 //---- Ascent to surface delay |
2218 // NOTE: count as if time is spent with bottom pressure, | 2198 // NOTE: count as if time is spent with bottom pressure, |
2219 // AND the bottom gas | 2199 // AND the bottom gas |
2220 actual_ppO2 = (pres_surface + char_I_bottom_depth * METER_TO_BAR) | 2200 actual_ppO2 = (pres_surface + char_I_bottom_depth * METER_TO_BAR) |
2230 { | 2210 { |
2231 deco_calc_CNS_fraction(); | 2211 deco_calc_CNS_fraction(); |
2232 sim_dive_mins++; | 2212 sim_dive_mins++; |
2233 } | 2213 } |
2234 | 2214 |
2235 //---- Do all further stops | 2215 //---- Do all further stops ------------------------------------------ |
2236 for(i=0; i<NUM_STOPS; ++i) | 2216 for(i=0; i<NUM_STOPS; ++i) |
2237 { | 2217 { |
2238 //---- Get next stop | 2218 overlay unsigned char switch_gas; |
2239 time = char_O_deco_time[i]; | 2219 |
2240 temp_depth_limit = char_O_deco_depth[i] & 0x7F; | 2220 //---- Get next stop, possibly in reverse order ------------------ |
2241 if( time == 0 ) break; // End of table: done. | 2221 if( deepest_first ) |
2222 { | |
2223 time = char_O_deco_time[i]; | |
2224 temp_depth_limit = char_O_deco_depth[i]; | |
2225 } | |
2226 else | |
2227 { | |
2228 time = char_O_deco_time[(NUM_STOPS-1)-i]; | |
2229 temp_depth_limit = char_O_deco_depth[(NUM_STOPS-1)-i]; | |
2230 } | |
2231 if( time == 0 ) continue; | |
2242 | 2232 |
2243 //---- Gas Switch ? | 2233 //---- Gas Switch ? ---------------------------------------------- |
2244 if( char_O_deco_depth[i] & 0x80 ) | 2234 switch_gas = temp_depth_limit & 0x80; // Switch flag. |
2245 if( gas_switch_deepest() ) | 2235 temp_depth_limit &= 0x7F; // True stop depth. |
2246 gas_switch_set(); | 2236 |
2247 | 2237 if( switch_gas ) |
2248 //---- Convert Depth and N2_ratio to ppO2 | 2238 { |
2239 gas_switch_deepest(); | |
2240 gas_switch_set(); | |
2241 } | |
2242 | |
2243 //---- Convert Depth and N2_ratio to ppO2 ------------------------ | |
2249 actual_ppO2 = (pres_surface + temp_depth_limit * METER_TO_BAR) | 2244 actual_ppO2 = (pres_surface + temp_depth_limit * METER_TO_BAR) |
2250 * (1.0 - calc_N2_ratio - calc_He_ratio); | 2245 * (1.0 - calc_N2_ratio - calc_He_ratio); |
2251 if( actual_ppO2 < 0.0 ) actual_ppO2 = 0.0; | 2246 if( actual_ppO2 < 0.0 ) actual_ppO2 = 0.0; |
2252 if( actual_ppO2 > 2.50 ) actual_ppO2 = 2.55; | 2247 if( actual_ppO2 > 2.50 ) actual_ppO2 = 2.55; |
2253 char_I_actual_ppO2 = (unsigned char)(100.0 * actual_ppO2 + 0.5); | 2248 char_I_actual_ppO2 = (unsigned char)(100.0 * actual_ppO2 + 0.5); |
2259 sim_dive_mins++; | 2254 sim_dive_mins++; |
2260 } | 2255 } |
2261 } | 2256 } |
2262 } | 2257 } |
2263 | 2258 |
2264 // Back to normal mode... | 2259 //---- Back to normal mode... -------------------------------------------- |
2265 char_I_step_is_1min = 0; | 2260 char_I_step_is_1min = 0; |
2266 sim_gas_last_depth = backup_gas_last_depth; | 2261 sim_gas_last_depth = backup_gas_last_depth; |
2267 sim_gas_last_used = backup_gas_last_used; | 2262 sim_gas_last_used = backup_gas_last_used; |
2268 sim_gas_delay = backup_gas_delay; | 2263 sim_gas_delay = backup_gas_delay; |
2269 sim_dive_mins = backup_dive_mins; | 2264 sim_dive_mins = backup_dive_mins; |
2303 void deco_calc_percentage(void) | 2298 void deco_calc_percentage(void) |
2304 { | 2299 { |
2305 RESET_C_STACK | 2300 RESET_C_STACK |
2306 | 2301 |
2307 assert( 60 <= char_I_temp && char_I_temp <= 100 ); | 2302 assert( 60 <= char_I_temp && char_I_temp <= 100 ); |
2308 assert( 0 <= int_I_temp && int_I_temp < 5760 ); // Less than 4 days = 96h... | 2303 assert( int_I_temp < 5760 ); // Less than 4 days = 96h... |
2309 | 2304 |
2310 int_I_temp = (unsigned short)(((float)int_I_temp * (float)char_I_temp) * 0.01 ); | 2305 int_I_temp = (unsigned short)(((float)int_I_temp * (float)char_I_temp) * 0.01 ); |
2311 | 2306 |
2312 assert( int_I_temp < 5760 ); // Less than 96h too... | 2307 assert( int_I_temp < 5760 ); // Less than 96h too... |
2313 } | 2308 } |