Mercurial > public > ostc4
annotate Common/Src/decom.c @ 559:84a4e1200726
Check if HW evaluation was performed:
Devicedata is only requested once at startup and then every 10 minutes. To make sure that HW information related to compass and ADC are forwarded, two indicators have been added which may delay the respond by one second.
author | Ideenmodellierer |
---|---|
date | Sun, 15 Nov 2020 19:52:03 +0100 |
parents | 239aa58b533d |
children | 1b995079c045 |
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> | |
40 #include "settings.h" | |
41 #include "calc_crush.h" | |
42 | |
43 # define FRACTION_N2_AIR 0.7902 | |
44 | |
45 const float helium_time_constant[16] = { | |
46 3.68695308808482E-001, | |
47 2.29518933960247E-001, | |
48 1.46853216220327E-001, | |
49 9.91626867753856E-002, | |
50 6.78890480470074E-002, | |
51 4.78692804254106E-002, | |
52 3.37626488338989E-002, | |
53 2.38113081607676E-002, | |
54 1.68239606932026E-002, | |
55 1.25592893741610E-002, | |
56 9.80544886914621E-003, | |
57 7.67264977374303E-003, | |
58 6.01220557342307E-003, | |
59 4.70185307665137E-003, | |
60 3.68225234041620E-003, | |
61 2.88775228329769E-003}; | |
62 | |
63 const float nitrogen_time_constant[16] = { | |
64 1.38629436111989E-001, | |
65 8.66433975699932E-002, | |
66 5.54517744447956E-002, | |
67 3.74674151654024E-002, | |
68 2.56721177985165E-002, | |
69 1.80978376125312E-002, | |
70 1.27651414467762E-002, | |
71 9.00191143584345E-003, | |
72 6.35914844550409E-003, | |
73 4.74758342849278E-003, | |
74 3.70666941475907E-003, | |
75 2.90019740820061E-003, | |
76 2.27261370675392E-003, | |
77 1.77730046297422E-003, | |
78 1.39186180835330E-003, | |
79 1.09157036308653E-003}; | |
80 | |
81 | |
82 const float buehlmann_N2_a[] = { | |
83 1.1696f, | |
84 1.0000f, | |
85 0.8618f, | |
86 0.7562f, | |
87 0.6200f, | |
88 0.5043f, | |
89 0.4410f, | |
90 0.4000f, | |
91 0.3750f, | |
92 0.3500f, | |
93 0.3295f, | |
94 0.3065f, | |
95 0.2835f, | |
96 0.2610f, | |
97 0.2480f, | |
98 0.2327f}; | |
99 | |
100 const float buehlmann_N2_b[] = { | |
101 0.5578f, | |
102 0.6514f, | |
103 0.7222f, | |
104 0.7825f, | |
105 0.8126f, | |
106 0.8434f, | |
107 0.8693f, | |
108 0.8910f, | |
109 0.9092f, | |
110 0.9222f, | |
111 0.9319f, | |
112 0.9403f, | |
113 0.9477f, | |
114 0.9544f, | |
115 0.9602f, | |
116 0.9653f}; | |
117 | |
118 const float buehlmann_He_a[] = { | |
119 1.6189f, | |
120 1.3830f, | |
121 1.1919f, | |
122 1.0458f, | |
123 0.9220f, | |
124 0.8205f, | |
125 0.7305f, | |
126 0.6502f, | |
127 0.5950f, | |
128 0.5545f, | |
129 0.5333f, | |
130 0.5189f, | |
131 0.5181f, | |
132 0.5176f, | |
133 0.5172f, | |
134 0.5119f}; | |
135 | |
136 const float buehlmann_He_b[] = { | |
137 0.4770f, | |
138 0.5747f, | |
139 0.6527f, | |
140 0.7223f, | |
141 0.7582f, | |
142 0.7957f, | |
143 0.8279f, | |
144 0.8553f, | |
145 0.8757f, | |
146 0.8903f, | |
147 0.8997f, | |
148 0.9073f, | |
149 0.9122f, | |
150 0.9171f, | |
151 0.9217f, | |
152 0.9267f}; | |
153 | |
154 const float buehlmann_N2_t_halflife[] = { | |
155 5.0f, | |
156 8.0f, | |
157 12.5f, | |
158 18.5f, | |
159 27.0f, | |
160 38.3f, | |
161 54.3f, | |
162 77.0f, | |
163 109.0f, | |
164 146.0f, | |
165 187.0f, | |
166 239.0f, | |
167 305.0f, | |
168 390.0f, | |
169 498.0f, | |
170 635.0f}; | |
171 | |
172 const float buehlmann_He_t_halflife[] = { | |
173 1.88f, | |
174 3.02f, | |
175 4.72f, | |
176 6.99f, | |
177 10.21f, | |
178 14.48f, | |
179 20.53f, | |
180 29.11f, | |
181 41.20f, | |
182 55.19f, | |
183 70.69f, | |
184 90.34f, | |
185 115.29f, | |
186 147.42f, | |
187 188.24f, | |
188 240.03f}; | |
189 | |
190 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}; | |
191 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}; | |
192 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}; | |
193 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}; | |
194 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}; | |
195 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}; | |
196 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}; | |
197 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}; | |
198 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}; | |
199 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}; | |
200 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}; | |
201 | |
202 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}; | |
203 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 | |
204 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 | |
205 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}; | |
206 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}; | |
207 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}; | |
208 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}; | |
209 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 | |
210 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 | |
211 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 | |
212 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}; | |
213 | |
214 void decom_get_inert_gases(const float ambient_pressure_bar,const SGas* pGas, float* fraction_nitrogen, float* fraction_helium ) | |
215 { | |
216 float fraction_all_inertgases; | |
217 float ppo2_fraction_setpoint; | |
218 float diluent_divisor; | |
219 | |
220 | |
221 *fraction_nitrogen = ((float)pGas->nitrogen_percentage) / 100.0f; | |
222 *fraction_helium = ((float)pGas->helium_percentage) / 100.0f; | |
223 | |
224 if(!pGas->setPoint_cbar) | |
225 return; | |
226 | |
227 // continue with CCR | |
228 fraction_all_inertgases = *fraction_nitrogen + *fraction_helium; | |
229 | |
230 ppo2_fraction_setpoint = (float)pGas->setPoint_cbar/ (100 * ambient_pressure_bar); | |
231 | |
232 diluent_divisor = (1.0f - ppo2_fraction_setpoint) / fraction_all_inertgases; | |
233 if(diluent_divisor < 0) | |
234 diluent_divisor = 0; | |
235 | |
236 *fraction_nitrogen *= diluent_divisor; | |
237 *fraction_helium *= diluent_divisor; | |
238 } | |
239 | |
240 | |
241 void decom_tissues_exposure(int period_in_seconds, SLifeData * pLifeData) | |
242 { | |
243 decom_tissues_exposure2(period_in_seconds, &pLifeData->actualGas, pLifeData->pressure_ambient_bar, pLifeData->tissue_nitrogen_bar, pLifeData->tissue_helium_bar); | |
244 } | |
245 | |
246 | |
247 void decom_tissues_exposure2(int period_in_seconds, SGas* pActualGas, float ambiant_pressure_bar, float *tissue_N2_selected_stage, float *tissue_He_selected_stage) | |
248 { | |
249 int ci; | |
250 float percent_N2; | |
251 float percent_He; | |
252 float partial_pressure_N2; | |
253 float partial_pressure_He; | |
254 | |
255 | |
256 | |
257 int period_in_seconds_left; | |
258 | |
57 | 259 if(period_in_seconds > 0) |
260 { | |
38 | 261 |
262 decom_get_inert_gases(ambiant_pressure_bar, pActualGas, &percent_N2, &percent_He); | |
263 | |
264 partial_pressure_N2 = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_N2; | |
265 partial_pressure_He = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_He; | |
57 | 266 period_in_seconds_left = period_in_seconds; |
38 | 267 |
57 | 268 while(period_in_seconds_left) |
269 { | |
270 if(period_in_seconds_left >= 3600) | |
271 period_in_seconds = 3600; | |
272 else | |
273 if(period_in_seconds_left >= 800) | |
274 period_in_seconds = 800; | |
275 else | |
276 if(period_in_seconds_left >= 300) | |
277 period_in_seconds = 300; | |
278 else | |
279 if(period_in_seconds_left >= 100) | |
280 period_in_seconds = 100; | |
281 else | |
282 if(period_in_seconds_left >= 60) | |
283 period_in_seconds = 60; | |
284 else | |
285 if(period_in_seconds_left == 36) | |
286 period_in_seconds = 18; | |
287 else | |
288 if(period_in_seconds_left >= 20) | |
289 period_in_seconds = 20; | |
290 else | |
291 if(period_in_seconds_left >= 18) | |
292 period_in_seconds = 18; | |
293 else | |
294 if(period_in_seconds_left >= 10) | |
295 period_in_seconds = 10; | |
296 else | |
297 if(period_in_seconds_left >= 8) | |
298 period_in_seconds = 8; | |
299 else | |
300 if(period_in_seconds_left >= 3) | |
301 period_in_seconds = 3; | |
302 else | |
303 period_in_seconds = 1; | |
38 | 304 |
57 | 305 period_in_seconds_left -= period_in_seconds; |
38 | 306 |
57 | 307 switch (period_in_seconds) |
38 | 308 { |
57 | 309 case 1: |
310 for (ci=0;ci<16;ci++) | |
311 { | |
312 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_one_second[ci]; | |
313 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_one_second[ci]; | |
314 } | |
315 break; | |
316 case 3: | |
317 for (ci=0;ci<16;ci++) | |
318 { | |
319 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_003_second[ci]; | |
320 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_003_second[ci]; | |
321 } | |
322 break; | |
323 case 8: | |
324 for (ci=0;ci<16;ci++) | |
325 { | |
326 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_008_second[ci]; | |
327 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_008_second[ci]; | |
328 } | |
329 break; | |
330 case 10: | |
331 for (ci=0;ci<16;ci++) | |
332 { | |
333 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_10_seconds[ci]; | |
334 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_10_seconds[ci]; | |
335 } | |
336 break; | |
337 case 18: | |
338 for (ci=0;ci<16;ci++) | |
339 { | |
340 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_18_seconds[ci]; | |
341 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_18_seconds[ci]; | |
342 } | |
343 break; | |
344 case 20: | |
345 for (ci=0;ci<16;ci++) | |
346 { | |
347 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_20_seconds[ci]; | |
348 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_20_seconds[ci]; | |
349 } | |
350 break; | |
351 case 60: | |
352 for (ci=0;ci<16;ci++) | |
353 { | |
354 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_one_minute[ci]; | |
355 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_one_minute[ci]; | |
356 } | |
357 break; | |
358 case 100: | |
359 for (ci=0;ci<16;ci++) | |
360 { | |
361 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_100_second[ci]; | |
362 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_100_second[ci]; | |
363 } | |
364 break; | |
365 case 300: | |
366 for (ci=0;ci<16;ci++) | |
367 { | |
368 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_five_minutes[ci]; | |
369 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_five_minutes[ci]; | |
370 } | |
371 break; | |
372 case 800: | |
373 for (ci=0;ci<16;ci++) | |
374 { | |
375 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_800_second[ci]; | |
376 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_800_second[ci]; | |
377 } | |
378 break; | |
379 case 3600: | |
380 for (ci=0;ci<16;ci++) | |
381 { | |
382 tissue_N2_selected_stage[ci] += (partial_pressure_N2 - tissue_N2_selected_stage[ci]) * float_buehlmann_N2_factor_expositon_one_hour[ci]; | |
383 tissue_He_selected_stage[ci] += (partial_pressure_He - tissue_He_selected_stage[ci]) * float_buehlmann_He_factor_expositon_one_hour[ci]; | |
384 } | |
385 break; | |
38 | 386 } |
387 } | |
388 } | |
389 } | |
390 | |
391 void decom_reset_with_1000mbar(SLifeData * pLifeData) | |
392 { | |
393 double saturation = 1.0; | |
394 | |
395 saturation -= WATER_VAPOUR_PRESSURE; | |
396 saturation *= FRACTION_N2_AIR; | |
397 | |
398 for(int i=0;i<16;i++) | |
399 { | |
400 pLifeData->tissue_nitrogen_bar[i] = saturation; | |
401 pLifeData->tissue_helium_bar[i] = 0; | |
402 } | |
403 pLifeData->otu = 0; | |
404 pLifeData->cns = 0; | |
405 pLifeData->desaturation_time_minutes = 0; | |
406 pLifeData->no_fly_time_minutes = 0; | |
407 } | |
408 | |
129
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
409 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
|
410 { |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
411 |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
412 float saturation = 1.0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
413 saturation = ambient; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
414 saturation -= WATER_VAPOUR_PRESSURE; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
415 saturation *= FRACTION_N2_AIR; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
416 |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
417 for(int i=0;i<16;i++) |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
418 { |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
419 pLifeData->tissue_nitrogen_bar[i] = saturation; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
420 pLifeData->tissue_helium_bar[i] = 0; |
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 pLifeData->otu = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
423 pLifeData->cns = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
424 pLifeData->desaturation_time_minutes = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
425 pLifeData->no_fly_time_minutes = 0; |
239aa58b533d
Added function to initialise structures with the actual ambient pressure
Ideenmodellierer
parents:
57
diff
changeset
|
426 } |
38 | 427 |
428 /* =============================================================================== */ | |
429 /* NOTE ABOUT PRESSURE UNITS USED IN CALCULATIONS: */ | |
430 /* It is the convention in decompression calculations to compute all gas */ | |
431 /* loadings, absolute pressures, partial pressures, etc., in the units of */ | |
432 /* depth pressure that you are diving - either feet of seawater (fsw) or */ | |
433 /* meters of seawater (msw). This program follows that convention with the */ | |
434 /* the exception that all VPM calculations are performed in SI units (by */ | |
435 /* necessity). Accordingly, there are several conversions back and forth */ | |
436 /* between the diving pressure units and the SI units. */ | |
437 /* =============================================================================== */ | |
438 /* =============================================================================== */ | |
439 /* FUNCTION SUBPROGRAM FOR GAS LOADING CALCULATIONS - ASCENT AND DESCENT */ | |
440 /* =============================================================================== */ | |
441 | |
442 | |
443 float decom_schreiner_equation(float *initial_inspired_gas_pressure, | |
444 float *rate_change_insp_gas_pressure, | |
445 float *interval_time_minutes, | |
446 const float *gas_time_constant, | |
447 float *initial_gas_pressure) | |
448 { | |
449 /* System generated locals */ | |
450 float ret_val; | |
451 float time_null_pressure = 0.0f; | |
452 float time_rest = 0.0f; | |
453 float time = *interval_time_minutes; | |
454 /* =============================================================================== */ | |
455 /* Note: The Schreiner equation is applied when calculating the uptake or */ | |
456 /* elimination of compartment gases during linear ascents or descents at a */ | |
457 /* constant rate. For ascents, a negative number for rate must be used. */ | |
458 /* =============================================================================== */ | |
459 if( *rate_change_insp_gas_pressure < 0.0f) | |
460 { | |
461 time_null_pressure = -1.0f * *initial_inspired_gas_pressure / *rate_change_insp_gas_pressure; | |
462 if(time > time_null_pressure ) | |
463 { | |
464 time_rest = time - time_null_pressure; | |
465 time = time_null_pressure; | |
466 } | |
467 } | |
468 ret_val = | |
469 *initial_inspired_gas_pressure + | |
470 *rate_change_insp_gas_pressure * | |
471 (time - 1.f / *gas_time_constant) - | |
472 (*initial_inspired_gas_pressure - | |
473 *initial_gas_pressure - | |
474 *rate_change_insp_gas_pressure / *gas_time_constant) * | |
475 expf(-(*gas_time_constant) * time); | |
476 | |
477 if(time_rest > 0.0f) | |
478 { | |
479 ret_val = ret_val * expf(-(*gas_time_constant) * time_rest); | |
480 } | |
481 | |
482 | |
483 return ret_val; | |
484 }; /* schreiner_equation__2 */ | |
485 | |
486 void decom_tissues_exposure_stage_schreiner(int period_in_seconds, SGas* pGas, float starting_ambient_pressure_bar, float ending_ambient_pressure_bar, | |
487 float* pTissue_nitrogen_bar, float* pTissue_helium_bar) | |
488 { | |
489 | |
490 float initial_pressure_N2; | |
491 float initial_pressure_He; | |
492 | |
493 float ending_pressure_N2; | |
494 float ending_pressure_He; | |
495 | |
496 float fraction_N2_begin; | |
497 float fraction_N2_end; | |
498 float fraction_He_begin; | |
499 float fraction_He_end; | |
500 | |
501 float rate_N2; | |
502 float rate_He; | |
503 | |
504 float period_in_minutes; | |
505 | |
506 int ci; | |
507 | |
508 if(period_in_seconds <= 0) | |
509 return; | |
510 | |
511 decom_get_inert_gases(starting_ambient_pressure_bar, pGas, &fraction_N2_begin, &fraction_He_begin ); | |
512 decom_get_inert_gases(ending_ambient_pressure_bar, pGas, &fraction_N2_end, &fraction_He_end ); | |
513 | |
514 initial_pressure_N2 = (starting_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_N2_begin; | |
515 initial_pressure_He = (starting_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_He_begin; | |
516 | |
517 ending_pressure_N2 = (ending_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_N2_end; | |
518 ending_pressure_He = (ending_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * fraction_He_end; | |
519 | |
520 rate_N2 = (ending_pressure_N2 - initial_pressure_N2) / period_in_seconds; | |
521 rate_He = (ending_pressure_He - initial_pressure_He) / period_in_seconds; | |
522 | |
523 period_in_minutes = ((float)period_in_seconds) / 60.0f; | |
524 | |
525 for (ci=0;ci<16;ci++) | |
526 { | |
527 pTissue_nitrogen_bar[ci] = | |
528 decom_schreiner_equation( | |
529 &initial_pressure_N2, | |
530 &rate_N2, | |
531 &period_in_minutes, | |
532 &nitrogen_time_constant[ci], | |
533 &pTissue_nitrogen_bar[ci]); | |
534 | |
535 pTissue_helium_bar[ci] = | |
536 decom_schreiner_equation( | |
537 &initial_pressure_He, | |
538 &rate_He, | |
539 &period_in_minutes, | |
540 &helium_time_constant[ci], | |
541 &pTissue_helium_bar[ci]); | |
542 } | |
543 } | |
544 | |
545 _Bool nextSetpointChange(SDiveSettings* pDiveSettings, uint8_t depth_meter, uint8_t* change_depth_meter, char* setpoint) | |
546 { | |
547 uint8_t new_depth = 0; | |
548 char new_setpoint = 0; | |
549 for(int i = 1; i <= 5; i++) | |
550 { | |
551 if(pDiveSettings->setpoint[i].setpoint_cbar > 0 && pDiveSettings->setpoint[i].depth_meter > 0 ) | |
552 { | |
553 if( pDiveSettings->setpoint[i].depth_meter > new_depth && pDiveSettings->setpoint[i].depth_meter < depth_meter) | |
554 { | |
555 new_depth = pDiveSettings->setpoint[i].depth_meter; | |
556 new_setpoint = pDiveSettings->setpoint[i].setpoint_cbar; | |
557 } | |
558 } | |
559 } | |
560 if(new_depth) | |
561 { | |
562 * change_depth_meter = new_depth; | |
563 * setpoint = new_setpoint; | |
564 return 1; | |
565 } | |
566 return 0; | |
567 } | |
568 | |
569 | |
570 | |
571 void decom_CreateGasChangeList(SDiveSettings* pInput, const SLifeData* pLifeData) | |
572 { | |
573 int i=0, j = 0; | |
574 int count = 0; | |
575 for(i=0;i< 5;i++) | |
576 { | |
577 //FirstGas | |
578 | |
579 pInput->decogaslist[i].change_during_ascent_depth_meter_otherwise_zero = 0; | |
580 pInput->decogaslist[i].GasIdInSettings = 255; | |
581 pInput->decogaslist[i].setPoint_cbar = 0; | |
582 pInput->decogaslist[i].helium_percentage = 0; | |
583 pInput->decogaslist[i].nitrogen_percentage = 0; | |
584 } | |
585 //pInput->liveData.dive_time_seconds = 0; | |
586 | |
587 /* FirstGas | |
588 * 0 = special gas, 1 to 5 ist OC gas, 6 to 10 is diluent | |
589 */ | |
590 | |
591 | |
592 | |
593 pInput->decogaslist[0] = pLifeData->actualGas; | |
594 | |
595 /* Add Deco Gases | |
596 * special (gasId == 0) is never a deco/travel gas but actual gas only | |
597 */ | |
598 if(pInput->diveMode == DIVEMODE_OC) | |
599 { | |
600 | |
601 for(i=1;i<= 5;i++) | |
602 { | |
603 if(pInput->gas[i].note.ub.active && pInput->gas[i].depth_meter | |
604 && (pLifeData->actualGas.GasIdInSettings != i) | |
605 &&(pInput->gas[i].depth_meter < pLifeData->depth_meter ) ) | |
606 { | |
607 count = 1; | |
608 for(j=1;j<= 5;j++) | |
609 { | |
610 if( (pInput->gas[j].note.ub.active && pInput->gas[j].depth_meter > 0) | |
611 && (pLifeData->actualGas.GasIdInSettings != j) // new hw 160905 | |
612 && (pInput->gas[j].depth_meter > pInput->gas[i].depth_meter)) | |
613 count++; | |
614 } | |
615 pInput->decogaslist[count].change_during_ascent_depth_meter_otherwise_zero = pInput->gas[i].depth_meter; | |
616 pInput->decogaslist[count].nitrogen_percentage = 100; | |
617 pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].oxygen_percentage; | |
618 pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].helium_percentage; | |
619 pInput->decogaslist[count].helium_percentage = pInput->gas[i].helium_percentage; | |
620 pInput->decogaslist[count].GasIdInSettings = i; | |
621 | |
622 } | |
623 } | |
624 } | |
625 else | |
626 { | |
627 //divmode CCR | |
628 for(i=6; i <= 10; i++) | |
629 { | |
630 if(pInput->gas[i].note.ub.active && pInput->gas[i].depth_meter | |
631 && (pLifeData->actualGas.GasIdInSettings != i) | |
632 &&(pInput->gas[i].depth_meter < pLifeData->depth_meter ) ) | |
633 { | |
634 count = 1; | |
635 for(j=6;j<= 10;j++) | |
636 { | |
637 // if(pInput->gas[j].note.ub.active && pInput->gas[j].depth_meter > 0 &&pInput->gas[j].depth_meter > pInput->gas[i].depth_meter) | |
638 if( (pInput->gas[j].note.ub.active && pInput->gas[j].depth_meter > 0) | |
639 && (pLifeData->actualGas.GasIdInSettings != j) // new hw 160905 | |
640 && (pInput->gas[j].depth_meter > pInput->gas[i].depth_meter)) | |
641 count++; | |
642 } | |
643 pInput->decogaslist[count].change_during_ascent_depth_meter_otherwise_zero = pInput->gas[i].depth_meter; | |
644 pInput->decogaslist[count].nitrogen_percentage = 100; | |
645 pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].oxygen_percentage; | |
646 pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].helium_percentage; | |
647 pInput->decogaslist[count].helium_percentage = pInput->gas[i].helium_percentage; | |
648 pInput->decogaslist[count].GasIdInSettings = i; | |
649 | |
650 } | |
651 } | |
652 /* Include Setpoint Changes */ | |
653 for(j=0; j <= count; j++) | |
654 { | |
655 uint8_t depth = 0; | |
656 uint8_t changedepth = 0; | |
657 char newSetpoint; | |
658 if(j == 0) | |
659 { | |
660 depth = pLifeData->depth_meter; | |
661 } | |
662 else | |
663 { | |
664 //no setpointchange ? | |
665 pInput->decogaslist[j].setPoint_cbar = pInput->decogaslist[j - 1].setPoint_cbar; | |
666 depth = pInput->decogaslist[j].change_during_ascent_depth_meter_otherwise_zero + 0.1f; | |
667 } | |
668 /* Setpoint change at the same depth as gas changes */ | |
669 if(nextSetpointChange(pInput,depth + 1, &changedepth,&newSetpoint) && changedepth == depth) | |
670 { | |
671 pInput->decogaslist[j].setPoint_cbar = newSetpoint; | |
672 } | |
673 /* Setpoint changes inbetween gas changes */ | |
674 while(nextSetpointChange(pInput, depth, &changedepth,&newSetpoint) | |
675 && ( | |
676 ( (j < count) && (changedepth > pInput->decogaslist[j + 1].change_during_ascent_depth_meter_otherwise_zero)) | |
677 || ((j == count) && (changedepth > 0)) | |
678 )) | |
679 { | |
680 //Include new entry with setpoint change in decogaslist | |
681 for(int k = count; k > j; k--) | |
682 { | |
683 pInput->decogaslist[k+1] = pInput->decogaslist[k]; | |
684 } | |
685 pInput->decogaslist[j + 1] = pInput->decogaslist[j]; | |
686 pInput->decogaslist[j + 1].setPoint_cbar = newSetpoint; | |
687 j++; | |
688 count++; | |
689 depth = changedepth; | |
690 } | |
691 | |
692 } | |
693 | |
694 } | |
695 } | |
696 void test_decom_CreateGasChangeList(void) | |
697 { | |
698 SDiveSettings diveSetting; | |
699 SLifeData lifeData; | |
700 lifeData.depth_meter = 100; | |
701 lifeData.actualGas.helium_percentage = 30; | |
702 lifeData.actualGas.nitrogen_percentage = 60; | |
703 lifeData.actualGas.setPoint_cbar = 18; | |
704 lifeData.actualGas.GasIdInSettings = 0; | |
705 lifeData.actualGas.change_during_ascent_depth_meter_otherwise_zero = 0; | |
706 diveSetting.diveMode = DIVEMODE_CCR; | |
707 diveSetting.gas[6].depth_meter = 0; | |
708 diveSetting.gas[6].helium_percentage = 30; | |
709 diveSetting.gas[6].oxygen_percentage = 10; | |
710 diveSetting.gas[6].note.ub.active = 1; | |
711 | |
712 diveSetting.gas[7].depth_meter = 60; | |
713 diveSetting.gas[7].helium_percentage = 0; | |
714 diveSetting.gas[7].oxygen_percentage = 10; | |
715 diveSetting.gas[7].note.ub.active = 1; | |
716 diveSetting.gas[8].note.ub.active = 0; | |
717 diveSetting.gas[9].note.ub.active = 0; | |
718 diveSetting.gas[10].note.ub.active = 0; | |
719 | |
720 diveSetting.setpoint[0].depth_meter = 0; | |
721 diveSetting.setpoint[1].depth_meter = 80; | |
722 diveSetting.setpoint[1].setpoint_cbar = 20; | |
723 diveSetting.setpoint[2].depth_meter = 60; | |
724 diveSetting.setpoint[2].setpoint_cbar = 25; | |
725 diveSetting.setpoint[3].depth_meter = 0; | |
726 diveSetting.setpoint[4].depth_meter = 0; | |
727 diveSetting.setpoint[5].depth_meter = 0; | |
728 | |
729 | |
730 decom_CreateGasChangeList(&diveSetting, &lifeData); | |
731 } | |
732 | |
733 uint8_t decom_tissue_test_tolerance(float* Tissue_nitrogen_bar, float* Tissue_helium_bar, float GF_value, float depth_in_bar_absolute) | |
734 { | |
735 float tissue_inertgas_saturation; | |
736 float inertgas_a; | |
737 float inertgas_b; | |
738 float inertgas_tolerance; | |
739 float gf_minus_1; | |
740 | |
741 gf_minus_1 = GF_value - 1.0f; | |
742 | |
743 for (int ci = 0; ci < 16; ci++) | |
744 { | |
745 if(Tissue_helium_bar[ci] == 0) | |
746 { | |
747 tissue_inertgas_saturation = Tissue_nitrogen_bar[ci]; | |
748 // | |
749 inertgas_a = buehlmann_N2_a[ci]; | |
750 inertgas_b = buehlmann_N2_b[ci]; | |
751 } | |
752 else | |
753 { | |
754 tissue_inertgas_saturation = Tissue_nitrogen_bar[ci] + Tissue_helium_bar[ci]; | |
755 // | |
756 inertgas_a = ( ( buehlmann_N2_a[ci] * Tissue_nitrogen_bar[ci]) + ( buehlmann_He_a[ci] * Tissue_helium_bar[ci]) ) / tissue_inertgas_saturation; | |
757 inertgas_b = ( ( buehlmann_N2_b[ci] * Tissue_nitrogen_bar[ci]) + ( buehlmann_He_b[ci] * Tissue_helium_bar[ci]) ) / tissue_inertgas_saturation; | |
758 } | |
759 // | |
760 inertgas_tolerance = ( (GF_value / inertgas_b - gf_minus_1) * depth_in_bar_absolute ) + ( GF_value * inertgas_a ); | |
761 // | |
762 if(inertgas_tolerance < tissue_inertgas_saturation) | |
763 return 0; | |
764 } | |
765 return 1; | |
766 } | |
767 | |
768 | |
769 void decom_tissues_desaturation_time(const SLifeData* pLifeData, SLifeData2* pOutput) | |
770 { | |
771 float pressure_in_gas_for_complete; | |
772 float pressure_in_gas_for_desat; | |
773 float diff_to_complete; | |
774 float diff_to_desatpoint; | |
775 float necessary_halftimes; | |
776 float desattime; | |
777 | |
778 pressure_in_gas_for_complete = 0.7902f * ( pLifeData->pressure_surface_bar - 0.0627f); | |
779 pressure_in_gas_for_desat = 1.05f * pressure_in_gas_for_complete; | |
780 for(int i=0; i<16; i++) | |
781 { | |
782 diff_to_complete = pressure_in_gas_for_complete - pLifeData->tissue_nitrogen_bar[i]; | |
783 diff_to_desatpoint = pressure_in_gas_for_desat - pLifeData->tissue_nitrogen_bar[i]; | |
784 | |
785 if((diff_to_desatpoint >= 0) || (diff_to_complete >= 0)) | |
786 pOutput->tissue_nitrogen_desaturation_time_minutes[i] = 0; | |
787 else | |
788 { | |
789 necessary_halftimes = (logf(1.0f - (diff_to_desatpoint/diff_to_complete)) / -0.6931f); | |
790 desattime = buehlmann_N2_t_halflife[i] * necessary_halftimes; | |
791 if(desattime <= (float)0xFFFF) | |
792 pOutput->tissue_nitrogen_desaturation_time_minutes[i] = desattime; | |
793 else | |
794 pOutput->tissue_nitrogen_desaturation_time_minutes[i] = 0xFFFF; | |
795 } | |
796 } | |
797 | |
798 for(int i=0; i<16; i++) | |
799 { | |
800 diff_to_desatpoint = 0.05f - pLifeData->tissue_helium_bar[i]; | |
801 diff_to_complete = -1.0f * pLifeData->tissue_helium_bar[i]; | |
802 | |
803 if((diff_to_desatpoint >= 0) || (diff_to_complete >= 0)) | |
804 pOutput->tissue_helium_desaturation_time_minutes[i] = 0; | |
805 else | |
806 { | |
807 necessary_halftimes = (logf(1.0f - (diff_to_desatpoint/diff_to_complete)) / -0.6931f); | |
808 desattime = buehlmann_He_t_halflife[i] * necessary_halftimes; | |
809 if(desattime <= (float)0xFFFF) | |
810 pOutput->tissue_helium_desaturation_time_minutes[i] = desattime; | |
811 else | |
812 pOutput->tissue_helium_desaturation_time_minutes[i] = 0xFFFF; | |
813 } | |
814 } | |
815 } | |
816 | |
817 #define MAX_DEGRADE_OTU_TIME_MINUTES (1440) | |
818 //CNS&OTU: | |
819 #define OXY_TEN_MINUTES_IN_SECONDS (600) | |
820 #define OXY_HALF_LIVE_OF_TEN_MINUTES__INVERSE_NINTH_ROOT_OF_TWO (0.92587471f) | |
821 #define OXY_NINE_DAYS_IN_TEN_MINUTES (1296) | |
822 #define OXY_ONE_SIXTIETH_PART (0.0166667f) | |
823 #define OXY_NEGATIVE_FIVE_SIXTH_PARTS (-0.8333333f) | |
824 void decom_oxygen_calculate_otu(float* oxygen_otu, float pressure_oxygen_real) | |
825 { | |
826 if(pressure_oxygen_real <= 0.5f) | |
827 return; | |
828 *oxygen_otu += (pow((double)(0.5f / (pressure_oxygen_real - 0.5f)),OXY_NEGATIVE_FIVE_SIXTH_PARTS)) * OXY_ONE_SIXTIETH_PART; | |
829 } | |
830 | |
831 void decom_oxygen_calculate_otu_degrade(float* oxygen_otu, long seconds_since_last_dive) | |
832 { | |
833 static long otu_time_ticker = 0; | |
834 static double otu_degrade_every_10_minutes = 999.9; | |
835 long cycles_since_last_call; | |
836 | |
837 if((*oxygen_otu <= 0) || (seconds_since_last_dive == 0)) | |
838 *oxygen_otu = 0; | |
839 else if(seconds_since_last_dive < OXY_TEN_MINUTES_IN_SECONDS) | |
840 { | |
841 otu_time_ticker = 1; | |
842 otu_degrade_every_10_minutes = *oxygen_otu / (MAX_DEGRADE_OTU_TIME_MINUTES / 10); | |
843 } | |
844 else | |
845 { | |
846 cycles_since_last_call = seconds_since_last_dive / (otu_time_ticker * OXY_TEN_MINUTES_IN_SECONDS); | |
847 *oxygen_otu -= ((double)cycles_since_last_call) * otu_degrade_every_10_minutes; | |
848 otu_time_ticker += cycles_since_last_call; | |
849 if((*oxygen_otu < 0) || (otu_time_ticker > (MAX_DEGRADE_OTU_TIME_MINUTES / 10))) | |
850 *oxygen_otu = 0; | |
851 } | |
852 } | |
853 | |
854 | |
855 | |
856 void decom_oxygen_calculate_cns_degrade(float* oxygen_cns, long seconds_since_last_dive) | |
857 { | |
858 static long cns_time_ticker = 0; | |
859 int cns_max_cycles; | |
860 | |
861 if((*oxygen_cns <= 0.5f) || (seconds_since_last_dive == 0)) | |
862 *oxygen_cns = 0; | |
863 else if(seconds_since_last_dive < OXY_TEN_MINUTES_IN_SECONDS) | |
864 cns_time_ticker = 1; | |
865 else | |
866 { | |
867 cns_max_cycles = OXY_NINE_DAYS_IN_TEN_MINUTES; | |
868 while((*oxygen_cns >= 0.5f) && ((cns_time_ticker * OXY_TEN_MINUTES_IN_SECONDS) < seconds_since_last_dive) && cns_max_cycles) | |
869 { | |
870 cns_time_ticker++; | |
871 cns_max_cycles--; | |
872 *oxygen_cns *= OXY_HALF_LIVE_OF_TEN_MINUTES__INVERSE_NINTH_ROOT_OF_TWO; | |
873 } | |
874 } | |
875 } | |
876 | |
877 | |
878 // new hwOS style | |
879 void decom_oxygen_calculate_cns(float* oxygen_cns, float pressure_oxygen_real) | |
880 { | |
881 uint8_t char_I_actual_ppO2; | |
882 float CNS_fraction = 0; | |
883 const float time_factor = 3000.0f; | |
884 | |
885 if(pressure_oxygen_real < 0.15f) | |
886 char_I_actual_ppO2 = 15; | |
887 else | |
888 if(pressure_oxygen_real >= 2.5f) | |
889 char_I_actual_ppO2 = 255; | |
890 else | |
891 char_I_actual_ppO2 = (uint8_t)(pressure_oxygen_real * 100); | |
892 | |
893 if (char_I_actual_ppO2 < 50) | |
894 (void)0; // no changes | |
895 //------------------------------------------------------------------------ | |
896 // Below (and including) 1.60 bar | |
897 else if (char_I_actual_ppO2 < 61) | |
898 CNS_fraction += time_factor/(-533.07f * char_I_actual_ppO2 + 54000.0f); | |
899 else if (char_I_actual_ppO2 < 71) | |
900 CNS_fraction += time_factor/(-444.22f * char_I_actual_ppO2 + 48600.0f); | |
901 else if (char_I_actual_ppO2 < 81) | |
902 CNS_fraction += time_factor/(-355.38f * char_I_actual_ppO2 + 42300.0f); | |
903 else if (char_I_actual_ppO2 < 91) | |
904 CNS_fraction += time_factor/(-266.53f * char_I_actual_ppO2 + 35100.0f); | |
905 else if (char_I_actual_ppO2 < 111) | |
906 CNS_fraction += time_factor/(-177.69f * char_I_actual_ppO2 + 27000.0f); | |
907 else if (char_I_actual_ppO2 < 152) | |
908 CNS_fraction += time_factor/( -88.84f * char_I_actual_ppO2 + 17100.0f); | |
909 else if (char_I_actual_ppO2 < 167) | |
910 CNS_fraction += time_factor/(-222.11f * char_I_actual_ppO2 + 37350.0f); | |
911 //------------------------------------------------------------------------ | |
912 // Arieli et all.(2002): Modeling pulmonary and CNS O2 toxicity: | |
913 // J Appl Physiol 92: 248--256, 2002, doi:10.1152/japplphysiol.00434.2001 | |
914 // Formula (A1) based on value for 1.55 and c=20 | |
915 // example calculation: Sqrt((1.7/1.55)^20)*0.000404 | |
916 else if (char_I_actual_ppO2 < 172) | |
917 CNS_fraction += time_factor*0.00102f; | |
918 else if (char_I_actual_ppO2 < 177) | |
919 CNS_fraction += time_factor*0.00136f; | |
920 else if (char_I_actual_ppO2 < 182) | |
921 CNS_fraction += time_factor*0.00180f; | |
922 else if (char_I_actual_ppO2 < 187) | |
923 CNS_fraction += time_factor*0.00237f; | |
924 else if (char_I_actual_ppO2 < 192) | |
925 CNS_fraction += time_factor*0.00310f; | |
926 else if (char_I_actual_ppO2 < 198) | |
927 CNS_fraction += time_factor*0.00401f; | |
928 else if (char_I_actual_ppO2 < 203) | |
929 CNS_fraction += time_factor*0.00517f; | |
930 else if (char_I_actual_ppO2 < 233) | |
931 CNS_fraction += time_factor*0.0209f; | |
932 else | |
933 CNS_fraction += time_factor*0.0482f; // value for 2.5 | |
934 | |
935 if( CNS_fraction > 999.0f) // Limit display to 999% | |
936 CNS_fraction = 999.0f; | |
937 if( CNS_fraction < 0.0f ) | |
938 CNS_fraction = 0.0f; | |
939 | |
940 //calculate cns for the actual ppo2 for 1 second | |
941 *oxygen_cns += OXY_ONE_SIXTIETH_PART * CNS_fraction; | |
942 | |
943 if( *oxygen_cns > 999.0f) // Limit display to 999% | |
944 *oxygen_cns = 999.0f; | |
945 if( *oxygen_cns < 0.0f ) | |
946 *oxygen_cns = 0.0f; | |
947 } | |
948 | |
949 /* old DR5 style | |
950 void decom_oxygen_calculate_cns(float* oxygen_cns, float pressure_oxygen_real) | |
951 { | |
952 int cns_no_range = 0; | |
953 _Bool not_found = 1; | |
954 //for the cns calculation | |
955 const float cns_ppo2_ranges[60][2] = { | |
956 {0.50f, 0.00f}, {0.60f, 0.14f}, {0.64f, 0.15f}, {0.66f, 0.16f}, {0.68f, 0.17f}, {0.70f, 0.18f}, | |
957 {0.74f, 0.19f}, {0.76f, 0.20f}, {0.78f, 0.21f}, {0.80f, 0.22f}, {0.82f, 0.23f}, {0.84f, 0.24f}, | |
958 {0.86f, 0.25f}, {0.88f, 0.26f}, {0.90f, 0.28f}, {0.92f, 0.29f}, {0.94f, 0.30f}, {0.96f, 0.31f}, | |
959 {0.98f, 0.32f}, {1.00f, 0.33f}, {1.02f, 0.35f}, {1.04f, 0.36f}, {1.06f, 0.38f}, {1.08f, 0.40f}, | |
960 {1.10f, 0.42f}, {1.12f, 0.43f}, {1.14f, 0.43f}, {1.16f, 0.44f}, {1.18f, 0.46f}, {1.20f, 0.47f}, | |
961 {1.22f, 0.48f}, {1.24f, 0.51f}, {1.26f, 0.52f}, {1.28f, 0.54f}, {1.30f, 0.56f}, {1.32f, 0.57f}, | |
962 {1.34f, 0.60f}, {1.36f, 0.62f}, {1.38f, 0.63f}, {1.40f, 0.65f}, {1.42f, 0.68f}, {1.44f, 0.71f}, | |
963 {1.46f, 0.74f}, {1.48f, 0.78f}, {1.50f, 0.83f}, {1.52f, 0.93f}, {1.54f, 1.04f}, {1.56f, 1.19f}, | |
964 {1.58f, 1.47f}, {1.60f, 2.22f}, {1.62f, 5.00f}, {1.65f, 6.25f}, {1.67f, 7.69f}, {1.70f, 10.0f}, | |
965 {1.72f,12.50f}, {1.74f,20.00f}, {1.77f,25.00f}, {1.79f,31.25f}, {1.80f,50.00f}, {1.82f,100.0f}}; | |
966 //find the correct cns range for the corresponding ppo2 | |
967 cns_no_range = 58; | |
968 while (cns_no_range && not_found) | |
969 { | |
970 if (pressure_oxygen_real > cns_ppo2_ranges[cns_no_range][0]) | |
971 { | |
972 cns_no_range++; | |
973 not_found = 0; | |
974 } | |
975 else | |
976 cns_no_range--; | |
977 } | |
978 | |
979 //calculate cns for the actual ppo2 for 1 second | |
980 *oxygen_cns += OXY_ONE_SIXTIETH_PART * cns_ppo2_ranges[cns_no_range][1]; | |
981 } | |
982 */ | |
983 | |
984 void decom_oxygen_calculate_cns_exposure(int period_in_seconds, SGas* pActualGas, float pressure_ambient_bar, float* oxygen_cns) | |
985 { | |
986 float pressure_oxygen_real; | |
987 float one_second_cns; | |
988 | |
989 pressure_oxygen_real = decom_calc_ppO2(pressure_ambient_bar, pActualGas); | |
990 one_second_cns = 0; | |
991 decom_oxygen_calculate_cns(&one_second_cns, pressure_oxygen_real); | |
992 *oxygen_cns += one_second_cns * period_in_seconds; | |
993 } | |
994 | |
995 | |
996 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) | |
997 { | |
998 if(ending_ambient_pressure_bar == starting_ambient_pressure_bar) | |
999 { | |
1000 decom_oxygen_calculate_cns_exposure(period_in_seconds, pGas, starting_ambient_pressure_bar, oxygen_cns); | |
1001 return; | |
1002 } | |
1003 | |
1004 float pressure_oxygen_real; | |
1005 float initial_pressure_oxygen; | |
1006 float ending_pressure_oxygen; | |
1007 float rate_oxygen; | |
1008 | |
1009 initial_pressure_oxygen = decom_calc_ppO2(starting_ambient_pressure_bar, pGas); | |
1010 ending_pressure_oxygen = decom_calc_ppO2(ending_ambient_pressure_bar, pGas); | |
1011 | |
1012 rate_oxygen = (ending_pressure_oxygen - initial_pressure_oxygen) / period_in_seconds; | |
1013 | |
1014 pressure_oxygen_real = initial_pressure_oxygen; | |
1015 for(int i = 0; i < period_in_seconds; i++) | |
1016 { | |
1017 decom_oxygen_calculate_cns(oxygen_cns, pressure_oxygen_real); | |
1018 pressure_oxygen_real += rate_oxygen; | |
1019 } | |
1020 } | |
1021 | |
1022 | |
1023 float decom_calc_ppO2(const float ambiant_pressure_bar, const SGas* pGas) | |
1024 { | |
1025 float percent_N2 = 0; | |
1026 float percent_He = 0; | |
1027 float percent_O2 = 0; | |
1028 decom_get_inert_gases(ambiant_pressure_bar, pGas, &percent_N2, &percent_He); | |
1029 percent_O2 = 1 - percent_N2 - percent_He; | |
1030 | |
1031 return (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_O2; | |
1032 } | |
1033 | |
1034 | |
1035 uint8_t decom_get_actual_deco_stop(SDiveState* pDiveState) | |
1036 { | |
1037 SDecoinfo* pDecoinfo; | |
1038 uint8_t depthNext, depthLast, depthSecond, depthInc; | |
1039 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
1040 pDecoinfo = &pDiveState->decolistBuehlmann; | |
1041 else | |
1042 pDecoinfo = &pDiveState->decolistVPM; | |
1043 | |
1044 depthLast = (uint8_t)(pDiveState->diveSettings.last_stop_depth_bar * 10); | |
1045 depthSecond = (uint8_t)(pDiveState->diveSettings.input_second_to_last_stop_depth_bar * 10); | |
1046 depthInc = (uint8_t)(pDiveState->diveSettings.input_next_stop_increment_depth_bar * 10); | |
1047 if(pDecoinfo->output_stop_length_seconds[0] > 0) | |
1048 { | |
1049 depthNext = depthLast; | |
1050 } | |
1051 else | |
1052 return 0; | |
1053 for(int i = DECOINFO_STRUCT_MAX_STOPS -1 ;i > 0; i--) | |
1054 { | |
1055 if(pDecoinfo->output_stop_length_seconds[i] > 0) | |
1056 { | |
1057 depthNext = depthSecond + ( (i - 1) * depthInc); | |
1058 break; | |
1059 } | |
1060 } | |
1061 return depthNext; | |
1062 } | |
1063 | |
1064 | |
1065 // =============================================================================== | |
1066 // decom_calc_desaturation_time | |
1067 /// @brief This code is used to calculate desat, calculated by RTE and send to Firmware | |
1068 /// similar but more technical in code than decom_tissues_desaturation_time() | |
1069 /// the later has 0.05 for helium in contrast to this one. | |
1070 /// This one goes down to 70%, the oterh | |
1071 /// | |
1072 /// output is desat time in minutes | |
1073 // =============================================================================== | |
1074 int decom_calc_desaturation_time(float* Tissue_nitrogen_bar, float* Tissue_helium_bar, float surface_pressure_bar) | |
1075 { | |
1076 const float N2_ratio = 0.7902; // FIXED sum as stated in b"uhlmann | |
1077 | |
1078 float pres_surface; | |
1079 float temp_atem; | |
1080 float float_desaturation_multiplier; | |
1081 float temp1,temp2,temp3,temp4; | |
1082 int ci; | |
1083 int int_temp; | |
1084 int int_O_desaturation_time; | |
1085 pres_surface = ((float)surface_pressure_bar); | |
1086 temp_atem = N2_ratio * (pres_surface - 0.0627f); | |
1087 | |
1088 int_O_desaturation_time = 0; | |
1089 float_desaturation_multiplier = 100 / 142.0f; // new in v.101 (70,42%/100.=142) | |
1090 | |
1091 for (ci=0;ci<16;ci++) | |
1092 { | |
1093 // saturation_time (for flight) and N2_saturation in multiples of halftime | |
1094 // version v.100: 1.1 = 10 percent distance to totally clean (totally clean is not possible, would take infinite time ) | |
1095 // new in version v.101: 1.07 = 7 percent distance to totally clean (totally clean is not possible, would take infinite time ) | |
1096 // changes in v.101: 1.05 = 5 percent dist to totally clean is new desaturation point for display and noFly calculations | |
1097 | |
1098 // N2 | |
1099 temp1 = 1.05f * temp_atem; | |
1100 temp1 = temp1 - (float)Tissue_nitrogen_bar[ci]; | |
1101 temp2 = temp_atem - (float)Tissue_nitrogen_bar[ci]; | |
1102 if (temp2 >= 0) | |
1103 { | |
1104 temp1 = 0; | |
1105 temp2 = 0; | |
1106 } | |
1107 else | |
1108 temp1 = temp1 / temp2; | |
1109 | |
1110 if (temp1 > 0) | |
1111 { | |
1112 temp1 = logf(1.0f - temp1); | |
1113 temp1 = temp1 / -0.6931f; // temp1 is the multiples of half times necessary. | |
1114 // 0.6931 is ln(2), because the math function log() calculates with a base of e not 2 as requested. | |
1115 // minus because log is negative | |
1116 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 | |
1117 } | |
1118 else | |
1119 { | |
1120 temp1 = 0; | |
1121 temp2 = 0; | |
1122 } | |
1123 | |
1124 // He | |
1125 temp3 = 0.1f - (float)Tissue_helium_bar[ci]; | |
1126 if (temp3 >= 0) | |
1127 { | |
1128 temp3 = 0; | |
1129 temp4 = 0; | |
1130 } | |
1131 else | |
1132 temp3 = -1.0f * temp3 / (float)Tissue_helium_bar[ci]; | |
1133 if (temp3 > 0) | |
1134 { | |
1135 temp3 = logf(1.0f - temp3); | |
1136 temp3 = temp3 / -0.6931f; // temp1 is the multiples of half times necessary. | |
1137 // 0.6931 is ln(2), because the math function log() calculates with a base of e not 2 as requested. | |
1138 // minus because log is negative | |
1139 temp4 = buehlmann_He_t_halflife[ci] * temp3 / float_desaturation_multiplier; // time necessary (in minutes ) for "complete" desaturation, new in v.101 float_desaturation_multiplier | |
1140 } | |
1141 else | |
1142 { | |
1143 temp3 = 0; | |
1144 temp4 = 0; | |
1145 } | |
1146 | |
1147 // saturation_time (for flight) | |
1148 if (temp4 > temp2) | |
1149 int_temp = (int)temp4; | |
1150 else | |
1151 int_temp = (int)temp2; | |
1152 if(int_temp > int_O_desaturation_time) | |
1153 int_O_desaturation_time = int_temp; | |
1154 | |
1155 /*// N2 saturation in multiples of halftime for display purposes | |
1156 temp2 = temp1 * 20.0; // 0 = 1/8, 120 = 0, 249 = 8 | |
1157 temp2 = temp2 + 80.0; // set center | |
1158 if (temp2 < 0.0) | |
1159 temp2 = 0.0; | |
1160 if (temp2 > 255.0) | |
1161 temp2 = 255.0; | |
1162 U8_tissue_N2_saturation[ci] = (U8)temp2; | |
1163 // He saturation in multiples of halftime for display purposes | |
1164 temp4 = temp3 * 20.0; // 0 = 1/8, 120 = 0, 249 = 8 | |
1165 temp4 = temp4 + 80.0; // set center | |
1166 if (temp4 < 0.0) | |
1167 temp4 = 0.0; | |
1168 if (temp4 > 255.0) | |
1169 temp4 = 255.0; | |
1170 U8_tissue_He_saturation[ci] = (char)temp4;*/ | |
1171 } | |
1172 | |
1173 return int_O_desaturation_time; | |
1174 } |