diff options
author | Tim Segers <tsegers@pm.me> | 2023-01-28 14:04:42 +0100 |
---|---|---|
committer | Tim Segers <tsegers@pm.me> | 2023-01-28 16:34:52 +0100 |
commit | 5d252b1f1710c4a2ef0316e9058f0e2f94d44490 (patch) | |
tree | c93a4289cc41cfffd88092c8243e9286539e027b | |
parent | c6880e27d2766bdfed4bb597475d605851c5ff59 (diff) | |
download | opendeco-5d252b1f1710c4a2ef0316e9058f0e2f94d44490.tar.gz |
Track depth, runtime, and gas in decostate_t
-rw-r--r-- | src/deco.c | 36 | ||||
-rw-r--r-- | src/deco.h | 21 | ||||
-rw-r--r-- | src/opendeco.c | 35 | ||||
-rw-r--r-- | src/schedule.c | 144 | ||||
-rw-r--r-- | src/schedule.h | 9 |
5 files changed, 110 insertions, 135 deletions
@@ -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) @@ -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 */ |