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 }