aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorGravatar Tim Segers <tsegers@pm.me>2023-01-28 14:04:42 +0100
committerGravatar Tim Segers <tsegers@pm.me>2023-01-28 16:34:52 +0100
commit5d252b1f1710c4a2ef0316e9058f0e2f94d44490 (patch)
treec93a4289cc41cfffd88092c8243e9286539e027b
parentc6880e27d2766bdfed4bb597475d605851c5ff59 (diff)
downloadopendeco-5d252b1f1710c4a2ef0316e9058f0e2f94d44490.tar.gz
Track depth, runtime, and gas in decostate_t
-rw-r--r--src/deco.c36
-rw-r--r--src/deco.h21
-rw-r--r--src/opendeco.c35
-rw-r--r--src/schedule.c144
-rw-r--r--src/schedule.h9
5 files changed, 110 insertions, 135 deletions
diff --git a/src/deco.c b/src/deco.c
index 349c8e5..bd6ed1e 100644
--- a/src/deco.c
+++ b/src/deco.c
@@ -158,7 +158,7 @@ double gas_mod(const gas_t *gas)
return gas->mod;
}
-double add_segment_ascdec(decostate_t *ds, double dstart, double dend, double time, const gas_t *gas)
+void add_segment_ascdec(decostate_t *ds, double dstart, double dend, double time, const gas_t *gas)
{
assert(time > 0);
@@ -184,16 +184,15 @@ double add_segment_ascdec(decostate_t *ds, double dstart, double dend, double ti
ds->pn2[i] = pio + r * (t - 1 / k) - (pio - po - (r / k)) * exp(-k * t);
}
- /* TODO add CNS */
- /* TODO add OTU */
+ ds->depth = dend;
+ ds->runtime += time;
+ ds->gas = gas;
if (dend > ds->max_depth)
ds->max_depth = dend;
-
- return time;
}
-double add_segment_const(decostate_t *ds, double depth, double time, const gas_t *gas)
+void add_segment_const(decostate_t *ds, double depth, double time, const gas_t *gas)
{
assert(time > 0);
@@ -215,13 +214,12 @@ double add_segment_const(decostate_t *ds, double depth, double time, const gas_t
ds->pn2[i] = po + (pio - po) * (1 - exp(-k * t));
}
- /* TODO add CNS */
- /* TODO add OTU */
+ ds->depth = depth;
+ ds->runtime += time;
+ ds->gas = gas;
if (depth > ds->max_depth)
ds->max_depth = depth;
-
- return time;
}
double get_gf(const decostate_t *ds, double depth)
@@ -312,14 +310,20 @@ void init_tissues(decostate_t *ds)
void init_decostate(decostate_t *ds, unsigned char gflo, unsigned char gfhi, double ceil_multiple)
{
assert(gflo <= gfhi);
+ assert(ceil_multiple > 0);
+
+ *ds = (struct decostate_t){
+ .gflo = gflo,
+ .gfhi = gfhi,
+ .firststop = -1,
+ .max_depth = 0,
+ .ceil_multiple = ceil_multiple,
+ .depth = abs_depth(0),
+ .runtime = 0,
+ .gas = NULL,
+ };
init_tissues(ds);
-
- ds->gflo = gflo;
- ds->gfhi = gfhi;
- ds->firststop = -1;
- ds->max_depth = 0;
- ds->ceil_multiple = ceil_multiple;
}
double ppO2(double depth, const gas_t *gas)
diff --git a/src/deco.h b/src/deco.h
index 2500580..0630fec 100644
--- a/src/deco.h
+++ b/src/deco.h
@@ -37,6 +37,13 @@ enum ALGO {
ZHL_16C = 2,
};
+typedef struct gas_t {
+ unsigned char o2;
+ unsigned char he;
+ unsigned char n2;
+ double mod;
+} gas_t;
+
typedef struct decostate_t {
double pn2[16];
double phe[16];
@@ -45,15 +52,11 @@ typedef struct decostate_t {
double firststop;
double max_depth;
double ceil_multiple;
+ const gas_t *gas;
+ double depth;
+ double runtime;
} decostate_t;
-typedef struct gas_t {
- unsigned char o2;
- unsigned char he;
- unsigned char n2;
- double mod;
-} gas_t;
-
/* global variables */
extern enum ALGO ALGO_VER;
extern enum UNITS UNITS;
@@ -83,8 +86,8 @@ unsigned char gas_he(const gas_t *gas);
unsigned char gas_n2(const gas_t *gas);
double gas_mod(const gas_t *gas);
-double add_segment_ascdec(decostate_t *ds, double dstart, double dend, double time, const gas_t *gas);
-double add_segment_const(decostate_t *ds, double depth, double time, const gas_t *gas);
+void add_segment_ascdec(decostate_t *ds, double dstart, double dend, double time, const gas_t *gas);
+void add_segment_const(decostate_t *ds, double depth, double time, const gas_t *gas);
double get_gf(const decostate_t *ds, double depth);
double ceiling(const decostate_t *ds, double gf);
double gf99(const decostate_t *ds, double depth);
diff --git a/src/opendeco.c b/src/opendeco.c
index 8e22e4b..6c2be17 100644
--- a/src/opendeco.c
+++ b/src/opendeco.c
@@ -67,36 +67,38 @@ void print_gas_use(void)
}
}
-void print_segment_callback_fn(const decostate_t *ds, waypoint_t wp, segtype_t type, void *arg)
+void print_segment_callback_fn(const decostate_t *ds, segtype_t type, void *arg)
{
static double last_depth;
- static double runtime;
+ static double last_runtime;
wchar_t sign;
+ double time_diff;
/* first time initialization */
if (!last_depth)
last_depth = SURFACE_PRESSURE;
- runtime += wp.time;
-
- if (wp.depth < last_depth)
+ if (ds->depth < last_depth)
sign = ASC;
- else if (wp.depth > last_depth)
+ else if (ds->depth > last_depth)
sign = DEC;
else
sign = LVL;
+ time_diff = ds->runtime - last_runtime;
+
if (SHOW_TRAVEL || type != SEG_TRAVEL)
- print_planline(sign, wp.depth, wp.time, runtime, wp.gas);
+ print_planline(sign, ds->depth, time_diff, ds->runtime, ds->gas);
/* register gas use */
- double avg_seg_depth = wp.depth == last_depth ? last_depth : (wp.depth + last_depth) / 2;
+ double avg_seg_depth = (ds->depth + last_depth) / 2;
double rmv = type == SEG_DIVE ? RMV_DIVE : RMV_DECO;
- register_gas_use(avg_seg_depth, wp.time, wp.gas, rmv);
+ register_gas_use(avg_seg_depth, time_diff, ds->gas, rmv);
- last_depth = wp.depth;
+ last_depth = ds->depth;
+ last_runtime = ds->runtime;
}
int parse_gasses(gas_t **gasses, char *str)
@@ -194,9 +196,6 @@ int main(int argc, char *argv[])
gas_t bottom_gas;
gas_t *deco_gasses;
- double depth;
- const gas_t *gas;
-
double dec_per_min = xsw_to_bar(msw_or_fsw(9, 30));
int nof_gasses = parse_gasses(&deco_gasses, arguments.decogasses);
@@ -227,19 +226,15 @@ int main(int argc, char *argv[])
};
print_planhead();
-
simulate_dive(&ds, waypoints, len(waypoints), &print_segment_callback);
-
- depth = waypoints[len(waypoints) - 1].depth;
- gas = waypoints[len(waypoints) - 1].gas;
ds_p5 = ds;
/* calculate deco */
- decoinfo_t di = calc_deco(&ds, depth, gas, deco_gasses, nof_gasses, &print_segment_callback);
+ decoinfo_t di = calc_deco(&ds, deco_gasses, nof_gasses, &print_segment_callback);
/* calculate @+5 TTS */
- add_segment_const(&ds_p5, depth, 5, gas);
- decoinfo_t di_p5 = calc_deco(&ds_p5, depth, gas, deco_gasses, nof_gasses, NULL);
+ add_segment_const(&ds_p5, ds_p5.depth, 5, ds_p5.gas);
+ decoinfo_t di_p5 = calc_deco(&ds_p5, deco_gasses, nof_gasses, NULL);
/* output deco info and disclaimer */
wprintf(L"\nNDL: %imin TTS: %imin TTS @+5: %imin\n", (int) floor(di.ndl), (int) ceil(di.tts),
diff --git a/src/schedule.c b/src/schedule.c
index 5528ce3..1827ff3 100644
--- a/src/schedule.c
+++ b/src/schedule.c
@@ -10,6 +10,12 @@
int SWITCH_INTERMEDIATE = SWITCH_INTERMEDIATE_DEFAULT;
+static void emit_waypoint(const decostate_t *ds, segtype_t type, const waypoint_callback_t *wp_cb)
+{
+ if (wp_cb && wp_cb->fn)
+ wp_cb->fn(ds, type, wp_cb->arg);
+}
+
const gas_t *best_gas(double depth, const gas_t *gasses, int nof_gasses)
{
const gas_t *best = NULL;
@@ -27,38 +33,33 @@ const gas_t *best_gas(double depth, const gas_t *gasses, int nof_gasses)
return best;
}
-int direct_ascent(const decostate_t *ds, double depth, double time, const gas_t *gas)
+int direct_ascent(const decostate_t *ds, double ascrate)
{
decostate_t ds_ = *ds;
assert(ds_.firststop == -1);
- add_segment_ascdec(&ds_, depth, abs_depth(0), time, gas);
+ add_segment_ascdec(&ds_, ds_.depth, abs_depth(0), gauge_depth(ds_.depth) / ascrate, ds_.gas);
return gauge_depth(ceiling(&ds_, ds_.gfhi)) <= 0;
}
void simulate_dive(decostate_t *ds, const waypoint_t *waypoints, int nof_waypoints, const waypoint_callback_t *wp_cb)
{
- double depth = abs_depth(0);
-
for (int i = 0; i < nof_waypoints; i++) {
double d = waypoints[i].depth;
double t = waypoints[i].time;
const gas_t *g = waypoints[i].gas;
- if (d != depth)
- add_segment_ascdec(ds, depth, d, t, g);
+ if (d != ds->depth)
+ add_segment_ascdec(ds, ds->depth, d, t, g);
else
add_segment_const(ds, d, t, g);
- depth = d;
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = d, .time = t, .gas = g}, SEG_DIVE, wp_cb->arg);
+ emit_waypoint(ds, SEG_DIVE, wp_cb);
}
}
-double calc_ndl(decostate_t *ds, double depth, double ascrate, const gas_t *gas)
+double calc_ndl(decostate_t *ds, double ascrate)
{
double ndl = 0;
@@ -66,33 +67,33 @@ double calc_ndl(decostate_t *ds, double depth, double ascrate, const gas_t *gas)
decostate_t ds_ = *ds;
while (ndl < 360) {
- double tmp = add_segment_const(&ds_, depth, STOPLEN_ROUGH, gas);
+ add_segment_const(&ds_, ds_.depth, STOPLEN_ROUGH, ds_.gas);
- if (!direct_ascent(&ds_, depth, gauge_depth(depth) / ascrate, gas))
+ if (!direct_ascent(&ds_, ascrate))
break;
- ndl += tmp;
+ ndl = ds_.runtime - ds->runtime;
}
/* fine steps */
ds_ = *ds;
if (ndl)
- add_segment_const(&ds_, depth, ndl, gas);
+ add_segment_const(&ds_, ds_.depth, ndl, ds_.gas);
while (ndl < 360) {
- double tmp = add_segment_const(&ds_, depth, STOPLEN_FINE, gas);
+ add_segment_const(&ds_, ds_.depth, STOPLEN_FINE, ds_.gas);
- if (!direct_ascent(&ds_, depth, gauge_depth(depth) / ascrate, gas))
+ if (!direct_ascent(&ds_, ascrate))
break;
- ndl += tmp;
+ ndl = ds_.runtime - ds->runtime;
}
return ndl;
}
-double deco_stop(decostate_t *ds, double depth, double next_stop, double current_gf, const gas_t *gas)
+static void deco_stop(decostate_t *ds, double next_stop, double current_gf)
{
double stoplen = 0;
@@ -100,86 +101,68 @@ double deco_stop(decostate_t *ds, double depth, double next_stop, double current
decostate_t ds_ = *ds;
for (;;) {
- double tmp = add_segment_const(&ds_, depth, STOPLEN_ROUGH, gas);
+ add_segment_const(&ds_, ds_.depth, STOPLEN_ROUGH, ds_.gas);
if (ceiling(&ds_, current_gf) <= next_stop)
break;
- stoplen += tmp;
+ stoplen = ds_.runtime - ds->runtime;
}
if (stoplen)
- add_segment_const(ds, depth, stoplen, gas);
+ add_segment_const(ds, ds->depth, stoplen, ds->gas);
/* fine steps */
while (ceiling(ds, current_gf) > next_stop)
- stoplen += add_segment_const(ds, depth, STOPLEN_FINE, gas);
-
- return stoplen;
+ add_segment_const(ds, ds->depth, STOPLEN_FINE, ds->gas);
}
-static int surfaced(double depth)
+static int surfaced(decostate_t *ds)
{
- return fabs(depth - SURFACE_PRESSURE) < 1E-2;
+ return ds->depth - SURFACE_PRESSURE < 1E-2;
}
-decoinfo_t calc_deco(decostate_t *ds, double start_depth, const gas_t *start_gas, const gas_t *deco_gasses,
- int nof_gasses, const waypoint_callback_t *wp_cb)
+decoinfo_t calc_deco(decostate_t *ds, const gas_t *deco_gasses, int nof_gasses, const waypoint_callback_t *wp_cb)
{
- decoinfo_t ret = {.tts = 0, .ndl = 0};
-
- /* setup start parameters */
- double depth = start_depth;
- const gas_t *gas = start_gas;
-
+ const double runtime_start = ds->runtime;
const double asc_per_min = msw_to_bar(9);
+ double next_stop;
+ double current_gf;
+ const gas_t *best;
+
/* check if direct ascent is possible */
- if (direct_ascent(ds, depth, gauge_depth(depth) / asc_per_min, gas)) {
- ret.ndl = calc_ndl(ds, depth, asc_per_min, gas);
- return ret;
- }
+ if (direct_ascent(ds, asc_per_min))
+ return (decoinfo_t){.tts = 0, .ndl = calc_ndl(ds, asc_per_min)};
- double next_stop = abs_depth(ds->ceil_multiple * (ceil(gauge_depth(depth) / ds->ceil_multiple) - 1));
+ /* prepare for the first stop */
+ next_stop = abs_depth(ds->ceil_multiple * (ceil(gauge_depth(ds->depth) / ds->ceil_multiple) - 1));
- if (next_stop == depth)
+ if (next_stop == ds->depth)
next_stop -= ds->ceil_multiple;
- double current_gf = get_gf(ds, next_stop);
-
- /* extra bookkeeping because waypoints and segments do not match 1:1 */
- double last_waypoint_depth = depth;
- double waypoint_time;
+ current_gf = get_gf(ds, next_stop);
+ /* alternate between ascending and stopping until we surface */
for (;;) {
- while (ceiling(ds, current_gf) < next_stop && !surfaced(depth)) {
+ /* ascend */
+ while (ceiling(ds, current_gf) < next_stop && !surfaced(ds)) {
/* switch to better gas if available */
- const gas_t *best = best_gas(depth, deco_gasses, nof_gasses);
+ best = best_gas(ds->depth, deco_gasses, nof_gasses);
- if (SWITCH_INTERMEDIATE && best && best != gas) {
- /* emit waypoint */
- waypoint_time = fabs(last_waypoint_depth - depth) / asc_per_min;
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = waypoint_time, .gas = gas}, SEG_TRAVEL,
- wp_cb->arg);
-
- last_waypoint_depth = depth;
+ if (SWITCH_INTERMEDIATE && best && best != ds->gas) {
+ /* emit waypoint because we're about to switch gas */
+ emit_waypoint(ds, SEG_TRAVEL, wp_cb);
/* switch gas */
- gas = best;
-
- ret.tts += add_segment_const(ds, depth, 1, gas);
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = 1, .gas = gas}, SEG_GAS_SWITCH, wp_cb->arg);
+ add_segment_const(ds, ds->depth, 1, best);
+ emit_waypoint(ds, SEG_GAS_SWITCH, wp_cb);
continue;
}
/* ascend to next stop */
- ret.tts += add_segment_ascdec(ds, depth, next_stop, fabs(depth - next_stop) / asc_per_min, gas);
- depth = next_stop;
+ add_segment_ascdec(ds, ds->depth, next_stop, fabs(ds->depth - next_stop) / asc_per_min, ds->gas);
/* make next stop shallower */
next_stop -= ds->ceil_multiple;
@@ -192,7 +175,7 @@ decoinfo_t calc_deco(decostate_t *ds, double start_depth, const gas_t *start_gas
}
if (ds->firststop == -1) {
- ds->firststop = depth;
+ ds->firststop = ds->depth;
/*
* if the first stop wasn't know yet during the previous call to
@@ -205,31 +188,22 @@ decoinfo_t calc_deco(decostate_t *ds, double start_depth, const gas_t *start_gas
continue;
}
- /* emit waypoint */
- waypoint_time = fabs(last_waypoint_depth - depth) / asc_per_min;
- enum segtype_t segtype = surfaced(depth) ? SEG_SURFACE : SEG_TRAVEL;
-
- if (wp_cb && wp_cb->fn && waypoint_time)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = waypoint_time, .gas = gas}, segtype, wp_cb->arg);
-
- last_waypoint_depth = depth;
-
/* terminate if we surfaced */
- if (surfaced(depth))
- return ret;
+ if (surfaced(ds)) {
+ emit_waypoint(ds, SEG_SURFACE, wp_cb);
+ return (decoinfo_t){.ndl = 0, .tts = ds->runtime - runtime_start};
+ }
+
+ emit_waypoint(ds, SEG_TRAVEL, wp_cb);
/* switch to better gas if available */
- const gas_t *best = best_gas(depth, deco_gasses, nof_gasses);
+ best = best_gas(ds->depth, deco_gasses, nof_gasses);
if (best)
- gas = best;
+ ds->gas = best;
/* stop until ceiling rises above next stop */
- double stoplen = deco_stop(ds, depth, next_stop, current_gf, gas);
-
- ret.tts += stoplen;
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = stoplen, .gas = gas}, SEG_DECO_STOP, wp_cb->arg);
+ deco_stop(ds, next_stop, current_gf);
+ emit_waypoint(ds, SEG_DECO_STOP, wp_cb);
}
}
diff --git a/src/schedule.h b/src/schedule.h
index d450232..06c4713 100644
--- a/src/schedule.h
+++ b/src/schedule.h
@@ -30,7 +30,7 @@ typedef enum segtype_t {
} segtype_t;
typedef struct waypoint_callback_t {
- void (*fn)(const decostate_t *, waypoint_t, segtype_t, void *);
+ void (*fn)(const decostate_t *, segtype_t, void *);
void *arg;
} waypoint_callback_t;
@@ -40,12 +40,11 @@ extern int SWITCH_INTERMEDIATE;
/* functions */
const gas_t *best_gas(double depth, const gas_t *gasses, int nof_gasses);
-int direct_ascent(const decostate_t *ds, double depth, double time, const gas_t *gas);
-double calc_ndl(decostate_t *ds, double depth, double ascrate, const gas_t *gas);
+int direct_ascent(const decostate_t *ds, double ascrate);
+double calc_ndl(decostate_t *ds, double ascrate);
void simulate_dive(decostate_t *ds, const waypoint_t *waypoints, int nof_waypoints, const waypoint_callback_t *wp_cb);
-decoinfo_t calc_deco(decostate_t *ds, double start_depth, const gas_t *start_gas, const gas_t *deco_gasses,
- int nof_gasses, const waypoint_callback_t *wp_cb);
+decoinfo_t calc_deco(decostate_t *ds, const gas_t *deco_gasses, int nof_gasses, const waypoint_callback_t *wp_cb);
#endif /* end of include guard: SCHEDULE_H */