Mercurial > public > ostc4
annotate Common/Src/decom.c @ 858:08ea8e9d6cfe Evo_2_23
Bugfix initialisation of surface pressure:
A reset of the RTE less than one minute before a dive starts may cause problems in the depth calculation because the default pressure is not set yet. To avoid this the first measured pressure value will now be used as stable surface pressure to close the gap till the stable surface pressure is evaluated.
author | Ideenmodellierer |
---|---|
date | Tue, 07 May 2024 21:12:37 +0200 |
parents | 012f94ec2fe0 |
children |
rev | line source |
---|---|
38 | 1 /////////////////////////////////////////////////////////////////////////////// |
2 /// -*- coding: UTF-8 -*- | |
3 /// | |
4 /// \file Common/Src/decom.c | |
5 /// \brief This code is used to calculate desat, calculated by RTE and send to Firmware | |
6 /// \author heinrichs weikamp gmbh | |
7 /// \date 22-Feb-2016 | |
8 /// | |
9 /// $Id$ | |
10 /////////////////////////////////////////////////////////////////////////////// | |
11 /// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh | |
12 /// | |
13 /// This program is free software: you can redistribute it and/or modify | |
14 /// it under the terms of the GNU General Public License as published by | |
15 /// the Free Software Foundation, either version 3 of the License, or | |
16 /// (at your option) any later version. | |
17 /// | |
18 /// This program is distributed in the hope that it will be useful, | |
19 /// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 /// GNU General Public License for more details. | |
22 /// | |
23 /// You should have received a copy of the GNU General Public License | |
24 /// along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 ////////////////////////////////////////////////////////////////////////////// | |
26 /** | |
27 @verbatim | |
28 ============================================================================== | |
29 ##### Changes ##### | |
30 ============================================================================== | |
31 V1.0.2 1602220x decom_oxygen_calculate_cns() changed to hwOS version | |
32 | |
33 @endverbatim | |
34 ****************************************************************************** | |
35 */ | |
36 | |
37 #include "decom.h" | |
38 | |
39 #include <math.h> | |
855 | 40 #include <string.h> |
38 | 41 #include "settings.h" |
42 #include "calc_crush.h" | |
43 | |
855 | 44 #define FRACTION_N2_AIR 0.7902 |
38 | 45 |
46 const float helium_time_constant[16] = { | |
47 3.68695308808482E-001, | |
48 2.29518933960247E-001, | |
49 1.46853216220327E-001, | |
50 9.91626867753856E-002, | |
51 6.78890480470074E-002, | |
52 4.78692804254106E-002, | |
53 3.37626488338989E-002, | |
54 2.38113081607676E-002, | |
55 1.68239606932026E-002, | |
56 1.25592893741610E-002, | |
57 9.80544886914621E-003, | |
58 7.67264977374303E-003, | |
59 6.01220557342307E-003, | |
60 4.70185307665137E-003, | |
61 3.68225234041620E-003, | |
62 2.88775228329769E-003}; | |
63 | |
64 const float nitrogen_time_constant[16] = { | |
65 1.38629436111989E-001, | |
66 8.66433975699932E-002, | |
67 5.54517744447956E-002, | |
68 3.74674151654024E-002, | |
69 2.56721177985165E-002, | |
70 1.80978376125312E-002, | |
71 1.27651414467762E-002, | |
72 9.00191143584345E-003, | |
73 6.35914844550409E-003, | |
74 4.74758342849278E-003, | |
75 3.70666941475907E-003, | |
76 2.90019740820061E-003, | |
77 2.27261370675392E-003, | |
78 1.77730046297422E-003, | |
79 1.39186180835330E-003, | |
80 1.09157036308653E-003}; | |
81 | |
82 | |
83 const float buehlmann_N2_a[] = { | |
84 1.1696f, | |
85 1.0000f, | |
86 0.8618f, | |
87 0.7562f, | |
88 0.6200f, | |
89 0.5043f, | |
90 0.4410f, | |
91 0.4000f, | |
92 0.3750f, | |
93 0.3500f, | |
94 0.3295f, | |
95 0.3065f, | |
96 0.2835f, | |
97 0.2610f, | |
98 0.2480f, | |
99 0.2327f}; | |
100 | |
101 const float buehlmann_N2_b[] = { | |
102 0.5578f, | |
103 0.6514f, | |
104 0.7222f, | |
105 0.7825f, | |
106 0.8126f, | |
107 0.8434f, | |
108 0.8693f, | |
109 0.8910f, | |
110 0.9092f, | |
111 0.9222f, | |
112 0.9319f, | |
113 0.9403f, | |
114 0.9477f, | |
115 0.9544f, | |
116 0.9602f, | |
117 0.9653f}; | |
118 | |
119 const float buehlmann_He_a[] = { | |
120 1.6189f, | |
121 1.3830f, | |
122 1.1919f, | |
123 1.0458f, | |
124 0.9220f, | |
125 0.8205f, | |
126 0.7305f, | |
127 0.6502f, | |
128 0.5950f, | |
129 0.5545f, | |
130 0.5333f, | |
131 0.5189f, | |
132 0.5181f, | |
133 0.5176f, | |
134 0.5172f, | |
135 0.5119f}; | |
136 | |
137 const float buehlmann_He_b[] = { | |
138 0.4770f, | |
139 0.5747f, | |
140 0.6527f, | |
141 0.7223f, | |
142 0.7582f, | |
143 0.7957f, | |
144 0.8279f, | |
145 0.8553f, | |
146 0.8757f, | |
147 0.8903f, | |
148 0.8997f, | |
149 0.9073f, | |
150 0.9122f, | |
151 0.9171f, | |
152 0.9217f, | |
153 0.9267f}; | |
154 | |
155 const float buehlmann_N2_t_halflife[] = { | |
156 5.0f, | |
157 8.0f, | |
158 12.5f, | |
159 18.5f, | |
160 27.0f, | |
161 38.3f, | |
162 54.3f, | |
163 77.0f, | |
164 109.0f, | |
165 146.0f, | |
166 187.0f, | |
167 239.0f, | |
168 305.0f, | |
169 390.0f, | |
170 498.0f, | |
171 635.0f}; | |
172 | |
173 const float buehlmann_He_t_halflife[] = { | |
174 1.88f, | |
175 3.02f, | |
176 4.72f, | |
177 6.99f, | |
178 10.21f, | |
179 14.48f, | |
180 20.53f, | |
181 29.11f, | |
182 41.20f, | |
183 55.19f, | |
184 70.69f, | |
185 90.34f, | |
186 115.29f, | |
187 147.42f, | |
188 188.24f, | |
189 240.03f}; | |
190 | |
191 const float float_buehlmann_N2_factor_expositon_one_second[] = { 2.30782347297664E-003f, 1.44301447809736E-003f, 9.23769302935806E-004f, 6.24261986779007E-004f, 4.27777107246730E-004f, 3.01585140931371E-004f, 2.12729727268379E-004f, 1.50020603047807E-004f, 1.05980191127841E-004f, 7.91232600646508E-005f, 6.17759153688224E-005f, 4.83354552742732E-005f, 3.78761777920511E-005f, 2.96212356654113E-005f, 2.31974277413727E-005f, 1.81926738960225E-005f}; | |
192 const float float_buehlmann_N2_factor_expositon_003_second[] = { 6.90750456296407E-003f, 4.32279956671600E-003f, 2.76874864793053E-003f, 1.87161709452954E-003f, 1.28278242026003E-003f, 9.04482589432765E-004f, 6.38053429621421E-004f, 4.49994293975742E-004f, 3.17906879170993E-004f, 2.37350999218289E-004f, 1.85316297551252E-004f, 1.44999356986975E-004f, 1.13624229615916E-004f, 8.88610747694640E-005f, 6.95906688746861E-005f, 5.45770287740943E-005f}; | |
193 const float float_buehlmann_N2_factor_expositon_008_second[] = { 1.83141447532454E-002f, 1.14859796471039E-002f, 7.36630472495203E-003f, 4.98319782231915E-003f, 3.41709742823104E-003f, 2.41013596224415E-003f, 1.70057124687550E-003f, 1.19953484034729E-003f, 8.47527105247492E-004f, 6.32810814525819E-004f, 4.94100480767923E-004f, 3.86618231662861E-004f, 3.02969256443353E-004f, 2.36945319086024E-004f, 1.85564355251966E-004f, 1.45532124251058E-004f}; | |
194 const float float_buehlmann_N2_factor_expositon_10_seconds[] = { 2.28400315657541E-002f, 1.43368013598124E-002f, 9.19938673477072E-003f, 6.22511239287027E-003f, 4.69545762670800E-003f, 3.01176178733265E-003f, 2.12526200031782E-003f, 1.49919365737827E-003f, 1.05929662305226E-03f, 7.909509380171760E-004f, 6.17587450108648E-004f, 4.83249432061905E-004f, 3.78697227222391E-004f, 2.61728759809380E-004f, 2.31950063482533E-004f, 1.81911845881011E-004f}; | |
195 const float float_buehlmann_N2_factor_expositon_18_seconds[] = { 4.07358806747357E-002f, 2.56581087982929E-002f, 1.64979259737517E-002f, 1.11772892486697E-002f, 7.67205373705648E-003f, 5.41463899418337E-003f, 3.82221908774349E-003f, 2.69693016270112E-003f, 1.90592594569927E-003f, 1.42326123023573E-003f, 1.11138278062062E-003f, 8.69680830683950E-004f, 6.81551750048359E-004f, 5.33048018290350E-004f, 4.17471377070378E-004f, 3.27417496114757E-004f}; | |
196 const float float_buehlmann_N2_factor_expositon_20_seconds[] = { 4.51583960895835E-002f, 2.84680588463941E-002f, 1.83141447532454E-002f, 1.24114727614367E-002f, 8.52086250432193E-003f, 6.01445286560154E-003f, 4.24600726206570E-003f, 2.99613973313428E-003f, 2.11747113676897E-003f, 1.58127627264804E-003f, 1.23479348595879E-003f, 9.66265334110261E-004f, 7.57251042854845E-004f, 5.92258033589421E-004f, 4.63846326133055E-004f, 3.63790599842373E-004f}; | |
197 const float float_buehlmann_N2_factor_expositon_one_minute[] = { 1.29449436703876E-001f, 8.29959567953288E-002f, 5.39423532744041E-002f, 3.67741962370398E-002f, 2.53453908775689E-002f, 1.79350552316596E-002f, 1.26840126026602E-002f, 8.96151553540825E-003f, 6.33897185233323E-003f, 4.73633146787078E-003f, 3.69980819572546E-003f, 2.89599589841472E-003f, 2.27003327536857E-003f, 1.77572199977927E-003f, 1.39089361795441E-003f, 1.09097481687104E-003f}; | |
198 const float float_buehlmann_N2_factor_expositon_100_second[] = { 2.06299474015900E-001f, 1.34463438993857E-001f, 8.82775114417832E-002f, 6.05359181023788E-002f, 4.18844218114071E-002f, 2.97126970072147E-002f, 2.10505144045823E-002f, 1.48911986890571E-002f, 1.05426136839346E-002f, 7.88141652426455E-003f, 6.15873909572406E-003f, 4.82199900095137E-003f, 3.78052526350936E-003f, 2.95778454900952E-003f, 2.31708109427220E-003f, 1.81763004457269E-003f}; | |
199 const float float_buehlmann_N2_factor_expositon_five_minutes[]= { 5.00000000000000E-001f, 3.51580222674495E-001f, 2.42141716744801E-001f, 1.70835801932547E-001f, 1.20463829104624E-001f, 8.65157896183918E-002f, 6.18314987350977E-002f, 4.40116547625051E-002f, 3.12955727186929E-002f, 2.34583889613009E-002f, 1.83626606868127E-002f, 1.43963540993090E-002f, 1.12987527093947E-002f, 8.84713405486026E-003f, 6.93514912851934E-003f, 5.44298480182925E-003f}; | |
200 const float float_buehlmann_N2_factor_expositon_800_second[] = { 8.42509868763141E-001f, 6.85019737526282E-001f, 5.22579198044792E-001f, 3.93205767018569E-001f, 2.89861248917861E-001f, 2.14397627137602E-001f, 1.56505490290652E-001f, 1.13102166881646E-001f, 8.12935637814599E-002f, 6.13392112527207E-002f, 4.82208523469105E-002f, 3.79311861210304E-002f, 2.98470272862601E-002f, 2.34187624071612E-002f, 1.83870151711824E-002f, 1.44488700649190E-002f}; | |
201 const float float_buehlmann_N2_factor_expositon_one_hour[]= { 9.99755859375000E-001f, 9.94475728271980E-001f, 9.64103176406343E-001f, 8.94394508891055E-001f, 7.85689004286732E-001f, 6.62392147498621E-001f, 5.35088626789486E-001f, 4.17318576947576E-001f, 3.17197008420226E-001f, 2.47876700002107E-001f, 1.99405069752929E-001f, 1.59713055172538E-001f, 1.27468761759271E-001f, 1.01149026804458E-001f, 8.01196838116008E-002f, 6.33955413542552E-002f}; | |
202 | |
203 const float float_buehlmann_He_factor_expositon_one_second[] = { 6.12608039419837E-003f, 3.81800836683133E-003f, 2.44456078654209E-003f, 1.65134647076792E-003f, 1.13084424730725E-003f, 7.97503165599123E-004f, 5.62552521860549E-004f, 3.96776399429366E-004f, 2.80360036664540E-004f, 2.09299583354805E-004f, 1.63410794820518E-004f, 1.27869320250551E-004f, 1.00198406028040E-004f, 7.83611475491108E-005f, 6.13689891868496E-005f, 4.81280465299827E-005f}; | |
204 const float float_buehlmann_He_factor_expositon_003_second[] = { 1.82658845044263E-002f, 1.14103491926518E-002f, 7.31576933570466E-003f, 4.94586307993539E-003f, 3.38869776192019E-003f, 2.39060197012086E-003f, 1.68670834759044E-003f, 1.18985696621965E-003f, 8.40844326779777E-004f, 6.27767340286467E-004f, 4.90152279561396E-004f, 3.83558911153159E-004f, 3.00565099928485E-004f, 2.35065021719993E-004f, 1.84095669333084E-004f, 1.44377190774980E-004f}; // 3 He | |
205 const float float_buehlmann_He_factor_expositon_008_second[] = { 4.79706116082057E-002f, 3.01390075707096E-002f, 1.93899772993034E-002f, 1.31346689569831E-002f, 9.01102820363486E-003f, 6.36224538449637E-003f, 4.49156910795023E-003f, 3.16980660943422E-003f, 2.24068067793926E-003f, 1.67317060331207E-003f, 1.30653891641375E-003f, 1.02249686330114E-003f, 8.01306192375617E-004f, 6.26717274191169E-004f, 4.90846474157092E-004f, 3.84959521834594E-004f}; // 8 He | |
206 const float float_buehlmann_He_factor_expositon_10_seconds[] = { 5.95993001714799E-002f, 3.75307444923134E-002f, 2.41784389107607E-002f, 1.63912909924208E-002f, 1.25106927410620E-002f, 7.94647192918641E-003f, 5.61130562069978E-003f, 3.96068706690245E-003f, 2.80006593100546E-003f, 2.09102564918129E-003f, 1.63290683272987E-003f, 1.27795767799976E-003f, 1.00153239354972E-003f, 7.33352120986130E-004f, 6.13520442722559E-004f, 4.81176244777948E-004f}; | |
207 const float float_buehlmann_He_factor_expositon_18_seconds[] = { 1.04710896899039E-001f, 6.65386126706349E-002f, 4.30995968284519E-002f, 2.93106657684409E-002f, 2.01607137751910E-002f, 1.42581599093282E-002f, 1.00776711616688E-002f, 7.11793906429403E-003f, 5.03447255531631E-003f, 3.76069760984632E-003f, 2.93731229281968E-003f, 2.29914783358365E-003f, 1.80203605181650E-003f, 1.40956155658090E-003f, 1.10406577253352E-003f, 8.65950533235460E-004f}; | |
208 const float float_buehlmann_He_factor_expositon_20_seconds[] = { 1.15646523762030E-001f, 7.36529322024796E-002f, 4.77722809133601E-002f, 3.25139075644434E-002f, 2.23755519884017E-002f, 1.58297974422514E-002f, 1.11911244906306E-002f, 7.90568709176287E-003f, 5.59229149279306E-003f, 4.17767891009702E-003f, 3.26314728073529E-003f, 2.55428218017273E-003f, 2.00206171996409E-003f, 1.56605681014277E-003f, 1.22666447811148E-003f, 9.62120958977297E-004f}; | |
209 const float float_buehlmann_He_factor_expositon_one_minute[] = { 3.08363886219441E-001f, 2.05084082411030E-001f, 1.36579295730211E-001f, 9.44046323514587E-002f, 6.56358626478964E-002f, 4.67416115355790E-002f, 3.31990512604121E-002f, 2.35300557146709E-002f, 1.66832281977395E-002f, 1.24807506400979E-002f, 9.75753219809561E-003f, 7.64329013320042E-003f, 5.99416843126677E-003f, 4.69081666943783E-003f, 3.67548116287808E-003f, 2.88358673732592E-003f}; | |
210 const float float_buehlmann_He_factor_expositon_100_second[] = { 4.59084487437744E-001f, 3.17867635141657E-001f, 2.17103957783539E-001f, 1.52336166567559E-001f, 1.06981885584572E-001f, 7.66825160768219E-002f, 5.47171474343117E-002f, 3.89083581201959E-002f, 2.76504642556165E-002f, 2.07145921483078E-002f, 1.62096019995457E-002f, 1.27063337640768E-002f, 9.97030625587825E-003f, 7.80579708939710E-003f, 6.11829377951190E-003f, 4.80135692933603E-003f}; // 100 He | |
211 const float float_buehlmann_He_factor_expositon_five_minutes[]= { 8.41733751018722E-001f, 6.82600697933713E-001f, 5.20142493735619E-001f, 3.90924736715930E-001f, 2.87834706153524E-001f, 2.12857832580192E-001f, 1.55333364924147E-001f, 1.12242395185686E-001f, 8.06788883581406E-002f, 6.08653819753062E-002f, 4.78448115000141E-002f, 3.76366999883051E-002f, 2.96136888654287E-002f, 2.32350754744602E-002f, 1.82428098114835E-002f, 1.43350223887367E-002f}; // thre | |
212 const float float_buehlmann_He_factor_expositon_800_second[] = { 9.92671155759686E-001f, 9.53124140216102E-001f, 8.58865632718416E-001f, 7.33443528431762E-001f, 5.95533881446524E-001f, 4.71787742036413E-001f, 3.62479376011699E-001f, 2.72021750877104E-001f, 2.00940186773410E-001f, 1.54187175639359E-001f, 1.22553521140786E-001f, 9.72431193565182E-002f, 7.70338702477497E-002f, 6.07666995543268E-002f, 4.79109397391700E-002f, 3.77715319879068E-002f}; // 800 He | |
213 const float float_buehlmann_He_factor_expositon_one_hour[]= { 9.99999999753021E-001f, 9.99998954626205E-001f, 9.99850944669188E-001f, 9.97393537149572E-001f, 9.82979603888650E-001f, 9.43423231328217E-001f, 8.68106292901111E-001f, 7.60374619482322E-001f, 6.35576141220644E-001f, 5.29310840978539E-001f, 4.44744511849213E-001f, 3.68942936079581E-001f, 3.02834419265355E-001f, 2.45810174422126E-001f, 1.98231319020275E-001f, 1.59085372294989E-001f}; | |
214 | |
215 void decom_get_inert_gases(const float ambient_pressure_bar,const SGas* pGas, float* fraction_nitrogen, float* fraction_helium ) | |
216 { | |
217 float fraction_all_inertgases; | |
218 float ppo2_fraction_setpoint; | |
219 float diluent_divisor; | |
220 | |
221 *fraction_nitrogen = ((float)pGas->nitrogen_percentage) / 100.0f; | |
222 *fraction_helium = ((float)pGas->helium_percentage) / 100.0f; | |
223 | |
662 | 224 if(pGas->AppliedDiveMode == DIVEMODE_CCR) |
225 { | |
226 // continue with CCR | |
227 fraction_all_inertgases = *fraction_nitrogen + *fraction_helium; | |
38 | 228 |
662 | 229 ppo2_fraction_setpoint = (float)pGas->setPoint_cbar/ (100 * ambient_pressure_bar); |
230 | |
231 diluent_divisor = (1.0f - ppo2_fraction_setpoint) / fraction_all_inertgases; | |
232 if(diluent_divisor < 0) | |
233 diluent_divisor = 0; | |
38 | 234 |
662 | 235 *fraction_nitrogen *= diluent_divisor; |
236 *fraction_helium *= diluent_divisor; | |
237 } | |
238 if(pGas->AppliedDiveMode == DIVEMODE_PSCR) | |
239 { | |
240 fraction_all_inertgases = *fraction_nitrogen + *fraction_helium; | |
241 ppo2_fraction_setpoint = decom_calc_SimppO2(ambient_pressure_bar, pGas) / ambient_pressure_bar; | |
242 diluent_divisor = (1.0f - ppo2_fraction_setpoint) / fraction_all_inertgases; | |
243 if(diluent_divisor < 0) | |
244 diluent_divisor = 0; | |
38 | 245 |
662 | 246 *fraction_nitrogen *= diluent_divisor; |
247 *fraction_helium *= diluent_divisor; | |
248 } | |
38 | 249 } |
250 | |
251 | |
252 void decom_tissues_exposure(int period_in_seconds, SLifeData * pLifeData) | |
253 { | |
254 decom_tissues_exposure2(period_in_seconds, &pLifeData->actualGas, pLifeData->pressure_ambient_bar, pLifeData->tissue_nitrogen_bar, pLifeData->tissue_helium_bar); | |
255 } | |
256 | |
257 | |
258 void decom_tissues_exposure2(int period_in_seconds, SGas* pActualGas, float ambiant_pressure_bar, float *tissue_N2_selected_stage, float *tissue_He_selected_stage) | |
259 { | |
260 int ci; | |
261 float percent_N2; | |
262 float percent_He; | |
263 float partial_pressure_N2; | |
264 float partial_pressure_He; | |
265 | |
266 | |
267 | |
268 int period_in_seconds_left; | |
269 | |
57 | 270 if(period_in_seconds > 0) |
271 { | |
38 | 272 |
273 decom_get_inert_gases(ambiant_pressure_bar, pActualGas, &percent_N2, &percent_He); | |
274 | |
275 partial_pressure_N2 = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_N2; | |
276 partial_pressure_He = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_He; | |
57 | 277 period_in_seconds_left = period_in_seconds; |
38 | 278 |
57 | 279 while(period_in_seconds_left) |
280 { | |
281 if(period_in_seconds_left >= 3600) | |
282 period_in_seconds = 3600; | |
283 else | |
284 if(period_in_seconds_left >= 800) | |
285 period_in_seconds = 800; | |
286 else | |
287 if(period_in_seconds_left >= 300) | |
288 period_in_seconds = 300; | |
289 else | |
290 if(period_in_seconds_left >= 100) | |
291 period_in_seconds = 100; | |
292 else | |
293 if(period_in_seconds_left >= 60) | |
294 period_in_seconds = 60; | |
295 else | |
296 if(period_in_seconds_left == 36) | |
297 period_in_seconds = 18; | |
298 else | |
299 if(period_in_seconds_left >= 20) | |
300 period_in_seconds = 20; | |
301 else | |
302 if(period_in_seconds_left >= 18) | |
303 period_in_seconds = 18; | |
304 else | |
305 if(period_in_seconds_left >= 10) | |
306 period_in_seconds = 10; | |
307 else | |
308 if(period_in_seconds_left >= 8) | |
309 period_in_seconds = 8; | |
310 else | |
311 if(period_in_seconds_left >= 3) | |
312 period_in_seconds = 3; | |
313 else | |
314 period_in_seconds = 1; | |
38 | 315 |
57 | 316 period_in_seconds_left -= period_in_seconds; |
38 | 317 |
57 | 318 switch (period_in_seconds) |
38 | 319 { |
57 | 320 case 1: |
321 for (ci=0;ci<16;ci++) | |
322 { | |
323 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_one_second[ci]; | |
324 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_one_second[ci]; | |
325 } | |
326 break; | |
327 case 3: | |
328 for (ci=0;ci<16;ci++) | |
329 { | |
330 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_003_second[ci]; | |
331 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_003_second[ci]; | |
332 } | |
333 break; | |
334 case 8: | |
335 for (ci=0;ci<16;ci++) | |
336 { | |
337 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_008_second[ci]; | |
338 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_008_second[ci]; | |
339 } | |
340 break; | |
341 case 10: | |
342 for (ci=0;ci<16;ci++) | |
343 { | |
344 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_10_seconds[ci]; | |
345 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_10_seconds[ci]; | |
346 } | |
347 break; | |
348 case 18: | |
349 for (ci=0;ci<16;ci++) | |
350 { | |
351 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_18_seconds[ci]; | |
352 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_18_seconds[ci]; | |
353 } | |
354 break; | |
355 case 20: | |
356 for (ci=0;ci<16;ci++) | |
357 { | |
358 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_20_seconds[ci]; | |
359 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_20_seconds[ci]; | |
360 } | |
361 break; | |
362 case 60: | |
363 for (ci=0;ci<16;ci++) | |
364 { | |
365 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_one_minute[ci]; | |
366 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_one_minute[ci]; | |
367 } | |
368 break; | |
369 case 100: | |
370 for (ci=0;ci<16;ci++) | |
371 { | |
372 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_100_second[ci]; | |
373 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_100_second[ci]; | |
374 } | |
375 break; | |
376 case 300: | |
377 for (ci=0;ci<16;ci++) | |
378 { | |
379 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_five_minutes[ci]; | |
380 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_five_minutes[ci]; | |
381 } | |
382 break; | |
383 case 800: | |
384 for (ci=0;ci<16;ci++) | |
385 { | |
386 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_800_second[ci]; | |
387 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_800_second[ci]; | |
388 } | |
389 break; | |
390 case 3600: | |
391 for (ci=0;ci<16;ci++) | |
392 { | |
393 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_one_hour[ci]; | |
394 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_one_hour[ci]; | |
395 } | |
396 break; | |
38 | 397 } |
398 } | |
399 } | |
400 } | |
401 | |
402 void decom_reset_with_1000mbar(SLifeData * pLifeData) | |
403 { | |
404 double saturation = 1.0; | |
405 | |
406 saturation -= WATER_VAPOUR_PRESSURE; | |
407 saturation *= FRACTION_N2_AIR; | |
408 | |
409 for(int i=0;i<16;i++) | |
410 { | |
411 pLifeData->tissue_nitrogen_bar[i] = saturation; | |
412 pLifeData->tissue_helium_bar[i] = 0; | |
413 } | |
414 pLifeData->otu = 0; | |
415 pLifeData->cns = 0; | |
416 pLifeData->desaturation_time_minutes = 0; | |
417 pLifeData->no_fly_time_minutes = 0; | |
418 } | |
419 | |
129
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
420 void decom_reset_with_ambientmbar(float ambient, SLifeData * pLifeData) |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
421 { |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
422 |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
423 float saturation = 1.0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
424 saturation = ambient; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
425 saturation -= WATER_VAPOUR_PRESSURE; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
426 saturation *= FRACTION_N2_AIR; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
427 |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
428 for(int i=0;i<16;i++) |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
429 { |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
430 pLifeData->tissue_nitrogen_bar[i] = saturation; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
431 pLifeData->tissue_helium_bar[i] = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
432 } |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
433 pLifeData->otu = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
434 pLifeData->cns = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
435 pLifeData->desaturation_time_minutes = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
436 pLifeData->no_fly_time_minutes = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
437 } |
38 | 438 |
439 /* =============================================================================== */ | |
440 /* NOTE ABOUT PRESSURE UNITS USED IN CALCULATIONS: */ | |
441 /* It is the convention in decompression calculations to compute all gas */ | |
442 /* loadings, absolute pressures, partial pressures, etc., in the units of */ | |
443 /* depth pressure that you are diving - either feet of seawater (fsw) or */ | |
444 /* meters of seawater (msw). This program follows that convention with the */ | |
445 /* the exception that all VPM calculations are performed in SI units (by */ | |
446 /* necessity). Accordingly, there are several conversions back and forth */ | |
447 /* between the diving pressure units and the SI units. */ | |
448 /* =============================================================================== */ | |
449 /* =============================================================================== */ | |
450 /* FUNCTION SUBPROGRAM FOR GAS LOADING CALCULATIONS - ASCENT AND DESCENT */ | |
451 /* =============================================================================== */ | |
452 | |
453 | |
454 float decom_schreiner_equation(float *initial_inspired_gas_pressure, | |
455 float *rate_change_insp_gas_pressure, | |
456 float *interval_time_minutes, | |
457 const float *gas_time_constant, | |
458 float *initial_gas_pressure) | |
459 { | |
460 /* System generated locals */ | |
461 float ret_val; | |
462 float time_null_pressure = 0.0f; | |
463 float time_rest = 0.0f; | |
464 float time = *interval_time_minutes; | |
465 /* =============================================================================== */ | |
466 /* Note: The Schreiner equation is applied when calculating the uptake or */ | |
467 /* elimination of compartment gases during linear ascents or descents at a */ | |
468 /* constant rate. For ascents, a negative number for rate must be used. */ | |
469 /* =============================================================================== */ | |
470 if( *rate_change_insp_gas_pressure < 0.0f) | |
471 { | |
472 time_null_pressure = -1.0f * *initial_inspired_gas_pressure / *rate_change_insp_gas_pressure; | |
473 if(time > time_null_pressure ) | |
474 { | |
475 time_rest = time - time_null_pressure; | |
476 time = time_null_pressure; | |
477 } | |
478 } | |
479 ret_val = | |
480 *initial_inspired_gas_pressure + | |
481 *rate_change_insp_gas_pressure * | |
482 (time - 1.f / *gas_time_constant) - | |
483 (*initial_inspired_gas_pressure - | |
484 *initial_gas_pressure - | |
485 *rate_change_insp_gas_pressure / *gas_time_constant) * | |
486 expf(-(*gas_time_constant) * time); | |
487 | |
488 if(time_rest > 0.0f) | |
489 { | |
490 ret_val = ret_val * expf(-(*gas_time_constant) * time_rest); | |
491 } | |
492 | |
493 | |
494 return ret_val; | |
495 }; /* schreiner_equation__2 */ | |
496 | |
497 void decom_tissues_exposure_stage_schreiner(int period_in_seconds, SGas* pGas, float starting_ambient_pressure_bar, float ending_ambient_pressure_bar, | |
498 float* pTissue_nitrogen_bar, float* pTissue_helium_bar) | |
499 { | |
500 | |
501 float initial_pressure_N2; | |
502 float initial_pressure_He; | |
503 | |
504 float ending_pressure_N2; | |
505 float ending_pressure_He; | |
506 | |
507 float fraction_N2_begin; | |
508 float fraction_N2_end; | |
509 float fraction_He_begin; | |
510 float fraction_He_end; | |
511 | |
512 float rate_N2; | |
513 float rate_He; | |
514 | |
515 float period_in_minutes; | |
516 | |
517 int ci; | |
518 | |
519 if(period_in_seconds <= 0) | |
520 return; | |
521 | |
522 decom_get_inert_gases(starting_ambient_pressure_bar, pGas, &fraction_N2_begin, &fraction_He_begin ); | |
523 decom_get_inert_gases(ending_ambient_pressure_bar, pGas, &fraction_N2_end, &fraction_He_end ); | |
524 | |
525 initial_pressure_N2 = (starting_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_N2_begin; | |
526 initial_pressure_He = (starting_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_He_begin; | |
527 | |
528 ending_pressure_N2 = (ending_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_N2_end; | |
529 ending_pressure_He = (ending_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_He_end; | |
530 | |
531 rate_N2 = (ending_pressure_N2 - initial_pressure_N2) / period_in_seconds; | |
532 rate_He = (ending_pressure_He - initial_pressure_He) / period_in_seconds; | |
533 | |
534 period_in_minutes = ((float)period_in_seconds) / 60.0f; | |
535 | |
536 for (ci=0;ci<16;ci++) | |
537 { | |
538 pTissue_nitrogen_bar[ci] = | |
539 decom_schreiner_equation( | |
540 &initial_pressure_N2, | |
541 &rate_N2, | |
542 &period_in_minutes, | |
543 &nitrogen_time_constant[ci], | |
544 &pTissue_nitrogen_bar[ci]); | |
545 | |
546 pTissue_helium_bar[ci] = | |
547 decom_schreiner_equation( | |
548 &initial_pressure_He, | |
549 &rate_He, | |
550 &period_in_minutes, | |
551 &helium_time_constant[ci], | |
552 &pTissue_helium_bar[ci]); | |
553 } | |
554 } | |
555 | |
556 _Bool nextSetpointChange(SDiveSettings* pDiveSettings, uint8_t depth_meter, uint8_t* change_depth_meter, char* setpoint) | |
557 { | |
558 uint8_t new_depth = 0; | |
559 char new_setpoint = 0; | |
560 for(int i = 1; i <= 5; i++) | |
561 { | |
562 if(pDiveSettings->setpoint[i].setpoint_cbar > 0 && pDiveSettings->setpoint[i].depth_meter > 0 ) | |
563 { | |
564 if( pDiveSettings->setpoint[i].depth_meter > new_depth && pDiveSettings->setpoint[i].depth_meter < depth_meter) | |
565 { | |
566 new_depth = pDiveSettings->setpoint[i].depth_meter; | |
567 new_setpoint = pDiveSettings->setpoint[i].setpoint_cbar; | |
568 } | |
569 } | |
570 } | |
571 if(new_depth) | |
572 { | |
573 * change_depth_meter = new_depth; | |
574 * setpoint = new_setpoint; | |
575 return 1; | |
576 } | |
577 return 0; | |
578 } | |
579 | |
580 | |
855 | 581 void insertGasIntoList(SGasLine* pGas, SGasLine** pGasList, uint8_t gasInSettings, uint8_t* pGasInSettingsList, uint8_t GasListLength) |
582 { | |
583 uint8_t localGasIndex = GasListLength; | |
584 if(pGas != 0) | |
585 { | |
586 while(localGasIndex != 0) /* first entry */ | |
587 { | |
588 if(pGasList[localGasIndex-1]->depth_meter > pGas->depth_meter) /* switch depth of existing gas is deeper then new one => move down */ | |
589 { | |
590 pGasList[localGasIndex] = pGasList[localGasIndex-1]; | |
591 pGasInSettingsList[localGasIndex] = pGasInSettingsList[localGasIndex - 1]; | |
592 localGasIndex--; | |
593 } | |
594 else | |
595 { | |
596 break; | |
597 } | |
598 } | |
599 pGasList[localGasIndex] = pGas; | |
600 pGasInSettingsList[localGasIndex] = gasInSettings; | |
601 } | |
602 } | |
38 | 603 |
604 void decom_CreateGasChangeList(SDiveSettings* pInput, const SLifeData* pLifeData) | |
605 { | |
855 | 606 SGasLine localPSCRFirst; |
607 SGasLine *pLocalGasList[5] = {0,0,0,0,0}; | |
608 uint8_t localGasInSettingsList[5] = {0,0,0,0,0}; | |
609 | |
610 uint8_t gasStart = 1; | |
611 uint8_t gasIndex = 0; | |
612 uint8_t gasEntryCnt = 0; | |
38 | 613 |
855 | 614 int i=0; |
615 for(i=0;i< 5;i++) /* reset list */ | |
616 { | |
617 pInput->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero = 0; | |
618 pInput->decogaslist[i].GasIdInSettings = 255; | |
619 pInput->decogaslist[i].setPoint_cbar = 0; | |
620 pInput->decogaslist[i].helium_percentage = 0; | |
621 pInput->decogaslist[i].nitrogen_percentage = 0; | |
622 } | |
623 /* FirstGas | |
624 * 0 = special gas, 1 to 5 is OC gas, 6 to 10 is diluent | |
625 */ | |
626 pInput->decogaslist[0] = pLifeData->actualGas; | |
627 /* Add Deco Gases | |
628 * special (gasId == 0) is never a deco/travel gas but actual gas only | |
629 */ | |
630 | |
631 if(pInput->diveMode != DIVEMODE_OC) | |
632 { | |
633 gasStart = 6; /* CCR or PSCR => CC gaslist */ | |
634 } | |
635 | |
636 if(pInput->diveMode == DIVEMODE_PSCR) /* Handle first gas as deco gas */ | |
637 { | |
638 for(gasIndex = gasStart; gasIndex < gasStart + 5; gasIndex++) | |
639 { | |
640 if(pInput->gas[gasIndex].note.ub.first) | |
641 { | |
642 if (pLifeData->actualGas.GasIdInSettings != gasIndex) | |
643 { | |
644 memcpy(&localPSCRFirst, &pInput->gas[gasIndex], sizeof(SGasLine)); | |
645 localPSCRFirst.depth_meter = calc_MOD(gasIndex); | |
646 insertGasIntoList(&localPSCRFirst, pLocalGasList, gasIndex, localGasInSettingsList, gasEntryCnt); | |
647 gasEntryCnt++; | |
648 break; | |
38 | 649 } |
855 | 650 } |
651 } | |
652 } | |
38 | 653 |
654 | |
855 | 655 for(gasIndex = gasStart; gasIndex < gasStart + 5; gasIndex++) |
656 { | |
657 if(((pInput->gas[gasIndex].note.ub.active) && (pInput->gas[gasIndex].depth_meter)) /* ready for deco calculation */ | |
658 && (pLifeData->actualGas.GasIdInSettings != gasIndex) /* not the actual gas */ | |
659 && (pInput->gas[gasIndex].depth_meter < pLifeData->depth_meter )) /* a gas which is on the way to surface */ | |
38 | 660 { |
855 | 661 insertGasIntoList(&pInput->gas[gasIndex], pLocalGasList, gasIndex, localGasInSettingsList, gasEntryCnt); |
662 gasEntryCnt++; | |
38 | 663 } |
855 | 664 } |
665 for(gasIndex = 1; gasIndex < gasEntryCnt+1; gasIndex++) /* move gasLine Information into deco List */ | |
666 { | |
667 pInput->decogaslist[gasIndex].change_during_ascent_depth_meter_otherwise_zero = pLocalGasList[gasIndex-1]->depth_meter; | |
668 pInput->decogaslist[gasIndex].nitrogen_percentage = 100; | |
669 pInput->decogaslist[gasIndex].nitrogen_percentage -= pLocalGasList[gasIndex-1]->oxygen_percentage; | |
670 pInput->decogaslist[gasIndex].nitrogen_percentage -= pLocalGasList[gasIndex-1]->helium_percentage; | |
671 pInput->decogaslist[gasIndex].helium_percentage = pLocalGasList[gasIndex-1]->helium_percentage; | |
672 pInput->decogaslist[gasIndex].GasIdInSettings = localGasInSettingsList[gasIndex-1]; | |
673 pInput->decogaslist[gasIndex].AppliedDiveMode = pInput->diveMode; | |
674 } | |
38 | 675 } |
676 void test_decom_CreateGasChangeList(void) | |
677 { | |
678 SDiveSettings diveSetting; | |
679 SLifeData lifeData; | |
680 lifeData.depth_meter = 100; | |
681 lifeData.actualGas.helium_percentage = 30; | |
682 lifeData.actualGas.nitrogen_percentage = 60; | |
683 lifeData.actualGas.setPoint_cbar = 18; | |
684 lifeData.actualGas.GasIdInSettings = 0; | |
685 lifeData.actualGas.change_during_ascent_depth_meter_otherwise_zero = 0; | |
686 diveSetting.diveMode = DIVEMODE_CCR; | |
687 diveSetting.gas[6].depth_meter = 0; | |
688 diveSetting.gas[6].helium_percentage = 30; | |
689 diveSetting.gas[6].oxygen_percentage = 10; | |
690 diveSetting.gas[6].note.ub.active = 1; | |
691 | |
692 diveSetting.gas[7].depth_meter = 60; | |
693 diveSetting.gas[7].helium_percentage = 0; | |
694 diveSetting.gas[7].oxygen_percentage = 10; | |
695 diveSetting.gas[7].note.ub.active = 1; | |
696 diveSetting.gas[8].note.ub.active = 0; | |
697 diveSetting.gas[9].note.ub.active = 0; | |
698 diveSetting.gas[10].note.ub.active = 0; | |
699 | |
700 diveSetting.setpoint[0].depth_meter = 0; | |
701 diveSetting.setpoint[1].depth_meter = 80; | |
702 diveSetting.setpoint[1].setpoint_cbar = 20; | |
703 diveSetting.setpoint[2].depth_meter = 60; | |
704 diveSetting.setpoint[2].setpoint_cbar = 25; | |
705 diveSetting.setpoint[3].depth_meter = 0; | |
706 diveSetting.setpoint[4].depth_meter = 0; | |
707 diveSetting.setpoint[5].depth_meter = 0; | |
708 | |
709 | |
710 decom_CreateGasChangeList(&diveSetting, &lifeData); | |
711 } | |
712 | |
713 uint8_t decom_tissue_test_tolerance(float* Tissue_nitrogen_bar, float* Tissue_helium_bar, float GF_value, float depth_in_bar_absolute) | |
714 { | |
715 float tissue_inertgas_saturation; | |
716 float inertgas_a; | |
717 float inertgas_b; | |
718 float inertgas_tolerance; | |
719 float gf_minus_1; | |
720 | |
721 gf_minus_1 = GF_value - 1.0f; | |
722 | |
723 for (int ci = 0; ci < 16; ci++) | |
724 { | |
725 if(Tissue_helium_bar[ci] == 0) | |
726 { | |
727 tissue_inertgas_saturation = Tissue_nitrogen_bar[ci]; | |
728 // | |
729 inertgas_a = buehlmann_N2_a[ci]; | |
730 inertgas_b = buehlmann_N2_b[ci]; | |
731 } | |
732 else | |
733 { | |
734 tissue_inertgas_saturation = Tissue_nitrogen_bar[ci] + Tissue_helium_bar[ci]; | |
735 // | |
736 inertgas_a = ( ( buehlmann_N2_a[ci] * Tissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * Tissue_helium_bar[ci]) ) / tissue_inertgas_saturation; | |
737 inertgas_b = ( ( buehlmann_N2_b[ci] * Tissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * Tissue_helium_bar[ci]) ) / tissue_inertgas_saturation; | |
738 } | |
739 // | |
740 inertgas_tolerance = ( (GF_value / inertgas_b - gf_minus_1) * depth_in_bar_absolute ) + ( GF_value * inertgas_a ); | |
741 // | |
742 if(inertgas_tolerance < tissue_inertgas_saturation) | |
743 return 0; | |
744 } | |
745 return 1; | |
746 } | |
747 | |
748 | |
749 void decom_tissues_desaturation_time(const SLifeData* pLifeData, SLifeData2* pOutput) | |
750 { | |
751 float pressure_in_gas_for_complete; | |
752 float pressure_in_gas_for_desat; | |
753 float diff_to_complete; | |
754 float diff_to_desatpoint; | |
755 float necessary_halftimes; | |
756 float desattime; | |
757 | |
758 pressure_in_gas_for_complete = 0.7902f * ( pLifeData->pressure_surface_bar - 0.0627f); | |
759 pressure_in_gas_for_desat = 1.05f * pressure_in_gas_for_complete; | |
760 for(int i=0; i<16; i++) | |
761 { | |
762 diff_to_complete = pressure_in_gas_for_complete - pLifeData->tissue_nitrogen_bar[i]; | |
763 diff_to_desatpoint = pressure_in_gas_for_desat - pLifeData->tissue_nitrogen_bar[i]; | |
764 | |
765 if((diff_to_desatpoint >= 0) || (diff_to_complete >= 0)) | |
766 pOutput->tissue_nitrogen_desaturation_time_minutes[i] = 0; | |
767 else | |
768 { | |
769 necessary_halftimes = (logf(1.0f - (diff_to_desatpoint/diff_to_complete)) / -0.6931f); | |
770 desattime = buehlmann_N2_t_halflife[i] * necessary_halftimes; | |
771 if(desattime <= (float)0xFFFF) | |
772 pOutput->tissue_nitrogen_desaturation_time_minutes[i] = desattime; | |
773 else | |
774 pOutput->tissue_nitrogen_desaturation_time_minutes[i] = 0xFFFF; | |
775 } | |
776 } | |
777 | |
778 for(int i=0; i<16; i++) | |
779 { | |
780 diff_to_desatpoint = 0.05f - pLifeData->tissue_helium_bar[i]; | |
781 diff_to_complete = -1.0f * pLifeData->tissue_helium_bar[i]; | |
782 | |
783 if((diff_to_desatpoint >= 0) || (diff_to_complete >= 0)) | |
784 pOutput->tissue_helium_desaturation_time_minutes[i] = 0; | |
785 else | |
786 { | |
787 necessary_halftimes = (logf(1.0f - (diff_to_desatpoint/diff_to_complete)) / -0.6931f); | |
788 desattime = buehlmann_He_t_halflife[i] * necessary_halftimes; | |
789 if(desattime <= (float)0xFFFF) | |
790 pOutput->tissue_helium_desaturation_time_minutes[i] = desattime; | |
791 else | |
792 pOutput->tissue_helium_desaturation_time_minutes[i] = 0xFFFF; | |
793 } | |
794 } | |
795 } | |
796 | |
797 #define MAX_DEGRADE_OTU_TIME_MINUTES (1440) | |
798 //CNS&OTU: | |
799 #define OXY_TEN_MINUTES_IN_SECONDS (600) | |
800 #define OXY_HALF_LIVE_OF_TEN_MINUTES__INVERSE_NINTH_ROOT_OF_TWO (0.92587471f) | |
801 #define OXY_NINE_DAYS_IN_TEN_MINUTES (1296) | |
802 #define OXY_ONE_SIXTIETH_PART (0.0166667f) | |
803 #define OXY_NEGATIVE_FIVE_SIXTH_PARTS (-0.8333333f) | |
804 void decom_oxygen_calculate_otu(float* oxygen_otu, float pressure_oxygen_real) | |
805 { | |
806 if(pressure_oxygen_real <= 0.5f) | |
807 return; | |
808 *oxygen_otu += (pow((double)(0.5f / (pressure_oxygen_real - 0.5f)),OXY_NEGATIVE_FIVE_SIXTH_PARTS)) * OXY_ONE_SIXTIETH_PART; | |
809 } | |
810 | |
811 void decom_oxygen_calculate_otu_degrade(float* oxygen_otu, long seconds_since_last_dive) | |
812 { | |
813 static long otu_time_ticker = 0; | |
814 static double otu_degrade_every_10_minutes = 999.9; | |
815 long cycles_since_last_call; | |
816 | |
817 if((*oxygen_otu <= 0) || (seconds_since_last_dive == 0)) | |
818 *oxygen_otu = 0; | |
819 else if(seconds_since_last_dive < OXY_TEN_MINUTES_IN_SECONDS) | |
820 { | |
821 otu_time_ticker = 1; | |
822 otu_degrade_every_10_minutes = *oxygen_otu / (MAX_DEGRADE_OTU_TIME_MINUTES / 10); | |
823 } | |
824 else | |
825 { | |
826 cycles_since_last_call = seconds_since_last_dive / (otu_time_ticker * OXY_TEN_MINUTES_IN_SECONDS); | |
827 *oxygen_otu -= ((double)cycles_since_last_call) * otu_degrade_every_10_minutes; | |
828 otu_time_ticker += cycles_since_last_call; | |
829 if((*oxygen_otu < 0) || (otu_time_ticker > (MAX_DEGRADE_OTU_TIME_MINUTES / 10))) | |
830 *oxygen_otu = 0; | |
831 } | |
832 } | |
833 | |
834 | |
835 | |
836 void decom_oxygen_calculate_cns_degrade(float* oxygen_cns, long seconds_since_last_dive) | |
837 { | |
838 static long cns_time_ticker = 0; | |
839 int cns_max_cycles; | |
840 | |
841 if((*oxygen_cns <= 0.5f) || (seconds_since_last_dive == 0)) | |
842 *oxygen_cns = 0; | |
843 else if(seconds_since_last_dive < OXY_TEN_MINUTES_IN_SECONDS) | |
844 cns_time_ticker = 1; | |
845 else | |
846 { | |
847 cns_max_cycles = OXY_NINE_DAYS_IN_TEN_MINUTES; | |
848 while((*oxygen_cns >= 0.5f) && ((cns_time_ticker * OXY_TEN_MINUTES_IN_SECONDS) < seconds_since_last_dive) && cns_max_cycles) | |
849 { | |
850 cns_time_ticker++; | |
851 cns_max_cycles--; | |
852 *oxygen_cns *= OXY_HALF_LIVE_OF_TEN_MINUTES__INVERSE_NINTH_ROOT_OF_TWO; | |
853 } | |
854 } | |
855 } | |
856 | |
857 | |
858 // new hwOS style | |
859 void decom_oxygen_calculate_cns(float* oxygen_cns, float pressure_oxygen_real) | |
860 { | |
861 uint8_t char_I_actual_ppO2; | |
862 float CNS_fraction = 0; | |
863 const float time_factor = 3000.0f; | |
864 | |
865 if(pressure_oxygen_real < 0.15f) | |
866 char_I_actual_ppO2 = 15; | |
867 else | |
868 if(pressure_oxygen_real >= 2.5f) | |
869 char_I_actual_ppO2 = 255; | |
870 else | |
871 char_I_actual_ppO2 = (uint8_t)(pressure_oxygen_real * 100); | |
872 | |
873 if (char_I_actual_ppO2 < 50) | |
874 (void)0; // no changes | |
875 //------------------------------------------------------------------------ | |
876 // Below (and including) 1.60 bar | |
877 else if (char_I_actual_ppO2 < 61) | |
878 CNS_fraction += time_factor/(-533.07f * char_I_actual_ppO2 + 54000.0f); | |
879 else if (char_I_actual_ppO2 < 71) | |
880 CNS_fraction += time_factor/(-444.22f * char_I_actual_ppO2 + 48600.0f); | |
881 else if (char_I_actual_ppO2 < 81) | |
882 CNS_fraction += time_factor/(-355.38f * char_I_actual_ppO2 + 42300.0f); | |
883 else if (char_I_actual_ppO2 < 91) | |
884 CNS_fraction += time_factor/(-266.53f * char_I_actual_ppO2 + 35100.0f); | |
885 else if (char_I_actual_ppO2 < 111) | |
886 CNS_fraction += time_factor/(-177.69f * char_I_actual_ppO2 + 27000.0f); | |
887 else if (char_I_actual_ppO2 < 152) | |
888 CNS_fraction += time_factor/( -88.84f * char_I_actual_ppO2 + 17100.0f); | |
889 else if (char_I_actual_ppO2 < 167) | |
890 CNS_fraction += time_factor/(-222.11f * char_I_actual_ppO2 + 37350.0f); | |
891 //------------------------------------------------------------------------ | |
892 // Arieli et all.(2002): Modeling pulmonary and CNS O2 toxicity: | |
893 // J Appl Physiol 92: 248--256, 2002, doi:10.1152/japplphysiol.00434.2001 | |
894 // Formula (A1) based on value for 1.55 and c=20 | |
895 // example calculation: Sqrt((1.7/1.55)^20)*0.000404 | |
896 else if (char_I_actual_ppO2 < 172) | |
897 CNS_fraction += time_factor*0.00102f; | |
898 else if (char_I_actual_ppO2 < 177) | |
899 CNS_fraction += time_factor*0.00136f; | |
900 else if (char_I_actual_ppO2 < 182) | |
901 CNS_fraction += time_factor*0.00180f; | |
902 else if (char_I_actual_ppO2 < 187) | |
903 CNS_fraction += time_factor*0.00237f; | |
904 else if (char_I_actual_ppO2 < 192) | |
905 CNS_fraction += time_factor*0.00310f; | |
906 else if (char_I_actual_ppO2 < 198) | |
907 CNS_fraction += time_factor*0.00401f; | |
908 else if (char_I_actual_ppO2 < 203) | |
909 CNS_fraction += time_factor*0.00517f; | |
910 else if (char_I_actual_ppO2 < 233) | |
911 CNS_fraction += time_factor*0.0209f; | |
912 else | |
913 CNS_fraction += time_factor*0.0482f; // value for 2.5 | |
914 | |
915 if( CNS_fraction > 999.0f) // Limit display to 999% | |
916 CNS_fraction = 999.0f; | |
917 if( CNS_fraction < 0.0f ) | |
918 CNS_fraction = 0.0f; | |
919 | |
920 //calculate cns for the actual ppo2 for 1 second | |
921 *oxygen_cns += OXY_ONE_SIXTIETH_PART * CNS_fraction; | |
922 | |
923 if( *oxygen_cns > 999.0f) // Limit display to 999% | |
924 *oxygen_cns = 999.0f; | |
925 if( *oxygen_cns < 0.0f ) | |
926 *oxygen_cns = 0.0f; | |
927 } | |
928 | |
929 /* old DR5 style | |
930 void decom_oxygen_calculate_cns(float* oxygen_cns, float pressure_oxygen_real) | |
931 { | |
932 int cns_no_range = 0; | |
933 _Bool not_found = 1; | |
934 //for the cns calculation | |
935 const float cns_ppo2_ranges[60][2] = { | |
936 {0.50f, 0.00f}, {0.60f, 0.14f}, {0.64f, 0.15f}, {0.66f, 0.16f}, {0.68f, 0.17f}, {0.70f, 0.18f}, | |
937 {0.74f, 0.19f}, {0.76f, 0.20f}, {0.78f, 0.21f}, {0.80f, 0.22f}, {0.82f, 0.23f}, {0.84f, 0.24f}, | |
938 {0.86f, 0.25f}, {0.88f, 0.26f}, {0.90f, 0.28f}, {0.92f, 0.29f}, {0.94f, 0.30f}, {0.96f, 0.31f}, | |
939 {0.98f, 0.32f}, {1.00f, 0.33f}, {1.02f, 0.35f}, {1.04f, 0.36f}, {1.06f, 0.38f}, {1.08f, 0.40f}, | |
940 {1.10f, 0.42f}, {1.12f, 0.43f}, {1.14f, 0.43f}, {1.16f, 0.44f}, {1.18f, 0.46f}, {1.20f, 0.47f}, | |
941 {1.22f, 0.48f}, {1.24f, 0.51f}, {1.26f, 0.52f}, {1.28f, 0.54f}, {1.30f, 0.56f}, {1.32f, 0.57f}, | |
942 {1.34f, 0.60f}, {1.36f, 0.62f}, {1.38f, 0.63f}, {1.40f, 0.65f}, {1.42f, 0.68f}, {1.44f, 0.71f}, | |
943 {1.46f, 0.74f}, {1.48f, 0.78f}, {1.50f, 0.83f}, {1.52f, 0.93f}, {1.54f, 1.04f}, {1.56f, 1.19f}, | |
944 {1.58f, 1.47f}, {1.60f, 2.22f}, {1.62f, 5.00f}, {1.65f, 6.25f}, {1.67f, 7.69f}, {1.70f, 10.0f}, | |
945 {1.72f,12.50f}, {1.74f,20.00f}, {1.77f,25.00f}, {1.79f,31.25f}, {1.80f,50.00f}, {1.82f,100.0f}}; | |
946 //find the correct cns range for the corresponding ppo2 | |
947 cns_no_range = 58; | |
948 while (cns_no_range && not_found) | |
949 { | |
950 if (pressure_oxygen_real > cns_ppo2_ranges[cns_no_range][0]) | |
951 { | |
952 cns_no_range++; | |
953 not_found = 0; | |
954 } | |
955 else | |
956 cns_no_range--; | |
957 } | |
958 | |
959 //calculate cns for the actual ppo2 for 1 second | |
960 *oxygen_cns += OXY_ONE_SIXTIETH_PART * cns_ppo2_ranges[cns_no_range][1]; | |
961 } | |
962 */ | |
963 | |
964 void decom_oxygen_calculate_cns_exposure(int period_in_seconds, SGas* pActualGas, float pressure_ambient_bar, float* oxygen_cns) | |
965 { | |
966 float pressure_oxygen_real; | |
967 float one_second_cns; | |
968 | |
969 pressure_oxygen_real = decom_calc_ppO2(pressure_ambient_bar, pActualGas); | |
970 one_second_cns = 0; | |
971 decom_oxygen_calculate_cns(&one_second_cns, pressure_oxygen_real); | |
972 *oxygen_cns += one_second_cns * period_in_seconds; | |
973 } | |
974 | |
975 | |
976 void decom_oxygen_calculate_cns_stage_SchreinerStyle(int period_in_seconds, SGas* pGas, float starting_ambient_pressure_bar, float ending_ambient_pressure_bar, float* oxygen_cns) | |
977 { | |
978 if(ending_ambient_pressure_bar == starting_ambient_pressure_bar) | |
979 { | |
980 decom_oxygen_calculate_cns_exposure(period_in_seconds, pGas, starting_ambient_pressure_bar, oxygen_cns); | |
981 return; | |
982 } | |
983 | |
984 float pressure_oxygen_real; | |
985 float initial_pressure_oxygen; | |
986 float ending_pressure_oxygen; | |
987 float rate_oxygen; | |
988 | |
989 initial_pressure_oxygen = decom_calc_ppO2(starting_ambient_pressure_bar, pGas); | |
990 ending_pressure_oxygen = decom_calc_ppO2(ending_ambient_pressure_bar, pGas); | |
991 | |
992 rate_oxygen = (ending_pressure_oxygen - initial_pressure_oxygen) / period_in_seconds; | |
993 | |
994 pressure_oxygen_real = initial_pressure_oxygen; | |
995 for(int i = 0; i < period_in_seconds; i++) | |
996 { | |
997 decom_oxygen_calculate_cns(oxygen_cns, pressure_oxygen_real); | |
998 pressure_oxygen_real += rate_oxygen; | |
999 } | |
1000 } | |
1001 | |
1002 | |
1003 float decom_calc_ppO2(const float ambiant_pressure_bar, const SGas* pGas) | |
1004 { | |
662 | 1005 float percent_N2 = 0; |
38 | 1006 float percent_He = 0; |
1007 float percent_O2 = 0; | |
1008 | |
662 | 1009 decom_get_inert_gases(ambiant_pressure_bar, pGas, &percent_N2, &percent_He); |
1010 percent_O2 = 1 - percent_N2 - percent_He; | |
1011 | |
1012 return (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_O2; | |
38 | 1013 } |
1014 | |
1015 | |
662 | 1016 float decom_calc_SimppO2(float ambiant_pressure_bar, const SGas* pGas) |
1017 { | |
1018 float o2Ratio = 0.0; | |
1019 float inertGasRatio = 0.0; | |
1020 float simulatedPSCRppo2 = 0.0; | |
1021 | |
1022 o2Ratio = (100.0 - pGas->nitrogen_percentage - pGas->helium_percentage) / 100.0; | |
1023 inertGasRatio = 1.0 - o2Ratio; | |
1024 simulatedPSCRppo2 = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * o2Ratio; | |
1025 simulatedPSCRppo2 -= (inertGasRatio * pGas->pscr_factor); | |
1026 if(simulatedPSCRppo2 < 0.0) | |
1027 { | |
1028 simulatedPSCRppo2 = 0.0; | |
1029 } | |
1030 return simulatedPSCRppo2; | |
1031 } | |
1032 | |
1033 float decom_calc_SimppO2_O2based(float ambiant_pressure_bar, uint8_t O2PerCent, float factor) | |
1034 { | |
1035 float o2Ratio = 0.0; | |
1036 float inertGasRatio = 0.0; | |
1037 float simulatedPSCRppo2 = 0.0; | |
1038 | |
1039 o2Ratio = O2PerCent / 100.0; | |
1040 inertGasRatio = 1.0 - o2Ratio; | |
1041 simulatedPSCRppo2 = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * o2Ratio; | |
1042 simulatedPSCRppo2 -= (inertGasRatio * factor); | |
1043 if(simulatedPSCRppo2 < 0.0) | |
1044 { | |
1045 simulatedPSCRppo2 = 0.0; | |
1046 } | |
1047 return simulatedPSCRppo2; | |
1048 } | |
1049 | |
38 | 1050 uint8_t decom_get_actual_deco_stop(SDiveState* pDiveState) |
1051 { | |
1052 SDecoinfo* pDecoinfo; | |
1053 uint8_t depthNext, depthLast, depthSecond, depthInc; | |
1054 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
1055 pDecoinfo = &pDiveState->decolistBuehlmann; | |
1056 else | |
1057 pDecoinfo = &pDiveState->decolistVPM; | |
1058 | |
1059 depthLast = (uint8_t)(pDiveState->diveSettings.last_stop_depth_bar * 10); | |
1060 depthSecond = (uint8_t)(pDiveState->diveSettings.input_second_to_last_stop_depth_bar * 10); | |
1061 depthInc = (uint8_t)(pDiveState->diveSettings.input_next_stop_increment_depth_bar * 10); | |
1062 if(pDecoinfo->output_stop_length_seconds[0] > 0) | |
1063 { | |
1064 depthNext = depthLast; | |
1065 } | |
1066 else | |
1067 return 0; | |
1068 for(int i = DECOINFO_STRUCT_MAX_STOPS -1 ;i > 0; i--) | |
1069 { | |
1070 if(pDecoinfo->output_stop_length_seconds[i] > 0) | |
1071 { | |
1072 depthNext = depthSecond + ( (i - 1) * depthInc); | |
1073 break; | |
1074 } | |
1075 } | |
1076 return depthNext; | |
1077 } | |
1078 | |
1079 | |
1080 // =============================================================================== | |
1081 // decom_calc_desaturation_time | |
1082 /// @brief This code is used to calculate desat, calculated by RTE and send to Firmware | |
1083 /// similar but more technical in code than decom_tissues_desaturation_time() | |
1084 /// the later has 0.05 for helium in contrast to this one. | |
1085 /// This one goes down to 70%, the oterh | |
1086 /// | |
1087 /// output is desat time in minutes | |
1088 // =============================================================================== | |
1089 int decom_calc_desaturation_time(float* Tissue_nitrogen_bar, float* Tissue_helium_bar, float surface_pressure_bar) | |
1090 { | |
1091 const float N2_ratio = 0.7902; // FIXED sum as stated in b"uhlmann | |
1092 | |
1093 float pres_surface; | |
1094 float temp_atem; | |
1095 float float_desaturation_multiplier; | |
1096 float temp1,temp2,temp3,temp4; | |
1097 int ci; | |
1098 int int_temp; | |
1099 int int_O_desaturation_time; | |
1100 pres_surface = ((float)surface_pressure_bar); | |
1101 temp_atem = N2_ratio * (pres_surface - 0.0627f); | |
1102 | |
1103 int_O_desaturation_time = 0; | |
1104 float_desaturation_multiplier = 100 / 142.0f; // new in v.101 (70,42%/100.=142) | |
1105 | |
1106 for (ci=0;ci<16;ci++) | |
1107 { | |
1108 // saturation_time (for flight) and N2_saturation in multiples of halftime | |
1109 // version v.100: 1.1 = 10 percent distance to totally clean (totally clean is not possible, would take infinite time ) | |
1110 // new in version v.101: 1.07 = 7 percent distance to totally clean (totally clean is not possible, would take infinite time ) | |
1111 // changes in v.101: 1.05 = 5 percent dist to totally clean is new desaturation point for display and noFly calculations | |
1112 | |
1113 // N2 | |
1114 temp1 = 1.05f * temp_atem; | |
1115 temp1 = temp1 - (float)Tissue_nitrogen_bar[ci]; | |
1116 temp2 = temp_atem - (float)Tissue_nitrogen_bar[ci]; | |
1117 if (temp2 >= 0) | |
1118 { | |
1119 temp1 = 0; | |
1120 temp2 = 0; | |
1121 } | |
1122 else | |
1123 temp1 = temp1 / temp2; | |
1124 | |
1125 if (temp1 > 0) | |
1126 { | |
1127 temp1 = logf(1.0f - temp1); | |
1128 temp1 = temp1 / -0.6931f; // temp1 is the multiples of half times necessary. | |
1129 // 0.6931 is ln(2), because the math function log() calculates with a base of e not 2 as requested. | |
1130 // minus because log is negative | |
1131 temp2 = buehlmann_N2_t_halflife[ci] * temp1 / float_desaturation_multiplier; // time necessary (in minutes ) for complete desaturation (see comment about 10 percent) , new in v.101: float_desaturation_multiplier | |
1132 } | |
1133 else | |
1134 { | |
1135 temp1 = 0; | |
1136 temp2 = 0; | |
1137 } | |
1138 | |
1139 // He | |
1140 temp3 = 0.1f - (float)Tissue_helium_bar[ci]; | |
1141 if (temp3 >= 0) | |
1142 { | |
1143 temp3 = 0; | |
1144 temp4 = 0; | |
1145 } | |
1146 else | |
1147 temp3 = -1.0f * temp3 / (float)Tissue_helium_bar[ci]; | |
1148 if (temp3 > 0) | |
1149 { | |
1150 temp3 = logf(1.0f - temp3); | |
1151 temp3 = temp3 / -0.6931f; // temp1 is the multiples of half times necessary. | |
1152 // 0.6931 is ln(2), because the math function log() calculates with a base of e not 2 as requested. | |
1153 // minus because log is negative | |
1154 temp4 = buehlmann_He_t_halflife[ci] * temp3 / float_desaturation_multiplier; // time necessary (in minutes ) for "complete" desaturation, new in v.101 float_desaturation_multiplier | |
1155 } | |
1156 else | |
1157 { | |
1158 temp3 = 0; | |
1159 temp4 = 0; | |
1160 } | |
1161 | |
1162 // saturation_time (for flight) | |
1163 if (temp4 > temp2) | |
1164 int_temp = (int)temp4; | |
1165 else | |
1166 int_temp = (int)temp2; | |
1167 if(int_temp > int_O_desaturation_time) | |
1168 int_O_desaturation_time = int_temp; | |
1169 | |
1170 /*// N2 saturation in multiples of halftime for display purposes | |
1171 temp2 = temp1 * 20.0; // 0 = 1/8, 120 = 0, 249 = 8 | |
1172 temp2 = temp2 + 80.0; // set center | |
1173 if (temp2 < 0.0) | |
1174 temp2 = 0.0; | |
1175 if (temp2 > 255.0) | |
1176 temp2 = 255.0; | |
1177 U8_tissue_N2_saturation[ci] = (U8)temp2; | |
1178 // He saturation in multiples of halftime for display purposes | |
1179 temp4 = temp3 * 20.0; // 0 = 1/8, 120 = 0, 249 = 8 | |
1180 temp4 = temp4 + 80.0; // set center | |
1181 if (temp4 < 0.0) | |
1182 temp4 = 0.0; | |
1183 if (temp4 > 255.0) | |
1184 temp4 = 255.0; | |
1185 U8_tissue_He_saturation[ci] = (char)temp4;*/ | |
1186 } | |
1187 | |
1188 return int_O_desaturation_time; | |
1189 } |