diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-01-06 18:20:12 -0800 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2013-01-06 22:17:13 -0800 |
commit | d85d8421e08583a8132cc3e0c5dd2b9415a8e091 (patch) | |
tree | 724590055934c4e750d787988bd050153bf1514c /profile.c | |
parent | 25209bfbb4c653c34ddd43f7067e6d0604779b07 (diff) | |
download | subsurface-d85d8421e08583a8132cc3e0c5dd2b9415a8e091.tar.gz |
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>
Diffstat (limited to 'profile.c')
-rw-r--r-- | profile.c | 177 |
1 files changed, 114 insertions, 63 deletions
@@ -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; struct plot_data *entry; 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); } for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { + 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, cur_pt; + pr_track_t *segment; + int pressure; + entry = pi->entry + i; + cyl = entry->cylinderindex; + if (SENSOR_PRESSURE(entry)) { - cur_pr[entry->cylinderindex] = 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; - } - magic = (nlist->end - cur_pr[entry->cylinderindex]) / pt; - } - if (pt != 0.0) { - double cur_pt = (entry->sec - (entry-1)->sec) * - (1 + (entry->depth + (entry-1)->depth) / 20000.0); - INTERPOLATED_PRESSURE(entry) = - cur_pr[entry->cylinderindex] + cur_pt * magic + 0.5; - cur_pr[entry->cylinderindex] = INTERPOLATED_PRESSURE(entry); - } else - INTERPOLATED_PRESSURE(entry) = cur_pr[entry->cylinderindex]; + 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; + } + + /* 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; /* - * 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 * additionally we want two surface events around the whole thing (thus the * additional 4). */ - nr = dc->samples + 4 + maxtime / 10; + nr = dc->samples + 5 + maxtime / 10; plot_data = calloc(nr, sizeof(struct plot_data)); pi->entry = 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); } -/* - * 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) { int i, cylinderindex; @@ -1759,7 +1810,7 @@ static void populate_pressure_information(struct dive *dive, struct divecomputer } 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++) list_free(track_pr[i]); |