Mercurial > public > hwos_code
comparison src/p2_deco.c @ 584:d63dec562d50
CNS fix
author | heinrichsweikamp |
---|---|
date | Wed, 28 Feb 2018 10:24:54 +0100 |
parents | b455b31ce022 |
children | 00ad4ffd915b |
comparison
equal
deleted
inserted
replaced
583:6636cbe64c6d | 584:d63dec562d50 |
---|---|
1 // *************************************************************************** | 1 // *************************************************************************** |
2 // p2_deco.c REFACTORED VERSION V2.97b | 2 // p2_deco.c REFACTORED VERSION V2.98 |
3 // | 3 // |
4 // Created on: 12.05.2009 | 4 // Created on: 12.05.2009 |
5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others | 5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others |
6 // | 6 // |
7 // *************************************************************************** | 7 // *************************************************************************** |
67 // 2014/06/29: [mH] Compute int_O_ceiling | 67 // 2014/06/29: [mH] Compute int_O_ceiling |
68 // 2015/06/12: [jDG] Fix NDL prediction while desaturating with the Buhlmann model. | 68 // 2015/06/12: [jDG] Fix NDL prediction while desaturating with the Buhlmann model. |
69 // 2017/08/04: [mH] Switch to absolute GF everywhere and apply safety margin parameters to both models (GF and non-GF), fixes from Ralph Lembcke | 69 // 2017/08/04: [mH] Switch to absolute GF everywhere and apply safety margin parameters to both models (GF and non-GF), fixes from Ralph Lembcke |
70 // 2017/10/31: [rl] enhancements for pSCR mode and introduction of 2nd deco plan computation | 70 // 2017/10/31: [rl] enhancements for pSCR mode and introduction of 2nd deco plan computation |
71 // 2017/12/31: [rl] completion of 2nd deco plan computation and various up-fixes | 71 // 2017/12/31: [rl] completion of 2nd deco plan computation and various up-fixes |
72 // 2018/02/17: [rl] switch-over to new ceiling rounding (V2.98a) | |
72 // | 73 // |
73 // | 74 // |
74 // Literature: | 75 // Literature: |
75 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002]; | 76 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002]; |
76 // Schr"oder, Kai & Reith, Steffen; 2000; S"attigungsvorg"ange beim Tauchen, das Modell ZH-L16, Funktionsweise von Tauchcomputern; http://www.achim-und-kai.de/kai/tausim/saett_faq | 77 // Schr"oder, Kai & Reith, Steffen; 2000; S"attigungsvorg"ange beim Tauchen, das Modell ZH-L16, Funktionsweise von Tauchcomputern; http://www.achim-und-kai.de/kai/tausim/saett_faq |
115 | 116 |
116 // thresholds | 117 // thresholds |
117 #define GF_WARNING_THRESHOLD 100 // threshold for GF warning (attention threshold is current GF_high) | 118 #define GF_WARNING_THRESHOLD 100 // threshold for GF warning (attention threshold is current GF_high) |
118 #define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning | 119 #define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning |
119 #define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention | 120 #define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention |
120 #define ppO2_ATTENTION_THRESHOLD 120 // threshold for ppO2 attention (thresholds for warnings come by options_table.asm) | 121 #define ppO2_ATTENTION_THRESHOLD 130 // threshold for ppO2 attention (thresholds for warnings come by options_table.asm) |
121 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar] | 122 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar] |
122 #define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention | 123 #define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention |
123 | 124 |
124 // deco engine states and modes - char_O_deco_status | 125 // deco engine states and modes - char_O_deco_status |
125 #define DECO_STATUS_MASK 0x03 | 126 #define DECO_STATUS_MASK 0x03 |
146 //#define DECO_MODE_PSCR 0x08 | 147 //#define DECO_MODE_PSCR 0x08 |
147 #define DECO_GASCHANGE_OVRD 0x10 | 148 #define DECO_GASCHANGE_OVRD 0x10 |
148 #define DECO_BOTTOM_CALCULATE 0x40 | 149 #define DECO_BOTTOM_CALCULATE 0x40 |
149 | 150 |
150 // deco engine states and modes - tissue_increment | 151 // deco engine states and modes - tissue_increment |
151 #define TIME_MASK 0x7F // (127 decimal, bits 0-6) | 152 #define TIME_MASK 0x7F // (127 decimal, bits 0-6 set) |
152 #define TISSUE_FLAG 0x80 // (128 decimal, bit 7 ) | 153 #define TISSUE_FLAG 0x80 // (128 decimal, bit 7 set) |
153 | 154 |
154 // deco engine warnings | 155 // deco engine warnings |
155 #define DECO_WARNING_IBCD 0x01 | 156 #define DECO_WARNING_IBCD 0x01 |
156 #define DECO_WARNING_IBCD_lock 0x02 | 157 #define DECO_WARNING_IBCD_lock 0x02 |
157 #define DECO_WARNING_MBUBBLES 0x04 | 158 #define DECO_WARNING_MBUBBLES 0x04 |
175 // ** P R O T O T Y P E S ** | 176 // ** P R O T O T Y P E S ** |
176 // ************************* | 177 // ************************* |
177 | 178 |
178 static void calc_hauptroutine(void); | 179 static void calc_hauptroutine(void); |
179 static void calc_hauptroutine_data_input(void); | 180 static void calc_hauptroutine_data_input(void); |
180 static void calc_hauptroutine_update_tissues(void); | |
181 static void calc_hauptroutine_calc_deco(void); | 181 static void calc_hauptroutine_calc_deco(void); |
182 static void calc_alveolar_pressures(void); | 182 static void calc_alveolar_pressures(void); |
183 static void calc_tissues(void); | 183 static void calc_tissues(void); |
184 static void calc_NDL_time(void); | 184 static void calc_NDL_time(void); |
185 static void calc_ascenttime(void); | 185 static void calc_ascenttime(void); |
515 ////////////////////////////////////////////////////////////////////////////// | 515 ////////////////////////////////////////////////////////////////////////////// |
516 // | 516 // |
517 // all new in v.102 | 517 // all new in v.102 |
518 // moved from 0x0D000 to 0x0C000 in v.108 | 518 // moved from 0x0D000 to 0x0C000 in v.108 |
519 #ifndef UNIX | 519 #ifndef UNIX |
520 # pragma code p2_deco = 0x0C000 | 520 # pragma code p2_deco = 0x0C000 |
521 #endif | 521 #endif |
522 | 522 |
523 ////////////////////////////////////////////////////////////////////////////// | 523 ////////////////////////////////////////////////////////////////////////////// |
524 ////////////////////////////////////////////////////////////////////////////// | 524 ////////////////////////////////////////////////////////////////////////////// |
525 //////////////// U T I L I T I E S //////////////// | 525 //////////////// U T I L I T I E S //////////////// |
537 ////////////////////////////////////////////////////////////////////////////// | 537 ////////////////////////////////////////////////////////////////////////////// |
538 // When calling C code from ASM context, the data stack pointer and | 538 // When calling C code from ASM context, the data stack pointer and |
539 // frames should be reset. Bank8 is used by stack | 539 // frames should be reset. Bank8 is used by stack |
540 | 540 |
541 #ifdef CROSS_COMPILE | 541 #ifdef CROSS_COMPILE |
542 # define RESET_C_STACK | 542 # define RESET_C_STACK |
543 #else | 543 #else |
544 # ifdef __DEBUG | 544 # ifdef __DEBUG |
545 # define RESET_C_STACK fillDataStack(); | 545 # define RESET_C_STACK fillDataStack(); |
546 void fillDataStack(void) | 546 void fillDataStack(void) |
547 { | 547 { |
548 _asm | 548 _asm |
549 LFSR 1,C_STACK | 549 LFSR 1,C_STACK |
550 MOVLW 0xCC | 550 MOVLW 0xCC |
551 loop: MOVWF POSTINC1,0 | 551 loop: MOVWF POSTINC1,0 |
552 TSTFSZ FSR1L,0 | 552 TSTFSZ FSR1L,0 |
553 BRA loop | 553 BRA loop |
554 | 554 |
555 LFSR 1,C_STACK | 555 LFSR 1,C_STACK |
556 LFSR 2,C_STACK | 556 LFSR 2,C_STACK |
557 _endasm | 557 _endasm |
558 } | 558 } |
559 # else | 559 # else |
560 # define RESET_C_STACK \ | 560 # define RESET_C_STACK \ |
561 _asm \ | 561 _asm \ |
562 LFSR 1, C_STACK \ | 562 LFSR 1, C_STACK \ |
563 LFSR 2, C_STACK \ | 563 LFSR 2, C_STACK \ |
564 _endasm | 564 _endasm |
565 # endif | 565 # endif |
566 #endif | 566 #endif |
567 | 567 |
568 ////////////////////////////////////////////////////////////////////////////// | 568 ////////////////////////////////////////////////////////////////////////////// |
569 // Fast subroutine to read timer 5. | 569 // Fast subroutine to read timer 5. |
570 // Note: result is in 1/32 of milliseconds (30,51757813 us/bit to be precise) | 570 // Note: result is in 1/32 of milliseconds (30,51757813 us/bit to be precise) |
571 static unsigned short tmr5(void) | 571 static unsigned short tmr5(void) |
572 { | 572 { |
573 #ifndef CROSS_COMPILE | 573 #ifndef CROSS_COMPILE |
574 _asm | 574 _asm |
575 movff 0xf7c,PRODL // TMR5L | 575 movff 0xf7c,PRODL // TMR5L |
576 movff 0xf7d,PRODH // TMR5H | 576 movff 0xf7d,PRODH // TMR5H |
577 _endasm // result in PRODH:PRODL. | 577 _endasm // result in PRODH:PRODL. |
578 #else | 578 #else |
579 return 0; | 579 return 0; |
580 #endif | 580 #endif |
581 } | 581 } |
582 | 582 |
583 ////////////////////////////////////////////////////////////////////////////// | 583 ////////////////////////////////////////////////////////////////////////////// |
584 // read Buhlmann tables A and B for compartment ci | 584 // read Buhlmann tables A and B for compartment ci |
585 // | 585 // |
586 static void read_Buhlmann_coefficients(void) | 586 static void read_Buhlmann_coefficients(void) |
587 { | 587 { |
588 #ifndef CROSS_COMPILE | 588 #ifndef CROSS_COMPILE |
589 // Note: we don't use far rom pointer, because the | 589 // Note: we don't use far rom pointer, because the |
590 // 24 bits is too complex, hence we have to set | 590 // 24 bits is too complex, hence we have to set |
591 // the UPPER page ourself... | 591 // the UPPER page ourself... |
592 // --> Set zero if tables are moved to lower pages ! | 592 // --> Set zero if tables are moved to lower pages ! |
593 _asm | 593 _asm |
594 movlw 1 | 594 movlw 1 |
595 movwf TBLPTRU,0 | 595 movwf TBLPTRU,0 |
596 _endasm | 596 _endasm |
597 #endif | 597 #endif |
598 | 598 |
599 assert( ci < NUM_COMP ); | 599 assert( ci < NUM_COMP ); |
600 | 600 |
601 // Use an interleaved array (AoS) to access coefficients with a | 601 // Use an interleaved array (AoS) to access coefficients with a |
602 // single addressing. | 602 // single addressing. |
603 { | 603 { |
604 overlay rom const float* ptr = &Buhlmann_ab[4*ci]; | 604 overlay rom const float* ptr = &Buhlmann_ab[4*ci]; |
605 var_N2_a = *ptr++; | 605 var_N2_a = *ptr++; |
606 var_N2_b = *ptr++; | 606 var_N2_b = *ptr++; |
607 var_He_a = *ptr++; | 607 var_He_a = *ptr++; |
608 var_He_b = *ptr++; | 608 var_He_b = *ptr++; |
609 } | 609 } |
610 } | 610 } |
611 | 611 |
612 ////////////////////////////////////////////////////////////////////////////// | 612 ////////////////////////////////////////////////////////////////////////////// |
613 // read Buhlmann tables for compartment ci | 613 // read Buhlmann tables for compartment ci |
614 // If period == 0 : 2sec interval | 614 // If period == 0 : 2sec interval |
615 // 1 : 1 min interval | 615 // 1 : 1 min interval |
616 // 2 : 10 min interval. | 616 // 2 : 10 min interval. |
617 static void read_Buhlmann_times(PARAMETER char period) | 617 static void read_Buhlmann_times(PARAMETER char period) |
618 { | 618 { |
619 #ifndef CROSS_COMPILE | 619 #ifndef CROSS_COMPILE |
620 // Note: we don't use far rom pointer, because the | 620 // Note: we don't use far rom pointer, because the |
621 // 24 bits is to complex, hence we have to set | 621 // 24 bits is to complex, hence we have to set |
622 // the UPPER page ourself... | 622 // the UPPER page ourself... |
623 // --> Set zero if tables are moved to lower pages ! | 623 // --> Set zero if tables are moved to lower pages! |
624 _asm | 624 _asm |
625 movlw 1 | 625 movlw 1 |
626 movwf TBLPTRU,0 | 626 movwf TBLPTRU,0 |
627 _endasm | 627 _endasm |
628 #endif | 628 #endif |
629 | 629 |
630 assert( ci < NUM_COMP ); | 630 assert( ci < NUM_COMP ); |
631 | 631 |
632 // Integration intervals. | 632 // Integration intervals |
633 switch(period) | 633 switch(period) |
634 { | 634 { |
635 case 0: //---- 2 sec ----------------------------------------------------- | 635 case 0: //---- 2 sec ----------------------------------------------------- |
636 { | 636 { |
637 overlay rom const float* ptr = &e2secs[2*ci]; | 637 overlay rom const float* ptr = &e2secs[2*ci]; |
638 var_N2_e = *ptr++; | 638 var_N2_e = *ptr++; |
639 var_He_e = *ptr++; | 639 var_He_e = *ptr++; |
640 } | 640 } |
641 break; | 641 break; |
642 | 642 |
643 case 1: //---- 1 min ----------------------------------------------------- | 643 case 1: //---- 1 min ----------------------------------------------------- |
644 { | 644 { |
645 overlay rom const float* ptr = &e1min[2*ci]; | 645 overlay rom const float* ptr = &e1min[2*ci]; |
646 var_N2_e = *ptr++; | 646 var_N2_e = *ptr++; |
647 var_He_e = *ptr++; | 647 var_He_e = *ptr++; |
648 } | 648 } |
649 break; | 649 break; |
650 | 650 |
651 case 2: //---- 10 min ---------------------------------------------------- | 651 case 2: //---- 10 min ---------------------------------------------------- |
652 { | 652 { |
653 overlay rom const float* ptr = &e10min[2*ci]; | 653 overlay rom const float* ptr = &e10min[2*ci]; |
654 var_N2_e = *ptr++; | 654 var_N2_e = *ptr++; |
655 var_He_e = *ptr++; | 655 var_He_e = *ptr++; |
656 } | 656 } |
657 break; | 657 break; |
658 | 658 |
659 default: | 659 default: |
660 assert(0); // Never go there... | 660 assert(0); // Never go there... |
661 } | 661 } |
662 } | 662 } |
663 | 663 |
664 ////////////////////////////////////////////////////////////////////////////// | 664 ////////////////////////////////////////////////////////////////////////////// |
665 // read Buhlmann tables for compartment ci | 665 // read Buhlmann tables for compartment ci |
666 // | 666 // |
667 static void read_Buhlmann_ht(void) | 667 static void read_Buhlmann_ht(void) |
668 { | 668 { |
669 | 669 |
670 #ifndef CROSS_COMPILE | 670 #ifndef CROSS_COMPILE |
671 // Note: we don't use far rom pointer, because the | 671 // Note: we don't use far rom pointer, because the |
672 // 24 bits is to complex, hence we have to set | 672 // 24 bits is to complex, hence we have to set |
673 // the UPPER page ourself... | 673 // the UPPER page ourself... |
674 // --> Set zero if tables are moved to lower pages ! | 674 // --> Set zero if tables are moved to lower pages ! |
675 _asm | 675 _asm |
676 movlw 1 | 676 movlw 1 |
677 movwf TBLPTRU,0 | 677 movwf TBLPTRU,0 |
678 _endasm | 678 _endasm |
679 #endif | 679 #endif |
680 | 680 |
681 assert( ci < NUM_COMP ); | 681 assert( ci < NUM_COMP ); |
682 { | 682 { |
683 overlay rom const float* ptr = &Buhlmann_ht[2*ci]; | 683 overlay rom const float* ptr = &Buhlmann_ht[2*ci]; |
684 var_N2_ht = *ptr++; | 684 var_N2_ht = *ptr++; |
685 var_He_ht = *ptr++; | 685 var_He_ht = *ptr++; |
686 } | 686 } |
687 | 687 |
688 assert( 4.0 <= var_N2_ht && var_N2_ht <= 635.0 ); | 688 assert( 4.0 <= var_N2_ht && var_N2_ht <= 635.0 ); |
689 assert( 1.5099 <= var_He_ht && var_He_ht <= 240.03 ); | 689 assert( 1.5099 <= var_He_ht && var_He_ht <= 240.03 ); |
690 } | 690 } |
691 | 691 |
692 ////////////////////////////////////////////////////////////////////////////// | 692 ////////////////////////////////////////////////////////////////////////////// |
693 ////////////////////////////////////////////////////////////////////////////// | 693 ////////////////////////////////////////////////////////////////////////////// |
694 //////////////// THE JUMP-IN CODE for the asm code //////////////// | 694 //////////////// THE JUMP-IN CODE for the asm code //////////////// |
1105 { | 1105 { |
1106 assert( 1 <= char_I_current_gas && char_I_current_gas <= 6 ); | 1106 assert( 1 <= char_I_current_gas && char_I_current_gas <= 6 ); |
1107 | 1107 |
1108 if( char_I_current_gas <= NUM_GAS ) // Gas 1-5 | 1108 if( char_I_current_gas <= NUM_GAS ) // Gas 1-5 |
1109 { | 1109 { |
1110 sim_gas_last_used = sim_gas_first_used = char_I_current_gas; | 1110 sim_gas_last_used = sim_gas_first_used = char_I_current_gas; |
1111 | 1111 sim_gas_last_depth = char_I_deco_gas_change[sim_gas_last_used-1]; // > 0 for OC deco gases, |
1112 // If current gas is a deco gas get it's change depth. | 1112 // > 0 for first & normal diluents, |
1113 // Set change depth to 0 if the current gas is the first gas or | 1113 // = 0 else |
1114 // a travel/normal gas, i.e. if it can be breathed at "any" depth. | |
1115 if( char_I_deco_gas_change[sim_gas_last_used-1] ) sim_gas_last_depth = char_I_deco_gas_change[sim_gas_last_used-1]; | |
1116 else sim_gas_last_depth = 0; | |
1117 } | 1114 } |
1118 else | 1115 else |
1119 { | 1116 { |
1120 sim_gas_last_used = sim_gas_first_used = 0; // Gas 6 (the manually set one) has number 0 here | 1117 sim_gas_last_used = sim_gas_first_used = 0; // Gas 6 (the manually set one) has number 0 here |
1121 sim_gas_last_depth = 0; // handle it as a travel/normal gas | 1118 sim_gas_last_depth = 0; // handle it as a travel/normal gas |
1122 } | 1119 } |
1123 } | 1120 } |
1124 | 1121 |
1125 | 1122 |
1126 ////////////////////////////////////////////////////////////////////////////// | 1123 ////////////////////////////////////////////////////////////////////////////// |
1253 // float_deco_distance : safety factor | 1250 // float_deco_distance : safety factor |
1254 // ppWater : water-vapor pressure inside respiratory tract | 1251 // ppWater : water-vapor pressure inside respiratory tract |
1255 // | 1252 // |
1256 // Output: ppN2 : respired N2 partial pressure | 1253 // Output: ppN2 : respired N2 partial pressure |
1257 // ppHe : respired He partial pressure | 1254 // ppHe : respired He partial pressure |
1255 // char_ppO2 : breathed ppO2 in %, to be used for CNS calculation | |
1258 // | 1256 // |
1259 void calc_alveolar_pressures(void) | 1257 void calc_alveolar_pressures(void) |
1260 { | 1258 { |
1261 overlay float pres_diluent; | 1259 overlay float pres_diluent; |
1262 overlay float calc_O2_ratio; | 1260 overlay float calc_O2_ratio; |
1451 static void calc_hauptroutine(void) | 1449 static void calc_hauptroutine(void) |
1452 { | 1450 { |
1453 overlay unsigned int int_ppO2_min; | 1451 overlay unsigned int int_ppO2_min; |
1454 overlay unsigned int int_ppO2_max; | 1452 overlay unsigned int int_ppO2_max; |
1455 overlay unsigned int int_ppO2_max_dil; | 1453 overlay unsigned int int_ppO2_max_dil; |
1456 | 1454 overlay float EAD; |
1457 //--- set-up part -------------------------------------------------------------------------------- | 1455 overlay float END; |
1456 | |
1457 | |
1458 //--- Set-up Part -------------------------------------------------------------------------------- | |
1458 | 1459 |
1459 // twosectimer: | 1460 // twosectimer: |
1460 // calc_hauptroutine is now invoked every second to speed up the deco planning. | 1461 // calc_hauptroutine is now invoked every second to speed up the deco planning. |
1461 // Because the tissue and CNS calculations are based on a 2 seconds period, the | 1462 // Because the tissue and CNS calculations are based on a two seconds period, a |
1462 // the following toggle-timer will be used by the respective routines to skip | 1463 // toggle-timer is used by the respective routines to skip every 2nd invocation. |
1463 // every 2nd invocation. | |
1464 twosectimer = (twosectimer) ? 0 : 1; // toggle the toggle-timer | 1464 twosectimer = (twosectimer) ? 0 : 1; // toggle the toggle-timer |
1465 | 1465 |
1466 | 1466 |
1467 // set up normal tissue updating or "fast forward" updating for simulator sim+5' function | 1467 // set up normal tissue updating or "fast forward" updating for simulator sim+5' function |
1468 // and deco calculator bottom time calculation | 1468 // and deco calculator bottom time calculation |
1480 tissue_increment = 0 // encoding for 2 seconds update | 1480 tissue_increment = 0 // encoding for 2 seconds update |
1481 | TISSUE_FLAG; // set flag for updating the "real" tissues & CNS | 1481 | TISSUE_FLAG; // set flag for updating the "real" tissues & CNS |
1482 } | 1482 } |
1483 | 1483 |
1484 | 1484 |
1485 //---- calculate the real tissue's data ----------------------------------------------------------------- | 1485 //---- Calculations Part ---------------------------------------------------------------------- |
1486 | 1486 |
1487 // acquire current environment data | 1487 // acquire current environment data |
1488 calc_hauptroutine_data_input(); | 1488 calc_hauptroutine_data_input(); |
1489 | 1489 |
1490 // update tissue pressures, also sets char_ppO2 for calc_CNS_increment() | |
1491 calc_hauptroutine_update_tissues(); | |
1492 | |
1493 // calculate CNS value increment for the real tissues | |
1494 calc_CNS_increment(); | |
1495 | |
1496 // update the CNS value for the real tissues | |
1497 CNS_fraction += CNS_fraction_inc; | |
1498 | |
1499 // compute integer copy of CNS value for display purpose | |
1500 convert_CNS_for_display(); | |
1501 | |
1502 | |
1503 //---- compute ppO2 warnings ------------------------------------------------------------------------------ | |
1504 | |
1505 // compute conditional min/max values | |
1506 int_ppO2_min = (char_O_main_status & DECO_MODE_LOOP) ? (unsigned int)char_I_ppO2_min_loop : (unsigned int)char_I_ppO2_min; | |
1507 int_ppO2_max = (char_O_deco_warnings & DECO_FLAG ) ? (unsigned int)char_I_ppO2_max_deco : (unsigned int)char_I_ppO2_max; | |
1508 | |
1509 // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold | |
1510 int_ppO2_max_dil = int_ppO2_max; | |
1511 | |
1512 // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint | |
1513 if( (char_O_main_status & DECO_MODE_MASK) == DECO_MODE_CCR ) | |
1514 { | |
1515 overlay unsigned int max_dil; | |
1516 | |
1517 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint... | |
1518 // (the condition protects from negative numbers which would cause a wrap-around) | |
1519 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned int)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0; | |
1520 | |
1521 // ...but never above int_ppO2_max. | |
1522 if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil; | |
1523 | |
1524 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check | |
1525 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks. | |
1526 } | |
1527 | |
1528 // check for safe range of pure oxygen | |
1529 if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1530 | |
1531 // check for safe range of breathed gas | |
1532 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; | |
1533 else if ( int_O_breathed_ppO2 >= int_ppO2_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1534 else if ( char_O_main_status & DECO_MODE_LOOP ) ; // no attention generated in loop modes | |
1535 else if ( int_O_breathed_ppO2 >= ppO2_ATTENTION_THRESHOLD ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION; | |
1536 | |
1537 // check for safe range of pure diluent | |
1538 if ( int_O_pure_ppO2 <= (unsigned int)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; | |
1539 else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1540 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION; | |
1541 | |
1542 // check for safe range of calculated pSCR loop gas | |
1543 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; | |
1544 else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1545 | |
1546 | |
1547 | |
1548 //---- toggle between calculation for NDL (bottom time), ------ | |
1549 //---- deco stops and more deco stops (continue) ------ | |
1550 | |
1551 | |
1552 // done with the real tissues, all following operations | |
1553 // target the simulated tissues so clear flag in bit 7 | |
1554 tissue_increment = 0; | |
1555 | |
1556 // branch to the code for the current phase the deco calculations are in | |
1557 switch( char_O_deco_status & DECO_STATUS_MASK ) | |
1558 { | |
1559 overlay unsigned char i; | |
1560 | |
1561 case DECO_STATUS_INIT: //---- At surface: Start a new dive --------------------- | |
1562 | |
1563 // clear the internal stops table from remains lasting from the last dive | |
1564 clear_deco_table(); | |
1565 | |
1566 // publish the cleared stops table to the display functions | |
1567 publish_deco_table(); | |
1568 | |
1569 // clear the gas needs table | |
1570 for(i=0; i<NUM_GAS; ++i) | |
1571 { | |
1572 int_O_gas_volumes[i] = 0; | |
1573 int_O_tank_pres_need[i] = 0 + INT_FLAG_ZERO; | |
1574 } | |
1575 | |
1576 // initialize the balancing between N2 and He for later no-fly time calculation | |
1577 for(i=0; i<NUM_COMP; ++i) | |
1578 { | |
1579 split_N2_He[i] = 90; // assumes 90% of total tissue pressure will be needed for N2 | |
1580 } | |
1581 | |
1582 // ** UNDER CONSTRUCTION - temporary code only ** | |
1583 char_I_gas_change_time = 1; // TODO: validate proper operation before enabling this options-table parameter | |
1584 char_I_ascent_speed = 10; // TODO: validate proper operation before enabling this options-table parameter, | |
1585 // caution: values < 10 may have an impact on the deco calculation run-times! | |
1586 | |
1587 // initialize values that are constant during the course of the dive | |
1588 float_ascent_speed = 1.00 * char_I_ascent_speed; | |
1589 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier; | |
1590 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier; | |
1591 float_deco_distance = 0.01 * char_I_deco_distance; | |
1592 | |
1593 // initialize values that will be recalculated later on periodically | |
1594 char_O_nullzeit = 0; // reset NDL time for the normal plan | |
1595 char_O_alternate_nullzeit = 0; // reset NDL time for the alternative plan | |
1596 int_O_ascenttime = 0; // reset ascent time for the normal plan | |
1597 int_O_alternate_ascenttime = 0; // reset ascent time for the alternative plan | |
1598 char_O_deco_warnings = 0; // reset all deco warnings | |
1599 deco_tissue_vector = 0; // reset tissue deco vector | |
1600 IBCD_tissue_vector = 0; // reset tissue IBCD vector | |
1601 NDL_lead_tissue = 0; // reset first tissue to look at during NDL calculation | |
1602 | |
1603 // tag desaturation time as invalid (it will not be computed during a dive) | |
1604 int_O_desaturation_time = 65535; | |
1605 | |
1606 // initialize CNS values | |
1607 int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = int_O_CNS_fraction; | |
1608 | |
1609 // Values that should be reset just once for the full real dive. | |
1610 // This is used to record the lowest stop for the whole dive, | |
1611 // including ACCROSS all simulated ascents. | |
1612 low_depth_norm = low_depth_alt = 0.0; | |
1613 locked_GF_step_norm = locked_GF_step_alt = 0.0; | |
1614 | |
1615 // | |
1616 // --> code execution continues in state DECO_STATUS_START | |
1617 // | |
1618 | |
1619 case DECO_STATUS_START: //---- Bottom Time & initial Ascent -------------------- | |
1620 default: | |
1621 | |
1622 // clear the internal(!) stops table | |
1623 clear_deco_table(); | |
1624 | |
1625 // initialize the simulated tissues with the current state of the real tissues | |
1626 for(i=0; i<NUM_COMP; i++) | |
1627 { | |
1628 sim_pres_tissue_N2[i] = pres_tissue_N2[i]; | |
1629 sim_pres_tissue_He[i] = pres_tissue_He[i]; | |
1630 } | |
1631 | |
1632 // Lookup the current gas and store it also as the first gas used. | |
1633 // This gas will be used for the bottom segment of the dive and for | |
1634 // the period of delayed ascent when calculating fTTS or bailout. | |
1635 gas_find_current(); | |
1636 | |
1637 // setup the calculation ratio's for N2, He and O2 (sim_N2/He/O2_ratio) | |
1638 gas_set_ratios(); | |
1639 | |
1640 // initialize depth in absolute pressure, it is needed by | |
1641 // - calc_alveolar_pressures(), | |
1642 // - calc_ascent_to_first_stop(), and | |
1643 // - calc_hauptroutine_calc_deco() | |
1644 sim_pres_respiration = pres_respiration; | |
1645 | |
1646 // calculate ppN2 and ppHe from sim_N2/He_ratio (<- tissue_increment has been set to 0) | |
1647 calc_alveolar_pressures(); | |
1648 | |
1649 // calculate the effect of extended bottom time due to delayed ascent | |
1650 if( char_O_deco_status & DECO_ASCENT_DELAYED ) | |
1651 { | |
1652 // program interval on simulated tissues (flag bit 7 = 0) | |
1653 tissue_increment = char_I_extra_time; | |
1654 | |
1655 // update the tissues | |
1656 calc_tissues(); | |
1657 } | |
1658 | |
1659 // calculate if we are within no decompression limit (NDL) | |
1660 calc_NDL_time(); | |
1661 | |
1662 // Calculate the initial ascent if in deco. calc_NDL_time() is very fast | |
1663 // in detecting being beyond NDL, so there is enough time left in this | |
1664 // phase to do the initial ascent calculation. | |
1665 if( NDL_time == 0 ) | |
1666 { | |
1667 //--- in deco -------------------------------------------------------- | |
1668 | |
1669 // calculate ascent to first stop | |
1670 calc_ascent_to_first_stop(); | |
1671 | |
1672 // continue with calculating the stops | |
1673 char_O_deco_status &= ~DECO_STATUS_MASK; // clear status bits and set status bits for | |
1674 char_O_deco_status |= DECO_STATUS_STOPS; // calculation of stops on next invocation | |
1675 } | |
1676 else | |
1677 { | |
1678 //--- within NDL ----------------------------------------------------- | |
1679 | |
1680 // continue with gathering all results | |
1681 char_O_deco_status &= ~DECO_STATUS_MASK; | |
1682 char_O_deco_status |= DECO_STATUS_RESULTS; | |
1683 } | |
1684 | |
1685 break; | |
1686 | |
1687 | |
1688 case DECO_STATUS_STOPS: //---- Calculate Stops --------------------------------- | |
1689 | |
1690 // calculate the stops | |
1691 calc_hauptroutine_calc_deco(); | |
1692 | |
1693 // calc_hauptroutine_calc_deco iterates in this phase as long as it is | |
1694 // calculating the stops. Once done, it will set the status to doing the | |
1695 // results gathering. | |
1696 | |
1697 break; | |
1698 | |
1699 | |
1700 case DECO_STATUS_RESULTS: //--- Gathering of all Results ----------------------- | |
1701 | |
1702 // if in normal plan, publish the stops table to the display functions | |
1703 if( !(char_O_deco_status & DECO_PLAN_ALTERNATE) ) publish_deco_table(); | |
1704 | |
1705 // The current depth is needed by calc_CNS_planning() and gas_volumes(). | |
1706 // As it may be needed in different code blocks below but we don't want | |
1707 // it to be in the code multiple times, it's done here on stockpile. | |
1708 bottom_depth = (unsigned char)((pres_respiration - pres_surface) * BAR_TO_METER); | |
1709 | |
1710 // Calculate the ascent time. | |
1711 // When within NDL, potential gas switches will be treated as done "on the fly". | |
1712 calc_ascenttime(); | |
1713 | |
1714 // results to publish depend whether within NDL or in deco | |
1715 if( NDL_time ) | |
1716 { | |
1717 //---- within NDL ---------------------------------------------- | |
1718 | |
1719 // Calculate the initial ascent (not yet done when within NDL) - | |
1720 // just to get potential gas switches into the stops table for use | |
1721 // by gas_volumes(). The stops table can be polluted by now because | |
1722 // the clean table has already been published to the display | |
1723 // functions before. | |
1724 calc_ascent_to_first_stop(); | |
1725 | |
1726 // check which plan we are on | |
1727 if( char_O_deco_status & DECO_PLAN_ALTERNATE ) | |
1728 { | |
1729 //---- alternate dive plan --------------------------------- | |
1730 | |
1731 // As we are in no stop, CNS at end of dive is more or less | |
1732 // the same CNS as we have right now. It's so simple that we | |
1733 // don't check if it requested to be computed or not... | |
1734 int_O_alternate_CNS_fraction = int_O_CNS_fraction; | |
1735 | |
1736 // output NDL time | |
1737 char_O_alternate_nullzeit = NDL_time; | |
1738 | |
1739 // clear ascent time | |
1740 int_O_alternate_ascenttime = 0; | |
1741 } | |
1742 else | |
1743 { | |
1744 //---- normal dive plan ------------------------------------ | |
1745 | |
1746 // As we are in no stop, CNS at end of dive is more or less | |
1747 // the same CNS as we have right now. It's so simple that we | |
1748 // don't check if it requested to be computed or not... | |
1749 int_O_normal_CNS_fraction = int_O_CNS_fraction; | |
1750 | |
1751 // output NDL time | |
1752 char_O_nullzeit = NDL_time; | |
1753 | |
1754 // clear ascent time | |
1755 int_O_ascenttime = 0; | |
1756 } | |
1757 } // NDL | |
1758 else | |
1759 { | |
1760 //---- in DECO ------------------------------------------------- | |
1761 | |
1762 // check which plan we are on | |
1763 if( char_O_deco_status & DECO_PLAN_ALTERNATE ) | |
1764 { | |
1765 //---- alternative plan ---------------------------------------------------- | |
1766 | |
1767 // shall the CNS at the end of the dive be calculated? | |
1768 if( char_O_deco_status & DECO_CNS_CALCULATE ) | |
1769 { | |
1770 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction | |
1771 calc_CNS_planning(); | |
1772 | |
1773 // add current CNS value | |
1774 sim_CNS_fraction += CNS_fraction; | |
1775 | |
1776 // convert to integer value | |
1777 convert_sim_CNS_for_display(); | |
1778 | |
1779 // export result | |
1780 int_O_alternate_CNS_fraction = int_sim_CNS_fraction; | |
1781 } | |
1782 | |
1783 // clear NDL time | |
1784 char_O_alternate_nullzeit = 0; | |
1785 | |
1786 // output ascent time | |
1787 int_O_alternate_ascenttime = ascent_time; | |
1788 | |
1789 } // alternative plan | |
1790 else | |
1791 { | |
1792 //---- normal plan --------------------------------------------------------- | |
1793 | |
1794 // shall the CNS at the end of the dive be calculated? | |
1795 if( char_O_deco_status & DECO_CNS_CALCULATE ) | |
1796 { | |
1797 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction | |
1798 calc_CNS_planning(); | |
1799 | |
1800 // add current CNS value | |
1801 sim_CNS_fraction += CNS_fraction; | |
1802 | |
1803 // convert to integer value | |
1804 convert_sim_CNS_for_display(); | |
1805 | |
1806 // export result | |
1807 int_O_normal_CNS_fraction = int_sim_CNS_fraction; | |
1808 } | |
1809 | |
1810 // clear NDL time | |
1811 char_O_nullzeit = 0; | |
1812 | |
1813 // output ascent time | |
1814 int_O_ascenttime = ascent_time; | |
1815 | |
1816 } // normal plan | |
1817 } // DECO | |
1818 | |
1819 // if requested, calculate the required gas volumes and tank pressures at the end of the dive | |
1820 if( char_O_deco_status & DECO_VOLUME_CALCULATE ) gas_volumes(); | |
1821 | |
1822 // signal that the computation cycle is finished | |
1823 char_O_deco_status &= ~DECO_STATUS_MASK; | |
1824 | |
1825 break; | |
1826 | |
1827 } // switch | |
1828 } | |
1829 | |
1830 ////////////////////////////////////////////////////////////////////////////// | |
1831 // calc_hauptroutine_data_input | |
1832 // | |
1833 // Set all C-code dive parameters from their ASM-code values. | |
1834 // Detect gas change condition. | |
1835 // | |
1836 void calc_hauptroutine_data_input(void) | |
1837 { | |
1838 overlay float IG_ratio; | |
1839 | |
1840 // get the current pressures | |
1841 pres_surface = 0.001 * int_I_pres_surface; | |
1842 pres_respiration = 0.001 * int_I_pres_respiration; | |
1843 | |
1844 // N2 tissue pressure at surface equilibrium, used for tissue graphics scaling | |
1845 N2_equilibrium = 0.7902 * (pres_surface - ppWater); | |
1846 | |
1847 // read the GF settings (they may have been switch between GF/aGF) | |
1848 GF_high = 0.01 * char_I_GF_High_percentage; | |
1849 GF_low = 0.01 * char_I_GF_Low_percentage; | |
1850 GF_delta = GF_high - GF_low; | |
1851 | |
1852 // get the currently breathed gas mixture | |
1853 O2_ratio = 0.01 * char_I_O2_ratio; | |
1854 He_ratio = 0.01 * char_I_He_ratio; | |
1855 | |
1856 // inert gas ratio (local helper variable) | |
1857 IG_ratio = 1.00 - O2_ratio; | |
1858 | |
1859 // N2 ratio | |
1860 N2_ratio = IG_ratio - He_ratio; | |
1861 | |
1862 // precomputed values for ppO2 drop in pSCR loop | |
1863 float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio; | |
1864 pSCR_drop = IG_ratio * float_pSCR_factor; | |
1865 } | |
1866 | |
1867 ////////////////////////////////////////////////////////////////////////////// | |
1868 // | |
1869 // | |
1870 void calc_hauptroutine_update_tissues(void) | |
1871 { | |
1872 overlay float EAD, END; | |
1873 | |
1874 //---- calculations part ---------------------------------------------------------------------- | |
1875 | |
1876 // calculate ppN2 and ppHe | 1490 // calculate ppN2 and ppHe |
1877 calc_alveolar_pressures(); | 1491 calc_alveolar_pressures(); |
1878 | 1492 |
1879 // calculate the tissues | 1493 // All deco code is invoked every second. But as the tissue and CNS updates are based |
1880 calc_tissues(); | 1494 // on 2 seconds periods, each update is done only on each 2nd second. |
1881 | 1495 // In case a "fast forward" of the tissues is commanded, the 2-seconds rule is over raided. |
1882 // calculate ceiling (at GF_high) and current GF | 1496 // To distribute computational load, updating of tissues and CNS is done in alternation. |
1883 calc_limit(GF_high); | 1497 if( twosectimer || (tissue_increment & TIME_MASK) ) |
1498 { | |
1499 // calculate the real tissues | |
1500 calc_tissues(); | |
1501 | |
1502 // calculate ceiling (at GF_high) and current GF | |
1503 calc_limit(GF_high); | |
1504 } | |
1505 | |
1506 if( !twosectimer || (tissue_increment & TIME_MASK) ) | |
1507 { | |
1508 // calculate CNS value increment for the real tissues | |
1509 calc_CNS_increment(); | |
1510 | |
1511 // increment CNS value of the real tissues | |
1512 CNS_fraction += CNS_fraction_inc; | |
1513 | |
1514 // compute integer copy of CNS value for display purpose | |
1515 convert_CNS_for_display(); | |
1516 } | |
1517 | |
1518 | |
1519 //---- Calculate and Export EAD and END ------------------------------------------------------ | |
1884 | 1520 |
1885 // calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air | 1521 // calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air |
1886 EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER; | 1522 EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER; |
1887 | 1523 |
1888 // calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too | 1524 // calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too |
1889 // Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott, | 1525 // Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott, |
1890 // 4th edition, 1993, W.B.Saunders Company Ltd, London. | 1526 // 4th edition, 1993, W.B.Saunders Company Ltd, London. |
1891 END = (pres_respiration - ppHe - pres_surface) * BAR_TO_METER; | 1527 END = (pres_respiration - ppHe - pres_surface) * BAR_TO_METER; |
1892 | 1528 |
1893 | 1529 // export EAD |
1894 //---- export ppO2 values in [cbar] for warning generation and display purpose ---------------- | 1530 if( (EAD < 0.0) || (EAD > 245.5) ) char_O_EAD = 0; |
1531 else char_O_EAD = (unsigned char)(EAD + 0.5); | |
1532 | |
1533 // export END | |
1534 if( (END < 0.0) || (END > 245.5) ) char_O_END = 0; | |
1535 else char_O_END = (unsigned char)(END + 0.5); | |
1536 | |
1537 | |
1538 //---- Compute ppO2 Values in [cbar] --------------------------------------------------------- | |
1895 | 1539 |
1896 // pure oxygen ppO2 | 1540 // pure oxygen ppO2 |
1897 if ( O2_ppO2 < 0.01 ) int_O_O2_ppO2 = 0; | 1541 if ( O2_ppO2 < 0.01 ) int_O_O2_ppO2 = 0; |
1898 else if ( O2_ppO2 >= 9.995 ) int_O_O2_ppO2 = 999; | 1542 else if ( O2_ppO2 >= 9.995 ) int_O_O2_ppO2 = 999; |
1899 else int_O_O2_ppO2 = (unsigned int)(100 * O2_ppO2 + 0.5); | 1543 else int_O_O2_ppO2 = (unsigned int)(100 * O2_ppO2 + 0.5); |
1912 if ( ppO2 < 0.01 ) int_O_breathed_ppO2 = 0; | 1556 if ( ppO2 < 0.01 ) int_O_breathed_ppO2 = 0; |
1913 else if ( ppO2 >= 9.995 ) int_O_breathed_ppO2 = 999; | 1557 else if ( ppO2 >= 9.995 ) int_O_breathed_ppO2 = 999; |
1914 else int_O_breathed_ppO2 = (unsigned int)(100 * ppO2 + 0.5); | 1558 else int_O_breathed_ppO2 = (unsigned int)(100 * ppO2 + 0.5); |
1915 | 1559 |
1916 | 1560 |
1917 //---- export EAD and END --------------------------------------------------------------------- | 1561 //---- Compute ppO2 Warnings ------------------------------------------------------------------ |
1918 | 1562 |
1919 // EAD | 1563 // compute conditional min/max values |
1920 if( (EAD < 0.0) || (EAD > 245.5) ) char_O_EAD = 0; | 1564 int_ppO2_min = (char_O_main_status & DECO_MODE_LOOP) ? (unsigned int)char_I_ppO2_min_loop : (unsigned int)char_I_ppO2_min; |
1921 else char_O_EAD = (unsigned char)(EAD + 0.5); | 1565 int_ppO2_max = (char_O_deco_warnings & DECO_FLAG ) ? (unsigned int)char_I_ppO2_max_deco : (unsigned int)char_I_ppO2_max; |
1922 | 1566 |
1923 // END | 1567 // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold |
1924 if( (END < 0.0) || (END > 245.5) ) char_O_END = 0; | 1568 int_ppO2_max_dil = int_ppO2_max; |
1925 else char_O_END = (unsigned char)(END + 0.5); | 1569 |
1570 // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint | |
1571 if( (char_O_main_status & DECO_MODE_MASK) == DECO_MODE_CCR ) | |
1572 { | |
1573 overlay unsigned int max_dil; | |
1574 | |
1575 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint... | |
1576 // (the condition protects from negative numbers which would cause a wrap-around) | |
1577 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned int)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0; | |
1578 | |
1579 // ...but never above int_ppO2_max. | |
1580 if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil; | |
1581 | |
1582 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check | |
1583 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks. | |
1584 } | |
1585 | |
1586 // check for safe range of pure oxygen | |
1587 if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1588 | |
1589 // check for safe range of breathed gas | |
1590 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; | |
1591 else if ( int_O_breathed_ppO2 >= int_ppO2_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1592 else if ( char_O_main_status & DECO_MODE_LOOP ) ; // no attention generated in loop modes | |
1593 else if ( int_O_breathed_ppO2 >= ppO2_ATTENTION_THRESHOLD ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION; | |
1594 | |
1595 // check for safe range of pure diluent | |
1596 if ( int_O_pure_ppO2 <= (unsigned int)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; | |
1597 else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1598 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION; | |
1599 | |
1600 // check for safe range of calculated pSCR loop gas | |
1601 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; | |
1602 else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; | |
1603 | |
1604 | |
1605 // done with the real tissues | |
1606 | |
1607 | |
1608 | |
1609 //---- Toggle between Calculation for NDL (bottom time), ------------------------------------- | |
1610 //---- Deco Stops, more Deco Stops and Results Gathering ------------------------------------- | |
1611 | |
1612 | |
1613 // all following operations target the simulated tissues, so clear flag in bit 7 | |
1614 tissue_increment = 0; | |
1615 | |
1616 // branch to the code for the current phase the deco calculations are in | |
1617 switch( char_O_deco_status & DECO_STATUS_MASK ) | |
1618 { | |
1619 overlay unsigned char i; | |
1620 | |
1621 case DECO_STATUS_INIT: //---- At surface: Start a new dive --------------------- | |
1622 | |
1623 // clear the internal stops table from remains lasting from the last dive | |
1624 clear_deco_table(); | |
1625 | |
1626 // publish the cleared stops table to the display functions | |
1627 publish_deco_table(); | |
1628 | |
1629 // clear the gas needs table | |
1630 for(i=0; i<NUM_GAS; ++i) | |
1631 { | |
1632 int_O_gas_volumes[i] = 0; | |
1633 int_O_tank_pres_need[i] = 0 + INT_FLAG_ZERO; | |
1634 } | |
1635 | |
1636 // initialize the balancing between N2 and He for later no-fly time calculation | |
1637 for(i=0; i<NUM_COMP; ++i) | |
1638 { | |
1639 split_N2_He[i] = 90; // assumes 90% of total tissue pressure will be needed for N2 | |
1640 } | |
1641 | |
1642 // ** UNDER CONSTRUCTION - temporary code only ** | |
1643 char_I_gas_change_time = 1; // TODO: validate proper operation before enabling this options-table parameter | |
1644 char_I_ascent_speed = 10; // TODO: validate proper operation before enabling this options-table parameter, | |
1645 // caution: values < 10 may have an impact on the deco calculation run-times! | |
1646 | |
1647 // initialize values that are constant during the course of the dive | |
1648 float_ascent_speed = 1.00 * char_I_ascent_speed; | |
1649 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier; | |
1650 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier; | |
1651 float_deco_distance = 0.01 * char_I_deco_distance; | |
1652 | |
1653 // initialize values that will be recalculated later on periodically | |
1654 char_O_nullzeit = 0; // reset NDL time for the normal plan | |
1655 char_O_alternate_nullzeit = 0; // reset NDL time for the alternative plan | |
1656 int_O_ascenttime = 0; // reset ascent time for the normal plan | |
1657 int_O_alternate_ascenttime = 0; // reset ascent time for the alternative plan | |
1658 char_O_deco_warnings = 0; // reset all deco warnings | |
1659 deco_tissue_vector = 0; // reset tissue deco vector | |
1660 IBCD_tissue_vector = 0; // reset tissue IBCD vector | |
1661 NDL_lead_tissue = 0; // reset first tissue to look at during NDL calculation | |
1662 | |
1663 // tag desaturation time as invalid (it will not be computed during a dive) | |
1664 int_O_desaturation_time = 65535; | |
1665 | |
1666 // initialize CNS values | |
1667 int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = int_O_CNS_fraction; | |
1668 | |
1669 // Values that should be reset just once for the full real dive. | |
1670 // This is used to record the lowest stop for the whole dive, | |
1671 // including ACCROSS all simulated ascents. | |
1672 low_depth_norm = low_depth_alt = 0.0; | |
1673 locked_GF_step_norm = locked_GF_step_alt = 0.0; | |
1674 | |
1675 // | |
1676 // --> code execution continues in state DECO_STATUS_START | |
1677 // | |
1678 | |
1679 case DECO_STATUS_START: //---- Bottom Time & initial Ascent -------------------- | |
1680 default: | |
1681 | |
1682 // clear the internal(!) stops table | |
1683 clear_deco_table(); | |
1684 | |
1685 // initialize the simulated tissues with the current state of the real tissues | |
1686 for(i=0; i<NUM_COMP; i++) | |
1687 { | |
1688 sim_pres_tissue_N2[i] = pres_tissue_N2[i]; | |
1689 sim_pres_tissue_He[i] = pres_tissue_He[i]; | |
1690 } | |
1691 | |
1692 // Lookup the current gas and store it also as the first gas used. | |
1693 // This gas will be used for the bottom segment of the dive and for | |
1694 // the period of delayed ascent when calculating fTTS or bailout. | |
1695 gas_find_current(); | |
1696 | |
1697 // setup the calculation ratio's for N2, He and O2 (sim_N2/He/O2_ratio) | |
1698 gas_set_ratios(); | |
1699 | |
1700 // initialize depth in absolute pressure, it is needed by | |
1701 // - calc_alveolar_pressures(), | |
1702 // - calc_ascent_to_first_stop(), and | |
1703 // - calc_hauptroutine_calc_deco() | |
1704 sim_pres_respiration = pres_respiration; | |
1705 | |
1706 // calculate ppN2 and ppHe from sim_N2/He_ratio (<- tissue_increment has been set to 0) | |
1707 calc_alveolar_pressures(); | |
1708 | |
1709 // calculate the effect of extended bottom time due to delayed ascent | |
1710 if( char_O_deco_status & DECO_ASCENT_DELAYED ) | |
1711 { | |
1712 // program interval on simulated tissues (flag bit 7 = 0) | |
1713 tissue_increment = char_I_extra_time; | |
1714 | |
1715 // update the tissues | |
1716 calc_tissues(); | |
1717 } | |
1718 | |
1719 // calculate if we are within no decompression limit (NDL) | |
1720 calc_NDL_time(); | |
1721 | |
1722 // Calculate the initial ascent if in deco. calc_NDL_time() is very fast | |
1723 // in detecting being beyond NDL, so there is enough time left in this | |
1724 // phase to do the initial ascent calculation. | |
1725 if( NDL_time == 0 ) | |
1726 { | |
1727 //--- in deco -------------------------------------------------------- | |
1728 | |
1729 // calculate ascent to first stop | |
1730 calc_ascent_to_first_stop(); | |
1731 | |
1732 // continue with calculating the stops | |
1733 char_O_deco_status &= ~DECO_STATUS_MASK; // clear status bits and set status bits for | |
1734 char_O_deco_status |= DECO_STATUS_STOPS; // calculation of stops on next invocation | |
1735 } | |
1736 else | |
1737 { | |
1738 //--- within NDL ----------------------------------------------------- | |
1739 | |
1740 // continue with gathering all results | |
1741 char_O_deco_status &= ~DECO_STATUS_MASK; | |
1742 char_O_deco_status |= DECO_STATUS_RESULTS; | |
1743 } | |
1744 | |
1745 break; | |
1746 | |
1747 | |
1748 case DECO_STATUS_STOPS: //---- Calculate Stops --------------------------------- | |
1749 | |
1750 // calculate the stops | |
1751 calc_hauptroutine_calc_deco(); | |
1752 | |
1753 // calc_hauptroutine_calc_deco iterates in this phase as long as it is | |
1754 // calculating the stops. Once done, it will set the status to doing the | |
1755 // results gathering. | |
1756 | |
1757 break; | |
1758 | |
1759 | |
1760 case DECO_STATUS_RESULTS: //--- Gathering of all Results ----------------------- | |
1761 | |
1762 // if in normal plan, publish the stops table to the display functions | |
1763 if( !(char_O_deco_status & DECO_PLAN_ALTERNATE) ) publish_deco_table(); | |
1764 | |
1765 // The current depth is needed by calc_CNS_planning() and gas_volumes(). | |
1766 // As it may be needed in different code blocks below but we don't want | |
1767 // it to be in the code multiple times, it's done here on stockpile. | |
1768 bottom_depth = (unsigned char)((pres_respiration - pres_surface) * BAR_TO_METER); | |
1769 | |
1770 // Calculate the ascent time. | |
1771 // When within NDL, potential gas switches will be treated as done "on the fly". | |
1772 calc_ascenttime(); | |
1773 | |
1774 // results to publish depend whether within NDL or in deco | |
1775 if( NDL_time ) | |
1776 { | |
1777 //---- within NDL ---------------------------------------------- | |
1778 | |
1779 // Calculate the initial ascent (not yet done when within NDL) - | |
1780 // just to get potential gas switches into the stops table for use | |
1781 // by gas_volumes(). The stops table can be polluted by now because | |
1782 // the clean table has already been published to the display | |
1783 // functions before. | |
1784 calc_ascent_to_first_stop(); | |
1785 | |
1786 // check which plan we are on | |
1787 if( char_O_deco_status & DECO_PLAN_ALTERNATE ) | |
1788 { | |
1789 //---- alternate dive plan --------------------------------- | |
1790 | |
1791 // As we are in no stop, CNS at end of dive is more or less | |
1792 // the same CNS as we have right now. It's so simple that we | |
1793 // don't check if it requested to be computed or not... | |
1794 int_O_alternate_CNS_fraction = int_O_CNS_fraction; | |
1795 | |
1796 // output NDL time | |
1797 char_O_alternate_nullzeit = NDL_time; | |
1798 | |
1799 // clear ascent time | |
1800 int_O_alternate_ascenttime = 0; | |
1801 } | |
1802 else | |
1803 { | |
1804 //---- normal dive plan ------------------------------------ | |
1805 | |
1806 // As we are in no stop, CNS at end of dive is more or less | |
1807 // the same CNS as we have right now. It's so simple that we | |
1808 // don't check if it requested to be computed or not... | |
1809 int_O_normal_CNS_fraction = int_O_CNS_fraction; | |
1810 | |
1811 // output NDL time | |
1812 char_O_nullzeit = NDL_time; | |
1813 | |
1814 // clear ascent time | |
1815 int_O_ascenttime = 0; | |
1816 } | |
1817 } // NDL | |
1818 else | |
1819 { | |
1820 //---- in DECO ------------------------------------------------- | |
1821 | |
1822 // check which plan we are on | |
1823 if( char_O_deco_status & DECO_PLAN_ALTERNATE ) | |
1824 { | |
1825 //---- alternative plan ---------------------------------------------------- | |
1826 | |
1827 // shall the CNS at the end of the dive be calculated? | |
1828 if( char_O_deco_status & DECO_CNS_CALCULATE ) | |
1829 { | |
1830 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction | |
1831 calc_CNS_planning(); | |
1832 | |
1833 // add current CNS value | |
1834 sim_CNS_fraction += CNS_fraction; | |
1835 | |
1836 // convert to integer value | |
1837 convert_sim_CNS_for_display(); | |
1838 | |
1839 // export result | |
1840 int_O_alternate_CNS_fraction = int_sim_CNS_fraction; | |
1841 } | |
1842 | |
1843 // clear NDL time | |
1844 char_O_alternate_nullzeit = 0; | |
1845 | |
1846 // output ascent time | |
1847 int_O_alternate_ascenttime = ascent_time; | |
1848 | |
1849 } // alternative plan | |
1850 else | |
1851 { | |
1852 //---- normal plan --------------------------------------------------------- | |
1853 | |
1854 // shall the CNS at the end of the dive be calculated? | |
1855 if( char_O_deco_status & DECO_CNS_CALCULATE ) | |
1856 { | |
1857 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction | |
1858 calc_CNS_planning(); | |
1859 | |
1860 // add current CNS value | |
1861 sim_CNS_fraction += CNS_fraction; | |
1862 | |
1863 // convert to integer value | |
1864 convert_sim_CNS_for_display(); | |
1865 | |
1866 // export result | |
1867 int_O_normal_CNS_fraction = int_sim_CNS_fraction; | |
1868 } | |
1869 | |
1870 // clear NDL time | |
1871 char_O_nullzeit = 0; | |
1872 | |
1873 // output ascent time | |
1874 int_O_ascenttime = ascent_time; | |
1875 | |
1876 } // normal plan | |
1877 } // DECO | |
1878 | |
1879 // if requested, calculate the required gas volumes and tank pressures at the end of the dive | |
1880 if( char_O_deco_status & DECO_VOLUME_CALCULATE ) gas_volumes(); | |
1881 | |
1882 // signal that the computation cycle is finished | |
1883 char_O_deco_status &= ~DECO_STATUS_MASK; | |
1884 | |
1885 break; | |
1886 | |
1887 } // switch | |
1888 } | |
1889 | |
1890 ////////////////////////////////////////////////////////////////////////////// | |
1891 // calc_hauptroutine_data_input | |
1892 // | |
1893 // Set all C-code dive parameters from their ASM-code values. | |
1894 // Detect gas change condition. | |
1895 // | |
1896 void calc_hauptroutine_data_input(void) | |
1897 { | |
1898 overlay float IG_ratio; | |
1899 | |
1900 // get the current pressures | |
1901 pres_surface = 0.001 * int_I_pres_surface; | |
1902 pres_respiration = 0.001 * int_I_pres_respiration; | |
1903 | |
1904 // N2 tissue pressure at surface equilibrium, used for tissue graphics scaling | |
1905 N2_equilibrium = 0.7902 * (pres_surface - ppWater); | |
1906 | |
1907 // read the GF settings (they may have been switch between GF/aGF) | |
1908 GF_high = 0.01 * char_I_GF_High_percentage; | |
1909 GF_low = 0.01 * char_I_GF_Low_percentage; | |
1910 GF_delta = GF_high - GF_low; | |
1911 | |
1912 // get the currently breathed gas mixture | |
1913 O2_ratio = 0.01 * char_I_O2_ratio; | |
1914 He_ratio = 0.01 * char_I_He_ratio; | |
1915 | |
1916 // inert gas ratio (local helper variable) | |
1917 IG_ratio = 1.00 - O2_ratio; | |
1918 | |
1919 // N2 ratio | |
1920 N2_ratio = IG_ratio - He_ratio; | |
1921 | |
1922 // precomputed values for ppO2 drop in pSCR loop | |
1923 float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio; | |
1924 pSCR_drop = IG_ratio * float_pSCR_factor; | |
1926 } | 1925 } |
1927 | 1926 |
1928 | 1927 |
1929 ////////////////////////////////////////////////////////////////////////////// | 1928 ////////////////////////////////////////////////////////////////////////////// |
1930 // Compute stops. | 1929 // Compute stops. |
2171 | 2170 |
2172 temp_tissue_safety(); | 2171 temp_tissue_safety(); |
2173 | 2172 |
2174 if( tissue_increment & TISSUE_FLAG ) | 2173 if( tissue_increment & TISSUE_FLAG ) |
2175 { | 2174 { |
2176 // The temp variable takes on purpose just the tissue increment from the last loop's iteration. | 2175 temp_tissue_N2 = temp_tissue; |
2177 temp_tissue_N2 = temp_tissue; | 2176 pres_tissue_N2[ci] += temp_tissue; |
2178 | |
2179 // Update the real tissues if either we are on the 2 seconds interval, | |
2180 // or if we shall advance the tissues on a one or several minutes basis. | |
2181 if( twosectimer || (tissue_increment & TIME_MASK) ) pres_tissue_N2[ci] += temp_tissue; | |
2182 } | 2177 } |
2183 else | 2178 else |
2184 { | 2179 { |
2185 // Updates of the sim-tissues always comes on a 1 minutes basis, | |
2186 // so we do not need to check of the 2 seconds interval. | |
2187 sim_pres_tissue_N2[ci] += temp_tissue; | 2180 sim_pres_tissue_N2[ci] += temp_tissue; |
2188 } | 2181 } |
2189 | 2182 |
2190 | 2183 |
2191 //---- He ------------------------------------------------------------------------------- | 2184 //---- He ------------------------------------------------------------------------------- |
2196 | 2189 |
2197 temp_tissue_safety(); | 2190 temp_tissue_safety(); |
2198 | 2191 |
2199 if( tissue_increment & TISSUE_FLAG ) | 2192 if( tissue_increment & TISSUE_FLAG ) |
2200 { | 2193 { |
2201 // The temp variable takes on purpose just the tissue increment from the last loop's iteration. | 2194 temp_tissue_He = temp_tissue; |
2202 temp_tissue_He = temp_tissue; | 2195 pres_tissue_He[ci] += temp_tissue; |
2203 | |
2204 // Update the real tissues if either we are on the 2 seconds interval, | |
2205 // or if we shall advance the tissues on a one or several minutes basis. | |
2206 if( twosectimer || (tissue_increment & TIME_MASK) ) pres_tissue_He[ci] += temp_tissue; | |
2207 } | 2196 } |
2208 else | 2197 else |
2209 { | 2198 { |
2210 // Updates of the sim-tissues always comes on a 1 minutes basis, | |
2211 // so we do not need to check of the 2 seconds interval. | |
2212 sim_pres_tissue_He[ci] += temp_tissue; | 2199 sim_pres_tissue_He[ci] += temp_tissue; |
2213 } | 2200 } |
2214 | 2201 |
2215 // decrement loop counter | 2202 // decrement loop counter |
2216 i -= period; | 2203 i -= period; |
2224 } | 2211 } |
2225 while( i ); | 2212 while( i ); |
2226 | 2213 |
2227 | 2214 |
2228 // have the computations been done for the "real" tissues? | 2215 // have the computations been done for the "real" tissues? |
2229 if( (tissue_increment & TISSUE_FLAG) && (twosectimer || (tissue_increment & TIME_MASK)) ) | 2216 if( tissue_increment & TISSUE_FLAG ) |
2230 { | 2217 { |
2231 // net tissue balance | 2218 // net tissue balance |
2232 temp_tissue = temp_tissue_N2 + temp_tissue_He; | 2219 temp_tissue = temp_tissue_N2 + temp_tissue_He; |
2233 | 2220 |
2234 // check tissue on-/off-gassing and IBCD with applying a threshold of +/-HYST | 2221 // check tissue on-/off-gassing and IBCD with applying a threshold of +/-HYST |
2235 // | 2222 // |
2236 if ( temp_tissue < -HYST ) // Check if the tissue is off-gassing | 2223 if ( temp_tissue < -HYST ) // check if the tissue is off-gassing |
2237 { | 2224 { |
2238 deco_tissue_vector |= (1 << ci); // tag tissue as being in decompression | 2225 deco_tissue_vector |= (1 << ci); // tag tissue as being in decompression |
2239 IBCD_tissue_vector &= ~(1 << ci); // tag tissue as not experiencing mentionable IBCD | 2226 IBCD_tissue_vector &= ~(1 << ci); // tag tissue as not experiencing mentionable IBCD |
2240 } | 2227 } |
2241 else if ( temp_tissue > +HYST ) // check if the tissue in on-gassing | 2228 else if ( temp_tissue > +HYST ) // check if the tissue in on-gassing |
2369 // next calculations are only relevant when invoked on the real tissues | 2356 // next calculations are only relevant when invoked on the real tissues |
2370 if( tissue_increment & TISSUE_FLAG ) | 2357 if( tissue_increment & TISSUE_FLAG ) |
2371 { | 2358 { |
2372 overlay float supersat; | 2359 overlay float supersat; |
2373 overlay float threshold; | 2360 overlay float threshold; |
2374 | 2361 |
2375 // calculate current supersaturation value (1.0 = 100%) of this tissue | 2362 // calculate current supersaturation value (1.0 = 100%) of this tissue |
2376 supersat = (pres_tissue - pres_respiration) / (pres_tissue - pres_min); | 2363 supersat = (pres_tissue - pres_respiration) / (pres_tissue - pres_min); |
2377 | 2364 |
2378 // check if tissue is in supersaturation | 2365 // check if tissue is in supersaturation |
2379 if( supersat > 0.0 ) | 2366 if( supersat > 0.0 ) |
2448 | 2435 |
2449 // convert ceiling to int_O_ceiling in mbar | 2436 // convert ceiling to int_O_ceiling in mbar |
2450 if ( ceiling <= 0 ) int_O_ceiling = 0; | 2437 if ( ceiling <= 0 ) int_O_ceiling = 0; |
2451 else if ( ceiling > 16 ) int_O_ceiling = 16000; | 2438 else if ( ceiling > 16 ) int_O_ceiling = 16000; |
2452 // Compatibility version | 2439 // Compatibility version |
2453 else int_O_ceiling = (short)(ceiling * 1000); | 2440 // else int_O_ceiling = (short)(ceiling * 1000); |
2454 | 2441 |
2455 // New version: Rounds up to next 10 cm so that the ceiling disappears on the display only when the | 2442 // New version: Rounds up to next 10 cm so that the ceiling disappears on the display only when the |
2456 // ceiling limit is really zero. This will coincident then with TTS switching back to NDL time. | 2443 // ceiling limit is really zero. This will coincident then with TTS switching back to NDL time. |
2457 // else int_O_ceiling = (short)(ceiling * 1000 + 9); | 2444 else int_O_ceiling = (short)(ceiling * 1000 + 9); |
2458 | 2445 |
2459 | 2446 |
2460 // convert highest supersaturation found to int_O_gradient_factor in % (1.0 = 100%) | 2447 // convert highest supersaturation found to int_O_gradient_factor in % (1.0 = 100%) |
2461 // limit to 255 because of constraints in ghostwriter code | 2448 // limit to 255 because of constraints in ghostwriter code |
2462 if ( lead_supersat <= 0.0 ) int_O_gradient_factor = 0; | 2449 if ( lead_supersat <= 0.0 ) int_O_gradient_factor = 0; |
3135 { | 3122 { |
3136 overlay float time_factor = 1.0; // default is 2sec | 3123 overlay float time_factor = 1.0; // default is 2sec |
3137 | 3124 |
3138 assert( char_ppO2 > 15 ); | 3125 assert( char_ppO2 > 15 ); |
3139 | 3126 |
3140 // All deco code is now invoked every second. But as the CNS update is based on | |
3141 // 2 seconds periods, we skip every 2nd seconds-based invocation of this function. | |
3142 // TISSUE_FLAG = 128 (flag for "real" CNS) + 0 (2 seconds period) | |
3143 // To distribute computational load, the CNS% is calculated in "the other second" | |
3144 // than the tissues. | |
3145 if( (tissue_increment == TISSUE_FLAG) && (twosectimer) ) return; | |
3146 | |
3147 // adjust time factor if minute-based stepping is commanded, mask out flag bit | 3127 // adjust time factor if minute-based stepping is commanded, mask out flag bit |
3148 if( tissue_increment & TIME_MASK ) time_factor = 30.0 * (float)(tissue_increment & TIME_MASK); | 3128 if( tissue_increment & TIME_MASK ) time_factor = 30.0 * (float)(tissue_increment & TIME_MASK); |
3149 | |
3150 | 3129 |
3151 //------------------------------------------------------------------------ | 3130 //------------------------------------------------------------------------ |
3152 // Don't increase CNS below 0.5 bar, but keep it steady. | 3131 // Don't increase CNS below 0.5 bar, but keep it steady. |
3153 if (char_ppO2 < 50) CNS_fraction_inc = 0; // no CNS increase below 0.5 bar ppO2 | 3132 if (char_ppO2 < 50) CNS_fraction_inc = 0; // no CNS increase below 0.5 bar ppO2 |
3154 //------------------------------------------------------------------------ | 3133 //------------------------------------------------------------------------ |