mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Allow for more O2 sensors
The Divesoft Liberty has four O2 sensors. So far, we had a hard coded limit of three sensors and crashed with a failed assert when we encoutered more than three. This allows for up to MAX_O2_SENSORS which is currently 6. The voting logic is adapted accordingly: We sort the values and we keep deleting the values that differ more than 20% by value from the closest. This follows what Shearwater implements on their computers. In some of the import/export functions the value is still hard coded to 6 thanks to explicit field names. Signed-off-by: Robert C. Helling <helling@lmu.de>
This commit is contained in:
parent
e00e1bb9f7
commit
e794efaba6
13 changed files with 31329 additions and 31257 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
core: allow of up to 6 O2 sensors (and corresponding voting logic)
|
||||||
desktop: add divemode as a possible dive list column
|
desktop: add divemode as a possible dive list column
|
||||||
profile-widget: Now zomed in profiles can be panned with horizontal scroll.
|
profile-widget: Now zomed in profiles can be panned with horizontal scroll.
|
||||||
desktop: hide only events with the same severity when 'Hide similar events' is used
|
desktop: hide only events with the same severity when 'Hide similar events' is used
|
||||||
|
|
11
core/dive.c
11
core/dive.c
|
@ -1184,15 +1184,12 @@ static void fixup_no_o2sensors(struct divecomputer *dc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < dc->samples; i++) {
|
for (int i = 0; i < dc->samples; i++) {
|
||||||
int nsensor = 0;
|
int nsensor = 0, j;
|
||||||
struct sample *s = dc->sample + i;
|
struct sample *s = dc->sample + i;
|
||||||
|
|
||||||
// How many o2 sensors can we find in this sample?
|
// How many o2 sensors can we find in this sample?
|
||||||
if (s->o2sensor[0].mbar)
|
for (j = 0; j < MAX_O2_SENSORS; j++)
|
||||||
nsensor++;
|
if (s->o2sensor[j].mbar)
|
||||||
if (s->o2sensor[1].mbar)
|
|
||||||
nsensor++;
|
|
||||||
if (s->o2sensor[2].mbar)
|
|
||||||
nsensor++;
|
nsensor++;
|
||||||
|
|
||||||
// If we fond more than the previous found max, record it.
|
// If we fond more than the previous found max, record it.
|
||||||
|
@ -1200,7 +1197,7 @@ static void fixup_no_o2sensors(struct divecomputer *dc)
|
||||||
dc->no_o2sensors = nsensor;
|
dc->no_o2sensors = nsensor;
|
||||||
|
|
||||||
// Already found the maximum posible amount.
|
// Already found the maximum posible amount.
|
||||||
if (nsensor == 3)
|
if (nsensor == MAX_O2_SENSORS)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,7 +456,7 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
|
||||||
sample->setpoint.mbar = po2 = lrint(value.setpoint * 1000);
|
sample->setpoint.mbar = po2 = lrint(value.setpoint * 1000);
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_PPO2:
|
case DC_SAMPLE_PPO2:
|
||||||
if (nsensor < 3)
|
if (nsensor < MAX_O2_SENSORS)
|
||||||
sample->o2sensor[nsensor].mbar = lrint(value.ppo2 * 1000);
|
sample->o2sensor[nsensor].mbar = lrint(value.ppo2 * 1000);
|
||||||
else
|
else
|
||||||
report_error("%d is more o2 sensors than we can handle", nsensor);
|
report_error("%d is more o2 sensors than we can handle", nsensor);
|
||||||
|
|
|
@ -589,6 +589,21 @@ static void parse_sample_keyvalue(void *_sample, const char *key, const char *va
|
||||||
sample->o2sensor[2].mbar = p.mbar;
|
sample->o2sensor[2].mbar = p.mbar;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(key, "sensor4")) {
|
||||||
|
pressure_t p = get_pressure(value);
|
||||||
|
sample->o2sensor[3].mbar = p.mbar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(key, "sensor5")) {
|
||||||
|
pressure_t p = get_pressure(value);
|
||||||
|
sample->o2sensor[4].mbar = p.mbar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(key, "sensor6")) {
|
||||||
|
pressure_t p = get_pressure(value);
|
||||||
|
sample->o2sensor[5].mbar = p.mbar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!strcmp(key, "o2pressure")) {
|
if (!strcmp(key, "o2pressure")) {
|
||||||
pressure_t p = get_pressure(value);
|
pressure_t p = get_pressure(value);
|
||||||
sample->pressure[1].mbar = p.mbar;
|
sample->pressure[1].mbar = p.mbar;
|
||||||
|
|
|
@ -932,7 +932,13 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu
|
||||||
return;
|
return;
|
||||||
if (MATCH("sensor2.sample", double_to_o2pressure, &sample->o2sensor[1]))
|
if (MATCH("sensor2.sample", double_to_o2pressure, &sample->o2sensor[1]))
|
||||||
return;
|
return;
|
||||||
if (MATCH("sensor3.sample", double_to_o2pressure, &sample->o2sensor[2])) // up to 3 CCR sensors
|
if (MATCH("sensor3.sample", double_to_o2pressure, &sample->o2sensor[2]))
|
||||||
|
return;
|
||||||
|
if (MATCH("sensor4.sample", double_to_o2pressure, &sample->o2sensor[3]))
|
||||||
|
return;
|
||||||
|
if (MATCH("sensor5.sample", double_to_o2pressure, &sample->o2sensor[4]))
|
||||||
|
return;
|
||||||
|
if (MATCH("sensor6.sample", double_to_o2pressure, &sample->o2sensor[5])) // up to 6 CCR sensors
|
||||||
return;
|
return;
|
||||||
if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint))
|
if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint))
|
||||||
return;
|
return;
|
||||||
|
@ -2230,8 +2236,7 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct divelog *log)
|
||||||
state.cur_sample->o2sensor[0].mbar = ( ((ptr[5] << 8) + ptr[4]) * o2_sensor_calibration_values[0]) / 10000;
|
state.cur_sample->o2sensor[0].mbar = ( ((ptr[5] << 8) + ptr[4]) * o2_sensor_calibration_values[0]) / 10000;
|
||||||
state.cur_sample->o2sensor[1].mbar = ( ((ptr[7] << 8) + ptr[6]) * o2_sensor_calibration_values[1]) / 10000;
|
state.cur_sample->o2sensor[1].mbar = ( ((ptr[7] << 8) + ptr[6]) * o2_sensor_calibration_values[1]) / 10000;
|
||||||
state.cur_sample->o2sensor[2].mbar = ( ((ptr[9] << 8) + ptr[8]) * o2_sensor_calibration_values[2]) / 10000;
|
state.cur_sample->o2sensor[2].mbar = ( ((ptr[9] << 8) + ptr[8]) * o2_sensor_calibration_values[2]) / 10000;
|
||||||
// Subsurface only handles 3 o2 sensors.
|
state.cur_sample->o2sensor[3].mbar = ( ((ptr[11] << 8) + ptr[10]) * o2_sensor_calibration_values[3]) / 10000;
|
||||||
//state.cur_sample->o2sensor[3].mbar = ( ((ptr[11] << 8) + ptr[10]) * o2_sensor_calibration_values[3]) / 10000;
|
|
||||||
sample_end(&state);
|
sample_end(&state);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
|
|
@ -476,9 +476,9 @@ static void populate_plot_entries(const struct dive *dive, const struct divecomp
|
||||||
entry->cns = sample->cns;
|
entry->cns = sample->cns;
|
||||||
if (dc->divemode == CCR || (dc->divemode == PSCR && dc->no_o2sensors)) {
|
if (dc->divemode == CCR || (dc->divemode == PSCR && dc->no_o2sensors)) {
|
||||||
entry->o2pressure.mbar = entry->o2setpoint.mbar = sample->setpoint.mbar; // for rebreathers
|
entry->o2pressure.mbar = entry->o2setpoint.mbar = sample->setpoint.mbar; // for rebreathers
|
||||||
entry->o2sensor[0].mbar = sample->o2sensor[0].mbar; // for up to three rebreather O2 sensors
|
int i;
|
||||||
entry->o2sensor[1].mbar = sample->o2sensor[1].mbar;
|
for (i = 0; i < MAX_O2_SENSORS; i++)
|
||||||
entry->o2sensor[2].mbar = sample->o2sensor[2].mbar;
|
entry->o2sensor[i].mbar = sample->o2sensor[i].mbar;
|
||||||
} else {
|
} else {
|
||||||
entry->pressures.o2 = sample->setpoint.mbar / 1000.0;
|
entry->pressures.o2 = sample->setpoint.mbar / 1000.0;
|
||||||
}
|
}
|
||||||
|
@ -1117,48 +1117,71 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_
|
||||||
unlock_planner();
|
unlock_planner();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sort the o2 pressure values. There are so few that a simple bubble sort
|
||||||
|
* will do */
|
||||||
|
|
||||||
|
void sort_o2_pressures(int *sensorn, int np, struct plot_data *entry)
|
||||||
|
{
|
||||||
|
int smallest, position, old;
|
||||||
|
|
||||||
|
for (int i = 0; i < np - 1; i++) {
|
||||||
|
position = i;
|
||||||
|
smallest = entry->o2sensor[sensorn[i]].mbar;
|
||||||
|
for (int j = i+1; j < np; j++)
|
||||||
|
if (entry->o2sensor[sensorn[j]].mbar < smallest) {
|
||||||
|
position = j;
|
||||||
|
smallest = entry->o2sensor[sensorn[j]].mbar;
|
||||||
|
}
|
||||||
|
old = sensorn[i];
|
||||||
|
sensorn[i] = position;
|
||||||
|
sensorn[position] = old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Function calculate_ccr_po2: This function takes information from one plot_data structure (i.e. one point on
|
/* Function calculate_ccr_po2: This function takes information from one plot_data structure (i.e. one point on
|
||||||
* the dive profile), containing the oxygen sensor values of a CCR system and, for that plot_data structure,
|
* the dive profile), containing the oxygen sensor values of a CCR system and, for that plot_data structure,
|
||||||
* calculates the po2 value from the sensor data. Several rules are applied, depending on how many o2 sensors
|
* calculates the po2 value from the sensor data. If there are at least 3 sensors, sensors are voted out until
|
||||||
* there are and the differences among the readings from these sensors.
|
* their span is within diff_limit.
|
||||||
*/
|
*/
|
||||||
static int calculate_ccr_po2(struct plot_data *entry, const struct divecomputer *dc)
|
static int calculate_ccr_po2(struct plot_data *entry, const struct divecomputer *dc)
|
||||||
{
|
{
|
||||||
int sump = 0, minp = 999999, maxp = -999999;
|
int sump = 0, minp = 0, maxp = 0;
|
||||||
int diff_limit = 100; // The limit beyond which O2 sensor differences are considered significant (default = 100 mbar)
|
int sensorn[MAX_O2_SENSORS];
|
||||||
int i, np = 0;
|
int i, np = 0;
|
||||||
|
|
||||||
for (i = 0; i < dc->no_o2sensors; i++)
|
for (i = 0; i < dc->no_o2sensors && i < MAX_O2_SENSORS; i++)
|
||||||
if (entry->o2sensor[i].mbar) { // Valid reading
|
if (entry->o2sensor[i].mbar) { // Valid reading
|
||||||
++np;
|
sensorn[np++] = i;
|
||||||
sump += entry->o2sensor[i].mbar;
|
sump += entry->o2sensor[i].mbar;
|
||||||
minp = MIN(minp, entry->o2sensor[i].mbar);
|
|
||||||
maxp = MAX(maxp, entry->o2sensor[i].mbar);
|
|
||||||
}
|
}
|
||||||
switch (np) {
|
if (np == 0)
|
||||||
case 0: // Uhoh
|
|
||||||
return entry->o2pressure.mbar;
|
return entry->o2pressure.mbar;
|
||||||
case 1: // Return what we have
|
else if (np == 1)
|
||||||
return sump;
|
return entry->o2sensor[sensorn[0]].mbar;
|
||||||
case 2: // Take the average
|
|
||||||
return sump / 2;
|
maxp = np - 1;
|
||||||
case 3: // Voting logic
|
sort_o2_pressures(sensorn, np, entry);
|
||||||
if (2 * maxp - sump + minp < diff_limit) { // Upper difference acceptable...
|
|
||||||
if (2 * minp - sump + maxp) // ...and lower difference acceptable
|
// This is the Shearwater voting logic: If there are still at least three sensors and one
|
||||||
return sump / 3;
|
// differs by more than 20% from the closest it is voted out.
|
||||||
else
|
while (maxp - minp > 1) {
|
||||||
return (sump - minp) / 2;
|
if (entry->o2sensor[sensorn[minp + 1]].mbar - entry->o2sensor[sensorn[minp]].mbar >
|
||||||
} else {
|
sump / (maxp - minp + 1) / 5) {
|
||||||
if (2 * minp - sump + maxp) // ...but lower difference acceptable
|
sump -= entry->o2sensor[sensorn[minp]].mbar;
|
||||||
return (sump - maxp) / 2;
|
++minp;
|
||||||
else
|
continue;
|
||||||
return sump / 3;
|
|
||||||
}
|
}
|
||||||
default: // This should not happen
|
if (entry->o2sensor[sensorn[maxp]].mbar - entry->o2sensor[sensorn[maxp - 1]].mbar >
|
||||||
assert(np <= 3);
|
sump / (maxp - minp +1) / 5) {
|
||||||
return 0;
|
sump -= entry->o2sensor[sensorn[maxp]].mbar;
|
||||||
|
--maxp;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sump / (maxp - minp + 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static double gas_density(const struct gas_pressures *pressures)
|
static double gas_density(const struct gas_pressures *pressures)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#define PROFILE_H
|
#define PROFILE_H
|
||||||
|
|
||||||
#include "dive.h"
|
#include "dive.h"
|
||||||
|
#include "sample.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -53,7 +54,7 @@ struct plot_data {
|
||||||
int running_sum;
|
int running_sum;
|
||||||
struct gas_pressures pressures;
|
struct gas_pressures pressures;
|
||||||
pressure_t o2pressure; // for rebreathers, this is consensus measured po2, or setpoint otherwise. 0 for OC.
|
pressure_t o2pressure; // for rebreathers, this is consensus measured po2, or setpoint otherwise. 0 for OC.
|
||||||
pressure_t o2sensor[3]; //for rebreathers with up to 3 PO2 sensors
|
pressure_t o2sensor[MAX_O2_SENSORS]; //for rebreathers with several sensors
|
||||||
pressure_t o2setpoint;
|
pressure_t o2setpoint;
|
||||||
pressure_t scr_OC_pO2;
|
pressure_t scr_OC_pO2;
|
||||||
int mod, ead, end, eadd;
|
int mod, ead, end, eadd;
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_SENSORS 2
|
#define MAX_SENSORS 2
|
||||||
|
#define MAX_O2_SENSORS 6
|
||||||
#define NO_SENSOR -1
|
#define NO_SENSOR -1
|
||||||
|
|
||||||
struct sample // BASE TYPE BYTES UNITS RANGE DESCRIPTION
|
struct sample // BASE TYPE BYTES UNITS RANGE DESCRIPTION
|
||||||
|
@ -23,7 +24,7 @@ struct sample // BASE TYPE BYTES UNITS RANGE
|
||||||
temperature_t temperature; // uint32_t 4 mK (0-4 MK) ambient temperature
|
temperature_t temperature; // uint32_t 4 mK (0-4 MK) ambient temperature
|
||||||
pressure_t pressure[MAX_SENSORS]; // int32_t 2x4 mbar (0-2 Mbar) cylinder pressures (main and CCR o2)
|
pressure_t pressure[MAX_SENSORS]; // int32_t 2x4 mbar (0-2 Mbar) cylinder pressures (main and CCR o2)
|
||||||
o2pressure_t setpoint; // uint16_t 2 mbar (0-65 bar) O2 partial pressure (will be setpoint)
|
o2pressure_t setpoint; // uint16_t 2 mbar (0-65 bar) O2 partial pressure (will be setpoint)
|
||||||
o2pressure_t o2sensor[3]; // uint16_t 3x2 mbar (0-65 bar) Up to 3 PO2 sensor values (rebreather)
|
o2pressure_t o2sensor[MAX_O2_SENSORS];// uint16_t 6x2 mbar (0-65 bar) Up to 6 PO2 sensor values (rebreather)
|
||||||
bearing_t bearing; // int16_t 2 degrees (-1 no val, 0-360 deg) compass bearing
|
bearing_t bearing; // int16_t 2 degrees (-1 no val, 0-360 deg) compass bearing
|
||||||
int16_t sensor[MAX_SENSORS]; // int16_t 2x2 sensorID (0-16k) ID of cylinder pressure sensor
|
int16_t sensor[MAX_SENSORS]; // int16_t 2x2 sensorID (0-16k) ID of cylinder pressure sensor
|
||||||
uint16_t cns; // uint16_t 2 % (0-64k %) cns% accumulated
|
uint16_t cns; // uint16_t 2 % (0-64k %) cns% accumulated
|
||||||
|
|
|
@ -338,6 +338,21 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
|
||||||
old->o2sensor[2] = sample->o2sensor[2];
|
old->o2sensor[2] = sample->o2sensor[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((sample->o2sensor[3].mbar) && (sample->o2sensor[3].mbar != old->o2sensor[3].mbar)) {
|
||||||
|
put_milli(b, " sensor4=", sample->o2sensor[3].mbar, "bar");
|
||||||
|
old->o2sensor[3] = sample->o2sensor[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sample->o2sensor[4].mbar) && (sample->o2sensor[4].mbar != old->o2sensor[4].mbar)) {
|
||||||
|
put_milli(b, " sensor5=", sample->o2sensor[4].mbar, "bar");
|
||||||
|
old->o2sensor[4] = sample->o2sensor[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sample->o2sensor[5].mbar) && (sample->o2sensor[5].mbar != old->o2sensor[5].mbar)) {
|
||||||
|
put_milli(b, " sensor6=", sample->o2sensor[5].mbar, "bar");
|
||||||
|
old->o2sensor[5] = sample->o2sensor[5];
|
||||||
|
}
|
||||||
|
|
||||||
if (sample->setpoint.mbar != old->setpoint.mbar) {
|
if (sample->setpoint.mbar != old->setpoint.mbar) {
|
||||||
put_milli(b, " po2=", sample->setpoint.mbar, "bar");
|
put_milli(b, " po2=", sample->setpoint.mbar, "bar");
|
||||||
old->setpoint = sample->setpoint;
|
old->setpoint = sample->setpoint;
|
||||||
|
|
|
@ -71,9 +71,8 @@ static void put_pd(struct membuffer *b, const struct plot_info *pi, int idx)
|
||||||
put_double(b, entry->pressures.n2);
|
put_double(b, entry->pressures.n2);
|
||||||
put_double(b, entry->pressures.he);
|
put_double(b, entry->pressures.he);
|
||||||
put_int(b, entry->o2pressure.mbar);
|
put_int(b, entry->o2pressure.mbar);
|
||||||
put_int(b, entry->o2sensor[0].mbar);
|
for (int i = 0; i < MAX_O2_SENSORS; i++)
|
||||||
put_int(b, entry->o2sensor[1].mbar);
|
put_int(b, entry->o2sensor[i].mbar);
|
||||||
put_int(b, entry->o2sensor[2].mbar);
|
|
||||||
put_int(b, entry->o2setpoint.mbar);
|
put_int(b, entry->o2setpoint.mbar);
|
||||||
put_int(b, entry->scr_OC_pO2.mbar);
|
put_int(b, entry->scr_OC_pO2.mbar);
|
||||||
put_int(b, entry->mod);
|
put_int(b, entry->mod);
|
||||||
|
|
|
@ -328,6 +328,21 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
|
||||||
old->o2sensor[2] = sample->o2sensor[2];
|
old->o2sensor[2] = sample->o2sensor[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((sample->o2sensor[3].mbar) && (sample->o2sensor[3].mbar != old->o2sensor[3].mbar)) {
|
||||||
|
put_milli(b, " sensor4='", sample->o2sensor[3].mbar, " bar'");
|
||||||
|
old->o2sensor[3] = sample->o2sensor[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sample->o2sensor[4].mbar) && (sample->o2sensor[4].mbar != old->o2sensor[4].mbar)) {
|
||||||
|
put_milli(b, " sensor5='", sample->o2sensor[4].mbar, " bar'");
|
||||||
|
old->o2sensor[4] = sample->o2sensor[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sample->o2sensor[5].mbar) && (sample->o2sensor[5].mbar != old->o2sensor[5].mbar)) {
|
||||||
|
put_milli(b, " sensor6='", sample->o2sensor[5].mbar, " bar'");
|
||||||
|
old->o2sensor[5] = sample->o2sensor[5];
|
||||||
|
}
|
||||||
|
|
||||||
if (sample->setpoint.mbar != old->setpoint.mbar) {
|
if (sample->setpoint.mbar != old->setpoint.mbar) {
|
||||||
put_milli(b, " po2='", sample->setpoint.mbar, " bar'");
|
put_milli(b, " po2='", sample->setpoint.mbar, " bar'");
|
||||||
old->setpoint = sample->setpoint;
|
old->setpoint = sample->setpoint;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue