Beispiel #1
0
/* add period_in_seconds at the given pressure and gas to the deco calculation */
double add_segment(double pressure, struct gasmix *gasmix, int period_in_seconds, double ccpo2, const struct dive *dive)
{
	int ci;
	int fo2 = gasmix->o2.permille ? gasmix->o2.permille : 209;
	double ppn2 = (pressure - WV_PRESSURE) * (1000 - fo2 - gasmix->he.permille) / 1000.0;
	double pphe = (pressure - WV_PRESSURE) * gasmix->he.permille / 1000.0;

#if GF_LOW_AT_MAXDEPTH
	if (pressure > gf_low_pressure_this_dive)
	        gf_low_pressure_this_dive = pressure;
#endif

	if (ccpo2 > 0.0) { /* CC */
		double rel_o2_amb, f_dilutent;
		rel_o2_amb = ccpo2 / pressure;
		f_dilutent = (1 - rel_o2_amb) / (1 - fo2 / 1000.0);
		if (f_dilutent < 0) { /* setpoint is higher than ambient pressure -> pure O2 */
			ppn2 = 0.0;
			pphe = 0.0;
		} else if (f_dilutent < 1.0) {
			ppn2 *= f_dilutent;
			pphe *= f_dilutent;
		}
	}
	if (period_in_seconds == 1) { /* one second interval during dive */
		for (ci = 0; ci < 16; ci++) {
			if (ppn2 - tissue_n2_sat[ci] > 0)
				tissue_n2_sat[ci] += buehlmann_config.satmult * (ppn2 - tissue_n2_sat[ci]) *
								buehlmann_N2_factor_expositon_one_second[ci];
			else
				tissue_n2_sat[ci] += buehlmann_config.desatmult * (ppn2 - tissue_n2_sat[ci]) *
								buehlmann_N2_factor_expositon_one_second[ci];
			if (pphe - tissue_he_sat[ci] > 0)
				tissue_he_sat[ci] += buehlmann_config.satmult * (pphe - tissue_he_sat[ci]) *
								buehlmann_He_factor_expositon_one_second[ci];
			else
				tissue_he_sat[ci] += buehlmann_config.desatmult * (pphe - tissue_he_sat[ci]) *
								buehlmann_He_factor_expositon_one_second[ci];
		}
	} else { /* all other durations */
		for (ci = 0; ci < 16; ci++)
		{
			if (ppn2 - tissue_n2_sat[ci] > 0)
				tissue_n2_sat[ci] += buehlmann_config.satmult * (ppn2 - tissue_n2_sat[ci]) *
					(1 - pow(2.0,(- period_in_seconds / (buehlmann_N2_t_halflife[ci] * 60))));
			else
				tissue_n2_sat[ci] += buehlmann_config.desatmult * (ppn2 - tissue_n2_sat[ci]) *
					(1 - pow(2.0,(- period_in_seconds / (buehlmann_N2_t_halflife[ci] * 60))));
			if (pphe - tissue_he_sat[ci] > 0)
				tissue_he_sat[ci] += buehlmann_config.satmult * (pphe - tissue_he_sat[ci]) *
					(1 - pow(2.0,(- period_in_seconds / (buehlmann_He_t_halflife[ci] * 60))));
			else
				tissue_he_sat[ci] += buehlmann_config.desatmult * (pphe - tissue_he_sat[ci]) *
					(1 - pow(2.0,(- period_in_seconds / (buehlmann_He_t_halflife[ci] * 60))));
		}
	}
	return tissue_tolerance_calc(dive);
}
Beispiel #2
0
/* Let's try to do some deco calculations.
 */
void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode)
{
	int i, count_iteration = 0;
	double surface_pressure = (dc->surface_pressure.mbar ? dc->surface_pressure.mbar : get_surface_pressure_in_mbar(dive, true)) / 1000.0;
	int last_ndl_tts_calc_time = 0;
	int first_ceiling = 0;
	bool first_iteration = true;
	int final_tts = 0 , time_clear_ceiling = 0, time_deep_ceiling = 0, deco_time = 0, prev_deco_time = 10000000;
	char *cache_data_initial = NULL;
	/* For VPM-B outside the planner, cache the initial deco state for CVA iterations */
	if (prefs.deco_mode == VPMB && !in_planner())
		cache_deco_state(&cache_data_initial);
	/* For VPM-B outside the planner, iterate until deco time converges (usually one or two iterations after the initial)
	 * Set maximum number of iterations to 10 just in case */
	while ((abs(prev_deco_time - deco_time) >= 30) && (count_iteration < 10)) {
		for (i = 1; i < pi->nr; i++) {
			struct plot_data *entry = pi->entry + i;
			int j, t0 = (entry - 1)->sec, t1 = entry->sec;
			int time_stepsize = 20;

			entry->ambpressure = depth_to_bar(entry->depth, dive);
			entry->gfline = MAX((double)prefs.gflow, (entry->ambpressure - surface_pressure) / (gf_low_pressure_this_dive - surface_pressure) *
										(prefs.gflow - prefs.gfhigh) +
									prefs.gfhigh) *
						(100.0 - AMB_PERCENTAGE) / 100.0 + AMB_PERCENTAGE;
			if (t0 > t1) {
				fprintf(stderr, "non-monotonous dive stamps %d %d\n", t0, t1);
				int xchg = t1;
				t1 = t0;
				t0 = xchg;
			}
			if (t0 != t1 && t1 - t0 < time_stepsize)
				time_stepsize = t1 - t0;
			for (j = t0 + time_stepsize; j <= t1; j += time_stepsize) {
				int depth = interpolate(entry[-1].depth, entry[0].depth, j - t0, t1 - t0);
				add_segment(depth_to_bar(depth, dive),
					&dive->cylinder[entry->cylinderindex].gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac);
				if ((t1 - j < time_stepsize) && (j < t1))
					time_stepsize = t1 - j;
			}
			if (t0 == t1) {
				entry->ceiling = (entry - 1)->ceiling;
			} else {
				/* Keep updating the VPM-B gradients until the start of the ascent phase of the dive. */
				if (prefs.deco_mode == VPMB && !in_planner() && (entry - 1)->ceiling >= first_ceiling && first_iteration == true) {
					nuclear_regeneration(t1);
					vpmb_start_gradient();
					/* For CVA calculations, start by guessing deco time = dive time remaining */
					deco_time = pi->maxtime - t1;
					vpmb_next_gradient(deco_time, surface_pressure / 1000.0);
				}
				entry->ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, !prefs.calcceiling3m);
				/* If using VPM-B outside the planner, take first_ceiling_pressure as the deepest ceiling */
				if (prefs.deco_mode == VPMB && !in_planner()) {
					if  (entry->ceiling >= first_ceiling) {
								time_deep_ceiling = t1;
								first_ceiling = entry->ceiling;
								first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive);
								if (first_iteration) {
									nuclear_regeneration(t1);
									vpmb_start_gradient();
									/* For CVA calculations, start by guessing deco time = dive time remaining */
									deco_time = pi->maxtime - t1;
									vpmb_next_gradient(deco_time, surface_pressure / 1000.0);
								}
					}
					// Use the point where the ceiling clears as the end of deco phase for CVA calculations
					if (entry->ceiling > 0)
						time_clear_ceiling = 0;
					else if (time_clear_ceiling == 0)
						time_clear_ceiling = t1;
				}
			}
			for (j = 0; j < 16; j++) {
				double m_value = buehlmann_inertgas_a[j] + entry->ambpressure / buehlmann_inertgas_b[j];
				entry->ceilings[j] = deco_allowed_depth(tolerated_by_tissue[j], surface_pressure, dive, 1);
				entry->percentages[j] = tissue_inertgas_saturation[j] < entry->ambpressure ?
								tissue_inertgas_saturation[j] / entry->ambpressure * AMB_PERCENTAGE :
								AMB_PERCENTAGE + (tissue_inertgas_saturation[j] - entry->ambpressure) / (m_value - entry->ambpressure) * (100.0 - AMB_PERCENTAGE);
			}

			/* should we do more calculations?
			* We don't for print-mode because this info doesn't show up there
			* If the ceiling hasn't cleared by the last data point, we need tts for VPM-B CVA calculation
			* It is not necessary to do these calculation on the first VPMB iteration, except for the last data point */
			if ((prefs.calcndltts && !print_mode && (prefs.deco_mode != VPMB || in_planner() || !first_iteration)) ||
			    (prefs.deco_mode == VPMB && !in_planner() && i == pi->nr - 1)) {
				/* only calculate ndl/tts on every 30 seconds */
				if ((entry->sec - last_ndl_tts_calc_time) < 30 && i != pi->nr - 1) {
					struct plot_data *prev_entry = (entry - 1);
					entry->stoptime_calc = prev_entry->stoptime_calc;
					entry->stopdepth_calc = prev_entry->stopdepth_calc;
					entry->tts_calc = prev_entry->tts_calc;
					entry->ndl_calc = prev_entry->ndl_calc;
					continue;
				}
				last_ndl_tts_calc_time = entry->sec;

				/* We are going to mess up deco state, so store it for later restore */
				char *cache_data = NULL;
				cache_deco_state(&cache_data);
				calculate_ndl_tts(entry, dive, surface_pressure);
				if (prefs.deco_mode == VPMB && !in_planner() && i == pi->nr - 1)
					final_tts = entry->tts_calc;
				/* Restore "real" deco state for next real time step */
				restore_deco_state(cache_data);
				free(cache_data);
			}
		}
		if (prefs.deco_mode == VPMB && !in_planner()) {
			prev_deco_time = deco_time;
			// Do we need to update deco_time?
			if (final_tts > 0)
				deco_time = pi->maxtime + final_tts - time_deep_ceiling;
			else if (time_clear_ceiling > 0)
				deco_time = time_clear_ceiling - time_deep_ceiling;
			vpmb_next_gradient(deco_time, surface_pressure / 1000.0);
			final_tts = 0;
			last_ndl_tts_calc_time = 0;
			first_ceiling = 0;
			first_iteration = false;
			count_iteration ++;
			restore_deco_state(cache_data_initial);
		} else {
			// With Buhlmann, or not in planner, iterating isn't needed.  This makes the while condition false.
			prev_deco_time = deco_time = 0;
		}
	}
	free(cache_data_initial);
#if DECO_CALC_DEBUG & 1
	dump_tissues();
#endif
}
Beispiel #3
0
/* calculate DECO STOP / TTS / NDL */
static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double surface_pressure)
{
	/* FIXME: This should be configurable */
	/* ascent speed up to first deco stop */
	const int ascent_s_per_step = 1;
	const int ascent_mm_per_step = 200; /* 12 m/min */
	/* ascent speed between deco stops */
	const int ascent_s_per_deco_step = 1;
	const int ascent_mm_per_deco_step = 16; /* 1 m/min */
	/* how long time steps in deco calculations? */
	const int time_stepsize = 60;
	const int deco_stepsize = 3000;
	/* at what depth is the current deco-step? */
	int next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)),
						    surface_pressure, dive, 1), deco_stepsize);
	int ascent_depth = entry->depth;
	/* at what time should we give up and say that we got enuff NDL? */
	int cylinderindex = entry->cylinderindex;
	/* If iterating through a dive, entry->tts_calc needs to be reset */
	entry->tts_calc = 0;

	/* If we don't have a ceiling yet, calculate ndl. Don't try to calculate
	 * a ndl for lower values than 3m it would take forever */
	if (next_stop == 0) {
		if (entry->depth < 3000) {
			entry->ndl = MAX_PROFILE_DECO;
			return;
		}
		/* stop if the ndl is above max_ndl seconds, and call it plenty of time */
		while (entry->ndl_calc < MAX_PROFILE_DECO && deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, 1) <= 0) {
			entry->ndl_calc += time_stepsize;
			add_segment(depth_to_bar(entry->depth, dive),
						       &dive->cylinder[cylinderindex].gasmix, time_stepsize, entry->o2pressure.mbar, dive, prefs.bottomsac);
		}
		/* we don't need to calculate anything else */
		return;
	}

	/* We are in deco */
	entry->in_deco_calc = true;

	/* Add segments for movement to stopdepth */
	for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_step, entry->tts_calc += ascent_s_per_step) {
		add_segment(depth_to_bar(ascent_depth, dive),
			    &dive->cylinder[cylinderindex].gasmix, ascent_s_per_step, entry->o2pressure.mbar, dive, prefs.decosac);
		next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(ascent_depth, dive)), surface_pressure, dive, 1), deco_stepsize);
	}
	ascent_depth = next_stop;

	/* And how long is the current deco-step? */
	entry->stoptime_calc = 0;
	entry->stopdepth_calc = next_stop;
	next_stop -= deco_stepsize;

	/* And how long is the total TTS */
	while (next_stop >= 0) {
		/* save the time for the first stop to show in the graph */
		if (ascent_depth == entry->stopdepth_calc)
			entry->stoptime_calc += time_stepsize;

		entry->tts_calc += time_stepsize;
		if (entry->tts_calc > MAX_PROFILE_DECO)
			break;
		add_segment(depth_to_bar(ascent_depth, dive),
			    &dive->cylinder[cylinderindex].gasmix, time_stepsize, entry->o2pressure.mbar, dive, prefs.decosac);

		if (deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(ascent_depth,dive)), surface_pressure, dive, 1) <= next_stop) {
			/* move to the next stop and add the travel between stops */
			for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_deco_step, entry->tts_calc += ascent_s_per_deco_step)
				add_segment(depth_to_bar(ascent_depth, dive),
					    &dive->cylinder[cylinderindex].gasmix, ascent_s_per_deco_step, entry->o2pressure.mbar, dive, prefs.decosac);
			ascent_depth = next_stop;
			next_stop -= deco_stepsize;
		}
	}
}