示例#1
0
void setupPlanVpmb100m60min(struct diveplan *dp)
{
	dp->salinity = 10300;
	dp->surface_pressure = 1013;
	dp->bottomsac = 0;
	dp->decosac = 0;

	struct gasmix bottomgas = { {180}, {450} };
	struct gasmix ean50 = { {500}, {0} };
	struct gasmix oxygen = { {1000}, {0} };
	pressure_t po2 = { 1600 };
	displayed_dive.cylinder[0].gasmix = bottomgas;
	displayed_dive.cylinder[1].gasmix = ean50;
	displayed_dive.cylinder[2].gasmix = oxygen;
	displayed_dive.surface_pressure.mbar = 1013;
	reset_cylinders(&displayed_dive, true);
	free_dps(dp);

	int droptime = M_OR_FT(100, 330) * 60 / M_OR_FT(99, 330);
	plan_add_segment(dp, droptime, M_OR_FT(100, 330), bottomgas, 0, 1);
	plan_add_segment(dp, 60*60 - droptime, M_OR_FT(100, 330), bottomgas, 0, 1);
	plan_add_segment(dp, 0, gas_mod(&ean50, po2, &displayed_dive, M_OR_FT(3,10)).mm, ean50, 0, 1);
	plan_add_segment(dp, 0, gas_mod(&oxygen, po2, &displayed_dive, M_OR_FT(3,10)).mm, oxygen, 0, 1);
}
示例#2
0
/* when planning a dive we need to make sure that all cylinders have a sane depth assigned
 * and that the pressures are reset to start = end = workingpressure */
void reset_cylinders(struct dive *dive)
{
	int i;
	pressure_t pO2 = {.mbar = 1400};

	for (i = 0; i < MAX_CYLINDERS; i++) {
		cylinder_t *cyl = &dive->cylinder[i];
		if (cylinder_none(cyl))
			continue;
		if (cyl->depth.mm == 0) /* if the gas doesn't give a mod, assume conservative pO2 */
			cyl->depth = gas_mod(&cyl->gasmix, pO2, M_OR_FT(3,10));
		if (cyl->type.workingpressure.mbar)
			cyl->start.mbar = cyl->end.mbar = cyl->type.workingpressure.mbar;
		cyl->gas_used.mliter = 0;
	}
}
示例#3
0
/* if a default cylinder is set, use that */
void fill_default_cylinder(cylinder_t *cyl)
{
	const char *cyl_name = prefs.default_cylinder;
	struct tank_info_t *ti = tank_info;
	pressure_t pO2 = {.mbar = 1600};

	if (!cyl_name)
		return;
	while (ti->name != NULL) {
		if (strcmp(ti->name, cyl_name) == 0)
			break;
		ti++;
	}
	if (ti->name == NULL)
		/* didn't find it */
		return;
	cyl->type.description = strdup(ti->name);
	if (ti->ml) {
		cyl->type.size.mliter = ti->ml;
		cyl->type.workingpressure.mbar = ti->bar * 1000;
	} else {
		cyl->type.workingpressure.mbar = psi_to_mbar(ti->psi);
		if (ti->psi)
			cyl->type.size.mliter = cuft_to_l(ti->cuft) * 1000 / bar_to_atm(psi_to_bar(ti->psi));
	}
	// MOD of air
	cyl->depth = gas_mod(&cyl->gasmix, pO2, 1);
}

/* make sure that the gas we are switching to is represented in our
 * list of cylinders */
static int verify_gas_exists(struct gasmix mix_in)
{
	int i;
	cylinder_t *cyl;

	for (i = 0; i < MAX_CYLINDERS; i++) {
		cyl = displayed_dive.cylinder + i;
		if (cylinder_nodata(cyl))
			continue;
		if (gasmix_distance(&cyl->gasmix, &mix_in) < 200)
			return i;
	}
	fprintf(stderr, "this gas %s should have been on the cylinder list\nThings will fail now\n", gasname(&mix_in));
	return -1;
}
示例#4
0
/* when planning a dive we need to make sure that all cylinders have a sane depth assigned
 * and if we are tracking gas consumption the pressures need to be reset to start = end = workingpressure */
