mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
CCR code: Split profile.c into two files, with gas caluclations separate.
This patch implements a separation of the code for gas pressure calculations from the rest of the code in profile.c. The latter file is now split into: profile.c and gaspressures.c. The details of the transferred functions is given at the top of gaspressures.c. The following chnages were made: 1) dive.h: The function types of calculate_depth_to_mbar and depth_to_mbar were made non-static in order to make them available within gaspressures.c. 2) profile.c: Prototypes for the functions in gaspressures.c were inserted at the top of profile. Ten functions were transferred from profile.c to gaspressures.c 3) gaspressures.c as well as a short header, gaspressures.h were created. For the gas pressure calculations for CCR dives, gaspressures.c forms the immediate basis for further code development. Signed-off-by: Willem Ferguson <willemferguson@zoology.up.ac.za> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
214bd0ed6e
commit
7575eb44df
6 changed files with 396 additions and 348 deletions
4
dive.h
4
dive.h
|
@ -362,7 +362,7 @@ static inline int get_surface_pressure_in_mbar(const struct dive *dive, bool non
|
||||||
/* Pa = N/m^2 - so we determine the weight (in N) of the mass of 10m
|
/* Pa = N/m^2 - so we determine the weight (in N) of the mass of 10m
|
||||||
* of water (and use standard salt water at 1.03kg per liter if we don't know salinity)
|
* of water (and use standard salt water at 1.03kg per liter if we don't know salinity)
|
||||||
* and add that to the surface pressure (or to 1013 if that's unknown) */
|
* and add that to the surface pressure (or to 1013 if that's unknown) */
|
||||||
static inline int calculate_depth_to_mbar(int depth, pressure_t surface_pressure, int salinity)
|
inline int calculate_depth_to_mbar(int depth, pressure_t surface_pressure, int salinity)
|
||||||
{
|
{
|
||||||
double specific_weight;
|
double specific_weight;
|
||||||
int mbar = surface_pressure.mbar;
|
int mbar = surface_pressure.mbar;
|
||||||
|
@ -376,7 +376,7 @@ static inline int calculate_depth_to_mbar(int depth, pressure_t surface_pressure
|
||||||
return mbar;
|
return mbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int depth_to_mbar(int depth, struct dive *dive)
|
inline int depth_to_mbar(int depth, struct dive *dive)
|
||||||
{
|
{
|
||||||
return calculate_depth_to_mbar(depth, dive->surface_pressure, dive->salinity);
|
return calculate_depth_to_mbar(depth, dive->surface_pressure, dive->salinity);
|
||||||
}
|
}
|
||||||
|
|
347
gaspressures.c
Normal file
347
gaspressures.c
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
/* 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()
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gettext.h"
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "dive.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "divelist.h"
|
||||||
|
|
||||||
|
#include "profile.h"
|
||||||
|
#include "gaspressures.h"
|
||||||
|
#include "deco.h"
|
||||||
|
#include "libdivecomputer/parser.h"
|
||||||
|
#include "libdivecomputer/version.h"
|
||||||
|
#include "membuffer.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.
|
||||||
|
*/
|
||||||
|
void fill_missing_segment_pressures(pr_track_t *list)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
|
||||||
|
struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, struct plot_info *pi, int cur)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
if (entry->sec >= segment->t_end) {
|
||||||
|
interpolate.pressure_time += entry->pressure_time;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (entry->sec == segment->t_start) {
|
||||||
|
interpolate.acc_pressure_time = 0;
|
||||||
|
interpolate.pressure_time = 0;
|
||||||
|
if (SENSOR_PRESSURE(entry))
|
||||||
|
interpolate.start = SENSOR_PRESSURE(entry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i < cur) {
|
||||||
|
if (SENSOR_PRESSURE(entry)) {
|
||||||
|
interpolate.start = SENSOR_PRESSURE(entry);
|
||||||
|
interpolate.acc_pressure_time = 0;
|
||||||
|
interpolate.pressure_time = 0;
|
||||||
|
} else {
|
||||||
|
interpolate.acc_pressure_time += entry->pressure_time;
|
||||||
|
interpolate.pressure_time += entry->pressure_time;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == cur) {
|
||||||
|
interpolate.acc_pressure_time += entry->pressure_time;
|
||||||
|
interpolate.pressure_time += entry->pressure_time;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
interpolate.pressure_time += entry->pressure_time;
|
||||||
|
if (SENSOR_PRESSURE(entry)) {
|
||||||
|
interpolate.end = SENSOR_PRESSURE(entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return interpolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr)
|
||||||
|
{
|
||||||
|
int cyl, i;
|
||||||
|
struct plot_data *entry;
|
||||||
|
int cur_pr[MAX_CYLINDERS];
|
||||||
|
|
||||||
|
#ifdef DEBUG_PR_TRACK
|
||||||
|
/* another great debugging tool */
|
||||||
|
dump_pr_track(track_pr);
|
||||||
|
#endif
|
||||||
|
for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
|
||||||
|
if (!track_pr[cyl]) {
|
||||||
|
/* no segment where this cylinder is used */
|
||||||
|
cur_pr[cyl] = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fill_missing_segment_pressures(track_pr[cyl]);
|
||||||
|
cur_pr[cyl] = track_pr[cyl]->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The first two are "fillers", but in case we don't have a sample
|
||||||
|
* at time 0 we need to process the second of them here */
|
||||||
|
for (i = 1; i < pi->nr; i++) {
|
||||||
|
double magic;
|
||||||
|
pr_track_t *segment;
|
||||||
|
pr_interpolate_t interpolate;
|
||||||
|
|
||||||
|
entry = pi->entry + i;
|
||||||
|
cyl = entry->cylinderindex;
|
||||||
|
|
||||||
|
if (SENSOR_PRESSURE(entry)) {
|
||||||
|
cur_pr[cyl] = SENSOR_PRESSURE(entry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the right pressure segment for this entry.. */
|
||||||
|
segment = track_pr[cyl];
|
||||||
|
while (segment && segment->t_end < entry->sec)
|
||||||
|
segment = segment->next;
|
||||||
|
|
||||||
|
/* No (or empty) segment? Just use our current pressure */
|
||||||
|
if (!segment || !segment->pressure_time) {
|
||||||
|
SENSOR_PRESSURE(entry) = cur_pr[cyl];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
interpolate = get_pr_interpolate_data(segment, pi, i);
|
||||||
|
#ifdef DEBUG_PR_INTERPOLATE
|
||||||
|
dump_pr_interpolate(i, interpolate);
|
||||||
|
#endif
|
||||||
|
/* if this segment has pressure time, 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);
|
||||||
|
}
|
||||||
|
INTERPOLATED_PRESSURE(entry) = cur_pr[cyl];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
inline int calc_pressure_time(struct dive *dive, struct divecomputer *dc, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
|
||||||
|
{
|
||||||
|
int i, cylinderindex;
|
||||||
|
pr_track_t *track_pr[MAX_CYLINDERS] = { NULL, };
|
||||||
|
pr_track_t *current;
|
||||||
|
bool missing_pr = false;
|
||||||
|
|
||||||
|
cylinderindex = -1;
|
||||||
|
current = NULL;
|
||||||
|
for (i = 0; i < pi->nr; i++) {
|
||||||
|
struct plot_data *entry = pi->entry + i;
|
||||||
|
int pressure = SENSOR_PRESSURE(entry);
|
||||||
|
|
||||||
|
/* discrete integration of pressure over time to get the SAC rate equivalent */
|
||||||
|
if (current) {
|
||||||
|
entry->pressure_time = calc_pressure_time(dive, dc, entry - 1, entry);
|
||||||
|
current->pressure_time += entry->pressure_time;
|
||||||
|
current->t_end = entry->sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* track the segments per cylinder and their pressure/time integral */
|
||||||
|
if (entry->cylinderindex != cylinderindex) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
current->end = pressure;
|
||||||
|
|
||||||
|
/* Was it continuous? */
|
||||||
|
if (SENSOR_PRESSURE(entry - 1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* transmitter changed its working status */
|
||||||
|
current = pr_track_alloc(pressure, entry->sec);
|
||||||
|
track_pr[cylinderindex] = list_add(track_pr[cylinderindex], current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missing_pr) {
|
||||||
|
fill_missing_tank_pressures(dive, pi, track_pr);
|
||||||
|
}
|
||||||
|
for (i = 0; i < MAX_CYLINDERS; i++)
|
||||||
|
list_free(track_pr[i]);
|
||||||
|
}
|
33
gaspressures.h
Normal file
33
gaspressures.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef GASPRESSURES_H
|
||||||
|
#define GASPRESSURES_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* simple structure to track the beginning and end tank pressure as
|
||||||
|
* well as the integral of depth over time spent while we have no
|
||||||
|
* pressure reading from the tank */
|
||||||
|
typedef struct pr_track_struct pr_track_t;
|
||||||
|
struct pr_track_struct {
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
int t_start;
|
||||||
|
int t_end;
|
||||||
|
int pressure_time;
|
||||||
|
pr_track_t *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct pr_interpolate_struct pr_interpolate_t;
|
||||||
|
struct pr_interpolate_struct {
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
int pressure_time;
|
||||||
|
int acc_pressure_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // GASPRESSURES_H
|
347
profile.c
347
profile.c
|
@ -10,6 +10,7 @@
|
||||||
#include "divelist.h"
|
#include "divelist.h"
|
||||||
|
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
|
#include "gaspressures.h"
|
||||||
#include "deco.h"
|
#include "deco.h"
|
||||||
#include "libdivecomputer/parser.h"
|
#include "libdivecomputer/parser.h"
|
||||||
#include "libdivecomputer/version.h"
|
#include "libdivecomputer/version.h"
|
||||||
|
@ -18,9 +19,13 @@
|
||||||
int selected_dive = -1; /* careful: 0 is a valid value */
|
int selected_dive = -1; /* careful: 0 is a valid value */
|
||||||
unsigned int dc_number = 0;
|
unsigned int dc_number = 0;
|
||||||
|
|
||||||
|
|
||||||
static struct plot_data *last_pi_entry_new = NULL;
|
static struct plot_data *last_pi_entry_new = NULL;
|
||||||
|
|
||||||
|
void fill_missing_segment_pressures(pr_track_t*);
|
||||||
|
struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t*, struct plot_info*, int);
|
||||||
|
void fill_missing_tank_pressures(struct dive*, struct plot_info*, pr_track_t**);
|
||||||
|
void populate_pressure_information(struct dive*, struct divecomputer*, struct plot_info*);
|
||||||
|
|
||||||
#ifdef DEBUG_PI
|
#ifdef DEBUG_PI
|
||||||
/* debugging tool - not normally used */
|
/* debugging tool - not normally used */
|
||||||
static void dump_pi(struct plot_info *pi)
|
static void dump_pi(struct plot_info *pi)
|
||||||
|
@ -284,295 +289,6 @@ struct plot_info *analyze_plot_info(struct plot_info *pi)
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* simple structure to track the beginning and end tank pressure as
|
|
||||||
* well as the integral of depth over time spent while we have no
|
|
||||||
* pressure reading from the tank */
|
|
||||||
typedef struct pr_track_struct pr_track_t;
|
|
||||||
struct pr_track_struct {
|
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
int t_start;
|
|
||||||
int t_end;
|
|
||||||
int pressure_time;
|
|
||||||
pr_track_t *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
typedef struct pr_interpolate_struct pr_interpolate_t;
|
|
||||||
struct pr_interpolate_struct {
|
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
int pressure_time;
|
|
||||||
int acc_pressure_time;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef DEBUG_PR_INTERPOLATE
|
|
||||||
static 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
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ok, we've done that set of segments */
|
|
||||||
list = list->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 pressure_time(struct dive *dive, struct divecomputer *dc, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, struct plot_info *pi, int cur)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
if (entry->sec >= segment->t_end) {
|
|
||||||
interpolate.pressure_time += entry->pressure_time;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (entry->sec == segment->t_start) {
|
|
||||||
interpolate.acc_pressure_time = 0;
|
|
||||||
interpolate.pressure_time = 0;
|
|
||||||
if (SENSOR_PRESSURE(entry))
|
|
||||||
interpolate.start = SENSOR_PRESSURE(entry);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (i < cur) {
|
|
||||||
if (SENSOR_PRESSURE(entry)) {
|
|
||||||
interpolate.start = SENSOR_PRESSURE(entry);
|
|
||||||
interpolate.acc_pressure_time = 0;
|
|
||||||
interpolate.pressure_time = 0;
|
|
||||||
} else {
|
|
||||||
interpolate.acc_pressure_time += entry->pressure_time;
|
|
||||||
interpolate.pressure_time += entry->pressure_time;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (i == cur) {
|
|
||||||
interpolate.acc_pressure_time += entry->pressure_time;
|
|
||||||
interpolate.pressure_time += entry->pressure_time;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
interpolate.pressure_time += entry->pressure_time;
|
|
||||||
if (SENSOR_PRESSURE(entry)) {
|
|
||||||
interpolate.end = SENSOR_PRESSURE(entry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return interpolate;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr)
|
|
||||||
{
|
|
||||||
int cyl, i;
|
|
||||||
struct plot_data *entry;
|
|
||||||
int cur_pr[MAX_CYLINDERS];
|
|
||||||
|
|
||||||
#ifdef DEBUG_PR_TRACK
|
|
||||||
/* another great debugging tool */
|
|
||||||
dump_pr_track(track_pr);
|
|
||||||
#endif
|
|
||||||
for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
|
|
||||||
if (!track_pr[cyl]) {
|
|
||||||
/* no segment where this cylinder is used */
|
|
||||||
cur_pr[cyl] = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fill_missing_segment_pressures(track_pr[cyl]);
|
|
||||||
cur_pr[cyl] = track_pr[cyl]->start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The first two are "fillers", but in case we don't have a sample
|
|
||||||
* at time 0 we need to process the second of them here */
|
|
||||||
for (i = 1; i < pi->nr; i++) {
|
|
||||||
double magic;
|
|
||||||
pr_track_t *segment;
|
|
||||||
pr_interpolate_t interpolate;
|
|
||||||
|
|
||||||
entry = pi->entry + i;
|
|
||||||
cyl = entry->cylinderindex;
|
|
||||||
|
|
||||||
if (SENSOR_PRESSURE(entry)) {
|
|
||||||
cur_pr[cyl] = SENSOR_PRESSURE(entry);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the right pressure segment for this entry.. */
|
|
||||||
segment = track_pr[cyl];
|
|
||||||
while (segment && segment->t_end < entry->sec)
|
|
||||||
segment = segment->next;
|
|
||||||
|
|
||||||
/* No (or empty) segment? Just use our current pressure */
|
|
||||||
if (!segment || !segment->pressure_time) {
|
|
||||||
SENSOR_PRESSURE(entry) = cur_pr[cyl];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
interpolate = get_pr_interpolate_data(segment, pi, i);
|
|
||||||
#ifdef DEBUG_PR_INTERPOLATE
|
|
||||||
dump_pr_interpolate(i, interpolate);
|
|
||||||
#endif
|
|
||||||
/* if this segment has pressure time, 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);
|
|
||||||
}
|
|
||||||
INTERPOLATED_PRESSURE(entry) = cur_pr[cyl];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_cylinder_index(struct dive *dive, struct event *ev)
|
int get_cylinder_index(struct dive *dive, struct event *ev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -955,57 +671,6 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc
|
||||||
} while ((secondary = secondary->next) != NULL);
|
} while ((secondary = secondary->next) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
|
|
||||||
{
|
|
||||||
int i, cylinderindex;
|
|
||||||
pr_track_t *track_pr[MAX_CYLINDERS] = { NULL, };
|
|
||||||
pr_track_t *current;
|
|
||||||
bool missing_pr = false;
|
|
||||||
|
|
||||||
cylinderindex = -1;
|
|
||||||
current = NULL;
|
|
||||||
for (i = 0; i < pi->nr; i++) {
|
|
||||||
struct plot_data *entry = pi->entry + i;
|
|
||||||
int pressure = SENSOR_PRESSURE(entry);
|
|
||||||
|
|
||||||
/* discrete integration of pressure over time to get the SAC rate equivalent */
|
|
||||||
if (current) {
|
|
||||||
entry->pressure_time = pressure_time(dive, dc, entry - 1, entry);
|
|
||||||
current->pressure_time += entry->pressure_time;
|
|
||||||
current->t_end = entry->sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* track the segments per cylinder and their pressure/time integral */
|
|
||||||
if (entry->cylinderindex != cylinderindex) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
current->end = pressure;
|
|
||||||
|
|
||||||
/* Was it continuous? */
|
|
||||||
if (SENSOR_PRESSURE(entry - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* transmitter changed its working status */
|
|
||||||
current = pr_track_alloc(pressure, entry->sec);
|
|
||||||
track_pr[cylinderindex] = list_add(track_pr[cylinderindex], current);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (missing_pr) {
|
|
||||||
fill_missing_tank_pressures(dive, pi, track_pr);
|
|
||||||
}
|
|
||||||
for (i = 0; i < MAX_CYLINDERS; i++)
|
|
||||||
list_free(track_pr[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate DECO STOP / TTS / NDL */
|
/* calculate DECO STOP / TTS / NDL */
|
||||||
static void calculate_ndl_tts(double tissue_tolerance, struct plot_data *entry, struct dive *dive, double surface_pressure)
|
static void calculate_ndl_tts(double tissue_tolerance, struct plot_data *entry, struct dive *dive, double surface_pressure)
|
||||||
{
|
{
|
||||||
|
|
11
profile.h
11
profile.h
|
@ -52,6 +52,12 @@ struct plot_data {
|
||||||
int heartbeat;
|
int heartbeat;
|
||||||
int bearing;
|
int bearing;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ev_select {
|
||||||
|
char *ev_name;
|
||||||
|
bool plot_ev;
|
||||||
|
};
|
||||||
|
|
||||||
struct plot_info calculate_max_limits_new(struct dive *dive, struct divecomputer *dc);
|
struct plot_info calculate_max_limits_new(struct dive *dive, struct divecomputer *dc);
|
||||||
void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int bufsize, int sum);
|
void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int bufsize, int sum);
|
||||||
struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer *dc, struct plot_info *pi);
|
struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer *dc, struct plot_info *pi);
|
||||||
|
@ -60,11 +66,6 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo
|
||||||
void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode);
|
void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode);
|
||||||
void get_plot_details_new(struct plot_info *pi, int time, struct membuffer *);
|
void get_plot_details_new(struct plot_info *pi, int time, struct membuffer *);
|
||||||
|
|
||||||
struct ev_select {
|
|
||||||
char *ev_name;
|
|
||||||
bool plot_ev;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When showing dive profiles, we scale things to the
|
* When showing dive profiles, we scale things to the
|
||||||
* current dive. However, we don't scale past less than
|
* current dive. However, we don't scale past less than
|
||||||
|
|
|
@ -38,6 +38,7 @@ HEADERS = \
|
||||||
worldmap-options.h \
|
worldmap-options.h \
|
||||||
pref.h \
|
pref.h \
|
||||||
profile.h \
|
profile.h \
|
||||||
|
gaspressures.h \
|
||||||
qt-gui.h \
|
qt-gui.h \
|
||||||
qthelper.h \
|
qthelper.h \
|
||||||
units.h \
|
units.h \
|
||||||
|
@ -117,6 +118,7 @@ SOURCES = \
|
||||||
parse-xml.c \
|
parse-xml.c \
|
||||||
planner.c \
|
planner.c \
|
||||||
profile.c \
|
profile.c \
|
||||||
|
gaspressures.c \
|
||||||
divecomputer.cpp \
|
divecomputer.cpp \
|
||||||
worldmap-save.c \
|
worldmap-save.c \
|
||||||
save-html.c \
|
save-html.c \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue