mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-12 15:46:15 +00:00
Split up helper functions for interpolating gas pressure
This splits up the function to create the estimated pressures for missing tank pressure information. The code now has a separate pass to create the beginning and ending pressures for segments that lack them, and fill them in to match the overall SAC-rate for that cylinder. In the process, it also fixes the calculation of the interpolated gas pressure: you can see this in test-dive 13, where we switch back to the first tank at the end of the dive. It used to be that the latter segment of that cylinder showed in a different color from the first segment, showing that we had a different SAC-rate. But that makes no sense, since our interpolation is supposed to use a constant SAC-rate for each cylinder. The bug was that the "magic" calculation (which is just the pressure change rate over pressure-time) was incorrect, and used the current cylinder pressure for start-pressure calculation. But that's wrong, since we update the current cylinder pressure as we go along, but we didn't update the total pressure_time. With the separate phase to calculate the segment beginning/ending pressures, the code got simplified and the bug stood out more. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
25209bfbb4
commit
d85d8421e0
1 changed files with 114 additions and 63 deletions
173
profile.c
173
profile.c
|
@ -1323,11 +1323,89 @@ static void dump_pr_track(pr_track_t **track_pr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_missing_tank_pressures(struct plot_info *pi, pr_track_t **track_pr)
|
/*
|
||||||
|
* 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;
|
||||||
|
double pt_sum = 0.0, pt = 0.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)*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.
|
||||||
|
*/
|
||||||
|
static inline double 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;
|
||||||
|
int mbar = depth_to_mbar(depth, dive);
|
||||||
|
|
||||||
|
return bar_to_atm(mbar / 1000.0) * time;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr)
|
||||||
{
|
{
|
||||||
pr_track_t *list = NULL;
|
|
||||||
pr_track_t *nlist = NULL;
|
|
||||||
double pt, magic;
|
|
||||||
int cyl, i;
|
int cyl, i;
|
||||||
struct plot_data *entry;
|
struct plot_data *entry;
|
||||||
int cur_pr[MAX_CYLINDERS];
|
int cur_pr[MAX_CYLINDERS];
|
||||||
|
@ -1337,57 +1415,44 @@ static void fill_missing_tank_pressures(struct plot_info *pi, pr_track_t **track
|
||||||
dump_pr_track(track_pr);
|
dump_pr_track(track_pr);
|
||||||
}
|
}
|
||||||
for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
|
for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
|
||||||
|
fill_missing_segment_pressures(track_pr[cyl]);
|
||||||
cur_pr[cyl] = track_pr[cyl]->start;
|
cur_pr[cyl] = track_pr[cyl]->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The first two are "fillers", but in case we don't have a sample
|
/* 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 */
|
* at time 0 we need to process the second of them here */
|
||||||
for (i = 1; i < pi->nr; i++) {
|
for (i = 1; i < pi->nr; i++) {
|
||||||
|
double magic, cur_pt;
|
||||||
|
pr_track_t *segment;
|
||||||
|
int pressure;
|
||||||
|
|
||||||
entry = pi->entry + i;
|
entry = pi->entry + i;
|
||||||
|
cyl = entry->cylinderindex;
|
||||||
|
|
||||||
if (SENSOR_PRESSURE(entry)) {
|
if (SENSOR_PRESSURE(entry)) {
|
||||||
cur_pr[entry->cylinderindex] = SENSOR_PRESSURE(entry);
|
cur_pr[cyl] = SENSOR_PRESSURE(entry);
|
||||||
} else {
|
|
||||||
if(!list || list->t_end < entry->sec) {
|
|
||||||
nlist = track_pr[entry->cylinderindex];
|
|
||||||
list = NULL;
|
|
||||||
while (nlist && nlist->t_start <= entry->sec) {
|
|
||||||
list = nlist;
|
|
||||||
nlist = list->next;
|
|
||||||
}
|
|
||||||
/* there may be multiple segments - so
|
|
||||||
* let's assemble the length */
|
|
||||||
nlist = list;
|
|
||||||
if (list) {
|
|
||||||
pt = list->pressure_time;
|
|
||||||
while (!nlist->end) {
|
|
||||||
nlist = nlist->next;
|
|
||||||
if (!nlist) {
|
|
||||||
/* oops - we have no end pressure,
|
|
||||||
* so this means this is a tank without
|
|
||||||
* gas consumption information */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pt += nlist->pressure_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!nlist) {
|
|
||||||
/* just continue without calculating
|
|
||||||
* interpolated values */
|
|
||||||
INTERPOLATED_PRESSURE(entry) = cur_pr[entry->cylinderindex];
|
|
||||||
list = NULL;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
magic = (nlist->end - cur_pr[entry->cylinderindex]) / pt;
|
|
||||||
}
|
/* Find the right pressure segment for this entry.. */
|
||||||
if (pt != 0.0) {
|
segment = track_pr[cyl];
|
||||||
double cur_pt = (entry->sec - (entry-1)->sec) *
|
while (segment && segment->t_end < entry->sec)
|
||||||
(1 + (entry->depth + (entry-1)->depth) / 20000.0);
|
segment = segment->next;
|
||||||
INTERPOLATED_PRESSURE(entry) =
|
|
||||||
cur_pr[entry->cylinderindex] + cur_pt * magic + 0.5;
|
/* No (or empty) segment? Just use our current pressure */
|
||||||
cur_pr[entry->cylinderindex] = INTERPOLATED_PRESSURE(entry);
|
if (!segment || !segment->pressure_time) {
|
||||||
} else
|
SENSOR_PRESSURE(entry) = cur_pr[cyl];
|
||||||
INTERPOLATED_PRESSURE(entry) = cur_pr[entry->cylinderindex];
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overall pressure change over total pressure-time for this segment*/
|
||||||
|
magic = (segment->end - segment->start) / segment->pressure_time;
|
||||||
|
|
||||||
|
/* Use that overall pressure change to update the current pressure */
|
||||||
|
cur_pt = pressure_time(dive, entry-1, entry);
|
||||||
|
pressure = cur_pr[cyl] + cur_pt * magic + 0.5;
|
||||||
|
INTERPOLATED_PRESSURE(entry) = pressure;
|
||||||
|
cur_pr[cyl] = pressure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1546,12 +1611,12 @@ static struct plot_data *populate_plot_entries(struct dive *dive, struct divecom
|
||||||
maxtime = dive->end;
|
maxtime = dive->end;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to have a plot_info event at least every 10s (so "maxtime/10"),
|
* We want to have a plot_info event at least every 10s (so "maxtime/10+1"),
|
||||||
* but samples could be more dense than that (so add in dc->samples), and
|
* but samples could be more dense than that (so add in dc->samples), and
|
||||||
* additionally we want two surface events around the whole thing (thus the
|
* additionally we want two surface events around the whole thing (thus the
|
||||||
* additional 4).
|
* additional 4).
|
||||||
*/
|
*/
|
||||||
nr = dc->samples + 4 + maxtime / 10;
|
nr = dc->samples + 5 + maxtime / 10;
|
||||||
plot_data = calloc(nr, sizeof(struct plot_data));
|
plot_data = calloc(nr, sizeof(struct plot_data));
|
||||||
pi->entry = plot_data;
|
pi->entry = plot_data;
|
||||||
if (!plot_data)
|
if (!plot_data)
|
||||||
|
@ -1685,20 +1750,6 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc
|
||||||
} while ((secondary = secondary->next) != NULL);
|
} while ((secondary = secondary->next) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* What's the pressure-time between two plot data entries?
|
|
||||||
* We're calculating the integral of pressure over time by
|
|
||||||
* adding these up.
|
|
||||||
*/
|
|
||||||
static inline double 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;
|
|
||||||
int mbar = depth_to_mbar(depth, dive);
|
|
||||||
|
|
||||||
return bar_to_atm(mbar / 1000.0) * time;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
|
static void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
|
||||||
{
|
{
|
||||||
int i, cylinderindex;
|
int i, cylinderindex;
|
||||||
|
@ -1759,7 +1810,7 @@ static void populate_pressure_information(struct dive *dive, struct divecomputer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (missing_pr) {
|
if (missing_pr) {
|
||||||
fill_missing_tank_pressures(pi, track_pr);
|
fill_missing_tank_pressures(dive, pi, track_pr);
|
||||||
}
|
}
|
||||||
for (i = 0; i < MAX_CYLINDERS; i++)
|
for (i = 0; i < MAX_CYLINDERS; i++)
|
||||||
list_free(track_pr[i]);
|
list_free(track_pr[i]);
|
||||||
|
|
Loading…
Add table
Reference in a new issue