void reset_cylinders(struct dive *dive, bool track_gas)
{
	int i;
	pressure_t decopo2 = {.mbar = prefs.decopo2};

	for (i = 0; i < MAX_CYLINDERS; i++) {
		cylinder_t *cyl = &dive->cylinder[i];
		if (cylinder_none(cyl))
			continue;
		if (cyl->depth.mm == 0) /* if the gas doesn't give a mod, calculate based on prefs */
			cyl->depth = gas_mod(&cyl->gasmix, decopo2, dive, M_OR_FT(3,10));
		if (track_gas)
			cyl->start.mbar = cyl->end.mbar = cyl->type.workingpressure.mbar;
		cyl->gas_used.mliter = 0;
		cyl->deco_gas_used.mliter = 0;
	}
}
示例#5
0
void setupPlanVpmb60m30minTx(struct diveplan *dp)
{
	dp->salinity = 10300;
	dp->surface_pressure = 1013;
	dp->bottomsac = prefs.bottomsac;
	dp->decosac = prefs.decosac;

	struct gasmix bottomgas = {{180}, {450}};
	struct gasmix ean50 = {{500}, {0}};
	pressure_t po2 = {1600};
	displayed_dive.cylinder[0].gasmix = bottomgas;
	displayed_dive.cylinder[0].type.size.mliter = 36000;
	displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
	displayed_dive.cylinder[1].gasmix = ean50;
	displayed_dive.surface_pressure.mbar = 1013;
	reset_cylinders(&displayed_dive, true);
	free_dps(dp);

	int droptime = M_OR_FT(60, 200) * 60 / M_OR_FT(99, 330);
	plan_add_segment(dp, 0, gas_mod(ean50, po2, &displayed_dive, M_OR_FT(3, 10)).mm, 1, 0, 1, OC);
	plan_add_segment(dp, droptime, M_OR_FT(60, 200), 0, 0, 1, OC);
	plan_add_segment(dp, 30 * 60 - droptime, M_OR_FT(60, 200), 0, 0, 1, OC);
}
示例#6
0
bool DivePlannerPointsModel::addGas(struct gasmix mix)
{
	sanitize_gasmix(&mix);

	for (int i = 0; i < MAX_CYLINDERS; i++) {
		cylinder_t *cyl = &displayed_dive.cylinder[i];
		if (cylinder_nodata(cyl)) {
			fill_default_cylinder(cyl);
			cyl->gasmix = mix;
			/* The depth to change to that gas is given by the depth where its pO₂ is 1.6 bar.
			 * The user should be able to change this depth manually. */
			pressure_t modpO2;
			if (displayed_dive.dc.divemode == PSCR)
				modpO2.mbar = prefs.decopo2 + (1000 - get_o2(&mix)) * SURFACE_PRESSURE *
						prefs.o2consumption / prefs.decosac / prefs.pscr_ratio;
			else
				modpO2.mbar = prefs.decopo2;
			cyl->depth = gas_mod(&mix, modpO2, M_OR_FT(3,10));




			// FIXME -- need to get rid of stagingDIve
			// the following now uses displayed_dive !!!!



			CylindersModel::instance()->updateDive();
			return true;
		}
		if (!gasmix_distance(&cyl->gasmix, &mix))
			return true;
	}
	qDebug("too many gases");
	return false;
}
示例#7
0
static void calculate_gas_information_new(struct dive *dive, struct plot_info *pi)
{
	int i;
	double amb_pressure;

	for (i = 1; i < pi->nr; i++) {
		int fn2, fhe;
		struct plot_data *entry = pi->entry + i;
		int cylinderindex = entry->cylinderindex;

		amb_pressure = depth_to_bar(entry->depth, dive);

		fill_pressures(&entry->pressures, amb_pressure, &dive->cylinder[cylinderindex].gasmix, entry->o2pressure.mbar / 1000.0, dive->dc.divemode);
		fn2 = (int)(1000.0 * entry->pressures.n2 / amb_pressure);
		fhe = (int)(1000.0 * entry->pressures.he / amb_pressure);

		/* Calculate MOD, EAD, END and EADD based on partial pressures calculated before
		 * so there is no difference in calculating between OC and CC
		 * END takes O₂ + N₂ (air) into account ("Narcotic" for trimix dives)
		 * EAD just uses N₂ ("Air" for nitrox dives) */
		pressure_t modpO2 = { .mbar = (int)(prefs.modpO2 * 1000) };
		entry->mod = (double)gas_mod(&dive->cylinder[cylinderindex].gasmix, modpO2, dive, 1).mm;
		entry->end = (entry->depth + 10000) * (1000 - fhe) / 1000.0 - 10000;
		entry->ead = (entry->depth + 10000) * fn2 / (double)N2_IN_AIR - 10000;
		entry->eadd = (entry->depth + 10000) *
				      (entry->pressures.o2 / amb_pressure * O2_DENSITY +
				       entry->pressures.n2 / amb_pressure * N2_DENSITY +
				       entry->pressures.he / amb_pressure * HE_DENSITY) /
				      (O2_IN_AIR * O2_DENSITY + N2_IN_AIR * N2_DENSITY) * 1000 - 10000;
		if (entry->mod < 0)
			entry->mod = 0;
		if (entry->ead < 0)
			entry->ead = 0;
		if (entry->end < 0)
			entry->end = 0;
		if (entry->eadd < 0)
			entry->eadd = 0;
	}
}

