diff options
Diffstat (limited to 'subsurface-core/gaspressures.c')
-rw-r--r-- | subsurface-core/gaspressures.c | 430 |
1 files changed, 0 insertions, 430 deletions
diff --git a/subsurface-core/gaspressures.c b/subsurface-core/gaspressures.c deleted file mode 100644 index 5d3fc9791..000000000 --- a/subsurface-core/gaspressures.c +++ /dev/null @@ -1,430 +0,0 @@ -/* gaspressures.c - * --------------- - * This file contains the routines to calculate the gas pressures in the cylinders. - * The functions below support the code in profile.c. - * The high-level function is populate_pressure_information(), called by function - * create_plot_info_new() in profile.c. The other functions below are, in turn, - * called by populate_pressure_information(). The calling sequence is as follows: - * - * populate_pressure_information() -> calc_pressure_time() - * -> fill_missing_tank_pressures() -> fill_missing_segment_pressures() - * -> get_pr_interpolate_data() - * - * The pr_track_t related functions below implement a linked list that is used by - * the majority of the functions below. The linked list covers a part of the dive profile - * for which there are no cylinder pressure data. Each element in the linked list - * represents a segment between two consecutive points on the dive profile. - * pr_track_t is defined in gaspressures.h - */ - -#include "dive.h" -#include "display.h" -#include "profile.h" -#include "gaspressures.h" - -static pr_track_t *pr_track_alloc(int start, int t_start) -{ - pr_track_t *pt = malloc(sizeof(pr_track_t)); - pt->start = start; - pt->end = 0; - pt->t_start = pt->t_end = t_start; - pt->pressure_time = 0; - pt->next = NULL; - return pt; -} - -/* poor man's linked list */ -static pr_track_t *list_last(pr_track_t *list) -{ - pr_track_t *tail = list; - if (!tail) - return NULL; - while (tail->next) { - tail = tail->next; - } - return tail; -} - -static pr_track_t *list_add(pr_track_t *list, pr_track_t *element) -{ - pr_track_t *tail = list_last(list); - if (!tail) - return element; - tail->next = element; - return list; -} - -static void list_free(pr_track_t *list) -{ - if (!list) - return; - list_free(list->next); - free(list); -} - -#ifdef DEBUG_PR_TRACK -static void dump_pr_track(pr_track_t **track_pr) -{ - int cyl; - pr_track_t *list; - - for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { - list = track_pr[cyl]; - while (list) { - printf("cyl%d: start %d end %d t_start %d t_end %d pt %d\n", cyl, - list->start, list->end, list->t_start, list->t_end, list->pressure_time); - list = list->next; - } - } -} -#endif - -/* - * This looks at the pressures for one cylinder, and - * calculates any missing beginning/end pressures for - * each segment by taking the over-all SAC-rate into - * account for that cylinder. - * - * NOTE! Many segments have full pressure information - * (both beginning and ending pressure). But if we have - * switched away from a cylinder, we will have the - * beginning pressure for the first segment with a - * missing end pressure. We may then have one or more - * segments without beginning or end pressures, until - * we finally have a segment with an end pressure. - * - * We want to spread out the pressure over these missing - * segments according to how big of a time_pressure area - * they have. - */ -static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_strategy strategy) -{ - double magic; - - while (list) { - int start = list->start, end; - pr_track_t *tmp = list; - int pt_sum = 0, pt = 0; - - for (;;) { - pt_sum += tmp->pressure_time; - end = tmp->end; - if (end) - break; - end = start; - if (!tmp->next) - break; - tmp = tmp->next; - } - - if (!start) - start = end; - - /* - * Now 'start' and 'end' contain the pressure values - * for the set of segments described by 'list'..'tmp'. - * pt_sum is the sum of all the pressure-times of the - * segments. - * - * Now dole out the pressures relative to pressure-time. - */ - list->start = start; - tmp->end = end; - switch (strategy) { - case SAC: - for (;;) { - int pressure; - pt += list->pressure_time; - pressure = start; - if (pt_sum) - pressure -= (start - end) * (double)pt / pt_sum; - list->end = pressure; - if (list == tmp) - break; - list = list->next; - list->start = pressure; - } - break; - case TIME: - if (list->t_end && (tmp->t_start - tmp->t_end)) { - magic = (list->t_start - tmp->t_end) / (tmp->t_start - tmp->t_end); - list->end = rint(start - (start - end) * magic); - } else { - list->end = start; - } - break; - case CONSTANT: - list->end = start; - } - - /* Ok, we've done that set of segments */ - list = list->next; - } -} - -#ifdef DEBUG_PR_INTERPOLATE -void dump_pr_interpolate(int i, pr_interpolate_t interpolate_pr) -{ - printf("Interpolate for entry %d: start %d - end %d - pt %d - acc_pt %d\n", i, - interpolate_pr.start, interpolate_pr.end, interpolate_pr.pressure_time, interpolate_pr.acc_pressure_time); -} -#endif - - -static struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, struct plot_info *pi, int cur) -{ // cur = index to pi->entry corresponding to t_end of segment; - struct pr_interpolate_struct interpolate; - int i; - struct plot_data *entry; - - interpolate.start = segment->start; - interpolate.end = segment->end; - interpolate.acc_pressure_time = 0; - interpolate.pressure_time = 0; - - for (i = 0; i < pi->nr; i++) { - entry = pi->entry + i; - - if (entry->sec < segment->t_start) - continue; - interpolate.pressure_time += entry->pressure_time; - if (entry->sec >= segment->t_end) - break; - if (i <= cur) - interpolate.acc_pressure_time += entry->pressure_time; - } - return interpolate; -} - -static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr, bool o2_flag) -{ - int cyl, i; - struct plot_data *entry; - pr_interpolate_t interpolate = { 0, 0, 0, 0 }; - pr_track_t *last_segment = NULL; - int cur_pr[MAX_CYLINDERS]; // cur_pr[MAX_CYLINDERS] is the CCR diluent cylinder - - for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { - enum interpolation_strategy strategy; - if (!track_pr[cyl]) { - /* no segment where this cylinder is used */ - cur_pr[cyl] = -1; - continue; - } - if (dive->cylinder[cyl].cylinder_use == OC_GAS) - strategy = SAC; - else - strategy = TIME; - fill_missing_segment_pressures(track_pr[cyl], strategy); // Interpolate the missing tank pressure values .. - cur_pr[cyl] = track_pr[cyl]->start; // in the pr_track_t lists of structures - } // and keep the starting pressure for each cylinder. - -#ifdef DEBUG_PR_TRACK - /* another great debugging tool */ - dump_pr_track(track_pr); -#endif - - /* Transfer interpolated cylinder pressures from pr_track strucktures to plotdata - * Go down the list of tank pressures in plot_info. Align them with the start & - * end times of each profile segment represented by a pr_track_t structure. Get - * the accumulated pressure_depths from the pr_track_t structures and then - * interpolate the pressure where these do not exist in the plot_info pressure - * variables. Pressure values are transferred from the pr_track_t structures - * to the plot_info structure, allowing us to plot the tank pressure. - * - * The first two pi structures are "fillers", but in case we don't have a sample - * at time 0 we need to process the second of them here, therefore i=1 */ - for (i = 1; i < pi->nr; i++) { // For each point on the profile: - double magic; - pr_track_t *segment; - int pressure; - int *save_pressure, *save_interpolated; - - entry = pi->entry + i; - - if (o2_flag) { - // Find the cylinder index (cyl) and pressure - cyl = dive->oxygen_cylinder_index; - if (cyl < 0) - return; // Can we do this?!? - pressure = O2CYLINDER_PRESSURE(entry); - save_pressure = &(entry->o2cylinderpressure[SENSOR_PR]); - save_interpolated = &(entry->o2cylinderpressure[INTERPOLATED_PR]); - } else { - pressure = SENSOR_PRESSURE(entry); - save_pressure = &(entry->pressure[SENSOR_PR]); - save_interpolated = &(entry->pressure[INTERPOLATED_PR]); - cyl = entry->cylinderindex; - } - - if (pressure) { // If there is a valid pressure value, - last_segment = NULL; // get rid of interpolation data, - cur_pr[cyl] = pressure; // set current pressure - continue; // and skip to next point. - } - // If there is NO valid pressure value.. - // Find the pressure segment corresponding to this entry.. - segment = track_pr[cyl]; - while (segment && segment->t_end < entry->sec) // Find the track_pr with end time.. - segment = segment->next; // ..that matches the plot_info time (entry->sec) - - if (!segment || !segment->pressure_time) { // No (or empty) segment? - *save_pressure = cur_pr[cyl]; // Just use our current pressure - continue; // and skip to next point. - } - - // If there is a valid segment but no tank pressure .. - if (segment == last_segment) { - interpolate.acc_pressure_time += entry->pressure_time; - } else { - // Set up an interpolation structure - interpolate = get_pr_interpolate_data(segment, pi, i); - last_segment = segment; - } - - if(dive->cylinder[cyl].cylinder_use == OC_GAS) { - - /* if this segment has pressure_time, then calculate a new interpolated pressure */ - if (interpolate.pressure_time) { - /* Overall pressure change over total pressure-time for this segment*/ - magic = (interpolate.end - interpolate.start) / (double)interpolate.pressure_time; - - /* Use that overall pressure change to update the current pressure */ - cur_pr[cyl] = rint(interpolate.start + magic * interpolate.acc_pressure_time); - } - } else { - magic = (interpolate.end - interpolate.start) / (segment->t_end - segment->t_start); - cur_pr[cyl] = rint(segment->start + magic * (entry->sec - segment->t_start)); - } - *save_interpolated = cur_pr[cyl]; // and store the interpolated data in plot_info - } -} - - -/* - * What's the pressure-time between two plot data entries? - * We're calculating the integral of pressure over time by - * adding these up. - * - * The units won't matter as long as everybody agrees about - * them, since they'll cancel out - we use this to calculate - * a constant SAC-rate-equivalent, but we only use it to - * scale pressures, so it ends up being a unitless scaling - * factor. - */ -static inline int calc_pressure_time(struct dive *dive, struct plot_data *a, struct plot_data *b) -{ - int time = b->sec - a->sec; - int depth = (a->depth + b->depth) / 2; - - if (depth <= SURFACE_THRESHOLD) - return 0; - - return depth_to_mbar(depth, dive) * time; -} - -#ifdef PRINT_PRESSURES_DEBUG -// A CCR debugging tool that prints the gas pressures in cylinder 0 and in the diluent cylinder, used in populate_pressure_information(): -static void debug_print_pressures(struct plot_info *pi) -{ - int i; - for (i = 0; i < pi->nr; i++) { - struct plot_data *entry = pi->entry + i; - printf("%5d |%9d | %9d || %9d | %9d |\n", i, SENSOR_PRESSURE(entry), INTERPOLATED_PRESSURE(entry), DILUENT_PRESSURE(entry), INTERPOLATED_DILUENT_PRESSURE(entry)); - } -} -#endif - -/* This function goes through the list of tank pressures, either SENSOR_PRESSURE(entry) or O2CYLINDER_PRESSURE(entry), - * of structure plot_info for the dive profile where each item in the list corresponds to one point (node) of the - * profile. It finds values for which there are no tank pressures (pressure==0). For each missing item (node) of - * tank pressure it creates a pr_track_alloc structure that represents a segment on the dive profile and that - * contains tank pressures. There is a linked list of pr_track_alloc structures for each cylinder. These pr_track_alloc - * structures ultimately allow for filling the missing tank pressure values on the dive profile using the depth_pressure - * of the dive. To do this, it calculates the summed pressure-time value for the duration of the dive and stores these - * in the pr_track_alloc structures. If diluent_flag = 1, then DILUENT_PRESSURE(entry) is used instead of SENSOR_PRESSURE. - * This function is called by create_plot_info_new() in profile.c - */ -void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, int o2_flag) -{ - (void) dc; - int i, cylinderid, cylinderindex = -1; - pr_track_t *track_pr[MAX_CYLINDERS] = { NULL, }; - pr_track_t *current = NULL; - bool missing_pr = false; - bool found_any_pr_data = false; - - /* if we have no pressure data whatsoever, this is pointless, so let's just return */ - for (i = 0; i < MAX_CYLINDERS; i++) { - if (dive->cylinder[i].start.mbar || dive->cylinder[i].sample_start.mbar || - dive->cylinder[i].end.mbar || dive->cylinder[i].sample_end.mbar) { - found_any_pr_data = true; - break; - } - } - if (!found_any_pr_data) - return; - - for (i = 0; i < pi->nr; i++) { - struct plot_data *entry = pi->entry + i; - unsigned pressure; - if (o2_flag) { // if this is a diluent cylinder: - pressure = O2CYLINDER_PRESSURE(entry); - cylinderid = dive->oxygen_cylinder_index; - if (cylinderid < 0) - goto GIVE_UP; - } else { - pressure = SENSOR_PRESSURE(entry); - cylinderid = entry->cylinderindex; - } - /* If track_pr structure already exists, then update it: */ - /* discrete integration of pressure over time to get the SAC rate equivalent */ - if (current) { - entry->pressure_time = calc_pressure_time(dive, entry - 1, entry); - current->pressure_time += entry->pressure_time; - current->t_end = entry->sec; - } - - /* If 1st record or different cylinder: Create a new track_pr structure: */ - /* track the segments per cylinder and their pressure/time integral */ - if (cylinderid != cylinderindex) { - if (o2_flag) // For CCR dives: - cylinderindex = dive->oxygen_cylinder_index; // indicate o2 cylinder - else - cylinderindex = entry->cylinderindex; - current = pr_track_alloc(pressure, entry->sec); - track_pr[cylinderindex] = list_add(track_pr[cylinderindex], current); - continue; - } - - if (!pressure) { - missing_pr = 1; - continue; - } - if (current) - current->end = pressure; - - /* Was it continuous? */ - if ((o2_flag) && (O2CYLINDER_PRESSURE(entry - 1))) // in the case of CCR o2 pressure - continue; - else if (SENSOR_PRESSURE(entry - 1)) // for all other cylinders - continue; - - /* transmitter stopped transmitting cylinder pressure data */ - current = pr_track_alloc(pressure, entry->sec); - if (cylinderindex >= 0) - track_pr[cylinderindex] = list_add(track_pr[cylinderindex], current); - } - - if (missing_pr) { - fill_missing_tank_pressures(dive, pi, track_pr, o2_flag); - } - -#ifdef PRINT_PRESSURES_DEBUG - debug_print_pressures(pi); -#endif - -GIVE_UP: - for (i = 0; i < MAX_CYLINDERS; i++) - list_free(track_pr[i]); -} |