comparison Discovery/Src/buehlmann.c @ 250:822416168585 bm-2

Buelmann: new implementation for ceiling Since my first functional fix in the ceiling computation in commit ceecabfddb57, I noticed that the computation used a linear search, that became rather computational expensive after that commit. The simple question is: why not a binary search? So, this commit implements the binary search. But there is a long story attached to this. Comparing ceiling results from hwOS and this OSTC4 code were very different. Basically, the original OSTC4 algorithm computed the ceiling using the same GFlow to GFhigh slope, in such a way, that the ceiling was in sync with the presented deco stops, where the hwOS code presents a GFhigh based ceiling. This said, it is more logical when the OSTC4 and hwOS code give similar results. This new recursive algorithm gives very similar results for the ceiling compared to hwOS. To be complete here, the Buelmann ceiling is the depth to which you can ascend, so that the leading tissue reaches GFhigh. This also explains why the deepest deco stop is normally deeper than the ceiling (unless one dives with GF like 80/80). The code implemented here is rather straightforward recursion. Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
author Jan Mulder <jlmulder@xs4all.nl>
date Thu, 11 Apr 2019 17:48:48 +0200
parents 3949781096d4
children 1663b3b204d7
comparison
equal deleted inserted replaced
249:cefee1448ea6 250:822416168585
65 int ascend_with_all_gaschanges(float pressure_decrease); 65 int ascend_with_all_gaschanges(float pressure_decrease);
66 float next_stop_depth_input_is_actual_stop_id(int actual_id); 66 float next_stop_depth_input_is_actual_stop_id(int actual_id);
67 float get_gf_at_pressure(float pressure); 67 float get_gf_at_pressure(float pressure);
68 void buehlmann_calc_ndl(void); 68 void buehlmann_calc_ndl(void);
69 _Bool dive1_check_deco(void); 69 _Bool dive1_check_deco(void);
70 uint8_t buehlmann_tissue_test_tolerance(float depth_in_bar_absolute);
71 70
72 /* 71 /*
73 _____________________________________________________________ 72 _____________________________________________________________
74 */ 73 */
75 74
444 } 443 }
445 } 444 }
446 } 445 }
447 446
448 447
449 uint8_t buehlmann_tissue_test_tolerance(float depth_in_bar_absolute) 448 float buehlmann_tissue_test_tolerance(float depth_in_bar_absolute)
450 { 449 {
451 float tissue_inertgas_saturation; 450 float tissue_inertgas_saturation;
452 float inertgas_a; 451 float inertgas_a;
453 float inertgas_b; 452 float inertgas_b;
454 float inertgas_tolerance; 453 float inertgas_tolerance;
459 for (int ci = 0; ci < 16; ci++) 458 for (int ci = 0; ci < 16; ci++)
460 { 459 {
461 if(gTissue_helium_bar[ci] == 0) 460 if(gTissue_helium_bar[ci] == 0)
462 { 461 {
463 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci]; 462 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci];
464 //
465 inertgas_a = buehlmann_N2_a[ci]; 463 inertgas_a = buehlmann_N2_a[ci];
466 inertgas_b = buehlmann_N2_b[ci]; 464 inertgas_b = buehlmann_N2_b[ci];
467 } 465 }
468 else 466 else
469 { 467 {
470 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci]; 468 tissue_inertgas_saturation = gTissue_nitrogen_bar[ci] + gTissue_helium_bar[ci];
471 //
472 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation; 469 inertgas_a = ( ( buehlmann_N2_a[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
473 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation; 470 inertgas_b = ( ( buehlmann_N2_b[ci] * gTissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * gTissue_helium_bar[ci]) ) / tissue_inertgas_saturation;
474 } 471 }
475 //
476 inertgas_tolerance = ( (gGF_value / inertgas_b - gf_minus_1) * depth_in_bar_absolute ) + ( gGF_value * inertgas_a ); 472 inertgas_tolerance = ( (gGF_value / inertgas_b - gf_minus_1) * depth_in_bar_absolute ) + ( gGF_value * inertgas_a );
477 //
478 if(inertgas_tolerance < tissue_inertgas_saturation) 473 if(inertgas_tolerance < tissue_inertgas_saturation)
479 return 0; 474 return tissue_inertgas_saturation - inertgas_tolerance; // positive
480 } 475 }
481 return 1; 476 return tissue_inertgas_saturation - inertgas_tolerance; // negative
482 } 477 }
483 478
484 479
485 void ambient_bar_to_deco_stop_depth_bar(float ceiling) 480 void ambient_bar_to_deco_stop_depth_bar(float ceiling)
486 { 481 {
713 return false; 708 return false;
714 else 709 else
715 return true; 710 return true;
716 } 711 }
717 712
718 713 // compute ceiling recursively, with a resolution of 10cm. Notice
719 void buehlmann_ceiling_calculator(SLifeData* pLifeData, SDiveSettings * pDiveSettings, SDecoinfo * pDecoInfo) 714 // that the initial call shall guarantee that the found ceiling
720 { 715 // is between low and high parameters.
721 float gf_low; 716 static float compute_ceiling(float low, float high)
722 float gf_high; 717 {
723 float gf_delta; 718 if ((high - low) < 0.01)
724 float dv_gf_low_stop_meter; 719 return low;
725 _Bool test_result; 720 else {
726 float next_gf_value; 721 float next_pressure_absolute = (low + high)/2;
727 float next_pressure_absolute; 722 float test_result = buehlmann_tissue_test_tolerance(next_pressure_absolute);
728 float depth_in_meter; 723 if (test_result < 0)
729 724 return compute_ceiling(low, next_pressure_absolute);
730 gf_low = pDiveSettings->gf_low; 725 else
731 gf_high = pDiveSettings->gf_high; 726 return compute_ceiling(next_pressure_absolute, high);
732 727 }
733 dv_gf_low_stop_meter = (int)((pDiveSettings->internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero - pLifeData->pressure_surface_bar) * 10); 728 }
734 729
735 if(dv_gf_low_stop_meter < 1) 730 void buehlmann_ceiling_calculator(SLifeData *pLifeData, SDecoinfo *pDecoInfo)
736 { 731 {
737 next_gf_value = gf_high; // fix hw 161024 732 float ceiling;
738 gf_delta = 0; 733
739 } 734 // this is just performance optimizing. The code below runs just fine
740 else 735 // without this. There is never a ceiling in NDL deco state
741 { 736 if (!pDecoInfo->output_time_to_surface_seconds) {
742 next_gf_value = gf_high; 737 pDecoInfo->output_ceiling_meter = 0;
743 gf_delta = gf_high - gf_low; 738 return;
744 gf_delta /= (dv_gf_low_stop_meter * 10); // gf_delta is delta for 10 cm !! 739 }
745 }
746
747 depth_in_meter = 0;
748 next_pressure_absolute = pLifeData->pressure_surface_bar;
749 740
750 memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16)); 741 memcpy(gTissue_nitrogen_bar, pLifeData->tissue_nitrogen_bar, (4*16));
751 memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16)); 742 memcpy(gTissue_helium_bar, pLifeData->tissue_helium_bar, (4*16));
752 gGF_value = next_gf_value / 100.0f; 743
753 // 744 ceiling = compute_ceiling(pLifeData->pressure_surface_bar, 1.0f + pLifeData->max_depth_meter/10.0f);
754 test_result = buehlmann_tissue_test_tolerance(next_pressure_absolute); 745 pDecoInfo->output_ceiling_meter = (ceiling - pLifeData->pressure_surface_bar) * 10.0f;
755 // 746 }
756 while(!test_result && depth_in_meter < 200)
757 {
758 depth_in_meter += 0.1;
759 next_gf_value = fmaxf(gf_low, next_gf_value - gf_delta);
760 gGF_value = next_gf_value / 100.0f;
761 next_pressure_absolute += 0.01f; // 0.1 meter down
762 test_result = buehlmann_tissue_test_tolerance(next_pressure_absolute);
763 }
764
765 if(test_result)
766 {
767 pDecoInfo->output_ceiling_meter = depth_in_meter;
768
769 if(depth_in_meter >= 0)
770 {
771 for(int i = 0; i < 10; i++)
772 {
773 next_gf_value += gf_delta/10.0f;
774 gGF_value = next_gf_value / 100.0f;
775 next_pressure_absolute -= 0.01f; // 0.1 meter up
776 if(!buehlmann_tissue_test_tolerance(next_pressure_absolute))
777 {
778 pDecoInfo->output_ceiling_meter -= ((float)i)/10.0f;
779 break;
780 }
781 }
782 }
783 }
784 else
785 {
786 pDecoInfo->output_ceiling_meter = 999;
787 }
788 }