void fill_o2_values(struct divecomputer *dc, struct plot_info *pi, struct dive *dive)
/* In the samples from each dive computer, there may be uninitialised oxygen
 * sensor or setpoint values, e.g. when events were inserted into the dive log
 * or if the dive computer does not report o2 values with every sample. But
 * for drawing the profile a complete series of valid o2 pressure values is
 * required. This function takes the oxygen sensor data and setpoint values
 * from the structures of plotinfo and replaces the zero values with their
 * last known values so that the oxygen sensor data are complete and ready
 * for plotting. This function called by: create_plot_info_new() */
{
	int i, j;
	pressure_t last_sensor[3], o2pressure;
	pressure_t amb_pressure;

	for (i = 0; i < pi->nr; i++) {
		struct plot_data *entry = pi->entry + i;

		if (dc->divemode == CCR) {
			if (i == 0) { // For 1st iteration, initialise the last_sensor values
				for (j = 0; j < dc->no_o2sensors; j++)
					last_sensor[j].mbar = pi->entry->o2sensor[j].mbar;
			} else { // Now re-insert the missing oxygen pressure values
				for (j = 0; j < dc->no_o2sensors; j++)
					if (entry->o2sensor[j].mbar)
						last_sensor[j].mbar = entry->o2sensor[j].mbar;
					else
						entry->o2sensor[j].mbar = last_sensor[j].mbar;
			} // having initialised the empty o2 sensor values for this point on the profile,
			amb_pressure.mbar = depth_to_mbar(entry->depth, dive);
			o2pressure.mbar = calculate_ccr_po2(entry, dc); // ...calculate the po2 based on the sensor data
			entry->o2pressure.mbar = MIN(o2pressure.mbar, amb_pressure.mbar);
		} else {
			entry->o2pressure.mbar = 0; // initialise po2 to zero for dctype = OC
		}
	}
}
示例#8
0
bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
	QString vString;
	bool addDiveMode = DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING;
	if (addDiveMode)
		DivePlannerPointsModel::instance()->rememberTanks();

	cylinder_t *cyl = cylinderAt(index);
	switch (index.column()) {
	case TYPE:
		if (!value.isNull()) {
			QByteArray ba = value.toByteArray();
			const char *text = ba.constData();
			if (!cyl->type.description || strcmp(cyl->type.description, text)) {
				cyl->type.description = strdup(text);
				changed = true;
			}
		}
		break;
	case SIZE:
		if (CHANGED()) {
			TankInfoModel *tanks = TankInfoModel::instance();
			QModelIndexList matches = tanks->match(tanks->index(0, 0), Qt::DisplayRole, cyl->type.description);

			cyl->type.size = string_to_volume(vString.toUtf8().data(), cyl->type.workingpressure);
			mark_divelist_changed(true);
			if (!matches.isEmpty())
				tanks->setData(tanks->index(matches.first().row(), TankInfoModel::ML), cyl->type.size.mliter);
			changed = true;
		}
		break;
	case WORKINGPRESS:
		if (CHANGED()) {
			TankInfoModel *tanks = TankInfoModel::instance();
			QModelIndexList matches = tanks->match(tanks->index(0, 0), Qt::DisplayRole, cyl->type.description);
			cyl->type.workingpressure = string_to_pressure(vString.toUtf8().data());
			if (!matches.isEmpty())
				tanks->setData(tanks->index(matches.first().row(), TankInfoModel::BAR), cyl->type.workingpressure.mbar / 1000.0);
			changed = true;
		}
		break;
	case START:
		if (CHANGED()) {
			cyl->start = string_to_pressure(vString.toUtf8().data());
			changed = true;
		}
		break;
	case END:
		if (CHANGED()) {
			//&& (!cyl->start.mbar || string_to_pressure(vString.toUtf8().data()).mbar <= cyl->start.mbar)) {
			cyl->end = string_to_pressure(vString.toUtf8().data());
			changed = true;
		}
		break;
	case O2:
		if (CHANGED()) {
			cyl->gasmix.o2 = string_to_fraction(vString.toUtf8().data());
			pressure_t modpO2;
			modpO2.mbar = prefs.decopo2;
			cyl->depth = gas_mod(&cyl->gasmix, modpO2, M_OR_FT(3,10));
			changed = true;
		}
		break;
	case HE:
		if (CHANGED()) {
			cyl->gasmix.he = string_to_fraction(vString.toUtf8().data());
			changed = true;
		}
		break;
	case DEPTH:
		if (CHANGED()) {
			cyl->depth = string_to_depth(vString.toUtf8().data());
			changed = true;
		}
	}
	if (addDiveMode)
		DivePlannerPointsModel::instance()->tanksUpdated();
	dataChanged(index, index);
	return true;
}