Mercurial > public > ostc4
annotate Discovery/Src/simulation.c @ 261:cc2406b835ff bm-3
Bugfix: do not reset saturation on surfacing
Commit 822416168585 introduced a subtle bug. On surfacing, the value of
saturation was reset to 0. This is prefect proof why global data is a
dangerous thing, and subtle changes can introduce seemingly unrelated
bugs.
While it would be much better to factor out as much as possible global
data, the fix here does not do that. Simply, the bug is fixed without
touching the rather complex gTissue_nitrogen_bar/gTissue_helium_bar
handling.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
author | Jan Mulder <jlmulder@xs4all.nl> |
---|---|
date | Tue, 23 Apr 2019 13:05:20 +0200 |
parents | 9f0efc4df01e |
children | 5ca177d2df5d |
rev | line source |
---|---|
38 | 1 /////////////////////////////////////////////////////////////////////////////// |
2 /// -*- coding: UTF-8 -*- | |
3 /// | |
4 /// \file Discovery/Src/simulation.c | |
5 /// \brief Contains dive simulation functionality | |
6 /// \author Heinrichs Weikamp gmbh | |
7 /// \date 13-Oct-2014 | |
8 /// | |
9 /// \details | |
10 /// The simulation uses "extern SDiveState stateSim" defined in dataCentral.h" | |
11 /// | |
12 /// simulation_start(void) sets stateUsed to stateSim and initializes simulation | |
13 /// simulation_UpdateLifeData should be called at least once per second | |
14 /// simulation_end() sets stateUsed back to stateReal | |
15 /// | |
16 /// $Id$ | |
17 /////////////////////////////////////////////////////////////////////////////// | |
18 /// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh | |
19 /// | |
20 /// This program is free software: you can redistribute it and/or modify | |
21 /// it under the terms of the GNU General Public License as published by | |
22 /// the Free Software Foundation, either version 3 of the License, or | |
23 /// (at your option) any later version. | |
24 /// | |
25 /// This program is distributed in the hope that it will be useful, | |
26 /// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 /// GNU General Public License for more details. | |
29 /// | |
30 /// You should have received a copy of the GNU General Public License | |
31 /// along with this program. If not, see <http://www.gnu.org/licenses/>. | |
32 ////////////////////////////////////////////////////////////////////////////// | |
33 | |
34 #include <string.h> | |
35 #include "simulation.h" | |
36 | |
37 #include "decom.h" | |
38 #include "calc_crush.h" | |
39 #include "data_exchange.h" | |
40 #include "timer.h" | |
41 #include "check_warning.h" | |
42 #include "vpm.h" | |
43 #include "buehlmann.h" | |
44 #include "logbook_miniLive.h" | |
45 | |
46 //Private state variables | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
47 static float sim_aim_depth_meter; |
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
48 static _Bool sim_heed_decostops = 1; |
38 | 49 |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
50 static const float sim_descent_rate_meter_per_min = 20; |
38 | 51 |
52 | |
53 //Private functions | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
54 static float sim_get_ambiant_pressure(SDiveState * pDiveState); |
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
55 static void sim_reduce_deco_time_one_second(SDiveState* pDiveState); |
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
56 static void simulation_set_aim_depth(int depth_meter); |
38 | 57 |
58 /** | |
59 ****************************************************************************** | |
60 * @brief sets heed_decostops_while_ascending | |
61 ****************************************************************************** | |
62 * @param heed_decostops_while_ascending : true -> deco_stops are considered while ascending | |
63 * @return void | |
64 */ | |
65 void simulation_set_heed_decostops(_Bool heed_decostops_while_ascending) | |
66 { | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
67 sim_heed_decostops = heed_decostops_while_ascending; |
38 | 68 } |
69 | |
70 /** | |
71 ****************************************************************************** | |
72 * @brief start of simulation | |
73 ****************************************************************************** | |
74 * @return void | |
75 */ | |
76 void simulation_start(int aim_depth) | |
77 { | |
78 copyDiveSettingsToSim(); | |
79 copyVpmRepetetiveDataToSim(); | |
80 //vpm_init(&stateSimGetPointerWrite()->vpm, stateSimGetPointerWrite()->diveSettings.vpm_conservatism, 0, 0); | |
81 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 0; | |
82 stateSimGetPointerWrite()->mode = MODE_DIVE; | |
83 if(aim_depth <= 0) | |
84 aim_depth = 20; | |
85 simulation_set_aim_depth(aim_depth); | |
86 timer_init(); | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
87 set_stateUsedToSim(); |
38 | 88 stateSim.lifeData.boolResetAverageDepth = 1; |
89 decoLock = DECO_CALC_init_as_is_start_of_dive; | |
90 | |
91 stateSim.lifeData.apnea_total_max_depth_meter = 0; | |
92 } | |
93 | |
94 /** | |
95 ****************************************************************************** | |
96 * @brief end of simulation | |
97 ****************************************************************************** | |
98 * | |
99 * @return void | |
100 */ | |
101 void simulation_exit(void) | |
102 { | |
103 timer_Stopwatch_Stop(); | |
104 set_stateUsedToReal(); | |
105 } | |
106 | |
107 /** | |
108 ****************************************************************************** | |
109 * @brief simulates change of Lifedata (saturation, depth change, etc.) within one second | |
110 ****************************************************************************** | |
111 * | |
112 * @param checkOncePerSecond : true -> simulation in real time (function is evaluated only once per second) | |
113 * and copy of parts of LifeData from SmallCPU with each call from HAL_TIM_PeriodElapsedCallback() | |
114 * : false -> fast simulation (many simulation cycles per second are possible) | |
115 * @return void | |
116 */ | |
117 void simulation_UpdateLifeData( _Bool checkOncePerSecond) | |
118 { | |
119 SDiveState * pDiveState = &stateSim; | |
120 | |
121 static int last_second = -1; | |
122 static _Bool two_second = 0; | |
123 static float lastPressure_bar = 0; | |
124 | |
125 if(checkOncePerSecond) | |
126 { | |
127 pDiveState->lifeData.temperature_celsius = stateRealGetPointer()->lifeData.temperature_celsius; | |
128 pDiveState->lifeData.compass_heading = stateRealGetPointer()->lifeData.compass_heading; | |
129 pDiveState->lifeData.battery_charge = stateRealGetPointer()->lifeData.battery_charge; | |
130 | |
131 int now = current_second(); | |
132 if( last_second == now) | |
133 return; | |
134 last_second = now; | |
135 | |
136 if(!two_second) | |
137 two_second = 1; | |
138 else | |
139 { | |
140 two_second = 0; | |
141 if(lastPressure_bar >= 0) | |
142 { | |
143 //2 seconds * 30 == 1 minute, bar * 10 = meter | |
144 pDiveState->lifeData.ascent_rate_meter_per_min = (lastPressure_bar - pDiveState->lifeData.pressure_ambient_bar) * 30 * 10; | |
145 } | |
146 lastPressure_bar = pDiveState->lifeData.pressure_ambient_bar; | |
147 } | |
148 } | |
149 else if(pDiveState->lifeData.depth_meter <= (float)(decom_get_actual_deco_stop(pDiveState) + 0.001)) | |
150 sim_reduce_deco_time_one_second(pDiveState); | |
151 | |
152 pDiveState->lifeData.ppO2Sensor_bar[0] = stateRealGetPointer()->lifeData.ppO2Sensor_bar[0]; | |
153 pDiveState->lifeData.ppO2Sensor_bar[1] = stateRealGetPointer()->lifeData.ppO2Sensor_bar[1]; | |
154 pDiveState->lifeData.ppO2Sensor_bar[2] = stateRealGetPointer()->lifeData.ppO2Sensor_bar[2]; | |
155 pDiveState->lifeData.sensorVoltage_mV[0] = stateRealGetPointer()->lifeData.sensorVoltage_mV[0]; | |
156 pDiveState->lifeData.sensorVoltage_mV[1] = stateRealGetPointer()->lifeData.sensorVoltage_mV[1]; | |
157 pDiveState->lifeData.sensorVoltage_mV[2] = stateRealGetPointer()->lifeData.sensorVoltage_mV[2]; | |
158 | |
159 pDiveState->lifeData.dive_time_seconds += 1; | |
160 pDiveState->lifeData.pressure_ambient_bar = sim_get_ambiant_pressure(pDiveState); | |
161 | |
162 if(!is_ambient_pressure_close_to_surface(&pDiveState->lifeData) && !(stateSimGetPointer()->lifeData.counterSecondsShallowDepth) ) | |
163 { | |
164 pDiveState->lifeData.dive_time_seconds_without_surface_time += 1; | |
165 } | |
166 | |
167 if(is_ambient_pressure_close_to_surface(&pDiveState->lifeData)) // new hw 170214 | |
168 { | |
169 if(!(stateSimGetPointer()->lifeData.counterSecondsShallowDepth)) | |
170 { | |
171 if(pDiveState->diveSettings.diveMode != DIVEMODE_Apnea) | |
172 pDiveState->lifeData.counterSecondsShallowDepth = settingsGetPointer()->timeoutDiveReachedZeroDepth - 15; | |
173 else | |
174 { | |
175 pDiveState->lifeData.apnea_last_dive_time_seconds = pDiveState->lifeData.dive_time_seconds; | |
176 if(pDiveState->lifeData.apnea_last_dive_time_seconds > pDiveState->lifeData.dive_time_seconds_without_surface_time) | |
177 pDiveState->lifeData.apnea_last_dive_time_seconds = pDiveState->lifeData.dive_time_seconds_without_surface_time; | |
178 pDiveState->lifeData.apnea_last_max_depth_meter = pDiveState->lifeData.max_depth_meter; | |
179 pDiveState->lifeData.counterSecondsShallowDepth = 1; | |
180 } | |
181 } | |
182 } | |
183 else | |
184 { | |
185 pDiveState->lifeData.counterSecondsShallowDepth = 0; | |
186 } | |
187 | |
188 pDiveState->lifeData.depth_meter = (pDiveState->lifeData.pressure_ambient_bar - pDiveState->lifeData.pressure_surface_bar) * 10.0f; | |
189 if(pDiveState->lifeData.max_depth_meter < pDiveState->lifeData.depth_meter) | |
190 pDiveState->lifeData.max_depth_meter = pDiveState->lifeData.depth_meter; | |
191 | |
192 /* apnoe specials | |
193 */ | |
194 if(pDiveState->diveSettings.diveMode == DIVEMODE_Apnea) | |
195 { | |
196 if(pDiveState->lifeData.max_depth_meter > pDiveState->lifeData.apnea_total_max_depth_meter) | |
197 pDiveState->lifeData.apnea_total_max_depth_meter = pDiveState->lifeData.max_depth_meter; | |
198 | |
199 if(pDiveState->lifeData.counterSecondsShallowDepth) | |
200 { | |
201 pDiveState->lifeData.dive_time_seconds = 0; | |
202 pDiveState->lifeData.max_depth_meter = 0; | |
203 pDiveState->lifeData.boolResetAverageDepth = 1; | |
204 pDiveState->lifeData.boolResetStopwatch = 1; | |
205 } | |
206 } | |
207 | |
208 /* average depth | |
209 */ | |
210 float *AvgDepthValue = &pDiveState->lifeData.average_depth_meter; | |
211 float DepthNow = pDiveState->lifeData.depth_meter; | |
212 uint32_t *AvgDepthCount = &pDiveState->lifeData.internal.average_depth_meter_Count; | |
213 uint32_t *AvgDepthTimer = &pDiveState->lifeData.internal.average_depth_last_update_dive_time_seconds_without_surface_time; | |
214 uint32_t AvgSecondsSinceLast; | |
215 uint32_t DiveTime = pDiveState->lifeData.dive_time_seconds_without_surface_time; | |
216 | |
217 if(pDiveState->lifeData.boolResetAverageDepth) | |
218 { | |
219 *AvgDepthValue = DepthNow; | |
220 *AvgDepthCount = 1; | |
221 *AvgDepthTimer = DiveTime; | |
222 pDiveState->lifeData.boolResetAverageDepth = 0; | |
223 } | |
224 else if (DiveTime > *AvgDepthTimer) | |
225 { | |
226 AvgSecondsSinceLast = DiveTime - *AvgDepthTimer; | |
227 for(int i=0;i<AvgSecondsSinceLast;i++) | |
228 { | |
229 *AvgDepthValue = (*AvgDepthValue * *AvgDepthCount + DepthNow) / (*AvgDepthCount + 1); | |
230 *AvgDepthCount += 1; | |
231 } | |
232 *AvgDepthTimer = DiveTime; | |
233 } | |
234 if(*AvgDepthCount == 0) | |
235 *AvgDepthValue = 0; | |
236 | |
237 /* Exposure Tissues | |
238 */ | |
239 decom_tissues_exposure(1, &pDiveState->lifeData); | |
240 decom_oxygen_calculate_cns_exposure(1, &pDiveState->lifeData.actualGas, pDiveState->lifeData.pressure_ambient_bar, &pDiveState->lifeData.cns); | |
233
9f0efc4df01e
cleanup, bugfix: do not exit simulator on 5h dive time
Jan Mulder <jlmulder@xs4all.nl>
parents:
225
diff
changeset
|
241 |
38 | 242 if(stateSimGetPointer()->lifeData.counterSecondsShallowDepth) |
243 { | |
244 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth += 1; | |
245 if(stateSimGetPointer()->lifeData.counterSecondsShallowDepth >= settingsGetPointer()->timeoutDiveReachedZeroDepth) | |
246 simulation_exit(); | |
247 } | |
248 vpm_crush(pDiveState); | |
249 } | |
250 | |
251 /** | |
252 ****************************************************************************** | |
253 * @brief adds extra time for fast simulation | |
254 ****************************************************************************** | |
255 *@param minutes | |
256 * @return float : new pressure | |
257 */ | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
258 static void simulation_add_time(int minutes) |
38 | 259 { |
260 for(int i = 0; i < 60 * minutes; i++) | |
261 { | |
262 simulation_UpdateLifeData(0); | |
263 updateMiniLiveLogbook(0); | |
264 timer_UpdateSecond(0); | |
265 } | |
266 } | |
267 | |
268 /** | |
269 ****************************************************************************** | |
270 * @brief get aim_depth | |
271 ****************************************************************************** | |
272 * @return sim_aim_depth_meter; | |
273 */ | |
274 | |
275 uint16_t simulation_get_aim_depth(void) | |
276 { | |
277 return (uint16_t)sim_aim_depth_meter; | |
278 } | |
279 | |
280 /** | |
281 ****************************************************************************** | |
282 * @brief get heed decostops | |
283 ****************************************************************************** | |
284 * @return true if ascend follows decostops; | |
285 */ | |
286 | |
287 _Bool simulation_get_heed_decostops(void) | |
288 { | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
289 return sim_heed_decostops; |
38 | 290 } |
291 | |
292 /** | |
293 ****************************************************************************** | |
294 * @brief sets aim_depth | |
295 ****************************************************************************** | |
296 *@param depth_meter | |
297 * @return float : new pressure | |
298 */ | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
299 static void simulation_set_aim_depth(int depth_meter) |
38 | 300 { |
301 sim_aim_depth_meter = depth_meter; | |
302 } | |
303 | |
304 /** | |
305 ****************************************************************************** | |
306 * @brief simulates ambiant pressure depending on aim depth | |
307 ****************************************************************************** | |
308 * @note if aim_depth != actual depth, the depth change within one second | |
309 * (depending on descent or ascent) rate is calculated | |
310 * @param SDiveState* pDiveState: | |
311 * @return float : new ambiant pressure | |
312 */ | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
313 static float sim_get_ambiant_pressure(SDiveState * pDiveState) |
38 | 314 { |
315 //Calc next depth | |
316 uint8_t actual_deco_stop = decom_get_actual_deco_stop(pDiveState); | |
317 float depth_meter = pDiveState->lifeData.depth_meter; | |
318 float surface_pressure_bar = pDiveState->lifeData.pressure_surface_bar; | |
319 if(depth_meter < sim_aim_depth_meter) | |
320 { | |
321 depth_meter = depth_meter + sim_descent_rate_meter_per_min / 60; | |
322 if(depth_meter > sim_aim_depth_meter) | |
323 depth_meter = sim_aim_depth_meter; | |
324 } | |
325 else if(depth_meter > sim_aim_depth_meter) | |
326 { | |
327 | |
328 depth_meter -= pDiveState->diveSettings.ascentRate_meterperminute / 60; | |
329 if(depth_meter < sim_aim_depth_meter) | |
330 depth_meter = sim_aim_depth_meter; | |
331 | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
332 if(sim_heed_decostops && depth_meter < actual_deco_stop) |
38 | 333 { |
334 if(actual_deco_stop < (depth_meter + pDiveState->diveSettings.ascentRate_meterperminute / 60)) | |
335 depth_meter = actual_deco_stop; | |
336 else | |
337 depth_meter += pDiveState->diveSettings.ascentRate_meterperminute / 60; | |
338 } | |
339 | |
340 } | |
341 | |
342 return surface_pressure_bar + depth_meter / 10; | |
343 } | |
344 | |
345 | |
346 /** | |
347 ****************************************************************************** | |
348 * @brief Reduces deco time of deepest stop by one second | |
349 ****************************************************************************** | |
350 * @note called during fast simulation | |
351 * @param SDiveState* pDiveState: | |
352 * @return void | |
353 */ | |
354 void sim_reduce_deco_time_one_second(SDiveState* pDiveState) | |
355 { | |
356 SDecoinfo* pDecoinfo; | |
357 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
358 pDecoinfo = &pDiveState->decolistBuehlmann; | |
359 else | |
360 pDecoinfo = &pDiveState->decolistVPM; | |
361 | |
362 //Reduce deco time of deepest stop by one second | |
363 for(int i = DECOINFO_STRUCT_MAX_STOPS -1 ;i >= 0; i--) | |
364 { | |
365 if(pDecoinfo->output_stop_length_seconds[i] > 0) | |
366 { | |
367 pDecoinfo->output_stop_length_seconds[i]--; | |
368 break; | |
369 } | |
370 } | |
371 } | |
372 | |
373 SDecoinfo* simulation_decoplaner(uint16_t depth_meter, uint16_t intervall_time_minutes, uint16_t dive_time_minutes, uint8_t *gasChangeListDepthGas20x2) | |
374 { | |
375 uint8_t ptrGasChangeList = 0; // new hw 160704 | |
376 | |
377 SDiveState * pDiveState = &stateSim; | |
378 copyDiveSettingsToSim(); | |
379 vpm_init(&pDiveState->vpm, pDiveState->diveSettings.vpm_conservatism, 0, 0); | |
380 //buehlmann_init(); | |
381 //timer_init(); | |
382 memset(&pDiveState->events,0, sizeof(SEvents)); | |
383 pDiveState->diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = 0; | |
384 //Calc desaturation during intervall (with Air) | |
385 setActualGasAir(&pDiveState->lifeData); | |
386 if(intervall_time_minutes > 0) | |
387 { | |
388 decom_tissues_exposure(intervall_time_minutes * 60, &pDiveState->lifeData); | |
389 decom_oxygen_calculate_cns_degrade(&pDiveState->lifeData.cns, intervall_time_minutes * 60); | |
390 } | |
391 | |
392 //Switch to first Gas | |
393 setActualGasFirst(&pDiveState->lifeData); | |
394 | |
395 // new hw 160704 | |
396 if(gasChangeListDepthGas20x2) | |
397 { | |
398 gasChangeListDepthGas20x2[ptrGasChangeList++] = 0; | |
399 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->lifeData.actualGas.GasIdInSettings; | |
400 gasChangeListDepthGas20x2[0] =0; // depth zero | |
401 } | |
402 | |
403 //Going down / descent | |
404 simulation_set_aim_depth(depth_meter); | |
405 for(int i = 0; i < 60 * dive_time_minutes; i++) | |
406 { | |
407 simulation_UpdateLifeData(0); | |
408 check_warning2(pDiveState); | |
409 if(pDiveState->warnings.betterGas) | |
410 { | |
411 setActualGas(&pDiveState->lifeData,actualBetterGasId(),pDiveState->lifeData.actualGas.setPoint_cbar); | |
412 if(gasChangeListDepthGas20x2 && (pDiveState->diveSettings.diveMode == DIVEMODE_OC)) | |
413 { | |
414 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->lifeData.depth_meter; | |
415 gasChangeListDepthGas20x2[ptrGasChangeList++] = actualBetterGasId(); | |
416 } | |
417 } | |
418 } | |
419 | |
420 decom_CreateGasChangeList(&pDiveState->diveSettings, &pDiveState->lifeData); // was there before and needed for buehlmann_calc_deco and vpm_calc | |
421 | |
422 // new hw 160704 | |
423 if(gasChangeListDepthGas20x2 && (pDiveState->diveSettings.diveMode == DIVEMODE_OC)) | |
424 { | |
425 // change direction from better gas to deco gas | |
426 gasChangeListDepthGas20x2[ptrGasChangeList++] = 255; | |
427 gasChangeListDepthGas20x2[ptrGasChangeList++] = 255; | |
428 | |
429 // ascend (deco) gases | |
430 for(int i=1; i<=5;i++) | |
431 { | |
432 if(pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0) | |
433 break; | |
434 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero; | |
435 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].GasIdInSettings; | |
436 } | |
437 gasChangeListDepthGas20x2[0] = 0; | |
438 } | |
439 | |
440 // deco and ascend calc | |
441 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
442 { | |
443 /* this does modify the cns now 11.06.2015 */ | |
444 buehlmann_calc_deco(&pDiveState->lifeData,&pDiveState->diveSettings,&pDiveState->decolistBuehlmann); | |
445 pDiveState->lifeData.cns += buehlmann_get_gCNS(); | |
446 return &pDiveState->decolistBuehlmann; | |
447 } | |
448 else | |
449 { | |
450 /* this does modify the cns now 11.06.2015 */ | |
451 vpm_calc(&pDiveState->lifeData,&pDiveState->diveSettings,&pDiveState->vpm,&pDiveState->decolistVPM, DECOSTOPS); | |
452 pDiveState->lifeData.cns += vpm_get_CNS(); | |
453 return &pDiveState->decolistVPM; | |
454 } | |
455 } | |
456 | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
176
diff
changeset
|
457 static float sGChelper_bar(uint16_t depth_meter) |
38 | 458 { |
459 SDiveState * pDiveState = &stateSim; | |
460 float ambient, surface, density, meter; | |
461 | |
462 surface = pDiveState->lifeData.pressure_surface_bar; | |
463 | |
464 if(!depth_meter) | |
465 return surface; | |
466 | |
467 density = ((float)( 100 + settingsGetPointer()->salinity)) / 100.0f; | |
468 meter = depth_meter * (0.09807f * density); | |
469 ambient = (meter + surface); | |
470 | |
471 return ambient; | |
472 } | |
473 | |
474 | |
475 /** | |
476 ****************************************************************************** | |
477 * @brief simulation_helper_change_points | |
478 ****************************************************************************** | |
479 * @param | |
480 * @return void | |
481 */ | |
482 void simulation_helper_change_points(SSimDataSummary *outputSummary, uint16_t depth_meter, uint16_t dive_time_minutes, SDecoinfo *decoInfoInput, const uint8_t *gasChangeListDepthGas20x2) | |
483 { | |
484 uint8_t ptrDecoInfo = 0; | |
485 uint16_t actualDepthPoint = 0; | |
486 uint16_t nextDepthPoint = 0; | |
487 uint8_t actualConsumGasId = 0; | |
488 uint8_t nextGasChangeMeter = 0; | |
489 uint8_t ptrChangeList = 0; | |
490 | |
491 float timeThis = 0; | |
492 float timeSummary = 0; | |
493 float sim_descent_rate_meter_per_min_local = 10; | |
494 float sim_ascent_rate_meter_per_min_local = 10; | |
495 | |
496 SDiveState * pDiveState = &stateSim; | |
497 | |
498 uint8_t depthDecoNext, depthLast, depthSecond, depthInc; | |
499 | |
500 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
501 { | |
502 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
503 sim_ascent_rate_meter_per_min_local = pDiveState->diveSettings.ascentRate_meterperminute; | |
504 } | |
505 else | |
506 { | |
507 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
508 sim_ascent_rate_meter_per_min_local = 10;// fix in vpm_calc_deco(); | |
509 } | |
510 | |
511 outputSummary->descentRateMeterPerMinute = sim_descent_rate_meter_per_min_local; | |
512 outputSummary->ascentRateMeterPerMinute = sim_ascent_rate_meter_per_min_local; | |
513 | |
514 // bottom gas ppO2 | |
515 if(gasChangeListDepthGas20x2) | |
516 { | |
517 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
518 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
519 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
520 | |
521 while(actualDepthPoint < depth_meter) | |
522 { | |
523 if(nextGasChangeMeter && (nextGasChangeMeter < depth_meter) && (gasChangeListDepthGas20x2[ptrChangeList] != 255)) // list has 255,255 for turn from travel to deco | |
524 { | |
525 nextDepthPoint = nextGasChangeMeter; | |
526 } | |
527 else | |
528 { | |
529 nextDepthPoint = depth_meter; | |
530 } | |
531 | |
532 if(actualConsumGasId > 5) // safety first | |
533 actualConsumGasId = 0; | |
534 | |
535 actualDepthPoint = nextDepthPoint; | |
536 | |
537 if(actualDepthPoint != depth_meter) | |
538 { | |
539 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
540 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
541 } | |
542 } | |
543 } | |
544 else | |
545 { | |
546 actualConsumGasId = pDiveState->lifeData.actualGas.GasIdInSettings; | |
547 nextGasChangeMeter = 0; | |
548 } | |
549 outputSummary->ppO2AtBottom = (sGChelper_bar(depth_meter) - WATER_VAPOUR_PRESSURE) * pDiveState->diveSettings.gas[actualConsumGasId].oxygen_percentage / 100.0f; | |
550 | |
551 | |
552 // going down | |
553 actualDepthPoint = 0; | |
554 nextDepthPoint = depth_meter; | |
555 | |
556 timeThis = ((float)(nextDepthPoint - actualDepthPoint)) / sim_descent_rate_meter_per_min_local; | |
557 timeSummary += timeThis; | |
558 outputSummary->timeToBottom = (uint16_t)timeThis; | |
559 | |
560 // bottom time | |
561 timeThis = ((float)dive_time_minutes) - timeSummary; | |
562 timeSummary += timeThis; | |
563 outputSummary->timeAtBottom = (uint16_t)timeSummary; | |
564 | |
565 | |
566 // ascend to first deco stop | |
567 actualDepthPoint = depth_meter; // that is where we are | |
568 timeThis = 0; | |
569 | |
570 if(!decoInfoInput->output_stop_length_seconds[0]) // NDL dive | |
571 { | |
572 depthLast = 0; | |
573 ptrDecoInfo = 0; | |
574 depthDecoNext = 0; | |
575 } | |
576 else | |
577 { | |
578 // prepare deco stop list | |
579 depthLast = (uint8_t)(stateUsed->diveSettings.last_stop_depth_bar * 10); | |
580 depthSecond = (uint8_t)(stateUsed->diveSettings.input_second_to_last_stop_depth_bar * 10); | |
581 depthInc = (uint8_t)(stateUsed->diveSettings.input_next_stop_increment_depth_bar * 10); | |
582 | |
583 for(ptrDecoInfo=DECOINFO_STRUCT_MAX_STOPS-1; ptrDecoInfo>0; ptrDecoInfo--) | |
584 if(decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) break; | |
585 | |
586 if(ptrDecoInfo == 0) | |
587 { | |
588 depthDecoNext = depthLast; | |
589 } | |
590 else | |
591 depthDecoNext = depthSecond + (( ptrDecoInfo - 1 )* depthInc); | |
592 } | |
593 | |
594 nextDepthPoint = depthDecoNext; | |
595 if(actualDepthPoint > nextDepthPoint) | |
596 { | |
597 // flip signs! It's going up | |
598 timeThis = ((float)(actualDepthPoint - nextDepthPoint)) / sim_ascent_rate_meter_per_min_local; | |
599 actualDepthPoint = nextDepthPoint; // that is where we are | |
600 } | |
601 timeSummary += timeThis; | |
602 outputSummary->timeToFirstStop = (uint16_t)timeSummary; | |
603 outputSummary->depthMeterFirstStop = actualDepthPoint; | |
604 | |
605 //ascent | |
606 nextDepthPoint = 0; | |
607 timeThis = 0; | |
608 if(actualDepthPoint > nextDepthPoint) // only if deco | |
609 { | |
610 // ascent time | |
611 timeThis = ((float)(actualDepthPoint - nextDepthPoint)) / sim_ascent_rate_meter_per_min_local; | |
612 | |
613 // deco stop time | |
614 for(ptrDecoInfo=0;ptrDecoInfo < DECOINFO_STRUCT_MAX_STOPS; ptrDecoInfo++) | |
615 { | |
616 timeThis += decoInfoInput->output_stop_length_seconds[ptrDecoInfo] / 60; | |
617 if(!decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) break; | |
618 } | |
619 } | |
620 timeSummary += timeThis; | |
621 outputSummary->timeToSurface = (uint16_t)timeSummary; | |
622 | |
623 } | |
624 | |
625 | |
626 /** | |
627 ****************************************************************************** | |
628 * @brief simulation_gas_consumption | |
629 ****************************************************************************** | |
630 * @note called by openEdit_PlanResult() in tMenuEditPlanner.c | |
631 * @note the ascend and descend time is taken from pDiveState->lifeData.ascent_rate_meter_per_min and const float sim_descent_rate_meter_per_min | |
632 * @param outputConsumptionList list from 1 to 5 for gas 1 to 5 | |
633 * @param depth_meter for descend | |
634 * @param dive_time_minutes for descend and bottom time | |
635 * @param the calculated deco list | |
636 * @param gasConsumTravelInput: how many l/min for all but deco stops | |
637 * @param gasConsumDecoInput: how many l/min for deco stops only | |
638 * @return void | |
639 */ | |
640 | |
641 void simulation_gas_consumption(uint16_t *outputConsumptionList, uint16_t depth_meter, uint16_t dive_time_minutes, SDecoinfo *decoInfoInput, uint8_t gasConsumTravelInput, uint8_t gasConsumDecoInput, const uint8_t *gasChangeListDepthGas20x2) | |
642 { | |
643 uint8_t ptrDecoInfo = 0; | |
644 uint8_t ptrChangeList = 0; | |
645 uint8_t actualConsumGasId = 0; | |
646 uint8_t nextGasChangeMeter = 0; | |
647 uint16_t actualDepthPoint = 0; | |
648 uint16_t nextDepthPoint = 0; | |
649 uint16_t inBetweenDepthPoint = 0; | |
650 float timeThis = 0; | |
651 float consumThis = 0; | |
652 float timeSummary = 0; | |
653 float outputConsumptionTempFloat[6]; | |
654 float sim_descent_rate_meter_per_min_local = 10; | |
655 float sim_ascent_rate_meter_per_min_local = 10; | |
656 | |
657 SDiveState * pDiveState = &stateSim; | |
658 | |
51
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
659 uint8_t depthDecoNext = 0; |
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
660 uint8_t depthLast = 0; |
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
661 uint8_t depthSecond = 0; |
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
662 uint8_t depthInc = 0; |
38 | 663 |
664 for(int i = 1; i < 6; i++) | |
665 outputConsumptionTempFloat[i] = 0; | |
666 | |
667 if(gasChangeListDepthGas20x2) | |
668 { | |
669 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
670 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
671 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
672 } | |
673 else | |
674 { | |
675 actualConsumGasId = pDiveState->lifeData.actualGas.GasIdInSettings; | |
676 nextGasChangeMeter = 0; | |
677 } | |
678 | |
679 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
680 { | |
681 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
682 sim_ascent_rate_meter_per_min_local = pDiveState->diveSettings.ascentRate_meterperminute; | |
683 } | |
684 else | |
685 { | |
686 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
687 sim_ascent_rate_meter_per_min_local = 10;// fix in vpm_calc_deco(); | |
688 } | |
689 | |
690 // while((nextGasChangeMeter < depth_meter) && (actualDepthPoint < depth_meter)) | |
691 while(actualDepthPoint < depth_meter) | |
692 { | |
693 if(nextGasChangeMeter && (nextGasChangeMeter < depth_meter) && (gasChangeListDepthGas20x2[ptrChangeList] != 255)) // list has 255,255 for turn from travel to deco | |
694 { | |
695 nextDepthPoint = nextGasChangeMeter; | |
696 } | |
697 else | |
698 { | |
699 nextDepthPoint = depth_meter; | |
700 } | |
701 | |
702 if(actualConsumGasId > 5) // safety first | |
703 actualConsumGasId = 0; | |
704 | |
705 timeThis = ((float)(nextDepthPoint - actualDepthPoint)) / sim_descent_rate_meter_per_min_local; | |
706 if(actualDepthPoint) // not if on surface | |
707 { | |
708 consumThis = ((float)gasConsumTravelInput) * sGChelper_bar(actualDepthPoint) * timeThis; | |
709 } | |
710 consumThis += ((float)gasConsumTravelInput) * sGChelper_bar(nextDepthPoint -actualDepthPoint) * timeThis / 2; | |
711 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
712 timeSummary += timeThis; | |
713 | |
714 actualDepthPoint = nextDepthPoint; | |
715 | |
716 if(actualDepthPoint != depth_meter) | |
717 { | |
718 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
719 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
720 } | |
721 } | |
722 | |
723 // bottom Time | |
724 timeThis = ((float)dive_time_minutes) - timeSummary; | |
725 | |
726 if(timeThis > 0) | |
727 { | |
728 consumThis = ((float)gasConsumTravelInput) * sGChelper_bar(depth_meter) * timeThis; | |
729 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
730 } | |
731 | |
732 // ascend with deco stops prepare | |
733 if(gasChangeListDepthGas20x2) | |
734 { | |
735 ptrChangeList++;// gasChangeListDepthGas20x2[ptrChangeList++]; // should be the 255 | |
736 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
737 } | |
738 else | |
739 { | |
740 nextGasChangeMeter = 0; | |
741 } | |
742 | |
743 | |
744 if(!decoInfoInput->output_stop_length_seconds[0]) // NDL dive | |
745 { | |
746 depthLast = 0; | |
747 ptrDecoInfo = 0; | |
748 } | |
749 else | |
750 { | |
751 // prepare deco stop list | |
752 depthLast = (uint8_t)(stateUsed->diveSettings.last_stop_depth_bar * 10); | |
753 depthSecond = (uint8_t)(stateUsed->diveSettings.input_second_to_last_stop_depth_bar * 10); | |
754 depthInc = (uint8_t)(stateUsed->diveSettings.input_next_stop_increment_depth_bar * 10); | |
755 | |
756 for(ptrDecoInfo=DECOINFO_STRUCT_MAX_STOPS-1; ptrDecoInfo>0; ptrDecoInfo--) | |
757 if(decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) break; | |
758 } | |
759 | |
760 actualDepthPoint = depth_meter; // that is where we are | |
761 | |
762 // ascend with deco stops | |
763 while(actualDepthPoint) | |
764 { | |
765 if(ptrDecoInfo == 0) | |
766 { | |
767 depthDecoNext = depthLast; | |
768 } | |
769 else | |
770 depthDecoNext = depthSecond + (( ptrDecoInfo - 1 )* depthInc); | |
771 | |
772 if(nextGasChangeMeter && (nextGasChangeMeter > depthDecoNext)) | |
773 { | |
774 nextDepthPoint = nextGasChangeMeter; | |
775 } | |
776 else | |
777 { | |
778 nextDepthPoint = depthDecoNext; | |
779 } | |
780 | |
781 if(actualConsumGasId > 5) // safety first | |
782 actualConsumGasId = 0; | |
783 | |
784 if(actualDepthPoint > nextDepthPoint) | |
785 { | |
786 // flip signs! It's going up | |
787 timeThis = ((float)(actualDepthPoint - nextDepthPoint)) / sim_ascent_rate_meter_per_min_local; | |
788 inBetweenDepthPoint = nextDepthPoint + ((actualDepthPoint - nextDepthPoint)/2); | |
789 consumThis = ((float)gasConsumDecoInput) * sGChelper_bar(inBetweenDepthPoint) * timeThis; | |
790 /* | |
791 if(nextDepthPoint) | |
792 { | |
793 consumThis = ((float)gasConsumDecoInput) * sGChelper_bar(nextDepthPoint) * timeThis; | |
794 } | |
795 else | |
796 { | |
797 consumThis = 0; | |
798 } | |
799 consumThis += ((float)gasConsumDecoInput) * sGChelper_bar(actualDepthPoint - nextDepthPoint) * timeThis / 2; | |
800 */ | |
801 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
802 } | |
803 | |
804 if(nextGasChangeMeter && (nextDepthPoint == nextGasChangeMeter)) | |
805 { | |
806 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
807 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
808 } | |
809 | |
810 if(actualConsumGasId > 5) // safety first | |
811 actualConsumGasId = 0; | |
812 | |
813 if(nextDepthPoint && (nextDepthPoint == depthDecoNext)) | |
814 { | |
815 if(decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) | |
816 { | |
817 timeThis = ((float)(decoInfoInput->output_stop_length_seconds[ptrDecoInfo])) / 60.0f; | |
818 consumThis = ((float)gasConsumDecoInput) * sGChelper_bar(nextDepthPoint) * timeThis; | |
819 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
820 } | |
821 if(ptrDecoInfo != 0) | |
822 { | |
823 ptrDecoInfo--; | |
824 } | |
825 else | |
826 { | |
827 depthLast = 0; | |
828 } | |
829 } | |
830 actualDepthPoint = nextDepthPoint; | |
831 } | |
832 | |
833 // copy and return | |
834 for(int i = 1; i < 6; i++) | |
835 outputConsumptionList[i] = (uint16_t)(outputConsumptionTempFloat[i]); | |
836 } | |
837 | |
838 /** | |
839 ****************************************************************************** | |
840 * @brief Simulator control during simulated dive | |
841 ****************************************************************************** | |
842 * @note called by user via tHomeDiveMenuControl() | |
843 * @param void | |
844 * @return void | |
845 */ | |
846 | |
847 | |
848 void Sim_Descend (void) | |
849 { | |
850 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 0; | |
851 if(simulation_get_aim_depth() < 200) | |
852 simulation_set_aim_depth(simulation_get_aim_depth() + 1); | |
853 } | |
854 | |
855 | |
856 void Sim_Ascend (void) | |
857 { | |
858 if(simulation_get_aim_depth() > 0) | |
859 simulation_set_aim_depth(simulation_get_aim_depth() - 1); | |
860 } | |
861 | |
862 | |
863 void Sim_Divetime (void) | |
864 { | |
865 simulation_add_time(5); | |
866 } | |
867 | |
868 | |
869 void Sim_Quit (void) | |
870 { | |
871 if(stateSimGetPointer()->lifeData.counterSecondsShallowDepth) | |
872 { | |
873 simulation_exit(); | |
874 return; | |
875 } | |
876 | |
877 if(simulation_get_aim_depth() > 0) | |
878 { | |
879 simulation_set_aim_depth(0); | |
880 } | |
881 else | |
882 { | |
883 stateSimGetPointerWrite()->lifeData.depth_meter = 0; | |
884 if(stateSimGetPointer()->diveSettings.diveMode == DIVEMODE_Apnea) | |
885 { | |
886 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 1; | |
887 } | |
888 else | |
889 { | |
890 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = settingsGetPointer()->timeoutDiveReachedZeroDepth - 15; | |
891 } | |
892 } | |
893 } |