summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/user-manual_es.txt75
-rw-r--r--profile-widget/profilewidget2.cpp32
-rw-r--r--profile-widget/profilewidget2.h2
-rw-r--r--subsurface-core/deco.c4
-rw-r--r--subsurface-core/file.c3
-rw-r--r--subsurface-core/parse-xml.c56
-rw-r--r--subsurface-core/profile.c183
7 files changed, 239 insertions, 116 deletions
diff --git a/Documentation/user-manual_es.txt b/Documentation/user-manual_es.txt
index a8cd4c267..8c9490638 100644
--- a/Documentation/user-manual_es.txt
+++ b/Documentation/user-manual_es.txt
@@ -6,7 +6,7 @@
// :revnumber: 4.5
// :revdate: October 2015
:icons:
-:toc:
+:toc2:
:toc-placement: manual
:numbered:
:ascii-ids:
@@ -24,7 +24,7 @@ Pedro Neves
Bienvenido como usuario de _Subsurface_, un avanzado programa de registro de
inmersiones con extensa infraestructura para describir, organizar e
-interpretarbuceos en apnea o con botella. _Subsurface_ ofrece muchas ventajas
+interpretar buceos en apnea o con botella. _Subsurface_ ofrece muchas ventajas
sobre otras soluciones de software similares:
- ¿Necesitas una forma flexible de registrar inmersiones usando equipo
@@ -65,14 +65,31 @@ Buceadores profesionales.
toc::[]
-[[S_UserSurvey]]
Utilizar este manual
--------------------
Cuando se abre desde dentro de _Subsurface_ este manual no tiene controles
-externos. Sin embargo, una función _BUSCAR_ es importante. Se activa pulsando
-control-F en el teclado. Aparecerá una ventana de texto al pié de la ventana.
-Utilízala para buscar cualquier término en el manual.
+externos para paginar o seleccionar páginas anteriores, sin embargo se
+proporcionan dos utilidades:
+
+- La función _BUSCAR_ se activa pulsando control-F o command-F en el teclado.
+Aparecerá una ventana de texto al pié de la ventana (ver imagen a continuación).
+Por ejemplo, si se tecleó la palabra "_lastre_" en la casilla de búsqueda, se
+buscará esta palabra por todo el manual. A la derecha de la casilla de texto
+hay dos flechas, una hacia arriba y otra hacia abajo. Pulsándolas se irá a la
+anterior o posterior aparición de la palabra buscada.
+
+image::images/usermanualfunctions.jpg["User manual functions",align="center"]
+
+- _LINK ANTERIOR/POSTERIOR_. Se puede navegar entre links (palabras resaltadas
+que permiten saltar a secciones específicas del manual) haciendo clic-derecho
+en el texto. Esto muestra un menú contextual que permite navegar a links
+del manual visitados anteriormente (ver imagen anterior). Por ejemplo, si se
+ha seleccionado un link del manual, la opción _Atrás_ muestra el texto del
+último link seleccionado. A la inversa, la opción _Adelante_ permite saltar
+al texto visitado antes de usar la opción _Atrás_. La opción _Recargar_ hace
+que se recargue el manual completo en la ventana.
+[[S_UserSurvey]]
La Encuesta de Usuarios
-----------------------
Para poder desarrollar _Subsurface_ de una forma que sirva a sus usuarios de la
@@ -509,8 +526,12 @@ _Limpiar_ y efectúa una nueva búsqueda utilizando el botón _Buscar_. Si
_Subsurface_ "ve" el ordenador de buceo, la línea de la lista contendrá el
nombre del dispositivo, su dirección y su estado de emparejamiento. Si el
dispositivo no está emparejado y tiene un fondo rojo, se puede abrir un menú
-contextual seleccionando su línea y pulsando clic-derecho. Pulsa el
-botón _Emparejar_ y espera a que se complete la tarea.
+contextual seleccionando su línea y pulsando clic-derecho.
+Pulsa el botón _Emparejar_ y espera a que se complete la tarea. Si este
+ordenador de buceo se está emparejando con _Subsurface_ por primera vez, es
+posible que se requiera una clave o número PIN. La clave más utilizada suele
+ser 0000, y funciona para el Shearwater Petrel. En caso necesario, consulta el
+manual de usuario del ordenador de buceo.
****
[icon="images/icons/important.png"]
@@ -543,7 +564,11 @@ image::images/DC_import_Bluetooth_Windows.png["FIGURE: Descarga Bluetooth en Win
En plataformas Windows no está disponible la _sección de detalles de los
dispositivos Bluetooth_. Para iniciar correctamente un escaneo pulsando el
botón _Buscar_ , comprueba que el dispositivo _Bluetooth_ del ordenador con
-_Subsurface_ está activado.
+_Subsurface_ está activado seleccionando el ordenador de la lista de
+dispositivos Bluetooth disponibles (ver imagen anterior). Si se accede por
+primera vez al ordenador de buceo con _Subsurface_, es posible que se
+requiera una clave/PIN. Introduce el recomendado en el manual de ordenador
+de buceo. A menudo es correcto un pin 0000.
El paso del emparejado se efectúa de forma
automática durante el proceso de descarga. Si los dispositivos no se han
@@ -559,7 +584,8 @@ proceso.
Hay que tener en cuenta que, actualmente, _Subsurface_ solo funciona con
adaptadores Bluetooth locales que usen Microsoft Bluetooth Stack. Si el
dispositivo local usa drivers _Widcomm_, _Stonestreet One Bluetopia Bluetooth_ o
-_BlueSolei_ no funcionará.
+_BlueSolei_ no funcionará, sin embargo, los receptores de estos fabricantes
+que usen el Microsoft Bluetooth Stack sí funcionarán.
Un mensaje de aviso en la parte inferior izquierda de la _Selección de
dispositivos Bluetooth remotos_ muestra detalles del estado actual del agente
@@ -1966,10 +1992,10 @@ oxígeno (OTU) en las que se ha incurrido.
[icon="images/icons/info.jpg"]
[NOTE]
-Consumo de gas y cálculos de CAS _Subsurface_ calcula el CAS y el consumo de gas
+Consumo de gas y cálculos de CAS: _Subsurface_ calcula el CAS y el consumo de gas
teniendo en cuenta la incompresibilidad de los gases, particularmente a
presiones en las botellas superiores a 200 bar, haciéndolos más precisos. Los
-usuarios deberían consultar el xref:SAC_CALCULATION[Apéndice_D] para más información.
+usuarios deberían consultar el xref:SAC_CALCULATION[Apéndice F] para más información.
[[S_ExtraDataTab]]
=== La pestaña *Otros datos* (para inmersiones individuales)
@@ -2265,6 +2291,20 @@ máxima de 1.4 en la sección *Preferencias*. Por debajo de la PMO existe un
riesgo muy elevado de exposición a los peligros asociados con la toxicidad del
oxígeno.
+[icon="images/icons/NDL.jpg"]
+[NOTE]
+Activar este botón hace que el recuadro Información muestre, bien el *Límite
+de no descompresión (LND)* o el **Tiempo total hasta superficie (TTS)*. El
+LND es el tiempo que un buzo puede permanecer sumergido a la profundidad actual
+sin requerir descompresión (esto es, sin que aparezca un techo para el ascenso).
+Una vez que se ha excedido el LND y se requiere descompresión, el TTS incluirá
+el total de minutos requeridos antes de que el buceador pueda salir a superficie.
+El TTS incluye el tiempo de ascenso y las paradas de descompresión. Se calcula
+suponiendo que se usa el gas actual. Incluso si el perfil incluye varios
+cambios de gas, el TTS en un momento dado de la inmersión se habrá calculado
+con el gas en uso en ese momento. Para TTS superiores a 2 horas, no se calcula
+con precisión y simplemente se indica _TTS > 2h_.
+
[icon="images/icons/SAC.jpg"]
[NOTE]
Activar este botón hace que el Recuadro de información muestre el *Consumo de
@@ -3787,7 +3827,7 @@ conectarse y se debería poder importar las inmersiones.
[icon="images/icons/bluetooth.jpg"]
[NOTE]
Para ordenadores de buceo que se comunican por bluetooth como el Heinrichs
-Weikamp Frog o el Shearwater Predator y Petrel hay un procedimiento distinto
+Weikamp Frog o el Shearwater Predator, Petrel y Nerd hay un procedimiento distinto
para localizar los nombres de dispositivo con los que se comunicará
_Subsurface_. En general consiste en estos pasos:
@@ -3795,7 +3835,7 @@ _Subsurface_. En general consiste en estos pasos:
modo Upload*
Para emparejar el ordenador de buceo, consulta la guía de usuario del
-fabricante. Si se está usando un Shearwater Predator/Petrel, hay que seleccionar
+fabricante. Si se está usando un Shearwater Predator/Petrel/Nerd, hay que seleccionar
_Dive Log → Upload Log_ y esperar al mensaje _Wait PC_.
* *Emparejar el PC con _Subsurface_ con el ordenador de buceo.*
@@ -3850,7 +3890,7 @@ Se trata esencialmente de un proceso en tres pasos.
- Descargar las inmersiones con _Subsurface_
Asegurarse de que el ordenador de buceo está en modo "upload". En el _Petrel_
-y _Petrel 2_, navega por el menú, selecciona 'Dive Log', luego 'Upload log'. En
+y _Petrel 2_ y _Nerd_, navega por el menú, selecciona 'Dive Log', luego 'Upload log'. En
la pantalla se leerá 'Initializing', luego 'Wait PC 3:00' e iniciará una cuenta
atrás. Una vez que la conexión esté establecida, en la pantalla se leerá
'Wait CMD ...' y la cuenta atrás seguirá. Cuando se descargue la inmersión a
@@ -3964,8 +4004,9 @@ Si se omite el canal, se asume el 1. Basándonos en un número limitado de
informaciones de usuarios el canal apropiado para el ordenador de buceo,
probablemente sea:
-- _Shearwater Petrel 2_: channel 5
- _Shearwater Petrel 1_: channel 1
+- _Shearwater Petrel 2_: channel 5
+- _Shearwater Nerd_: channel 5
- _Heinrichs-Weikamp OSTC Sport_: channel 1
P.e. para conectar un _Shearwater Petrel 2_, ajusta el ordenador de buceo a
@@ -4106,7 +4147,7 @@ capa de deco en el *Perfil deinmersión* de _Subsurface_ pero fíjate que la
deco calculada por _Subsurface_ diferirá con toda probabilidad de la que
mostraría el xDEEP BLACK.
-=== Importar del Shearwater Predator/Petrel usando Bluetooth
+=== Importar del Shearwater Predator/Petrel/Nerd usando Bluetooth
[icon="images/icons/predator.jpg"]
[NOTE]
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp
index 8ff8e8669..653818556 100644
--- a/profile-widget/profilewidget2.cpp
+++ b/profile-widget/profilewidget2.cpp
@@ -87,7 +87,7 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent),
gasPressureItem(new DiveGasPressureItem()),
diveComputerText(new DiveTextItem()),
diveCeiling(new DiveCalculatedCeiling()),
- gradientFactor(new DiveTextItem()),
+ decoModelParameters(new DiveTextItem()),
reportedCeiling(new DiveReportedCeiling()),
pn2GasItem(new PartialPressureGasItem()),
pheGasItem(new PartialPressureGasItem()),
@@ -204,7 +204,7 @@ void ProfileWidget2::addItemsToScene()
diveComputerText->setData(SUBSURFACE_OBJ_DATA, SUBSURFACE_OBJ_DC_TEXT);
scene()->addItem(diveComputerText);
scene()->addItem(diveCeiling);
- scene()->addItem(gradientFactor);
+ scene()->addItem(decoModelParameters);
scene()->addItem(reportedCeiling);
scene()->addItem(pn2GasItem);
scene()->addItem(pheGasItem);
@@ -288,11 +288,11 @@ void ProfileWidget2::setupItemOnScene()
rulerItem->setAxis(timeAxis, profileYAxis);
tankItem->setHorizontalAxis(timeAxis);
- // show the gradient factor at the top in the center
- gradientFactor->setY(0);
- gradientFactor->setX(50);
- gradientFactor->setBrush(getColor(PRESSURE_TEXT));
- gradientFactor->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
+ // show the deco model parameters at the top in the center
+ decoModelParameters->setY(0);
+ decoModelParameters->setX(50);
+ decoModelParameters->setBrush(getColor(PRESSURE_TEXT));
+ decoModelParameters->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
setupItem(reportedCeiling, timeAxis, profileYAxis, dataModel, DivePlotDataModel::CEILING, DivePlotDataModel::TIME, 1);
setupItem(diveCeiling, timeAxis, profileYAxis, dataModel, DivePlotDataModel::CEILING, DivePlotDataModel::TIME, 1);
@@ -509,7 +509,10 @@ void ProfileWidget2::plotDive(struct dive *d, bool force)
// this copies the dive and makes copies of all the relevant additional data
copy_dive(d, &displayed_dive);
- gradientFactor->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh));
+ if (prefs.deco_mode == VPMB)
+ decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.conservatism_level));
+ else
+ decoModelParameters->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh));
} else {
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
plannerModel->createTemporaryPlan();
@@ -518,7 +521,10 @@ void ProfileWidget2::plotDive(struct dive *d, bool force)
plannerModel->deleteTemporaryPlan();
return;
}
- gradientFactor->setText(QString("GF %1/%2").arg(diveplan.gflow).arg(diveplan.gfhigh));
+ if (prefs.deco_mode == VPMB)
+ decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.conservatism_level));
+ else
+ decoModelParameters->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh));
}
// special handling for the first time we display things
@@ -926,7 +932,7 @@ void ProfileWidget2::setEmptyState()
toolTipItem->setVisible(false);
diveComputerText->setVisible(false);
diveCeiling->setVisible(false);
- gradientFactor->setVisible(false);
+ decoModelParameters->setVisible(false);
reportedCeiling->setVisible(false);
rulerItem->setVisible(false);
tankItem->setVisible(false);
@@ -1053,7 +1059,7 @@ void ProfileWidget2::setProfileState()
diveComputerText->setPos(itemPos.dcLabel.on);
diveCeiling->setVisible(prefs.calcceiling);
- gradientFactor->setVisible(prefs.calcceiling);
+ decoModelParameters->setVisible(prefs.calcceiling);
reportedCeiling->setVisible(prefs.dcceiling);
if (prefs.calcalltissues) {
@@ -1131,7 +1137,7 @@ void ProfileWidget2::setAddState()
/* show the same stuff that the profile shows. */
currentState = ADD; /* enable the add state. */
diveCeiling->setVisible(true);
- gradientFactor->setVisible(true);
+ decoModelParameters->setVisible(true);
setBackgroundBrush(QColor("#A7DCFF"));
}
@@ -1165,7 +1171,7 @@ void ProfileWidget2::setPlanState()
/* show the same stuff that the profile shows. */
currentState = PLAN; /* enable the add state. */
diveCeiling->setVisible(true);
- gradientFactor->setVisible(true);
+ decoModelParameters->setVisible(true);
setBackgroundBrush(QColor("#D7E3EF"));
}
diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h
index f11ec5be1..ce3fda083 100644
--- a/profile-widget/profilewidget2.h
+++ b/profile-widget/profilewidget2.h
@@ -170,7 +170,7 @@ private:
QList<DiveEventItem *> eventItems;
DiveTextItem *diveComputerText;
DiveCalculatedCeiling *diveCeiling;
- DiveTextItem *gradientFactor;
+ DiveTextItem *decoModelParameters;
QList<DiveCalculatedTissue *> allTissues;
DiveReportedCeiling *reportedCeiling;
PartialPressureGasItem *pn2GasItem;
diff --git a/subsurface-core/deco.c b/subsurface-core/deco.c
index 86acc0351..506d8b58f 100644
--- a/subsurface-core/deco.c
+++ b/subsurface-core/deco.c
@@ -244,7 +244,7 @@ double tissue_tolerance_calc(const struct dive *dive, double pressure)
double lowest_ceiling = 0.0;
double tissue_lowest_ceiling[16];
- if (prefs.deco_mode != VPMB || !in_planner()) {
+ if (prefs.deco_mode != VPMB) {
for (ci = 0; ci < 16; ci++) {
tissue_inertgas_saturation[ci] = tissue_n2_sat[ci] + tissue_he_sat[ci];
buehlmann_inertgas_a[ci] = ((buehlmann_N2_a[ci] * tissue_n2_sat[ci]) + (buehlmann_He_a[ci] * tissue_he_sat[ci])) / tissue_inertgas_saturation[ci];
@@ -509,7 +509,7 @@ void add_segment(double pressure, const struct gasmix *gasmix, int period_in_sec
tissue_n2_sat[ci] += n2_satmult * pn2_oversat * n2_f;
tissue_he_sat[ci] += he_satmult * phe_oversat * he_f;
}
- if(prefs.deco_mode == VPMB && in_planner())
+ if(prefs.deco_mode == VPMB)
calc_crushing_pressure(pressure);
return;
}
diff --git a/subsurface-core/file.c b/subsurface-core/file.c
index c4032c1f2..0263da457 100644
--- a/subsurface-core/file.c
+++ b/subsurface-core/file.c
@@ -105,6 +105,9 @@ int try_to_open_zip(const char *filename, struct memblock *mem)
success++;
}
subsurface_zip_close(zip);
+
+ if (!success)
+ return report_error(translate("gettextFromC", "No dives in the input file '%s'"), filename);
}
return success;
}
diff --git a/subsurface-core/parse-xml.c b/subsurface-core/parse-xml.c
index 3d86222b9..93ce74305 100644
--- a/subsurface-core/parse-xml.c
+++ b/subsurface-core/parse-xml.c
@@ -1398,32 +1398,36 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf)
return;
if (MATCH("visibility.dive", get_rating, &dive->visibility))
return;
- if (MATCH("size.cylinder", cylindersize, &dive->cylinder[cur_cylinder_index].type.size))
- return;
- if (MATCH("workpressure.cylinder", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure))
- return;
- if (MATCH("description.cylinder", utf8_string, &dive->cylinder[cur_cylinder_index].type.description))
- return;
- if (MATCH("start.cylinder", pressure, &dive->cylinder[cur_cylinder_index].start))
- return;
- if (MATCH("end.cylinder", pressure, &dive->cylinder[cur_cylinder_index].end))
- return;
- if (MATCH("use.cylinder", cylinder_use, &dive->cylinder[cur_cylinder_index].cylinder_use))
- return;
- if (MATCH("description.weightsystem", utf8_string, &dive->weightsystem[cur_ws_index].description))
- return;
- if (MATCH("weight.weightsystem", weight, &dive->weightsystem[cur_ws_index].weight))
- return;
- if (MATCH("weight", weight, &dive->weightsystem[cur_ws_index].weight))
- return;
- if (MATCH("o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
- return;
- if (MATCH("o2percent", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
- return;
- if (MATCH("n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix))
- return;
- if (MATCH("he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he))
- return;
+ if (cur_ws_index < MAX_WEIGHTSYSTEMS) {
+ if (MATCH("description.weightsystem", utf8_string, &dive->weightsystem[cur_ws_index].description))
+ return;
+ if (MATCH("weight.weightsystem", weight, &dive->weightsystem[cur_ws_index].weight))
+ return;
+ if (MATCH("weight", weight, &dive->weightsystem[cur_ws_index].weight))
+ return;
+ }
+ if (cur_cylinder_index < MAX_CYLINDERS) {
+ if (MATCH("size.cylinder", cylindersize, &dive->cylinder[cur_cylinder_index].type.size))
+ return;
+ if (MATCH("workpressure.cylinder", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure))
+ return;
+ if (MATCH("description.cylinder", utf8_string, &dive->cylinder[cur_cylinder_index].type.description))
+ return;
+ if (MATCH("start.cylinder", pressure, &dive->cylinder[cur_cylinder_index].start))
+ return;
+ if (MATCH("end.cylinder", pressure, &dive->cylinder[cur_cylinder_index].end))
+ return;
+ if (MATCH("use.cylinder", cylinder_use, &dive->cylinder[cur_cylinder_index].cylinder_use))
+ return;
+ if (MATCH("o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
+ return;
+ if (MATCH("o2percent", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
+ return;
+ if (MATCH("n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix))
+ return;
+ if (MATCH("he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he))
+ return;
+ }
if (MATCH("air.divetemperature", temperature, &dive->airtemp))
return;
if (MATCH("water.divetemperature", temperature, &dive->watertemp))
diff --git a/subsurface-core/profile.c b/subsurface-core/profile.c
index d39133c21..edba51ebd 100644
--- a/subsurface-core/profile.c
+++ b/subsurface-core/profile.c
@@ -28,6 +28,9 @@ unsigned int dc_number = 0;
static struct plot_data *last_pi_entry_new = NULL;
void populate_pressure_information(struct dive *, struct divecomputer *, struct plot_info *, int);
+extern bool in_planner();
+extern pressure_t first_ceiling_pressure;
+
#ifdef DEBUG_PI
/* debugging tool - not normally used */
static void dump_pi(struct plot_info *pi)
@@ -866,6 +869,8 @@ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double
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 */
@@ -927,69 +932,133 @@ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double
*/
void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode)
{
- int i;
+ 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;
- 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
- entry->ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, !prefs.calcceiling3m);
- 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);
- }
+ 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 (prefs.calcndltts && !print_mode) {
- /* only calculate ndl/tts on every 30 seconds */
- if ((entry->sec - last_ndl_tts_calc_time) < 30) {
- 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;
+ /* 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);
}
- 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);
- /* 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