Mercurial > public > ostc4
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 } |